← back to Model Arena

data/artifacts/0b9bb5066c06/claude-code.html

729 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Which Design Era? — Designer Wallcoverings</title>
<style>
  :root{
    --bg:#0d0d0f;
    --surface:#17171c;
    --surface-2:#1e1e24;
    --text:#f5f2ea;
    --muted:#8a8578;
    --accent:#c9a961;
    --accent-deep:#7d6a45;
    --line:rgba(201,169,97,.22);
    --hairline:rgba(245,242,234,.10);
    --radius:14px;
    --serif:'Didot','Bodoni MT','Playfair Display',Georgia,serif;
    --sans:-apple-system,'Segoe UI','Helvetica Neue',Arial,sans-serif;
  }
  *{box-sizing:border-box;margin:0;padding:0}
  html,body{height:100%}
  body{
    background:var(--bg);
    color:var(--text);
    font-family:var(--sans);
    font-size:16px;
    line-height:1.55;
    -webkit-font-smoothing:antialiased;
    min-height:100%;
    display:flex;
    flex-direction:column;
    overflow-x:hidden;
  }
  /* ambient drift */
  body::before{
    content:"";
    position:fixed;
    inset:-30%;
    z-index:0;
    background:
      radial-gradient(closest-side at 20% 25%, rgba(201,169,97,.06), transparent 70%),
      radial-gradient(closest-side at 80% 75%, rgba(125,106,69,.07), transparent 70%);
    animation:drift 18s ease-in-out infinite alternate;
    pointer-events:none;
  }
  @keyframes drift{
    from{transform:translate3d(-2%,-1%,0) scale(1)}
    to{transform:translate3d(2%,2%,0) scale(1.08)}
  }

  /* ---------- Top bar ---------- */
  .topbar{
    position:fixed;top:0;left:0;right:0;z-index:40;
    display:flex;align-items:center;justify-content:space-between;
    padding:18px 32px;
    background:rgba(13,13,15,.72);
    backdrop-filter:blur(14px) saturate(1.1);
    border-bottom:1px solid var(--hairline);
  }
  .wordmark{
    font-family:var(--serif);
    font-weight:400;
    font-size:20px;
    letter-spacing:.18em;
    text-transform:uppercase;
    color:var(--text);
    white-space:nowrap;
  }
  .wordmark .amp{color:var(--accent)}
  .topbar .tag{
    font-size:12px;letter-spacing:.15em;text-transform:uppercase;
    color:var(--muted);white-space:nowrap;
  }

  /* ---------- Layout ---------- */
  .wrap{
    position:relative;z-index:1;
    flex:1;
    width:100%;
    max-width:1080px;
    margin:0 auto;
    padding:120px 32px 64px;
    display:flex;
    flex-direction:column;
  }

  .eyebrow{
    font-size:12px;letter-spacing:.28em;text-transform:uppercase;
    color:var(--accent);
    margin-bottom:14px;
  }
  h1.title{
    font-family:var(--serif);
    font-weight:400;
    font-size:50px;
    line-height:1.05;
    letter-spacing:.01em;
    margin-bottom:10px;
  }
  h1.title em{font-style:italic;color:var(--accent)}
  .subtitle{
    color:var(--muted);
    font-size:17px;
    max-width:52ch;
    margin-bottom:8px;
  }

  /* ---------- Scoreboard ---------- */
  .scorebar{
    display:flex;flex-wrap:wrap;gap:14px;
    margin:28px 0 24px;
  }
  .stat{
    background:var(--surface);
    border:1px solid var(--hairline);
    border-radius:var(--radius);
    padding:14px 20px;
    min-width:104px;
    box-shadow:0 8px 24px rgba(0,0,0,.24);
  }
  .stat .k{
    font-size:11px;letter-spacing:.18em;text-transform:uppercase;
    color:var(--muted);margin-bottom:6px;
  }
  .stat .v{
    font-family:var(--serif);font-size:30px;line-height:1;
    color:var(--text);
  }
  .stat.best .v{color:var(--accent)}

  /* progress rail */
  .rail{
    height:2px;width:100%;
    background:var(--hairline);
    border-radius:2px;overflow:hidden;
    margin-bottom:30px;
  }
  .rail span{
    display:block;height:100%;
    background:linear-gradient(90deg,var(--accent-deep),var(--accent));
    width:0;transition:width .6s cubic-bezier(.22,1,.36,1);
  }

  /* ---------- Stage / vignette ---------- */
  .stage-wrap{
    display:grid;
    grid-template-columns:1fr;
    gap:32px;
  }
  @media(min-width:860px){
    .stage-wrap{grid-template-columns:minmax(0,1.15fr) minmax(0,1fr)}
  }

  .vignette{
    position:relative;
    aspect-ratio:4/3;
    border-radius:var(--radius);
    overflow:hidden;
    border:1px solid var(--hairline);
    box-shadow:0 16px 48px rgba(0,0,0,.42);
    background:#111;
    animation:fadeUp .7s cubic-bezier(.22,1,.36,1) both;
  }
  .vignette .frame-label{
    position:absolute;left:14px;top:14px;z-index:6;
    font-size:11px;letter-spacing:.2em;text-transform:uppercase;
    color:rgba(255,255,255,.72);
    background:rgba(0,0,0,.34);
    backdrop-filter:blur(4px);
    padding:6px 12px;border-radius:40px;
    border:1px solid rgba(255,255,255,.14);
  }

  /* the room: floor + wall + rug + furniture built in CSS */
  .room{position:absolute;inset:0}
  .wall{position:absolute;left:0;right:0;top:0;height:70%}
  .floor{position:absolute;left:0;right:0;bottom:0;height:30%}
  .baseboard{position:absolute;left:0;right:0;top:70%;height:2.4%;transform:translateY(-100%)}
  /* window / art frame */
  .feature{
    position:absolute;left:50%;top:15%;transform:translateX(-50%);
    width:34%;height:42%;
    border-radius:4px;
  }
  /* sofa / console */
  .furniture{
    position:absolute;left:50%;bottom:9%;transform:translateX(-50%);
    width:56%;height:26%;
    border-radius:10px 10px 6px 6px;
  }
  .furniture::after{
    content:"";position:absolute;left:8%;right:8%;bottom:-9px;height:12px;
    background:rgba(0,0,0,.35);filter:blur(7px);border-radius:50%;
  }
  /* lamp / accent object */
  .accentobj{
    position:absolute;bottom:12%;width:9%;height:30%;
    border-radius:6px 6px 2px 2px;
  }
  .accentobj.l{left:7%}
  .accentobj.r{right:7%}
  .glow{
    position:absolute;inset:0;pointer-events:none;
    background:radial-gradient(ellipse at 50% 38%, rgba(255,255,255,.10), transparent 60%);
    mix-blend-mode:screen;
  }
  .vin{
    position:absolute;inset:0;pointer-events:none;
    box-shadow:inset 0 0 120px 30px rgba(0,0,0,.55);
  }

  /* ---------- Panel (guesses / reveal) ---------- */
  .panel{
    display:flex;flex-direction:column;justify-content:center;
    animation:fadeUp .7s cubic-bezier(.22,1,.36,1) .09s both;
  }
  .panel .prompt{
    font-size:12px;letter-spacing:.2em;text-transform:uppercase;
    color:var(--muted);margin-bottom:16px;
  }
  .choices{display:grid;grid-template-columns:1fr 1fr;gap:14px}
  @media(max-width:420px){.choices{grid-template-columns:1fr}}
  .choice{
    appearance:none;cursor:pointer;
    font-family:var(--serif);
    font-size:19px;letter-spacing:.01em;
    color:var(--text);
    background:var(--surface);
    border:1px solid var(--line);
    border-radius:var(--radius);
    padding:20px 16px;
    text-align:left;
    line-height:1.2;
    transition:transform .18s ease, border-color .2s ease, background .2s ease, box-shadow .2s ease;
  }
  .choice small{
    display:block;
    font-family:var(--sans);
    font-size:11px;letter-spacing:.16em;text-transform:uppercase;
    color:var(--muted);margin-top:8px;
    transition:color .2s ease;
  }
  .choice:hover:not(:disabled){
    transform:translateY(-3px);
    border-color:var(--accent);
    box-shadow:0 16px 48px rgba(0,0,0,.4),0 0 24px rgba(201,169,97,.18);
  }
  .choice:disabled{cursor:default}
  .choice.correct{
    border-color:var(--accent);
    background:linear-gradient(180deg,rgba(201,169,97,.16),rgba(201,169,97,.05));
    box-shadow:0 0 24px rgba(201,169,97,.32);
  }
  .choice.correct small{color:var(--accent)}
  .choice.wrong{
    border-color:rgba(176,71,46,.6);
    background:rgba(176,71,46,.09);
    opacity:.92;
  }
  .choice.dim{opacity:.4}

  /* reveal card */
  .reveal{
    background:var(--surface);
    border:1px solid var(--line);
    border-radius:var(--radius);
    padding:24px;
    box-shadow:0 16px 48px rgba(0,0,0,.38);
    animation:fadeUp .5s cubic-bezier(.22,1,.36,1) both;
  }
  .reveal .verdict{
    font-size:12px;letter-spacing:.2em;text-transform:uppercase;
    margin-bottom:10px;
  }
  .reveal .verdict.hit{color:var(--accent)}
  .reveal .verdict.miss{color:#d98b6f}
  .reveal h3{
    font-family:var(--serif);font-weight:400;
    font-size:28px;line-height:1.1;margin-bottom:4px;
  }
  .reveal .years{
    font-size:12px;letter-spacing:.14em;text-transform:uppercase;
    color:var(--muted);margin-bottom:14px;
  }
  .reveal .fact{
    color:var(--text);font-size:15px;line-height:1.6;
    padding-top:14px;border-top:1px solid var(--hairline);
  }
  .reveal .fact b{color:var(--accent);font-weight:600}

  .actions{display:flex;gap:12px;margin-top:20px;flex-wrap:wrap}
  .btn{
    appearance:none;cursor:pointer;
    font-family:var(--sans);
    font-size:12px;letter-spacing:.16em;text-transform:uppercase;
    padding:14px 26px;border-radius:40px;
    border:1px solid var(--accent);
    background:var(--accent);color:#141310;font-weight:600;
    transition:transform .18s ease,box-shadow .2s ease,background .2s ease;
  }
  .btn:hover{transform:translateY(-2px);box-shadow:0 0 24px rgba(201,169,97,.4)}
  .btn.ghost{background:transparent;color:var(--text);border-color:var(--hairline)}
  .btn.ghost:hover{border-color:var(--accent);box-shadow:none}

  /* ---------- Final screen ---------- */
  .final{
    text-align:center;
    max-width:640px;margin:0 auto;
    animation:fadeUp .7s cubic-bezier(.22,1,.36,1) both;
    padding:24px 0;
  }
  .final .grade{
    font-family:var(--serif);
    font-size:67px;line-height:1;
    color:var(--accent);
    margin:6px 0 4px;
  }
  .final .finalscore{
    font-family:var(--serif);font-size:38px;margin-bottom:8px;
  }
  .final p{color:var(--muted);font-size:16px;margin-bottom:6px}
  .final .newbest{
    display:inline-block;margin:14px 0;
    font-size:12px;letter-spacing:.2em;text-transform:uppercase;
    color:var(--accent);
    border:1px solid var(--line);border-radius:40px;padding:8px 18px;
  }

  .hidden{display:none !important}

  footer{
    position:relative;z-index:1;
    text-align:center;padding:26px 32px 34px;
    font-size:11px;letter-spacing:.16em;text-transform:uppercase;
    color:var(--muted);
    border-top:1px solid var(--hairline);
  }
  @keyframes fadeUp{from{opacity:0;transform:translateY(28px)}to{opacity:1;transform:none}}

  @media(max-width:560px){
    h1.title{font-size:38px}
    .topbar{padding:14px 20px}
    .topbar .tag{display:none}
    .wrap{padding:104px 20px 48px}
  }
</style>
</head>
<body>
  <header class="topbar">
    <div class="wordmark">Designer&nbsp;Wallcoverings</div>
    <div class="tag">The Design Era Salon</div>
  </header>

  <main class="wrap">
    <!-- Intro / persistent header -->
    <div class="eyebrow">A Connoisseur's Game</div>
    <h1 class="title">Which <em>Design Era</em>?</h1>
    <p class="subtitle">Study each interior vignette and name the period it belongs to. Eight rounds. One trained eye.</p>

    <div class="scorebar">
      <div class="stat"><div class="k">Round</div><div class="v" id="roundNum">1<span style="color:var(--muted);font-size:18px">/8</span></div></div>
      <div class="stat"><div class="k">Score</div><div class="v" id="scoreNum">0</div></div>
      <div class="stat best"><div class="k">Best</div><div class="v" id="bestNum">0</div></div>
    </div>
    <div class="rail"><span id="rail"></span></div>

    <!-- Game area -->
    <section id="gameArea" class="stage-wrap">
      <div class="vignette" id="vignette">
        <span class="frame-label">Interior Study № <span id="studyNo">01</span></span>
        <div class="room" id="room"></div>
        <div class="glow"></div>
        <div class="vin"></div>
      </div>

      <div class="panel">
        <div id="guessBlock">
          <div class="prompt">Name the era</div>
          <div class="choices" id="choices"></div>
        </div>
        <div id="revealBlock" class="hidden"></div>
      </div>
    </section>

    <!-- Final -->
    <section id="finalArea" class="final hidden"></section>
  </main>

  <footer>Designer Wallcoverings · Curated Interiors Since The Grand Tradition</footer>

<script>
(function(){
  "use strict";

  /* ---------- Era definitions (with CSS-render recipes) ---------- */
  var ERAS = [
    {
      id:"victorian",
      name:"Victorian",
      years:"c. 1837 – 1901",
      fact:"The Victorians pioneered mass-produced wallpaper — deep jewel tones, dense damask and floral repeats, and layered pattern-on-pattern. William Morris's <b>arts-and-crafts botanicals</b> defined the age's love of ornament.",
      render:function(){
        return {
          wall:"repeating-linear-gradient(45deg,#3a1220 0 14px,#4a1a2b 14px 28px),radial-gradient(circle at 30% 30%,rgba(201,169,97,.16),transparent 40%)",
          wallExtra:"#3d1424",
          floor:"repeating-linear-gradient(90deg,#3a2418 0 26px,#2e1c12 26px 30px)",
          baseboard:"#1c0f14",
          feature:{bg:"linear-gradient(160deg,#6d2338,#3a1120)",border:"5px solid #b8933f",radius:"50% 50% 4px 4px"},
          furniture:{bg:"linear-gradient(180deg,#7a2438,#521726)",border:"1px solid #a07a34"},
          accent:{bg:"linear-gradient(180deg,#c9a961,#8a6d34)"},
          accentShape:"2px"
        };
      }
    },
    {
      id:"artdeco",
      name:"Art Deco",
      years:"c. 1920 – 1939",
      fact:"Art Deco celebrated the machine age — <b>bold geometry, sunburst and chevron motifs, and lacquered luxury</b>. Black, gold and jade in symmetrical, streamlined compositions signalled glamour and modern optimism.",
      render:function(){
        return {
          wall:"repeating-linear-gradient(90deg,#12181b 0 40px,#161f22 40px 80px),linear-gradient(180deg,rgba(201,169,97,.14),transparent 55%)",
          wallExtra:"#12181b",
          floor:"repeating-linear-gradient(90deg,#0e1214 0 20px,#1a2226 20px 40px)",
          baseboard:"linear-gradient(90deg,#c9a961,#7d6a45)",
          feature:{bg:"conic-gradient(from 270deg at 50% 100%,#c9a961 0 25%,#1a2226 0 50%,#c9a961 0 75%,#1a2226 0)",border:"3px solid #c9a961",radius:"4px"},
          furniture:{bg:"linear-gradient(180deg,#12454a,#0c2e32)",border:"1px solid #c9a961"},
          accent:{bg:"linear-gradient(180deg,#c9a961,#6d5a2e)"},
          accentShape:"50% 50% 0 0"
        };
      }
    },
    {
      id:"midcentury",
      name:"Mid-Century Modern",
      years:"c. 1945 – 1969",
      fact:"Post-war design embraced <b>clean lines, organic curves and warm woods</b>. Atomic-age motifs, tapered legs, mustard-teal-walnut palettes and an easy indoor-outdoor optimism defined the modern home.",
      render:function(){
        return {
          wall:"linear-gradient(180deg,#c98a3f,#b07530)",
          wallExtra:"#bd7f37",
          floor:"linear-gradient(180deg,#6b4a2c,#54371f)",
          baseboard:"#3c2817",
          feature:{bg:"radial-gradient(circle at 50% 50%,#2f7d6b 0 30%,#e0c07a 30% 42%,#c05a34 42% 54%,#2f7d6b 54% 66%,transparent 66%)",border:"0",radius:"50%"},
          furniture:{bg:"linear-gradient(180deg,#d8a94e,#b98634)",border:"1px solid #8a5f2c"},
          accent:{bg:"linear-gradient(180deg,#2f7d6b,#1f5548)"},
          accentShape:"40% 40% 6px 6px"
        };
      }
    },
    {
      id:"grandmillennial",
      name:"Grandmillennial",
      years:"c. 2015 – present",
      fact:"A modern revival of <b>'granny chic' — chintz florals, scalloped edges, skirted tables and ruffles</b> reimagined for a new generation. Soft pinks, blues and layered pattern bring maximalist warmth back to interiors.",
      render:function(){
        return {
          wall:"repeating-radial-gradient(circle at 20px 20px,rgba(176,71,46,.14) 0 6px,transparent 6px 22px),linear-gradient(180deg,#e9eef0,#dbe6e6)",
          wallExtra:"#e6edee",
          floor:"linear-gradient(180deg,#c9b9a6,#b6a390)",
          baseboard:"#f5f2ea",
          feature:{bg:"repeating-linear-gradient(45deg,#e79db0 0 10px,#f3d0da 10px 20px)",border:"5px solid #ffffff",radius:"8px 8px 40% 40%"},
          furniture:{bg:"repeating-linear-gradient(90deg,#7fa7c4 0 12px,#a9c6dc 12px 24px)",border:"2px solid #ffffff"},
          accent:{bg:"linear-gradient(180deg,#e79db0,#c56f84)"},
          accentShape:"50% 50% 4px 4px"
        };
      }
    }
  ];

  var ERA_META = {
    victorian:"c. 1837 – 1901",
    artdeco:"c. 1920 – 1939",
    midcentury:"c. 1945 – 1969",
    grandmillennial:"c. 2015 – now"
  };

  var TOTAL_ROUNDS = 8;
  var BEST_KEY = "dw_design_era_best";

  /* ---------- State ---------- */
  var state = {
    round:0,
    score:0,
    best:0,
    sequence:[],
    answered:false
  };

  /* ---------- Elements ---------- */
  var el = {
    room:document.getElementById("room"),
    studyNo:document.getElementById("studyNo"),
    choices:document.getElementById("choices"),
    guessBlock:document.getElementById("guessBlock"),
    revealBlock:document.getElementById("revealBlock"),
    roundNum:document.getElementById("roundNum"),
    scoreNum:document.getElementById("scoreNum"),
    bestNum:document.getElementById("bestNum"),
    rail:document.getElementById("rail"),
    gameArea:document.getElementById("gameArea"),
    finalArea:document.getElementById("finalArea"),
    vignette:document.getElementById("vignette")
  };

  /* ---------- Utilities ---------- */
  function shuffle(arr){
    var a = arr.slice();
    for(var i=a.length-1;i>0;i--){
      var j = Math.floor(Math.random()*(i+1));
      var t=a[i];a[i]=a[j];a[j]=t;
    }
    return a;
  }
  function pad(n){return n<10?("0"+n):(""+n);}

  function loadBest(){
    try{
      var v = localStorage.getItem(BEST_KEY);
      state.best = v ? (parseInt(v,10)||0) : 0;
    }catch(e){ state.best = 0; }
  }
  function saveBest(){
    try{ localStorage.setItem(BEST_KEY, String(state.best)); }catch(e){}
  }

  /* ---------- Build the CSS room for an era ---------- */
  function paintRoom(era){
    var r = era.render();
    el.room.innerHTML = "";

    var wall = document.createElement("div");
    wall.className = "wall";
    wall.style.background = r.wallExtra;
    wall.style.backgroundImage = r.wall;

    var baseboard = document.createElement("div");
    baseboard.className = "baseboard";
    baseboard.style.background = r.baseboard;

    var floor = document.createElement("div");
    floor.className = "floor";
    floor.style.backgroundImage = r.floor;

    var feature = document.createElement("div");
    feature.className = "feature";
    feature.style.background = r.feature.bg;
    feature.style.border = r.feature.border;
    feature.style.borderRadius = r.feature.radius;
    feature.style.boxShadow = "0 10px 30px rgba(0,0,0,.4)";

    var furn = document.createElement("div");
    furn.className = "furniture";
    furn.style.background = r.furniture.bg;
    furn.style.border = r.furniture.border;
    furn.style.boxShadow = "0 12px 26px rgba(0,0,0,.4)";

    var lampL = document.createElement("div");
    lampL.className = "accentobj l";
    lampL.style.background = r.accent.bg;
    lampL.style.borderRadius = r.accentShape;

    var lampR = document.createElement("div");
    lampR.className = "accentobj r";
    lampR.style.background = r.accent.bg;
    lampR.style.borderRadius = r.accentShape;

    el.room.appendChild(wall);
    el.room.appendChild(floor);
    el.room.appendChild(baseboard);
    el.room.appendChild(feature);
    el.room.appendChild(lampL);
    el.room.appendChild(lampR);
    el.room.appendChild(furn);

    /* re-trigger entrance animation */
    el.vignette.style.animation = "none";
    void el.vignette.offsetWidth;
    el.vignette.style.animation = "";
  }

  /* ---------- Render a round ---------- */
  function renderRound(){
    state.answered = false;
    var era = state.sequence[state.round];

    el.studyNo.textContent = pad(state.round+1);
    el.roundNum.innerHTML = (state.round+1) + '<span style="color:var(--muted);font-size:18px">/'+TOTAL_ROUNDS+'</span>';
    el.scoreNum.textContent = state.score;
    el.bestNum.textContent = state.best;
    el.rail.style.width = ((state.round)/TOTAL_ROUNDS*100) + "%";

    paintRoom(era);

    el.revealBlock.classList.add("hidden");
    el.revealBlock.innerHTML = "";
    el.guessBlock.classList.remove("hidden");

    el.choices.innerHTML = "";
    var order = shuffle(ERAS);
    order.forEach(function(opt){
      var b = document.createElement("button");
      b.className = "choice";
      b.type = "button";
      b.setAttribute("data-id", opt.id);
      b.innerHTML = opt.name + "<small>" + ERA_META[opt.id] + "</small>";
      b.addEventListener("click", function(){ onGuess(opt, era, b); });
      el.choices.appendChild(b);
    });
  }

  /* ---------- Handle a guess ---------- */
  function onGuess(picked, actual, btnEl){
    if(state.answered) return;
    state.answered = true;

    var correct = picked.id === actual.id;
    if(correct) state.score++;

    /* mark buttons */
    var btns = el.choices.querySelectorAll(".choice");
    btns.forEach(function(b){
      b.disabled = true;
      var id = b.getAttribute("data-id");
      if(id === actual.id){ b.classList.add("correct"); }
      else if(b === btnEl){ b.classList.add("wrong"); }
      else { b.classList.add("dim"); }
    });

    el.scoreNum.textContent = state.score;
    el.rail.style.width = ((state.round+1)/TOTAL_ROUNDS*100) + "%";

    /* reveal card */
    var isLast = (state.round+1) >= TOTAL_ROUNDS;
    var v = correct
      ? '<div class="verdict hit">✦ Correct — a trained eye</div>'
      : '<div class="verdict miss">Not quite — you guessed '+picked.name+'</div>';

    el.revealBlock.innerHTML =
      '<div class="reveal">'+
        v+
        '<h3>'+actual.name+'</h3>'+
        '<div class="years">'+actual.years+'</div>'+
        '<div class="fact">'+actual.fact+'</div>'+
        '<div class="actions">'+
          '<button class="btn" id="nextBtn">'+(isLast?"See Results":"Next Vignette")+'</button>'+
        '</div>'+
      '</div>';

    el.guessBlock.classList.add("hidden");
    el.revealBlock.classList.remove("hidden");

    document.getElementById("nextBtn").addEventListener("click", function(){
      if(isLast){ showFinal(); }
      else { state.round++; renderRound(); }
    });
  }

  /* ---------- Final screen ---------- */
  function gradeFor(score){
    var pct = score/TOTAL_ROUNDS;
    if(pct === 1) return {g:"Curator", note:"A flawless eye. The archive is yours."};
    if(pct >= .75) return {g:"Connoisseur", note:"Exceptional taste and a discerning eye."};
    if(pct >= .5) return {g:"Aesthete", note:"A fine sense of period and place."};
    if(pct >= .25) return {g:"Apprentice", note:"The eye is training. Study on."};
    return {g:"Novice", note:"Every collector begins somewhere."};
  }

  function showFinal(){
    var newBest = false;
    if(state.score > state.best){
      state.best = state.score;
      saveBest();
      newBest = true;
    }
    el.bestNum.textContent = state.best;
    el.rail.style.width = "100%";

    var gr = gradeFor(state.score);

    el.gameArea.classList.add("hidden");
    el.finalArea.classList.remove("hidden");
    el.finalArea.innerHTML =
      '<div class="eyebrow" style="text-align:center">The Verdict</div>'+
      '<div class="grade">'+gr.g+'</div>'+
      '<div class="finalscore">'+state.score+' <span style="color:var(--muted);font-size:24px">/ '+TOTAL_ROUNDS+'</span></div>'+
      '<p>'+gr.note+'</p>'+
      (newBest ? '<div class="newbest">✦ New Personal Best</div>' : '<p style="margin-top:8px">Personal best · '+state.best+' / '+TOTAL_ROUNDS+'</p>')+
      '<div class="actions" style="justify-content:center;margin-top:26px">'+
        '<button class="btn" id="restartBtn">Play Again</button>'+
      '</div>';

    document.getElementById("restartBtn").addEventListener("click", startGame);
  }

  /* ---------- Start / restart ---------- */
  function buildSequence(){
    /* 8 rounds: two shuffled passes of the four eras so each appears twice, order randomized */
    var seq = shuffle(ERAS).concat(shuffle(ERAS));
    /* avoid the same era back-to-back at the seam */
    if(seq.length>4 && seq[3].id === seq[4].id){
      var tmp = seq[4]; seq[4] = seq[5]; seq[5] = tmp;
    }
    return seq;
  }

  function startGame(){
    state.round = 0;
    state.score = 0;
    state.answered = false;
    state.sequence = buildSequence();

    el.finalArea.classList.add("hidden");
    el.finalArea.innerHTML = "";
    el.gameArea.classList.remove("hidden");

    renderRound();
  }

  /* ---------- Init ---------- */
  loadBest();
  el.bestNum.textContent = state.best;
  startGame();
})();
</script>
</body>
</html>