diff --git a/THREADS.md b/THREADS.md index a17fec3..7619718 100644 --- a/THREADS.md +++ b/THREADS.md @@ -3966,3 +3966,46 @@ anchors are your GLB), but the tooling is now waiting, not TODO. Β· **gate 3 β John plays the week. FIVE sprints standing, and for the first time the excuse is gone: the week is playable end to end.** Β§BROKE_BELOW watch: if the bank runs away, A's declared first cut is the $20 clean bonus, not feeFor/gardenBonusMax. + +[A] 2026-07-17 β π **E's letterhead/invoice kit is PASTED (SPRINT12 gate 3.1), and both rulings are made.** + The CUT block went into hud.js verbatim β CSS and markup shape both β replacing my Sprint 11 + placeholder rules that were holding the seat for exactly this. `.void` survives, exactly as E built + it: the forfeited clean bonus renders struck-through at the QUOTED amount, not zeroed and not + hidden. Both documents now carry the same letterhead and share a docket number (JOB 1043's morning + is INV 1043; `docketNo = 1040 + night`), the client moved into E's bill-to block, and week.js grew + an `addr` per night ("14 Kurrajong St β the backyard" / "2 Bight Rd β the corner block") because a + letterhead bills somebody somewhere. AMOUNT DUE landed with it: pay β spent, 20px, red when + negative β the invoice finally has a conclusion, and the bank line under it stays because "what the + night was worth" and "where that leaves you" are different facts. Both terms lines shipped; the + invoice's collateral variant amended from E's "back up by Thursday" to "made right by Friday" so it + reads against any broken thing and lands on the Hendersons' return day. + + **RULING β the masthead is HARD YARDS, adopted as proposed.** E's reasoning holds on all three + legs: it's the game's own joke ("nobody thanks you for the storm that did nothing" IS the hard + yards), it's literally about yards, and it's one word at letterhead size. Their caveat is adopted + with it: if a future sprint names the player, a surname mark is the better answer and one constant + changes. Not renaming the outfit in a juice pass either. + + **RULING β the ABN stays sequential, and this is now pinned by an assert.** Any plausible 11-digit + number is potentially a real business's tax identity; sequential digits read as "example" the way + 555 numbers do. Deliberate, not lazy β a.test now FAILS if someone "fixes" it realistic. + + Two things the paste taught, both logged as warnings elsewhere and both ignored by me anyway: + Β· **The card CSS is a template literal and I put backticks in a comment** ("engines that don't + know `safe`"). node --check PASSED β the stray pair re-paired with a later literal into + accidentally-valid JS β and the browser's import of hud.js died on "Unexpected identifier + 'safe'", which took boot down with it. The dawn block's own comment has warned about exactly + this since E wrote it. Caught by the browser, not the linter; `node -e "import(...)"` is the + honest check and --check is not. + Β· **E's kit made the tall cards taller than a short window** β at 800Γ450 the RIG IT button was + below the fold of an unscrollable overlay, a soft-lock with good typography. #hud-card is now + `place-items:safe center` + `overflow-y:auto` (plain `center` clips BOTH ends of overflow; the + un-safe value stays above it as fallback). Seen in the pane, invisible to every assert. + + Verified by LOOKING, per the standing rule: job sheet night 1 and the carport invoice both rendered + in the browser against E's four preview PNGs β letterhead, bill-to, struck $20, red β$130 due, + terms lines, all there. Plus two new a.test DOM renders asserting the kit's load-bearing pieces + (mark, docket, sequential ABN, .void at quoted amount WITH line-through actually drawing, due + arithmetic, neg class) β because both of last sprint's card bugs were invisible to a suite that + never rendered a card. hud.dispose() also stops leaking the dawn div. selftest **317/0/0** + (315 + the two card renders). diff --git a/web/world/js/hud.js b/web/world/js/hud.js index 2bbb6e7..4e1f2de 100644 --- a/web/world/js/hud.js +++ b/web/world/js/hud.js @@ -20,6 +20,33 @@ import { forecastLines, leadFor } from './weather.js'; const clamp01 = (v) => (v < 0 ? 0 : v > 1 ? 1 : v); const kmh = (ms) => ms * 3.6; +/** + * SPRINT12 gate 3 β the letterhead, and the two rulings E left with it + * (tools/jobsheet/index.html; full reasoning in THREADS [A]). + * + * RULING 1 β the masthead is HARD YARDS, adopted as proposed. It's the joke the + * game already tells ("nobody thanks you for the storm that did nothing") said + * as a business name, it's literally about yards, and it's one mark at + * letterhead size. E's own caveat stands with it: the day the player gets a + * name, a surname mark is the better answer, and this constant is the only + * thing that changes. + * + * RULING 2 β the ABN stays sequential, exactly as E shipped it. Any plausible + * 11-digit number is potentially a REAL business's tax identity, and we are not + * printing a stranger's ABN on a game card. Sequential digits read as "example" + * the way 555 phone numbers do β deliberate, not lazy. DO NOT "fix" this into + * something realistic; that is the bug, not the polish. + */ +const BUSINESS = { mark: 'HARD YARDS', trade: 'landscaping Β· shade Β· drainage' }; +const ABN = 'ABN 12 345 678 901'; + +/** + * Docket numbers. 1040 + night: a running count off a small outfit's pad, and + * the job sheet and its invoice share the number β JOB 1043's morning is + * INV 1043, which is how the two documents answer each other line for line. + */ +const docketNo = (night) => 1040 + night; + // Load bar colours: green β amber β red. The amber band is deliberately wide; // a corner at 60% in a lull is one gust from 100% and the player should feel // that before the bar turns red on them. @@ -49,11 +76,19 @@ const CSS = ` color:#93a6b2; opacity:.85; white-space:nowrap; } #hud-card { position:fixed; inset:0; z-index:30; display:none; place-items:center; + /* SPRINT12: E's letterhead + brief + conditions made the tall cards taller + than a short window, and a RIG IT button below the fold with no scroll is a + soft-lock with good typography. 'safe center' keeps the top reachable when + the card overflows (plain 'center' clips BOTH ends); the value above is the + fallback for engines that don't know 'safe'. Seen, not reasoned: the button + was gone at 800x450. (And no backticks in this comment β this whole CSS + block is a JS template literal, as the dawn block already warns.) */ + place-items:safe center; overflow-y:auto; background:#060a0dc4; backdrop-filter:blur(3px); font:13px/1.7 ui-monospace,SFMono-Regular,Menlo,monospace; color:#dde5ea; } #hud-card.on { display:grid; } #hud-card .card { background:#0d1418; border:1px solid #2f3f4a; border-radius:9px; - padding:22px 26px; min-width:440px; max-width:620px; pointer-events:auto; } + padding:22px 26px; margin:20px 0; min-width:440px; max-width:620px; pointer-events:auto; } #hud-card h1 { margin:0 0 2px; font-size:19px; letter-spacing:.16em; color:#fff; } #hud-card h2 { margin:0 0 16px; font-size:12px; font-weight:400; color:#8ba0ad; letter-spacing:.04em; } #hud-card .row { display:flex; justify-content:space-between; gap:18px; padding:3px 0; @@ -84,22 +119,126 @@ const CSS = ` #hud-card .ledger .row.total { margin-top:6px; padding-top:8px; border-top:1px solid #24343d; } #hud-card .ledger .row.total b { color:#fff; } -/* SPRINT11 β the job sheet and the invoice. STRUCTURE ONLY, deliberately: the - letterhead and the invoice styling are Lane E's this sprint (Β§gate 2), and - everything below is the plainest thing that reads correctly so E can restyle - it without unpicking layout. The class names are the contract β .letterhead, - .brief, .jobsheet, .tomorrow β and E owns what they look like. */ -#hud-card .letterhead { display:flex; justify-content:space-between; align-items:baseline; - margin:-4px 0 10px; padding-bottom:8px; border-bottom:1px solid #24343d; - font-size:12px; letter-spacing:.18em; text-transform:uppercase; color:#7ee0ff; } -#hud-card .letterhead .inv { color:#8ba0ad; letter-spacing:.1em; } -#hud-card .brief { margin:10px 0 12px; padding:9px 11px; border-left:2px solid #2f3f4a; - background:#101a20; color:#c3d2da; font-size:13px; line-height:1.55; font-style:italic; } -#hud-card .jobsheet { margin-top:12px; padding-top:10px; border-top:1px solid #24343d; } -#hud-card .jobsheet .row b { color:#a8f0b8; } -#hud-card .jobsheet .row.total { margin-top:6px; padding-top:8px; border-top:1px solid #24343d; } -#hud-card .jobsheet .row.total b { color:#fff; } -/* Tomorrow is a rumour, and it should look like one next to tonight's numbers. */ +/* SPRINT12 β E's letterhead/invoice kit, pasted from tools/jobsheet/index.html + (between the CUT markers, verbatim). Sprint 11's placeholder rules for + .letterhead/.brief are gone β E designed against those class names and this + is the styling they were holding the seat for. E's design commentary kept: + the reasoning is why the rules look like this. */ + +/* --- the letterhead ---------------------------------------------------- + One business, two documents. This is the whole trick of the sprint: the + job sheet and the invoice carry the SAME letterhead, so they read as a + pair of papers off the same outfit's printer rather than as two game + screens. The player's business is the constant; the client changes every + night. That's the framing DESIGN.md opens with β "you run a small + landscaping outfit" β finally showing up on the glass. + + Sits above the existing .card content, inside the same .card box. */ +#hud-card .letterhead { + display: flex; align-items: baseline; justify-content: space-between; + gap: 16px; margin: -4px 0 14px; padding-bottom: 10px; + border-bottom: 2px solid #2f3f4a; +} +#hud-card .letterhead .mark { + font-weight: 800; font-size: 15px; letter-spacing: .22em; color: #fff; + white-space: nowrap; +} +/* The trade line does the work a logo would. Lowercase and spaced out so it + reads as printed rule, not as a heading competing with the mark. */ +#hud-card .letterhead .trade { + font-size: 10px; letter-spacing: .13em; color: #6d818e; margin-top: 3px; +} +#hud-card .letterhead .docket { text-align: right; white-space: nowrap; } +#hud-card .letterhead .docket .kind { + font-weight: 700; font-size: 11px; letter-spacing: .18em; color: #8ba0ad; +} +#hud-card .letterhead .docket .no { font-size: 10px; color: #55677a; letter-spacing: .06em; } + +/* --- bill-to / job-for block ------------------------------------------- + Deliberately the same component on both documents. On the job sheet it's + who you're working for; on the invoice it's who's paying. Same box, and + the fact that it doesn't move between the two is the joke landing. */ +#hud-card .billto { margin: 0 0 12px; } +#hud-card .billto .who { font-weight: 700; color: #fff; letter-spacing: .04em; } +#hud-card .billto .addr { font-size: 11px; color: #6d818e; } + +/* --- the brief --------------------------------------------------------- + The client's own words. Italic and rule-marked because it is the one bit + of text on the card that isn't the game talking to the player β it's a + person who wants their seedlings alive. It should feel quoted, and it + should be the thing the player's eye lands on after the letterhead, + because it is the only place the stakes are ever said out loud. */ +#hud-card .brief { + margin: 0 0 14px; padding: 9px 0 9px 12px; + border-left: 2px solid #3f5561; + color: #c3d0d9; font-style: italic; line-height: 1.6; +} +#hud-card .brief .attrib { + display: block; margin-top: 5px; font-style: normal; + font-size: 10px; letter-spacing: .1em; color: #55677a; +} + +/* --- section rules ------------------------------------------------------ */ +#hud-card .sect { + margin: 16px 0 7px; font-size: 10px; font-weight: 700; letter-spacing: .18em; + color: #55677a; border-bottom: 1px solid #1c262d; padding-bottom: 5px; +} + +/* --- the pay schedule (job sheet) -------------------------------------- + This is a QUOTE, not a receipt: it's what the night is worth if you do it + right. It reuses your .row shape so it lines up with everything else, but + the money is dimmed β these are amounts you have NOT earned yet, and they + should not read with the same confidence as the bank line. The conditions + are the point; the numbers are just what the conditions are worth. */ +#hud-card .sched .row b { color: #9fb3bf; font-weight: 700; } +#hud-card .sched .cond { + font-size: 10px; color: #55677a; letter-spacing: .02em; + padding: 0 0 5px; border-bottom: 1px solid #1c262d; margin-top: -2px; +} +#hud-card .sched .row.headline b { color: #fff; } +#hud-card .sched .row.max { border-bottom: 0; margin-top: 6px; padding-top: 7px; + border-top: 1px solid #24343d; } +#hud-card .sched .row.max span { color: #8ba0ad; } +#hud-card .sched .row.max b { color: #ffd9a3; } + +/* --- the invoice ------------------------------------------------------- + Your .ledger already IS an invoice; it just never said so. These rules sit + ON TOP of it β paste them and .ledger keeps every behaviour it has, it + just gains a rule above the total and a due line under it. + + .earned/.bad you already colour. The one thing I've added is .void: a + bonus that was on the job sheet and did NOT survive the night. Struck + through, not hidden. The player must see the money they didn't get sitting + in the same column as the money they did β a bonus you never see fail is a + bonus you never learn to protect. This is the single highest-value line in + the whole handover, and it's four CSS declarations. */ +#hud-card .ledger .row.void span { color: #55677a; } +#hud-card .ledger .row.void b { + color: #55677a; font-weight: 400; text-decoration: line-through; + text-decoration-color: #7d2b2b; text-decoration-thickness: 1px; +} +/* The amount due. An invoice's whole rhetorical shape is that everything + above is argument and this is the conclusion. Give it the weight. */ +#hud-card .ledger .row.due { + margin-top: 8px; padding-top: 9px; border-top: 2px solid #2f3f4a; border-bottom: 0; + align-items: baseline; +} +#hud-card .ledger .row.due span { color: #8ba0ad; letter-spacing: .12em; font-weight: 700; + font-size: 11px; } +#hud-card .ledger .row.due b { color: #fff; font-size: 20px; letter-spacing: .02em; } +#hud-card .ledger .row.due.neg b { color: #ff8f86; } + +/* The terms line. Pure flavour, and the cheapest joke on the card: a real + invoice's most boring sentence, printed under a night that nearly killed + you. Left in as its own class so you can delete it in one line if it + doesn't land. */ +#hud-card .terms { + margin-top: 10px; font-size: 10px; color: #45566a; letter-spacing: .04em; +} +/* ---- end of E's kit ----------------------------------------------------- */ + +/* Tomorrow is a rumour, and it should look like one next to tonight's numbers. + (Mine, not E's β the kit predates the tomorrow line and doesn't restyle it.) */ #hud-card .tomorrow { display:flex; gap:10px; align-items:baseline; margin-top:9px; font-size:12px; color:#6d8494; } #hud-card .tomorrow .tlabel { letter-spacing:.14em; text-transform:uppercase; color:#55707f; } @@ -406,11 +545,28 @@ showForecast({ key, def, site, tomorrowDef }, wk, onGo) { // else. The client and the brief are data (week.js NIGHTS), so an // unbriefed night degrades to the old storm card rather than an empty // letterhead β which is also what keeps every existing test honest. + // + // SPRINT12 β the letterhead is E's kit now: the outfit's mark on the + // left, the docket on the right, the client demoted to a bill-to block β + // because the business is the constant and the client changes nightly. const job = wk.job ?? {}; - const letterhead = job.client - ? `
${job.brief}
` : ''; + ? `