S17 integration: apply C's offerBand hunk — the board stops lying about night 7 (hail on every offer card)

This commit is contained in:
type-two 2026-07-21 06:25:14 +10:00
parent 8edf461286
commit 9498dfc1b9
2 changed files with 18 additions and 4 deletions

View File

@ -331,6 +331,11 @@ const CSS = `
#hud-card .offer .line { display:flex; justify-content:space-between; gap:14px;
font-size:12px; color:#8ba0ad; padding:2px 0; }
#hud-card .offer .line b { color:#dde5ea; font-weight:700; }
/* SPRINT17 [C]: the weather band. The hail line is lit brighter than the rest
because the soaker's whole trap is that its wind reads gentle the one line
a player must not skim past. */
#hud-card .offer .line.wx { color:#8ba0ad; }
#hud-card .offer .line.hail span { color:#cbd8e0; }
/* The two numbers a tradie decides on. The fee is the reason to say yes and
the exposure is the reason to say no, so they are weighted against each
other rather than both being grey: money in, money at risk. */
@ -816,14 +821,17 @@ export function createHud(d) {
const offerHtml = (o, i) => {
const n = o.night;
const cons = o.constraints ?? [];
const f = o.forecast;
// SPRINT17 [C], applied by the integrator: the offer maps C's ORDERED
// band (wind · hail · rain · change · confidence) instead of picking
// two forecast fields, so an offer card can never hide a night's hail.
// The .hail line is lit brighter because it is the one a player must
// not skim past — the soaker's whole trap is a gentle-reading wind.
return `
<button class="offer${cons.length ? ' constrained' : ''}" data-offer="${i}">
<span class="tag">${o.kind === 'scripted' ? 'tonight, as booked' : 'callout'}</span>
<div class="who">${n.client ?? 'no client'}</div>
<div class="addr">${n.addr ?? ''}</div>
${f?.wind ? `<div class="line"><span>${f.wind}</span></div>` : ''}
${f?.stones ? `<div class="line"><span>${f.stones}</span></div>` : ''}
${(o.band ?? []).map((l) => `<div class="line wx ${l.key}"><span>${l.text}</span></div>`).join('')}
${o.fee != null ? `<div class="line fee"><span>the job pays${
o.premium ? ` · +${Math.round(o.premium * 100)}% on their terms` : ''
}</span><b>$${o.fee}</b></div>` : ''}

View File

@ -17,7 +17,7 @@ import * as THREE from '../vendor/three.module.js';
import { FIXED_DT, PHASES, STORM_LEN, HARDWARE, SPARE_COST, Emitter } from './contracts.js';
import { createWorld, loadSite } from './world.js';
import { createCameraRig, spawnYawFor } from './camera.js';
import { loadStorm, createWind, forecastLines } from './weather.js';
import { loadStorm, createWind, forecastLines, offerBand } from './weather.js';
import { SailRig, createSailView } from './sail.js';
import { createPlayer } from './player.js';
import { Interact, wireYardActions } from './interact.js';
@ -1041,6 +1041,12 @@ export async function boot(opts = {}) {
// C's honest lines at lead 0 — tonight, exact. The same call the job
// sheet makes, so the board can never be more confident than the sheet.
forecast: def ? forecastLines(def, 0) : null,
// SPRINT17 [C], applied by the integrator: the ORDERED band the offer
// card maps, so a night's hail can never be dropped by the card picking
// two fields. Night 7 read softer than the buster on wind+stones alone
// (55 vs 76 km/h) while carrying 6× the hail — the board recommending
// its own trap. offerBand carries every fact the storm has.
band: def ? offerBand(def, 0) : null,
fee: def ? calloutFee(def, week.rep, night.constraints) : null,
exposure: exp.total,
exposureItems: exp.items,