Author SHA1 Message Date
Eric WagonerandClaude Fable 5 4354a1860f Rules divide the checkbox stanza only
Between checkboxed rows and nowhere else — no frame above or below
the stanza, none around the control rows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 15:53:17 -04:00
Eric WagonerandClaude Fable 5 4e93a77e8d The preferences read as a ruled ledger
Rows rule apart with the games ledger's own brown line, fill the
panel's width so the checkbox column aligns, and control rows
right-justify their controls opposite their labels.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 15:51:40 -04:00
Eric WagonerandClaude Fable 5 bdfe357429 Preferences wear the table's ink; hand-drawn becomes alternate
The native checkboxes clashed with the parchment: they are now
stamp-bordered boxes checked solid with a parchment tick, and their
labels rag left with the box instead of centering. The token-art
toggle's second option reads "alternate".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 15:47:27 -04:00
Eric WagonerandClaude Fable 5 e4a93ec3aa Forfeit legs earn no scolding (from the FPV playtest)
Picking up an object ends the turn's actions and movement, yet the
end-turn caution still tallied the unspendable points as a regret.
The unspent-movement reason now stays quiet once actions have ended.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 13:56:11 -04:00
+52 -9
View File
@@ -955,8 +955,10 @@
if (view && me) { if (view && me) {
const left = view.turn.movementAllowance - view.turn.movementUsed; const left = view.turn.movementAllowance - view.turn.movementUsed;
// Unspent legs are no regret when the walk ended ON someone's gold — // Unspent legs are no regret when the walk ended ON someone's gold —
// stopping there was the point. // stopping there was the point — nor when a pickup or drop already
if (left > 0 && !treasuresHere.some((t) => t.owner !== view.you)) { // forfeited them: those points cannot be spent, only mourned.
if (left > 0 && !view.turn.actionsEnded &&
!treasuresHere.some((t) => t.owner !== view.you)) {
reasons.push(`${left} movement point${left === 1 ? "" : "s"} unspent`); reasons.push(`${left} movement point${left === 1 ? "" : "s"} unspent`);
} }
const limit = me.displayed.some((c) => c.cardId === "brainstone") ? 9 : 7; const limit = me.displayed.some((c) => c.cardId === "brainstone") ? 9 : 7;
@@ -1381,24 +1383,24 @@
<button class="stamp tiny" class:lit={prefs.art === "photo"} <button class="stamp tiny" class:lit={prefs.art === "photo"}
onclick={() => setPref("art", "photo")}>cardboard</button> onclick={() => setPref("art", "photo")}>cardboard</button>
<button class="stamp tiny" class:lit={prefs.art === "drawn"} <button class="stamp tiny" class:lit={prefs.art === "drawn"}
onclick={() => setPref("art", "drawn")}>hand-drawn</button> onclick={() => setPref("art", "drawn")}>alternate</button>
</div> </div>
<label class="pref-row"> <label class="pref-row pref-check">
<input type="checkbox" checked={prefs.autoGrab} <input type="checkbox" checked={prefs.autoGrab}
onchange={(e) => setPref("autoGrab", e.currentTarget.checked)} /> onchange={(e) => setPref("autoGrab", e.currentTarget.checked)} />
<span>Ending my turn on a lone treasure picks it up (never on my own home)</span> <span>Ending my turn on a lone treasure picks it up (never on my own home)</span>
</label> </label>
<label class="pref-row"> <label class="pref-row pref-check">
<input type="checkbox" checked={prefs.flourishes} <input type="checkbox" checked={prefs.flourishes}
onchange={(e) => setPref("flourishes", e.currentTarget.checked)} /> onchange={(e) => setPref("flourishes", e.currentTarget.checked)} />
<span>Spell flourishes (the animated effects)</span> <span>Spell flourishes (the animated effects)</span>
</label> </label>
<label class="pref-row"> <label class="pref-row pref-check">
<input type="checkbox" checked={prefs.instantReplay} <input type="checkbox" checked={prefs.instantReplay}
onchange={(e) => setPref("instantReplay", e.currentTarget.checked)} /> onchange={(e) => setPref("instantReplay", e.currentTarget.checked)} />
<span>Instant replay: notable chronicle lines offer a 👁 that relives the turn</span> <span>Instant replay: notable chronicle lines offer a 👁 that relives the turn</span>
</label> </label>
<label class="pref-row"> <label class="pref-row pref-check">
<input type="checkbox" checked={prefs.cautions} <input type="checkbox" checked={prefs.cautions}
onchange={(e) => setPref("cautions", e.currentTarget.checked)} /> onchange={(e) => setPref("cautions", e.currentTarget.checked)} />
<span>Ask "are you sure?" before easy-to-regret plays (unspent movement, capped draws, undropped deliveries)</span> <span>Ask "are you sure?" before easy-to-regret plays (unspent movement, capped draws, undropped deliveries)</span>
@@ -2793,11 +2795,52 @@
.pref-row { .pref-row {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.6rem;
margin: 0.55rem 0; width: 100%;
box-sizing: border-box;
margin: 0;
padding: 0.55rem 0.1rem;
font-size: 0.85rem; font-size: 0.85rem;
color: #43331f; color: #43331f;
text-align: left;
cursor: pointer;
} }
/* Rules divide the checkbox stanza only — never framing it, never
around the control rows. */
.pref-check + .pref-check { border-top: 1.5px solid #6b5a41; }
/* Checkboxes wear the table's own ink: a stamp-bordered box, checked
solid with a parchment tick — the native widget never matches the
parchment. */
.pref-row input[type="checkbox"] {
appearance: none;
flex: none;
width: 1.05rem;
height: 1.05rem;
border: 1.5px solid #43331f;
border-radius: 3px;
background: #f6efdd;
cursor: pointer;
display: grid;
place-content: center;
margin: 0;
}
.pref-row input[type="checkbox"]:checked {
background: #43331f;
}
.pref-row input[type="checkbox"]:checked::before {
content: "✓";
color: #f6efdd;
font-size: 0.8rem;
line-height: 1;
font-weight: 700;
}
.pref-row span { flex: 1; }
/* Control rows read as a two-column table: the label holds the left
column, its controls right-align into the second. */
.pref-row > span:first-child { flex: 0 1 auto; }
.pref-row > span:first-child + .stamp,
.pref-row > span:first-child + input,
.pref-row > span:first-child + .pref-swatch { margin-left: auto; }
.pref-note { font-size: 0.72rem; color: #8a7a5e; margin-top: 0.6rem; } .pref-note { font-size: 0.72rem; color: #8a7a5e; margin-top: 0.6rem; }
.pref-name { max-width: 11rem; } .pref-name { max-width: 11rem; }
.pref-swatch { .pref-swatch {