- .body wasn't a flex container, so the "View at The Met" CTA's align-self was
ignored and the inline link collapsed over the metadata. Make .head/.body flex
columns → CTA sits correctly below the collection/rights.
- Widen the /art desktop card (max-width 1052→1280, art column 46→50%, tighter
padding) so the framed piece is properly sized and the frame reads in better
proportion — /art intentionally breaks the hub's 1180 column since the artwork
is the point and mobile has its own layout.
- Darken the Space Mono micro-labels (Frame / Thickness / Colors / Collection /
Rights) so they stand out.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rebuilt /art to CD's "The Story" hybrid: a warm-tan editorial card with the
Daily-Art purple accent. Left = guide write-up (kicker · title · attribution ·
the museum-guide blurb · Collection/Rights · View at The Met). Right = the framed
piece (our existing frame + thickness customizer, on one line each) on a deeper-
tan ground, then a divider, the "Colors in this piece" palette, and Share /
Download (Download gated on public-domain license; image is same-origin so it
just works). Self-hosted Space Mono for the curatorial micro-labels; Newsreader
display + Hanken UI like the rest of the hub.
Mobile: the left/right wrappers collapse (display:contents) so the blocks reflow
to head → artwork → writeup → controls — the art sits high, seen before it's read.
Kept HubBar, the Back button, and the fullscreen lightbox (incl. landscape rotate).
Save-to-account + framed-composite export deferred to Phase 2.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There were three different top bars (home3/detail vs /play vs /art). Unify on the
shared HubBar:
- HubBar is now fully self-contained (own @font-face + hardcoded hub colors) so it
renders identically regardless of the host page's tokens/fonts.
- /art: dropped its bespoke gallery bar for <HubBar active="art" />.
- /play: dropped its bar for <HubBar active="games" />; the contextual in-game
step-back (Game Selection / Play Hub) moves into the page body as a secondary
".gameback" control, shown only in game views (the global nav is in HubBar).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Daily Art had no Back. Add a top-left "‹ Back" in its own gallery bar styling:
history.back() when arrived via in-app nav, else goto('/home3', {replaceState})
on a cold deep-link — same rule as the hub detail pages.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The rotated fullscreen clipped the top rail: the image's short edge plus rail/mat
exceeded the phone's narrow width. Cap the short edge (max-height pre-rotation),
use a modest fixed rail/mat in this view so the moulding always fits regardless
of the thickness slider, and hide the (now-sideways) caption — the placard is on
the page anyway.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Conditional 90° rotate of the fullscreen stage (frame + caption together): only
when the artwork is landscape AND the screen is a narrow portrait phone — so a
wide painting fills the long axis (turn phone to view level, tap to close).
Portrait/square art and desktop stay upright. Landscape detected from the loaded
image's natural dimensions; CSS decides WHEN via (orientation: portrait). Image
caps use swapped vh/vw units post-rotation so the whole framed piece always fits.
No screen-orientation lock API (unreliable on mobile web) — pure CSS transform.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- WOTD /word: watermark was nudged too far down last round; bring it back up to
sit JUST below the date (clears it by a few px instead of dropping markedly).
- home3 Entertainment card: stacked on mobile it lost the height it borrowed from
Play on desktop and felt crowded — add vertical breathing (padding + gaps), not
as tall as desktop.
- /art lightbox: on a narrow portrait phone the framed piece (image + mat + rail)
overflowed the viewport (rail clipped → looked distorted). Cap the image so the
WHOLE frame fits, leaving room for the caption.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- /api/art/image/{id} now answers HEAD as well as GET (was 404 on HEAD) — mirrors the
/a/{id} fix. Added tests/test_art_api.py (GET+HEAD+size=full fallback + today payload).
- /textures/* served immutable (long cache) instead of no-cache; excluded from the
revalidate matcher. Live Caddyfile + repo snapshot both updated.
- Lightbox: Escape closes it, and focus moves to it on open (keyboard-friendly).
- Trimmed the gallery's top padding so "Daily Art" sits closer to the bar.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Woods are now built from four real mitered rails clipped to 45° joints, each showing the
grain along its length — horizontal on top/bottom (rotated texture wood-grain-h.jpg),
vertical on the sides — so the grain TURNS at every corner like real cut moulding. Each
rail carries a directional bevel (lit top-left) for a rounded profile; per-species recolor
moved onto the rails. Rendered via a Svelte snippet in both page + full-screen frames.
- Gold/Silver gain fine brushed-metal striations over the existing sheen.
- New asset: wood-grain-h.jpg (the CC0 texture rotated 90°), credited in textures/CREDITS.txt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- No frame in full-screen now fills the screen (img max 96vw / 88vh instead of the
framed cap).
- Full-screen backdrop is a soft top-lit gallery wall (light, not dark) so the Black
frame — and every frame — reads like a piece hung on a real wall; caption text darkened
to match.
- Mat now sits recessed below the moulding: a rabbet groove line at the lip, frame shadow
on the mat's top/left, catch-light on bottom/right — a small chiseled step in place of
the flat frame→mat transition.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Black frame (no grain) added after Silver — a satin charcoal moulding in the metals family.
- Full-screen rail bumped (clamp 18–36px) so the moulding reads as thick as the page view
against the much larger image; mat held.
- Thickness slider extended to 1.9× and the mat now caps at 1.5× (min()), so the top of
the slider thickens only the wood while the white border stays put. Applies to the
full-screen frame too.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Replace procedural grain with a real fine-grain wood texture (CC0, Poly Haven —
static/textures/wood-grain.jpg). The three woods share it, recolored per species via
CSS filter on ::before: Walnut (as-is dark), Oak (lightened/warmed), Mahogany (new —
deepened/reddened). Miters now apply to all three woods; mat sits between texture and
miters via z-index.
- Full-screen sizing fixed: image capped (max-height 66vh) so the bottom rail always
fits — no more cutoff. Rail/mat dialed back to ~1:1 wood:white (was mat-heavy), only
slightly larger than the page so the proportion matches the small view.
Texture credit (CC0, no attribution required) recorded in static/textures/CREDITS.txt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Oak grain is now a real feTurbulence noise field (organic wood, no drawn-on lines),
with a soft light/shade for moulding roundness; miters kept.
- Thickness slider (0.7–1.5×) scales rail + mat via --frame-scale, remembered locally;
applies to both the page and the full-screen view.
- No-jump layout: every frame — including "No frame" — reserves the same footprint
(rail + mat as CSS vars), so switching never reflows the page. "No frame" is the bare
art floating with a soft shadow.
- Full-screen wears a thicker rail + mat so the white border keeps its proportion at
large size; "No frame" still maximizes there.
- Frame chips redesigned as beveled beads with a clean offset selection ring.
- Subtle fading hairline divider between the title and the artwork.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- New "Oak" frame: real wood-grain along the rails plus 45° mitered corner joints
(CSS conic-free miter via per-corner diagonal seam gradients sized to the rail width),
so it reads as four lengths of moulding meeting at the corners.
- The lightbox now wears the selected frame too — the same moulding + cream mat around
the full-resolution image, which makes the piece pop on a dark full screen. Image is
capped to leave room for the frame; "No frame" still maximizes size.
- Frame picker wraps gracefully now that there are five options.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Virtual frames (Walnut/Gold/Silver/None), selectable + remembered in localStorage,
built as a beveled moulding around a cream museum mat.
- Header uses the real /logo.svg wordmark; the "No ads" pill is replaced by an
account icon (the pill doesn't need to follow every page).
- Lightbox now opens a full-resolution copy that fills the screen: art._download_image
caches a hi-res {id}-full copy alongside the web-large display copy, served via
/api/art/image/{id}?size=full (image_url_large in /api/art/today).
- Centered the placard bullet separators (explicit .sep spans, equal margins).
- Image no longer shifts on hover; a quiet "Click to expand" affordance sits on the art.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A calm "walk up to one piece on a quiet wall" page for the Daily Art engine. Bright,
modern, cream canvas (not a dim brown gallery) so the artwork's own colors are the pop
— the new look prototyped, scoped to /art so it doesn't touch the rest of the site yet.
- Fetches /api/art/today; large soft-shadowed frame (click -> lightbox), a museum
"placard" (serif title, artist · date, medium, "from The Met · Public Domain (CC0)",
View-at-museum link). Calm loading/empty states. Unlinked from the homepage (safe to
iterate). Ships the (Codex-cleared) art backend too.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>