Files
roast_command_center/public/index.html
T
snowspeederandClaude Sonnet 5 fedaf29847 Initial roast planner webapp: fillable worksheet, live ledger, curve, URL prefill, .alog reference curve
- shared/ ports the worksheet's ledger math, time parsing, and reference tables
  (cultivars/processes/roast-levels/machine bands) as browser-safe ESM, imported
  by both the server and the browser so the arithmetic can't drift between them.
- server/prefill.js runs a zero-tool Pi Coding Agent SDK turn to extract page facts
  from a bean product URL, then derives worksheet field IDs deterministically from
  reference-data.js — the model never invents a first-crack anchor or a modifier.
- server/alog.js ports the Python alog_parser.py's format handling, including the
  tokenizer-based Python-dict-literal-to-JSON conversion the real files need.
- public/ is the worksheet reproduced as a live HTML form: worksheet.css is a
  verbatim copy of the paper worksheet's print CSS, print.js bakes values into
  the print layout so the same DOM renders both on screen and on paper.
- Ledger math verified against both of the paper worksheet's worked examples;
  alog parser verified against all 14 real logs in ref/roasts/.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-29 15:41:35 -04:00

360 lines
26 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Roast Planner</title>
<link rel="stylesheet" href="/worksheet.css">
<link rel="stylesheet" href="/app.css">
</head>
<body>
<div class="app-toolbar">
<h1>Roast Planner</h1>
<button id="btn-toggle-prefill" type="button">Prefill from URL</button>
<button id="btn-toggle-alog" type="button">Reference curve (.alog)</button>
<span class="spacer"></span>
<button id="btn-load" type="button">Load plan</button>
<input id="file-load" type="file" accept="application/json">
<button id="btn-save" type="button">Download plan</button>
<button id="btn-print" type="button">Print</button>
<span class="status" id="autosave-status"></span>
</div>
<div class="panel hidden" id="panel-prefill">
<h3>Prefill from a bean product URL</h3>
<div class="row">
<input type="url" id="prefill-url" placeholder="https://roaster.example/shop/some-coffee">
<label><input type="checkbox" id="prefill-overwrite"> overwrite filled fields</label>
<button id="prefill-go" type="button">Fetch &amp; prefill</button>
<button id="prefill-undo" type="button" disabled>Undo prefill</button>
</div>
<div id="prefill-result"></div>
</div>
<div class="panel hidden" id="panel-alog">
<h3>Attach an Artisan .alog as a reference curve</h3>
<div class="row">
<label class="filebtn">Choose .alog file<input type="file" id="alog-file" accept=".alog"></label>
<button id="alog-library-refresh" type="button">Show local library</button>
</div>
<ul class="lib-list hidden" id="alog-library-list"></ul>
<div id="alog-result"></div>
</div>
<div class="sheet-wrap">
<div class="sheet">
<form id="plan-form">
<!-- ══════════════════ FRONT ══════════════════ -->
<section class="first">
<div class="wsbar">
<span class="t">Manual Roast Plan — Worksheet</span>
<span class="r">Sheet 1 of 2 · Plan | Hottop KN-8828B-2K+</span>
</div>
<div class="wsbox">
<div class="hd"><span class="id">THE COFFEE</span><span class="ref">[n.n] = field ID · cited everywhere it feeds a number</span></div>
<div class="bd wsline tightln">
<span class="fid">0.1</span><span class="lb">Coffee / lot</span> <input class="f ws-input" style="min-width:44mm" name="0.1"><span class="pv"></span>
<span class="sep">|</span><span class="fid">0.2</span><span class="lb">Date</span> <input class="f n ws-input" type="date" name="0.2"><span class="pv"></span>
<span class="sep">|</span><span class="fid">0.3</span><span class="lb">Batch&nbsp;#</span> <input class="f ws-input" style="min-width:10mm" name="0.3"><span class="pv"></span>
<span class="sep">|</span><span class="fid">0.4</span><span class="lb">Green in</span> <input class="f n ws-input" name="0.4">g<span class="pv"></span><br>
<span class="stepdot">1</span><span class="fid">1.1</span><span class="lb">Cultivar</span> <input class="f ws-input" style="min-width:30mm" name="1.1" list="cultivar-list"><span class="pv"></span>
<span class="sep">|</span><span class="fid">1.2</span><span class="lb">Group</span>
<span class="circ" data-radio-group="1.2">
<label class="opt"><input type="radio" name="1.2" value="typica"><span>Typica</span></label>
<label class="opt"><input type="radio" name="1.2" value="bourbon"><span>Bourbon</span></label>
<label class="opt"><input type="radio" name="1.2" value="ethiopian"><span>Ethiopian</span></label>
<label class="opt"><input type="radio" name="1.2" value="hybrid"><span>Hybrid</span></label>
</span>
<span class="sep">|</span><span class="fid">1.3</span><span class="lb">Origin</span> <input class="f ws-input" style="min-width:20mm" name="1.3"><span class="pv"></span><br>
<span class="fid" style="margin-left:4.6mm">1.4</span><span class="lb">FC anchor</span> <input class="f n ws-input" name="1.4"><span class="pv"></span>
<span class="sep">|</span><span class="fid">1.5</span><span class="lb">Profile mm:ss|mm:ss|mm:ss</span> <input class="f ws-input" style="min-width:22mm" name="1.5"><span class="pv"></span>
<span class="sep">|</span><small>your cultivar's row, Step 1 — not a group number</small><br>
<span class="fid" style="margin-left:4.6mm">1.6</span><span class="lb">± Refine → ledger 2</span> <input class="f n ws-input" name="1.6"><span class="pv"></span> <small>0 first cook, else Step 12</small>
<span class="sep">|</span><span class="fid">1.7</span><span class="lb">± Dev mod → ledger 9</span> <input class="f n ws-input" name="1.7"><span class="pv"></span> <small>Step 1's profile 3rd # 1:30</small><br>
<span class="stepdot">3</span><span class="fid">3.1</span><span class="lb">Process</span>
<span class="circ" data-radio-group="3.1">
<label class="opt"><input type="radio" name="3.1" value="washed"><span>washed</span></label>
<label class="opt"><input type="radio" name="3.1" value="yellow-honey"><span>yellow/white honey</span></label>
<label class="opt"><input type="radio" name="3.1" value="red-black-honey"><span>red/black honey</span></label>
<label class="opt"><input type="radio" name="3.1" value="natural"><span>natural</span></label>
<label class="opt"><input type="radio" name="3.1" value="anaerobic"><span>anaerobic/CM</span></label>
</span>
<span class="sep">|</span><span class="fid">3.2</span><span class="lb">Dev mod → ledger 8</span> <input class="f n ws-input" name="3.2"><span class="pv"></span> <small>Step 3 table</small><br>
<span class="stepdot">4</span><span class="fid">4.1</span><span class="lb">Roast level</span>
<span class="circ" data-radio-group="4.1">
<label class="opt"><input type="radio" name="4.1" value="light"><span>light</span></label>
<label class="opt"><input type="radio" name="4.1" value="light-medium"><span>light-med</span></label>
<label class="opt"><input type="radio" name="4.1" value="medium"><span>medium</span></label>
<label class="opt"><input type="radio" name="4.1" value="dark"><span>dark</span></label>
<label class="opt"><input type="radio" name="4.1" value="very-dark"><span>very dark</span></label>
</span>
<span class="sep">|</span><span class="fid">4.2</span><span class="lb">Target WL</span> <input class="f n ws-input" name="4.2">%<span class="pv"></span>
<span class="sep">|</span><span class="fid">4.3</span><span class="lb">Dev base → ledger 7</span> <input class="f n ws-input" style="min-width:12mm" name="4.3"><span class="pv"></span><br>
<span class="stepdot">5</span><span class="fid">5.1</span><span class="lb">Moisture</span> <input class="f n ws-input" name="5.1">%<span class="pv"></span>
<span class="sep">|</span><span class="fid">5.2</span><span class="lb">Density</span> <input class="f n ws-input" name="5.2">g/L<span class="pv"></span>
<span class="sep">|</span><span class="fid">5.3</span><span class="lb">Altitude</span> <input class="f n ws-input" name="5.3"><span class="pv"></span>
<span class="sep">|</span><span class="fid">5.4</span><span class="lb">Screen</span> <input class="f n ws-input" name="5.4"><span class="pv"></span>
<span class="sep">|</span><span class="fid">5.5</span><span class="lb">Sweet</span>
<span class="circ" data-radio-group="5.5">
<label class="opt"><input type="radio" name="5.5" value="narrow"><span>narrow</span></label>
<label class="opt"><input type="radio" name="5.5" value="med"><span>med</span></label>
<label class="opt"><input type="radio" name="5.5" value="wide"><span>wide</span></label>
</span><br>
<span class="fid" style="margin-left:4.6mm">5.6</span><span class="lb">± Net correction → ledger 3</span> <input class="f n ws-input" name="5.6"><span class="pv"></span> <small>judgment, rarely &gt;±0:15</small>
</div>
</div>
<div class="wsbox">
<div class="hd"><span class="n">2 · BLEND</span><span class="ref">skip if single-origin → Step 2</span></div>
<div class="bd">
<div class="wsline tightln">
<span class="fid">2.1</span>This lot is:
<span class="circ" data-radio-group="2.1">
<label class="opt"><input type="radio" name="2.1" value="single" checked><span>single-origin — skip this box</span></label>
<label class="opt"><input type="radio" name="2.1" value="blend"><span>blend or community lot</span></label>
</span>
</div>
<table class="tight">
<thead><tr><th><span class="fid">2.2</span>Component</th><th style="width:22mm">Group</th><th style="width:24mm">Process</th>
<th class="num" style="width:14mm">Share %</th><th class="num" style="width:20mm">FC anchor</th></tr></thead>
<tbody id="blend-rows"></tbody>
</table>
<div class="wsline tightln">
<span class="fid">2.3</span>Method:
<span class="circ" data-radio-group="2.3">
<label class="opt"><input type="radio" name="2.3" value="dominant"><span>dominant (≥60%)</span></label>
<label class="opt"><input type="radio" name="2.3" value="weighted"><span>weighted average</span></label>
<label class="opt"><input type="radio" name="2.3" value="split"><span>split-roast, blend after</span></label>
</span>
</div>
<div class="wsline tightln">
<span class="fid">2.4</span><span class="lb">Resulting FC anchor → ledger line 1</span> <input class="f n ws-input" name="2.4"><span class="pv"></span>
<span class="sep">|</span><span class="fid">2.5</span><span class="lb">Resulting processing modifier → ledger line 8</span> <input class="f n ws-input" name="2.5"><span class="pv"></span>
</div>
</div>
</div>
<div class="wsbox">
<div class="hd"><span class="n">6 · TIME LEDGER</span><span class="ref">method &amp; why → Step 6</span></div>
<div class="bd">
<table class="ledger">
<tr class="row"><td class="ln">1</td><td class="desc">Cultivar/blend anchor
<span class="sub">from 1.4, or 2.4 if blend</span></td><td class="val"><output data-out="l1"></output></td></tr>
<tr class="row"><td class="ln">2</td><td class="desc"><span class="op">±</span> Refinement — from 1.6
<span class="sub">0 first cook, else Step 12</span></td><td class="val"><output data-out="l2"></output></td></tr>
<tr class="row"><td class="ln">3</td><td class="desc"><span class="op">±</span> Bean condition — from 5.6</td><td class="val"><output data-out="l3"></output></td></tr>
<tr class="row"><td class="ln">4</td><td class="desc"><span class="op">±</span> Batch size vs. Step 9 reference weights
<span class="sub">225 g ≈ 1:302:00 later than 200 g</span></td><td class="val"><input class="f n ws-input" name="6.4" placeholder="0"><span class="pv"></span></td></tr>
<tr class="total"><td class="ln">A</td><td class="desc"><strong>FIRST CRACK</strong></td><td class="val"><output data-out="A"></output></td></tr>
<tr class="grp"><td class="ln"></td><td class="desc" colspan="2">B · YELLOW / MAILLARD — informational only. NOT summed into C.</td></tr>
<tr class="row"><td class="ln">5</td><td class="desc"><strong>YELLOW</strong> = A × 0.56</td><td class="val"><output data-out="yellow"></output></td></tr>
<tr class="row"><td class="ln">6</td><td class="desc"><strong>MAILLARD</strong> = A line 5</td><td class="val"><output data-out="maillard"></output></td></tr>
<tr class="grp"><td class="ln"></td><td class="desc" colspan="2">C · DEVELOPMENT — sum ONLY rows 7 + 8 + 9</td></tr>
<tr class="row"><td class="ln">7</td><td class="desc">Development base — from 4.3</td><td class="val"><output data-out="l7"></output></td></tr>
<tr class="row"><td class="ln">8</td><td class="desc"><span class="op">±</span> Processing modifier — from 3.2, or 2.5 if blend</td><td class="val"><output data-out="l8"></output></td></tr>
<tr class="row"><td class="ln">9</td><td class="desc"><span class="op">±</span> Cultivar dev modifier — from 1.7</td><td class="val"><output data-out="l9"></output></td></tr>
<tr class="total"><td class="ln">C</td><td class="desc"><strong>DEVELOPMENT</strong> = 7 + 8 + 9 only</td><td class="val"><output data-out="C"></output></td></tr>
<tr class="total"><td class="ln">D</td><td class="desc"><strong>DROP (end of roast)</strong> = A + C</td><td class="val"><output data-out="D"></output></td></tr>
</table>
</div>
</div>
<div class="wsbox">
<div class="hd"><span class="n">7 · SANITY CHECKS</span><span class="ref">a fail sends you back to box 6 → Step 7</span></div>
<div class="bd">
<table class="tight">
<thead><tr><th style="width:44mm">Check</th><th class="num" style="width:24mm">Should be</th>
<th class="num" style="width:24mm">Yours</th><th class="num" style="width:16mm">Pass?</th><th>Failure means</th></tr></thead>
<tbody>
<tr><td>Drying share</td><td class="num">4351 %</td><td class="num"><output data-out="check-drying"></output></td>
<td class="num passcell unknown" data-pass="drying"></td><td>high = late yellow · low = rushed</td></tr>
<tr><td>Maillard share</td><td class="num">3339 %</td><td class="num"><output data-out="check-maillard"></output></td>
<td class="num passcell unknown" data-pass="maillard"></td><td>low = too little browning</td></tr>
<tr><td>Development ratio</td><td class="num">1220 %</td><td class="num"><output data-out="check-dtr"></output></td>
<td class="num passcell unknown" data-pass="dtr"></td><td>under 12 % = under-developed</td></tr>
<tr><td>Development ceiling</td><td class="num">&lt; 4:30</td><td class="num"><output data-out="check-ceiling"></output></td>
<td class="num passcell unknown" data-pass="ceiling"></td><td>over 4:30 mutes any roast</td></tr>
</tbody>
</table>
</div>
</div>
</section>
<!-- ══════════════════ BACK ══════════════════ -->
<section>
<div class="wsbar">
<span class="t">Roast &amp; Record</span>
<span class="r">Sheet 2 of 2 | coffee: <span id="back-coffee-name"></span></span>
</div>
<div class="wsbox">
<div class="hd"><span class="n">8 · TEMPERATURES &amp; RATE-OF-RISE</span><span class="ref">→ Step 8</span></div>
<div class="bd">
<table class="tight">
<thead><tr><th style="width:28mm">Milestone</th><th class="num" style="width:20mm">Time</th>
<th class="num" style="width:18mm">°C</th><th class="num" style="width:36mm">Your logged band</th></tr></thead>
<tbody>
<tr><td>Charge</td><td class="num"><output data-out="t-charge">0:00</output></td>
<td class="num"><input class="f n ws-input" name="temps.charge.tempC"><span class="pv"></span></td><td class="num">133195 °C</td></tr>
<tr><td>Turning point</td><td class="num"><input class="f n ws-input" name="temps.tp.time" placeholder="m:ss"><span class="pv"></span></td>
<td class="num"><input class="f n ws-input" name="temps.tp.tempC"><span class="pv"></span></td><td class="num">77100 °C @ 0:471:15</td></tr>
<tr><td>Yellow</td><td class="num"><output data-out="t-yellow"></output></td>
<td class="num"><input class="f n ws-input" name="temps.yellow.tempC"><span class="pv"></span></td><td class="num">148166 °C</td></tr>
<tr><td>First crack</td><td class="num"><output data-out="t-fc"></output></td>
<td class="num"><input class="f n ws-input" name="temps.fc.tempC"><span class="pv"></span></td><td class="num">176187 °C</td></tr>
<tr><td>Drop</td><td class="num"><output data-out="t-drop"></output></td>
<td class="num"><input class="f n ws-input" name="temps.drop.tempC"><span class="pv"></span></td><td class="num">183197 °C light</td></tr>
</tbody>
</table>
</div>
</div>
<div class="wsbox">
<div class="hd"><span class="n">9 · ACTUATOR SCHEDULE (planned)</span><span class="ref">→ Step 9</span></div>
<div class="bd">
<table class="tight">
<thead><tr><th class="num" style="width:20mm">Time</th><th class="num" style="width:18mm">Heat %</th>
<th class="num" style="width:18mm">Fan %</th><th class="num" style="width:26mm">Expected BT</th><th>Why this change</th></tr></thead>
<tbody id="actuator-rows"></tbody>
</table>
</div>
</div>
<div class="wsbox wsgrid">
<div class="hd"><span class="n">10 · THE CURVE</span><span class="ref">plan drawn live · reference from an .alog if attached → Step 10</span></div>
<div class="bd">
<div class="grid-wrap">
<svg id="curve-svg" viewBox="0 0 714 334" width="100%" role="img" aria-label="Roast curve plotting grid">
<defs><style>
.maj{stroke:#8b8078;stroke-width:.7} .min{stroke:#e2dad2;stroke-width:.45}
.ax{stroke:#1a1512;stroke-width:1.3} .al{font-size:8px;fill:#5a5048}
.alr{font-size:8px;fill:#7a3b12} .band{fill:#7a3b12;opacity:.05}
.ttl{font-size:8px;font-weight:700;fill:#1a1512;letter-spacing:.5px}
</style></defs>
<rect x="52" y="24" width="600" height="270" fill="#fff"/>
<rect class="band" x="52" y="65.4" width="600" height="19.8"/>
<text x="58" y="62.4" class="alr" style="font-size:7px">your first-crack band, 176187 °C</text>
<g class="min">
<line x1="72" y1="24" x2="72" y2="294"/><line x1="112" y1="24" x2="112" y2="294"/>
<line x1="152" y1="24" x2="152" y2="294"/><line x1="192" y1="24" x2="192" y2="294"/>
<line x1="232" y1="24" x2="232" y2="294"/><line x1="272" y1="24" x2="272" y2="294"/>
<line x1="312" y1="24" x2="312" y2="294"/><line x1="352" y1="24" x2="352" y2="294"/>
<line x1="392" y1="24" x2="392" y2="294"/><line x1="432" y1="24" x2="432" y2="294"/>
<line x1="472" y1="24" x2="472" y2="294"/><line x1="512" y1="24" x2="512" y2="294"/>
<line x1="552" y1="24" x2="552" y2="294"/><line x1="592" y1="24" x2="592" y2="294"/>
<line x1="632" y1="24" x2="632" y2="294"/>
</g>
<g class="maj">
<line x1="92" y1="24" x2="92" y2="294"/><line x1="132" y1="24" x2="132" y2="294"/>
<line x1="172" y1="24" x2="172" y2="294"/><line x1="212" y1="24" x2="212" y2="294"/>
<line x1="252" y1="24" x2="252" y2="294"/><line x1="292" y1="24" x2="292" y2="294"/>
<line x1="332" y1="24" x2="332" y2="294"/><line x1="372" y1="24" x2="372" y2="294"/>
<line x1="412" y1="24" x2="412" y2="294"/><line x1="452" y1="24" x2="452" y2="294"/>
<line x1="492" y1="24" x2="492" y2="294"/><line x1="532" y1="24" x2="532" y2="294"/>
<line x1="572" y1="24" x2="572" y2="294"/><line x1="612" y1="24" x2="612" y2="294"/>
</g>
<g class="min">
<line x1="52" y1="276" x2="652" y2="276"/><line x1="52" y1="240" x2="652" y2="240"/>
<line x1="52" y1="204" x2="652" y2="204"/><line x1="52" y1="168" x2="652" y2="168"/>
<line x1="52" y1="132" x2="652" y2="132"/><line x1="52" y1="96" x2="652" y2="96"/>
<line x1="52" y1="60" x2="652" y2="60"/>
</g>
<g class="maj">
<line x1="52" y1="258" x2="652" y2="258"/><line x1="52" y1="222" x2="652" y2="222"/>
<line x1="52" y1="186" x2="652" y2="186"/><line x1="52" y1="150" x2="652" y2="150"/>
<line x1="52" y1="114" x2="652" y2="114"/><line x1="52" y1="78" x2="652" y2="78"/>
<line x1="52" y1="42" x2="652" y2="42"/>
</g>
<line class="ax" x1="52" y1="24" x2="52" y2="294"/>
<line class="ax" x1="52" y1="294" x2="652" y2="294"/>
<line class="ax" x1="652" y1="24" x2="652" y2="294"/>
<g class="al" text-anchor="end">
<text x="47" y="296.8">60</text><text x="47" y="260.8">80</text><text x="47" y="224.8">100</text>
<text x="47" y="188.8">120</text><text x="47" y="152.8">140</text><text x="47" y="116.8">160</text>
<text x="47" y="80.8">180</text><text x="47" y="44.8">200</text>
</g>
<text x="14" y="159" class="ttl" transform="rotate(-90 14 159)" text-anchor="middle">BEAN TEMP °C</text>
<g class="al" text-anchor="middle">
<text x="52" y="304">0:00</text><text x="92" y="304">1:00</text><text x="132" y="304">2:00</text>
<text x="172" y="304">3:00</text><text x="212" y="304">4:00</text><text x="252" y="304">5:00</text>
<text x="292" y="304">6:00</text><text x="332" y="304">7:00</text><text x="372" y="304">8:00</text>
<text x="412" y="304">9:00</text><text x="452" y="304">10:00</text><text x="492" y="304">11:00</text>
<text x="532" y="304">12:00</text><text x="572" y="304">13:00</text><text x="612" y="304">14:00</text>
<text x="652" y="304">15:00</text>
</g>
<text x="368" y="320" style="font-size:8px;fill:#5a5048">TIME FROM CHARGE · solid = plan · dashed = reference (.alog)</text>
<g id="plan-curve"></g>
<g id="ref-curve"></g>
</svg>
</div>
</div>
</div>
<div class="wsbox">
<div class="hd"><span class="n">11 · AT THE MACHINE — PLAN vs ACTUAL</span><span class="ref">→ Step 11</span></div>
<div class="bd">
<table class="tight">
<thead><tr><th style="width:28mm">Milestone</th><th class="num" style="width:20mm">Plan time</th>
<th class="num" style="width:22mm">Actual time</th><th class="num" style="width:18mm">Actual BT</th><th>Note</th></tr></thead>
<tbody>
<tr><td>Charge</td><td class="num"><output data-out="pa-charge">0:00</output></td>
<td class="num"><input class="f n ws-input" name="planActual.charge.actualTime" placeholder="0:00"><span class="pv"></span></td>
<td class="num"><input class="f n ws-input" name="planActual.charge.actualBt"><span class="pv"></span></td>
<td><input class="f ws-input" style="min-width:52mm" name="planActual.charge.note"><span class="pv"></span></td></tr>
<tr><td>Turning point</td><td class="num"><output data-out="pa-tp"></output></td>
<td class="num"><input class="f n ws-input" name="planActual.tp.actualTime"><span class="pv"></span></td>
<td class="num"><input class="f n ws-input" name="planActual.tp.actualBt"><span class="pv"></span></td>
<td><input class="f ws-input" style="min-width:52mm" name="planActual.tp.note"><span class="pv"></span></td></tr>
<tr><td>Yellow</td><td class="num"><output data-out="pa-yellow"></output></td>
<td class="num"><input class="f n ws-input" name="planActual.yellow.actualTime"><span class="pv"></span></td>
<td class="num"><input class="f n ws-input" name="planActual.yellow.actualBt"><span class="pv"></span></td>
<td><input class="f ws-input" style="min-width:52mm" name="planActual.yellow.note"><span class="pv"></span></td></tr>
<tr><td>First crack</td><td class="num"><output data-out="pa-fc"></output></td>
<td class="num"><input class="f n ws-input" name="planActual.fc.actualTime"><span class="pv"></span></td>
<td class="num"><input class="f n ws-input" name="planActual.fc.actualBt"><span class="pv"></span></td>
<td><input class="f ws-input" style="min-width:52mm" name="planActual.fc.note"><span class="pv"></span></td></tr>
<tr><td>Drop</td><td class="num"><output data-out="pa-drop"></output></td>
<td class="num"><input class="f n ws-input" name="planActual.drop.actualTime"><span class="pv"></span></td>
<td class="num"><input class="f n ws-input" name="planActual.drop.actualBt"><span class="pv"></span></td>
<td><input class="f ws-input" style="min-width:52mm" name="planActual.drop.note"><span class="pv"></span></td></tr>
</tbody>
</table>
</div>
</div>
<div class="wsbox">
<div class="hd"><span class="n">12 · AFTER THE ROAST</span><span class="ref">→ Step 12</span></div>
<div class="bd wsline tightln">
<span class="lb">Green in</span> <input class="f n ws-input" name="afterRoast.greenIn"><span class="pv"></span>g
<span class="sep">|</span><span class="lb">Out</span> <input class="f n ws-input" name="afterRoast.out"><span class="pv"></span>g
<span class="sep">|</span><span class="lb">Weight loss</span> <input class="f n ws-input" name="afterRoast.weightLossPct"><span class="pv"></span>%
<span class="sep">|</span><span class="lb">Actual DTR</span> <input class="f n ws-input" name="afterRoast.actualDtrPct"><span class="pv"></span>%<br>
<span class="lb">Colour WB/GR</span> <input class="f ws-input" name="afterRoast.colour"><span class="pv"></span>
<span class="sep">|</span><span class="lb">Rested</span> <input class="f n ws-input" name="afterRoast.restedDays"><span class="pv"></span>days
<span class="sep">|</span><span class="lb">Brew ratio</span> <input class="f ws-input" name="afterRoast.brewRatio"><span class="pv"></span>
<span class="sep">|</span><span class="lb">Method</span> <input class="f w ws-input" name="afterRoast.method"><span class="pv"></span><br>
<span class="lb">Cup notes</span> <input class="f xw ws-input" style="min-width:152mm" name="afterRoast.cupNotes"><span class="pv"></span><br>
<span class="lb" style="color:var(--accent)">One change next batch</span> <input class="f ws-input" style="min-width:58mm" name="afterRoast.oneChange"><span class="pv"></span>
<span class="sep">|</span><span class="lb">What would prove it wrong</span> <input class="f ws-input" style="min-width:34mm" name="afterRoast.disproof"><span class="pv"></span>
</div>
</div>
</section>
</form>
</div>
</div>
<datalist id="cultivar-list"></datalist>
<script type="module" src="/js/main.js"></script>
</body>
</html>