Files
prosolis a15d67e210 web: the muted text that was never muted, and the stylesheet fetched every time
Every text-[color:var(--ink)]/50, border-[color:var(--ink)]/10 and
bg-[color:var(--ink)]/5 in the templates compiled to nothing. Tailwind v3
cannot put an opacity on an arbitrary var() colour, so all 538 of them were
dropped from output.css without a word. Meta text rendered at full ink, card
borders fell back to Tailwind's default grey (bright white rings at night),
and the washes, backdrops and hover pills simply weren't there, on the news
site, the casino and the adventure pages alike.

The palette is now written once per phase and casino room as bare rgb
channels (--ink-rgb and friends), the plain vars are built from them, and
tailwind.config.js exposes ink, muted, accent, warn and card as real colours.
The classes are text-ink/80, border-ink/10, bg-accent/20 now, and they compile.

Restoring the intended opacities as-is would have traded flat for illegible:
ink at 50% measures 2.7 to 2.9:1 on the lit phases. So secondary text gets
its own colour, --muted, per phase and per casino room, taken as faint as it
can go while still clearing 4.5:1 on both the card and the page. Everything
that was ink at 35 to 70% is text-muted. The 20-30% ones are separators and
empty-cell dashes and stay faint.

The bg-theme-* chips carry white text everywhere they appear, and eight of
them measured 2.5 to 3.2:1. Same hues, taken just dark enough to pass (4.6 to
4.7:1). eu, lego and adventure already passed and are unchanged, and the
underline and border colours keep the old pastels since they carry no text.

Static files came out of the embedded FS with no Last-Modified, no ETag and
no Cache-Control, so every page view downloaded the stylesheet and every
script in full, and the service worker's "cheap 304" never happened. Each
file is hashed once now. Templates link through {{asset}}, which appends
?v=<hash>; a request naming the current hash is served immutable for a year,
and everything else gets the hash as its ETag and revalidates to a 304. The
service worker serves versioned URLs cache-first, drops older versions of the
same file as new ones land, and moves to cache v6.
2026-09-22 22:54:50 -07:00

177 lines
8.1 KiB
HTML
Raw Permalink 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.
{{define "title"}}Hangman · {{.Room.Name}}{{end}}
{{define "main"}}
<div class="space-y-6" data-hangman>
<div class="flex flex-wrap items-center justify-between gap-3">
<div class="flex items-center gap-3 min-w-0">
<a href="/games" class="grid h-10 w-10 shrink-0 place-items-center rounded-full bg-card shadow-pete border-2 border-ink/10 hover:bg-ink/5 transition" title="Back to the casino">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="h-5 w-5" aria-hidden="true">
<path d="M19 12H5"></path><polyline points="12 19 5 12 12 5"></polyline>
</svg>
<span class="sr-only">Back to the casino</span>
</a>
<h1 class="font-display text-3xl font-bold">Hangman</h1>
</div>
<p class="text-sm text-muted">{{.MaxWrong}} lives · every wrong guess costs you a tenth of the win</p>
</div>
{{template "_chipbar" .}}
<!-- The felt. The gallows is on it because the gallows is the meter: it counts
down your lives and your winnings at the same time. -->
<section class="pete-felt relative overflow-hidden rounded-3xl p-6 sm:p-10 shadow-pete-lg border-2 border-ink/10">
<div class="pete-rack" data-house aria-hidden="true">
<span data-chip="500" style="--stack: 5"></span>
<span data-chip="100" style="--stack: 7"></span>
<span data-chip="25" style="--stack: 4"></span>
<span data-chip="5" style="--stack: 6"></span>
</div>
<!-- The gallows and the stake stack up on the left; the phrase and what it's
worth take the rest. The right column keeps clear of the rack in the
corner, which is why nothing in it is pushed to the far edge. -->
<div class="relative grid gap-x-10 gap-y-8 lg:grid-cols-[auto,1fr] lg:items-start">
<div class="flex flex-col items-center gap-6 lg:items-start">
<svg data-gallows viewBox="0 0 130 150" class="pete-gallows h-48 w-auto sm:h-56" role="img"
aria-labelledby="gallows-title">
<title id="gallows-title">The gallows</title>
<g class="pete-gallows-frame">
<path d="M8 145 H72" />
<path d="M28 145 V8" />
<path d="M28 8 H92" />
<path d="M92 8 V26" />
</g>
<g class="pete-gallows-body">
<circle data-part="0" cx="92" cy="38" r="12" />
<path data-part="1" d="M92 50 V88" />
<path data-part="2" d="M92 58 L74 76" />
<path data-part="3" d="M92 58 L110 76" />
<path data-part="4" d="M92 88 L76 114" />
<path data-part="5" d="M92 88 L108 114" />
</g>
</svg>
<!-- The stake sits under the gallows it's riding on, the same spot the
blackjack table puts your bet on. -->
<div class="flex items-center gap-4">
<div class="pete-spot" data-spot>
<span class="pete-spot-label">Bet</span>
<div class="pete-stack" data-stack></div>
<span data-spot-total class="pete-spot-total hidden"></span>
</div>
<p data-lives class="text-xs font-bold uppercase tracking-wider text-white/50"></p>
</div>
</div>
<div class="min-w-0 space-y-6">
<!-- What a win is worth right now. It falls as the figure fills in.
This row is the only one level with the house rack in the corner, so
it is the only one that has to keep clear of it — the board below
gets the full width, and needs it. -->
<div class="flex flex-wrap items-center gap-3 pr-24 sm:pr-28">
<div class="pete-meter" data-meter>
<span class="pete-meter-label">Pays</span>
<span data-multiple class="pete-meter-value">—</span>
</div>
<p class="text-sm text-white/60">
<span data-stands class="font-bold tabular-nums text-white/90">—</span>
<span data-stands-label>if you get it</span>
</p>
</div>
<!-- The phrase. -->
<div data-board class="pete-board" aria-live="polite" aria-label="The phrase"></div>
<!-- Letters that missed. -->
<div class="flex min-h-[1.75rem] flex-wrap items-center gap-1.5">
<span data-wrong-label class="hidden text-xs font-bold uppercase tracking-wider text-white/40">Missed</span>
<div data-wrong class="flex flex-wrap gap-1.5"></div>
</div>
<!-- What just happened. -->
<div class="flex min-h-[2.75rem] items-center">
<p data-verdict class="hidden rounded-full bg-white/95 px-5 py-2 font-display text-lg font-bold text-[#2b2118] shadow-pete"></p>
</div>
</div>
</div>
</section>
<!-- Guessing: shown while a game is live. -->
<section data-guessing class="hidden rounded-3xl bg-card p-5 sm:p-6 shadow-pete border-2 border-ink/10">
<div data-keyboard class="pete-keys"></div>
<div class="mt-4 flex flex-wrap items-center gap-2">
<label for="solve" class="sr-only">Guess the whole phrase</label>
<input id="solve" data-solve-input type="text" autocomplete="off" enterkeyhint="go"
placeholder="Or just say what it is…"
class="min-w-0 flex-1 rounded-full bg-ink/5 px-4 py-2.5 text-sm font-semibold
border-2 border-ink/10 focus:outline-none focus:border-accent">
<button type="button" data-solve
class="rounded-full bg-accent px-6 py-2.5 font-display font-bold text-white shadow-pete
hover:brightness-105 active:translate-y-px disabled:opacity-40 disabled:pointer-events-none transition">
Solve
</button>
</div>
<p class="mt-3 text-center text-xs text-muted">
Type a letter to guess it. A wrong solve costs a life, same as a wrong letter.
</p>
<p data-game-msg class="hidden mt-3 rounded-2xl bg-ink/5 px-4 py-2 text-sm font-semibold"></p>
</section>
<!-- Betting: shown between games. -->
<section data-betting class="rounded-3xl bg-card p-5 sm:p-6 shadow-pete border-2 border-ink/10">
<div class="text-xs font-semibold uppercase tracking-wider text-muted">How long a phrase?</div>
<div class="mt-2 grid gap-2 sm:grid-cols-3">
{{range .Tiers}}
<button type="button" data-tier="{{.Slug}}"
class="pete-tier rounded-2xl border-2 p-3 text-left transition">
<div class="flex items-baseline justify-between gap-2">
<span class="font-display text-lg font-bold">{{.Name}}</span>
<span class="font-display text-lg font-bold tabular-nums text-accent">{{printf "%.1f" .Base}}×</span>
</div>
<p class="mt-0.5 text-xs text-muted">{{.Blurb}}</p>
</button>
{{end}}
</div>
<div class="mt-5 flex flex-wrap items-center gap-x-6 gap-y-4">
<div>
<div class="text-xs font-semibold uppercase tracking-wider text-muted">Your bet</div>
<div class="font-display text-3xl font-bold tabular-nums"><span data-bet-amount>0</span></div>
</div>
<div class="flex flex-wrap items-center gap-2">
{{range .Denominations}}
<button type="button" data-chip="{{.}}" aria-label="Bet {{.}} more"
class="pete-chip pete-disc grid h-12 w-12 place-items-center font-display text-sm font-bold text-white">
<span>{{.}}</span>
</button>
{{end}}
<button type="button" data-bet-clear
class="rounded-full px-3 py-2 text-sm font-semibold text-muted hover:text-ink transition">Clear</button>
</div>
<button type="button" data-start
class="ml-auto rounded-full bg-accent px-8 py-3 font-display text-lg font-bold text-white shadow-pete
hover:brightness-105 active:translate-y-px disabled:opacity-40 disabled:pointer-events-none transition">
Play
</button>
</div>
<p data-table-msg class="hidden mt-3 rounded-2xl bg-ink/5 px-4 py-2 text-sm font-semibold"></p>
</section>
</div>
{{end}}
{{define "scripts"}}
<script src="{{asset "/static/js/casino-fx.js"}}" defer></script>
<script src="{{asset "/static/js/games.js"}}" defer></script>
<script src="{{asset "/static/js/hangman.js"}}" defer></script>
{{end}}