SolLunar-Kitchen/backups/home.html.pre-reorder-20260831-061852

583 lines
30 KiB
Text
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<meta name="theme-color" content="#FFFFFF">
<link rel="icon" type="image/png" sizes="64x64" href="icon.png">
<link rel="icon" type="image/png" sizes="192x192" href="icon-192.png">
<link rel="icon" type="image/png" sizes="512x512" href="icon-512.png">
<link rel="apple-touch-icon" sizes="192x192" href="icon-192.png">
<link rel="manifest" href="manifest.webmanifest">
<title>K484 · A Private Membership Association</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=Orbitron:wght@400;700;900&display=swap" rel="stylesheet">
<style>
:root{
--bg:#FFFFFF; --bg2:#f8fafc;
--ink:#0A0A0A; --ink2:#475569; --muted:#94a3b8;
--line:#e2e8f0; --line2:#cbd5e1;
--black:#0a0a0a;
--radius:18px;
--shadow:0 1px 2px rgb(10 10 10 / .05), 0 8px 24px -12px rgb(10 10 10 / .12);
--font:-apple-system,'Avenir Next','Avenir',system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
--display:'Orbitron',var(--font);
}
*{box-sizing:border-box;margin:0;padding:0}
html{line-height:1.5;scroll-behavior:smooth}
body{font-family:var(--font);background:var(--bg);color:var(--ink);-webkit-font-smoothing:antialiased}
a{color:inherit}
.wrap{max-width:1040px;margin:0 auto;padding:0 22px}
/* ============ HEADER ============ */
header{position:sticky;top:0;z-index:50;background:rgba(255,255,255,.9);backdrop-filter:blur(10px);border-bottom:1px solid var(--line)}
.header-in{display:flex;align-items:center;gap:12px;padding:12px 22px;max-width:1040px;margin:0 auto}
.logo{width:46px;height:46px;flex:0 0 46px;object-fit:contain}
.brand b{font-family:var(--display);font-weight:900;font-size:15px;letter-spacing:2px;display:block;line-height:1.2}
.brand span{font-size:11px;color:var(--muted);letter-spacing:1px}
.header-right{margin-left:auto;display:flex;align-items:center;gap:10px}
.member-chip{font-family:var(--display);font-size:10px;font-weight:700;letter-spacing:1px;border:1px solid var(--line2);border-radius:99px;padding:6px 12px;color:var(--ink2)}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;border:none;cursor:pointer;font-family:var(--font);font-weight:700;font-size:14px;border-radius:99px;padding:12px 22px;transition:transform .12s,opacity .12s;text-decoration:none}
.btn:active{transform:scale(.97)}
.btn-primary{background:var(--black);color:#fff}
.btn-primary:hover{opacity:.88}
.btn-ghost{background:var(--bg);color:var(--ink);border:1.5px solid var(--line2)}
.btn-ghost:hover{border-color:var(--ink)}
.btn-sm{padding:9px 16px;font-size:13px}
/* ============ HERO ============ */
.hero{text-align:center;padding:72px 22px 56px;position:relative;overflow:hidden}
.hero-logo{width:140px;height:140px;object-fit:contain;margin:0 auto 26px;display:block;animation:fadeup 1s ease both}
.hero-kicker{font-family:var(--display);font-size:11px;font-weight:700;letter-spacing:4px;color:var(--muted);animation:fadeup .9s ease both .1s}
.hero h1{font-family:var(--display);font-weight:900;font-size:clamp(40px,8vw,72px);letter-spacing:6px;margin:10px 0 6px;animation:fadeup .9s ease both .2s}
.hero .assoc{font-size:clamp(15px,2.4vw,19px);color:var(--ink2);letter-spacing:2px;text-transform:uppercase;animation:fadeup .9s ease both .3s}
.hero-sub{max-width:560px;margin:18px auto 0;font-size:14px;color:var(--ink2);animation:fadeup .9s ease both .4s}
.tagline-row{display:flex;flex-wrap:wrap;justify-content:center;gap:10px;margin:28px auto 6px;animation:fadeup .9s ease both .5s}
.tagline{font-family:var(--display);font-size:10px;font-weight:700;letter-spacing:2px;border:1.5px solid var(--ink);border-radius:99px;padding:8px 16px;text-transform:uppercase}
.hero-cta{display:flex;flex-wrap:wrap;justify-content:center;gap:12px;margin-top:30px;animation:fadeup .9s ease both .6s}
@keyframes fadeup{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:translateY(0)}}
/* ============ SECTIONS ============ */
section{padding:64px 0}
.sec-head{text-align:center;margin-bottom:36px}
.sec-head h2{font-family:var(--display);font-weight:900;font-size:clamp(22px,4vw,30px);letter-spacing:3px;text-transform:uppercase}
.sec-head .sub{font-size:12px;color:var(--muted);letter-spacing:2px;text-transform:uppercase;margin-top:8px}
.divider{border:none;border-top:1px solid var(--line);max-width:1040px;margin:0 auto}
/* ============ MENU ============ */
#menu{background:var(--bg2)}
.day-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:18px;align-items:start}
.day-card{background:var(--bg);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);overflow:hidden}
.day-card.today{border-color:var(--ink);border-width:2px}
.day-head{padding:16px 18px 12px;border-bottom:1px solid var(--line);display:flex;align-items:baseline;gap:10px}
.day-tag{font-family:var(--display);font-size:11px;font-weight:900;letter-spacing:2px}
.day-date{font-size:12px;color:var(--muted);letter-spacing:1px;margin-left:auto;text-transform:uppercase}
.today-chip{font-family:var(--display);font-size:9px;font-weight:700;letter-spacing:1px;background:var(--black);color:#fff;border-radius:99px;padding:3px 8px}
.day-list{padding:6px 0}
.day-row{display:flex;align-items:center;gap:10px;padding:10px 18px;border-bottom:1px solid var(--line)}
.day-row:last-child{border-bottom:none}
.day-em{font-size:18px;width:26px;text-align:center;flex:0 0 26px}
.day-info{min-width:0}
.day-name{font-weight:700;font-size:14px}
.day-time{font-family:var(--display);font-size:10px;color:var(--muted);letter-spacing:.5px;margin-top:1px}
.day-price{font-family:var(--display);font-weight:900;font-size:14px;margin-left:auto}
.day-foot{padding:14px 18px}
.day-foot a{display:block;text-align:center}
.tags{display:inline-flex;gap:4px;margin-left:6px;vertical-align:1px}
.tag{font-family:var(--display);font-size:8px;font-weight:700;letter-spacing:.5px;border:1px solid var(--line2);border-radius:99px;padding:1px 6px;color:var(--muted)}
/* ============ HOW IT WORKS ============ */
.steps{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:18px}
.step{border:1px solid var(--line);border-radius:var(--radius);padding:24px 20px;background:var(--bg)}
.step .n{font-family:var(--display);font-weight:900;font-size:26px;color:var(--muted)}
.step h3{font-family:var(--display);font-size:13px;font-weight:700;letter-spacing:2px;text-transform:uppercase;margin:8px 0 6px}
.step p{font-size:13px;color:var(--ink2)}
/* ============ MEMBERSHIP ============ */
#join{background:var(--bg2)}
.join-wrap{max-width:640px;margin:0 auto}
.note-box{border:1px solid var(--line2);border-radius:14px;padding:14px 18px;font-size:13px;color:var(--ink2);background:var(--bg);margin-bottom:22px}
.note-box b{color:var(--ink)}
.form-card{background:var(--bg);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);padding:26px}
.field{margin-bottom:16px}
.field label{display:block;font-family:var(--display);font-size:10px;font-weight:700;letter-spacing:1.5px;text-transform:uppercase;color:var(--ink2);margin-bottom:6px}
.field input{width:100%;border:1px solid var(--line2);border-radius:12px;padding:13px 14px;font-family:var(--font);font-size:14px;background:var(--bg2);color:var(--ink);outline:none;transition:border-color .15s}
.field input:focus{border-color:var(--ink)}
.sig-wrap{border:1.5px dashed var(--line2);border-radius:12px;position:relative;background:var(--bg2)}
.sig-canvas{display:block;width:100%;height:140px;touch-action:none;cursor:crosshair;border-radius:12px}
.sig-hint{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--muted);letter-spacing:1px;pointer-events:none;text-transform:uppercase}
.sig-tools{display:flex;align-items:center;justify-content:space-between;margin-top:8px}
.sig-status{font-size:11px;color:var(--muted);letter-spacing:.5px}
.sig-status.ok{font-weight:700;color:var(--ink)}
.link-btn{background:none;border:none;cursor:pointer;font-family:var(--display);font-size:10px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--muted);text-decoration:underline}
.link-btn:hover{color:var(--ink)}
.covenant{background:var(--bg2);border:1px solid var(--line);border-radius:12px;padding:16px 18px;margin:18px 0;max-height:190px;overflow-y:auto;font-size:12.5px;color:var(--ink2)}
.covenant h4{font-family:var(--display);font-size:11px;font-weight:700;letter-spacing:1.5px;text-transform:uppercase;color:var(--ink);margin-bottom:8px}
.covenant ol{padding-left:18px;display:grid;gap:6px}
.agree-row{display:flex;gap:10px;align-items:flex-start;margin:16px 0}
.agree-row input{width:18px;height:18px;margin-top:1px;accent-color:var(--black);flex:0 0 18px}
.agree-row label{font-size:12.5px;color:var(--ink2)}
.form-err{font-size:12px;font-weight:700;color:var(--ink);background:var(--bg2);border:1.5px solid var(--ink);border-radius:10px;padding:9px 12px;margin-bottom:12px;display:none}
.form-err.show{display:block}
.form-actions{display:grid;gap:10px}
.member-done{text-align:center;padding:10px 0}
.member-done .check{width:56px;height:56px;border-radius:50%;background:var(--black);color:#fff;font-size:26px;display:flex;align-items:center;justify-content:center;margin:0 auto 14px}
.member-done h3{font-family:var(--display);font-weight:900;font-size:17px;letter-spacing:2px}
.member-code{font-family:var(--display);font-weight:900;font-size:22px;letter-spacing:3px;background:var(--bg2);border:1px solid var(--line);border-radius:12px;padding:12px;margin:16px 0}
.member-meta{font-size:13px;color:var(--ink2);margin-bottom:6px}
/* ============ FOOTER ============ */
footer{border-top:1px solid var(--line);padding:28px 22px 34px;text-align:center}
footer .f-logo{width:52px;height:52px;object-fit:contain;margin:0 auto 10px;display:block}
footer .f-line{font-family:var(--display);font-size:10px;font-weight:700;letter-spacing:3px;text-transform:uppercase;color:var(--muted)}
footer .f-sub{font-size:11px;color:var(--muted);margin-top:6px}
</style>
</head>
<body>
<header>
<div class="header-in">
<img class="logo" src="logo.png" alt="K484">
<div class="brand"><b>KITCHEN 484</b><span>SOLARPUNK SUMMIT</span></div>
<div class="header-right">
<span class="member-chip" id="member-chip" hidden></span>
<a class="btn btn-ghost btn-sm" href="#join" id="nav-join">Join</a>
<a class="btn btn-primary btn-sm" href="index.html">Food Menu</a>
</div>
</div>
</header>
<div class="hero">
<img class="hero-logo" src="logo.png" alt="K484">
<div class="hero-kicker">SOLARPUNK SUMMIT · Oct 8–12</div>
<h1>K484</h1>
<div class="assoc">A Private Membership Association</div>
<p class="hero-sub">Five days. Off-grid kitchen. No seed oils, all organic grass-fed, gluten free and vegetarian friendly. See when the food is on, pre-order, and pay with Bitcoin — no cash, no cards.</p>
<div class="tagline-row">
<span class="tagline">No Seed Oils</span>
<span class="tagline">All Organic Grass Fed</span>
<span class="tagline">Gluten Free &amp; Vegetarian Friendly</span>
<span class="tagline">Off Grid — Zero Waste</span>
</div>
<div class="hero-cta">
<a class="btn btn-primary" href="index.html">Food Menu →</a>
<a class="btn btn-ghost" href="#join">Become a Member</a>
</div>
</div>
<section id="menu">
<div class="wrap">
<div class="sec-head">
<h2>Food Menu</h2>
<div class="sub">Off Grid — Zero Waste · What's on, and when</div>
</div>
<div class="day-grid" id="day-grid"></div>
<div style="text-align:center;margin-top:28px">
<a class="btn btn-primary" href="index.html">Open the Full Schedule &amp; Order →</a>
</div>
</div>
</section>
<div class="divider"></div>
<section id="how">
<div class="wrap">
<div class="sec-head">
<h2>How It Works</h2>
<div class="sub">Five days, three steps</div>
</div>
<div class="steps">
<div class="step">
<div class="n">01</div>
<h3>Check the Schedule</h3>
<p>Every stand posts its serving window for each day. The live timeline shows what's open right now and what's coming.</p>
</div>
<div class="step">
<div class="n">02</div>
<h3>Pre-Order Your Window</h3>
<p>Add items to your order, pick a pickup window, and name your order so we can call it out at the stand.</p>
</div>
<div class="step">
<div class="n">03</div>
<h3>Pay with Bitcoin</h3>
<p>Pay on-chain or via Lightning through BTCPay Server. Get your pickup code the moment your payment confirms.</p>
</div>
</div>
</div>
</section>
<div class="divider"></div>
<section id="join">
<div class="wrap join-wrap">
<div class="sec-head">
<h2>Membership</h2>
<div class="sub">Kitchen 484 · Private Membership Association</div>
</div>
<div id="join-form-wrap">
<div class="note-box">
<b>Note:</b> This is a private, members-only association. Participation is absolutely voluntary. Membership is granted for the duration of the festival (24 hours per day, Oct 8–12), beginning upon acceptance of this application.
</div>
<form class="form-card" id="join-form" novalidate>
<div class="form-err" id="join-err"></div>
<div class="field">
<label for="m-name">Full Name</label>
<input id="m-name" type="text" placeholder="Your full name" maxlength="80" autocomplete="name">
</div>
<div class="field">
<label for="m-email">Email</label>
<input id="m-email" type="email" placeholder="you@example.com" maxlength="120" autocomplete="email">
</div>
<div class="field">
<label for="m-phone">Phone</label>
<input id="m-phone" type="tel" placeholder="+1 (555) 000-0000" maxlength="30" autocomplete="tel">
</div>
<div class="field">
<label>Digital Signature</label>
<div class="sig-wrap">
<canvas class="sig-canvas" id="sig-canvas"></canvas>
<div class="sig-hint" id="sig-hint">Sign here with mouse or finger</div>
</div>
<div class="sig-tools">
<span class="sig-status" id="sig-status">Signature required to apply</span>
<button type="button" class="link-btn" id="sig-clear">Clear</button>
</div>
</div>
<div class="covenant">
<h4>K484 Membership Covenant</h4>
<p style="margin-bottom:8px">By submitting this application and becoming a member of Kitchen 484, I acknowledge and agree that:</p>
<ol>
<li>I am joining a private, members-only association, not a public business.</li>
<li>Access to kitchen activities, meals, and services is limited to accepted members only.</li>
<li>I agree to abide by the rules, governance, and confidentiality requirements outlined in this Covenant.</li>
<li>Membership is granted for a 24-hour period beginning upon acceptance of this application, unless ended earlier by the member or by Kitchen 484.</li>
<li>I acknowledge that my membership, participation, and personal information are confidential, and that I will respect the privacy of Kitchen 484 and other members.</li>
<li>I acknowledge that Kitchen 484 operates under internal Articles, Bylaws, and policies, which are not publicly distributed, and that I do not acquire governance, voting, or inspection rights by virtue of my membership.</li>
</ol>
</div>
<div class="agree-row">
<input type="checkbox" id="m-agree">
<label for="m-agree">"I have read and agree to the Kitchen 484 Membership Covenant, and I voluntarily apply for membership."</label>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">Sign &amp; Apply for Membership</button>
<a class="btn btn-ghost" href="index.html" style="text-decoration:none">Browse the Food Menu First</a>
</div>
</form>
</div>
<div class="form-card member-done" id="join-done" hidden>
<div class="check">✓</div>
<h3>APPLICATION SUBMITTED</h3>
<div class="member-code" id="done-code">K484-XXXX</div>
<div class="member-meta" id="done-name"></div>
<div class="member-meta" id="done-date"></div>
<p class="member-meta" style="margin-top:10px;font-size:12px;color:var(--muted)">Keep this code — it is your member reference. Your signed covenant is available for download and printing.</p>
<div class="form-actions" style="margin-top:18px">
<button class="btn btn-primary" id="btn-download">Download Signed Agreement</button>
<div style="display:flex;gap:10px">
<a class="btn btn-ghost" href="index.html" style="flex:1;text-decoration:none">Open Food Menu</a>
<button class="btn btn-ghost" id="btn-new-apply" style="flex:1">New Application</button>
</div>
</div>
</div>
</div>
</section>
<footer>
<img class="f-logo" src="logo.png" alt="K484">
<div class="f-line">Off Grid — Zero Waste</div>
<div class="f-sub">KITCHEN 484 · SOLARPUNK SUMMIT · Oct 8–12 · No cash, no cards — Bitcoin only</div>
</footer>
<script>
/* ============================== DATA (mirrors index.html) ============================== */
const FEST_START=new Date(2026,9,8); /* Oct 8, 2026 — festival start (coincides with hero dates) */
function dayLabel(offset){
const d=new Date(FEST_START); d.setDate(d.getDate()+offset);
return {
name:d.toLocaleDateString('en-US',{weekday:'short'}),
date:d.toLocaleDateString('en-US',{month:'short',day:'numeric'}),
iso:d.toISOString().slice(0,10)
};
}
const FEST={
days:[
{ tag:'DAY 1', items:[
{name:'Coffee Station', emoji:'☕', price:4, start:540, end:1080, tags:['VG']},
{name:'Sweets Cart', emoji:'🍭', price:5, start:660, end:1320, tags:['V','GF']},
{name:'Taco Stand', emoji:'🌮', price:8, start:720, end:870, tags:['GF']},
{name:'BBQ Pit', emoji:'🍖', price:12, start:780, end:930, tags:[]},
{name:'Chicken Grill', emoji:'🍗', price:9, start:1050, end:1230, tags:['GF']},
{name:'Pasta Bar', emoji:'🍝', price:10, start:1080, end:1200, tags:['V']},
{name:'Drinks', emoji:'🥤', price:3, start:600, end:1320, tags:['VG']}
]},
{ tag:'DAY 2', items:[
{name:'Coffee Station', emoji:'☕', price:4, start:570, end:1020, tags:['VG']},
{name:'Sweets Cart', emoji:'🍭', price:5, start:660, end:1260, tags:['V','GF']},
{name:'Garden Burgers', emoji:'🍔', price:11, start:720, end:900, tags:[]},
{name:'Grill 484', emoji:'🔥', price:9, start:750, end:960, tags:['GF']},
{name:'Ramen Tent', emoji:'🍜', price:12, start:1020, end:1200, tags:['V']},
{name:'Drinks', emoji:'🥤', price:3, start:570, end:1290, tags:['VG']}
]},
{ tag:'DAY 3', items:[
{name:'Coffee Station', emoji:'☕', price:4, start:540, end:1050, tags:['VG']},
{name:'Sweets Cart', emoji:'🍭', price:5, start:660, end:1320, tags:['V','GF']},
{name:'Flatbread Oven', emoji:'🫓', price:9, start:720, end:930, tags:['V','GF']},
{name:'BBQ Pit', emoji:'🍖', price:12, start:780, end:960, tags:[]},
{name:'Dumpling Bar', emoji:'🥟', price:10, start:1020, end:1230, tags:['GF']},
{name:'Drinks', emoji:'🥤', price:3, start:600, end:1320, tags:['VG']}
]},
{ tag:'DAY 4', items:[
{name:'Coffee Station', emoji:'☕', price:4, start:540, end:1020, tags:['VG']},
{name:'Sweets Cart', emoji:'🍭', price:5, start:660, end:1290, tags:['V','GF']},
{name:'Taco Stand', emoji:'🌮', price:8, start:720, end:870, tags:['GF']},
{name:'Pasta Bar', emoji:'🍝', price:10, start:900, end:1140, tags:['V']},
{name:'Grill 484', emoji:'🔥', price:9, start:960, end:1170, tags:['GF']},
{name:'Drinks', emoji:'🥤', price:3, start:600, end:1290, tags:['VG']}
]},
{ tag:'FINAL DAY', items:[
{name:'Coffee Station', emoji:'☕', price:4, start:600, end:960, tags:['VG']},
{name:'Sweets Cart', emoji:'🍭', price:5, start:660, end:1200, tags:['V','GF']},
{name:'Taco Stand', emoji:'🌮', price:8, start:720, end:840, tags:['GF']},
{name:'Farewell Feast · BBQ', emoji:'🍖', price:14, start:720, end:960, tags:[]},
{name:'Pasta Bar', emoji:'🍝', price:10, start:1020, end:1170, tags:['V']},
{name:'Drinks', emoji:'🥤', price:3, start:600, end:1230, tags:['VG']}
]}
]
};
FEST.days.forEach((d,i)=>{ const L=dayLabel(i); d.name=L.name; d.date=L.date; d.iso=L.iso; });
const $=s=>document.querySelector(s);
const esc=s=>String(s).replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
const fmtT=min=>{let h=Math.floor(min/60),m=min%60,ap=h>=12?'PM':'AM';h=h%12||12;return h+':'+String(m).padStart(2,'0')+' '+ap;};
/* ============================== MENU CARDS ============================== */
function renderMenu(){
$('#day-grid').innerHTML=FEST.days.map((d,i)=>{
const rows=[...d.items].sort((a,b)=>a.start-b.start).map(it=>
'<div class="day-row">'+
'<div class="day-em">'+it.emoji+'</div>'+
'<div class="day-info">'+
'<div class="day-name">'+it.name+'<span class="tags">'+it.tags.map(t=>'<span class="tag">'+t+'</span>').join('')+'</span></div>'+
'<div class="day-time">'+fmtT(it.start)+' – '+fmtT(it.end)+'</div>'+
'</div>'+
'<div class="day-price">$'+it.price+'</div>'+
'</div>').join('');
return '<div class="day-card'+(i===0?' today':'')+'">'+
'<div class="day-head">'+
'<span class="day-tag">'+d.tag+'</span>'+
(i===0?'<span class="today-chip">TODAY</span>':'')+
'<span class="day-date">'+d.name+' '+d.date+'</span>'+
'</div>'+
'<div class="day-list">'+rows+'</div>'+
'<div class="day-foot"><a class="btn btn-ghost btn-sm" href="index.html">Order for '+d.tag+' →</a></div>'+
'</div>';
}).join('');
}
renderMenu();
/* ============================== SIGNATURE PAD ============================== */
const canvas=$('#sig-canvas');
const ctx=canvas.getContext('2d');
let drawing=false, lastPt=null, hasInk=false;
function sizeCanvas(){
const r=canvas.getBoundingClientRect();
const dpr=window.devicePixelRatio||1;
const img=canvas.width?canvas.toDataURL():null;
canvas.width=Math.max(1,r.width*dpr);
canvas.height=140*dpr;
ctx.scale(dpr,dpr);
ctx.lineWidth=2.2;
ctx.lineCap='round';
ctx.lineJoin='round';
ctx.strokeStyle='#0A0A0A';
if(img){const im=new Image();im.onload=()=>ctx.drawImage(im,0,0,r.width,140);im.src=img;}
}
function pt(e){
const r=canvas.getBoundingClientRect();
const t=e.touches?e.touches[0]:e;
return {x:t.clientX-r.left,y:t.clientY-r.top};
}
function startDraw(e){
drawing=true; lastPt=pt(e);
// draw a dot so taps (touch users) register ink, not just drags
ctx.beginPath();
ctx.arc(lastPt.x,lastPt.y,1.2,0,Math.PI*2);
ctx.fillStyle='#0A0A0A';
ctx.fill();
if(!hasInk){
hasInk=true;
$('#sig-hint').style.display='none';
const st=$('#sig-status');
st.textContent='✓ Signed — you can apply now';
st.classList.add('ok');
}
e.preventDefault();
}
function moveDraw(e){
if(!drawing)return;
const p=pt(e);
ctx.beginPath();
ctx.moveTo(lastPt.x,lastPt.y);
ctx.lineTo(p.x,p.y);
ctx.stroke();
lastPt=p;
if(!hasInk){
hasInk=true;
$('#sig-hint').style.display='none';
const st=$('#sig-status');
st.textContent='✓ Signed — you can apply now';
st.classList.add('ok');
}
e.preventDefault();
}
function endDraw(){drawing=false;lastPt=null;}
canvas.addEventListener('mousedown',startDraw);
canvas.addEventListener('mousemove',moveDraw);
window.addEventListener('mouseup',endDraw);
canvas.addEventListener('touchstart',startDraw,{passive:false});
canvas.addEventListener('touchmove',moveDraw,{passive:false});
canvas.addEventListener('touchend',endDraw);
$('#sig-clear').onclick=()=>{
ctx.clearRect(0,0,canvas.width,canvas.height);
hasInk=false;
$('#sig-hint').style.display='flex';
const st=$('#sig-status');
st.textContent='Signature required to apply';
st.classList.remove('ok');
};
window.addEventListener('resize',sizeCanvas);
sizeCanvas();
/* ============================== MEMBERSHIP ============================== */
const LS_MEMBER='slk_member';
const LS_MEMBERS='slk_members';
function loadMember(){try{return JSON.parse(localStorage.getItem(LS_MEMBER)||'null');}catch(e){return null;}}
function saveMember(m){
localStorage.setItem(LS_MEMBER,JSON.stringify(m));
const all=JSON.parse(localStorage.getItem(LS_MEMBERS)||'[]');
all.push(m);
localStorage.setItem(LS_MEMBERS,JSON.stringify(all));
}
function showMember(m){
$('#join-form-wrap').hidden=true;
$('#join-done').hidden=false;
$('#done-code').textContent=m.code;
$('#done-name').textContent=m.fullName;
$('#done-date').textContent='Applied '+new Date(m.ts).toLocaleDateString('en-US',{weekday:'long',month:'long',day:'numeric',year:'numeric'});
const chip=$('#member-chip');
chip.hidden=false;
chip.textContent=m.code;
document.getElementById('nav-join').textContent='Member';
$('#join').scrollIntoView({behavior:'smooth'});
}
const existing=loadMember();
if(existing)showMember(existing);
$('#join-form').addEventListener('submit',e=>{
e.preventDefault();
const err=$('#join-err');
err.classList.remove('show');
const name=$('#m-name').value.trim();
const email=$('#m-email').value.trim();
const phone=$('#m-phone').value.trim();
const agree=$('#m-agree').checked;
let problem=null;
if(!name)problem='Please enter your full name.';
else if(!email||!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email))problem='Please enter a valid email address.';
else if(!phone)problem='Please enter a phone number.';
else if(!hasInk)problem='Please sign in the signature box.';
else if(!agree)problem='Please check the covenant agreement box.';
if(problem){
err.textContent=problem;
err.classList.add('show');
err.scrollIntoView({behavior:'smooth',block:'center'});
return;
}
const member={
code:'K484-'+Math.random().toString(36).slice(2,6).toUpperCase(),
fullName:name, email, phone,
ts:Date.now(),
signature:canvas.toDataURL('image/png')
};
saveMember(member);
showMember(member);
});
$('#btn-new-apply').onclick=()=>{
localStorage.removeItem(LS_MEMBER);
location.reload();
};
/* ============================== AGREEMENT DOWNLOAD ============================== */
$('#btn-download').onclick=()=>{
const m=loadMember();
if(!m){toast('No application found');return;}
const d=new Date(m.ts);
const html='<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Kitchen 484 Membership Agreement - '+esc(m.fullName)+'</title>'+
'<style>'+
'body{font-family:Georgia,serif;color:#000;max-width:720px;margin:40px auto;padding:0 24px;line-height:1.6;font-size:14px}'+
'h1{font-size:22px;letter-spacing:2px;text-transform:uppercase;text-align:center}'+
'h2{font-size:14px;letter-spacing:1px;text-transform:uppercase;text-align:center;font-weight:normal;color:#333;margin-top:4px}'+
'.box{border:1px solid #000;padding:18px 22px;margin:22px 0}'+
'.info p{margin:6px 0}'+
'.info b{display:inline-block;width:110px}'+
'ol{padding-left:20px}li{margin:8px 0}'+
'.sig{margin-top:30px;text-align:center}'+
'.sig img{height:90px;border:1px solid #999;border-radius:6px;padding:6px;background:#fff}'+
'.sig .line{margin-top:6px;font-size:12px;color:#333}'+
'.declare{margin-top:24px;font-style:italic}'+
'@media print{body{margin:20px auto}}'+
'</style></head><body>'+
'<h1>Kitchen 484</h1><h2>Membership Agreement — '+esc(m.code)+'</h2>'+
'<div class="box info">'+
'<p><b>Member:</b> '+esc(m.fullName)+'</p>'+
'<p><b>Email:</b> '+esc(m.email)+'</p>'+
'<p><b>Phone:</b> '+esc(m.phone)+'</p>'+
'<p><b>Applied:</b> '+d.toLocaleString('en-US')+'</p>'+
'</div>'+
'<p>Note: This is a private, members-only association. Participation is absolutely voluntary.</p>'+
'<h2 style="text-align:left;margin-top:20px">K484 Membership Covenant</h2>'+
'<p>By submitting this application and becoming a member of Kitchen 484, I acknowledge and agree that:</p>'+
'<ol>'+
'<li>I am joining a private, members-only association, not a public business.</li>'+
'<li>Access to kitchen activities, meals, and services is limited to accepted members only.</li>'+
'<li>I agree to abide by the rules, governance, and confidentiality requirements outlined in this Covenant.</li>'+
'<li>Membership is granted for a 24-hour period beginning upon acceptance of this application, unless ended earlier by the member or by Kitchen 484.</li>'+
'<li>I acknowledge that my membership, participation, and personal information are confidential, and that I will respect the privacy of Kitchen 484 and other members.</li>'+
'<li>I acknowledge that Kitchen 484 operates under internal Articles, Bylaws, and policies, which are not publicly distributed, and that I do not acquire governance, voting, or inspection rights by virtue of my membership.</li>'+
'</ol>'+
'<p class="declare">"I have read and agree to the Kitchen 484 Membership Covenant, and I voluntarily apply for membership."</p>'+
'<div class="sig"><img src="'+m.signature+'" alt="signature"><div class="line">Digital signature — '+esc(m.fullName)+' · '+d.toLocaleDateString('en-US')+'</div></div>'+
'<script>setTimeout(function(){window.print()},600)</'+'script>'+
'</body></html>';
const w=window.open('','_blank');
if(!w){toast('Pop-up blocked — allow pop-ups to download');return;}
w.document.write(html);
w.document.close();
};
function toast(msg){
let t=document.getElementById('h-toast');
if(!t){t=document.createElement('div');t.id='h-toast';t.style.cssText='position:fixed;left:50%;bottom:36px;transform:translateX(-50%) translateY(20px);background:#0A0A0A;color:#fff;font-size:12px;font-weight:700;padding:10px 18px;border-radius:99px;opacity:0;transition:all .25s;z-index:200;pointer-events:none';document.body.appendChild(t);}
t.textContent=msg;t.style.opacity='1';t.style.transform='translateX(-50%) translateY(0)';
clearTimeout(t._x);t._x=setTimeout(()=>{t.style.opacity='0';t.style.transform='translateX(-50%) translateY(20px)';},2200);
}
</script>
</body>
</html>