← back to Model Arena
data/artifacts/193230252710/claude-code.html
619 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 — Mood Board Maker</title>
<style>
:root{
/* ——— DW luxury design tokens ——— */
--bg:#f4f0e8;
--surface:#fbf8f2;
--panel:#ffffff;
--ink:#1c1a17; /* darkest ink — wordmark */
--ink-soft:#4a463e;
--muted:#9b948a;
--accent:#a6863f; /* single antique-brass metallic */
--accent-deep:#7d6a45;
--line:rgba(28,26,23,.14);
--hair:rgba(28,26,23,.09);
--shadow:0 18px 50px rgba(28,26,23,.16);
--shadow-soft:0 8px 26px rgba(28,26,23,.10);
--ease:cubic-bezier(.22,1,.36,1);
--serif:'Didot','Bodoni MT','Playfair Display','Hoefler Text',Georgia,'Cormorant Garamond',serif;
--sans:-apple-system,'Segoe UI','Helvetica Neue',Arial,sans-serif;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{
font-family:var(--sans);
color:var(--ink);
background:
radial-gradient(1200px 700px at 15% -10%, #fbf7ef 0%, transparent 60%),
radial-gradient(1000px 800px at 110% 120%, #efe9dc 0%, transparent 55%),
var(--bg);
background-attachment:fixed;
animation:drift 22s ease-in-out infinite alternate;
min-height:100%;
-webkit-font-smoothing:antialiased;
}
@keyframes drift{from{background-position:0 0, 0 0, 0 0}to{background-position:-30px 20px, 20px -20px, 0 0}}
/* ——— fixed top bar : logo zone ——— */
header.topbar{
position:fixed;top:0;left:0;right:0;z-index:50;
height:78px;
display:flex;align-items:center;justify-content:space-between;
padding:0 40px;
background:linear-gradient(180deg, rgba(251,248,242,.96), rgba(251,248,242,.82));
backdrop-filter:blur(10px);
border-bottom:1px solid var(--hair);
}
.wordmark{
font-family:var(--serif);
color:var(--ink);
font-size:42px;
line-height:1;
font-weight:500;
letter-spacing:.18em;
text-transform:uppercase;
white-space:nowrap;
}
.wordmark .amp{color:var(--accent-deep)}
.topbar-right{
display:flex;align-items:center;gap:26px;
}
.tagline{
font-family:var(--sans);
font-size:11px;letter-spacing:.22em;text-transform:uppercase;
color:var(--muted);
}
.edition{
font-family:var(--sans);
font-size:11px;letter-spacing:.2em;text-transform:uppercase;
color:var(--ink-soft);
}
.edition b{color:var(--accent-deep);font-weight:600}
/* ——— controls ——— */
.controls{
position:fixed;top:78px;left:0;right:0;z-index:40;
display:flex;align-items:center;justify-content:center;gap:14px;flex-wrap:wrap;
padding:16px 40px;
border-bottom:1px solid var(--hair);
background:rgba(244,240,232,.72);
backdrop-filter:blur(6px);
}
.themes{display:flex;gap:8px;flex-wrap:wrap}
.tab{
font-family:var(--sans);
font-size:11px;letter-spacing:.18em;text-transform:uppercase;
color:var(--ink-soft);
background:transparent;
border:1px solid var(--line);
border-radius:999px;
padding:9px 18px;
cursor:pointer;
transition:all .2s var(--ease);
}
.tab:hover{border-color:var(--accent);color:var(--ink)}
.tab.active{
background:var(--ink);color:var(--surface);border-color:var(--ink);
}
.spacer{width:1px;height:26px;background:var(--line)}
.btn{
font-family:var(--sans);
font-size:11px;letter-spacing:.2em;text-transform:uppercase;font-weight:600;
color:var(--surface);
background:var(--accent-deep);
border:1px solid var(--accent-deep);
border-radius:999px;
padding:11px 26px;
cursor:pointer;
display:inline-flex;align-items:center;gap:9px;
box-shadow:var(--shadow-soft);
transition:transform .18s var(--ease), background .2s var(--ease);
}
.btn:hover{background:var(--accent);transform:translateY(-1px)}
.btn:active{transform:translateY(0)}
.btn svg{width:14px;height:14px}
.btn.ghost{
color:var(--ink);background:transparent;border-color:var(--line);box-shadow:none;
}
.btn.ghost:hover{border-color:var(--accent);background:transparent}
/* ——— stage / board ——— */
.stage{
padding-top:172px;
min-height:100vh;
display:flex;align-items:flex-start;justify-content:center;
padding-bottom:60px;
}
.scaler{transform-origin:top center}
.board{
width:1080px;height:1350px;
background:var(--boardbg,#fbf8f2);
color:var(--boardink,#1c1a17);
box-shadow:var(--shadow);
border:1px solid var(--line);
padding:72px 72px 60px;
display:flex;flex-direction:column;gap:34px;
position:relative;
overflow:hidden;
transition:background .6s var(--ease), color .6s var(--ease);
}
/* board head */
.board-head{
display:flex;align-items:flex-end;justify-content:space-between;
padding-bottom:22px;border-bottom:1px solid var(--boardline,var(--line));
}
.bh-left .bh-mark{
font-family:var(--serif);font-size:20px;letter-spacing:.16em;text-transform:uppercase;
color:var(--boardink);
}
.bh-left .bh-sub{
font-family:var(--sans);font-size:11px;letter-spacing:.24em;text-transform:uppercase;
color:var(--boardmuted,#9b948a);margin-top:8px;
}
.bh-theme{
font-family:var(--serif);font-style:italic;font-size:46px;line-height:1;
color:var(--boardaccent,#a6863f);
text-align:right;
}
.bh-theme small{
display:block;font-family:var(--sans);font-style:normal;
font-size:10px;letter-spacing:.28em;text-transform:uppercase;
color:var(--boardmuted);margin-top:10px;
}
/* hero */
.hero{
position:relative;flex:1;min-height:0;
border:1px solid var(--boardline);
overflow:hidden;
box-shadow:inset 0 0 0 1px rgba(255,255,255,.04);
}
.hero-pattern{position:absolute;inset:0}
.hero-label{
position:absolute;left:0;bottom:0;
background:var(--boardink);color:var(--boardbg);
padding:14px 22px;
font-family:var(--sans);font-size:10px;letter-spacing:.26em;text-transform:uppercase;
}
.hero-label b{font-family:var(--serif);font-size:15px;letter-spacing:.04em;text-transform:none;font-weight:500}
.hero-crest{
position:absolute;top:20px;right:22px;
width:44px;height:44px;border:1px solid var(--boardaccent);
border-radius:50%;display:flex;align-items:center;justify-content:center;
font-family:var(--serif);font-size:15px;color:var(--boardaccent);
background:rgba(0,0,0,.06);letter-spacing:.02em;
}
/* mid grid : pairing + texture */
.mid{display:grid;grid-template-columns:1.8fr 1fr;gap:28px}
.card{
border:1px solid var(--boardline);
background:var(--boardpanel,rgba(255,255,255,.5));
padding:26px 28px;
display:flex;flex-direction:column;
}
.card .cap{
font-family:var(--sans);font-size:10px;letter-spacing:.24em;text-transform:uppercase;
color:var(--boardmuted);margin-bottom:16px;
}
.pair-display{
font-family:var(--pairD,var(--serif));
font-size:64px;line-height:.98;color:var(--boardink);font-weight:500;
}
.pair-body{
font-family:var(--pairB,var(--sans));
font-size:15px;line-height:1.7;color:var(--boardink-soft,#4a463e);
margin-top:16px;max-width:46ch;
}
.pair-names{
margin-top:auto;padding-top:18px;
display:flex;gap:22px;
font-family:var(--sans);font-size:10px;letter-spacing:.16em;text-transform:uppercase;
color:var(--boardmuted);
}
.pair-names span b{color:var(--boardaccent);font-weight:600}
.texture{position:relative;padding:0;overflow:hidden;min-height:200px}
.texture .tx-fill{position:absolute;inset:0}
.texture .tx-tag{
position:absolute;left:0;bottom:0;right:0;
background:linear-gradient(0deg, rgba(0,0,0,.55), transparent);
color:#fff;padding:22px 20px 16px;
font-family:var(--sans);font-size:10px;letter-spacing:.2em;text-transform:uppercase;
}
.texture .tx-tag b{font-family:var(--serif);font-size:16px;letter-spacing:.03em;text-transform:none;font-weight:500;display:block;margin-top:4px}
/* chips */
.chips{display:grid;grid-template-columns:repeat(3,1fr);gap:28px}
.chip{display:flex;flex-direction:column}
.chip .sw{
height:150px;border:1px solid var(--boardline);
box-shadow:var(--shadow-soft);
}
.chip .nm{
font-family:var(--serif);font-size:22px;color:var(--boardink);margin-top:16px;
}
.chip .hx{
font-family:var(--sans);font-size:11px;letter-spacing:.16em;text-transform:uppercase;
color:var(--boardmuted);margin-top:6px;
}
/* footer */
.board-foot{
display:flex;align-items:center;justify-content:space-between;
padding-top:20px;border-top:1px solid var(--boardline);
font-family:var(--sans);font-size:10px;letter-spacing:.22em;text-transform:uppercase;
color:var(--boardmuted);
}
.board-foot .dot{color:var(--boardaccent)}
/* stagger entrance */
.anim{opacity:0}
.play .anim{animation:fadeUp .72s var(--ease) both}
@keyframes fadeUp{from{opacity:0;transform:translateY(26px)}to{opacity:1;transform:none}}
/* toast overlay */
.toast{
position:fixed;left:50%;bottom:34px;transform:translate(-50%,20px);
background:var(--ink);color:var(--surface);
padding:14px 26px;border-radius:999px;
font-family:var(--sans);font-size:11px;letter-spacing:.2em;text-transform:uppercase;
box-shadow:var(--shadow);opacity:0;pointer-events:none;
transition:opacity .3s var(--ease), transform .3s var(--ease);z-index:80;
}
.toast.show{opacity:1;transform:translate(-50%,0)}
.toast b{color:var(--accent)}
</style>
</head>
<body>
<header class="topbar">
<div class="wordmark">Designer <span class="amp">Wallcoverings</span></div>
<div class="topbar-right">
<span class="tagline">Atelier Mood Boards</span>
<span class="edition">Edition <b id="ednum">№ 001</b></span>
</div>
</header>
<nav class="controls">
<div class="themes" id="themes"></div>
<span class="spacer"></span>
<button class="btn" id="regen">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-2.64-6.36"/><path d="M21 3v6h-6"/></svg>
Regenerate
</button>
<button class="btn ghost" id="share">Copy Palette</button>
</nav>
<main class="stage">
<div class="scaler" id="scaler">
<section class="board play" id="board"></section>
</div>
</main>
<div class="toast" id="toast"></div>
<script>
/* ————————————————————————— pattern makers ————————————————————————— */
const svg = s => `url("data:image/svg+xml,${encodeURIComponent(s)}")`;
function damask(fg,bg,ac){
const s=`<svg xmlns='http://www.w3.org/2000/svg' width='120' height='160' viewBox='0 0 120 160'>
<rect width='120' height='160' fill='${bg}'/>
<g fill='none' stroke='${fg}' stroke-width='2.2'>
<path d='M60 14 C90 42 90 62 60 90 C30 62 30 42 60 14 Z'/>
<path d='M60 46 C74 62 74 74 60 90 C46 74 46 62 60 46 Z' fill='${ac}' stroke='none' opacity='.85'/>
<path d='M60 90 C78 110 78 128 60 150 C42 128 42 110 60 90 Z'/>
<path d='M0 90 C14 74 30 74 44 90 C30 106 14 106 0 90 Z'/>
<path d='M120 90 C106 74 90 74 76 90 C90 106 106 106 120 90 Z'/>
</g>
<circle cx='60' cy='118' r='4' fill='${ac}'/>
</svg>`;
return {background:`${bg} ${svg(s)} repeat`, backgroundSize:'120px 160px'};
}
function medallion(fg,bg,ac){
const s=`<svg xmlns='http://www.w3.org/2000/svg' width='110' height='110' viewBox='0 0 110 110'>
<rect width='110' height='110' fill='${bg}'/>
<g stroke='${fg}' stroke-width='2' fill='none'>
<g transform='translate(55,55)'>
<ellipse rx='9' ry='30'/>
<ellipse rx='9' ry='30' transform='rotate(90)'/>
<ellipse rx='8' ry='24' transform='rotate(45)' stroke='${ac}'/>
<ellipse rx='8' ry='24' transform='rotate(135)' stroke='${ac}'/>
<circle r='6' fill='${ac}' stroke='none'/>
</g>
</g>
</svg>`;
return {background:`${bg} ${svg(s)} repeat`, backgroundSize:'110px 110px'};
}
function trellis(fg,bg,ac){
const s=`<svg xmlns='http://www.w3.org/2000/svg' width='72' height='72' viewBox='0 0 72 72'>
<rect width='72' height='72' fill='${bg}'/>
<g stroke='${fg}' stroke-width='2' fill='none'>
<path d='M0 36 L36 0 L72 36 L36 72 Z'/>
<path d='M-36 36 L0 0 M72 0 L108 36 M-36 36 L0 72 M72 72 L108 36'/>
</g>
<circle cx='36' cy='36' r='4' fill='${ac}'/>
<circle cx='0' cy='0' r='3' fill='${ac}'/><circle cx='72' cy='0' r='3' fill='${ac}'/>
<circle cx='0' cy='72' r='3' fill='${ac}'/><circle cx='72' cy='72' r='3' fill='${ac}'/>
</svg>`;
return {background:`${bg} ${svg(s)} repeat`, backgroundSize:'72px 72px'};
}
function botanical(fg,bg,ac){
const s=`<svg xmlns='http://www.w3.org/2000/svg' width='120' height='150' viewBox='0 0 120 150'>
<rect width='120' height='150' fill='${bg}'/>
<g fill='none' stroke='${fg}' stroke-width='2' stroke-linecap='round'>
<path d='M60 150 C60 120 60 90 60 30'/>
<path d='M60 120 C40 112 30 96 32 78 C50 82 60 100 60 118'/>
<path d='M60 96 C80 88 90 72 88 54 C70 58 60 76 60 94'/>
<path d='M60 66 C42 60 34 46 36 30 C52 34 60 50 60 64'/>
</g>
<g fill='${ac}'>
<circle cx='60' cy='26' r='6'/><circle cx='50' cy='36' r='4'/><circle cx='70' cy='36' r='4'/>
</g>
</svg>`;
return {background:`${bg} ${svg(s)} repeat`, backgroundSize:'120px 150px'};
}
function scallop(fg,bg,ac){
const s=`<svg xmlns='http://www.w3.org/2000/svg' width='60' height='36' viewBox='0 0 60 36'>
<rect width='60' height='36' fill='${bg}'/>
<g fill='none' stroke='${fg}' stroke-width='2'>
<path d='M0 18 A15 15 0 0 1 30 18 A15 15 0 0 1 60 18'/>
<path d='M-30 36 A15 15 0 0 1 0 36 A15 15 0 0 1 30 36 A15 15 0 0 1 60 36 A15 15 0 0 1 90 36'/>
<path d='M15 0 A15 15 0 0 1 45 0' stroke='${ac}'/>
</g>
</svg>`;
return {background:`${bg} ${svg(s)} repeat`, backgroundSize:'60px 36px'};
}
function herringbone(fg,bg,ac){
const s=`<svg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 0 48 48'>
<rect width='48' height='48' fill='${bg}'/>
<g stroke='${fg}' stroke-width='3' fill='none' stroke-linecap='square'>
<path d='M0 24 L12 12 L24 24'/><path d='M24 24 L36 12 L48 24'/>
<path d='M0 48 L12 36 L24 48'/><path d='M24 48 L36 36 L48 48'/>
<path d='M0 0 L12 -12 M24 0 L36 -12' stroke='${ac}'/>
</g>
</svg>`;
return {background:`${bg} ${svg(s)} repeat`, backgroundSize:'48px 48px'};
}
function stripe(fg,bg,ac){
return {background:`repeating-linear-gradient(90deg, ${bg} 0 34px, ${fg} 34px 40px, ${bg} 40px 74px, ${ac} 74px 78px)`};
}
function wave(fg,bg,ac){
const s=`<svg xmlns='http://www.w3.org/2000/svg' width='120' height='40' viewBox='0 0 120 40'>
<rect width='120' height='40' fill='${bg}'/>
<g fill='none' stroke-width='2.4'>
<path d='M0 20 Q30 2 60 20 T120 20' stroke='${fg}'/>
<path d='M0 32 Q30 14 60 32 T120 32' stroke='${ac}'/>
</g>
</svg>`;
return {background:`${bg} ${svg(s)} repeat`, backgroundSize:'120px 40px'};
}
function pindot(fg,bg,ac){
return {background:`radial-gradient(${ac} 2.4px, transparent 3px) 0 0/26px 26px, radial-gradient(${fg} 1.6px, transparent 2px) 13px 13px/26px 26px, ${bg}`};
}
function chevron(fg,bg,ac){
return {background:`repeating-linear-gradient(135deg, ${fg} 0 6px, ${bg} 6px 30px), repeating-linear-gradient(45deg, ${ac} 0 3px, transparent 3px 30px), ${bg}`, backgroundBlendMode:'normal'};
}
/* textures — CSS only */
function txGrasscloth(bg,sh){
return {background:`repeating-linear-gradient(90deg, ${bg} 0 2px, ${sh} 2px 3px), repeating-linear-gradient(0deg, rgba(0,0,0,.05) 0 1px, transparent 1px 5px), ${bg}`};
}
function txLinen(bg,sh){
return {background:`repeating-linear-gradient(0deg, ${sh} 0 1px, transparent 1px 4px), repeating-linear-gradient(90deg, ${sh} 0 1px, transparent 1px 4px), ${bg}`};
}
function txSilk(bg,sh){
return {background:`linear-gradient(115deg, ${bg} 0%, ${sh} 40%, ${bg} 55%, ${sh} 80%, ${bg} 100%)`};
}
function txMoire(bg,sh){
return {background:`repeating-radial-gradient(circle at 30% 30%, ${bg} 0 4px, ${sh} 4px 8px)`};
}
const HEROS={damask,medallion,trellis,botanical,scallop,herringbone,stripe,wave,pindot,chevron};
const TEX={txGrasscloth,txLinen,txSilk,txMoire};
/* ————————————————————————— themes ————————————————————————— */
const THEMES={
Classic:{
label:'Heritage Damask',
board:{bg:'#f6f0e2',ink:'#241f16',soft:'#4c4634',muted:'#a99e83',accent:'#a6863f',line:'rgba(36,31,22,.16)',panel:'rgba(255,255,255,.42)'},
heros:['damask','medallion','trellis'],
tex:{fn:'txGrasscloth',names:['Antique Grasscloth','Woven Raffia','Aged Sisal']},
hueBase:'#c9b784',
colors:[['Alabaster','#eee6d4'],['Old Gold','#b6923d'],['Bordeaux','#5c2733'],['Sage','#8b9271'],['Ivory','#f4ecda'],['Espresso','#3a2c22'],['Celadon','#a9bfa4'],['Burnished Brass','#9a7b3f']],
words:['Damask','Ogee','Heirloom','Regalia'],
body:'A hand-drawn ogee, softened by time — printed on grasscloth for a room that remembers its history.'
},
Coastal:{
label:'Harbour Stripe',
board:{bg:'#eef3f4',ink:'#17272e',soft:'#3c5460',muted:'#8fa3ab',accent:'#4f8199',line:'rgba(23,39,46,.15)',panel:'rgba(255,255,255,.5)'},
heros:['stripe','wave','scallop'],
tex:{fn:'txLinen',names:['Salt Linen','Bleached Flax','Sea-Cloth']},
hueBase:'#a9c7d2',
colors:[['Chalk','#eef2f2'],['Harbour Blue','#3f6f88'],['Driftwood','#b6a892'],['Seafoam','#a8cfc6'],['Dune','#ddd2bd'],['Navy Ink','#1f3a4a'],['Pale Sky','#c6dbe3'],['Rope','#c9a86a']],
words:['Harbour','Tideline','Regatta','Estuary'],
body:'Sun-washed stripes and lapping waves — a breezy, open palette drawn from morning light on the water.'
},
Moody:{
label:'Nocturne Trellis',
board:{bg:'#16130f',ink:'#efe7d6',soft:'#c8bda6',muted:'#8a8069',accent:'#c9a961',line:'rgba(239,231,214,.16)',panel:'rgba(255,255,255,.05)'},
heros:['medallion','herringbone','pindot'],
tex:{fn:'txSilk',names:['Midnight Silk','Lacquer Sheen','Onyx Velvet']},
hueBase:'#3a3327',
colors:[['Obsidian','#1a1712'],['Antique Gold','#c9a961'],['Oxblood','#4a1f22'],['Forest','#22362b'],['Pewter','#6b665b'],['Champagne','#d8c8a0'],['Ink Teal','#1e3a3c'],['Smoke','#3d3831']],
words:['Nocturne','Lacquer','Midnight','Vesper'],
body:'Deep, saturated ground with a single thread of gold — drama for a library, a dining room, a late hour.'
},
Botanical:{
label:'Verdure Vine',
board:{bg:'#f1f0e2',ink:'#22301f',soft:'#3f5236',muted:'#94a086',accent:'#5c7a3f',line:'rgba(34,48,31,.16)',panel:'rgba(255,255,255,.46)'},
heros:['botanical','scallop','trellis'],
tex:{fn:'txMoire',names:['Mossed Weave','Fern Cloth','Garden Sisal']},
hueBase:'#a9bd8e',
colors:[['Parchment','#efe9d5'],['Fern','#5c7a3f'],['Terracotta','#b25a3a'],['Olive','#77794a'],['Bloom','#d98fa0'],['Bark','#4a3a2a'],['Celadon','#aac0a2'],['Honey','#cca24e']],
words:['Verdure','Foliage','Arbour','Trellis'],
body:'Trailing stems and quiet blooms — a garden brought indoors, grounded in soft earth and living green.'
}
};
/* type pairings */
const PAIRS=[
{d:"'Didot','Bodoni MT',Georgia,serif", b:"var(--sans)", dn:'Didot', bn:'Neue Grotesque'},
{d:"'Playfair Display','Hoefler Text',Georgia,serif", b:"var(--sans)", dn:'Playfair', bn:'Helvetica Neue'},
{d:"Georgia,'Times New Roman',serif", b:"'Segoe UI',var(--sans)", dn:'Georgia', bn:'Segoe'},
{d:"'Hoefler Text',Garamond,serif", b:"var(--sans)", dn:'Hoefler', bn:'System Sans'},
{d:"'Bodoni MT','Didot',serif", b:"'Helvetica Neue',Arial,sans-serif", dn:'Bodoni', bn:'Helvetica'}
];
/* ————————————————————————— render ————————————————————————— */
let current='Classic', edition=1, lastColors=[];
const rnd=a=>a[Math.floor(Math.random()*a.length)];
function pick(arr,n){const c=[...arr],o=[];while(n-->0&&c.length)o.push(c.splice(Math.floor(Math.random()*c.length),1)[0]);return o;}
function styleStr(o){return Object.entries(o).map(([k,v])=>k.replace(/[A-Z]/g,m=>'-'+m.toLowerCase())+':'+v).join(';');}
function build(theme){
const T=THEMES[theme];
const b=T.board;
const board=document.getElementById('board');
board.style.setProperty('--boardbg',b.bg);
board.style.setProperty('--boardink',b.ink);
board.style.setProperty('--boardink-soft',b.soft);
board.style.setProperty('--boardmuted',b.muted);
board.style.setProperty('--boardaccent',b.accent);
board.style.setProperty('--boardline',b.line);
board.style.setProperty('--boardpanel',b.panel);
// hero
const heroName=rnd(T.heros);
const hero=HEROS[heroName](b.accent, b.bg, b.accent);
// build hero with accent lines on a tinted ground for richness
const heroGround = mix(b.bg,b.ink,theme==='Moody'?0.28:0.10);
const heroPat=HEROS[heroName](b.accent, heroGround, b.accent);
// colors
const cols=pick(T.colors,3);
lastColors=cols;
// texture
const txName=rnd(T.tex.names);
const tx=TEX[T.tex.fn](mix(b.bg,b.ink,theme==='Moody'?0.4:0.16), mix(b.bg,b.accent,0.5));
// pairing
const pr=rnd(PAIRS);
const word=rnd(T.words);
const heroTitle={damask:'Ogee Damask',medallion:'Floret Medallion',trellis:'Garden Trellis',botanical:'Trailing Vine',scallop:'Scallop Shell',herringbone:'Herringbone',stripe:'Regency Stripe',wave:'Tidal Wave',pindot:'Pinned Dot',chevron:'Chevron'}[heroName];
const seed=String(edition).padStart(3,'0');
board.innerHTML=`
<div class="board-head anim" style="animation-delay:.02s">
<div class="bh-left">
<div class="bh-mark">Designer Wallcoverings</div>
<div class="bh-sub">Atelier Curation · Board № ${seed}</div>
</div>
<div class="bh-theme">${theme}<small>${T.label}</small></div>
</div>
<div class="hero anim" style="animation-delay:.10s">
<div class="hero-pattern" style="${styleStr(heroPat)}"></div>
<div class="hero-crest">DW</div>
<div class="hero-label"><b>${heroTitle}</b><br>Signature Pattern · ${theme} Collection</div>
</div>
<div class="mid">
<div class="card anim" style="animation-delay:.18s">
<div class="cap">Type Pairing</div>
<div class="pair-display" style="font-family:${pr.d}">${word}</div>
<div class="pair-body" style="font-family:${pr.b}">${T.body}</div>
<div class="pair-names">
<span>Display · <b>${pr.dn}</b></span>
<span>Text · <b>${pr.bn}</b></span>
</div>
</div>
<div class="card texture anim" style="animation-delay:.26s">
<div class="tx-fill" style="${styleStr(tx)}"></div>
<div class="tx-tag">Texture<b>${txName}</b></div>
</div>
</div>
<div class="chips">
${cols.map((c,i)=>`
<div class="chip anim" style="animation-delay:${.34+i*.09}s">
<div class="sw" style="background:${c[1]}"></div>
<div class="nm">${c[0]}</div>
<div class="hx">${c[1].toUpperCase()}</div>
</div>`).join('')}
</div>
<div class="board-foot anim" style="animation-delay:.62s">
<span>Designer Wallcoverings <span class="dot">◆</span> To The Trade</span>
<span>${theme} · Mood Board № ${seed}</span>
</div>
`;
// replay animation
board.classList.remove('play'); void board.offsetWidth; board.classList.add('play');
}
/* small color mix helper */
function hex2rgb(h){h=h.replace('#','');if(h.length===3)h=h.split('').map(x=>x+x).join('');return[parseInt(h.slice(0,2),16),parseInt(h.slice(2,4),16),parseInt(h.slice(4,6),16)];}
function mix(a,b,t){const A=hex2rgb(a),B=hex2rgb(b);const c=A.map((v,i)=>Math.round(v+(B[i]-v)*t));return'#'+c.map(v=>v.toString(16).padStart(2,'0')).join('');}
/* ————————————————————————— controls ————————————————————————— */
const themesEl=document.getElementById('themes');
Object.keys(THEMES).forEach(name=>{
const btn=document.createElement('button');
btn.className='tab'+(name===current?' active':'');
btn.textContent=name;
btn.onclick=()=>{
current=name;
[...themesEl.children].forEach(c=>c.classList.toggle('active',c.textContent===name));
edition++; setEd(); build(current);
};
themesEl.appendChild(btn);
});
function setEd(){document.getElementById('ednum').textContent='№ '+String(edition).padStart(3,'0');}
document.getElementById('regen').onclick=()=>{edition++;setEd();build(current);toast('Reshuffled');};
document.getElementById('share').onclick=()=>{
const txt=lastColors.map(c=>`${c[0]} ${c[1]}`).join(' · ');
navigator.clipboard&&navigator.clipboard.writeText(`Designer Wallcoverings — ${current} palette: ${txt}`).catch(()=>{});
toast('Palette copied');
};
let tT;
function toast(msg){
const t=document.getElementById('toast');
t.innerHTML=`<b>◆</b> ${msg}`;
t.classList.add('show');
clearTimeout(tT); tT=setTimeout(()=>t.classList.remove('show'),1600);
}
/* fit board to viewport */
function fit(){
const scaler=document.getElementById('scaler');
const availW=window.innerWidth-64;
const availH=window.innerHeight-172-40;
const s=Math.min(availW/1080, availH/1350, 1);
scaler.style.transform=`scale(${s})`;
scaler.style.height=(1350*s)+'px';
scaler.style.width='1080px';
}
window.addEventListener('resize',fit);
setEd();
build(current);
fit();
</script>
</body>
</html>