DIY — Project Contest Page
A themed maker-community contest page for the fictional MAKELOG Contests, built in plain HTML, CSS and vanilla JavaScript. It pairs a confetti-flecked hero with a live ticking deadline countdown, three SVG-medal prize tiers with an elevated grand prize, an eligibility checklist beside weighted judging bars that fill on scroll, a filterable entries gallery with like toggles and staggered reshuffling, hoverable judge bios, an accordion FAQ and a validated entry dialog.
MCP
Code
:root{
--paper:#fffdfa;
--paper-2:#fbf6ef;
--primary:#e8552d;
--primary-d:#c9421d;
--primary-soft:#ffe6dd;
--teal:#0f8a8a;
--teal-d:#0b6d6d;
--teal-soft:#dcf1f1;
--gold:#f2b134;
--gold-d:#c9902a;
--gold-soft:#fdf0d6;
--ink:#22201e;
--ink-2:#4a4744;
--muted:#7c7873;
--line:rgba(34,32,30,.12);
--line-2:rgba(34,32,30,.22);
--ok:#2f9e6f;
--danger:#d4503e;
--r-sm:6px; --r-md:12px; --r-lg:18px;
--sh-1:0 1px 2px rgba(34,32,30,.06), 0 4px 14px rgba(34,32,30,.06);
--sh-2:0 2px 6px rgba(34,32,30,.08), 0 18px 40px rgba(34,32,30,.12);
}
*,*::before,*::after{box-sizing:border-box}
/* Keeps [hidden] winning over class rules that set a display value. */
[hidden]{display:none!important}
html{-webkit-text-size-adjust:100%}
body{
margin:0;
font-family:Inter,system-ui,sans-serif;
font-size:16px;line-height:1.5;
color:var(--ink);
background:var(--paper);
-webkit-font-smoothing:antialiased;
}
h1,h2,h3{margin:0;line-height:1.15;letter-spacing:-.02em}
p{margin:0}
ul{margin:0;padding:0;list-style:none}
img,svg{max-width:100%}
code{font-family:"JetBrains Mono",monospace;font-size:.86em;background:var(--gold-soft);padding:1px 5px;border-radius:4px}
.mono{font-family:"JetBrains Mono",monospace}
:focus-visible{outline:3px solid var(--teal);outline-offset:2px;border-radius:4px}
.skip{position:absolute;left:-9999px;top:0;background:var(--ink);color:#fff;padding:10px 16px;z-index:99}
.skip:focus{left:8px;top:8px}
.wrap{width:min(1180px,100% - 40px);margin-inline:auto}
.wrap-narrow{width:min(760px,100% - 40px)}
/* ---------- buttons ---------- */
.btn{
font:inherit;font-weight:600;cursor:pointer;
border:1px solid transparent;border-radius:999px;
padding:10px 20px;
display:inline-flex;align-items:center;justify-content:center;gap:8px;
transition:transform .14s ease, box-shadow .18s ease, background .18s ease, color .18s ease;
}
.btn:active{transform:translateY(1px) scale(.99)}
.btn-sm{padding:8px 16px;font-size:.9rem}
.btn-lg{padding:14px 28px;font-size:1.02rem}
.btn-full{width:100%}
.btn-primary{background:var(--primary);color:#fff;box-shadow:0 6px 18px rgba(232,85,45,.3)}
.btn-primary:hover{background:var(--primary-d);box-shadow:0 10px 26px rgba(232,85,45,.38)}
.btn-gold{background:var(--gold);color:#3a2c08;box-shadow:0 6px 18px rgba(242,177,52,.35)}
.btn-gold:hover{background:var(--gold-d);color:#2a2005}
.btn-ghost{background:transparent;color:var(--ink);border-color:var(--line-2)}
.btn-ghost:hover{background:var(--paper-2);border-color:var(--ink-2)}
/* ---------- topbar ---------- */
.topbar{
position:sticky;top:0;z-index:40;
background:rgba(255,253,250,.9);
backdrop-filter:blur(10px);
border-bottom:1px solid var(--line);
}
.topbar-in{display:flex;align-items:center;gap:24px;height:66px}
.brand{display:flex;align-items:center;gap:10px;text-decoration:none;color:var(--ink)}
.brand-mark{width:34px;height:34px;flex:none}
.brand-text{font-weight:800;letter-spacing:-.03em;font-size:1.02rem}
.brand-text em{font-style:normal;font-weight:500;color:var(--muted);margin-left:5px}
.topnav{margin-left:auto;display:flex;gap:22px}
.topnav a{color:var(--ink-2);text-decoration:none;font-weight:500;font-size:.94rem;padding:4px 0;border-bottom:2px solid transparent}
.topnav a:hover{color:var(--primary);border-bottom-color:var(--primary)}
/* ---------- hero ---------- */
.hero{
position:relative;overflow:hidden;
background:
radial-gradient(900px 420px at 12% -10%, rgba(242,177,52,.22), transparent 60%),
radial-gradient(700px 400px at 92% 0%, rgba(15,138,138,.16), transparent 62%),
linear-gradient(180deg,var(--paper-2),var(--paper));
border-bottom:1px solid var(--line);
}
.confetti{position:absolute;inset:0;pointer-events:none;opacity:.9}
.confetti svg{width:100%;height:100%}
.hero-in{
display:grid;grid-template-columns:1.35fr .85fr;gap:48px;align-items:center;
padding:70px 0 78px;position:relative;
}
.ribbon{
display:inline-flex;align-items:center;gap:8px;
background:var(--primary-soft);color:var(--primary-d);
font-family:"JetBrains Mono",monospace;font-size:.76rem;font-weight:700;
text-transform:uppercase;letter-spacing:.08em;
padding:7px 14px;border-radius:999px;border:1px solid rgba(232,85,45,.24);
}
.ribbon svg{width:13px;height:13px}
h1{font-size:clamp(2.3rem,5.4vw,3.7rem);font-weight:800;margin:18px 0 14px}
h1 .hl{color:var(--primary);position:relative;white-space:nowrap}
h1 .hl::after{
content:"";position:absolute;left:0;right:0;bottom:.06em;height:.16em;
background:var(--gold);opacity:.42;border-radius:4px;z-index:-1;
}
.lede{font-size:1.08rem;color:var(--ink-2);max-width:56ch}
.hero-meta{display:flex;flex-wrap:wrap;gap:10px;margin:22px 0 26px}
.chip{
background:#fff;border:1px solid var(--line);border-radius:999px;
padding:7px 14px;font-size:.88rem;color:var(--ink-2);box-shadow:var(--sh-1);
}
.chip b{color:var(--ink);font-family:"JetBrains Mono",monospace}
.hero-cta{display:flex;flex-wrap:wrap;gap:12px}
.countdown{
background:#fff;border:1px solid var(--line);border-radius:var(--r-lg);
padding:26px;box-shadow:var(--sh-2);position:relative;
}
.countdown::before{
content:"";position:absolute;inset:0 0 auto 0;height:5px;border-radius:var(--r-lg) var(--r-lg) 0 0;
background:linear-gradient(90deg,var(--primary),var(--gold),var(--teal));
}
.cd-label{
font-family:"JetBrains Mono",monospace;font-size:.74rem;font-weight:700;
text-transform:uppercase;letter-spacing:.12em;color:var(--muted);margin-bottom:14px;
}
.cd-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}
.cd-cell{
background:var(--paper-2);border:1px solid var(--line);border-radius:var(--r-md);
padding:12px 4px;text-align:center;
}
.cd-num{
display:block;font-family:"JetBrains Mono",monospace;font-weight:700;
font-size:clamp(1.3rem,3vw,1.7rem);color:var(--ink);font-variant-numeric:tabular-nums;
}
.cd-unit{display:block;font-size:.68rem;text-transform:uppercase;letter-spacing:.1em;color:var(--muted);margin-top:4px}
.cd-live{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.cd-dates{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:18px 0 0;padding-top:16px;border-top:1px dashed var(--line-2)}
.cd-dates dt{font-size:.7rem;text-transform:uppercase;letter-spacing:.09em;color:var(--muted)}
.cd-dates dd{margin:3px 0 0;font-family:"JetBrains Mono",monospace;font-size:.84rem;font-weight:600}
/* ---------- sections ---------- */
.section{padding:76px 0}
.section-alt{background:var(--paper-2);border-block:1px solid var(--line)}
.sec-head{max-width:62ch;margin-bottom:36px}
.sec-head h2{font-size:clamp(1.6rem,3.2vw,2.2rem);font-weight:800}
.sec-head p{margin-top:10px;color:var(--ink-2)}
.sec-head-row{display:flex;flex-wrap:wrap;gap:20px;justify-content:space-between;align-items:flex-end;max-width:none}
.sec-head-light h2{color:var(--paper)}
.sec-head-light p{color:rgba(255,253,250,.72)}
/* ---------- prizes ---------- */
.prizes{display:grid;grid-template-columns:1fr 1.16fr 1fr;gap:22px;align-items:center}
.prize{
background:#fff;border:1px solid var(--line);border-radius:var(--r-lg);
padding:30px 26px;text-align:center;box-shadow:var(--sh-1);
transition:transform .2s ease, box-shadow .2s ease;
}
.prize:hover{transform:translateY(-4px);box-shadow:var(--sh-2)}
.medal{width:74px;height:82px;margin:0 auto 14px}
.medal svg{width:100%;height:100%}
.prize-grand .medal{width:92px;height:102px}
.tier-tag{
display:inline-block;font-family:"JetBrains Mono",monospace;font-size:.7rem;font-weight:700;
text-transform:uppercase;letter-spacing:.1em;color:var(--teal-d);
background:var(--teal-soft);border-radius:999px;padding:5px 12px;
}
.prize h3{font-size:1.24rem;margin:12px 0 8px}
.prize p{color:var(--ink-2);font-size:.95rem}
.value{
display:inline-block;margin-top:16px;font-family:"JetBrains Mono",monospace;
font-weight:700;font-size:.86rem;color:var(--ink);
background:var(--paper-2);border:1px solid var(--line-2);border-radius:999px;padding:6px 14px;
}
.value-gold{background:var(--gold-soft);border-color:var(--gold-d);color:#5c4310}
.prize-grand{
position:relative;padding:44px 30px 34px;
border:2px solid var(--gold);
background:linear-gradient(180deg,#fffaf0,#fff);
box-shadow:0 18px 46px rgba(242,177,52,.28);
z-index:1;
}
.crown{
position:absolute;top:-14px;left:50%;transform:translateX(-50%);
background:var(--primary);color:#fff;font-family:"JetBrains Mono",monospace;
font-size:.72rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
padding:6px 18px;border-radius:999px;white-space:nowrap;
box-shadow:0 6px 16px rgba(232,85,45,.35);
}
.perks{margin-top:18px;padding-top:16px;border-top:1px dashed var(--line-2);display:grid;gap:8px;text-align:left}
.perks li{font-size:.9rem;color:var(--ink-2);padding-left:22px;position:relative}
.perks li::before{content:"★";position:absolute;left:0;color:var(--gold-d)}
/* ---------- rules ---------- */
.rules-grid{display:grid;grid-template-columns:1fr 1fr;gap:22px}
.card{background:#fff;border:1px solid var(--line);border-radius:var(--r-lg);padding:28px;box-shadow:var(--sh-1)}
.card-h{font-size:1.16rem;margin-bottom:6px}
.card-sub{color:var(--muted);font-size:.92rem;margin-bottom:18px}
.checklist{display:grid;gap:14px;margin-top:16px}
.checklist li{display:flex;gap:12px;align-items:flex-start;font-size:.95rem;color:var(--ink-2)}
.checklist b{color:var(--ink)}
.tick{
flex:none;width:24px;height:24px;border-radius:50%;
background:var(--teal-soft);color:var(--teal-d);
display:grid;place-items:center;font-size:.8rem;font-weight:700;margin-top:1px;
}
.criteria{display:grid;gap:20px}
.crit-top{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:7px}
.crit-name{font-weight:600}
.crit-pct{font-family:"JetBrains Mono",monospace;font-weight:700;color:var(--primary)}
.bar{height:12px;border-radius:999px;background:var(--paper-2);border:1px solid var(--line);overflow:hidden}
.bar i{
display:block;height:100%;width:0;border-radius:999px;
background:linear-gradient(90deg,var(--primary),var(--gold));
transition:width 1.05s cubic-bezier(.22,.9,.28,1);
}
.criteria li:nth-child(2) .bar i{transition-delay:.1s;background:linear-gradient(90deg,var(--teal),#4fbdbd)}
.criteria li:nth-child(3) .bar i{transition-delay:.2s}
.criteria li:nth-child(4) .bar i{transition-delay:.3s;background:linear-gradient(90deg,var(--teal),#4fbdbd)}
.criteria.is-in .bar i{width:var(--w)}
.crit-note{margin-top:7px;font-size:.86rem;color:var(--muted)}
/* ---------- tabs + gallery ---------- */
.tabs{display:inline-flex;gap:4px;background:var(--paper-2);border:1px solid var(--line);border-radius:999px;padding:4px}
.tab{
font:inherit;font-size:.9rem;font-weight:600;cursor:pointer;
border:0;background:transparent;color:var(--ink-2);
padding:8px 18px;border-radius:999px;transition:background .16s ease,color .16s ease;
}
.tab:hover{color:var(--ink)}
.tab.is-active{background:var(--primary);color:#fff;box-shadow:0 4px 12px rgba(232,85,45,.28)}
.gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(268px,1fr));gap:20px}
.entry{
background:#fff;border:1px solid var(--line);border-radius:var(--r-lg);
overflow:hidden;box-shadow:var(--sh-1);
display:flex;flex-direction:column;
opacity:0;transform:translateY(14px);
animation:pop .42s cubic-bezier(.2,.85,.3,1) forwards;
transition:transform .2s ease, box-shadow .2s ease;
}
.entry:hover{transform:translateY(-4px);box-shadow:var(--sh-2)}
@keyframes pop{to{opacity:1;transform:translateY(0)}}
.entry-art{height:158px;position:relative;display:block}
.entry-art svg{width:100%;height:100%;display:block}
.entry-body{padding:16px 18px 18px;display:flex;flex-direction:column;gap:10px;flex:1}
.entry h3{font-size:1.03rem}
.entry-meta{display:flex;align-items:center;gap:8px;margin-top:auto;padding-top:8px}
.maker{
display:inline-flex;align-items:center;gap:7px;font-size:.84rem;color:var(--ink-2);
background:var(--paper-2);border:1px solid var(--line);border-radius:999px;padding:4px 11px 4px 4px;
}
.maker .av{width:20px;height:20px;border-radius:50%;display:grid;place-items:center;font-size:.62rem;font-weight:700;color:#fff;font-family:"JetBrains Mono",monospace}
.like{
margin-left:auto;font:inherit;font-size:.85rem;font-weight:600;cursor:pointer;
display:inline-flex;align-items:center;gap:6px;
background:#fff;border:1px solid var(--line-2);border-radius:999px;padding:6px 13px;color:var(--ink-2);
transition:all .16s ease;
}
.like:hover{border-color:var(--primary);color:var(--primary)}
.like svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:2}
.like.on{background:var(--primary-soft);border-color:var(--primary);color:var(--primary-d)}
.like.on svg{fill:var(--primary-d);stroke:var(--primary-d)}
.like.bump{animation:bump .34s ease}
@keyframes bump{40%{transform:scale(1.16)}70%{transform:scale(.96)}100%{transform:scale(1)}}
.badge-new{
position:absolute;top:10px;left:10px;
background:var(--teal);color:#fff;font-family:"JetBrains Mono",monospace;
font-size:.66rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
padding:4px 10px;border-radius:999px;
}
/* ---------- judges ---------- */
.section-dark{
background:
radial-gradient(700px 300px at 20% 0%, rgba(232,85,45,.2), transparent 60%),
radial-gradient(600px 320px at 85% 100%, rgba(15,138,138,.28), transparent 62%),
#22201e;
}
.judges{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}
.judge{
background:rgba(255,253,250,.06);border:1px solid rgba(255,253,250,.14);
border-radius:var(--r-lg);padding:24px;color:var(--paper);
transition:background .2s ease, transform .2s ease, border-color .2s ease;
}
.judge:hover,.judge:focus-within{background:rgba(255,253,250,.11);border-color:var(--gold);transform:translateY(-3px)}
.judge-top{display:flex;align-items:center;gap:14px}
.judge-av{width:52px;height:52px;border-radius:50%;flex:none;display:grid;place-items:center;font-family:"JetBrains Mono",monospace;font-weight:700;color:#22201e}
.judge h3{font-size:1.04rem}
.judge .role{font-size:.84rem;color:rgba(255,253,250,.66);font-family:"JetBrains Mono",monospace}
.judge-bio{
max-height:0;opacity:0;overflow:hidden;
transition:max-height .35s ease, opacity .3s ease, margin .35s ease;
font-size:.92rem;color:rgba(255,253,250,.82);margin-top:0;
}
.judge:hover .judge-bio,.judge:focus-within .judge-bio{max-height:180px;opacity:1;margin-top:14px}
.judge-hint{font-size:.74rem;color:rgba(255,253,250,.45);font-family:"JetBrains Mono",monospace;margin-top:12px}
.judge:hover .judge-hint,.judge:focus-within .judge-hint{display:none}
/* ---------- faq ---------- */
.faq{display:grid;gap:10px}
.q{
background:#fff;border:1px solid var(--line);border-radius:var(--r-md);overflow:hidden;
transition:border-color .18s ease, box-shadow .18s ease;
}
.q.open{border-color:var(--primary);box-shadow:var(--sh-1)}
.q-btn{
width:100%;font:inherit;font-weight:600;text-align:left;cursor:pointer;
background:transparent;border:0;padding:18px 20px;
display:flex;align-items:center;gap:14px;color:var(--ink);
}
.q-btn:hover{background:var(--paper-2)}
.q-ico{
margin-left:auto;flex:none;width:24px;height:24px;border-radius:50%;
background:var(--primary-soft);color:var(--primary-d);display:grid;place-items:center;
font-weight:700;transition:transform .25s ease;
}
.q.open .q-ico{transform:rotate(45deg)}
.q-body{max-height:0;overflow:hidden;transition:max-height .3s ease}
.q-body p{padding:0 20px 20px;color:var(--ink-2);font-size:.95rem}
/* ---------- enter band ---------- */
.enter-band{
background:linear-gradient(120deg,var(--primary),#f0703f 55%,var(--gold));
color:#fff;padding:56px 0;
}
.enter-in{display:flex;flex-wrap:wrap;gap:24px;align-items:center;justify-content:space-between}
.enter-in h2{font-size:clamp(1.5rem,3vw,2rem);font-weight:800}
.enter-in p{margin-top:8px;color:rgba(255,255,255,.9)}
.enter-band .btn-gold{background:#fffdfa;color:var(--primary-d);box-shadow:0 8px 24px rgba(0,0,0,.18)}
.enter-band .btn-gold:hover{background:#fff;color:var(--primary-d)}
/* ---------- footer ---------- */
.foot{background:var(--ink);color:rgba(255,253,250,.6);padding:26px 0}
.foot-in{display:flex;flex-wrap:wrap;gap:12px;justify-content:space-between;font-size:.82rem}
/* ---------- modal ---------- */
.modal{position:fixed;inset:0;z-index:80;display:grid;place-items:center;padding:20px}
.modal-back{position:absolute;inset:0;background:rgba(34,32,30,.6);backdrop-filter:blur(3px);animation:fade .2s ease}
@keyframes fade{from{opacity:0}}
.modal-card{
position:relative;background:var(--paper);border-radius:var(--r-lg);
padding:32px;width:min(460px,100%);box-shadow:var(--sh-2);
animation:rise .26s cubic-bezier(.2,.85,.3,1);max-height:90vh;overflow:auto;
}
@keyframes rise{from{opacity:0;transform:translateY(18px)}}
.modal-x{
position:absolute;top:12px;right:14px;border:0;background:transparent;cursor:pointer;
font-size:1.6rem;line-height:1;color:var(--muted);padding:4px 8px;border-radius:8px;
}
.modal-x:hover{background:var(--paper-2);color:var(--ink)}
.modal-sub{color:var(--muted);font-size:.93rem;margin:8px 0 20px}
#enter-form label{display:block;font-size:.86rem;font-weight:600;margin:14px 0 6px}
#enter-form input[type=text],#enter-form input[type=url]{
width:100%;font:inherit;padding:11px 14px;border:1px solid var(--line-2);
border-radius:var(--r-sm);background:#fff;color:var(--ink);
}
#enter-form input:focus{border-color:var(--primary);outline:none;box-shadow:0 0 0 3px var(--primary-soft)}
.check{display:flex!important;align-items:flex-start;gap:10px;font-weight:400!important;font-size:.9rem!important;margin-top:18px!important}
.check input{margin-top:3px;accent-color:var(--primary);width:16px;height:16px}
.form-err{color:var(--danger);font-size:.86rem;margin:12px 0 0;font-weight:600}
#enter-form .btn-full{margin-top:20px}
/* ---------- toasts ---------- */
.toasts{position:fixed;left:50%;bottom:24px;transform:translateX(-50%);z-index:90;display:grid;gap:8px;width:min(360px,calc(100% - 32px))}
.toast{
background:var(--ink);color:var(--paper);padding:12px 18px;border-radius:999px;
font-size:.9rem;font-weight:500;text-align:center;box-shadow:var(--sh-2);
animation:tin .3s cubic-bezier(.2,.85,.3,1);
}
.toast.out{animation:tout .3s ease forwards}
@keyframes tin{from{opacity:0;transform:translateY(14px)}}
@keyframes tout{to{opacity:0;transform:translateY(10px)}}
/* ---------- responsive ---------- */
@media (max-width:980px){
.hero-in{grid-template-columns:1fr;gap:34px;padding:52px 0 60px}
.prizes{grid-template-columns:1fr;max-width:520px;margin-inline:auto}
.prize-grand{order:-1}
.rules-grid{grid-template-columns:1fr}
.judges{grid-template-columns:1fr}
.judge-bio{max-height:180px;opacity:1;margin-top:14px}
.judge-hint{display:none}
.topnav{display:none}
}
@media (max-width:520px){
.wrap,.wrap-narrow{width:calc(100% - 28px)}
.section{padding:52px 0}
.topbar-in{height:60px;gap:12px}
.brand-text em{display:none}
h1{font-size:2rem}
.lede{font-size:1rem}
.hero-cta .btn{width:100%}
.countdown{padding:20px}
.cd-grid{gap:6px}
.cd-cell{padding:10px 2px}
.cd-dates{grid-template-columns:1fr;gap:10px;text-align:left}
.cd-dates div{display:flex;justify-content:space-between;align-items:baseline}
.cd-dates dd{margin:0}
.sec-head-row{flex-direction:column;align-items:stretch}
.tabs{width:100%;justify-content:space-between}
.tab{flex:1;padding:8px 6px}
.gallery{grid-template-columns:1fr}
.prize-grand{padding:38px 20px 28px}
.enter-in .btn{width:100%}
.modal-card{padding:24px 20px}
}
@media (prefers-reduced-motion:reduce){
*,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}
}(function () {
"use strict";
/* ---------------- toast ---------------- */
var toastHost = document.getElementById("toasts");
function toast(msg) {
var el = document.createElement("div");
el.className = "toast";
el.textContent = msg;
toastHost.appendChild(el);
setTimeout(function () {
el.classList.add("out");
setTimeout(function () { el.remove(); }, 320);
}, 2600);
}
/* ---------------- countdown ---------------- */
var DEADLINE = new Date(Date.now() + (23 * 864e5) + (7 * 36e5) + (41 * 6e4) + 12e3);
var cd = {
d: document.querySelector('[data-cd="d"]'),
h: document.querySelector('[data-cd="h"]'),
m: document.querySelector('[data-cd="m"]'),
s: document.querySelector('[data-cd="s"]')
};
var live = document.getElementById("cd-live");
var closeEl = document.getElementById("cd-close");
closeEl.textContent = DEADLINE.toLocaleDateString("en-US", { month: "short", day: "2-digit", year: "numeric" });
function pad(n) { return String(n).padStart(2, "0"); }
var lastAnnounce = 0;
function tick() {
var left = Math.max(0, DEADLINE - Date.now());
var s = Math.floor(left / 1000);
var d = Math.floor(s / 86400);
var h = Math.floor((s % 86400) / 3600);
var m = Math.floor((s % 3600) / 60);
cd.d.textContent = pad(d);
cd.h.textContent = pad(h);
cd.m.textContent = pad(m);
cd.s.textContent = pad(s % 60);
if (Date.now() - lastAnnounce > 60000) {
lastAnnounce = Date.now();
live.textContent = d + " days, " + h + " hours and " + m + " minutes left to enter.";
}
}
tick();
setInterval(tick, 1000);
/* ---------------- criteria bars on scroll ---------------- */
var criteria = document.getElementById("criteria");
if ("IntersectionObserver" in window) {
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (e) {
if (e.isIntersecting) { e.target.classList.add("is-in"); io.unobserve(e.target); }
});
}, { threshold: 0.35 });
io.observe(criteria);
} else {
criteria.classList.add("is-in");
}
/* ---------------- entries data ---------------- */
var PALETTES = [
["#e8552d", "#f2b134"], ["#0f8a8a", "#7fc9c0"], ["#f2b134", "#e8552d"],
["#22201e", "#0f8a8a"], ["#c9421d", "#f2b134"], ["#0b6d6d", "#f2b134"]
];
var ENTRIES = [
{ t: "Pallet-slat hall bench", m: "Rina Okafor", likes: 412, age: 2, art: 0 },
{ t: "Offcut chessboard, no glue-up jig", m: "Tomas Vidal", likes: 388, age: 9, art: 1 },
{ t: "Chevron plant stand from fence pickets", m: "Devi Ramaswamy", likes: 356, age: 1, art: 2 },
{ t: "Scrap-strip serving tray", m: "Jonah Kessler", likes: 301, age: 14, art: 3 },
{ t: "Wall-hung tool till, all salvage", m: "Marit Solheim", likes: 277, age: 4, art: 4 },
{ t: "End-grain phone dock", m: "Ade Bankole", likes: 244, age: 21, art: 5 },
{ t: "Nesting crates from crib rails", m: "Lucia Ferrante", likes: 198, age: 3, art: 1 },
{ t: "Shopmade mallet, hickory offcut", m: "Peter Nowak", likes: 176, age: 17, art: 0 },
{ t: "Louvered shoe rack, deck leftovers", m: "Sana Qureshi", likes: 151, age: 6, art: 2 },
{ t: "Segmented lamp from stair treads", m: "Elias Brandt", likes: 133, age: 11, art: 3 },
{ t: "Kerf-bent tissue box", m: "Noor Haddad", likes: 108, age: 0, art: 4 },
{ t: "Two-board birdhouse, zero waste", m: "Grace Whitlow", likes: 87, age: 8, art: 5 }
];
function initials(name) {
return name.split(" ").map(function (p) { return p[0]; }).join("").slice(0, 2).toUpperCase();
}
function artSvg(kind, i) {
var p = PALETTES[i % PALETTES.length];
var shapes = [
'<rect x="30" y="52" width="200" height="14" rx="3" fill="' + p[0] + '"/><rect x="30" y="72" width="200" height="14" rx="3" fill="' + p[1] + '" opacity=".8"/><rect x="30" y="92" width="200" height="14" rx="3" fill="' + p[0] + '" opacity=".55"/><rect x="46" y="106" width="14" height="34" rx="3" fill="#22201e" opacity=".7"/><rect x="200" y="106" width="14" height="34" rx="3" fill="#22201e" opacity=".7"/>',
'<g>' + (function () { var o = ""; for (var r = 0; r < 4; r++) for (var c = 0; c < 6; c++) { o += '<rect x="' + (44 + c * 29) + '" y="' + (30 + r * 29) + '" width="27" height="27" rx="2" fill="' + ((r + c) % 2 ? p[0] : p[1]) + '"/>'; } return o; })() + '</g>',
'<path d="M130 24l84 48v66h-84z" fill="' + p[0] + '"/><path d="M130 24L46 72v66h84z" fill="' + p[1] + '"/><rect x="60" y="138" width="140" height="10" rx="3" fill="#22201e" opacity=".65"/>',
'<rect x="34" y="42" width="192" height="76" rx="10" fill="none" stroke="' + p[0] + '" stroke-width="9"/><rect x="56" y="60" width="30" height="40" rx="3" fill="' + p[1] + '"/><rect x="94" y="60" width="30" height="40" rx="3" fill="' + p[0] + '" opacity=".6"/><rect x="132" y="60" width="30" height="40" rx="3" fill="' + p[1] + '" opacity=".75"/><rect x="170" y="60" width="30" height="40" rx="3" fill="' + p[0] + '" opacity=".45"/>',
'<rect x="48" y="30" width="164" height="110" rx="8" fill="' + p[1] + '" opacity=".35"/><rect x="62" y="44" width="60" height="38" rx="4" fill="' + p[0] + '"/><rect x="132" y="44" width="66" height="38" rx="4" fill="' + p[0] + '" opacity=".6"/><rect x="62" y="92" width="136" height="34" rx="4" fill="#22201e" opacity=".55"/>',
'<circle cx="130" cy="84" r="52" fill="' + p[1] + '" opacity=".38"/><circle cx="130" cy="84" r="32" fill="' + p[0] + '"/><rect x="118" y="84" width="24" height="62" rx="5" fill="#22201e" opacity=".7"/>'
];
return '<svg viewBox="0 0 260 160" role="img" aria-label="Stylised illustration of the project"><rect width="260" height="160" fill="#fbf6ef"/>' + shapes[kind] + "</svg>";
}
var gallery = document.getElementById("gallery");
var state = ENTRIES.map(function (e, i) { return Object.assign({ id: i, liked: false }, e); });
function render(list) {
gallery.innerHTML = "";
list.forEach(function (e, idx) {
var card = document.createElement("article");
card.className = "entry";
card.style.animationDelay = (idx * 45) + "ms";
var pal = PALETTES[e.id % PALETTES.length];
card.innerHTML =
'<div class="entry-art">' + artSvg(e.art, e.id) +
(e.age <= 2 ? '<span class="badge-new">New</span>' : "") +
"</div>" +
'<div class="entry-body">' +
"<h3>" + e.t + "</h3>" +
'<div class="entry-meta">' +
'<span class="maker"><span class="av" style="background:' + pal[0] + '">' + initials(e.m) + "</span>" + e.m + "</span>" +
'<button class="like' + (e.liked ? " on" : "") + '" data-id="' + e.id + '" aria-pressed="' + e.liked + '" aria-label="Like ' + e.t + '">' +
'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 20s-7-4.5-7-9a4 4 0 017-2.6A4 4 0 0119 11c0 4.5-7 9-7 9z"/></svg>' +
'<span class="like-n">' + (e.likes + (e.liked ? 1 : 0)) + "</span>" +
"</button>" +
"</div>" +
"</div>";
gallery.appendChild(card);
});
}
var sorters = {
all: function (a, b) { return a.id - b.id; },
liked: function (a, b) { return (b.likes + (b.liked ? 1 : 0)) - (a.likes + (a.liked ? 1 : 0)); },
"new": function (a, b) { return a.age - b.age; }
};
var currentSort = "all";
function apply() { render(state.slice().sort(sorters[currentSort])); }
apply();
gallery.addEventListener("click", function (ev) {
var btn = ev.target.closest(".like");
if (!btn) return;
var item = state[Number(btn.dataset.id)];
item.liked = !item.liked;
btn.classList.toggle("on", item.liked);
btn.setAttribute("aria-pressed", String(item.liked));
btn.querySelector(".like-n").textContent = item.likes + (item.liked ? 1 : 0);
btn.classList.remove("bump");
void btn.offsetWidth;
btn.classList.add("bump");
toast(item.liked ? "Liked “" + item.t + "”" : "Removed your like");
});
document.querySelectorAll(".tab").forEach(function (tab) {
tab.addEventListener("click", function () {
document.querySelectorAll(".tab").forEach(function (t) {
t.classList.toggle("is-active", t === tab);
t.setAttribute("aria-selected", String(t === tab));
});
currentSort = tab.dataset.sort;
apply();
});
});
/* ---------------- judges ---------------- */
var JUDGES = [
{ n: "Halina Bem", r: "Furniture maker · Kraków", c: "#f2b134", b: "Twenty years of chairs, most of them out of material somebody else threw away. Scores hard on joinery and forgives a rough finish." },
{ n: "Curtis Amadi", r: "Shop teacher · Detroit", c: "#e8552d", b: "Runs a high-school woodshop with a permanent offcut bin. Cares most about whether a beginner could follow your steps without getting hurt." },
{ n: "Yuki Tanabe", r: "Design writer · Osaka", c: "#7fc9c0", b: "Writes about repair culture and low-waste making. Reads every build log end to end, which is why documentation is worth 20 percent." }
];
var jl = document.getElementById("judges-list");
JUDGES.forEach(function (j) {
var li = document.createElement("li");
li.className = "judge";
li.tabIndex = 0;
li.innerHTML =
'<div class="judge-top"><span class="judge-av" style="background:' + j.c + '">' + initials(j.n) + "</span>" +
"<div><h3>" + j.n + '</h3><span class="role">' + j.r + "</span></div></div>" +
'<p class="judge-bio">' + j.b + "</p>" +
'<p class="judge-hint">Hover or focus for bio</p>';
jl.appendChild(li);
});
/* ---------------- faq ---------------- */
var FAQ = [
["Can I enter more than one project?", "Yes — up to three per maker. Each one is judged on its own, but only your highest-scoring entry is eligible for the grand prize so the shortlist stays varied."],
["Does plywood count as scrap wood?", "It counts if it was already cut and headed for disposal — a shelf out of a skip, a crate panel, a cut-off from someone else's job. A fresh sheet from the yard does not."],
["What if I can't take good photos?", "Phone photos in daylight against a plain wall score exactly the same as studio shots. Judges are told to ignore photography quality and read the steps."],
["How are ties broken?", "By the reuse score first, then by community likes on the entry page. If it is still tied, all tied entries receive the prize."],
["When do winners hear back?", "Two weeks after entries close. Everyone shortlisted gets an email either way, and the full scoring sheet is published with the results."]
];
var faqHost = document.getElementById("faq-list");
FAQ.forEach(function (pair, i) {
var wrap = document.createElement("div");
wrap.className = "q";
wrap.innerHTML =
'<button class="q-btn" aria-expanded="false" aria-controls="fa' + i + '">' + pair[0] + '<span class="q-ico" aria-hidden="true">+</span></button>' +
'<div class="q-body" id="fa' + i + '" role="region"><p>' + pair[1] + "</p></div>";
faqHost.appendChild(wrap);
});
faqHost.addEventListener("click", function (ev) {
var btn = ev.target.closest(".q-btn");
if (!btn) return;
var q = btn.parentElement;
var body = q.querySelector(".q-body");
var open = q.classList.toggle("open");
btn.setAttribute("aria-expanded", String(open));
body.style.maxHeight = open ? body.scrollHeight + "px" : "0px";
});
/* ---------------- smooth scroll ---------------- */
document.querySelectorAll("[data-scroll]").forEach(function (b) {
b.addEventListener("click", function () {
var t = document.querySelector(b.dataset.scroll);
if (t) t.scrollIntoView({ behavior: "smooth", block: "start" });
});
});
/* ---------------- modal ---------------- */
var modal = document.getElementById("modal");
var lastFocus = null;
function openModal() {
lastFocus = document.activeElement;
modal.hidden = false;
document.getElementById("e-title").focus();
}
function closeModal() {
modal.hidden = true;
document.getElementById("form-err").hidden = true;
if (lastFocus) lastFocus.focus();
}
document.querySelectorAll("[data-enter]").forEach(function (b) { b.addEventListener("click", openModal); });
modal.querySelectorAll("[data-close]").forEach(function (b) { b.addEventListener("click", closeModal); });
document.addEventListener("keydown", function (e) {
if (e.key === "Escape" && !modal.hidden) closeModal();
});
document.getElementById("enter-form").addEventListener("submit", function (e) {
e.preventDefault();
var err = document.getElementById("form-err");
var title = document.getElementById("e-title").value.trim();
var url = document.getElementById("e-url").value.trim();
var ok = document.getElementById("e-ok").checked;
if (!title) { err.textContent = "Give your project a title."; err.hidden = false; return; }
if (!/^https?:\/\/.+\..+/.test(url)) { err.textContent = "That build log URL doesn't look right."; err.hidden = false; return; }
if (!ok) { err.textContent = "Please confirm your entry meets the eligibility rules."; err.hidden = false; return; }
err.hidden = true;
closeModal();
this.reset();
toast("Entry received — “" + title + "” is in the queue.");
});
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Scrap Wood Challenge 2026 — MAKELOG Contests</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<a class="skip" href="#main">Skip to content</a>
<header class="topbar">
<div class="wrap topbar-in">
<a class="brand" href="#main" aria-label="MAKELOG Contests home">
<svg class="brand-mark" viewBox="0 0 40 40" aria-hidden="true">
<rect x="2" y="6" width="36" height="28" rx="7" fill="#e8552d"/>
<path d="M9 27V13l6 8 6-8v14" fill="none" stroke="#fffdfa" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="29" cy="20" r="4.2" fill="none" stroke="#f2b134" stroke-width="3.2"/>
</svg>
<span class="brand-text">MAKELOG<em>Contests</em></span>
</a>
<nav class="topnav" aria-label="Primary">
<a href="#prizes">Prizes</a>
<a href="#rules">Rules</a>
<a href="#entries">Entries</a>
<a href="#judges">Judges</a>
<a href="#faq">FAQ</a>
</nav>
<button class="btn btn-primary btn-sm" data-enter>Enter contest</button>
</div>
</header>
<main id="main">
<!-- HERO -->
<section class="hero">
<div class="confetti" aria-hidden="true">
<svg viewBox="0 0 1200 420" preserveAspectRatio="none">
<g fill="none" stroke-width="3" stroke-linecap="round">
<path d="M80 40l14 22" stroke="#f2b134"/><path d="M180 96l-16 18" stroke="#0f8a8a"/>
<path d="M300 30l18 10" stroke="#e8552d"/><path d="M420 120l10 20" stroke="#f2b134"/>
<path d="M520 46l-14 16" stroke="#0f8a8a"/><path d="M700 34l16 18" stroke="#f2b134"/>
<path d="M830 110l-18 12" stroke="#e8552d"/><path d="M960 44l12 22" stroke="#0f8a8a"/>
<path d="M1090 92l16 14" stroke="#f2b134"/><path d="M1140 30l-14 18" stroke="#e8552d"/>
</g>
<g opacity=".85">
<rect x="240" y="150" width="10" height="10" rx="2" fill="#f2b134" transform="rotate(24 245 155)"/>
<rect x="640" y="80" width="9" height="9" rx="2" fill="#0f8a8a" transform="rotate(-18 644 84)"/>
<rect x="900" y="170" width="10" height="10" rx="2" fill="#e8552d" transform="rotate(35 905 175)"/>
<circle cx="140" cy="180" r="5" fill="#0f8a8a"/><circle cx="1040" cy="150" r="5" fill="#e8552d"/>
</g>
</svg>
</div>
<div class="wrap hero-in">
<div class="hero-copy">
<span class="ribbon">
<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M4 2h12v16l-6-4-6 4V2z" fill="currentColor"/></svg>
Open for entries — season 04
</span>
<h1>Scrap Wood <span class="hl">Challenge</span> 2026</h1>
<p class="lede">Offcuts, pallet boards, sawn-off ends, that pile behind the shed. Build something worth keeping out of wood that was already headed for the bin — then write the build log that lets someone else do it too.</p>
<div class="hero-meta">
<span class="chip"><b>1,284</b> entries</span>
<span class="chip"><b>$6,400</b> in prizes</span>
<span class="chip"><b>Worldwide</b> eligible</span>
</div>
<div class="hero-cta">
<button class="btn btn-primary btn-lg" data-enter>Enter your build</button>
<button class="btn btn-ghost btn-lg" data-scroll="#rules">Read the rules</button>
</div>
</div>
<aside class="countdown" aria-label="Time remaining to enter">
<p class="cd-label">Entries close in</p>
<div class="cd-grid" id="countdown">
<div class="cd-cell"><span class="cd-num" data-cd="d">00</span><span class="cd-unit">days</span></div>
<div class="cd-cell"><span class="cd-num" data-cd="h">00</span><span class="cd-unit">hrs</span></div>
<div class="cd-cell"><span class="cd-num" data-cd="m">00</span><span class="cd-unit">min</span></div>
<div class="cd-cell"><span class="cd-num" data-cd="s">00</span><span class="cd-unit">sec</span></div>
</div>
<p class="cd-live" aria-live="polite" id="cd-live"></p>
<dl class="cd-dates">
<div><dt>Opens</dt><dd>Mar 02, 2026</dd></div>
<div><dt>Closes</dt><dd id="cd-close">—</dd></div>
<div><dt>Winners</dt><dd>2 weeks later</dd></div>
</dl>
</aside>
</div>
</section>
<!-- PRIZES -->
<section id="prizes" class="section">
<div class="wrap">
<header class="sec-head">
<h2>Prize tiers</h2>
<p>Three tiers, twelve winners. Every prize ships worldwide; cash equivalents available where shipping is restricted.</p>
</header>
<div class="prizes">
<article class="prize">
<div class="medal medal-silver" aria-hidden="true">
<svg viewBox="0 0 64 72"><path d="M20 2h24l-6 20H26z" fill="#0f8a8a"/><circle cx="32" cy="46" r="22" fill="#dfe3e0" stroke="#b9c0bc" stroke-width="3"/><circle cx="32" cy="46" r="14" fill="none" stroke="#9aa39e" stroke-width="2"/><text x="32" y="52" text-anchor="middle" font-family="JetBrains Mono, monospace" font-size="15" font-weight="700" fill="#4c5450">2</text></svg>
</div>
<span class="tier-tag">Runner-up × 3</span>
<h3>The Bench Kit</h3>
<p>A 14-piece chisel and marking set, a low-angle block plane, and a year of MAKELOG Pro for the build logs.</p>
<span class="value">Value $620</span>
</article>
<article class="prize prize-grand">
<span class="crown">Grand prize</span>
<div class="medal medal-gold" aria-hidden="true">
<svg viewBox="0 0 64 72"><path d="M20 2h24l-6 20H26z" fill="#e8552d"/><circle cx="32" cy="46" r="23" fill="#f2b134" stroke="#c9902a" stroke-width="3"/><circle cx="32" cy="46" r="15" fill="none" stroke="#a97a1f" stroke-width="2"/><text x="32" y="53" text-anchor="middle" font-family="JetBrains Mono, monospace" font-size="17" font-weight="700" fill="#5c4310">1</text></svg>
</div>
<span class="tier-tag">One winner</span>
<h3>The Whole Shop</h3>
<p>A cordless track saw, a benchtop dust extractor, a 12-inch sliding mitre saw and a $1,500 lumber credit at a supplier of your choosing.</p>
<span class="value value-gold">Value $3,900</span>
<ul class="perks">
<li>Featured on the MAKELOG front page for a month</li>
<li>Filmed shop tour with our video team</li>
</ul>
</article>
<article class="prize">
<div class="medal medal-bronze" aria-hidden="true">
<svg viewBox="0 0 64 72"><path d="M20 2h24l-6 20H26z" fill="#f2b134"/><circle cx="32" cy="46" r="22" fill="#e0b48d" stroke="#b98a63" stroke-width="3"/><circle cx="32" cy="46" r="14" fill="none" stroke="#9c7350" stroke-width="2"/><text x="32" y="52" text-anchor="middle" font-family="JetBrains Mono, monospace" font-size="15" font-weight="700" fill="#5b3d24">3</text></svg>
</div>
<span class="tier-tag">Honorable mention × 8</span>
<h3>The Starter Crate</h3>
<p>A hardwood offcut crate, digital calipers, a MAKELOG apron and a sticker sheet designed by this season's judges.</p>
<span class="value">Value $110</span>
</article>
</div>
</div>
</section>
<!-- RULES + JUDGING -->
<section id="rules" class="section section-alt">
<div class="wrap">
<header class="sec-head">
<h2>Rules & judging</h2>
<p>Read both columns before you submit. Entries that miss an eligibility line get bounced back with a note, not disqualified — you can fix and resubmit until the deadline.</p>
</header>
<div class="rules-grid">
<div class="card">
<h3 class="card-h">Eligibility checklist</h3>
<ul class="checklist">
<li><span class="tick" aria-hidden="true">✓</span><div><b>Published during the window.</b> The build log must go live between Mar 02 and the closing date shown above.</div></li>
<li><span class="tick" aria-hidden="true">✓</span><div><b>Majority reclaimed wood.</b> At least 70% of the visible material was offcut, pallet, salvage or otherwise second-hand.</div></li>
<li><span class="tick" aria-hidden="true">✓</span><div><b>Your own work.</b> Built by you, photographed by you. Collaborations are fine — name everyone.</div></li>
<li><span class="tick" aria-hidden="true">✓</span><div><b>Five steps minimum.</b> With at least one photo per step and a materials list with rough dimensions.</div></li>
<li><span class="tick" aria-hidden="true">✓</span><div><b>Tagged correctly.</b> Add the <code>scrapwood26</code> tag before submitting so the sorter can find it.</div></li>
<li><span class="tick" aria-hidden="true">✓</span><div><b>Safety shown honestly.</b> Guards on, eyes covered. We won't feature a photo of an unguarded blade.</div></li>
</ul>
</div>
<div class="card">
<h3 class="card-h">Judging criteria</h3>
<p class="card-sub">Each entry is scored independently by three judges. Scores are weighted as follows.</p>
<ul class="criteria" id="criteria">
<li data-weight="40">
<div class="crit-top"><span class="crit-name">Originality</span><span class="crit-pct">40%</span></div>
<div class="bar"><i style="--w:40%"></i></div>
<p class="crit-note">Did you make something we haven't seen ninety times this season?</p>
</li>
<li data-weight="30">
<div class="crit-top"><span class="crit-name">Craftsmanship</span><span class="crit-pct">30%</span></div>
<div class="bar"><i style="--w:30%"></i></div>
<p class="crit-note">Joints, finish, and whether it will still be standing next winter.</p>
</li>
<li data-weight="20">
<div class="crit-top"><span class="crit-name">Documentation</span><span class="crit-pct">20%</span></div>
<div class="bar"><i style="--w:20%"></i></div>
<p class="crit-note">Could a stranger rebuild it from your log alone?</p>
</li>
<li data-weight="10">
<div class="crit-top"><span class="crit-name">Reuse</span><span class="crit-pct">10%</span></div>
<div class="bar"><i style="--w:10%"></i></div>
<p class="crit-note">How little new material you bought to get there.</p>
</li>
</ul>
</div>
</div>
</div>
</section>
<!-- ENTRIES -->
<section id="entries" class="section">
<div class="wrap">
<header class="sec-head sec-head-row">
<div>
<h2>Entries gallery</h2>
<p>A slice of the 1,284 builds submitted so far. Like one and it moves up the community board.</p>
</div>
<div class="tabs" role="tablist" aria-label="Sort entries">
<button class="tab is-active" role="tab" aria-selected="true" data-sort="all">All</button>
<button class="tab" role="tab" aria-selected="false" data-sort="liked">Most liked</button>
<button class="tab" role="tab" aria-selected="false" data-sort="new">Newest</button>
</div>
</header>
<div class="gallery" id="gallery" aria-live="polite"></div>
</div>
</section>
<!-- JUDGES -->
<section id="judges" class="section section-dark">
<div class="wrap">
<header class="sec-head sec-head-light">
<h2>This season's judges</h2>
<p>Three makers score every shortlisted entry. Hover or focus a judge to read their bio.</p>
</header>
<ul class="judges" id="judges-list"></ul>
</div>
</section>
<!-- FAQ -->
<section id="faq" class="section">
<div class="wrap wrap-narrow">
<header class="sec-head">
<h2>Frequently asked</h2>
</header>
<div class="faq" id="faq-list"></div>
</div>
</section>
<!-- FINAL BAND -->
<section class="enter-band">
<div class="wrap enter-in">
<div>
<h2>Got a pile of offcuts and a free weekend?</h2>
<p>Submitting takes about ten minutes if your photos are already on your phone.</p>
</div>
<button class="btn btn-gold btn-lg" data-enter>Enter the challenge</button>
</div>
</section>
</main>
<footer class="foot">
<div class="wrap foot-in">
<span class="mono">MAKELOG Contests — a fictional community for demo purposes.</span>
<span class="mono">Season 04 · scrapwood26</span>
</div>
</footer>
<!-- ENTER DIALOG -->
<div class="modal" id="modal" hidden>
<div class="modal-back" data-close></div>
<div class="modal-card" role="dialog" aria-modal="true" aria-labelledby="modal-t">
<button class="modal-x" data-close aria-label="Close">×</button>
<h3 id="modal-t">Enter the Scrap Wood Challenge</h3>
<p class="modal-sub">Drop a link to your published build log. You can edit it any time before the deadline.</p>
<form id="enter-form" novalidate>
<label for="e-title">Project title</label>
<input id="e-title" name="title" type="text" placeholder="Pallet-slat hall bench" required />
<label for="e-url">Build log URL</label>
<input id="e-url" name="url" type="url" placeholder="https://makelog.example/build/…" required />
<label class="check"><input type="checkbox" id="e-ok" required /> <span>My entry meets every eligibility line above.</span></label>
<p class="form-err" id="form-err" role="alert" hidden></p>
<button class="btn btn-primary btn-lg btn-full" type="submit">Submit entry</button>
</form>
</div>
</div>
<div class="toasts" id="toasts" aria-live="polite" aria-atomic="false"></div>
<script src="script.js"></script>
</body>
</html>Project Contest Page
A complete competition landing page for a fictional maker community running its “Scrap Wood Challenge 2026”. The hero states the theme, the entry count and the prize pool, then hands the visitor two things at once: a countdown that ticks down to the second, and an Enter button that opens a small validated submission dialog. The countdown card is topped by a three-stop gradient rule and repeats the key dates underneath, so the urgency never comes at the cost of the actual schedule.
Below it the page walks the full contest information architecture. Three prize tiers sit in a row with hand-drawn SVG medals — silver, gold, bronze — with the grand prize card physically larger, gold-bordered, lifted on its own shadow and carrying an extra perks list. Rules split into two columns: an eligibility checklist with teal tick badges on the left, and weighted judging criteria on the right whose bars animate from zero to 40/30/20/10 percent the first time the section scrolls into view.
The entries gallery renders twelve fictional builds from a data array, each with a CSS/SVG illustration generated from a small shape library, a maker chip with generated initials, a “New” badge on recent submissions and a like toggle that bumps, recolours and reports through a toast. Filter tabs re-sort by likes or recency and the cards re-enter with a 45 ms stagger. Judges expand their bios on hover or keyboard focus, the FAQ accordion measures its own content for a smooth height transition, and everything collapses cleanly to a single column at 520px.
How this look is built
The layout is in the spirit of Instructables-style contest pages, but the mechanics are modern: CSS grid handles the asymmetric hero and the auto-fill entries gallery without a single float or media-query breakpoint per column, layered radial-gradients paint the confetti-lit hero and dark judges band with no image requests, and an IntersectionObserver toggles one class on the criteria list so the four bars animate their --w custom property with staggered transition-delays instead of a scroll listener firing on every frame. The old approach — background JPEGs, a jQuery scroll handler recalculating offsets, and fixed pixel columns — cost bytes and repaints; here the whole page is three files with no network dependencies beyond the font link, and prefers-reduced-motion shuts every animation off in one rule.
Illustrative UI only — always follow real safety guidance when working with tools, electronics, or repairs.