/* =========================================================
   Crumble App - old black & white film
   Same brand (Dela Gothic One + Bricolage Grotesque, mascots),
   printed on silver-gelatin: paper white, soot black, grain,
   gate weave, flicker and the odd scratch.
   ========================================================= */
@font-face {
  font-family: "Dela Gothic One";
  src: url("/assets/fonts/dela-gothic-one-latin.woff2") format("woff2");
  font-weight: 400; font-display: swap;
}
@font-face {
  font-family: "Bricolage Grotesque";
  src: url("/assets/fonts/bricolage-grotesque-latin.woff2") format("woff2");
  font-weight: 200 800; font-display: swap;
}

:root {
  --soot: #0b0b0a;
  --soot-2: #141412;
  --soot-3: #1d1d1a;
  --line: #3a3a35;
  --ash: #8d8c85;
  --silver: #c9c7bd;
  --paper: #eeece3;
  --lime: #e2fea5;          /* the only colour: used sparingly */
  --bad: #ff8a80;

  --f-display: "Dela Gothic One", "Arial Black", sans-serif;
  --f-body: "Bricolage Grotesque", system-ui, sans-serif;
  --f-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  --shell: 1120px;
  --gutter: clamp(16px, 4vw, 40px);
  --r: 18px;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; min-height: 100vh;
  background: var(--soot);
  color: var(--paper);
  font-family: var(--f-body); font-size: 16px; line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  animation: weave 5s steps(1) infinite; /* gate weave: the whole frame shivers a hair */
}
img { display: block; max-width: 100%; }
a { color: inherit; }
button, input, select { font: inherit; color: inherit; }
::selection { background: var(--paper); color: var(--soot); }

.shell { width: 100%; max-width: var(--shell); margin: 0 auto; padding: 0 var(--gutter); }
.mono { font-family: var(--f-mono); font-feature-settings: "tnum"; }
.dim { color: var(--ash); }
.lime { color: var(--lime); }
.bw { filter: grayscale(1) contrast(1.15) brightness(1.02); }

/* ---------- film layer (grain + flicker + vignette + scratches) ---------- */
.film { position: fixed; inset: 0; pointer-events: none; z-index: 90; }
.film::before { /* grain, 4 frames */
  content: ""; position: absolute; inset: -64px;
  background: url("/assets/img/grain-1.png") 0 0 / 128px 128px repeat;
  opacity: .07; mix-blend-mode: screen;
  animation: grain .34s steps(1) infinite;
}
.film::after { /* vignette + flicker */
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(ellipse at 50% 45%, transparent 55%, rgba(0,0,0,.55) 100%);
  animation: flicker 3.2s steps(1) infinite;
}
.scratch { position: absolute; top: -10%; bottom: -10%; width: 1px; background: rgba(238,236,227,.18); opacity: 0; }
.scratch.s1 { left: 18%; animation: scratch 7s steps(1) infinite; }
.scratch.s2 { left: 63%; animation: scratch 11s steps(1) 2s infinite; width: 2px; background: rgba(0,0,0,.35); }
.scratch.s3 { left: 84%; animation: scratch 13s steps(1) 5s infinite; }
@keyframes grain {
  0%   { background-image: url("/assets/img/grain-1.png"); transform: translate(0, 0); }
  25%  { background-image: url("/assets/img/grain-2.png"); transform: translate(-17px, 9px); }
  50%  { background-image: url("/assets/img/grain-3.png"); transform: translate(11px, -21px); }
  75%  { background-image: url("/assets/img/grain-4.png"); transform: translate(-7px, -13px); }
}
@keyframes flicker {
  0% { opacity: 1; } 12% { opacity: .9; } 14% { opacity: 1; } 47% { opacity: .94; } 49% { opacity: 1; } 78% { opacity: .88; } 80% { opacity: 1; }
}
@keyframes scratch {
  0% { opacity: 0; } 3% { opacity: 1; transform: translateX(0); } 5% { opacity: 1; transform: translateX(6px); } 7% { opacity: 0; } 100% { opacity: 0; }
}
@keyframes weave {
  0% { background-position: 0 0; } 50% { background-position: 0 1px; }
}
@media (prefers-reduced-motion: reduce) {
  body, .film::before, .film::after, .scratch, .tape-track { animation: none !important; }
}

/* ---------- header ---------- */
.top { position: sticky; top: 0; z-index: 40; background: rgba(11,11,10,.92); backdrop-filter: blur(6px); border-bottom: 1px solid var(--line); }
.top-row { display: flex; align-items: center; gap: 16px; height: 68px; }
/* The bar used to hold four things and the tabs sat between two of them, so the
   auto margins happened to balance. With the oven widget gone they do not, and
   the tabs drift right by half the wallet's width. Centre them against the bar
   itself instead of against whatever happens to sit beside them. */
.top-row { position: relative; }
.tabs { position: absolute; left: 50%; transform: translateX(-50%); margin: 0; }
/* Taking the tabs out of the flow also took away the auto margin that used to
   push the wallet to the right edge, so state it directly. */
.top-row > .wallet { margin-left: auto; }
.logo { display: flex; align-items: center; gap: 10px; text-decoration: none; font-family: var(--f-display); font-size: 24px; letter-spacing: .02em; }
.logo img { width: 40px; height: 40px; filter: grayscale(1) contrast(1.2); }
.tabs { display: flex; gap: 4px; margin: 0 auto; padding: 4px; border: 1px solid var(--line); border-radius: 100px; }
.tabs button { border: 0; background: none; padding: 8px 16px; border-radius: 100px; font-weight: 700; color: var(--silver); }
.tabs button.on { background: var(--paper); color: var(--soot); }
.wallet { display: flex; align-items: center; gap: 8px; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 44px; padding: 0 18px; border-radius: 100px;
  background: var(--paper); color: var(--soot); border: 1.5px solid var(--paper);
  font-weight: 800; white-space: nowrap; text-decoration: none;
  transition: transform .12s ease, background .12s ease;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(1px); }
.btn.ghost { background: transparent; color: var(--paper); border-color: var(--line); }
.btn.ghost:hover { border-color: var(--paper); }
.btn.lime { background: var(--lime); border-color: var(--lime); }
.btn.big { height: 60px; font-size: 18px; width: 100%; border-radius: 16px; font-family: var(--f-display); font-weight: 400; letter-spacing: .02em; text-transform: uppercase; }
.btn[disabled], .btn.is-disabled { opacity: .45; transform: none; }
.chip { display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 12px; border-radius: 100px; border: 1px solid var(--line); font-size: 13px; font-weight: 700; color: var(--silver); background: none; }
.chip.warn { border-color: var(--bad); color: var(--bad); }
.chip i { width: 7px; height: 7px; border-radius: 50%; background: var(--lime); }
.chip.warn i { background: var(--bad); }

/* ticker tape: newsreel prices */
.tape { overflow: hidden; border-top: 1px solid var(--line); background: var(--soot-2); }
.tape-track { display: flex; width: max-content; padding: 7px 0; animation: tape 60s linear infinite; font-family: var(--f-mono); font-size: 12.5px; color: var(--silver); letter-spacing: .04em; }
.tape-track b { color: var(--paper); font-weight: 700; }
/* spacing lives on each item, not as flex gap: with a gap the two halves are
   one gap short of equal and the loop visibly hops at the seam */
.tape-track > span { padding-right: 34px; white-space: nowrap; }
@keyframes tape { to { transform: translateX(-50%); } }

/* ---------- intertitle hero (silent-movie card) ---------- */
.intertitle {
  /* The mascot is lifted 96px out of this card's 44px of top padding, so it
     pokes 52px above the border. That overhang needs room: at 44px the mascot
     cleared the card but slid up under the sticky header and behind the price
     tape. The top margin has to stay larger than the overhang. */
  position: relative; margin: 70px auto 28px; max-width: 760px; text-align: center;
  padding: 44px clamp(20px, 5vw, 56px);
  border: 1.5px solid var(--silver); border-radius: 6px;
  outline: 1px solid var(--line); outline-offset: 6px;
}
.intertitle::before, .intertitle::after { content: "✦"; position: absolute; top: 50%; transform: translateY(-50%); color: var(--silver); font-size: 14px; }
.intertitle::before { left: 14px; } .intertitle::after { right: 14px; }
.eyebrow { display: inline-block; font-family: var(--f-mono); font-size: 12px; letter-spacing: .18em; text-transform: uppercase; color: var(--ash); margin-bottom: 14px; }
.intertitle h1 { font-family: var(--f-display); font-weight: 400; text-transform: uppercase; font-size: clamp(34px, 6.4vw, 64px); line-height: .98; margin: 0 0 18px; }
.intertitle p { margin: 0 auto 10px; max-width: 540px; color: var(--silver); }
.intertitle .punch { color: var(--paper); font-weight: 700; }
.hero-cta { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-top: 22px; }
.hero-mascot { width: 120px; margin: -96px auto 10px; filter: grayscale(1) contrast(1.2); }

/* ---------- cards & layout ---------- */
.grid2 { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); gap: 18px; align-items: stretch; margin: 26px 0 60px; }
/* Both columns end on the same line. Whichever is shorter lets its last card
   take up the slack, so the page has one bottom edge instead of a ragged step.
   Only the last card grows - the ones above it keep their natural height. */
.grid2 > div { display: flex; flex-direction: column; min-width: 0; }
.grid2 > div > :last-child { flex: 1 1 auto; }
/* When the swap card is the one that grows, the slack belongs above the button:
   the call to action sits on the bottom edge rather than floating mid-card. */
.card[data-swap] { display: flex; flex-direction: column; }
[data-cta] { margin-top: 16px; }
/* An inline style would beat this, which is why the margin lives here now. */
.card[data-swap] [data-cta] { margin-top: auto; padding-top: 16px; }
.card { background: var(--soot-2); border: 1px solid var(--line); border-radius: var(--r); padding: 22px; }
.card + .card { margin-top: 18px; }
.card h2 { font-family: var(--f-display); font-weight: 400; text-transform: uppercase; font-size: 22px; letter-spacing: .02em; margin: 0 0 4px; }
.card h3 { font-size: 14px; font-family: var(--f-mono); letter-spacing: .14em; text-transform: uppercase; color: var(--ash); margin: 0 0 14px; font-weight: 400; }
.card .lead { color: var(--silver); margin: 0 0 18px; }
.label { display: block; font-size: 13px; font-weight: 700; color: var(--ash); margin: 16px 0 8px; }
.label:first-child { margin-top: 0; }
.row { display: flex; gap: 10px; align-items: center; }
.row.between { justify-content: space-between; }
.stack { display: grid; gap: 10px; }

.field { display: flex; align-items: center; gap: 10px; background: var(--soot); border: 1px solid var(--line); border-radius: 14px; padding: 6px 6px 6px 16px; }
.field:focus-within { border-color: var(--silver); }
.field input { flex: 1; min-width: 0; background: none; border: 0; outline: 0; font-family: var(--f-mono); font-size: 22px; padding: 8px 0; }
.field input::placeholder { color: #55544e; }
.field .unit { color: var(--ash); font-family: var(--f-mono); font-size: 20px; }
.token-btn { display: inline-flex; align-items: center; gap: 8px; height: 42px; padding: 0 12px 0 8px; border-radius: 100px; border: 1px solid var(--line); background: var(--soot-3); font-weight: 800; white-space: nowrap; }
.token-btn:hover { border-color: var(--silver); }
.tok-ico { width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; background: var(--paper); color: var(--soot); font-size: 8.5px; font-weight: 800; letter-spacing: -.04em; flex: none; overflow: hidden; }
.caret { opacity: .6; font-size: 11px; }
.hint { font-size: 12.5px; color: var(--ash); margin-top: 6px; display: flex; justify-content: space-between; gap: 8px; }
.hint button { background: none; border: 0; padding: 0; color: var(--silver); font-weight: 700; text-decoration: underline; text-underline-offset: 2px; }

.seg { display: inline-flex; border: 1px solid var(--line); border-radius: 12px; padding: 3px; gap: 3px; flex-wrap: wrap; }
.seg button { border: 0; background: none; padding: 7px 14px; border-radius: 9px; font-weight: 800; color: var(--silver); font-family: var(--f-mono); }
.seg button.on { background: var(--paper); color: var(--soot); }

.swap-arrow { display: grid; place-items: center; margin: -4px 0; }
.swap-arrow span { width: 34px; height: 34px; border-radius: 10px; display: grid; place-items: center; border: 1px solid var(--line); background: var(--soot); color: var(--silver); }

.summary { margin-top: 18px; border-top: 1px dashed var(--line); padding-top: 14px; display: grid; gap: 8px; font-size: 14.5px; }
.summary .row { justify-content: space-between; }
.summary b { font-family: var(--f-mono); font-weight: 700; }
.summary .big-line { font-size: 16px; }
.summary .big-line b { color: var(--lime); }
.summary .legs { display: grid; gap: 4px; }
.summary .legs .mono { font-size: 12.5px; color: var(--silver); line-height: 1.6; }
.note { font-size: 13px; color: var(--ash); margin: 12px 0 0; }
.note.bad { color: var(--bad); }

/* receipt: the round-up explained */
.receipt { font-family: var(--f-mono); font-size: 14px; background: var(--paper); color: var(--soot); border-radius: 6px; padding: 18px 18px 14px; position: relative; }
.receipt::after { content: ""; position: absolute; left: 0; right: 0; bottom: -8px; height: 8px; background: linear-gradient(-45deg, transparent 6px, var(--paper) 0) 0 0 / 12px 8px repeat-x, linear-gradient(45deg, transparent 6px, var(--paper) 0) 0 0 / 12px 8px repeat-x; }
.receipt .r-row { display: flex; justify-content: space-between; gap: 10px; padding: 3px 0; }
.receipt .r-total { border-top: 1px dashed #777; margin-top: 8px; padding-top: 8px; font-weight: 800; }
.receipt .r-head { text-align: center; letter-spacing: .2em; font-size: 12px; margin-bottom: 8px; }

/* basket editor */
.stocks { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.stock { text-align: left; border: 1px solid var(--line); background: var(--soot); border-radius: 14px; padding: 12px; display: grid; gap: 2px; position: relative; }
.stock:hover { border-color: var(--silver); }
.stock.on { border-color: var(--paper); background: var(--soot-3); }
.stock .sym { font-family: var(--f-display); font-size: 18px; letter-spacing: .02em; }
.stock .nm { font-size: 12.5px; color: var(--ash); }
.stock .px { font-family: var(--f-mono); font-size: 13px; color: var(--silver); }
.stock .tick { position: absolute; top: 10px; right: 10px; width: 20px; height: 20px; border-radius: 50%; border: 1.5px solid var(--line); display: grid; place-items: center; font-size: 12px; }
.stock.on .tick { background: var(--paper); color: var(--soot); border-color: var(--paper); }
.weights { display: grid; gap: 8px; margin-top: 14px; }
.wrow { display: grid; grid-template-columns: 64px 1fr 76px; gap: 12px; align-items: center; }
/* A five-letter ticker in the display face is wider than the column it was
   given, and it ran into the slider. Nothing here may overflow its cell. */
.wrow > * { min-width: 0; }
.wrow .sym { font-family: var(--f-display); }
.wrow input[type="range"] {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 10px; margin: 0;
  border-radius: 100px; outline-offset: 4px;
  /* --fill is written by app.js as the value changes, so the track still shows
     how far along you are - accent-color used to do this for free. */
  background: linear-gradient(to right, var(--paper) var(--fill, 0%), var(--line) var(--fill, 0%));
}
.wrow input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--paper); border: 2px solid var(--soot-2);
  transition: transform .13s ease, box-shadow .13s ease;
}
.wrow input[type="range"]::-moz-range-thumb {
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--paper); border: 2px solid var(--soot-2);
  transition: transform .13s ease, box-shadow .13s ease;
}
/* Grows under the cursor: the answer to "am I actually dragging this one?" */
.wrow input[type="range"]:hover::-webkit-slider-thumb { transform: scale(1.18); }
.wrow input[type="range"]:hover::-moz-range-thumb { transform: scale(1.18); }
.wrow input[type="range"]:active::-webkit-slider-thumb { transform: scale(1.28); box-shadow: 0 0 0 6px rgba(238, 236, 227, .12); }
.wrow input[type="range"]:active::-moz-range-thumb { transform: scale(1.28); box-shadow: 0 0 0 6px rgba(238, 236, 227, .12); }
.wrow input[type="range"]:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 4px rgba(226, 254, 165, .35); }
.wrow input[type="range"]:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 4px rgba(226, 254, 165, .35); }
.wrow .pct { display: flex; align-items: center; gap: 4px; justify-content: flex-end; font-family: var(--f-mono); }
.wrow .pct input { width: 52px; text-align: right; background: var(--soot); border: 1px solid var(--line); border-radius: 8px; padding: 4px 6px; font-family: var(--f-mono); }
.total-line { display: flex; justify-content: space-between; font-family: var(--f-mono); font-size: 14px; margin-top: 8px; }
.total-line.bad { color: var(--bad); }

/* vault */
.worth { font-family: var(--f-display); font-size: clamp(40px, 7vw, 72px); line-height: 1; margin: 6px 0 4px; }
.bar { display: flex; height: 12px; border-radius: 6px; overflow: hidden; background: var(--soot-3); margin: 16px 0 6px; }
.bar i { display: block; height: 100%; }
.hold { display: grid; grid-template-columns: 1fr auto; gap: 4px 12px; padding: 14px 0; border-top: 1px solid var(--line); align-items: center; }
.hold .sym { font-family: var(--f-display); font-size: 18px; }
.hold .amt { font-family: var(--f-mono); font-size: 13px; color: var(--ash); }
.hold .val { font-family: var(--f-mono); font-weight: 700; text-align: right; }
.hold .act { grid-column: 1 / -1; display: none; gap: 8px; margin-top: 8px; }
.hold.open .act { display: flex; }
.hold .act .field { flex: 1; padding: 2px 4px 2px 12px; }
.hold .act .field input { font-size: 16px; }
.link-btn { background: none; border: 0; padding: 0; color: var(--silver); font-weight: 700; text-decoration: underline; text-underline-offset: 3px; font-size: 13px; }
.empty { text-align: center; padding: 30px 10px; color: var(--ash); }
.empty img { width: 110px; margin: 0 auto 12px; }

/* activity */
.acts { display: grid; }
.act-row { display: grid; grid-template-columns: 34px 1fr auto; gap: 12px; align-items: center; padding: 12px 0; border-top: 1px solid var(--line); text-decoration: none; }
.act-row:hover .what { text-decoration: underline; }
.act-ico { width: 34px; height: 34px; border-radius: 10px; border: 1px solid var(--line); display: grid; place-items: center; font-family: var(--f-mono); font-size: 14px; }
.act-row .what { font-weight: 700; }
.act-row .when { font-size: 12.5px; color: var(--ash); font-family: var(--f-mono); }
.act-row .amt { font-family: var(--f-mono); font-size: 13.5px; text-align: right; }
.act-row .st { font-family: var(--f-body); }
.act-row.st-ok .act-ico { color: var(--lime); border-color: var(--lime); }
.act-row.st-ok .st { color: var(--lime); }
.act-row.st-failed .act-ico, .act-row.st-failed .st { color: var(--bad); border-color: var(--bad); }
.act-row.st-dropped .act-ico, .act-row.st-dropped .st { color: var(--ash); }
.act-row.st-failed .what, .act-row.st-dropped .what { text-decoration: line-through; text-decoration-color: rgba(255,255,255,.35); }
.act-row.st-pending .act-ico { animation: pulse 1.4s ease-in-out infinite; }

/* steps list (how it works) */
.steps { counter-reset: s; display: grid; gap: 12px; margin: 0; padding: 0; list-style: none; }
.steps li { counter-increment: s; display: grid; grid-template-columns: 30px 1fr; gap: 12px; color: var(--silver); }
.steps li::before { content: counter(s); width: 30px; height: 30px; border-radius: 50%; border: 1px solid var(--silver); display: grid; place-items: center; font-family: var(--f-mono); font-size: 13px; color: var(--paper); }
.steps b { color: var(--paper); }

.banner { border: 1px dashed var(--silver); border-radius: 14px; padding: 12px 16px; display: flex; gap: 12px; align-items: center; justify-content: space-between; flex-wrap: wrap; margin-top: 20px; font-size: 14px; color: var(--silver); }
.banner b { color: var(--paper); }

/* modal + toast */
.modal { position: fixed; inset: 0; z-index: 80; background: rgba(0,0,0,.7); display: grid; place-items: center; padding: 16px; }
.modal[hidden] { display: none; }
.sheet { width: min(460px, 100%); max-height: 86vh; overflow: auto; background: var(--soot-2); border: 1px solid var(--line); border-radius: 20px; padding: 20px; }
.sheet h2 { font-family: var(--f-display); font-weight: 400; text-transform: uppercase; font-size: 20px; margin: 0 0 12px; }
.opt { width: 100%; display: flex; align-items: center; gap: 12px; padding: 10px; border: 1px solid transparent; border-radius: 12px; background: none; text-align: left; }
.opt:hover { border-color: var(--line); background: var(--soot-3); }
.opt .nm { font-size: 12.5px; color: var(--ash); }
.opt img { width: 28px; height: 28px; border-radius: 8px; }
.toast { position: fixed; left: 50%; bottom: 22px; transform: translate(-50%, 24px); opacity: 0; visibility: hidden; z-index: 95; background: var(--paper); color: var(--soot); font-weight: 800; padding: 12px 18px; border-radius: 100px; max-width: calc(100vw - 32px); text-align: center; transition: transform .25s ease, opacity .25s ease, visibility .25s; }
.toast.show { transform: translate(-50%, 0); opacity: 1; visibility: visible; }
.toast a { font-weight: 800; }

/* footer */
.foot { border-top: 1px solid var(--line); margin-top: 40px; padding-top: 18px; padding-bottom: 34px; color: var(--ash); font-size: 13px; }
.foot-row { display: flex; gap: 12px 24px; flex-wrap: wrap; justify-content: space-between; }
.foot-row a { text-decoration: none; color: var(--silver); }
.foot-small { margin: 12px 0 0; }

.skeleton { display: inline-block; min-width: 60px; height: 1em; border-radius: 4px; background: linear-gradient(90deg, var(--soot-3), #2a2a26, var(--soot-3)); background-size: 200% 100%; animation: sk 1.2s linear infinite; vertical-align: middle; }
@keyframes sk { to { background-position: -200% 0; } }

/* ---------- responsive ---------- */
@media (max-width: 860px) {
  .grid2 { grid-template-columns: minmax(0, 1fr); }
  .top-row { flex-wrap: wrap; height: auto; padding-top: 10px; padding-bottom: 10px; row-gap: 10px; }
  .tabs { order: 3; width: 100%; justify-content: space-between; position: static; transform: none; }
  .tabs button { flex: 1; }
  .wallet { margin-left: auto; }
}
@media (max-width: 480px) {
  /* A phone header wraps onto two rows, so there is LESS room above the hero,
     not more. Save the space by shrinking the mascot's lift, never by cutting
     the card's top margin: trimming the margin alone is exactly what pushed
     the mascot up behind the price tape. Margin must stay above the overhang,
     which here is 78 - 44 = 34px. */
  .hero-mascot { width: 100px; margin-top: -78px; }
  .intertitle { margin-top: 56px; }
  .intertitle::before, .intertitle::after { display: none; }
  .card { padding: 18px; }
  .field input { font-size: 19px; }
  .wrow { grid-template-columns: 62px 1fr 68px; gap: 10px; }
  .wrow .sym { font-size: 14px; }
}

/* -------------------------------------------------------------
   Guided first run
   A strip that states the order the app implies but never says:
   basket before swap. It shows only until the loop has been walked
   once (see guideStep in app.js), then disappears for good - so it
   teaches a newcomer without ever standing in a regular's way.
   ------------------------------------------------------------- */
.guide {
  margin: 26px 0 0;
  background: var(--soot-2);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 18px 20px;
}
.guide ol {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 26px;
  list-style: none;
  margin: 0 0 16px;
  padding: 0;
}
.guide li {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  color: var(--ash);
}
/* The number carries the state, so the row reads at a glance even
   in grayscale: filled = here, outlined = done, dim = not yet. */
.guide li b {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: 1px solid var(--line);
  font: 700 12px/1 var(--f-mono);
  color: var(--ash);
  flex: none;
}
.guide li.now { color: var(--paper); font-weight: 700; }
.guide li.now b { background: var(--lime); border-color: var(--lime); color: var(--soot); }
.guide li.done { color: var(--silver); }
.guide li.done b { border-color: var(--silver); color: var(--silver); }
.guide-do {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
  border-top: 1px solid var(--line);
  padding-top: 16px;
}
.guide-do p { margin: 0; flex: 1 1 320px; color: var(--silver); font-size: 15px; }
.guide-do .btn { flex: none; }

@media (max-width: 640px) {
  .guide { padding: 16px; }
  .guide ol { gap: 10px 18px; }
  .guide li span { font-size: 13px; }
  .guide-do .btn { width: 100%; }
}

/* ---------- guide: dismissing, spotlight, attention ---------- */

/* Room for the cross, and a positioned box for it to sit in. */
.guide {
  position: relative;
  padding-right: 54px;
  overflow: hidden;
  transition: max-height .36s cubic-bezier(.4, 0, .2, 1),
              opacity .26s ease,
              transform .36s cubic-bezier(.4, 0, .2, 1),
              margin .36s ease, padding .36s ease;
}
.guide-x {
  position: absolute; top: 12px; right: 12px;
  width: 30px; height: 30px; display: grid; place-items: center;
  background: none; border: 1px solid var(--line); border-radius: 50%;
  color: var(--ash); font-size: 17px; line-height: 1; padding: 0;
  transition: color .15s ease, border-color .15s ease, transform .15s ease;
}
.guide-x:hover { color: var(--paper); border-color: var(--silver); transform: rotate(90deg); }

/* The strip folds into the corner the cross sits in, so the small round "?"
   that replaces it reads as the same object shrunk, not a new one. */
.guide.closing {
  max-height: 0 !important;
  opacity: 0;
  transform: scale(.3);
  transform-origin: 100% 0;
  margin: 0; padding-top: 0; padding-bottom: 0; border-width: 0;
}
@keyframes guide-in {
  from { opacity: 0; transform: scale(.3); }
  to   { opacity: 1; transform: scale(1); }
}
.guide { transform-origin: 100% 0; }
.guide.opening { animation: guide-in .34s cubic-bezier(.2, .8, .3, 1) both; }

/* The way back in. Small, out of the way, always in the same place. */
.guide-peek {
  position: fixed; right: 18px; bottom: 18px; z-index: 44;
  width: 42px; height: 42px; border-radius: 50%;
  display: grid; place-items: center; padding: 0;
  background: var(--soot-2); border: 1px solid var(--line);
  color: var(--ash); font: 700 17px/1 var(--f-mono);
  transition: color .15s ease, border-color .15s ease, transform .15s ease;
}
.guide-peek:hover { color: var(--soot); background: var(--lime); border-color: var(--lime); transform: translateY(-2px); }

/* Attention lives on exactly one button: the one the guide is pointing at right
   now. It breathes - scales out and back - rather than sliding, and it exists
   nowhere else in the app, so nothing competes with it. */
@keyframes pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.055); }
}
.guide-do .btn:not([disabled]) { animation: pulse 2.2s ease-in-out infinite; }
.guide-do .btn:hover, .guide-do .btn:focus-visible { animation: none; }

/* The basket page keeps the guide's own edges - a card that sits narrower than
   the strip above it reads as a different column, not the next step. */
.one-col { margin: 26px 0 60px; }

@media (prefers-reduced-motion: reduce) {
  .guide { animation: none !important; }
  .guide-do .btn { animation: none !important; }
}

@media (max-width: 640px) {
  .guide { padding-right: 46px; }
  .guide-peek { right: 12px; bottom: 12px; }
}

/* ---------- basket: two panes, one card ---------- */

/* The card drops its own padding so the two halves can meet on a single line
   with nothing between them - the divider is the border, not a gap. */
.basket-split { padding: 0; overflow: hidden; }
.bs-cols { display: grid; grid-template-columns: minmax(0, .82fr) minmax(0, 1.18fr); }
.bs-left { padding: 22px; border-right: 1px solid var(--line); }
.bs-right { padding: 22px; }
.bs-left h2 { margin-bottom: 6px; }
.bs-left .lead { margin-bottom: 0; }
.bs-actions { margin-top: 16px; flex-wrap: wrap; }

.presets { display: grid; gap: 10px; margin-top: 18px; }
.preset {
  display: grid; gap: 4px; text-align: left;
  background: var(--soot); border: 1px solid var(--line);
  border-radius: 14px; padding: 12px 14px;
  transition: border-color .15s ease, background .15s ease;
}
.preset b { font-size: 15px; font-weight: 700; }
.preset span { font-size: 13px; line-height: 1.45; color: var(--ash); }
.preset:hover { border-color: var(--silver); }
/* The chosen mix is the only lime thing in the pane, so it reads at a glance
   even before the words do. */
.preset.on { border-color: var(--lime); background: rgba(226, 254, 165, .06); }
.preset.on b { color: var(--lime); }

@media (max-width: 900px) {
  .bs-cols { grid-template-columns: minmax(0, 1fr); }
  .bs-left { border-right: 0; border-bottom: 1px solid var(--line); }
}

/* Brand sizing mirrors the landing exactly, breakpoint for breakpoint, so the
   header does not change scale when you cross from the site into the app. */
@media (max-width: 809px) {
  .logo { font-size: 20px; gap: 8px; }
  .logo img { width: 34px; height: 34px; }
}
@media (max-width: 380px) {
  .logo img { display: none; }
}

/* ---------- Custom cursors ---------- */
/* Same drawings as the landing, remapped onto the app's two colours - the app
   is a black and white film and a cream cursor would be the one prop that
   forgot. Mechanics are identical: 32px base, 64px @2x, url() first so a
   browser without image-set() still gets a cursor, hotspot after the url. */
html, body {
  cursor: url("/app/cursors/arrow-32.png") 1 0, auto;
  cursor: -webkit-image-set(url("/app/cursors/arrow-32.png") 1x,
                            url("/app/cursors/arrow-64.png") 2x) 1 0, auto;
  cursor: image-set(url("/app/cursors/arrow-32.png") 1x,
                    url("/app/cursors/arrow-64.png") 2x) 1 0, auto;
}
a, button, summary, label, select, [role="button"],
.stock, .preset, .guide-x, .guide-peek,
input[type="checkbox"], input[type="radio"] {
  cursor: url("/app/cursors/point-32.png") 10 0, pointer;
  cursor: -webkit-image-set(url("/app/cursors/point-32.png") 1x,
                            url("/app/cursors/point-64.png") 2x) 10 0, pointer;
  cursor: image-set(url("/app/cursors/point-32.png") 1x,
                    url("/app/cursors/point-64.png") 2x) 10 0, pointer;
}
/* Typing gets its own beam rather than the system caret. The hotspot is the
   middle of the bar, not a corner: a text cursor that clicks anywhere else
   drops the caret between the wrong two letters. */
input[type="text"], input[type="number"], input[type="email"],
input[type="search"], input[type="tel"], input[type="url"], textarea {
  cursor: url("/app/cursors/text-32.png") 16 16, text;
  cursor: -webkit-image-set(url("/app/cursors/text-32.png") 1x,
                            url("/app/cursors/text-64.png") 2x) 16 16, text;
  cursor: image-set(url("/app/cursors/text-32.png") 1x,
                    url("/app/cursors/text-64.png") 2x) 16 16, text;
}
/* Re-stated after the block above, which would otherwise hand a dead button
   the same inviting glove as a live one. */
button[disabled], .btn[disabled], .btn.is-disabled { cursor: not-allowed; }

/* The weight sliders get the open glove instead - the gesture is "take hold of
   this", not "click here", and it closes into a fist for as long as you hold it.

   Each vendor pseudo-element gets its own rule on purpose. A selector list is
   thrown away whole when a browser does not recognise one of its parts, so
   putting ::-webkit-slider-thumb and ::-moz-range-thumb in the same list as the
   input would leave every engine with no rule at all. The thumb needs its own
   because a cursor set there beats the one set on the track. */
.wrow input[type="range"] {
  cursor: url("/app/cursors/palm-32.png") 16 15, grab;
  cursor: -webkit-image-set(url("/app/cursors/palm-32.png") 1x,
                            url("/app/cursors/palm-64.png") 2x) 16 15, grab;
  cursor: image-set(url("/app/cursors/palm-32.png") 1x,
                    url("/app/cursors/palm-64.png") 2x) 16 15, grab;
}
.wrow input[type="range"]::-webkit-slider-thumb {
  cursor: url("/app/cursors/palm-32.png") 16 15, grab;
  cursor: -webkit-image-set(url("/app/cursors/palm-32.png") 1x,
                            url("/app/cursors/palm-64.png") 2x) 16 15, grab;
}
.wrow input[type="range"]::-moz-range-thumb {
  cursor: url("/app/cursors/palm-32.png") 16 15, grab;
  cursor: image-set(url("/app/cursors/palm-32.png") 1x,
                    url("/app/cursors/palm-64.png") 2x) 16 15, grab;
}
.wrow input[type="range"]:active {
  cursor: url("/app/cursors/fist-32.png") 14 16, grabbing;
  cursor: -webkit-image-set(url("/app/cursors/fist-32.png") 1x,
                            url("/app/cursors/fist-64.png") 2x) 14 16, grabbing;
  cursor: image-set(url("/app/cursors/fist-32.png") 1x,
                    url("/app/cursors/fist-64.png") 2x) 14 16, grabbing;
}
.wrow input[type="range"]:active::-webkit-slider-thumb {
  cursor: url("/app/cursors/fist-32.png") 14 16, grabbing;
  cursor: -webkit-image-set(url("/app/cursors/fist-32.png") 1x,
                            url("/app/cursors/fist-64.png") 2x) 14 16, grabbing;
}
.wrow input[type="range"]:active::-moz-range-thumb {
  cursor: url("/app/cursors/fist-32.png") 14 16, grabbing;
  cursor: image-set(url("/app/cursors/fist-32.png") 1x,
                    url("/app/cursors/fist-64.png") 2x) 14 16, grabbing;
}

/* ---------- The Oven ---------- */
.oven-card { margin-top: 18px; }
.oven-card .oven-head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; margin-bottom: 10px; }
.oven-card .oven-head h3 { margin: 0; }
.oven-card .oven-head a { font-size: 13px; font-weight: 700; color: var(--ash); }
.oven-card .oven-head a:hover { color: var(--lime); }
.oven-card code { font-family: var(--f-mono); font-size: .92em; background: var(--soot-3); border-radius: 6px; padding: 1px 6px; }
.oven-nums { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.oven-nums > div { background: var(--soot-3); border: 1px solid var(--line); border-radius: 12px; padding: 14px 16px; }
.oven-nums span { display: block; font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--ash); margin-bottom: 8px; }
.oven-nums b { font-family: var(--f-display); font-weight: 400; font-size: 19px; line-height: 1.15; color: var(--lime); overflow-wrap: break-word; }
@media (max-width: 720px) { .oven-nums { grid-template-columns: 1fr; } }


/* ---------- Oven ticker in the header ----------
   Same idea as the landing, in the app's palette: a pulsing dot, the live pot,
   and a hairline that only shows a percentage once the contract declares one. */
.app-oven { display: flex; flex-direction: column; justify-content: center; gap: 6px; height: 38px; padding: 0 14px; border: 1px solid var(--line); border-radius: 100px; background: var(--soot-3); cursor: pointer; }
.app-oven:hover { border-color: var(--lime); }
.app-oven-in { display: flex; align-items: center; gap: 8px; line-height: 1; }
.app-oven-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--lime); flex: none; animation: ovenPulse 3.4s ease-out infinite; }
@keyframes ovenPulse {
  0% { box-shadow: 0 0 0 0 rgba(226, 254, 165, .45); }
  70% { box-shadow: 0 0 0 7px rgba(226, 254, 165, 0); }
  100% { box-shadow: 0 0 0 0 rgba(226, 254, 165, 0); }
}
.app-oven-label { font-size: 9.5px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase; color: var(--ash); white-space: nowrap; }
.app-oven b { font-size: 12.5px; font-weight: 800; color: var(--lime); font-family: var(--f-mono); white-space: nowrap; }
.app-oven-line { display: block; height: 2px; border-radius: 2px; background: var(--line); overflow: hidden; }
.app-oven-line i { display: block; height: 100%; width: 0; background: var(--lime); transition: width .9s cubic-bezier(.2, .8, .2, 1); }
.app-oven.is-idle .app-oven-line i { width: 100%; opacity: .45; background: repeating-linear-gradient(115deg, var(--lime) 0 8px, rgba(226, 254, 165, .08) 8px 20px); background-size: 200% 100%; animation: ovenStripe 9s linear infinite; }
@keyframes ovenStripe { to { background-position: -200% 0; } }
@media (max-width: 1100px) { .app-oven-label { display: none; } }
@media (max-width: 760px) { .app-oven { display: none; } }
@media (prefers-reduced-motion: reduce) {
  .app-oven-dot { animation: none; }
  .app-oven-line i { transition: none; }
  .app-oven.is-idle .app-oven-line i { animation: none; }
}
