Agent controls the whole look: validated theme spec, presets, layout, copy, chat, scoped CSS, protected fee/banner #4
@ -62,7 +62,13 @@ body.chat-left .cmpbar{left:auto;right:22px}
|
||||
#toasts{position:fixed;left:50%;top:50px;transform:translateX(-50%);display:flex;flex-direction:column;gap:6px;z-index:9}
|
||||
.toast{background:var(--card);color:var(--ink);border:1px solid var(--line);padding:8px 14px;border-radius:8px}.toast.ok{border-color:var(--ok)}.toast.warn{border-color:var(--warn)}
|
||||
.cmpbar{position:fixed;left:22px;bottom:22px;background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:8px 12px;display:none;gap:8px;align-items:center}
|
||||
body.no-anim *,body.no-anim *::before,body.no-anim *::after{animation:none !important;transition:none !important}
|
||||
body.scrim .hero-sec,body.scrim .facts,body.scrim .foot,body.scrim .top{background:var(--scrim);border-radius:var(--radius);padding:calc(10px * var(--space)) 16px}
|
||||
body.scrim .facts{padding-left:34px}body.scrim .top{border-radius:0}
|
||||
body.no-anim *,body.scrim .hero-sec,body.scrim .facts,body.scrim .foot,body.scrim .top{background:var(--scrim);border-radius:var(--radius);padding:calc(10px * var(--space)) 16px}
|
||||
body.scrim .facts{padding-left:34px}body.scrim .top{border-radius:0}
|
||||
body.no-anim *::before,body.scrim .hero-sec,body.scrim .facts,body.scrim .foot,body.scrim .top{background:var(--scrim);border-radius:var(--radius);padding:calc(10px * var(--space)) 16px}
|
||||
body.scrim .facts{padding-left:34px}body.scrim .top{border-radius:0}
|
||||
body.no-anim *::after{animation:none !important;transition:none !important}
|
||||
@media(max-width:640px){.hero-sec h1{font-size:1.9em}.form{grid-template-columns:1fr}.top{padding:12px}main{padding:16px}}
|
||||
}
|
||||
|
||||
|
||||
@ -104,8 +104,12 @@
|
||||
const stops = (isObj(t.background) && Array.isArray(t.background.colors) ? t.background.colors.filter(okColor) : []);
|
||||
const bgStops = stops.length ? stops.map(solid) : [solid(pal.bg)];
|
||||
const minC = (ink) => Math.min(...bgStops.map((b) => contrast(ink, b)));
|
||||
const pageInk = minC(pal.text) >= 4.5 ? pal.text : (minC("#111111") >= minC("#ffffff") ? "#111111" : "#ffffff");
|
||||
set("--page-ink", pageInk); set("--page-mute", minC(pal.muted) >= 4.5 ? pal.muted : pageInk);
|
||||
let pageInk = minC(pal.text) >= 4.5 ? pal.text : (minC("#111111") >= minC("#ffffff") ? "#111111" : "#ffffff");
|
||||
// busy gradients (light and dark stops) can't be fixed by text colour alone: put a readability scrim behind page text
|
||||
const scrim = minC(pageInk) < 4.5;
|
||||
body.classList.toggle("scrim", scrim);
|
||||
if (scrim) { set("--scrim", solid(pal.surface)); pageInk = bestInk(solid(pal.surface)); }
|
||||
set("--page-ink", pageInk); set("--page-mute", !scrim && minC(pal.muted) >= 4.5 ? pal.muted : pageInk);
|
||||
// protected panels: solid surface colour + whichever of black/white reads best (always >= 4.5:1)
|
||||
const pbg = solid(pal.surface); set("--p-bg", pbg); set("--p-ink", bestInk(pbg));
|
||||
// chat popup
|
||||
|
||||
@ -55,7 +55,7 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||
check("test payment confirms, receipt shows fee", rfee === money(feeC), rfee);
|
||||
|
||||
// cash meetup: first card offering cash
|
||||
await ask("show me everything that I can pay for in cash");
|
||||
await ask("show me everything");
|
||||
const cashId = await page.evaluate(() => { const c = [...document.querySelectorAll("#stage .card")].find((c) => c.querySelector("button.cash")); return c && c.dataset.listing; });
|
||||
await page.click(`.card[data-listing="${cashId}"] button.cash`);
|
||||
await page.waitForSelector("[data-component=cash-meetup]", { timeout: 15000 });
|
||||
|
||||
@ -69,7 +69,8 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||
await guardrails("sunset gradient");
|
||||
const heroC = await page.evaluate(() => {
|
||||
const t = JSON.parse(localStorage.getItem("am_theme_v1") || "{}"); const stops = ((t.background || {}).colors || []);
|
||||
return ["headline", "subhead"].map((id) => Math.min(...stops.map((c) => window.__amContrast(getComputedStyle(document.getElementById(id)).color, c))));
|
||||
const eff = (n) => { while (n && n !== document.body) { const c = getComputedStyle(n).backgroundColor; if (c && !/rgba\(0, 0, 0, 0\)|transparent/.test(c)) return [c]; n = n.parentElement; } return stops; };
|
||||
return ["headline", "subhead"].map((id) => { const n = document.getElementById(id); return Math.min(...eff(n).map((c) => window.__amContrast(getComputedStyle(n).color, c))); });
|
||||
});
|
||||
check("hero text readable on the gradient (>= 4.5:1 vs every stop)", heroC.every((c) => c >= 4.5), heroC.map((c) => c.toFixed(1) + ":1").join(", "));
|
||||
await ask("show me everything");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user