Models 44

Claude Haiku 5.5

by AnthropicReasoningClean
Open in new window

Running live in a sandboxed frame. Click inside it before using the keyboard.

How it went

Total time
6 min 34 s
Cost
$0.049
Output tokens
97,319
Spent thinking
72,613 tokens
Speed
248.1 tok/s
Console errors
0
First token after
2.1 s
First visible text after
5 min 24 s
Prompt tokens
543
Code size
51.7 KB
Finish reason
stop
Served by
Claude Platform on AWS
Model id
anthropic/claude-haiku-5.5
Reasoning sent
{"effort":"xhigh"}
Max output
128,000 tokens
Generated
Nov 10, 2026

What it was asked

The prompt
“i'm opening a korean taco food truck called "Kimchi Loco", make me a website that makes people really want to come”
System prompt, sent with every prompt
You are generating a self-contained web demo. It will be rendered automatically in a sandboxed iframe and compared side by side with the output of other AI models given the exact same task.

Output rules:
- Reply with exactly ONE fenced code block containing the complete file: ```html (or ```svg when the task asks for an SVG). No text before or after the code block.
- Everything must be inline: CSS in <style>, JavaScript in <script>. No external files, images, fonts or network requests, except the CDN URLs explicitly allowed by the task.
- Do not use localStorage, sessionStorage, cookies, IndexedDB, alert(), confirm(), prompt() or window.open(): they are blocked in the sandbox and will throw.
- The page must look right in a 1280×800 viewport and adapt gracefully down to 375px wide. No horizontal scrollbar.
- Something meaningful must be visible on first paint: a screenshot is taken automatically about 3 seconds after load, without any interaction.
- Everything that makes the demo interesting must be visible within the first seconds: nothing hidden behind a high score, a later level or a long play session.
- Games must start in a self-playing demo mode (a simple AI plays) behind a "Click or press a key to start" message, so the game can be judged in action without playing.
- The iframe only receives keyboard events after the user clicks it: if the demo uses the keyboard, display a clear "Click or press a key to start" message.
- The code must run with zero errors in the console of the latest Chrome.

Code run-1.html · 1034 lines

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Kimchi Loco · Korean tacos on wheels</title>
<meta name="description" content="Kimchi Loco: Korean-Mexican street tacos from a food truck. Bulgogi, yangnyeom chicken, kimchi fries and more.">
<meta name="theme-color" content="#1d0e0a">
<style>
:root{
  --ink:#1d0e0a;
  --ink-2:#2b1714;
  --cream:#fff6e8;
  --paper:#fffaf1;
  --kimchi:#d6402a;
  --gochu:#e5503a;
  --saffron:#ffb627;
  --mint:#5be38a;
  --line:rgba(29,14,10,.12);
  --display:"Arial Black",Impact,"Helvetica Neue",Arial,sans-serif;
  --body:system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
}
*,*::before,*::after{box-sizing:border-box}
[hidden]{display:none!important}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
body{margin:0;background:var(--cream);color:var(--ink);font-family:var(--body);font-size:16px;line-height:1.5;overflow-x:hidden;-webkit-font-smoothing:antialiased}
h1,h2,h3,h4{font-family:var(--display);font-weight:900;letter-spacing:-.01em;line-height:1.05;margin:0}
p{margin:0}
a{color:inherit}
button,input,select,textarea{font:inherit;color:inherit}
svg{display:block}

.wrap{width:min(1180px,calc(100% - 40px));margin-inline:auto}
.kicker{font-size:12px;letter-spacing:.2em;text-transform:uppercase;font-weight:800;color:var(--gochu);margin:0 0 14px}
.section{padding:96px 0}
.sec-head{max-width:680px;margin-bottom:38px}
.sec-head h2{font-size:clamp(38px,5vw,62px);margin-bottom:14px}
.sec-head p{font-size:18px;opacity:.75}
.fine{font-size:13px;opacity:.7}

/* ---------- Header ---------- */
.top{position:sticky;top:0;z-index:50;background:rgba(29,14,10,.92);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);color:var(--cream)}
.top-inner{height:68px;display:flex;align-items:center;justify-content:space-between;gap:16px}
.brand{display:flex;align-items:center;gap:10px;text-decoration:none;font-family:var(--display);font-size:19px;text-transform:uppercase;letter-spacing:.02em}
.brand b{color:var(--saffron);font-weight:900}
.mark{width:40px;height:40px;border-radius:50%;background:var(--saffron);color:var(--ink);display:grid;place-items:center;font-family:var(--display);font-size:15px;box-shadow:0 0 0 3px var(--gochu)}
nav.links{display:flex;gap:28px}
nav.links a{text-decoration:none;font-weight:700;font-size:15px;opacity:.85;transition:color .2s,opacity .2s}
nav.links a:hover{opacity:1;color:var(--saffron)}
.cart-btn{display:inline-flex;align-items:center;gap:10px;background:var(--saffron);color:var(--ink);border:0;border-radius:999px;padding:9px 10px 9px 18px;font-weight:800;cursor:pointer;font-size:15px;transition:transform .15s}
.cart-btn:hover{transform:translateY(-1px)}
.count{display:inline-grid;place-items:center;min-width:26px;height:26px;border-radius:999px;background:var(--ink);color:var(--saffron);font-size:13px;padding:0 7px}
.bump{animation:bump .4s ease}
@keyframes bump{0%{transform:scale(1)}40%{transform:scale(1.3)}100%{transform:scale(1)}}

/* ---------- Hero ---------- */
.hero{position:relative;overflow:hidden;color:var(--cream);padding:58px 0 70px;
  background:
    radial-gradient(circle at 80% 30%,rgba(255,110,60,.4),transparent 45%),
    radial-gradient(circle at 5% 100%,rgba(255,182,39,.25),transparent 40%),
    var(--ink)}
.hero::before{content:"";position:absolute;inset:0;background-image:radial-gradient(rgba(255,246,232,.08) 1.2px,transparent 1.6px);background-size:26px 26px;pointer-events:none}
.hero-grid{position:relative;display:grid;grid-template-columns:1fr 1.05fr;gap:40px;align-items:center}
.pill{display:inline-flex;align-items:center;gap:10px;padding:8px 14px;border-radius:999px;background:rgba(255,246,232,.08);border:1px solid rgba(255,246,232,.18);font-size:14px;font-weight:600;margin:0 0 24px}
.pill .dot{width:9px;height:9px;border-radius:50%;background:var(--saffron);animation:ping 1.8s infinite}
.pill[data-state="open"] .dot{background:var(--mint)}
@keyframes ping{0%{box-shadow:0 0 0 0 rgba(255,246,232,.5)}70%,100%{box-shadow:0 0 0 10px rgba(255,246,232,0)}}
.hero h1{font-size:clamp(50px,6.8vw,98px);margin-bottom:24px}
.hero h1 em{font-style:normal;background:linear-gradient(90deg,var(--saffron),#ff7a3d 75%);-webkit-background-clip:text;background-clip:text;color:transparent}
.lede{font-size:clamp(16px,1.5vw,19px);color:rgba(255,246,232,.82);max-width:32em}
.cta{display:flex;flex-wrap:wrap;gap:12px;margin-top:30px}
.facts{list-style:none;padding:0;margin:34px 0 0;display:flex;flex-wrap:wrap;gap:10px 24px;font-size:14px;opacity:.85}
.facts li::before{content:"✦";color:var(--saffron);margin-right:8px}

.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:15px 24px;border-radius:999px;font-weight:800;font-size:16px;text-decoration:none;border:2px solid transparent;cursor:pointer;transition:transform .15s,background .2s,box-shadow .2s}
.btn:hover{transform:translateY(-2px)}
.btn.primary{background:var(--gochu);color:#fff;box-shadow:0 12px 30px -10px rgba(229,80,58,.9)}
.btn.primary:hover{background:#f0604a}
.btn.ghost{border-color:rgba(255,246,232,.4);color:var(--cream)}
.btn.ghost:hover{background:rgba(255,246,232,.08)}
.btn.block{width:100%}
.btn:disabled{opacity:.4;cursor:not-allowed;transform:none;box-shadow:none}

.hero-art{position:relative;width:100%}
.bob{animation:bob 5s ease-in-out infinite}
@keyframes bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-6px)}}
.truck{width:100%;height:auto;overflow:visible}
.drive{animation:drive 1.2s cubic-bezier(.2,.8,.2,1) both}
@keyframes drive{from{transform:translateX(-160px);opacity:0}to{transform:none;opacity:1}}
.spin{transform-box:fill-box;transform-origin:center;animation:spin 1.6s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.puff{fill:#fff4e3;opacity:0;transform-box:fill-box;transform-origin:center;animation:puff 2.8s ease-out infinite}
@keyframes puff{0%{opacity:0;transform:translateY(0) scale(.5)}25%{opacity:.7}100%{opacity:0;transform:translate(14px,-44px) scale(1.9)}}
.bulb{fill:#ffe27a;animation:twinkle 1.6s ease-in-out infinite}
@keyframes twinkle{0%,100%{opacity:.35}50%{opacity:1}}
.truck text.sign{font-family:var(--display);font-weight:900;font-size:36px;fill:#fff4e3;letter-spacing:1px}
.truck text.open-txt{font-family:var(--display);font-size:15px;fill:var(--ink)}
.truck text.board{font-family:var(--display);font-size:11px;fill:#fff4e3}
.truck text.board-title{font-family:var(--display);font-size:14px;fill:var(--saffron)}
.float-taco{position:absolute;right:-2%;top:0;width:140px;z-index:2;animation:float 4.6s ease-in-out infinite;filter:drop-shadow(0 18px 22px rgba(0,0,0,.5))}
.float-taco svg{width:100%;height:auto}
@keyframes float{0%,100%{transform:rotate(12deg) translateY(0)}50%{transform:rotate(7deg) translateY(-12px)}}

/* ---------- Ticker ---------- */
.ticker{background:var(--saffron);color:var(--ink);overflow:hidden;border-block:2px solid var(--ink)}
.ticker-track{display:flex;width:max-content;animation:marquee 34s linear infinite}
.ticker-group{display:flex;align-items:center;flex-shrink:0}
.ticker span{font-family:var(--display);font-size:20px;text-transform:uppercase;padding:13px 16px;white-space:nowrap}
.ticker i{font-style:normal;color:var(--kimchi);font-size:16px}
@keyframes marquee{to{transform:translateX(-50%)}}

/* ---------- Menu ---------- */
.tabs{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:30px}
.tab{background:transparent;border:2px solid var(--ink);border-radius:999px;padding:9px 18px;font-weight:800;cursor:pointer;transition:background .2s,color .2s}
.tab:hover{background:rgba(29,14,10,.06)}
.tab[aria-selected="true"]{background:var(--ink);color:var(--cream)}
.menu-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:22px}
.card{background:var(--paper);border-radius:22px;overflow:hidden;display:flex;flex-direction:column;box-shadow:0 1px 0 var(--line),0 22px 40px -28px rgba(29,14,10,.5);transition:transform .25s ease,box-shadow .25s}
.card:hover{transform:translateY(-5px);box-shadow:0 1px 0 var(--line),0 30px 50px -26px rgba(29,14,10,.55)}
.card-art{height:180px;background:var(--bg);display:grid;place-items:center;position:relative}
.card-art svg{width:72%;height:auto;filter:drop-shadow(0 10px 12px rgba(0,0,0,.2))}
.card-art .word{font-family:var(--display);font-size:40px;letter-spacing:.02em;background:var(--paper);padding:10px 18px;border-radius:12px;transform:rotate(-5deg);box-shadow:0 10px 20px -10px rgba(0,0,0,.4)}
.card-body{padding:18px 20px 20px;display:flex;flex-direction:column;flex:1}
.card-body h3{font-size:21px;margin-bottom:8px}
.card-body p{font-size:15px;opacity:.75;flex:1}
.meta{display:flex;align-items:center;gap:10px;margin:14px 0;flex-wrap:wrap;font-size:13px;font-weight:700}
.heat{display:inline-flex;gap:4px}
.heat i{width:9px;height:9px;border-radius:50%;background:rgba(29,14,10,.15)}
.heat i.on{background:var(--kimchi)}
.badge{background:#dcf2e1;color:#15602f;padding:4px 9px;border-radius:999px;font-size:12px}
.card-foot{display:flex;align-items:center;justify-content:space-between}
.price{font-family:var(--display);font-size:22px}
.add{background:var(--ink);color:var(--cream);border:0;border-radius:999px;padding:10px 16px;font-weight:800;cursor:pointer;transition:background .2s,transform .15s}
.add:hover{background:var(--gochu)}
.add:active{transform:scale(.94)}

/* ---------- Builder ---------- */
.dark{background:var(--ink);color:var(--cream)}
.build{display:grid;grid-template-columns:1.1fr .9fr;gap:56px;align-items:start}
.build h2{font-size:clamp(38px,5vw,60px);margin-bottom:14px}
.sub{font-size:18px;opacity:.75;max-width:520px;margin-bottom:32px}
fieldset{border:0;padding:0;margin:0 0 30px;min-width:0}
legend{font-size:13px;letter-spacing:.14em;text-transform:uppercase;font-weight:800;color:var(--saffron);margin-bottom:14px;padding:0}
.chips{display:flex;flex-wrap:wrap;gap:10px}
.chip{background:transparent;border:2px solid rgba(255,246,232,.22);color:var(--cream);border-radius:999px;padding:10px 16px;font-weight:700;font-size:15px;cursor:pointer;display:inline-flex;align-items:center;gap:8px;transition:all .15s}
.chip:hover{border-color:var(--cream)}
.chip[aria-pressed="true"]{background:var(--cream);color:var(--ink);border-color:var(--cream)}
.sw{width:12px;height:12px;border-radius:50%;border:1px solid rgba(0,0,0,.25);flex-shrink:0}
.range{display:grid;grid-template-columns:1fr auto;align-items:center;gap:14px}
input[type=range]{accent-color:var(--saffron);width:100%}
output{font-family:var(--display);color:var(--saffron);min-width:96px;text-align:right}
.preview{position:sticky;top:96px;background:radial-gradient(circle at 50% 38%,rgba(229,80,58,var(--h,.1)),transparent 62%),var(--ink-2);border-radius:28px;padding:30px;text-align:center;border:1px solid rgba(255,246,232,.1);transition:background .4s}
.preview-art svg{width:min(86%,340px);height:auto;margin:0 auto;animation:pop .35s ease}
@keyframes pop{from{transform:scale(.9) rotate(-3deg);opacity:.5}to{transform:none;opacity:1}}
.preview h3{font-size:clamp(24px,3vw,32px);margin:14px 0 8px}
.preview p{opacity:.75}
.preview-foot{display:flex;align-items:center;justify-content:space-between;margin-top:22px;gap:12px;flex-wrap:wrap}
.preview-foot .price{font-size:30px}

/* ---------- Find us ---------- */
.find{display:grid;grid-template-columns:1fr 1fr;gap:40px;align-items:start}
.now{background:var(--ink);color:var(--cream);border-radius:24px;padding:28px;margin-bottom:22px}
.now h3{font-size:clamp(24px,3vw,34px);margin:8px 0 10px}
.now p:last-child{opacity:.8}
.sched{list-style:none;margin:0;padding:0;background:var(--paper);border-radius:22px;overflow:hidden;box-shadow:0 1px 0 var(--line),0 22px 40px -28px rgba(29,14,10,.5)}
.sched li{display:grid;grid-template-columns:124px 1fr auto;gap:12px;align-items:center;padding:14px 20px;border-bottom:1px solid var(--line);font-size:15px}
.sched li:last-child{border-bottom:0}
.sched li.today{background:#ffe9a8;font-weight:700}
.sched .day{font-weight:800}
.sched .day em{display:block;font-style:normal;font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--gochu)}
.sched .time{font-variant-numeric:tabular-nums;opacity:.75;font-size:14px;text-align:right;white-space:nowrap}
.sched .time.closed{opacity:.45}
.loco{margin-top:22px;background:var(--paper);border-radius:22px;padding:24px;box-shadow:0 1px 0 var(--line),0 22px 40px -28px rgba(29,14,10,.5)}
.loco h3{font-size:24px;margin-bottom:16px}
.stamps{display:grid;grid-template-columns:repeat(5,1fr);gap:10px;max-width:380px;margin-bottom:14px}
.stamp{aspect-ratio:1;border-radius:50%;border:2px dashed rgba(29,14,10,.3);background:#fff;font-weight:800;cursor:pointer;transition:all .2s;display:grid;place-items:center;font-size:14px}
.stamp:hover{border-color:var(--ink)}
.stamp[aria-pressed="true"]{background:var(--saffron);border:2px solid var(--ink);transform:rotate(-8deg)}
.map{border-radius:24px;overflow:hidden;box-shadow:0 1px 0 var(--line),0 22px 40px -28px rgba(29,14,10,.5);border:1px solid var(--line)}
.map svg{width:100%;height:auto}
.pulse{transform-box:fill-box;transform-origin:center;animation:pulse 2s ease-out infinite}
@keyframes pulse{0%{transform:scale(.4);opacity:.9}100%{transform:scale(2.6);opacity:0}}
.map-note{padding:16px 20px;font-size:14px;background:var(--paper);border-top:1px solid var(--line)}

/* ---------- Catering ---------- */
.cater{background:radial-gradient(circle at 92% 8%,rgba(255,182,39,.35),transparent 40%),linear-gradient(160deg,#dd4a30,#b52e1d);color:var(--cream)}
.cater-grid{display:grid;grid-template-columns:1fr 1.05fr;gap:56px;align-items:center}
.cater h2{font-size:clamp(38px,5vw,60px);margin-bottom:16px}
.cater .sub{margin-bottom:0}
.cater ul{list-style:none;padding:0;margin:26px 0 0;display:grid;gap:12px;font-weight:600}
.cater li::before{content:"✦";color:var(--saffron);margin-right:10px}
.form-card{background:var(--paper);color:var(--ink);border-radius:26px;padding:28px;box-shadow:0 30px 60px -30px rgba(0,0,0,.5)}
.form-head h3{font-size:26px;margin-bottom:6px}
.form-head p{opacity:.7;font-size:15px;margin-bottom:20px}
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-bottom:18px}
.form label{display:grid;gap:6px;font-size:13px;font-weight:800}
.form .full{grid-column:1/-1}
.form input,.form select,.form textarea{width:100%;padding:12px 14px;border:2px solid var(--line);border-radius:12px;background:#fff;font-weight:500;font-size:15px}
.form input:focus,.form select:focus,.form textarea:focus{outline:none;border-color:var(--gochu)}
.thanks{text-align:center;padding:30px 10px}
.thanks h3{font-size:28px;margin-bottom:10px}
.thanks p{opacity:.75}

/* ---------- Footer ---------- */
.foot{background:var(--ink);color:var(--cream);padding:64px 0 40px}
.foot-grid{display:grid;grid-template-columns:1.4fr 1fr 1fr;gap:30px}
.foot h4{font-size:15px;letter-spacing:.12em;text-transform:uppercase;color:var(--saffron);margin-bottom:12px}
.foot p{opacity:.8;font-size:15px}
.foot a{text-decoration:none;border-bottom:1px solid rgba(255,246,232,.3)}
.copy{margin-top:44px;font-size:13px;opacity:.55;padding-top:22px;border-top:1px solid rgba(255,246,232,.12)}

/* ---------- Mobile order bar ---------- */
.mobile-bar{position:fixed;left:14px;right:14px;bottom:14px;z-index:40;display:none;justify-content:space-between;align-items:center;background:var(--saffron);color:var(--ink);border-radius:18px;padding:14px 18px;font-weight:800;font-size:16px;box-shadow:0 14px 30px -8px rgba(0,0,0,.5);border:0;cursor:pointer}

/* ---------- Drawer ---------- */
.drawer{position:fixed;inset:0;z-index:90;pointer-events:none}
.drawer.open{pointer-events:auto}
.scrim{position:absolute;inset:0;background:rgba(10,4,2,.55);opacity:0;transition:opacity .3s}
.drawer.open .scrim{opacity:1}
.panel{position:absolute;top:0;right:0;bottom:0;width:min(420px,100%);background:var(--cream);color:var(--ink);transform:translateX(100%);transition:transform .35s cubic-bezier(.2,.8,.2,1);display:flex;flex-direction:column;box-shadow:-20px 0 50px rgba(0,0,0,.3)}
.drawer.open .panel{transform:none}
.panel-head{display:flex;justify-content:space-between;align-items:center;padding:20px 22px;border-bottom:1px solid var(--line)}
.panel-head h2{font-size:26px}
.close{background:none;border:0;font-size:30px;line-height:1;cursor:pointer;padding:4px 8px}
.panel-body{flex:1;overflow:auto;padding:4px 22px}
.line{display:grid;grid-template-columns:1fr auto;gap:8px 12px;padding:16px 0;border-bottom:1px solid var(--line)}
.line strong{font-size:16px}
.line small{display:block;opacity:.65;font-size:13px}
.line .price{font-size:17px;text-align:right}
.qty{grid-column:1/-1;display:flex;align-items:center;gap:10px}
.qty button{width:30px;height:30px;border-radius:50%;border:2px solid var(--ink);background:none;font-weight:900;cursor:pointer;line-height:1}
.qty span{min-width:20px;text-align:center;font-weight:800}
.empty{padding:40px 0;text-align:center;opacity:.7}
.panel-foot{padding:20px 22px 24px;border-top:1px solid var(--line)}
.sum{display:flex;justify-content:space-between;font-weight:800;font-size:18px;margin-bottom:14px}
.done{padding:40px 6px;text-align:center}
.done h3{font-size:30px;margin:8px 0 12px}
.done p{opacity:.8}

/* ---------- Toast ---------- */
.toast{position:fixed;left:50%;bottom:24px;transform:translate(-50%,180%);background:var(--ink);color:var(--cream);padding:12px 18px;border-radius:14px;font-weight:700;z-index:100;transition:transform .35s cubic-bezier(.2,.8,.2,1);box-shadow:0 14px 30px -10px rgba(0,0,0,.5);max-width:calc(100% - 32px);text-align:center}
.toast.show{transform:translate(-50%,0)}

/* ---------- Responsive ---------- */
@media (max-width:1000px){
  .hero-grid,.build,.find,.cater-grid{grid-template-columns:1fr}
  .hero-art{max-width:600px;width:100%;margin:10px auto 0}
  .preview{position:static}
  .foot-grid{grid-template-columns:1fr 1fr}
}
@media (max-width:820px){
  nav.links{display:none}
}
@media (max-width:700px){
  .mobile-bar{display:flex}
  .toast{bottom:92px}
  .foot{padding-bottom:110px}
}
@media (max-width:600px){
  .section{padding:72px 0}
  .form-grid{grid-template-columns:1fr}
  .foot-grid{grid-template-columns:1fr}
  .sched li{grid-template-columns:100px 1fr auto;padding:14px 16px;font-size:14px}
  .float-taco{width:112px;right:0}
  .card-art{height:165px}
  .brand{font-size:17px}
  .preview{padding:24px}
  .form-card{padding:22px}
  .hero{padding:44px 0 56px}
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}
}
</style>
</head>
<body id="top">

<header class="top">
  <div class="wrap top-inner">
    <a class="brand" href="#top" aria-label="Kimchi Loco home"><span class="mark">KL</span><span>Kimchi<b>Loco</b></span></a>
    <nav class="links" aria-label="Primary">
      <a href="#menu">Menu</a>
      <a href="#build">Build a taco</a>
      <a href="#find">Find the truck</a>
      <a href="#cater">Catering</a>
    </nav>
    <button class="cart-btn" id="cartBtn" type="button" aria-label="Open your order">Your order <span class="count" id="cartCount">0</span></button>
  </div>
</header>

<section class="hero">
  <div class="wrap hero-grid">
    <div class="hero-copy">
      <p class="pill" id="statusPill" data-state="closed"><span class="dot"></span><span id="liveStatus">Finding the truck…</span></p>
      <h1>Seoul on a <em>tortilla.</em></h1>
      <p class="lede">Slow-glazed bulgogi, double-fried yangnyeom chicken and kimchi we ferment ourselves, folded into a tortilla and served hot from a truck that’s never parked in the same place twice.</p>
      <div class="cta">
        <a class="btn primary" href="#menu">See the menu</a>
        <a class="btn ghost" href="#build">Build your own taco</a>
      </div>
      <ul class="facts">
        <li>Kimchi fermented in-house</li>
        <li>Veg &amp; gluten-free options</li>
        <li>Catering for 20–500 guests</li>
      </ul>
    </div>

    <div class="hero-art">
      <div class="float-taco" id="heroTaco"></div>
      <div class="bob">
        <svg class="truck" viewBox="0 0 600 380" role="img" aria-label="Kimchi Loco food truck illustration">
          <defs>
            <linearGradient id="bodyG" x1="0" y1="0" x2="0" y2="1">
              <stop offset="0" stop-color="#ea5a3f"/>
              <stop offset="1" stop-color="#b52e1d"/>
            </linearGradient>
            <radialGradient id="winGlow" cx="50%" cy="40%" r="70%">
              <stop offset="0" stop-color="#ffd27a" stop-opacity=".6"/>
              <stop offset="1" stop-color="#ff7a3d" stop-opacity="0"/>
            </radialGradient>
          </defs>
          <ellipse cx="290" cy="354" rx="250" ry="14" fill="#000" opacity=".35"/>
          <g class="drive">
            <g>
              <circle class="puff" cx="312" cy="40" r="7" style="animation-delay:0s"/>
              <circle class="puff" cx="312" cy="40" r="7" style="animation-delay:.9s"/>
              <circle class="puff" cx="312" cy="40" r="7" style="animation-delay:1.8s"/>
            </g>
            <rect x="300" y="48" width="26" height="22" rx="4" fill="#4a2016"/>
            <rect x="30" y="66" width="480" height="236" rx="30" fill="url(#bodyG)"/>
            <g id="bulbs"></g>
            <text class="sign" x="270" y="114" text-anchor="middle">KIMCHI LOCO</text>
            <rect x="90" y="126" width="37.5" height="26" fill="#ffb627"/>
            <rect x="127.5" y="126" width="37.5" height="26" fill="#fff4e3"/>
            <rect x="165" y="126" width="37.5" height="26" fill="#ffb627"/>
            <rect x="202.5" y="126" width="37.5" height="26" fill="#fff4e3"/>
            <rect x="240" y="126" width="37.5" height="26" fill="#ffb627"/>
            <rect x="277.5" y="126" width="37.5" height="26" fill="#fff4e3"/>
            <rect x="315" y="126" width="37.5" height="26" fill="#ffb627"/>
            <rect x="352.5" y="126" width="37.5" height="26" fill="#fff4e3"/>
            <rect x="90" y="152" width="300" height="6" fill="rgba(0,0,0,.28)"/>
            <rect x="100" y="162" width="280" height="98" rx="8" fill="#24120d"/>
            <rect x="100" y="162" width="280" height="98" rx="8" fill="url(#winGlow)"/>
            <rect x="150" y="180" width="72" height="28" rx="6" fill="#ffb627"/>
            <text class="open-txt" x="186" y="199" text-anchor="middle">OPEN</text>
            <rect x="90" y="262" width="300" height="12" rx="4" fill="#fff4e3"/>
            <rect x="90" y="274" width="300" height="6" fill="rgba(0,0,0,.3)"/>
            <rect x="404" y="150" width="92" height="118" rx="8" fill="#1f1512" stroke="#fff4e3" stroke-width="3"/>
            <text class="board-title" x="450" y="171" text-anchor="middle">MENU</text>
            <text class="board" x="414" y="192">BULGOGI 5</text>
            <text class="board" x="414" y="212">DWAEJI 5</text>
            <text class="board" x="414" y="232">CRUNCH 5</text>
            <text class="board" x="414" y="252">FRIES 6</text>
            <rect x="510" y="130" width="72" height="172" rx="18" fill="#b52e1d"/>
            <rect x="526" y="146" width="44" height="58" rx="8" fill="#1d2a36"/>
            <path d="M534 156 L546 156 L536 194 L530 194Z" fill="#fff" opacity=".14"/>
            <rect x="520" y="222" width="52" height="2" fill="rgba(0,0,0,.25)"/>
            <circle cx="566" cy="272" r="8" fill="#ffe27a"/>
            <rect x="500" y="296" width="92" height="12" rx="5" fill="#1d0e0a"/>
            <rect x="40" y="302" width="470" height="10" rx="4" fill="#1d0e0a"/>
            <circle cx="120" cy="318" r="44" fill="#120a08"/>
            <circle cx="470" cy="318" r="44" fill="#120a08"/>
            <g transform="translate(120 318)">
              <g class="spin">
                <circle r="34" fill="#2b2220"/>
                <circle r="22" fill="#d9d4cc"/>
                <path d="M0 -22V22M-22 0H22M-15.5 -15.5L15.5 15.5M-15.5 15.5L15.5 -15.5" stroke="#8c857c" stroke-width="4"/>
                <circle r="5" fill="#3a3a3a"/>
              </g>
            </g>
            <g transform="translate(470 318)">
              <g class="spin">
                <circle r="34" fill="#2b2220"/>
                <circle r="22" fill="#d9d4cc"/>
                <path d="M0 -22V22M-22 0H22M-15.5 -15.5L15.5 15.5M-15.5 15.5L15.5 -15.5" stroke="#8c857c" stroke-width="4"/>
                <circle r="5" fill="#3a3a3a"/>
              </g>
            </g>
          </g>
        </svg>
      </div>
    </div>
  </div>
</section>

<div class="ticker" aria-hidden="true">
  <div class="ticker-track">
    <div class="ticker-group">
      <span>Seoul bulgogi</span><i>✦</i><span>Yangnyeom crunch</span><i>✦</i><span>Kimchi fries</span><i>✦</i><span>Gochujang honey</span><i>✦</i><span>Yuzu soda</span><i>✦</i><span>Tacos on wheels</span><i>✦</i>
    </div>
    <div class="ticker-group">
      <span>Seoul bulgogi</span><i>✦</i><span>Yangnyeom crunch</span><i>✦</i><span>Kimchi fries</span><i>✦</i><span>Gochujang honey</span><i>✦</i><span>Yuzu soda</span><i>✦</i><span>Tacos on wheels</span><i>✦</i>
    </div>
  </div>
</div>

<section class="section" id="menu">
  <div class="wrap">
    <div class="sec-head">
      <p class="kicker">The menu</p>
      <h2>Small tacos. Big flavor.</h2>
      <p>Order three, share them, then argue about which one you’re coming back for.</p>
    </div>
    <div class="tabs" id="tabs" role="tablist" aria-label="Menu categories">
      <button class="tab" role="tab" data-filter="all" aria-selected="true">All</button>
      <button class="tab" role="tab" data-filter="tacos" aria-selected="false">Tacos</button>
      <button class="tab" role="tab" data-filter="sides" aria-selected="false">Sides</button>
      <button class="tab" role="tab" data-filter="drinks" aria-selected="false">Drinks</button>
    </div>
    <div class="menu-grid" id="menuGrid"></div>
  </div>
</section>

<section class="section dark" id="build">
  <div class="wrap build">
    <div class="build-controls">
      <p class="kicker">Build your own</p>
      <h2>Build your loco taco.</h2>
      <p class="sub">Pick a protein, a sauce and whatever makes you happy. The preview heats up as you do.</p>

      <fieldset>
        <legend>1 · Protein</legend>
        <div class="chips" id="proteinChips"></div>
      </fieldset>
      <fieldset>
        <legend>2 · Sauce</legend>
        <div class="chips" id="sauceChips"></div>
      </fieldset>
      <fieldset>
        <legend>3 · Toppings</legend>
        <div class="chips" id="toppingChips"></div>
      </fieldset>
      <fieldset>
        <legend>4 · Heat</legend>
        <div class="range">
          <input type="range" id="heat" min="0" max="3" step="1" value="2" aria-label="Heat level">
          <output id="heatOut" for="heat">Hot</output>
        </div>
      </fieldset>
    </div>

    <div class="preview" id="preview">
      <div class="preview-art" id="previewArt"></div>
      <h3 id="previewName"></h3>
      <p id="previewDesc"></p>
      <div class="preview-foot">
        <span class="price" id="previewPrice"></span>
        <button class="btn primary" id="addBuilt" type="button">Add to order</button>
      </div>
    </div>
  </div>
</section>

<section class="section" id="find">
  <div class="wrap">
    <div class="sec-head">
      <p class="kicker">Find the truck</p>
      <h2>Where’s the truck today?</h2>
      <p>We move around the city. Check here before you come, and we’ll tell you exactly where we’re parked.</p>
    </div>
    <div class="find">
      <div>
        <div class="now">
          <p class="kicker" style="color:var(--saffron)">Live location</p>
          <h3 id="nowTitle">Finding the truck…</h3>
          <p id="nowMeta"></p>
        </div>
        <ul class="sched" id="sched" aria-label="Weekly schedule"></ul>
        <div class="loco">
          <p class="kicker">The Loco Card</p>
          <h3>10 tacos. The 10th is on us.</h3>
          <div class="stamps" id="stamps"></div>
          <p class="fine" id="stampMsg">9 more to go. Tap a stamp to try it.</p>
        </div>
      </div>

      <div class="map">
        <svg viewBox="0 0 600 460" role="img" aria-label="Stylized downtown map with today’s stop marked">
          <rect width="600" height="460" fill="#f1e4cb"/>
          <g fill="#e6d4b3">
            <rect x="200" y="20" width="150" height="80" rx="6"/>
            <rect x="20" y="150" width="80" height="80" rx="6"/>
            <rect x="140" y="150" width="120" height="80" rx="6"/>
            <rect x="420" y="20" width="160" height="80" rx="6"/>
            <rect x="420" y="150" width="140" height="80" rx="6"/>
            <rect x="20" y="290" width="120" height="70" rx="6"/>
            <rect x="420" y="290" width="160" height="70" rx="6"/>
          </g>
          <rect x="40" y="40" width="130" height="90" rx="14" fill="#bfe3b0"/>
          <path d="M0 360 C120 330 200 410 330 380 S520 330 600 355 L600 420 C520 395 430 445 330 425 S120 400 0 425Z" fill="#a9d6e8"/>
          <g fill="none" stroke="#fffaf1" stroke-linecap="round">
            <path d="M-10 120 H610" stroke-width="22"/>
            <path d="M-10 250 H610" stroke-width="28"/>
            <path d="M120 -10 V470" stroke-width="22"/>
            <path d="M380 -10 V470" stroke-width="26"/>
            <path d="M-10 60 L610 200" stroke-width="12"/>
          </g>
          <g fill="none" stroke="#e6d4b3" stroke-width="2" stroke-dasharray="10 10">
            <path d="M-10 250 H610"/>
            <path d="M380 -10 V470"/>
          </g>
          <g font-family="Arial, sans-serif" font-size="12" font-weight="700" fill="rgba(29,14,10,.45)" letter-spacing="1">
            <text x="392" y="36">5TH ST</text>
            <text x="20" y="108">MAPLE AVE</text>
            <text x="500" y="244">MARKET BLVD</text>
            <text x="132" y="440">RIVER WALK</text>
          </g>
          <g transform="translate(380 250)">
            <circle class="pulse" r="18" fill="#e5503a"/>
            <circle r="16" fill="#e5503a" stroke="#fffaf1" stroke-width="4"/>
            <circle r="4" fill="#fffaf1"/>
            <rect x="-206" y="-62" width="200" height="40" rx="12" fill="#1d0e0a"/>
            <text id="mapLabel" x="-106" y="-37" text-anchor="middle" fill="#fff6e8" font-family="Arial Black, Impact, sans-serif" font-size="14">Finding…</text>
          </g>
        </svg>
        <div class="map-note">Pin updates automatically with today’s stop. Follow us for last-minute changes.</div>
      </div>
    </div>
  </div>
</section>

<section class="section cater" id="cater">
  <div class="wrap cater-grid">
    <div>
      <p class="kicker" style="color:var(--saffron)">Catering</p>
      <h2>Feed your crew.</h2>
      <p class="sub">Office lunches, backyard parties, weddings, or the after-party that needs something great at 1am. We bring the truck, the tacos and the energy.</p>
      <ul>
        <li>Drop-off trays, or we park and serve on-site</li>
        <li>Vegetarian and gluten-free options on every tray</li>
        <li>Groups of 20 to 500 guests</li>
        <li>We reply within one business day</li>
      </ul>
    </div>

    <div class="form-card">
      <form id="cateringForm" class="form">
        <div class="form-head">
          <h3>Request a quote</h3>
          <p>Tell us the rough details. We’ll handle the rest.</p>
        </div>
        <div class="form-grid">
          <label>Name<input name="name" required autocomplete="name"></label>
          <label>Email<input type="email" name="email" required autocomplete="email"></label>
          <label>Event date<input type="date" id="eventDate" required></label>
          <label>Guests
            <select name="guests" required>
              <option value="">Choose…</option>
              <option>20–50</option>
              <option>50–100</option>
              <option>100–250</option>
              <option>250–500</option>
              <option>500+</option>
            </select>
          </label>
          <label class="full">Anything we should know?
            <textarea name="notes" rows="3" placeholder="Venue, vibe, dietary needs, spice tolerance…"></textarea>
          </label>
        </div>
        <button class="btn primary block" type="submit">Send request</button>
      </form>
      <div id="cateringOk" class="thanks" hidden>
        <p class="kicker">Got it</p>
        <h3>Thanks! Let’s make it happen.</h3>
        <p>We’ll reply within one business day with a quote and a menu.</p>
      </div>
    </div>
  </div>
</section>

<footer class="foot">
  <div class="wrap foot-grid">
    <div>
      <a class="brand" href="#top"><span class="mark">KL</span><span>Kimchi<b>Loco</b></span></a>
      <p class="fine" style="margin-top:16px;max-width:32ch;opacity:.7">Korean-Mexican street tacos on wheels. Follow the truck, chase the flavor.</p>
    </div>
    <div>
      <h4>Find us</h4>
      <p>The live schedule above always shows where we are. Check before you roll up.</p>
    </div>
    <div>
      <h4>Say hi</h4>
      <p><a id="phoneLink" href="#"></a></p>
      <p style="margin-top:8px"><a id="emailLink" href="#"></a></p>
      <p style="margin-top:8px" id="igText"></p>
    </div>
  </div>
  <p class="wrap copy">© <span id="year"></span> Kimchi Loco. Made with lots of gochujang.</p>
</footer>

<button class="mobile-bar" id="mobileBar" type="button" aria-label="Open your order">
  <span id="mobileTotal">Start your order</span>
  <span>View →</span>
</button>

<div class="drawer" id="drawer" aria-hidden="true">
  <div class="scrim" data-close></div>
  <aside class="panel" role="dialog" aria-modal="true" aria-labelledby="cartTitle">
    <header class="panel-head">
      <h2 id="cartTitle">Your order</h2>
      <button class="close" type="button" data-close aria-label="Close">×</button>
    </header>
    <div class="panel-body">
      <div id="cartView"><div id="lines"></div></div>
      <div id="doneView" class="done" hidden>
        <p class="kicker">Order received</p>
        <h3>Order <span id="doneNum"></span> is on the grill.</h3>
        <p>We’ll text you when it’s hot, usually in 8–10 minutes. Head to the window and say hi.</p>
        <button class="btn primary" type="button" data-close style="margin-top:22px">Keep browsing</button>
      </div>
    </div>
    <footer class="panel-foot" id="panelFoot">
      <div class="sum"><span>Subtotal</span><span id="subtotal">$0.00</span></div>
      <button class="btn primary block" id="placeOrder" type="button" disabled>Place order for pickup</button>
      <p class="fine" style="text-align:center;margin-top:12px">Pickup at the window · Pay at pickup</p>
    </footer>
  </aside>
</div>

<div class="toast" id="toast" role="status" aria-live="polite"></div>

<script>
(() => {
  'use strict';

  /* ===== EDIT THESE: your real details (placeholders for now) ===== */
  const CONFIG = {
    phone: '(555) 014-2024',
    email: 'hello@kimchiloco.com',
    instagram: '@kimchiloco'
  };

  /* ===== EDIT THESE: your real weekly spots & hours ===== */
  // open/close are 24h decimals. stop:null = day off.
  const SCHEDULE = [
    { day: 0, stop: 'Hollow Park Brunch', open: 10, close: 15 },
    { day: 1, stop: null },
    { day: 2, stop: 'Brewery Row', open: 11, close: 21 },
    { day: 3, stop: 'Riverside Market', open: 11, close: 21 },
    { day: 4, stop: '5th & Maple', open: 11, close: 22 },
    { day: 5, stop: 'Night Market Lot', open: 17, close: 23 },
    { day: 6, stop: 'Farmers Market', open: 9, close: 16 }
  ];

  const DAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
  const HEAT = ['No heat', 'Mild', 'Hot', 'Loco'];

  const PROTEINS = [
    { id: 'bulgogi', name: 'Seoul Bulgogi', price: 5, filling: '#8a3a1c' },
    { id: 'pork', name: 'Dwaeji Fire', price: 5, filling: '#c4281c' },
    { id: 'chicken', name: 'Yangnyeom Crunch', price: 5, filling: '#e8a33a' },
    { id: 'tofu', name: 'Tofu Tofu', price: 4.5, filling: '#e6c97a' }
  ];
  const SAUCES = [
    { id: 'honey', name: 'Gochu Honey', color: '#ff6b3d' },
    { id: 'ranch', name: 'Ssamjang Ranch', color: '#fbf6e6' },
    { id: 'yuzu', name: 'Yuzu Chili', color: '#ffe14d' }
  ];
  const TOPPINGS = [
    { id: 'kimchi', name: 'Kimchi', color: '#c8321e', kind: 'dot', price: 0.5 },
    { id: 'cilantro', name: 'Cilantro', color: '#3fae5a', kind: 'leaf', price: 0.5 },
    { id: 'daikon', name: 'Pickled daikon', color: '#fff7e6', kind: 'dot', price: 0.5 },
    { id: 'sesame', name: 'Sesame', color: '#f7e7b5', kind: 'speck', price: 0.5 },
    { id: 'egg', name: 'Fried egg', color: '#fffdf6', kind: 'egg', price: 1.25 }
  ];

  const MENU = [
    { id: 't-bulgogi', cat: 'tacos', name: 'Seoul Bulgogi', desc: 'Thin-sliced ribeye, soy-pear glaze, quick-pickled onion, scallion ranch.', price: 5, heat: 0, tags: ['Start here'], bg: '#ffd9b8', taco: { filling: '#8a3a1c', sauce: '#fbf6e6', toppings: ['sesame', 'daikon'] } },
    { id: 't-pork', cat: 'tacos', name: 'Dwaeji Fire', desc: 'Gochujang pork shoulder, kimchi slaw, cilantro-lime crema. Bring water.', price: 5, heat: 3, tags: [], bg: '#ffc9b8', taco: { filling: '#c4281c', sauce: '#ff6b3d', toppings: ['kimchi', 'cilantro'] } },
    { id: 't-chicken', cat: 'tacos', name: 'Yangnyeom Crunch', desc: 'Double-fried chicken tossed in sweet-spicy yangnyeom, pickled daikon and sesame.', price: 5, heat: 2, tags: ['Crispy'], bg: '#ffe7a3', taco: { filling: '#e8a33a', sauce: '#ffe14d', toppings: ['daikon', 'sesame'] } },
    { id: 't-tofu', cat: 'tacos', name: 'Tofu Tofu', desc: 'Crispy tofu, mushroom bulgogi, cilantro and kimchi. Plant-based, zero compromise.', price: 4.5, heat: 1, tags: ['Vegetarian'], bg: '#d6efd3', taco: { filling: '#e6c97a', sauce: '#fbf6e6', toppings: ['cilantro', 'kimchi'] } },
    { id: 's-fries', cat: 'sides', name: 'Kimchi Fries', desc: 'Crispy fries, gochujang cheese sauce, kimchi and scallion. Share it, or don’t.', price: 6, word: 'FRIES', bg: '#ffd0bd' },
    { id: 's-mandu', cat: 'sides', name: 'Pork Mandu', desc: 'Six pan-fried dumplings with a sharp soy-vinegar dip.', price: 7, word: 'MANDU', bg: '#ffe9c9' },
    { id: 's-tots', cat: 'sides', name: 'Corn Cheese Tots', desc: 'Golden tots, sweet corn, melted cheese, crushed seaweed.', price: 5, word: 'TOTS', bg: '#fff1b8' },
    { id: 'd-yuzu', cat: 'drinks', name: 'Yuzu Soda', desc: 'Sparkling citrus made with real yuzu. Bright, tart, refreshing.', price: 3.5, word: 'YUZU', bg: '#d3f1ec' },
    { id: 'd-barley', cat: 'drinks', name: 'Roasted Barley Tea', desc: 'Toasty, nutty and served cold. The classic cooling sip.', price: 2.5, word: 'TEA', bg: '#f1e0c4' },
    { id: 'd-sikhye', cat: 'drinks', name: 'Sweet Rice Punch', desc: 'Cinnamon-kissed rice drink. The reset between bites.', price: 3.5, word: 'RICE', bg: '#ffd6e0' }
  ];

  const SPOTS = [[96, 136], [128, 146], [162, 138], [198, 146], [230, 134], [112, 126], [212, 126], [146, 150], [180, 128]];
  const DRIZZLE = 'M52 146 Q78 112 104 128 T152 122 T200 128 T246 120 T270 138';

  /* ---------- Helpers ---------- */
  const $ = (s, r = document) => r.querySelector(s);
  const $$ = (s, r = document) => Array.from(r.querySelectorAll(s));
  const money = n => '$' + n.toFixed(2);
  const fmt = h => {
    const hr = Math.floor(h);
    const disp = hr % 12 === 0 ? 12 : hr % 12;
    return disp + (hr < 12 ? 'am' : 'pm');
  };

  /* ---------- Procedural taco art ---------- */
  function tacoSVG({ filling, sauce, toppings = [] }) {
    const egg = toppings.includes('egg')
      ? '<ellipse cx="160" cy="101" rx="38" ry="19" fill="#fffdf6"/><circle cx="166" cy="99" r="10.5" fill="#ffb11e"/><circle cx="163" cy="96" r="3" fill="#fff3c4"/>'
      : '';
    const items = toppings.filter(id => id !== 'egg').map((id, i) => {
      const tp = TOPPINGS.find(t => t.id === id);
      const [x, y] = SPOTS[i % SPOTS.length];
      if (tp.kind === 'leaf') {
        return `<ellipse cx="${x}" cy="${y}" rx="8" ry="4" fill="${tp.color}" transform="rotate(${(i * 53) % 180} ${x} ${y})"/>`;
      }
      if (tp.kind === 'speck') {
        return [[-4, -2], [3, -3], [0, 3], [5, 2]].map(([dx, dy]) =>
          `<circle cx="${x + dx}" cy="${y + dy}" r="2" fill="${tp.color}"/>`).join('');
      }
      return `<circle cx="${x}" cy="${y}" r="6.5" fill="${tp.color}" stroke="rgba(0,0,0,.2)" stroke-width="1"/>`;
    }).join('');

    return `<svg viewBox="0 0 320 200" aria-hidden="true">
      <ellipse cx="160" cy="172" rx="150" ry="11" fill="rgba(0,0,0,.2)"/>
      <path d="M20 160 Q160 -20 300 160 Z" fill="#f2c061"/>
      <path d="M38 148 Q160 12 282 148" fill="none" stroke="#fff3c9" stroke-width="3" stroke-linecap="round" opacity=".6"/>
      <path d="M38 160 Q160 30 282 160 Z" fill="${filling}"/>
      <path d="${DRIZZLE}" fill="none" stroke="rgba(0,0,0,.25)" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" transform="translate(0 2)"/>
      <path d="${DRIZZLE}" fill="none" stroke="${sauce}" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
      ${egg}${items}
      <path d="M20 160 H300" stroke="#c98a3a" stroke-width="5" stroke-linecap="round"/>
    </svg>`;
  }

  /* ---------- Hero art ---------- */
  $('#heroTaco').innerHTML = tacoSVG({ filling: '#c4281c', sauce: '#ff6b3d', toppings: ['kimchi', 'sesame', 'cilantro', 'egg'] });

  const NS = 'http://www.w3.org/2000/svg';
  const bulbs = $('#bulbs');
  for (let i = 0; i < 12; i++) {
    const c = document.createElementNS(NS, 'circle');
    c.setAttribute('cx', 56 + i * 38);
    c.setAttribute('cy', 80);
    c.setAttribute('r', 4);
    c.setAttribute('class', 'bulb');
    c.style.animationDelay = (i * 0.18) + 's';
    bulbs.appendChild(c);
  }

  /* ---------- Menu ---------- */
  const HEAT_DOTS = n => `<span class="heat" aria-hidden="true">${[0, 1, 2].map(i => `<i class="${i < n ? 'on' : ''}"></i>`).join('')}</span><span>${HEAT[n]}</span>`;
  const cardHTML = m => {
    const art = m.taco ? tacoSVG(m.taco) : `<span class="word">${m.word}</span>`;
    const heat = m.heat != null ? HEAT_DOTS(m.heat) : '';
    const tags = (m.tags || []).map(t => `<span class="badge">${t}</span>`).join('');
    return `<article class="card">
      <div class="card-art" style="--bg:${m.bg}">${art}</div>
      <div class="card-body">
        <h3>${m.name}</h3>
        <p>${m.desc}</p>
        <div class="meta">${heat}${tags}</div>
        <div class="card-foot">
          <span class="price">${money(m.price)}</span>
          <button class="add" type="button" data-id="${m.id}">Add +</button>
        </div>
      </div>
    </article>`;
  };

  let menuFilter = 'all';
  function renderMenu() {
    const list = MENU.filter(m => menuFilter === 'all' || m.cat === menuFilter);
    $('#menuGrid').innerHTML = list.map(cardHTML).join('');
  }
  $('#tabs').addEventListener('click', e => {
    const t = e.target.closest('.tab');
    if (!t) return;
    menuFilter = t.dataset.filter;
    $$('.tab').forEach(b => b.setAttribute('aria-selected', String(b === t)));
    renderMenu();
  });
  $('#menuGrid').addEventListener('click', e => {
    const btn = e.target.closest('.add');
    if (!btn) return;
    const m = MENU.find(x => x.id === btn.dataset.id);
    if (m) addItem({ id: m.id, name: m.name, note: '', price: m.price });
  });

  /* ---------- Builder ---------- */
  const build = { protein: 'pork', sauce: 'honey', toppings: new Set(['kimchi', 'cilantro']), heat: 2 };

  function buildState() {
    const p = PROTEINS.find(x => x.id === build.protein);
    const s = SAUCES.find(x => x.id === build.sauce);
    const tops = [...build.toppings];
    const tp = tops.map(id => TOPPINGS.find(t => t.id === id));
    const price = p.price + tp.reduce((n, t) => n + t.price, 0);
    return { p, s, tops, names: tp.map(t => t.name), price, heat: build.heat };
  }

  function renderChips() {
    $('#proteinChips').innerHTML = PROTEINS.map(p =>
      `<button class="chip" type="button" data-group="protein" data-id="${p.id}" aria-pressed="${build.protein === p.id}"><span class="sw" style="background:${p.filling}"></span>${p.name}</button>`).join('');
    $('#sauceChips').innerHTML = SAUCES.map(s =>
      `<button class="chip" type="button" data-group="sauce" data-id="${s.id}" aria-pressed="${build.sauce === s.id}"><span class="sw" style="background:${s.color}"></span>${s.name}</button>`).join('');
    $('#toppingChips').innerHTML = TOPPINGS.map(t =>
      `<button class="chip" type="button" data-group="topping" data-id="${t.id}" aria-pressed="${build.toppings.has(t.id)}"><span class="sw" style="background:${t.color}"></span>${t.name}</button>`).join('');
  }

  function renderPreview() {
    const b = buildState();
    $('#previewArt').innerHTML = tacoSVG({ filling: b.p.filling, sauce: b.s.color, toppings: b.tops });
    $('#previewName').textContent = `${b.p.name} + ${b.s.name}`;
    $('#previewDesc').textContent = `${HEAT[b.heat]} heat · ${b.names.length ? b.names.join(', ') : 'no toppings'}`;
    $('#previewPrice').textContent = money(b.price);
    $('#heatOut').textContent = HEAT[b.heat];
    $('#preview').style.setProperty('--h', (0.08 + b.heat * 0.12).toFixed(2));
  }

  $('.build-controls').addEventListener('click', e => {
    const c = e.target.closest('.chip');
    if (!c) return;
    const { group, id } = c.dataset;
    if (group === 'protein') build.protein = id;
    else if (group === 'sauce') build.sauce = id;
    else if (group === 'topping') {
      if (build.toppings.has(id)) build.toppings.delete(id);
      else build.toppings.add(id);
    }
    renderChips();
    renderPreview();
  });
  $('#heat').addEventListener('input', e => {
    build.heat = Number(e.target.value);
    renderPreview();
  });
  $('#addBuilt').addEventListener('click', () => {
    const b = buildState();
    const id = `b-${b.p.id}-${b.s.id}-${b.heat}-${[...b.tops].sort().join('.')}`;
    addItem({
      id,
      name: `${b.p.name} + ${b.s.name}`,
      note: `${HEAT[b.heat]} · ${b.names.join(', ') || 'no toppings'}`,
      price: b.price
    });
  });

  /* ---------- Schedule & live status ---------- */
  function renderSchedule(dow) {
    $('#sched').innerHTML = [1, 2, 3, 4, 5, 6, 0].map(d => {
      const s = SCHEDULE.find(x => x.day === d);
      const isToday = d === dow;
      const time = s.stop ? `${fmt(s.open)} – ${fmt(s.close)}` : 'Closed';
      return `<li class="${isToday ? 'today' : ''}">
        <span class="day">${DAYS[d]}${isToday ? '<em>Today</em>' : ''}</span>
        <span>${s.stop || 'Prep day, truck resting'}</span>
        <span class="time ${s.stop ? '' : 'closed'}">${time}</span>
      </li>`;
    }).join('');
  }

  function updateStatus() {
    const now = new Date();
    const dow = now.getDay();
    const h = now.getHours() + now.getMinutes() / 60;
    const today = SCHEDULE.find(s => s.day === dow);
    let state = 'closed', title, meta, stop, mapText;

    if (today && today.stop && h >= today.open && h < today.close) {
      state = 'open';
      stop = today.stop;
      title = `Open now · ${stop}`;
      meta = `Serving until ${fmt(today.close)}. Come hungry.`;
      mapText = stop;
    } else if (today && today.stop && h < today.open) {
      state = 'soon';
      stop = today.stop;
      title = `Opens at ${fmt(today.open)} today`;
      meta = `${stop}. Get there early for the first batch.`;
      mapText = stop;
    } else {
      title = today && today.stop ? 'Closed for tonight' : 'Prep day, truck resting';
      for (let i = 1; i <= 7; i++) {
        const next = SCHEDULE.find(s => s.day === (dow + i) % 7);
        if (next && next.stop) {
          stop = next.stop;
          meta = `Next stop: ${next.stop}, ${i === 1 ? 'tomorrow' : DAYS[next.day]} from ${fmt(next.open)}.`;
          mapText = `Next: ${next.stop}`;
          break;
        }
      }
    }

    $('#statusPill').dataset.state = state;
    $('#liveStatus').textContent = title;
    $('#nowTitle').textContent = title;
    $('#nowMeta').textContent = meta || '';
    $('#mapLabel').textContent = mapText || 'Stay tuned';
    renderSchedule(dow);
  }

  /* ---------- Loco card ---------- */
  const stampWrap = $('#stamps');
  stampWrap.innerHTML = Array.from({ length: 10 }, (_, i) =>
    `<button class="stamp" type="button" data-i="${i}" aria-pressed="false" aria-label="Stamp ${i + 1}">${i + 1}</button>`).join('');
  stampWrap.addEventListener('click', e => {
    const b = e.target.closest('.stamp');
    if (!b) return;
    const on = b.getAttribute('aria-pressed') !== 'true';
    b.setAttribute('aria-pressed', String(on));
    const count = $$('.stamp', stampWrap).filter(x => x.getAttribute('aria-pressed') === 'true').length;
    $('#stampMsg').textContent = count === 10
      ? 'Free taco unlocked! Show this card at the window.'
      : `${10 - count} more to go. Your 10th taco is on us.`;
  });

  /* ---------- Cart ---------- */
  let cart = [];
  let toastTimer;

  function toast(msg) {
    const t = $('#toast');
    t.textContent = msg;
    t.classList.add('show');
    clearTimeout(toastTimer);
    toastTimer = setTimeout(() => t.classList.remove('show'), 1800);
  }

  function lineHTML(i) {
    return `<div class="line">
      <div><strong>${i.name}</strong>${i.note ? `<small>${i.note}</small>` : ''}</div>
      <div class="price">${money(i.price * i.qty)}</div>
      <div class="qty">
        <button type="button" data-act="dec" data-id="${i.id}" aria-label="Remove one">−</button>
        <span>${i.qty}</span>
        <button type="button" data-act="inc" data-id="${i.id}" aria-label="Add one">+</button>
      </div>
    </div>`;
  }

  function renderCart() {
    const count = cart.reduce((n, i) => n + i.qty, 0);
    const total = cart.reduce((n, i) => n + i.qty * i.price, 0);
    $('#cartCount').textContent = count;
    $('#mobileTotal').textContent = count
      ? `${count} item${count > 1 ? 's' : ''} · ${money(total)}`
      : 'Start your order';
    $('#subtotal').textContent = money(total);
    $('#placeOrder').disabled = count === 0;
    $('#lines').innerHTML = count
      ? cart.map(lineHTML).join('')
      : '<p class="empty">Your tray is empty. Add something loco.</p>';
  }

  function addItem(item) {
    const found = cart.find(i => i.id === item.id);
    if (found) found.qty++;
    else cart.push({ ...item, qty: 1 });
    renderCart();
    const c = $('#cartCount');
    c.classList.remove('bump');
    void c.offsetWidth;
    c.classList.add('bump');
    toast(`Added ${item.name} to your order`);
  }

  $('#lines').addEventListener('click', e => {
    const b = e.target.closest('button[data-act]');
    if (!b) return;
    const item = cart.find(i => i.id === b.dataset.id);
    if (!item) return;
    if (b.dataset.act === 'inc') item.qty++;
    else {
      item.qty--;
      if (item.qty <= 0) cart = cart.filter(i => i !== item);
    }
    renderCart();
  });

  $('#placeOrder').addEventListener('click', () => {
    if (!cart.length) return;
    const num = 100 + Math.floor(Math.random() * 900);
    cart = [];
    renderCart();
    $('#cartView').hidden = true;
    $('#panelFoot').hidden = true;
    $('#doneNum').textContent = '#' + num;
    $('#doneView').hidden = false;
  });

  function openDrawer() {
    const d = $('#drawer');
    d.classList.add('open');
    d.setAttribute('aria-hidden', 'false');
  }
  function closeDrawer() {
    const d = $('#drawer');
    d.classList.remove('open');
    d.setAttribute('aria-hidden', 'true');
    setTimeout(() => {
      $('#doneView').hidden = true;
      $('#cartView').hidden = false;
      $('#panelFoot').hidden = false;
    }, 350);
  }

  $('#cartBtn').addEventListener('click', openDrawer);
  $('#mobileBar').addEventListener('click', openDrawer);
  document.addEventListener('click', e => {
    if (e.target.closest('[data-close]')) closeDrawer();
  });
  document.addEventListener('keydown', e => {
    if (e.key === 'Escape') closeDrawer();
  });

  /* ---------- Catering form ---------- */
  const eventDate = $('#eventDate');
  const today = new Date();
  today.setMinutes(today.getMinutes() - today.getTimezoneOffset());
  eventDate.min = today.toISOString().slice(0, 10);

  $('#cateringForm').addEventListener('submit', e => {
    e.preventDefault();
    e.target.hidden = true;
    $('#cateringOk').hidden = false;
  });

  /* ---------- Footer ---------- */
  $('#year').textContent = new Date().getFullYear();
  $('#phoneLink').textContent = CONFIG.phone;
  $('#phoneLink').href = 'tel:' + CONFIG.phone.replace(/[^\d+]/g, '');
  $('#emailLink').textContent = CONFIG.email;
  $('#emailLink').href = 'mailto:' + CONFIG.email;
  $('#igText').textContent = 'Instagram ' + CONFIG.instagram;

  /* ---------- Init ---------- */
  renderChips();
  renderPreview();
  renderMenu();
  renderCart();
  updateStatus();
  setInterval(updateStatus, 60000);
})();
</script>
</body>
</html>
Reasoning trace (72,613 tokens)
I need a single self-contained HTML file for the Kimchi Loco taco truck, with inline CSS and JS and no external resources, so no web fonts. It has to look good at both 1280x800 and 375px, and the first screen should already be appetizing and energetic, with the menu, hours, location, and a truck animation.

I'm settling on the page's sections: a hero with a headline, an SVG food truck that animates, and calls to action, plus a live open/closed status. I'm still weighing the order interactive, taco builder, map, and social proof, aiming for something polished but not oversized.

I'm sketching out the rest of the page now: a marquee ticker of flavors under the hero, then a menu with filter tabs, prices, spice tags, and add-to-order cards. A floating cart button will track the running total. I'm also weighing a "build your own taco" section where picking a protein and sauce recolors a live taco illustration, though I'm keeping an eye on scope so it stays polished and not overbuilt.

I'm planning the site's data setup: a CONFIG object at the top of the script will hold the name, address, hours, and phone, so they're easy to swap out. I'm also weighing whether to use plausible placeholder details, since the user hasn't supplied real ones yet.

I'm weighing a few more sections for the site: a schedule showing where the truck will be each day with today's stop highlighted, plus a live open/closed pill. For social proof, I'm wary of inventing testimonials, so I'm leaning toward a "why people line up" list of features like fresh daily prep, in-house kimchi, and vegan or gluten-free options, which the owner can verify before launch.

I'm now thinking through the footer, with a catering inquiry form that shows a thank-you message, and a floating cart button that sits at the bottom on mobile. I'm also planning the animations: the truck drives in on load, the wheels turn, steam rises, the ticker scrolls, and sections fade in on scroll, while making sure the hero stays visible right away.

I'm dropping the idea of hiding content until it scrolls into view, since it could leave sections blank in a full-page capture. Animations will stay on the hero, with the rest of the page visible by default. Next I'm sketching the menu entries, starting with the Bulgogi Beef Taco and the spicy pork option.

I'm filling in the menu with the rest of the tacos: a crispy chicken option tossed in a sweet-spicy glaze, and a vegetarian tofu taco with mushroom bulgogi. Next are the sides, a kimchi fries entry and a Korean dumpling option, and then a short list of drinks, including yuja soda and barley tea, with an alcohol option still undecided.

I'm working out the signature taco builder next, with protein options like bulgogi, spicy pork, and crispy chicken, each paired with a sauce choice.

I'm settling the build-your-taco section now: three protein choices, three sauces, and optional toppings, with a live SVG taco that recolors as I pick each one. I'm also adding a heat slider and generating a playful name from the protein and sauce, with the price rising slightly for extra toppings.

Still writing the taco SVG...

Still writing the truck SVG...

Now I'm picking the color palette: a dark brown-black base, kimchi red, gochujang orange, saffron, a cilantro green, and cream, with a pink accent for the "loco" energy. For the hero I'm weighing a left-side pill for "Korean BBQ × Mexican street · Now rolling" with a punchy headline to match.

I'm trimming the hero copy down: a short headline about Seoul on a tortilla, a sub-line naming the bulgogi, yangnyeom chicken, and in-house kimchi, and two buttons pointing to the find and build sections. I'm avoiding invented stats like ratings or fermentation times, and I'll put the placeholder details in the config so the owner can edit them.

I'm laying out the weekly schedule now, with each day's stop and time, so the page can highlight whichever spot is live today.

I'm settling the Mon-closed prep day and the "Today" highlight tied to the day of the week, plus the catering form with required fields and a success message on submit. Next I'm working out the hours config as a schedule with start and end times so the open-now check works, and the order drawer as a side panel on desktop that goes full-screen on mobile.

Next I'm writing a helper that builds the taco SVG from a filling, sauce, and toppings, so the same drawing can appear in the menu cards and the builder.

Still writing the taco SVG...

Still working out the taco's shape: a flat-bottomed half-moon with an arched top, and a wavy filling sitting inside it.

Still working out the taco's arc: the filling sits along a curve from the bottom-left to the bottom-right, and its midpoint lands around the center of the shell. I'm placing the egg and toppings along that same curve so they follow the filling's shape.

Still writing the taco SVG...

Still writing taco SVG...

Still writing the taco SVG...

Still writing the menu item data...

Still writing the menu item data...

Now I'm laying out the drink list: a yuzu soda, roasted barley tea with free refills, and sweet rice punch. Then the menu tabs will be All, Tacos, and Sides.

Now I'm wiring up the cart and the builder: the cart will hold items with an id, name, price, and quantity, and the badge will count them. For the taco builder, I'm tracking protein, sauce, toppings, egg, and a heat level from mild to loco, and building a playful name from the choices.

Still working out the builder's pricing and the heat control: the price will be the protein's price plus a dollar for the egg and a bit for each topping, and a heat slider will adjust the label.

Next I'm adding a "Find the truck" section with a schedule grid that highlights today, a live status pill, and a stylized SVG map with roads and a pulsing pin marking where the truck is parked.

Still writing the truck SVG...

Still writing the truck SVG...

Still writing the truck SVG...

Still writing the truck SVG...

Still writing the truck SVG...

Still writing the truck SVG...

I'm giving the hero a warm radial glow behind the headline, with the copy on the left and the truck on the right, and it stacks into one column on mobile. The header will be a sticky bar with a wordmark and links to Menu, Build, Find us, Catering, and the cart, followed by a ticker under the hero and sections with ids for menu, build, find, and cater.

I'm laying out the hero copy now: an eyebrow line with the live status, a headline about Seoul on a tortilla, a short description of the bulgogi, chicken, and in-house kimchi, and two buttons for the menu and the taco builder. Under that I'll add a row of quick facts about in-house kimchi, veg and gluten-free options, and catering size. The ticker will use ✦ separators with no emoji.

I'm laying out the menu tabs and the taco builder band, with a sticky preview beside the controls. The find section will get a live status card, a seven-day schedule, and a map, and the catering section will have a short benefits list and a form ending in a success message. The footer and a right-side order drawer with a disabled checkout button when the cart is empty will close things out.

Still writing the JS setup with the config and schedule data...

Still writing the schedule data, filling in the days of the week with their stops and hours.

Still working out the live status logic: I'm checking today's entry in the schedule, and if the current hour falls inside its open window, the status reads as open now; if it's before opening, it says when today's stop opens; otherwise it falls back to the next stop.

Now I'm writing the live status logic for the schedule, and the map needs a light cream background with grey roads, a green park, and a blue river, plus a pulsing pin at the truck's spot.

Setting the colour scheme now: cream for the page body and menu, a dark ink hero and builder band, saffron for the ticker, red for the catering card, and ink for the footer. For type, I'll use a heavy uppercase sans-serif stack for headings and the system font for body text, so nothing needs to load externally.

Still writing the HTML structure: a sticky header with the brand, the section links, and the order button, followed by the hero with its status pill and headline.

Still writing the hero markup: the buttons, the three quick facts, and the truck art on the right, with the live status line set by the script.

Now I'm laying out the menu section: a heading and subhead, a row of filter tabs, and a grid where each card gets its own illustration, name, and description.

Still writing the menu cards: each one gets a Korean character in a coloured circle as its art, with the side and drink entries using the same treatment.

Now I'm writing the builder section: a protein picker, then the sauce, toppings, egg, and heat choices.

Now I'm setting up the builder's sauce, topping, and heat controls, with the preview card beside them showing the taco's name, description, and price as I pick things.

Still writing the taco builder markup: the chips for protein, sauce, and toppings, the heat slider, and a preview card that shows the name and price.

Still writing the builder data: the proteins, the price for each one, and the taco's name and description.

Still writing the builder data: the sauces and toppings, with the kimchi and cilantro options and their prices.

Still writing the taco SVG function, which takes the filling, sauce, toppings, and egg options and places the toppings at fixed spots.

Still writing the taco SVG, placing the toppings across fixed spots with dots, leaves, and specks.

Still writing the taco SVG, adding the sauce drizzle and then the shell, its highlight, and a plate shadow.

Still writing the taco SVG, adding the shell's flat bottom edge and the plate shadow beneath it.

Still writing the taco SVG, adding the shell's bottom edge, a few tortilla spots, and the egg on top of the filling.

Still writing the truck SVG, starting with the glow and body gradients in its defs.

Still writing the truck SVG: the shadow under the wheels, a steam group with puffs, and a dark chimney on the roof.

Still writing the truck SVG: the body rectangle with its rounded corners, then a row of roof bulbs that I'll generate with a small script loop instead of writing each one out.

Still writing the truck's sign text, centred across the body, and checking that the lettering clears the roof lights, so I'm moving the bulbs up and nudging the text baseline down.

Still writing the awning: eight alternating stripes across the front of the truck, starting at x=90, and I'm deciding whether to draw them by hand or loop over them in JS.

Still writing the awning: eight alternating stripes, and I'm dropping the scallops to keep it flat with a dark shadow strip underneath.

Still writing the truck's window and counter: a dark recess with a warm glow, then the cream counter top and its shadowed edge beneath.

Still writing the truck's menu board: a dark panel on the right with a MENU heading and the item prices listed beneath it.

Still writing the truck's cab: a red box on the right with a windshield cut into it.

Still writing the truck's wheels: a dark headlight and front bumper, then each wheel with a dark rim and a silver hub.

Still writing the truck's wheels: each one is a dark tyre with a silver hub and spokes, set to spin with a CSS rotation around its centre.

Still working out the wheels: the spin should pivot on each wheel's centre, so I'm weighing whether to wrap the spinning circles in a group translated to the wheel position with the origin at 0,0, and how the CSS transform-origin behaves under the default view-box reference.

Still working out the wheels: I need the spin to pivot on each wheel's centre, and I'm checking whether `transform-box: fill-box` with `transform-origin: center` on the circle group will hold that point, since the default view-box reference behaves differently.

Still writing the wheel group: a tyre circle and a hub, with the spin set to pivot on the tyre's centre.

Still writing the truck's wheel spin: the rotation pivots on each tyre's centre, and I'm setting the transform origin to match.

Still writing the truck's wheel spin and drive-in: the wheels pivot on their centres, the whole truck slides in from the left, and I'm adding steam puffs that rise and fade above the chimney.

Still writing the hero's floating taco: a positioned element that bobs and tilts, with its SVG injected from JavaScript into the hero art area.

Still writing the page's CSS: a dark warm background with a faint dot pattern and glowing orange and yellow radial gradients behind the hero, plus a yellow marquee ticker band.

Still writing the page's CSS: the color variables and base body styles, with the display headings set in a heavy system sans.

Still writing the page's header CSS: a sticky dark bar with a blurred backdrop and a brand block with a small round logo badge.

Still writing the header's styling: the brand mark and nav links, then the cart button with its count badge.

Still writing the page's CSS: the hero heading sized with clamp, with the emphasis word in a saffron-to-orange gradient, then the lede text and the pill-shaped buttons with their hover lift.

Still writing the page's CSS: the button and status pill styling, a pulsing mint dot, and a saffron star marker on each fact in the hero list.

Still writing the page's CSS: the hero art area sized to the truck, with the floating taco pinned top-left and gently bobbing.

Still writing the page's CSS: the section kicker and headings, the tab buttons for the menu, and a menu grid of cards with rounded corners and soft shadows.

Still writing the card styles: a rounded paper card with a soft shadow and a slight lift on hover, and a fixed-height art area holding the SVG.

I'm dropping the Korean-character logo idea for the card art, since the sandbox may lack CJK fonts and it would render as empty boxes. Instead I'll show each item's English keyword in big Arial Black type, which reads well and needs no extra fonts.

I'm deciding to keep the Korean names out of the page, since the Hangul would render as empty boxes on any machine without CJK fonts. The brand stays in plain Latin letters, and the card art will use big English keywords in Arial Black.

Still writing the card styles: the price, the add button, and the heat indicator dots below the description.

Still writing the builder's CSS: a dark section with a two-column grid, styled fieldset legends and chip buttons.

Still writing the builder's styling: the chip buttons get a transparent fill with a light border, turning cream when pressed, and each swatch is a small round color dot. Then the range slider, the preview card's dark panel with a soft glow behind the art, and its name heading.

Still writing the find section: a cream background with a two-column grid, a live card and schedule list on the left, and a parchment map on the right.

Still writing the page's styles: the catering band in kimchi red with a two-column layout, a paper form card with bordered white inputs, and then the footer and a fixed toast at the bottom.

Still writing the cart drawer: a fixed overlay that fades in, with a cream side panel sliding in from the right and holding a header, a scrolling item list, and a footer.

Still writing the responsive rules: the hero and build and find grids collapse to one column at 900px, the nav hides at 820px, and at 480px the section padding and wrap width tighten.

Checking the hero text width at 375px and the overflow settings, then moving on to the JavaScript config and menu data.

Still writing the menu data array: each taco gets a name, description, price, and heat level, with colour fields for its SVG art.

Still writing the menu data: the Yuzu Soda entry with its description, price, and a pale yellow background for its card.

Still writing the JavaScript: the money format uses toFixed(2) everywhere, and the order button will show a confirmation with an order number in the drawer.

Next I'm wiring up the order confirmation: placing an order empties the cart and swaps the drawer for an order number, and a "Back to tacos" button resets it. The live status check runs on load and then every minute, and the schedule and map label both pull from today's stop. For the builder, I'm starting from a default protein, sauce, and toppings set, with heat at two.

Still writing the builder logic: the protein, sauce, and toppings selections feed a render function that rebuilds the taco art, name, and description, and the price adds up each chosen topping. The heat slider maps its zero-to-three value to a label, and I'm weighing whether a higher heat level should also make the sauce drizzle look more intense.

Still writing the hero art: a glowing taco filled with kimchi, sesame, and cilantro toppings. I'm making the preview glow respond to the heat slider, so it shifts from a calm dark tone toward a red radial gradient as the heat rises.

Still writing the taco art helper: it builds the SVG from a filling color, a sauce color, and a list of topping IDs, with the egg drawn first and the other toppings placed on spots below it.

Still writing the taco art helper: I'm placing the toppings on a set of spots that sit just inside the filling below the egg, so they don't spill out of the shell.

Still writing the taco art: I'm placing the toppings on spots low in the filling, with the egg sitting at the top center so the layers stack cleanly, and I'm sketching a sauce drizzle that runs across the shell.

Still writing the taco SVG: a dark ellipse under the shell for a shadow, then the shell path.

Still writing the taco SVG: the shell's base layer, a highlight stroke, the filling, and the sauce drizzle, followed by the egg and toppings.

Still writing the taco SVG: checking that the shell's flat bottom and curved top leave an even ring of crust around the filling.

Still working out where the drizzle lands: I'm checking whether its curve at x around 104 stays inside the filling region, which means working out the filling's top edge there from its quadratic curve.

Still writing the taco SVG: the egg goes in as an ellipse with a yolk, sitting at the top center so it peeks above the filling.

Still writing the taco SVG: the egg sits at the top center and the toppings are small dots, leaves, and specks, each rotated by an index-based angle. Next I'm setting up the heat dots helper and starting the menu item list.

Still writing the menu data: the Seoul Bulgogi entry gets its description, a price, zero heat, a crowd-favorite tag, and a peach card background.

Still writing the menu data: the Yangnyeom Crunch entry with its description, a price, heat level two, a crispy tag, and a pale yellow background, followed by the Tofu Tofu entry.

Still writing the side items: Kimchi Fries, Pork Mandu, and a Corn Cheese Tots entry whose description is cut off.

Still writing the drink entries: the Yuzu Soda, Roasted Barley Tea, and Sweet Rice Punch, each with a short description, a price, and a card background colour.

Still writing the card art: each side and drink gets a tilted sticker word on a coloured background, and I'm setting the card art height to 180px so the grid stays consistent.

Still writing the cart code: the drawer rows show each item's quantity controls and price, and I'm wiring the place-order button to clear the cart and show an order number.

Still writing the drawer code: the body holds a cart view and a hidden done view, with a footer that disappears once the order goes through.

Still writing the schedule: each entry has a day, a stop, and open and close hours, which the live status check reads to decide whether the truck is open right now.

Still writing the schedule: each day gets a stop with open and close hours, and I'm marking Monday as a prep day with no stop.

Now I'm wiring the live status check: it finds today's entry in the schedule, and if the truck is still before opening, it says it's opening later today at that stop. If today's stop is already over or today is a prep day, it loops forward through the week to find the next stop and reports its day and opening time.

Still writing the live status: the hours-check updates both the pill and the "Right now" card, which will show the stop name and its times.

Still writing the live status: the schedule lookup now returns a state, a stop name, a title for the hero pill, and a meta line for the "Right now" card.

Still writing the live status: the status text is the title, and the "Right now" card gets the stop name and its meta line, which covers open, opening soon, or closed with the next stop.

Still writing the schedule rendering and the bulb lights: I'm drawing twelve bulbs along the top of the truck, spaced evenly and each with its own animation delay.

Still writing the SVG truck: I'm placing twelve bulbs along the top edge, just below the roofline and clear of the sign text, so they read as a marquee above "KIMCHI LOCO."

Still writing the truck SVG: the body's rounded rectangle goes in with a gradient fill and an amber outline, and I'm placing the sign and the window and awning stripes.

Still writing the truck's awning stripes, alternating amber and cream across the window band.

Still writing the truck's awning shadow and the window, with a warm glow over it and a small "OPEN" sign hanging inside.

Still writing the truck's sign window: a dark interior with a warm glow over it, and a small amber "OPEN" sign hanging inside.

Still writing the truck SVG: the menu board goes on the right side of the body, with a "MENU" header and the first few price lines.

Still writing the truck's menu board and cab: I'm adding a cab block to the right with a windshield.

Still writing the truck SVG: the cab's windshield and headlight are going in, and I'm adding a bumper along the bottom of the front.

Still writing the truck SVG: the wheel arches go in as dark circles behind each wheel, with the front wheel tucked under the body.

Still writing the page's hero section: I'm placing the floating taco absolutely, adding some sparkle stars for energy, and setting the truck artwork's container to a centered flex layout that caps at 600px wide. I'm also planning a "Kimchi Loco" wordmark in the footer before writing out the final HTML.

Now I'm writing the CSS, starting with the root colour variables for the ink, cream, kimchi red, and saffron.

Still writing the stylesheet: the root colour variables and font stacks are set, and I'm now resetting box sizing and the body margins.

Still writing the stylesheet: the body rules and the wrapper, kicker, and section heading styles are going in.

Still writing the top header bar: it's sticky, dark, slightly translucent, and holds the brand mark.

Still writing the header styles: the brand mark is a small taco at about 44px wide, and the nav links get a saffron hover.

Still writing the header styles: the cart button is a saffron pill with a small dark count badge that bumps when an item is added, and I'm starting on the hero section.

Still writing the hero layout: it's a two-column grid with a dark background, a soft orange glow, and a faint dot pattern, all centred vertically.

Still writing the hero styles: the grid is two columns on a dark background, and I'm sizing it to fit the viewport with padding at the top and bottom.

Still writing the hero styles: I'm giving the status pill its bottom margin, then the headline with its gradient-clipped accent, the lede in muted cream, and a row of buttons.

Still writing the stylesheet: the truck's drive-in and bobbing animations are set up, with the wheels spinning on their own rotation.

Still writing the stylesheet: the truck's spin and puff animations are going in, and the puff needs a fill-box transform origin so it scales from its own centre rather than the SVG origin. Then the bulb twinkle is set up with its own colour and timing.

Still writing the stylesheet: the sign text gets its display font, cream fill, and letter spacing, and the floating taco is positioned at the top left of the hero, rotated and given a soft drop shadow with a gentle float animation.

Still writing the stylesheet: the ticker's saffron band and marquee track are going in, with each label set in the display font and a kimchi-red separator between them.

Still writing the ticker's marquee: the labels get duplicated so the loop lines up, and I'm moving on to the menu's tab styles.

Still writing the menu tab styles and the card grid, with the cards set to lift slightly on hover.

Still writing the card styles: the art area is a centred grid with a tilted label, and I'm adding the card body and the meta row under the title.

Still writing the card footer and the price styles.

Still writing the card styles: the add button is a dark pill that turns chilli red on hover and presses in slightly when clicked.

Still writing the stylesheet: the builder's two-column grid and heading sizes are going in, along with the fieldset and legend styles for the option groups.

Still writing the stylesheet: the range slider and its output readout are going in, and the preview panel gets its sticky position and radial glow tied to a custom property.

Still writing the stylesheet: the find section is set up as a two-column grid, and the "now" card gets a dark background with its heading sizing.

Still writing the schedule styles: the list rows get a three-column grid for the day, the hours, and the status, with a divider line between each.

Still writing the schedule and map styles: the closed days are faded, and the map panel sits on the right with rounded corners, with the schedule and the "now" card on the left.

Still writing the stylesheet: the pulse ring around the map pin is set to scale out and fade, and I'm starting the catering section with its deep red gradient background and a two-column layout.

Still writing the form and footer styles.

Still writing the mobile bar styles: it's fixed to the bottom of the screen, hidden by default, and saffron with a dark label.

Still writing the drawer styles: the cart panel slides in from the right over a dimmed scrim, and it's hidden with pointer events off until it's opened.

Still writing the drawer styles: the panel's header, close button, and scrollable body are going in, and I'm starting the cart line-item rows.

Still writing the drawer styles: the cart line rows get their name and price layout, and the quantity buttons are going in.

Still writing the stylesheet: the cart panel's footer, the summary total row, and the full-width checkout button are going in, plus the thank-you state and the toast that slides up from the bottom.

Still writing the stylesheet: the toast is set to slide up into view, and I'm adding a media query that lifts it above the mobile bar. Then I'm setting up reduced-motion handling and the responsive breakpoints for the hero, builder, find, and catering grids, plus the footer.

Still writing the stylesheet's breakpoints: at 820px the nav links are hidden, and at 600px the sections tighten up, the form and footer grids collapse to one column, the schedule rows get a narrower day column, and the float taco and card art shrink.

Still writing the JavaScript: I'm setting up the SVG namespace, the query helpers, and a money formatter, then a CONFIG block with the business details like phone, email, Instagram, and address for the footer to use.

Still writing the JavaScript: I'm setting up the taco SVG generator with its spot positions, and the business details in the CONFIG block will feed the footer's phone, email, and Instagram.

Still writing the JavaScript: I'm building the taco SVG generator, starting with the egg check and the topping spots.

Still writing the taco SVG generator: the egg is an ellipse with a yolk circle and a small highlight, and the other toppings are placed across the spots, rotated by index.

Still writing the taco SVG generator: the toppings are drawn as leaves, specks, or dots, each placed on a spot and rotated by its index.

Still writing the taco SVG generator: the toppings are drawn as leaves, specks, or dots, and I'm now building the SVG markup with the tortilla shell.

Still writing the taco SVG markup: the sauce drizzle is going on top of the filling, with the egg, toppings, and a warm rim line added last.

Checking the taco drawing code now: the drizzle path uses smooth quadratic commands, and the sauce should read clearly over the filling. The egg sits above the drizzle, so the drizzle goes underneath it. I also need to avoid shadowing by naming the topping lookup differently from the map variable.

Still writing the topping list: each entry gets an id, display name, color, a shape kind, and a price, with the fried egg priced higher than the rest.

Now I'm finishing the topping chips: each gets a colored swatch and a label, and the egg's swatch is a pale cream with a yellow center. Next I need to decide what the default build starts with.

Still writing the card markup: each menu card gets its art, heat meter, and tags, with the art colored by a background custom property.

Still writing the card markup: the card body gets the name, description, heat meter and tags, and the footer holds the price and an add button.

Still writing the menu cards: each taco gets a heat meter with the pork set to the top level, and the filter tabs will show the matching cards.

Still writing the cart code, the schedule, and the map label, plus the catering form and the hero status pill.

Still wiring up the JavaScript: the ticker is duplicated as static content, and I'm attaching listeners for the cart buttons, the close button and scrim, placing the order, and the Escape key. Builder items will get a deterministic id built from the choices, so identical builds merge in the cart, and the heat level goes into both the id and the note.

Still wiring up the builder: I'm writing the chip rendering for protein, sauce, and toppings, with each chip marked by its group and id and a swatch in its color.

Still wiring up the builder clicks: the chip container handles protein, sauce, and topping picks, with toppings toggling on and off.

Still wiring up the builder clicks: the toggle handler adds or removes a topping from the set, then re-renders the chips and the preview.

Still writing the builder preview: the preview name, description, and price are being filled in from the chosen protein, sauce, toppings, and heat.

Still wiring up the builder: the Add button will create a deterministic id from the protein, sauce, heat, and sorted toppings, so identical builds merge in the cart. I'm also having the preview art replay a short pop animation on each re-render.

Still writing the status logic: I'm working out whether the stand is open now, opening later today, or closed, and then looking for the next day that has service.

Still writing the status logic: the code is finding the next scheduled stop after today by looping through the coming days, and the closed-state title depends on whether there was a stop today.

Still writing the status logic: the code is wiring up the status pill and the live title and meta text, with the closed-state copy depending on whether today had a stop.

Still writing the status logic: I'm settling on the card titles, with the open, opening-soon, and closed states each getting their own wording.

Still wiring up the status card: the map pin will show the current stop when the truck is open or about to open, and the next stop's name when it's closed.

Still wiring up the status logic: the schedule view is being rendered from the weekly list, with each day showing its stop or a prep-day note, and today's row marked.

Still writing the schedule rendering: the day labels get a "today" marker, and each row shows the time window or "Closed" for prep days.

Still wiring up the schedule and form: each day row gets a small "Today" label under the day name, and the catering form swaps to a confirmation message on submit.

Still wiring up the order button: it does nothing when the cart is empty, otherwise it picks a random order number, clears the cart, hides the cart and checkout area, and shows the done view with that number.

Still wiring up the drawer: the render function now sums up the cart count and total, updates the header badge and mobile total, and fills the subtotal and item list.

Still wiring up the drawer: each cart line gets its name, an optional note, the line total, and minus and plus buttons keyed by the item's id.

Still writing the cart drawer: the line items get their quantity buttons wired up through event delegation, so the plus and minus clicks update the quantity and remove the item at zero.

Still wiring up the cart: the line bump animation and the mobile bar totals are next, plus a check that the sticky preview works inside the build grid.

I'm checking the hero animation timing: the truck drive wraps up around 1.2 seconds, which should keep the opening screen lively without feeling slow. Next I'm thinking about what would make visitors want to come by, like punchy copy and a stamp-card idea offering a free taco after ten, and I'll decide where a loyalty section fits, maybe near the find-us area or the catering block.

Next I'm weighing a "Loco Card" loyalty idea: ten stamp slots that visitors can click to fill in, with the tenth taco free. I'm leaning toward placing it in the Find section as a compact card, though it adds some length and a bit more to test.

I'm putting a Loco Card under the schedule in the Find section, a stamp strip where each tap fills a slot. Ten stamps, and the tenth taco is free, so I'll show a little celebration message when all ten are filled.

I'm drafting the copy now: a hero lede about bulgogi, double-fried chicken, and house-fermented kimchi served from a truck that keeps moving. The facts row will cover in-house kimchi, veg and gluten-free options, and catering for 20 to 500 people. I'm also planning a scrolling ticker of the signature dishes.

Now I'm drafting the copy for the menu, builder, find, and catering sections, aiming for short punchy lines about small tacos and big flavor, with a truck-location theme.

I'm writing out the catering section's copy now: the pitch about office lunches and parties, a short list of service options like drop-off or on-site serving, vegetarian and gluten-free trays, the guest range, and a quote turnaround. I'm also planning a footer line that calls the brand Korean tacos on wheels.

Now I'm looking at the footer: a short tagline, a few columns for visiting, contact, and social links, and a copyright line whose year gets filled in by the script.

Still writing the hero markup: the status pill, headline, lede, call-to-action buttons, and facts list go into the copy column, with the truck art and floating taco in the right column.

Still writing the markup: the hero copy and art go in place, and the sections below get their headings, tabs, and find-us layout next.

Still writing the drawer markup: the cart view holds the line items, and a done view shows the order number, with the panel footer just starting.

Still writing the drawer markup: the footer gets a subtotal row, a disabled place-order button, and a pickup note, and the done view is hidden until an order goes through.

Still writing the drawer's CSS: the hidden done view gets forced to display none, and the closed drawer relies on pointer-events so the scrim stays inert until it opens.

Still writing the Loco Card markup: a title, a stamp strip generated by the script, and a short status line underneath.

Still writing the Loco Card styles: each stamp is a 40px circle with a dashed border, and once tapped it fills in saffron with a solid ink border and a slight tilt.

Still writing the drawer's JavaScript: the open and close helpers toggle the drawer's open state and aria-hidden, and closing resets the done view after a short delay.

Still wiring up the cart: the add handler bumps the count and shows a toast, and the menu's add buttons feed their item into it.

Still wiring up the builder: I'm adding a buildState helper that looks up the chosen protein and sauce, gathers the picked toppings, and works out the total price and topping names, so the render and add handlers can share one source of truth.

Still wiring up the builder: a buildState helper gathers the chosen protein, sauce, toppings and heat level, then works out the total price and topping names, and the add button turns that into a cart line.

Still writing the builder's price and copy: the line total multiplies by quantity, and the description falls back to "no toppings" when none are picked.

Still writing the stylesheet: the steam puffs fade in and float upward on a loop, and I'm checking that the floating taco and the truck's bobbing wrapper animate without clashing.

Still working out the steam puffs: they rise from the chimney and fade, and I'm checking they won't get clipped by the hero's edge, so I'm nudging the truck SVG up a bit to leave room.

Still working on the truck's wheel and drive styles: the spin animation needs a center origin, and the drive group carries the wheels along with it.

Writing SVG truck markup...

Still writing the truck's SVG body: the drive group holds the steam puffs, chimney, and main body with its gradient, and the sign goes across the front.

Still writing the SVG window and its open sign.

Still writing the truck's SVG window and the open sign inside it.

Still writing the SVG menu board: the box sits to the right of the window, and I'm placing the MENU title and the Bulgogi, Dwaeji, and Crunch price lines inside it.

Still working on the menu board: I'm setting its box to sit on the right of the counter, with the MENU title and four price lines spaced down the chalk surface.

Still writing the truck's cab: the body is a red rounded box with a dark window and a little door seam, and a yellow headlight near the bottom.

Still writing the truck's SVG wheels: the tire and rim circles sit at the two axles, and the spokes spin on their own group.

Still writing the truck's wheels: the spokes spin around their hub, and I'm mirroring the same wheel setup on the rear axle.

Still wiring up the truck's SVG: I'm moving the bumper so the wheel arches sit over it cleanly, and the bulbs get generated by the script into the drive group.

Still writing the CSS for the truck's sign and setting the SVG to overflow visibly.

Still tuning the hero headline: at 1280px it should sit at around 84px, and "Seoul on a tortilla." may break onto two lines or stay as one, depending on how the font renders.

Finishing the page's styles and the closing HTML.

Still writing the HTML head, with the title, description, and inline styles, then the body and script.

Still writing the menu data: the taco entries carry their names, prices, heat levels, and colors, and I'm on the Dwaeji Fire spec now.

Still writing the menu data: the taco entries are filled in with their fillings, sauces, and toppings, and I'm moving on to the sides.

Still writing the menu data: the side dishes are being filled in, with Kimchi Fries, Pork Mandu, and Corn Cheese Tots each carrying a price and a background color.

Still writing the menu data: the drink entries carry their names, prices, and background colors, and I'm on the Sweet Rice Punch description now.

Still writing the menu card markup, a card-art block with a sticker-style word on each item.

Still writing the menu cards: each item gets a colored art block with a sticker-style word on it, and I'm setting up the tab filter for All, Tacos, Sides, and Drinks so the grid re-renders when a tab is picked.

Still wiring up the stamp grid: each stamp button toggles its pressed state, and I'm counting how many are pressed.

Still writing the stamp click handler: it re-counts the pressed stamps and updates the message, which reads as a free taco unlocked at ten and a countdown before that.

Now I'm wrapping up the form and the page's closing details, with the catering fields for name, email, date, guest count, and notes.

Still tidying the layout details: the tab filter and menu grid should wrap cleanly on a 375px screen, so I'm checking that the grid's minimum column width still fits.

Still working on the schedule's list layout: at 375px the three-column grid of time, label, and price has to fit, so I'm checking whether the middle column keeps enough width.

Now I'm reworking the header to fit a 375px screen, tightening the brand text to 17px on small screens so the logo and cart button still fit side by side.

Still writing the page's CSS: the variables for ink, cream, kimchi red, and saffron are set, and I'm working through the stylesheet rules now.

Still writing the CSS variables: ink, cream, kimchi red, saffron, and mint, with the display and body font stacks.

Still checking the JavaScript: I'm confirming the hero and bulb elements exist before the script touches them, and that the build controls are wrapped in their container.

Still wiring up the page's event handlers: the drawer closes from any element tagged for it, and the cart button and mobile bar both open it.

Still wiring up the click handler: the cart line buttons bump a quantity up or remove the item when it drops to zero, and then the cart re-renders.

Still writing the pill's CSS: the dot takes a saffron color by default, with a pulsing ring, and I'm setting the open, soon, and closed states to change its color.

Still writing the map: I'm laying out the city blocks, a park in the upper left, and a river curving along the bottom of the SVG.

Still writing the map SVG: the road strokes and the river path are going in now.

Still writing the map SVG: the road lines and a pin sitting at the main intersection.

Still writing the map's SVG: the label box sits beside the pin, with a text line reading "5th & Maple".

Still writing the map's labels: the label box sits up and to the left of the pin, and I'm checking the street names so the text fits inside the viewBox without clipping.

Still writing the map labels and the Find section: the street names sit near the roads, and the "now" card gets a live-location kicker. Next comes the schedule list and the location card.

Next I'm writing out the final file, starting with the hero's fact list: three short lines on in-house kimchi, veg and gluten-free options, and catering size. Its styling gets a little saffron star before each item, with the spacing set so the list wraps cleanly.

Still writing the ticker markup, with two identical groups of menu highlights, each item separated by a small star, and I'm setting up the marquee CSS so the track scrolls smoothly.

Still writing the stylesheet: the reset rules and base body styles are going in, with the cream background and ink text set from the variables.

Still writing the stylesheet: the hero's background gradients are going in now, with the cream and ink variables driving the rest of the page's colors.

Still writing the hero's stylesheet: the pill and headline get their sizing and a saffron gradient on the emphasized words, and I'm moving on to the lede's font size.

Still writing the hero's button styles: the primary and ghost buttons get their padding, rounded shape, and hover lift, with the primary one in the red tone.

Still writing the hero's CSS: the float-taco sits over the truck's top-left corner, and I'm adding the bob and float animations for the art.

I'm placing the floating taco at the top-right of the hero art, above the cab, since the upper area there is mostly empty apart from the chimney in the middle.

Still writing the stylesheet: the hero's floating taco is placed at the top-right of the art, above the cab where the space is mostly open.

Now I'm building the taco builder markup, with a left column of four option groups: protein, sauce, toppings, and heat.

Still writing the taco builder: I'm laying out the protein, sauce, toppings, and heat controls with the live preview card beside them.

Adding the JavaScript for the taco builder and the hero's inline SVG taco now.

Still writing the hero taco's inline SVG, wiring up the bulbs with staggered animation delays.

Still wiring up the footer: the phone, email, and Instagram links get filled in from the shared config, so they're easy to edit in one place.

Now I'm wiring up the footer: the phone, email, and Instagram links get filled from the shared config, so they can be edited in one place.

Still writing the card markup: each menu card gets its art, a heat indicator with three dots filled to match the level, and a tooltip naming the heat.

Still writing the sub-heading styles, with a slightly faded font size and opacity so it sits quietly under the headline.

Still writing the catering section markup, with a two-column grid for the copy and the order form.

Still writing the catering section: a short intro with the kicker and heading, a line about the service, and a list of four points covering drop-off or on-site service, veg and gluten-free trays, group sizes from 20 to 500, and a reply within one business day.

Now I'm writing the catering form's fields: name, email, event date, guest count, and a notes box for the venue and any dietary needs.

Still writing the catering form's styles: the form card gets a paper background, rounded corners, and padding, with the fields laid out as labeled grid items.

Still writing the footer: the brand block and a short tagline sit on the left, with the find-us note and the contact links filled from the config beside them, and I'm about to add the copyright line with the year.

Still writing the footer's links: the phone and email get filled from the config, and I'm adding the copyright line with the year.

Still writing the taco SVG: the egg gets its own little ellipse and yolk, and I'm mapping the remaining toppings onto spots around the shell, with leaves rotated so they don't all line up.

Still writing the taco SVG: the toppings get mapped onto spots around the shell, with the speckles drawn as small clusters and the rest as plain dots.

Still writing the taco SVG: the shell, filling, and sauce drizzle are going in, and I'm about to drop the egg and toppings in after them.

Still writing the taco SVG: the spot coordinates for the toppings are being set up, and the egg sits over the filling.

Still working out the taco's drizzle path, checking that the curve's control points land where I want them.

Still writing the taco SVG: the drizzle path's edge points are being checked against the filling, since the left end may sit a little over the shell.

Still writing the updateStatus function: it works out the day's hours, sets the open, soon, or closed state, and fills in the map label.

Still writing the status logic: when the truck is open or opening later today, it sets the title and the stop name, and otherwise it looks ahead a week for the next stop to fill in the map label.

I'm wiring the status logic so the hero pill and live card both follow the day's state, with the pill showing the stop name when open, and the card's heading falling back to the status line when there's no stop.

Still writing the status logic: the hero pill and the live card both follow the day's state, and the mapLabel gets set to the stop name or the next stop.