← back to Model Arena
data/artifacts/104018fe5adc/claude-code.html
524 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Designer Wallcoverings — This or That</title>
<style>
/* ============ DESIGN TOKENS ============ */
:root{
--bg:#f4f1ea; /* warm ivory ground */
--surface:#ffffff;
--ink:#1c1a17; /* darkest near-black ink */
--ink-soft:#3a352d;
--muted:#9b948a;
--accent:#a9884f; /* single metallic accent — antique brass */
--accent-deep:#8a6c38;
--line:rgba(28,26,23,.12);
--line-strong:rgba(28,26,23,.22);
--shadow:0 10px 40px rgba(28,26,23,.14);
--shadow-soft:0 4px 18px rgba(28,26,23,.08);
--story-bg:#161310; /* espresso story canvas */
--ease:cubic-bezier(.22,1,.36,1);
/* editable swatch palettes */
--l-ground:#33403a; /* Damask ground — deep sage */
--l-motif:#c8a86a; /* Damask motif — brass */
--r-ground:#2b3550; /* Geometric ground — deep indigo */
--r-motif:#e6ddcf; /* Geometric motif — cream */
--serif:'Cormorant Garamond','Playfair Display','EB Garamond',Georgia,'Times New Roman',serif;
--sans:-apple-system,'Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{
background:
radial-gradient(120% 90% at 50% -10%, #faf8f3 0%, var(--bg) 55%, #ece7dc 100%);
color:var(--ink);
font-family:var(--sans);
-webkit-font-smoothing:antialiased;
min-height:100vh;
padding-bottom:56px;
}
/* ============ HEADER / WORDMARK LOCKUP ============ */
header.topbar{
position:sticky;top:0;z-index:50;
display:flex;align-items:center;justify-content:space-between;
gap:24px;
padding:20px 32px;
background:rgba(244,241,234,.82);
backdrop-filter:saturate(120%) blur(10px);
border-bottom:1px solid var(--line);
}
.wordmark{
font-family:var(--serif);
color:var(--ink); /* darkest ink — never a surface token */
font-weight:600;
font-size:44px; /* >=40px */
line-height:.92;
letter-spacing:.18em;
text-transform:uppercase;
max-width:280px; /* compact upper-left lockup, wraps to 2 lines */
text-indent:.18em;
}
.topbar .kicker{
font-family:var(--sans);
font-size:12px;letter-spacing:.28em;text-transform:uppercase;
color:var(--muted);
text-align:right;
line-height:1.7;
}
.topbar .kicker b{display:block;color:var(--accent-deep);font-weight:600;letter-spacing:.22em}
/* ============ LAYOUT ============ */
main{
max-width:520px;margin:0 auto;padding:40px 24px 0;
display:flex;flex-direction:column;align-items:center;gap:34px;
animation:fadeUp .8s var(--ease) both;
}
@keyframes fadeUp{from{opacity:0;transform:translateY(28px)}to{opacity:1;transform:none}}
/* ============ PHONE FRAME 9:16 ============ */
.phone{
position:relative;
width:100%;max-width:340px;
aspect-ratio:9/16;
background:#0c0a08;
border-radius:42px;
padding:12px;
box-shadow:var(--shadow), 0 0 0 1px rgba(28,26,23,.4), inset 0 0 0 2px rgba(255,255,255,.05);
}
.phone::before{ /* notch */
content:"";position:absolute;top:18px;left:50%;transform:translateX(-50%);
width:108px;height:26px;background:#0c0a08;border-radius:0 0 16px 16px;z-index:6;
}
.story{
position:relative;height:100%;width:100%;
border-radius:32px;overflow:hidden;
background:var(--story-bg);
display:flex;flex-direction:column;
color:#f5f2ea;
}
/* ---- Story chrome ---- */
.progress{position:absolute;top:12px;left:12px;right:12px;display:flex;gap:5px;z-index:5}
.progress span{flex:1;height:2.5px;border-radius:2px;background:rgba(255,255,255,.28);overflow:hidden}
.progress span i{display:block;height:100%;width:0;background:#fff;border-radius:2px}
.progress span:first-child i{width:64%;animation:load 6s linear forwards}
@keyframes load{to{width:100%}}
.story-head{
position:absolute;top:24px;left:14px;right:14px;z-index:5;
display:flex;align-items:center;gap:9px;
}
.avatar{
width:32px;height:32px;border-radius:50%;flex:none;
padding:2px;background:conic-gradient(from 210deg,var(--accent),#e7d3a6,var(--accent-deep),var(--accent));
}
.avatar div{
width:100%;height:100%;border-radius:50%;
background:var(--story-bg);
display:flex;align-items:center;justify-content:center;
font-family:var(--serif);font-size:15px;color:var(--accent);font-weight:600;
}
.handle{font-size:12.5px;font-weight:600;letter-spacing:.02em}
.handle b{font-weight:600}
.handle span{color:rgba(245,242,234,.6);font-weight:400;margin-left:6px}
.story-head .x{margin-left:auto;font-size:20px;color:rgba(245,242,234,.85);line-height:1;cursor:pointer}
/* ---- Story body ---- */
.story-body{
flex:1;display:flex;flex-direction:column;
padding:70px 18px 16px;
}
.poll-eyebrow{
font-size:11px;letter-spacing:.32em;text-transform:uppercase;
color:var(--accent);text-align:center;margin-bottom:6px;font-weight:600;
}
.poll-title{
font-family:var(--serif);
font-size:34px; /* heading >=24px */
line-height:1;text-align:center;font-weight:600;font-style:italic;
letter-spacing:.01em;
text-shadow:0 2px 18px rgba(0,0,0,.4);
}
.poll-sub{
text-align:center;color:rgba(245,242,234,.62);
font-size:12px;letter-spacing:.06em;margin-top:8px;
}
/* ---- Arena ---- */
.arena{
position:relative;flex:1;margin-top:16px;
display:flex;gap:2px;border-radius:20px;overflow:hidden;
box-shadow:0 8px 30px rgba(0,0,0,.45), inset 0 0 0 1px rgba(255,255,255,.06);
}
.swatch{
position:relative;flex:1;overflow:hidden;cursor:pointer;
display:flex;flex-direction:column;justify-content:flex-end;
border:none;background:transparent;
transition:flex .55s var(--ease);
isolation:isolate;
}
.swatch .ground{position:absolute;inset:0;z-index:0;transition:background-color .3s ease}
.swatch.left .ground{background-color:var(--l-ground)}
.swatch.right .ground{background-color:var(--r-ground)}
.swatch .tex{position:absolute;inset:0;z-index:1;opacity:.9;transition:transform .6s var(--ease)}
.swatch:hover .tex{transform:scale(1.06)}
.swatch .veil{position:absolute;inset:0;z-index:2;
background:linear-gradient(to top,rgba(10,8,6,.72) 0%,rgba(10,8,6,.15) 45%,rgba(10,8,6,0) 70%);}
/* rising vote fill */
.swatch .fill{
position:absolute;left:0;right:0;bottom:0;height:0;z-index:3;
background:linear-gradient(to top,rgba(169,136,79,.55),rgba(169,136,79,.14));
border-top:1.5px solid rgba(231,211,166,.9);
transition:height .8s var(--ease);
}
.swatch .name{
position:relative;z-index:4;
font-family:var(--serif);font-size:19px;font-weight:600;
text-align:center;padding:0 8px 6px;line-height:1.1;
text-shadow:0 2px 10px rgba(0,0,0,.6);
outline:none;border-radius:6px;
}
.swatch .name:focus{box-shadow:0 0 0 1px rgba(231,211,166,.7)}
.swatch .pct{
position:relative;z-index:4;text-align:center;
font-family:var(--serif);font-size:30px;font-weight:600;
color:#fff;letter-spacing:.02em;
height:0;opacity:0;overflow:hidden;
transition:opacity .5s ease .2s, height .5s var(--ease);
text-shadow:0 2px 12px rgba(0,0,0,.7);
padding-bottom:14px;
}
.voted .swatch .pct{height:40px;opacity:1}
/* VS badge */
.vs{
position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:6;
width:46px;height:46px;border-radius:50%;
background:var(--surface);color:var(--ink);
display:flex;align-items:center;justify-content:center;
font-family:var(--serif);font-style:italic;font-weight:600;font-size:19px;
box-shadow:0 6px 20px rgba(0,0,0,.5), 0 0 0 4px rgba(22,19,16,.9), 0 0 0 5px var(--accent);
}
/* winner wax seal */
.seal{
position:absolute;top:14px;left:50%;transform:translateX(-50%) scale(.4) rotate(-12deg);
z-index:7;width:74px;height:74px;border-radius:50%;
background:radial-gradient(circle at 35% 30%,#c8a86a,var(--accent) 55%,var(--accent-deep));
box-shadow:0 6px 18px rgba(0,0,0,.5), inset 0 0 0 2px rgba(255,255,255,.35), inset 0 0 0 6px rgba(138,108,56,.5);
display:flex;flex-direction:column;align-items:center;justify-content:center;
color:#26200f;opacity:0;pointer-events:none;
transition:opacity .45s ease, transform .55s var(--ease);
}
.seal small{font-size:8px;letter-spacing:.22em;text-transform:uppercase;font-weight:700}
.seal b{font-family:var(--serif);font-size:13px;letter-spacing:.14em;font-weight:700;line-height:1;margin-top:1px}
.seal.show{opacity:1;transform:translateX(-50%) scale(1) rotate(-12deg)}
/* ---- Results split bar ---- */
.results{margin-top:14px;height:0;opacity:0;overflow:hidden;transition:height .5s var(--ease),opacity .4s ease}
.voted .results{height:44px;opacity:1}
.bar{height:8px;border-radius:5px;overflow:hidden;display:flex;background:rgba(255,255,255,.12)}
.bar .bl{background:linear-gradient(90deg,var(--accent-deep),var(--accent));transition:width .8s var(--ease)}
.bar .br{background:rgba(245,242,234,.55);transition:width .8s var(--ease)}
.rlabels{display:flex;justify-content:space-between;margin-top:8px;
font-size:11px;letter-spacing:.08em;color:rgba(245,242,234,.75)}
.rlabels b{color:var(--accent);font-weight:600}
/* ---- Story footer ---- */
.story-foot{padding:12px 16px 18px;display:flex;align-items:center;gap:12px}
.reply{
flex:1;border:1px solid rgba(245,242,234,.4);border-radius:22px;
padding:9px 16px;font-size:12px;color:rgba(245,242,234,.7);letter-spacing:.04em;
}
.story-foot svg{width:22px;height:22px;stroke:rgba(245,242,234,.9);fill:none;stroke-width:1.6}
.tap-hint{
text-align:center;font-size:11px;letter-spacing:.14em;text-transform:uppercase;
color:var(--accent);padding:0 16px 6px;transition:opacity .3s ease;
}
.voted .tap-hint{color:rgba(245,242,234,.5)}
.votecount{font-weight:600;color:#fff}
/* ============ CONTROLS (ivory) ============ */
.controls{
width:100%;max-width:340px;
background:var(--surface);
border:1px solid var(--line);border-radius:16px;
box-shadow:var(--shadow-soft);
padding:22px 22px 24px;
}
.controls h2{
font-family:var(--serif);font-size:24px;font-weight:600;color:var(--ink);
letter-spacing:.01em;margin-bottom:3px;
}
.controls .lead{font-size:12.5px;color:var(--muted);letter-spacing:.02em;line-height:1.5;margin-bottom:18px}
.field-label{
font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--muted);
font-weight:600;margin:16px 0 9px;
}
.pickrow{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.pick{display:flex;flex-direction:column;gap:6px}
.pick span{font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-soft)}
.pick .swatchrow{display:flex;gap:8px}
.pick label{
display:flex;align-items:center;gap:6px;font-size:10px;color:var(--muted);
letter-spacing:.06em;cursor:pointer;
}
input[type=color]{
-webkit-appearance:none;appearance:none;
width:26px;height:26px;border:1px solid var(--line-strong);border-radius:50%;
padding:0;background:none;cursor:pointer;
}
input[type=color]::-webkit-color-swatch-wrapper{padding:0}
input[type=color]::-webkit-color-swatch{border:none;border-radius:50%}
input[type=color]::-moz-color-swatch{border:none;border-radius:50%}
.btnrow{display:flex;gap:10px;margin-top:22px}
button.act{
flex:1;font-family:var(--sans);
font-size:11px;letter-spacing:.18em;text-transform:uppercase;font-weight:600;
padding:13px 14px;border-radius:10px;cursor:pointer;border:1px solid var(--line-strong);
background:var(--surface);color:var(--ink);
transition:all .18s ease;
}
button.act:hover{border-color:var(--accent);color:var(--accent-deep)}
button.act.primary{background:var(--ink);color:var(--bg);border-color:var(--ink)}
button.act.primary:hover{background:var(--accent-deep);border-color:var(--accent-deep);color:#fff}
.foot-note{
max-width:340px;text-align:center;font-size:11px;letter-spacing:.12em;
text-transform:uppercase;color:var(--muted);margin-top:6px;
}
</style>
</head>
<body>
<header class="topbar">
<div class="wordmark">Designer Wallcoverings</div>
<div class="kicker"><b>Atelier</b>Story Poll · No.14</div>
</header>
<main>
<!-- PHONE -->
<div class="phone">
<div class="story" id="story">
<div class="progress"><span><i></i></span><span><i></i></span><span><i></i></span><span><i></i></span></div>
<div class="story-head">
<div class="avatar"><div>D</div></div>
<div class="handle"><b>designerwallcoverings</b><span>2h</span></div>
<div class="x">×</div>
</div>
<div class="story-body">
<div class="poll-eyebrow">This · or · That</div>
<div class="poll-title">Which wall<br>speaks to you?</div>
<div class="poll-sub">Tap a side — the room will tell.</div>
<div class="arena" id="arena">
<!-- LEFT -->
<div class="swatch left" data-side="left">
<div class="ground"></div>
<svg class="tex" viewBox="0 0 90 120" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
<defs>
<pattern id="pat-damask" width="90" height="120" patternUnits="userSpaceOnUse">
<g fill="var(--l-motif)" fill-opacity="0.94">
<path d="M45 6 C55 18 55 30 45 40 C35 30 35 18 45 6 Z"/>
<path d="M45 15 C61 10 71 21 66 33 C58 29 50 27 45 31 Z"/>
<path d="M45 15 C29 10 19 21 24 33 C32 29 40 27 45 31 Z"/>
<path d="M45 44 C67 56 69 85 45 101 C21 85 23 56 45 44 Z"/>
<path d="M45 57 C58 67 58 85 45 93 C32 85 32 67 45 57 Z" fill="var(--l-ground)"/>
<path d="M45 104 C55 112 58 119 52 120 L38 120 C32 119 35 112 45 104 Z"/>
<circle cx="8" cy="60" r="3.2"/><circle cx="82" cy="60" r="3.2"/>
<circle cx="0" cy="0" r="3"/><circle cx="90" cy="0" r="3"/>
<circle cx="0" cy="120" r="3"/><circle cx="90" cy="120" r="3"/>
</g>
</pattern>
</defs>
<rect width="90" height="120" fill="url(#pat-damask)"/>
</svg>
<div class="veil"></div>
<div class="fill"></div>
<div class="seal"><small>Winner</small><b>WINNER</b></div>
<div class="name" contenteditable="true" spellcheck="false" data-name="left">Damask</div>
<div class="pct" data-pct="left">50%</div>
</div>
<!-- RIGHT -->
<div class="swatch right" data-side="right">
<div class="ground"></div>
<svg class="tex" viewBox="0 0 108 120" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
<defs>
<pattern id="pat-geo" width="54" height="54" patternUnits="userSpaceOnUse">
<g stroke="var(--r-motif)" stroke-width="1.6" fill="none">
<polygon points="27,3 51,27 27,51 3,27"/>
<polygon points="27,14 40,27 27,40 14,27"/>
</g>
<circle cx="27" cy="27" r="2.4" fill="var(--r-motif)"/>
<circle cx="0" cy="0" r="2.4" fill="var(--r-motif)"/>
<circle cx="54" cy="0" r="2.4" fill="var(--r-motif)"/>
<circle cx="0" cy="54" r="2.4" fill="var(--r-motif)"/>
<circle cx="54" cy="54" r="2.4" fill="var(--r-motif)"/>
</pattern>
</defs>
<rect width="108" height="120" fill="url(#pat-geo)"/>
</svg>
<div class="veil"></div>
<div class="fill"></div>
<div class="seal"><small>Winner</small><b>WINNER</b></div>
<div class="name" contenteditable="true" spellcheck="false" data-name="right">Geometric</div>
<div class="pct" data-pct="right">50%</div>
</div>
<div class="vs">vs</div>
</div>
<div class="results" id="results">
<div class="bar"><div class="bl" style="width:50%"></div><div class="br" style="width:50%"></div></div>
<div class="rlabels">
<span><b id="rl-name">Damask</b> · <span id="rl-count">0</span></span>
<span><span id="rr-count">0</span> · <b id="rr-name">Geometric</b></span>
</div>
</div>
</div>
<div class="tap-hint" id="hint">Tap a side to cast your vote</div>
<div class="story-foot">
<div class="reply">Send message…</div>
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20.8 4.6a5.5 5.5 0 0 0-7.8 0L12 5.6l-1-1a5.5 5.5 0 1 0-7.8 7.8L12 21l8.8-8.6a5.5 5.5 0 0 0 0-7.8Z"/></svg>
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M22 2 11 13"/><path d="M22 2 15 22l-4-9-9-4 20-7Z"/></svg>
</div>
</div>
</div>
<!-- CONTROLS -->
<div class="controls">
<h2>Style the Poll</h2>
<p class="lead">Rename either style directly on the swatch, and set each palette below. Colours flow live into the CSS-drawn wallcovering.</p>
<div class="field-label">Left — Palette</div>
<div class="pickrow">
<div class="pick"><span>Ground</span><input type="color" value="#33403a" data-var="--l-ground"></div>
<div class="pick"><span>Motif</span><input type="color" value="#c8a86a" data-var="--l-motif"></div>
</div>
<div class="field-label">Right — Palette</div>
<div class="pickrow">
<div class="pick"><span>Ground</span><input type="color" value="#2b3550" data-var="--r-ground"></div>
<div class="pick"><span>Motif</span><input type="color" value="#e6ddcf" data-var="--r-motif"></div>
</div>
<div class="btnrow">
<button class="act" id="reset">Reset Votes</button>
<button class="act primary" id="demo">Simulate Audience</button>
</div>
</div>
<p class="foot-note">Designer Wallcoverings · Interactive Story Mockup</p>
</main>
<script>
const story = document.getElementById('story');
const arena = document.getElementById('arena');
const results = document.getElementById('results');
const hint = document.getElementById('hint');
const root = document.documentElement;
const state = { left:0, right:0 };
const names = { left:'Damask', right:'Geometric' };
const el = {
lFill: document.querySelector('.swatch.left .fill'),
rFill: document.querySelector('.swatch.right .fill'),
lPct: document.querySelector('[data-pct="left"]'),
rPct: document.querySelector('[data-pct="right"]'),
lSeal: document.querySelector('.swatch.left .seal'),
rSeal: document.querySelector('.swatch.right .seal'),
bl: results.querySelector('.bl'),
br: results.querySelector('.br'),
rlName: document.getElementById('rl-name'),
rrName: document.getElementById('rr-name'),
rlCount: document.getElementById('rl-count'),
rrCount: document.getElementById('rr-count'),
};
function render(){
const total = state.left + state.right;
const voted = total > 0;
story.classList.toggle('voted', voted);
let lp = 50, rp = 50;
if (voted){ lp = Math.round(state.left/total*100); rp = 100 - lp; }
el.lFill.style.height = voted ? lp+'%' : '0';
el.rFill.style.height = voted ? rp+'%' : '0';
el.lPct.textContent = lp+'%';
el.rPct.textContent = rp+'%';
el.bl.style.width = lp+'%';
el.br.style.width = rp+'%';
el.rlCount.textContent = state.left;
el.rrCount.textContent = state.right;
// grow the leader's tile slightly
document.querySelector('.swatch.left').style.flex = voted ? Math.max(lp,25) : 1;
document.querySelector('.swatch.right').style.flex = voted ? Math.max(rp,25) : 1;
// winner seal
const lead = state.left === state.right ? null : (state.left > state.right ? 'left' : 'right');
el.lSeal.classList.toggle('show', voted && lead==='left');
el.rSeal.classList.toggle('show', voted && lead==='right');
hint.innerHTML = voted
? `<span class="votecount">${total}</span> votes cast · tap to keep voting`
: 'Tap a side to cast your vote';
}
function vote(side){
state[side]++;
render();
}
arena.addEventListener('click', (e)=>{
if (e.target.closest('.name')) return; // editing the label, not voting
const sw = e.target.closest('.swatch');
if (sw) vote(sw.dataset.side);
});
// editable style names
document.querySelectorAll('.name').forEach(n=>{
n.addEventListener('input', ()=>{
const side = n.dataset.name;
names[side] = n.textContent.trim() || (side==='left'?'Style A':'Style B');
el.rlName.textContent = names.left;
el.rrName.textContent = names.right;
});
n.addEventListener('keydown', ev=>{ if(ev.key==='Enter'){ ev.preventDefault(); n.blur(); }});
});
// live color tokens
document.querySelectorAll('input[type=color]').forEach(inp=>{
inp.addEventListener('input', ()=> root.style.setProperty(inp.dataset.var, inp.value));
});
// buttons
document.getElementById('reset').addEventListener('click', ()=>{
state.left = 0; state.right = 0; render();
});
document.getElementById('demo').addEventListener('click', ()=>{
let n = 0;
const iv = setInterval(()=>{
vote(Math.random() < 0.56 ? 'left' : 'right');
if(++n >= 18) clearInterval(iv);
}, 70);
});
render();
</script>
</body>
</html>