Food truck websiteOne-line
Mistral Large 4
by MistralReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 10 min 21 s
- Cost
- $0.110
- Output tokens
- 52,307
- Spent thinking
- 36,631 tokens
- Speed
- 84.4 tok/s
- Console errors
- 0
- First token after
- 1.7 s
- First visible text after
- 7 min 49 s
- Prompt tokens
- 375
- Code size
- 47.6 KB
- Finish reason
- stop
- Served by
- Mistral
- Model id
mistralai/mistral-large-4-0- Reasoning sent
model default- Max output
- 262,144 tokens
- Generated
- Nov 12, 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 · 832 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Kimchi Loco 🌶 Korean Tacos Food Truck</title>
<meta name="description" content="Kimchi Loco — Korean BBQ meets street tacos. 30-day house kimchi, 24-hour bulgogi, tortillas pressed to order. Find the truck.">
<script>document.documentElement.classList.add('js');</script>
<style>
:root{
--cream:#FFF6E9; --paper:#FFFCF4; --ink:#221A13; --red:#E8442E; --red-d:#B9301C;
--orange:#FF7A1A; --yellow:#FFC531; --green:#3F8F3A; --sky:#BFE3F0; --pink:#FFD9CF;
--disp:'Arial Black','Archivo Black','Helvetica Neue',Helvetica,Arial,sans-serif;
--body:system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{font-family:var(--body);background:var(--cream);color:var(--ink);line-height:1.55;overflow-x:hidden}
img,svg{display:block;max-width:100%}
button,input{font:inherit;color:inherit}
[id]{scroll-margin-top:92px}
::selection{background:var(--yellow);color:var(--ink)}
:focus-visible{outline:3px dashed var(--red);outline-offset:3px}
.container{width:min(1140px,92%);margin-inline:auto}
.section{padding:88px 0}
/* ---------- buttons / pills ---------- */
.btn{display:inline-flex;align-items:center;gap:8px;font-family:var(--disp);font-weight:900;text-transform:uppercase;
letter-spacing:.03em;font-size:.92rem;padding:14px 24px;border:3px solid var(--ink);border-radius:14px;
background:var(--paper);color:var(--ink);text-decoration:none;cursor:pointer;box-shadow:5px 5px 0 var(--ink);
transition:transform .15s,box-shadow .15s;white-space:nowrap}
.btn:hover{transform:translate(-2px,-2px);box-shadow:8px 8px 0 var(--ink)}
.btn:active{transform:translate(3px,3px);box-shadow:1px 1px 0 var(--ink)}
.btn-primary{background:var(--red);color:var(--cream)}
.btn-cream{background:var(--cream)}
.btn-outline-cream{background:transparent;color:var(--cream);border-color:var(--cream)}
.pill{font-weight:800;font-size:.85rem;text-transform:uppercase;letter-spacing:.05em;padding:9px 18px;border:3px solid var(--ink);
background:var(--paper);border-radius:999px;cursor:pointer;box-shadow:4px 4px 0 var(--ink);
transition:transform .12s,box-shadow .12s,background .12s}
.pill:hover{background:var(--yellow)}
.pill.active{background:var(--ink);color:var(--cream);transform:translate(2px,2px);box-shadow:2px 2px 0 var(--ink)}
/* ---------- nav ---------- */
.nav{position:sticky;top:0;z-index:90;background:var(--cream);border-bottom:3px solid var(--ink)}
.nav-inner{display:flex;align-items:center;gap:14px;height:72px}
.logo{display:flex;align-items:center;gap:10px;font-family:var(--disp);font-weight:900;font-size:1.2rem;
text-transform:uppercase;text-decoration:none;color:var(--ink);letter-spacing:-.01em}
.logo-badge{width:40px;height:40px;flex:0 0 auto;background:var(--red);border:3px solid var(--ink);border-radius:50%;
display:grid;place-items:center;box-shadow:3px 3px 0 var(--ink)}
.nav-links{display:flex;gap:4px;margin-left:auto}
.nav-links a{padding:8px 14px;border-radius:999px;text-decoration:none;color:var(--ink);font-weight:700;border:3px solid transparent}
.nav-links a:hover{border-color:var(--ink);background:var(--yellow)}
.cart-pill{display:inline-flex;align-items:center;gap:6px;font-weight:900;border:3px solid var(--ink);background:var(--paper);
border-radius:999px;padding:8px 15px;cursor:pointer;box-shadow:3px 3px 0 var(--ink);font-size:.9rem}
.cart-pill.bump{animation:bump .45s}
.nav-cta{padding:10px 18px;font-size:.8rem}
.burger{display:none;flex-direction:column;align-items:center;justify-content:center;gap:4px;width:44px;height:44px;
border:3px solid var(--ink);border-radius:12px;background:var(--yellow);box-shadow:3px 3px 0 var(--ink);cursor:pointer}
.burger span{display:block;width:20px;height:3px;background:var(--ink);border-radius:2px}
.mobile-panel{display:none;position:absolute;top:100%;left:0;right:0;background:var(--cream);border-bottom:3px solid var(--ink);padding:8px 4% 16px;flex-direction:column}
.nav.open .mobile-panel{display:flex}
.mobile-panel a{padding:13px 6px;font-weight:800;text-decoration:none;color:var(--ink);border-bottom:2px dashed rgba(34,26,19,.25);font-size:1.05rem}
.mobile-panel a:last-child{border-bottom:0}
/* ---------- hero ---------- */
.hero{padding:60px 0 84px;position:relative;overflow:hidden;
background-image:radial-gradient(#EBD9BF 1.6px,transparent 1.7px);background-size:26px 26px}
.hero-grid{display:grid;grid-template-columns:1.08fr .92fr;gap:48px;align-items:center}
.eyebrow{display:inline-block;background:var(--paper);border:3px solid var(--ink);border-radius:999px;padding:7px 16px;
font-weight:900;font-size:.74rem;letter-spacing:.14em;text-transform:uppercase;box-shadow:4px 4px 0 var(--ink)}
h1{font-family:var(--disp);font-weight:900;text-transform:uppercase;font-size:clamp(3.3rem,8.2vw,6.6rem);
line-height:.92;letter-spacing:-.015em;margin:18px 0 20px}
.loco{color:var(--red);position:relative;z-index:0;display:inline-block}
.loco::after{content:"";position:absolute;left:-.05em;right:-.05em;bottom:.05em;height:.16em;background:var(--yellow);z-index:-1;border-radius:4px}
.hero-sub{font-size:1.12rem;font-weight:600;max-width:520px}
.hero-cta{display:flex;gap:14px;flex-wrap:wrap;margin-top:26px}
.today-chip{display:inline-flex;align-items:center;gap:8px;margin-top:22px;background:var(--paper);border:3px solid var(--ink);
border-radius:999px;padding:9px 16px;font-weight:700;font-size:.88rem;box-shadow:4px 4px 0 var(--ink);max-width:100%;flex-wrap:wrap}
.today-chip b{color:var(--red)}
.stats{display:flex;gap:30px;flex-wrap:wrap;margin-top:30px;padding-top:22px;border-top:3px dashed rgba(34,26,19,.3)}
.stat b{font-family:var(--disp);font-size:1.5rem;display:block;line-height:1.1}
.stat span{font-size:.82rem;font-weight:700;opacity:.72}
.hero-visual{position:relative;display:grid;place-items:center;min-height:430px}
.halo{position:absolute;width:min(430px,86%);aspect-ratio:1;border-radius:50%;background:var(--yellow);border:3px solid var(--ink)}
.halo::after{content:"";position:absolute;inset:14px;border-radius:50%;border:3px dashed rgba(34,26,19,.35)}
.ring{position:absolute;width:min(505px,100%);aspect-ratio:1;border-radius:50%;border:3px dashed var(--red);opacity:.65;animation:spin 46s linear infinite}
.taco-wrap{position:relative;width:min(470px,94%);transition:transform .25s ease-out}
svg.taco{width:100%;height:auto;animation:bob 5.5s ease-in-out infinite;filter:drop-shadow(12px 14px 0 rgba(34,26,19,.16))}
.chip{position:absolute;z-index:2;background:var(--paper);border:3px solid var(--ink);border-radius:999px;padding:7px 14px;
font-weight:900;font-size:.74rem;letter-spacing:.09em;text-transform:uppercase;box-shadow:4px 4px 0 var(--ink);
animation:float 4.5s ease-in-out infinite;white-space:nowrap}
.chip.c1{top:2%;left:-1%;background:var(--red);color:var(--cream);--r:-7deg}
.chip.c2{top:12%;right:-2%;background:var(--yellow);--r:6deg;animation-delay:1.2s}
.chip.c3{bottom:17%;left:-3%;--r:5deg;animation-delay:.6s}
.chip.c4{bottom:3%;right:4%;background:var(--pink);--r:-5deg;animation-delay:1.8s}
/* ---------- marquee ---------- */
.tilt{overflow:hidden;padding:20px 0;margin:-4px 0}
.marquee{width:112%;margin-left:-6%;background:var(--red);border-block:3px solid var(--ink);transform:rotate(-1.4deg)}
.mq-track{display:flex;width:max-content;animation:mq 26s linear infinite}
.mq-group{display:flex}
.mq-group span{white-space:nowrap;font-family:var(--disp);font-weight:900;text-transform:uppercase;color:var(--cream);
font-size:1.05rem;letter-spacing:.06em;padding:13px 24px 13px 0}
/* ---------- section heads ---------- */
.sec-head{margin-bottom:34px}
h2{font-family:var(--disp);font-weight:900;text-transform:uppercase;font-size:clamp(2.1rem,4.6vw,3.4rem);line-height:1.02;margin-top:16px;letter-spacing:-.01em}
.sec-sub{margin-top:12px;font-weight:600;max-width:580px;font-size:1.02rem}
.hl{background:linear-gradient(transparent 60%,var(--yellow) 60%,var(--yellow) 96%,transparent 96%)}
/* ---------- menu ---------- */
.pills{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:28px}
.menu-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(255px,1fr));gap:22px}
.card{background:var(--paper);border:3px solid var(--ink);border-radius:18px;box-shadow:6px 6px 0 var(--ink);
padding:20px;display:flex;flex-direction:column;gap:8px;animation:pop .4s both;transition:transform .18s,box-shadow .18s}
.card:hover{transform:translate(-3px,-3px) rotate(-.6deg);box-shadow:9px 9px 0 var(--ink)}
.card-top{display:flex;justify-content:space-between;align-items:flex-start}
.food{width:70px;height:70px;display:grid;place-items:center;font-size:2.4rem;background:var(--yellow);
border:3px solid var(--ink);border-radius:50%;box-shadow:4px 4px 0 var(--ink);transform:rotate(-6deg)}
.price{font-family:var(--disp);font-weight:900;font-size:1.35rem;color:var(--red)}
.card h3{font-family:var(--disp);font-weight:900;text-transform:uppercase;font-size:1.05rem}
.card p{font-size:.9rem;font-weight:500;opacity:.85;flex:1}
.card-foot{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin-top:6px}
.spice{font-size:.85rem}
.spice em{font-style:normal;opacity:.55;font-weight:700;font-size:.78rem}
.tag{font-size:.6rem;font-weight:900;letter-spacing:.08em;padding:3px 8px;border:2px solid var(--ink);border-radius:6px;background:var(--yellow)}
.tag.vegan{background:#BFE3B0}.tag.new{background:var(--pink)}.tag.hot{background:var(--red);color:var(--cream)}.tag.sweet{background:#E4D6FF}
.add{margin-left:auto;font-weight:900;font-size:.78rem;padding:7px 13px;border:3px solid var(--ink);border-radius:999px;
background:var(--yellow);cursor:pointer;box-shadow:3px 3px 0 var(--ink);transition:transform .12s,box-shadow .12s,background .12s}
.add:hover{background:var(--red);color:var(--cream)}
.add:active{transform:translate(2px,2px);box-shadow:1px 1px 0 var(--ink)}
.menu-note{margin-top:24px;font-weight:700;font-size:.9rem;opacity:.8}
/* ---------- schedule (dark) ---------- */
.schedule{background:var(--ink);color:var(--cream)}
.eyebrow-dark{background:transparent;color:var(--cream);border-color:var(--cream);box-shadow:4px 4px 0 rgba(255,246,233,.25)}
.schedule .sec-sub{color:rgba(255,246,233,.75)}
.next-banner{display:inline-block;background:var(--yellow);color:var(--ink);border:3px solid var(--ink);
box-shadow:6px 6px 0 var(--red);padding:13px 20px;border-radius:14px;font-weight:800;margin-bottom:28px;
font-variant-numeric:tabular-nums;max-width:100%}
#schedGrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:18px}
.day-card{position:relative;background:var(--paper);color:var(--ink);border:3px solid var(--ink);border-radius:16px;
box-shadow:6px 6px 0 var(--red);padding:16px 14px;min-height:158px;display:flex;flex-direction:column;gap:3px}
.day-card.today{background:var(--red);color:var(--cream);box-shadow:6px 6px 0 var(--yellow)}
.day-card.rest{background:transparent;color:var(--cream);border-style:dashed;border-color:rgba(255,246,233,.45);box-shadow:none}
.day-badge{position:absolute;top:-13px;right:10px;background:var(--ink);color:var(--yellow);border:3px solid var(--ink);
font-size:.62rem;font-weight:900;letter-spacing:.1em;padding:4px 9px;border-radius:999px;animation:blink 1.6s infinite}
.day-top{display:flex;justify-content:space-between;align-items:center}
.day-name{font-family:var(--disp);font-weight:900;font-size:1.05rem}
.day-emoji{font-size:1.5rem}
.day-loc{font-weight:900;font-size:.95rem}
.day-sub{font-size:.82rem;opacity:.75;font-weight:600}
.day-time{font-size:.8rem;font-weight:800;margin-top:auto;padding-top:8px}
.today .day-sub,.today .day-time{opacity:.9}
/* ---------- story ---------- */
.story-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:52px;align-items:center}
.truck-frame{position:relative;background:#FFE7D2;border:3px solid var(--ink);border-radius:22px;box-shadow:8px 8px 0 var(--ink);padding:30px 18px 16px}
.sticker{position:absolute;top:-18px;left:26px;background:var(--red);color:var(--cream);border:3px solid var(--ink);
padding:7px 14px;font-weight:900;font-size:.74rem;letter-spacing:.12em;text-transform:uppercase;border-radius:10px;
transform:rotate(-3deg);box-shadow:4px 4px 0 var(--ink)}
.story-copy p{margin-top:14px;font-weight:500}
.checks{list-style:none;margin-top:24px;display:grid;gap:12px}
.checks li{display:flex;gap:12px;font-weight:700;align-items:flex-start}
.checks li::before{content:"✓";flex:0 0 auto;width:26px;height:26px;display:grid;place-items:center;background:var(--green);
color:#fff;border:3px solid var(--ink);border-radius:50%;font-weight:900;font-size:.8rem}
/* ---------- gallery ---------- */
.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:20px}
.tile{position:relative;border:3px solid var(--ink);border-radius:16px;overflow:hidden;box-shadow:6px 6px 0 var(--ink);
height:230px;display:grid;place-items:center;transition:transform .2s}
.tile:hover{transform:rotate(-1.5deg) scale(1.03)}
.tile.t1{background:linear-gradient(135deg,#FF8A3D,#E8442E)}
.tile.t2{background:linear-gradient(135deg,#FFC531,#FF7A1A)}
.tile.t3{background:linear-gradient(135deg,#58B368,#2F7D32)}
.tile.t4{background:linear-gradient(135deg,#8ED0F2,#4A90C2)}
.tile-emoji{font-size:4.2rem;filter:drop-shadow(4px 6px 0 rgba(34,26,19,.35))}
.tile figcaption{position:absolute;bottom:0;left:0;right:0;background:var(--paper);border-top:3px solid var(--ink);
padding:8px 12px;font-weight:800;font-size:.84rem}
/* ---------- reviews ---------- */
.quotes{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:22px}
.quote-card{background:var(--paper);border:3px solid var(--ink);border-radius:18px;box-shadow:6px 6px 0 var(--ink);
padding:24px;display:flex;flex-direction:column;gap:12px;transition:transform .18s,box-shadow .18s}
.quote-card:hover{transform:translate(-3px,-3px) rotate(.5deg);box-shadow:9px 9px 0 var(--ink)}
.stars{color:var(--red);letter-spacing:4px;font-size:1.05rem}
.quote-card p{font-weight:600;font-size:1rem;flex:1}
.quote-card .who{font-weight:800;font-size:.88rem}
.quote-card .who span{display:block;font-weight:600;opacity:.7;font-size:.78rem}
/* ---------- newsletter ---------- */
.drop{background:var(--yellow);border-block:3px solid var(--ink);padding:80px 0;text-align:center}
.drop .sec-sub{margin-inline:auto}
.drop-form{display:flex;gap:12px;justify-content:center;flex-wrap:wrap;margin-top:28px}
.drop-form input{font-weight:700;padding:14px 20px;border:3px solid var(--ink);border-radius:999px;background:var(--paper);
min-width:min(320px,80vw);box-shadow:5px 5px 0 var(--ink)}
.drop-form input:focus{outline:3px dashed var(--red);outline-offset:3px}
.drop-msg{margin-top:16px;font-weight:800;min-height:1.5em}
.drop-msg.err{color:var(--red-d)}
.drop-msg.ok{color:#2c6e27}
.shake{animation:shake .4s}
/* ---------- cta band ---------- */
.cta{background:var(--red);border-block:3px solid var(--ink);color:var(--cream);text-align:center;padding:78px 0}
.cta h2{font-size:clamp(2.6rem,6vw,4.6rem);text-shadow:5px 5px 0 var(--ink);margin:0 0 14px}
.cta p{font-weight:700;font-size:1.05rem}
.cta-btns{display:flex;gap:14px;justify-content:center;flex-wrap:wrap;margin-top:30px}
/* ---------- footer ---------- */
.footer{background:var(--ink);color:var(--cream);padding:64px 0 0}
.foot-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:36px}
.footer h4{font-family:var(--disp);font-size:.92rem;letter-spacing:.12em;text-transform:uppercase;margin-bottom:14px;color:var(--yellow)}
.footer ul{list-style:none;display:grid;gap:9px}
.footer a{color:var(--cream);text-decoration:none;font-weight:600}
.footer a:hover{color:var(--yellow)}
.footer p,.footer li{font-size:.92rem;opacity:.88}
.foot-brand{display:flex;align-items:center;gap:10px;font-family:var(--disp);font-weight:900;font-size:1.3rem;text-transform:uppercase;margin-bottom:12px}
.foot-bottom{margin-top:46px;border-top:2px solid rgba(255,246,233,.18);padding:18px 0;display:flex;
justify-content:space-between;gap:10px;flex-wrap:wrap;font-size:.82rem;opacity:.75}
/* ---------- toasts ---------- */
#toasts{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);z-index:200;display:flex;flex-direction:column;
align-items:center;gap:8px;pointer-events:none;width:max-content;max-width:92vw}
.toast{background:var(--ink);color:var(--cream);padding:11px 20px;border-radius:999px;font-weight:800;font-size:.9rem;
box-shadow:5px 5px 0 rgba(34,26,19,.3);animation:toastIn .25s ease both;transition:opacity .4s,transform .4s;text-align:center}
.toast.out{opacity:0;transform:translateY(10px)}
/* ---------- reveal ---------- */
html.js .reveal{opacity:0;transform:translateY(26px);transition:opacity .65s ease,transform .65s ease}
html.js .reveal.in{opacity:1;transform:none}
/* ---------- keyframes ---------- */
@keyframes spin{to{transform:rotate(360deg)}}
@keyframes bob{0%,100%{transform:translateY(0) rotate(-1deg)}50%{transform:translateY(-12px) rotate(1.5deg)}}
@keyframes float{0%,100%{transform:translateY(0) rotate(var(--r,0deg))}50%{transform:translateY(-10px) rotate(var(--r,0deg))}}
@keyframes mq{to{transform:translateX(-50%)}}
@keyframes pop{from{opacity:0;transform:translateY(14px) scale(.97)}to{opacity:1;transform:none}}
@keyframes bump{0%{transform:scale(1)}40%{transform:scale(1.25) rotate(-6deg)}100%{transform:scale(1)}}
@keyframes blink{0%,100%{opacity:1}50%{opacity:.5}}
@keyframes toastIn{from{opacity:0;transform:translateY(12px) scale(.95)}to{opacity:1;transform:none}}
@keyframes shake{0%,100%{transform:translateX(0)}25%{transform:translateX(-6px)}75%{transform:translateX(6px)}}
.steam path{animation:steamUp 2.8s ease-in-out infinite}
.steam .s2{animation-delay:.9s}
.steam .s3{animation-delay:1.8s}
@keyframes steamUp{0%{transform:translateY(8px);opacity:0}35%{opacity:.8}100%{transform:translateY(-16px);opacity:0}}
/* ---------- responsive ---------- */
@media (max-width:960px){
.hero-grid,.story-grid{grid-template-columns:1fr}
.hero-visual{min-height:360px;margin-top:8px}
.section{padding:70px 0}
}
@media (max-width:860px){
.nav-links,.nav-cta{display:none}
.burger{display:flex}
}
@media (max-width:560px){
.chip{font-size:.6rem;padding:5px 10px}
.chip.c2{right:0}.chip.c3{left:0}
.hero{padding-top:44px}
.stats{gap:20px}
}
@media (prefers-reduced-motion:reduce){
*{animation:none!important;transition:none!important}
html{scroll-behavior:auto}
html.js .reveal{opacity:1;transform:none}
}
</style>
</head>
<body>
<!-- ============ NAV ============ -->
<header class="nav" id="nav">
<div class="container nav-inner">
<a class="logo" href="#top" aria-label="Kimchi Loco home">
<span class="logo-badge" aria-hidden="true">
<svg viewBox="0 0 24 24" width="22" height="22"><path d="M3 16a9 9 0 0 1 18 0z" fill="#FFC531" stroke="#221A13" stroke-width="1.6"/><circle cx="8" cy="13.5" r="1.7" fill="#E8442E"/><circle cx="12" cy="12.3" r="1.7" fill="#3F8F3A"/><circle cx="16" cy="13.5" r="1.7" fill="#E8442E"/></svg>
</span>
Kimchi Loco
</a>
<nav class="nav-links" aria-label="Main">
<a href="#menu">Menu</a>
<a href="#truck">Find the truck</a>
<a href="#story">Story</a>
<a href="#reviews">Reviews</a>
<a href="#drop">Loco Drop</a>
</nav>
<button class="cart-pill" id="cartPill" aria-label="Your order">🧾 <span id="cartCount">0</span></button>
<a class="btn btn-primary nav-cta" href="#menu">Order ahead</a>
<button class="burger" id="burger" aria-label="Open menu"><span></span><span></span><span></span></button>
</div>
<div class="mobile-panel">
<a href="#menu">Menu</a>
<a href="#truck">Find the truck</a>
<a href="#story">Story</a>
<a href="#reviews">Reviews</a>
<a href="#drop">Loco Drop</a>
</div>
</header>
<main id="top">
<!-- ============ HERO ============ -->
<section class="hero">
<div class="container hero-grid">
<div>
<span class="eyebrow">Seoul ✕ Mexico City · Est. 2019</span>
<h1>Kimchi<br><span class="loco">Loco</span></h1>
<p class="hero-sub">Korean BBQ meets street tacos — 30-day house kimchi, 24-hour bulgogi and tortillas pressed to order. One truck. Zero chill.</p>
<div class="hero-cta">
<a class="btn btn-primary" href="#menu">See the menu</a>
<a class="btn" href="#truck">Find the truck</a>
</div>
<div class="today-chip" id="todayChip">📍 Loading today's stop…</div>
<div class="stats">
<div class="stat"><b>4.9★</b><span>2,300+ reviews</span></div>
<div class="stat"><b>30-day</b><span>house-fermented kimchi</span></div>
<div class="stat"><b>2019</b><span>grilling ever since</span></div>
</div>
</div>
<div class="hero-visual" id="heroVisual">
<div class="halo" aria-hidden="true"></div>
<div class="ring" aria-hidden="true"></div>
<div class="taco-wrap" id="tacoWrap">
<svg class="taco" viewBox="0 0 460 340" role="img" aria-label="A loaded Korean taco with kimchi, bulgogi and lettuce">
<defs>
<linearGradient id="shell" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#F8C766"/><stop offset="1" stop-color="#DE8A2B"/>
</linearGradient>
<linearGradient id="lettuce" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#8CCB5E"/><stop offset="1" stop-color="#5DA83C"/>
</linearGradient>
</defs>
<ellipse cx="230" cy="292" rx="205" ry="22" fill="#FFFDF6" stroke="#221A13" stroke-width="5"/>
<ellipse cx="230" cy="288" rx="165" ry="13" fill="#F3E4CE"/>
<ellipse cx="230" cy="280" rx="140" ry="10" fill="#E9D2B4"/>
<g class="steam" stroke="#E4CFAF" stroke-width="7" fill="none" stroke-linecap="round">
<path d="M175 84 q12 -16 0 -32 q-10 -14 2 -28"/>
<path class="s2" d="M232 72 q12 -16 0 -32 q-10 -14 2 -28"/>
<path class="s3" d="M288 86 q12 -16 0 -32 q-10 -14 2 -28"/>
</g>
<g stroke="#221A13" stroke-width="4">
<path d="M58 168 Q78 128 98 168 Q118 128 138 168 Q158 128 178 168 Q198 128 218 168 Q238 128 258 168 Q278 128 298 168 Q318 128 338 168 Q358 128 378 168 Q392 142 402 168 L402 180 L58 180 Z" fill="url(#lettuce)"/>
<circle cx="105" cy="142" r="17" fill="#8A4B22"/>
<circle cx="165" cy="130" r="15" fill="#6E3A18"/>
<circle cx="235" cy="138" r="18" fill="#8A4B22"/>
<circle cx="305" cy="128" r="15" fill="#6E3A18"/>
<circle cx="360" cy="144" r="16" fill="#8A4B22"/>
<rect x="128" y="112" width="34" height="26" rx="8" fill="#E8442E" transform="rotate(-12 145 125)"/>
<rect x="205" y="104" width="36" height="26" rx="8" fill="#F05A3A" transform="rotate(8 223 117)"/>
<rect x="282" y="108" width="32" height="24" rx="8" fill="#E8442E" transform="rotate(-8 298 120)"/>
<rect x="340" y="118" width="30" height="22" rx="8" fill="#F05A3A" transform="rotate(14 355 129)"/>
<rect x="70" y="120" width="30" height="24" rx="8" fill="#F05A3A" transform="rotate(10 85 132)"/>
<path d="M150 152 q12 -14 24 0" fill="none" stroke="#FFF6E9" stroke-width="5"/>
<path d="M255 154 q12 -14 24 0" fill="none" stroke="#FFF6E9" stroke-width="5"/>
<path d="M190 120 q8 -12 16 -2 q-10 4 -16 2Z" fill="#3F8F3A"/>
<path d="M320 142 q10 -10 16 0 q-10 5 -16 0Z" fill="#3F8F3A"/>
</g>
<path d="M34 172 Q230 372 426 172 Q230 268 34 172 Z" fill="url(#shell)" stroke="#221A13" stroke-width="6" stroke-linejoin="round"/>
<g stroke="#C77B22" stroke-width="5" fill="none" stroke-linecap="round">
<path d="M120 236 Q150 252 184 258"/>
<path d="M276 258 Q310 252 340 236"/>
<path d="M196 276 Q230 284 264 276"/>
</g>
<g fill="#FFE3A6" stroke="#221A13" stroke-width="2.5">
<ellipse cx="150" cy="246" rx="6" ry="3.5" transform="rotate(-18 150 246)"/>
<ellipse cx="205" cy="266" rx="6" ry="3.5" transform="rotate(10 205 266)"/>
<ellipse cx="262" cy="264" rx="6" ry="3.5" transform="rotate(-12 262 264)"/>
<ellipse cx="312" cy="246" rx="6" ry="3.5" transform="rotate(20 312 246)"/>
</g>
<g transform="translate(52 268)">
<circle r="24" fill="#BFE36B" stroke="#221A13" stroke-width="5"/>
<circle r="16" fill="#EAF7C8" stroke="#7CB342" stroke-width="3"/>
<path d="M0 -16 V16 M-14 -8 L14 8 M-14 8 L14 -8" stroke="#7CB342" stroke-width="3"/>
</g>
<g transform="translate(400 268) rotate(-28)">
<path d="M0 0 C14 2 24 -2 30 -12 C33 -17 28 -21 24 -17 C16 -8 8 -4 -2 -3 Z" fill="#E8442E" stroke="#221A13" stroke-width="4" stroke-linejoin="round"/>
<path d="M26 -16 q6 -6 12 -3" stroke="#3F8F3A" stroke-width="6" fill="none" stroke-linecap="round"/>
</g>
</svg>
</div>
<span class="chip c1">30-day kimchi</span>
<span class="chip c2">Gochujang glaze</span>
<span class="chip c3">Smoked over oak</span>
<span class="chip c4">Pressed to order</span>
</div>
</div>
</section>
<!-- ============ MARQUEE ============ -->
<div class="tilt" aria-hidden="true">
<div class="marquee">
<div class="mq-track">
<div class="mq-group">
<span>Kimchi Loco ✶ Korean BBQ tacos ✶ 30-day kimchi ✶ Seoul ✕ Mexico City ✶ Open late ✶</span>
<span>Kimchi Loco ✶ Korean BBQ tacos ✶ 30-day kimchi ✶ Seoul ✕ Mexico City ✶ Open late ✶</span>
<span>Kimchi Loco ✶ Korean BBQ tacos ✶ 30-day kimchi ✶ Seoul ✕ Mexico City ✶ Open late ✶</span>
</div>
<div class="mq-group">
<span>Kimchi Loco ✶ Korean BBQ tacos ✶ 30-day kimchi ✶ Seoul ✕ Mexico City ✶ Open late ✶</span>
<span>Kimchi Loco ✶ Korean BBQ tacos ✶ 30-day kimchi ✶ Seoul ✕ Mexico City ✶ Open late ✶</span>
<span>Kimchi Loco ✶ Korean BBQ tacos ✶ 30-day kimchi ✶ Seoul ✕ Mexico City ✶ Open late ✶</span>
</div>
</div>
</div>
</div>
<!-- ============ MENU ============ -->
<section class="section" id="menu">
<div class="container">
<div class="sec-head reveal">
<span class="eyebrow">The lineup</span>
<h2>Pick your <span class="hl">poison</span></h2>
<p class="sec-sub">Everything is cooked at the window, made to order. Spice levels are real — ask for "gringo mild" at your own risk.</p>
</div>
<div class="pills" id="pills">
<button class="pill active" data-f="all">All</button>
<button class="pill" data-f="tacos">Tacos</button>
<button class="pill" data-f="burritos">Burritos</button>
<button class="pill" data-f="sides">Sides</button>
<button class="pill" data-f="drinks">Drinks</button>
<button class="pill" data-f="sweet">Sweet</button>
</div>
<div class="menu-grid" id="menuGrid"></div>
<p class="menu-note">🌶 = heat level · Corn or flour tortillas · Everything gluten-free adaptable · Ask about today's secret menu</p>
</div>
</section>
<!-- ============ SCHEDULE ============ -->
<section class="section schedule" id="truck">
<div class="container">
<div class="sec-head reveal">
<span class="eyebrow eyebrow-dark">Find the truck</span>
<h2>Where's <span class="hl">La Loca</span> today?</h2>
<p class="sec-sub">One truck, seven stops a week. We post up, fire up the grill, and feed the line until it's gone.</p>
</div>
<div class="next-banner reveal"><span id="nsText">⏰ Checking the grill schedule…</span></div>
<div id="schedGrid"></div>
</div>
</section>
<!-- ============ STORY ============ -->
<section class="section" id="story">
<div class="container story-grid">
<div class="truck-frame reveal">
<span class="sticker">La Loca · our 1987 step van</span>
<svg viewBox="0 0 560 320" role="img" aria-label="The Kimchi Loco food truck, La Loca">
<defs><clipPath id="awnClip"><path d="M66 102 L254 102 L242 66 L78 66 Z"/></clipPath></defs>
<ellipse cx="280" cy="288" rx="245" ry="14" fill="#E8D5BC"/>
<line x1="24" y1="288" x2="536" y2="288" stroke="#221A13" stroke-width="5" stroke-linecap="round"/>
<rect x="40" y="70" width="380" height="160" rx="20" fill="#E8442E" stroke="#221A13" stroke-width="6"/>
<path d="M40 190 h380 v22 a20 20 0 0 1 -20 20 H60 a20 20 0 0 1 -20 -20 Z" fill="#FFC531" stroke="#221A13" stroke-width="6"/>
<rect x="80" y="102" width="160" height="76" rx="10" fill="#FFF6E9" stroke="#221A13" stroke-width="6"/>
<rect x="118" y="110" width="84" height="26" rx="6" fill="#221A13"/>
<text x="160" y="128" text-anchor="middle" font-size="13" font-weight="900" fill="#FFC531" letter-spacing="3" font-family="Arial, sans-serif">OPEN</text>
<path d="M96 164 q17 -22 34 0 Z" fill="#F8C766" stroke="#221A13" stroke-width="4"/>
<rect x="176" y="138" width="14" height="26" rx="4" fill="#BFE3F0" stroke="#221A13" stroke-width="4"/>
<line x1="181" y1="138" x2="187" y2="128" stroke="#E8442E" stroke-width="4" stroke-linecap="round"/>
<path d="M66 102 L254 102 L242 66 L78 66 Z" fill="#FFF6E9" stroke="#221A13" stroke-width="6" stroke-linejoin="round"/>
<g clip-path="url(#awnClip)">
<rect x="70" y="58" width="24" height="52" fill="#E8442E"/>
<rect x="118" y="58" width="24" height="52" fill="#E8442E"/>
<rect x="166" y="58" width="24" height="52" fill="#E8442E"/>
<rect x="214" y="58" width="24" height="52" fill="#E8442E"/>
</g>
<text x="330" y="142" text-anchor="middle" font-size="30" font-weight="900" fill="#FFF6E9" font-family="'Arial Black', Arial, sans-serif">KIMCHI</text>
<text x="330" y="174" text-anchor="middle" font-size="30" font-weight="900" fill="#FFC531" font-family="'Arial Black', Arial, sans-serif">LOCO</text>
<text x="330" y="204" text-anchor="middle" font-size="11" font-weight="900" fill="#221A13" letter-spacing="2" font-family="Arial, sans-serif">KOREAN TACOS</text>
<path d="M420 100 h58 q22 0 30 22 l12 44 q6 22 -18 22 h-82 Z" fill="#FFF6E9" stroke="#221A13" stroke-width="6" stroke-linejoin="round"/>
<path d="M436 116 h36 q14 0 19 14 l7 24 h-62 Z" fill="#BFE3F0" stroke="#221A13" stroke-width="5" stroke-linejoin="round"/>
<line x1="466" y1="122" x2="466" y2="184" stroke="#221A13" stroke-width="4"/>
<circle cx="510" cy="172" r="9" fill="#FFC531" stroke="#221A13" stroke-width="4"/>
<line x1="498" y1="198" x2="522" y2="198" stroke="#221A13" stroke-width="6" stroke-linecap="round"/>
<rect x="140" y="30" width="130" height="36" rx="8" fill="#FFC531" stroke="#221A13" stroke-width="5"/>
<text x="205" y="54" text-anchor="middle" font-size="17" font-weight="900" fill="#221A13" font-family="'Arial Black', Arial, sans-serif">HOT TACOS</text>
<rect x="155" y="64" width="8" height="8" fill="#221A13"/>
<rect x="247" y="64" width="8" height="8" fill="#221A13"/>
<circle cx="130" cy="232" r="30" fill="#221A13"/><circle cx="130" cy="232" r="12" fill="#FFF6E9"/>
<circle cx="470" cy="232" r="30" fill="#221A13"/><circle cx="470" cy="232" r="12" fill="#FFF6E9"/>
</svg>
</div>
<div class="story-copy reveal">
<span class="eyebrow">Our story</span>
<h2>One grill.<br>Two <span class="hl">homelands.</span></h2>
<p>Kimchi Loco started in 2019 when cousins Min-ji from Seoul and Diego from Mexico City parked one grill, one cooler of 30-day kimchi, and a line of hungry people around the block. The line never really left.</p>
<p>Everything is cooked at the window: bulgogi marinated overnight, tortillas pressed every morning, kimchi fermented in the back of the truck (yes, really). Seoul flavor, Mexican soul — no fusion clichés, just really good street food.</p>
<ul class="checks">
<li>Kimchi fermented 30 days, in-house</li>
<li>Bulgogi marinated 24 hours</li>
<li>Corn tortillas pressed every morning</li>
<li>Gochujang in literally everything</li>
</ul>
</div>
</div>
</section>
<!-- ============ GALLERY ============ -->
<section class="section" id="feed" style="padding-top:20px">
<div class="container">
<div class="sec-head reveal">
<span class="eyebrow">@kimchiloco</span>
<h2>Straight from the <span class="hl">feed</span></h2>
</div>
<div class="tiles">
<figure class="tile t1 reveal"><span class="tile-emoji">🌯</span><figcaption>Bulgogi burrito, mid-bite</figcaption></figure>
<figure class="tile t2 reveal"><span class="tile-emoji">🍟</span><figcaption>Seoul fries, extra kimchi mayo</figcaption></figure>
<figure class="tile t3 reveal"><span class="tile-emoji">🌶️</span><figcaption>Day-30 kimchi, perfectly funky</figcaption></figure>
<figure class="tile t4 reveal"><span class="tile-emoji">🎡</span><figcaption>Friday night market chaos</figcaption></figure>
</div>
</div>
</section>
<!-- ============ REVIEWS ============ -->
<section class="section" id="reviews" style="padding-top:30px">
<div class="container">
<div class="sec-head reveal">
<span class="eyebrow">Word on the street</span>
<h2>People are <span class="hl">obsessed</span></h2>
</div>
<div class="quotes">
<div class="quote-card reveal">
<div class="stars">★★★★★</div>
<p>"I drove 40 minutes in the rain for the Seoul Fire Chicken taco. I'd drive 80."</p>
<div class="who">Dana R.<span>Regular since day one</span></div>
</div>
<div class="quote-card reveal">
<div class="stars">★★★★★</div>
<p>"The kimchi quesadilla should be illegal. Crunchy, cheesy, funky — a perfect little disc of joy."</p>
<div class="who">Marcus T.<span>Food blogger</span></div>
</div>
<div class="quote-card reveal">
<div class="stars">★★★★★</div>
<p>"Best food truck in the city, no contest. And the horchata fixes whatever the gochujang broke."</p>
<div class="who">Priya S.<span>Sunday brunch loyalist</span></div>
</div>
</div>
</div>
</section>
<!-- ============ NEWSLETTER ============ -->
<section class="drop" id="drop">
<div class="container reveal">
<span class="eyebrow">No spam, just tacos</span>
<h2>Get the <span class="hl" style="background:linear-gradient(transparent 60%,var(--cream) 60%,var(--cream) 96%,transparent 96%)">Loco Drop</span></h2>
<p class="sec-sub" style="text-align:center">Secret menu items, truck locations and free-taco flash mobs — straight to your inbox, twice a month.</p>
<form class="drop-form" id="dropForm" novalidate>
<input type="email" id="dropEmail" placeholder="you@hungry.com" aria-label="Email address" autocomplete="email">
<button class="btn btn-primary" type="submit">Sign me up</button>
</form>
<p class="drop-msg" id="dropMsg" role="status"></p>
</div>
</section>
<!-- ============ CTA ============ -->
<section class="cta">
<div class="container reveal">
<h2>Hungry yet?</h2>
<p>Call ahead and skip the line — we'll have your order bagged in 10 minutes.</p>
<div class="cta-btns">
<a class="btn btn-cream" href="tel:+15550123456">📞 Call (555) 012-3456</a>
<a class="btn btn-outline-cream" href="#truck">See tonight's stop</a>
</div>
</div>
</section>
</main>
<!-- ============ FOOTER ============ -->
<footer class="footer">
<div class="container">
<div class="foot-grid">
<div>
<div class="foot-brand">
<span class="logo-badge" aria-hidden="true">
<svg viewBox="0 0 24 24" width="22" height="22"><path d="M3 16a9 9 0 0 1 18 0z" fill="#FFC531" stroke="#221A13" stroke-width="1.6"/><circle cx="8" cy="13.5" r="1.7" fill="#E8442E"/><circle cx="12" cy="12.3" r="1.7" fill="#3F8F3A"/><circle cx="16" cy="13.5" r="1.7" fill="#E8442E"/></svg>
</span>
Kimchi Loco
</div>
<p>Korean BBQ street tacos, fermented with love and served from a 1987 step van named La Loca.</p>
</div>
<div>
<h4>Truck</h4>
<ul>
<li><a href="#menu">Menu</a></li>
<li><a href="#truck">Weekly schedule</a></li>
<li><a href="#story">Our story</a></li>
<li><a href="#reviews">Reviews</a></li>
</ul>
</div>
<div>
<h4>Hours</h4>
<ul>
<li>Mon — rest & ferment day 🌙</li>
<li>Tue–Sun — check the schedule</li>
<li>Fri & Sat — till 11 PM</li>
</ul>
</div>
<div>
<h4>Say hi</h4>
<ul>
<li><a href="mailto:hello@kimchiloco.truck">hello@kimchiloco.truck</a></li>
<li><a href="tel:+15550123456">(555) 012-3456</a></li>
<li><a href="#top">@kimchiloco — everywhere</a></li>
</ul>
</div>
</div>
<div class="foot-bottom">
<span>© <span id="year">2025</span> Kimchi Loco Food Truck Co. All rights reserved.</span>
<span>Made with gochujang & love 🌶️</span>
</div>
</div>
</footer>
<div id="toasts" aria-live="polite"></div>
<script>
(function(){
"use strict";
var $ = function(s){ return document.querySelector(s); };
/* ---------- toast ---------- */
var toasts = $('#toasts');
function toast(t){
var d = document.createElement('div');
d.className = 'toast';
d.textContent = t;
toasts.appendChild(d);
setTimeout(function(){ d.classList.add('out'); }, 1900);
setTimeout(function(){ d.remove(); }, 2400);
}
/* ---------- menu ---------- */
var MENU = [
{name:"Kimchi Carnitas", cat:"tacos", price:4.50, emoji:"🌮", spice:2, tags:["BESTSELLER","hot"], desc:"Slow-braised pork shoulder, 30-day house kimchi, cilantro and lime crema on a charred corn tortilla."},
{name:"Seoul Fire Chicken", cat:"tacos", price:5.00, emoji:"🍗", spice:3, tags:["NEW","hot"], desc:"Double-fried chicken thigh glazed in gochujang-honey, pickled slaw, toasted sesame. Handle with care."},
{name:"Tofu Kimchi (Vegan)", cat:"tacos", price:4.25, emoji:"🥬", spice:1, tags:["VEGAN"], desc:"Crispy tofu, kimchi, vegan crema, sesame. Plants never tasted this loud."},
{name:"Bulgogi Burrito", cat:"burritos", price:9.50, emoji:"🌯", spice:2, tags:["BESTSELLER","hot"], desc:"24-hour marinated ribeye, rice, melty cheese and kimchi crema — wrapped and griddled shut."},
{name:"Seoul Fries", cat:"sides", price:6.00, emoji:"🍟", spice:1, tags:[], desc:"Crinkle fries loaded with bulgogi bits, cheese sauce, kimchi mayo and scallions."},
{name:"Kimchi Quesadilla", cat:"sides", price:7.50, emoji:"🧀", spice:2, tags:["hot"], desc:"Flour tortilla, three cheeses, kimchi, and gochujang ranch for dunking."},
{name:"Kimchi Mandu (6pc)", cat:"sides", price:7.00, emoji:"🥟", spice:1, tags:[], desc:"Hand-folded pork & kimchi dumplings with a soy-ginger dipping sauce."},
{name:"Horchata", cat:"drinks", price:3.50, emoji:"🥛", spice:0, tags:[], desc:"Cinnamon rice milk over ice. Cools the fire, keeps the flavor."},
{name:"Kimchi Lemonade", cat:"drinks", price:4.00, emoji:"🍋", spice:1, tags:["NEW"], desc:"Fresh lemon, sparkling water and a whisper of kimchi brine. Trust us on this one."},
{name:"Hotteok", cat:"sweet", price:5.00, emoji:"🍯", spice:0, tags:["SWEET"], desc:"Warm Korean sweet pancake with a molten brown-sugar, walnut and cinnamon center."}
];
var TAGCLASS = {VEGAN:"vegan", NEW:"new", BESTSELLER:"best", hot:"hot", SWEET:"sweet"};
var grid = $('#menuGrid');
function renderMenu(f){
var items = MENU.filter(function(m){ return f === 'all' || m.cat === f; });
grid.innerHTML = items.map(function(m, i){
return '<article class="card" style="animation-delay:' + (i*45) + 'ms">' +
'<div class="card-top"><span class="food">' + m.emoji + '</span><span class="price">$' + m.price.toFixed(2) + '</span></div>' +
'<h3>' + m.name + '</h3>' +
'<p>' + m.desc + '</p>' +
'<div class="card-foot">' +
'<span class="spice">' + (m.spice ? '🌶'.repeat(m.spice) : '<em>mild</em>') + '</span>' +
m.tags.map(function(t){ return '<span class="tag ' + (TAGCLASS[t]||'') + '">' + t + '</span>'; }).join('') +
'<button class="add" data-name="' + m.name + '">+ ADD</button>' +
'</div></article>';
}).join('');
}
renderMenu('all');
document.querySelectorAll('.pill').forEach(function(p){
p.addEventListener('click', function(){
document.querySelectorAll('.pill').forEach(function(x){ x.classList.remove('active'); });
p.classList.add('active');
renderMenu(p.dataset.f);
});
});
var cart = 0, cartPill = $('#cartPill'), cartCount = $('#cartCount');
grid.addEventListener('click', function(e){
var b = e.target.closest('.add');
if(!b) return;
cart++;
cartCount.textContent = cart;
cartPill.classList.remove('bump'); void cartPill.offsetWidth; cartPill.classList.add('bump');
toast('🌮 ' + b.dataset.name + ' added to your order');
});
cartPill.addEventListener('click', function(){
toast(cart ? '🧾 ' + cart + ' item' + (cart>1?'s':'') + ' — pay at the window!' : 'Your bag is empty — add something tasty!');
});
/* ---------- schedule ---------- */
var WEEK = [
{day:1, short:"MON", name:"Rest day", loc:"Fermenting in the kitchen", time:"—", emoji:"🌙", rest:true},
{day:2, short:"TUE", name:"Downtown", loc:"5th & Main Plaza", time:"11:30 AM – 2:00 PM", emoji:"🏙️", h:11, m:30, eh:14, em:0},
{day:3, short:"WED", name:"Brewery Row", loc:"Hop Yard Brewery", time:"5:00 PM – 10:00 PM", emoji:"🍺", h:17, m:0, eh:22, em:0},
{day:4, short:"THU", name:"City Hall", loc:"City Hall Plaza", time:"11:30 AM – 2:00 PM", emoji:"🏛️", h:11, m:30, eh:14, em:0},
{day:5, short:"FRI", name:"Night Market", loc:"Neon District", time:"5:00 PM – 11:00 PM", emoji:"🎡", h:17, m:0, eh:23, em:0},
{day:6, short:"SAT", name:"Farmers Market", loc:"Market St + Stadium Lot", time:"12:00 PM – 11:00 PM", emoji:"☀️", h:12, m:0, eh:23, em:0},
{day:0, short:"SUN", name:"Brunch Club", loc:"Riverside Park", time:"10:00 AM – 3:00 PM", emoji:"🌳", h:10, m:0, eh:15, em:0}
];
var DAYN = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
var schedGrid = $('#schedGrid');
function fmtT(d){
var h = d.getHours(), m = d.getMinutes(), ap = h >= 12 ? 'PM' : 'AM';
h = h % 12 || 12;
return h + ':' + String(m).padStart(2,'0') + ' ' + ap;
}
function renderSched(){
var now = new Date(), today = now.getDay();
schedGrid.innerHTML = WEEK.map(function(w){
var isT = w.day === today, live = false;
if(isT && !w.rest){
var st = new Date(now); st.setHours(w.h, w.m, 0, 0);
var en = new Date(now); en.setHours(w.eh, w.em, 0, 0);
live = now >= st && now <= en;
}
return '<div class="day-card' + (w.rest ? ' rest' : '') + (isT ? ' today' : '') + '">' +
(isT ? '<span class="day-badge">' + (live ? '● LIVE NOW' : 'TODAY') + '</span>' : '') +
'<div class="day-top"><span class="day-name">' + w.short + '</span><span class="day-emoji">' + w.emoji + '</span></div>' +
'<div class="day-loc">' + w.name + '</div>' +
'<div class="day-sub">' + w.loc + '</div>' +
'<div class="day-time">' + w.time + '</div>' +
'</div>';
}).join('');
}
renderSched();
function nextCand(){
var now = new Date(), c = [];
for(var off = 0; off < 8; off++){
for(var i = 0; i < WEEK.length; i++){
var s = WEEK[i];
if(s.rest) continue;
var st = new Date(now.getFullYear(), now.getMonth(), now.getDate() + off, s.h, s.m, 0);
if(st > now) c.push({s: s, st: st});
}
}
c.sort(function(a,b){ return a.st - b.st; });
return c[0];
}
var nsText = $('#nsText'), chip = $('#todayChip');
function tick(){
var now = new Date(), live = null, i, st, en;
for(i = 0; i < WEEK.length; i++){
var s = WEEK[i];
if(s.rest || s.day !== now.getDay()) continue;
st = new Date(now); st.setHours(s.h, s.m, 0, 0);
en = new Date(now); en.setHours(s.eh, s.em, 0, 0);
if(now >= st && now <= en){ live = {s: s, en: en}; break; }
}
if(live){
nsText.textContent = '🔴 LIVE NOW — ' + live.s.name.toUpperCase() + ' · ' + live.s.loc + ' · until ' + fmtT(live.en);
} else {
var c = nextCand();
if(c){
var diff = c.st - now;
var d = Math.floor(diff/864e5), h = Math.floor(diff/36e5)%24, m = Math.floor(diff/6e4)%60, sec = Math.floor(diff/1e3)%60;
var dur = d > 0 ? (d + 'd ' + h + 'h ' + m + 'm') : (h + 'h ' + m + 'm ' + sec + 's');
var when = (c.st.getDate() === now.getDate() && c.st.getMonth() === now.getMonth()) ? 'TODAY' : DAYN[c.st.getDay()].toUpperCase();
nsText.textContent = '⏰ NEXT STOP — ' + c.s.name.toUpperCase() + ' · ' + c.s.loc + ' · ' + when + ' ' + fmtT(c.st) + ' · in ' + dur;
}
}
if(live){
chip.innerHTML = '🔴 <b>LIVE NOW</b> at ' + live.s.loc + ' — until ' + fmtT(live.en);
} else {
var todays = WEEK.filter(function(w){ return w.day === now.getDay() && !w.rest; })
.sort(function(a,b){ return (a.h*60+a.m) - (b.h*60+b.m); });
var up = null;
for(i = 0; i < todays.length; i++){
st = new Date(now); st.setHours(todays[i].h, todays[i].m, 0, 0);
if(st > now){ up = todays[i]; break; }
}
if(up){
chip.innerHTML = '📍 <b>TODAY:</b> ' + up.name + ' · ' + up.loc + ' · ' + up.time;
} else {
var c2 = nextCand();
chip.innerHTML = '🌙 Rest day today — back <b>' + DAYN[c2.st.getDay()] + '</b> at ' + c2.s.name + ', ' + fmtT(c2.st);
}
}
}
tick();
setInterval(tick, 1000);
/* ---------- newsletter ---------- */
var form = $('#dropForm'), email = $('#dropEmail'), msg = $('#dropMsg');
form.addEventListener('submit', function(e){
e.preventDefault();
var v = email.value.trim();
if(!/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(v)){
msg.textContent = 'Hmm, that email looks undercooked — try again?';
msg.className = 'drop-msg err';
email.classList.add('shake');
setTimeout(function(){ email.classList.remove('shake'); }, 450);
email.focus();
return;
}
msg.textContent = "🌶 You're in! The next Loco Drop lands in " + v + "'s inbox soon.";
msg.className = 'drop-msg ok';
form.reset();
toast('Welcome to the Loco Drop 🌶');
});
/* ---------- burger ---------- */
var nav = $('#nav');
$('#burger').addEventListener('click', function(){ nav.classList.toggle('open'); });
document.querySelectorAll('.mobile-panel a').forEach(function(a){
a.addEventListener('click', function(){ nav.classList.remove('open'); });
});
/* ---------- reveal on scroll ---------- */
var io = new IntersectionObserver(function(entries){
entries.forEach(function(en){
if(en.isIntersecting){ en.target.classList.add('in'); io.unobserve(en.target); }
});
}, {threshold: .12});
document.querySelectorAll('.reveal').forEach(function(el){ io.observe(el); });
/* ---------- hero parallax ---------- */
var hv = $('#heroVisual'), tw = $('#tacoWrap');
if(hv && window.matchMedia('(pointer:fine)').matches){
hv.addEventListener('mousemove', function(e){
var r = hv.getBoundingClientRect();
var x = (e.clientX - r.left) / r.width - .5;
var y = (e.clientY - r.top) / r.height - .5;
tw.style.transform = 'rotate(' + (x*6) + 'deg) translate(' + (x*10) + 'px,' + (y*8) + 'px)';
});
hv.addEventListener('mouseleave', function(){ tw.style.transform = ''; });
}
/* ---------- footer year ---------- */
$('#year').textContent = new Date().getFullYear();
})();
</script>
</body>
</html>Reasoning trace (36,631 tokens)
The user wants a website for a Korean taco food truck called "Kimchi Loco". They want it to make people really want to come — appetizing, vibrant, with menu, location/hours, etc. I need to output exactly one fenced code block with a complete self-contained HTML file. No external files except allowed CDN URLs (I can use Google Fonts? The task says "except the CDN URLs explicitly allowed by the task" — the task doesn't explicitly allow any, so safest to use no external resources at all, or use system fonts. Actually Google Fonts is commonly allowed, but to be safe I'll use system font stacks with nice styling. Hmm, many similar tasks allow Google Fonts. The instruction says "No external files, images, fonts or network requests, except the CDN URLs explicitly allowed by the task." The task doesn't allow any CDN explicitly. So I should avoid external requests entirely. Use system fonts and CSS-drawn graphics / emoji / SVG inline.
I need:
- Looks right at 1280×800, adapts to 375px, no horizontal scrollbar.
- Something visible on first paint (screenshot ~3s after load, no interaction).
- Games requirement doesn't apply (not a game), but maybe add a small interactive element? Not required. But "Click or press a key to start" only applies if demo uses keyboard. I can add a fun interactive bit like a "build your taco" or a marquee, countdown to next location, etc. Keep it simple but rich.
Design concept: Kimchi Loco — Korean-Mexican fusion food truck. Bold colors: kimchi red/orange (#e63312 or similar), deep charcoal, cream, neon accents. Big typography, marquee ticker, hero with illustrated taco (SVG/CSS), menu with prices, "Find the truck" schedule by day, testimonials, Instagram-style gallery (CSS art), newsletter signup (no backend — just shows a toast), hours, location map-ish graphic.
Make it mouth-watering: big hero with huge headline "KIMCHI LOCO", tagline "Korean BBQ meets street tacos", CTA buttons "See the menu" / "Find the truck". Floating ingredients (emoji or SVG) with subtle animation. Sticky nav.
Sections:
1. Nav: logo "🌮 KIMCHI LOCO", links Menu, Truck Schedule, About, Order; CTA "Order ahead".
2. Hero: huge display text, sub copy, CTAs, a CSS/SVG taco illustration, badges (100% organic kimchi, etc.), marquee strip.
3. Marquee ticker: "SEOUL × MEXICO CITY • FERMENTED & FIRED • ..." repeating.
4. "The Lineup" menu — cards with emoji/SVG illustrations, names (Kimchi Carnitas Taco, Bulgogi Burrito, Seoul Fries, Kimchi Quesadilla, Korean Fried Chicken, Horchata, etc.), prices, spice level indicators (🌶).
5. "How it works" / about: 3 steps: Find the truck, Order, Eat.
6. Truck schedule: day-of-week cards with location + time (Mon–Sun), today highlighted via JS.
7. Gallery strip: CSS-art "photos" — gradient cards with emoji and labels.
8. Reviews: quote cards.
9. Newsletter / "Get the loco drop" — email input, on submit show success message (no backend, just JS).
10. Footer: hours, contact, socials (text), small print.
Interactivity:
- Smooth scroll nav.
- Today highlighted in schedule.
- Countdown "Next stop in Xh Ym" computed to next scheduled time — nice touch.
- Menu filter tabs (All / Tacos / Sides / Drinks) — clickable.
- Newsletter submit shows inline success.
- Maybe a "spice-o-meter" hover.
- Tilt effect on hero taco on mousemove (subtle).
- Marquee animation via CSS.
Everything must be visible within first seconds — hero is rich. Good.
No horizontal scrollbar: use overflow-x hidden on body, max-width containers.
Fonts: system stack. Use big heavy weights: font-family: "Arial Black", "Helvetica Neue", Arial... For display, could use "Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif" for that poster look. Body: system-ui.
Colors:
- Background cream: #FFF6E9 / #FFF3E0
- Ink: #1E1A17 (near-black warm)
- Kimchi red: #E8442E or #FF3B1F
- Chili orange: #FF7A00
- Green (kimchi): #3E7C3A / #7CB342
- Yellow: #FFC531
Use CSS variables.
SVG taco illustration: I can draw a taco with SVG inline — shell (semicircle), fillings (lettuce zigzag, meat blobs, kimchi red). Let me craft a decent SVG taco. Alternatively use big emoji 🌮 at large size — emojis render fine and look appetizing. Mix: big emoji with CSS drop-shadow, plus SVG garnish. Emoji at font-size 180px looks decent. But cross-platform emoji style varies; still fine in Chrome. I'll do an SVG taco for crispness plus floating emoji bits. Let me design an SVG taco:
viewBox 0 0 400 300. Shell: path semicircle-ish: M20,240 A180,180 0 0 1 380,240 ... Actually taco shell is like a half-pipe: an arc from left to right, with a flat bottom. Fill with gradient golden (#F2B04E to #D98A2B), stroke darker. Add sesame seeds (small ellipses). Fillings peeking above the arc: lettuce (green wavy path), kimchi (red chunks), meat (brown circles), cilantro. Salsa drizzle. That can look nice.
Let me write it carefully:
```svg
<svg viewBox="0 0 420 320">
<!-- fillings behind shell top edge -->
<g>
lettuce: path along top with zigzag, green
kimchi chunks: red rounded rects rotated
meat: brown circles
onion: white arcs
</g>
<!-- shell -->
<path d="M30 250 C30 120 120 60 210 60 C300 60 390 120 390 250 L390 250 Q210 290 30 250 Z" fill="url(#shell)"/>
...
</svg>
```
Hmm, taco shape: bottom is a curve (U shape), top is open with fillings. Simpler: draw shell as a crescent: outer arc big, inner arc smaller. Path: M20,240 A190,170 0 0 1 400,240 (outer top edge? no...). Let me think: taco standing: bottom curve down. The shell outline: start left-top (30,150), curve down to bottom (210,300), up to right-top (390,150). That's the outer silhouette: M30,150 Q210,330 390,150 — a U. Then the top edge is a line/arc between (30,150) and (390,150) but the top is open — shell thickness shown by inner curve: from (390,150) back along inner arc to (30,150): Q210,270 30,150? That would close shape giving crescent (thick bottom). Fillings sit above the line y=150 between x 30..390, drawn before shell so shell covers bottoms.
So:
- Fillings group: clip to region above shell top line; draw lettuce zigzag along y≈150, meat circles at y 120-150, kimchi red blobs, etc. They'll be partially covered by shell? Shell only covers below its top edge (the crescent region). Fillings drawn first, then shell path covers lower parts. Shell path: M30,150 Q210,340 390,150 L390,150 Q210,250 30,150 Z? Hmm need closed crescent: outer: M30,150 Q210,340 390,150 then inner back: Q210,240 30,150 Z. The area between outer curve and inner curve is the shell (thickness at bottom = 340-240=100 at center, tapering to 0 at ends). Fillings above y=150 line will show fully; where fillings dip below 150 near edges they get covered by shell. Good.
Add grill marks on shell: a few darker arcs following curvature. Sesame seeds: small light ellipses scattered on shell. Add a lime wedge and chili on side. Add steam lines animated (CSS) above.
Also "kimchi" red crinkle: use path with wavy top.
I'll craft it reasonably; it doesn't need to be photorealistic — playful flat illustration matches brand.
Alternatively simpler and reliably cute: giant emoji 🌮 with layered drop-shadows + floating ingredient emojis (🥬🌶️🧅🍋🧄) animated floating. Emoji at 160-200px in Chrome on Linux... In the sandbox, Chrome may render emoji as color (Noto Color Emoji usually installed on many Linux images, but not guaranteed). Risk: if no emoji font, shows tofu boxes. Safer to use SVG shapes for everything critical, emoji only as decorative garnish. I'll primarily use inline SVG icons (pepper, etc.) and CSS shapes. But menu items benefit from imagery — I can use small SVG illustrations per item or colored circles with initials. Let me create a set of small inline SVG icons: taco, burrito, fries, quesadilla, chicken, drink. Drawing 6 detailed SVGs is heavy but doable with simple shapes. Alternatively use emoji but with fallback... Can't detect easily. Hmm.
Actually, modern Chrome headless in these sandboxes typically has Noto Color Emoji installed (Google's own environment). Most similar tasks use emoji freely and they render. I'll use emoji for menu item icons but keep design strong with colors/typography so even monochrome fallback isn't broken (emoji fallback would be boxes though). Compromise: use emoji inside colored circles — if emoji fails, circle still shows letter? Could put a letter behind emoji? Overkill. I'll use emoji; widely renders in Chrome. Also add SVG hero taco as the centerpiece (guaranteed vector), so hero looks great regardless.
Let me plan layout details:
Nav (sticky, cream with border-bottom 3px ink, slight shadow): left logo: red circle badge with 🌮? Use SVG mini taco or text "KIMCHI LOCO" in display font with a red 🌶 or asterisk. Links: Menu, Schedule, Reviews, Find Us. Right: button "Order Ahead" (red bg, cream text, hard shadow offset — neo-brutalist style fits food truck). Mobile: hide links, show just CTA (simple; hamburger optional — maybe simple: hide links under 720px, keep CTA). Could add a details/summary mobile menu... keep simple: on small screens show compact nav with logo + CTA; links hidden. That's acceptable.
Hero: two-column grid (min 900px), left: eyebrow badge "SEOUL 🇰🇷 × MEXICO CITY 🇲🇽" (flags as emoji might fail... use text "SEOUL ✕ MEXICO CITY"), H1 huge: "KIMCHI LOCO" with "LOCO" in red outlined or highlighted; sub: "Korean BBQ meets street tacos..." CTAs: "See the menu" (red) and "Find today's truck" (outline). Under: stats row: "4.9★ (2,300+ reviews)" — star emoji; "100% house-fermented kimchi"; "Since 2019". Right: SVG taco in a blob/circle background with rotating dashed ring (CSS animation) + floating chips: "SPICY", "FERMENTED", "SMoky" tags absolutely positioned with float animation. Also steam SVG animated.
Background hero: cream with subtle repeating diagonal stripes or dot pattern via CSS gradient. Maybe big outlined text behind: "LOCO" watermark.
Marquee: red band, rotated slightly (-1deg), repeating text "KIMCHI LOCO ★ KOREAN BBQ TACOS ★ ..." CSS animation translating -50%.
Menu section: heading "THE LINEUP" + sub. Filter pills: All, Tacos, Burritos, Sides, Drinks, Sweet. Grid of cards (3 cols → 2 → 1). Card: cream/white bg, 3px ink border, hard shadow (6px 6px 0 ink), hover: translate(-2px,-2px) shadow grows. Top: emoji in colored circle + spice peppers 🌶 (1-3). Name, description, price big red. Tag chips: "BESTSELLER", "VEGAN", "NEW". Data in JS array, render cards, filter on click. 8 items:
Tacos:
1. Kimchi Carnitas — "Slow-braised pork, 30-day kimchi, cilantro, lime crema" $4.50, 🌶🌶, BESTSELLER, emoji 🌮
2. Bulgogi Burrito — actually that's burrito. Tacos:
2. Seoul Fire Chicken Taco — gochujang fried chicken, pickled slaw, $5.00 🌶🌶🌶 NEW
3. Tofu Kimchi Taco (vegan) — crispy tofu, kimchi, sesame $4.25 🌶 VEGAN
Burritos:
4. Bulgogi Burrito — marinated beef, rice, cheese, kimchi crema $9.50 🌶🌶
Sides:
5. Seoul Fries — kimchi mayo, bonito... maybe "loaded with bulgogi & cheese sauce" $6.00 🧀 emoji 🍟
6. Kimchi Quesadilla — $7.50 🌶 VEGAN-ish (cheese) emoji 🧀? use 🫓 (flatbread emoji may not exist everywhere) — use 🌯 for quesadilla? I'll assign: quesadilla 🧀, fries 🍟, dumplings 🥟.
7. Mandu (dumplings) 6pc — pork & kimchi dumplings, soy-ginger dip $7.00 🥟
Drinks:
8. Horchata — cinnamon rice milk $3.50 ☕? use 🥤
9. Yakult... "Soju Lemonade (21+)" maybe keep family friendly: "Kimchi Lemonade" $4.00 🍋
Sweet:
10. Churro with gochujang caramel? "Hotteok" — Korean sweet pancake $5.00 🍯
That's 10 items across categories: Tacos(3), Burritos(1), Sides(3: fries, quesadilla, mandu), Drinks(2), Sweet(1). Good.
Each card also small "add" button? Could do a mini cart counter: clicking "+" increments cart badge in nav with little animation — fun interactive, no backend. Cart count in nav "🛒 0". Clicking + on card increments with toast "Added Kimchi Carnitas". That's nice interactivity visible. Implement simple.
Schedule section: "FIND THE TRUCK" — 7 day cards (Mon–Sun) each with day, location, time. JS highlights today (new Date().getDay()). Also a "Next stop" countdown: compute next upcoming slot from a weekly schedule array with day index + start hour; countdown updates every second: "Next stop: Today 11:30 AM at ... in 2h 14m". If today's slot passed, go to next day. Implement schedule data:
- Mon: Rest day? Food trucks often rest Monday. "MON — Rest & ferment day 🌙" cute. But then countdown skips. Let's do: Mon rest; Tue–Sun locations:
- Tue: Downtown — 5th & Main, 11:30–14:00
- Wed: Brewery Row — Hop Yard, 17:00–22:00
- Thu: City Hall Plaza, 11:30–14:00
- Fri: Night Market — Neon District, 17:00–23:00
- Sat: Farmers Market + Stadium lot, 12:00–23:00
- Sun: Brunch Club — Riverside Park, 10:00–15:00
Countdown logic: slots array with day (0=Sun..6=Sat), hour, minute. Find next slot with (day,time) > now. Compute diff, display "in Xd Xh Xm Xs" ticking. Also mark "TODAY" badge on current day card and "LIVE NOW" if within window. Nice.
Schedule card design: horizontal scroll row on mobile? Grid 7 columns on desktop is tight; use grid auto-fit minmax(150px,1fr). Each card: day name big, location, time, small emoji per venue (🏢🍺🏛️🎡🌳☀️). Today card gets red bg.
Reviews: 3 quote cards with names, stars (★★★★★ text in red — use text stars "★★★★★" colored, not emoji, reliable). Quotes fun: "I drove 40 minutes. Worth every minute." etc.
Gallery/"@kimchiloco" strip: 4-5 gradient tiles with big emoji + caption, CSS hover scale. Emojis again... fine.
About/Story section: short: "Started in 2019 with one grill, one abuela recipe and a 30-day kimchi..." with 3 stat blocks. Maybe merge into a two-col with image-like SVG of truck! Draw a food truck SVG — that's a great centerpiece: a cute truck with "KIMCHI LOCO" on side, window, awning stripes, wheels. Doable: rounded rect body, cab, window, awning with scallops (striped), wheels circles, serving window with tiny taco. Place in About section or hero side? Hero has taco; About gets truck SVG.
Order/CTA section: big red band: "HUNGRY? Find us tonight." + button + phone number. Newsletter: "Get the LOCO DROP — secret menu items & truck locations first." email input + button; on submit validate contains @, show success message inline (replace form content). No storage.
Footer: dark ink bg, cream text: columns: logo + blurb, hours quick, contact (hello@kimchiloco.com, (555) 012-3456, @kimchiloco), small print "© 2025 Kimchi Loco Food Truck Co." + "Made with 🌶 in the city".
Extras:
- Smooth scroll: html {scroll-behavior:smooth} plus scroll-margin-top on sections for sticky nav.
- Reveal on scroll: IntersectionObserver adding .in class → fade/slide up. Keep subtle.
- Mousemove parallax on hero taco (rotate slight). Guard for touch.
- Toast component bottom for cart adds.
- Marquee duplicated content for seamless loop.
- Spice level as 🌶 repeated — emoji again; fallback: could use CSS chili? Use text "SPICY ●●●"? Emoji fine.
Accessibility-ish: buttons real buttons, alt-ish aria-labels.
Performance: all inline, fine.
No horizontal scrollbar: body{overflow-x:hidden}; marquee uses width max-content inside overflow hidden container; rotated marquee could overflow — wrap in overflow:hidden section with padding.
Responsive:
- ≤900px: hero single column, taco below text, smaller H1 via clamp.
- Use clamp() for font sizes: h1 clamp(3rem, 9vw, 7rem).
- Nav links hidden ≤760px.
- Menu grid: repeat(auto-fill,minmax(240px,1fr)) handles all widths.
- Schedule grid auto-fit minmax(150px,1fr).
Fonts: display: 'Arial Black', 'Archivo Black' fallback... Without webfont, use font-family: "Arial Black", "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing tight; for body: system-ui. Add font-weight 900 where possible. Maybe use 'Trebuchet MS' for body? system-ui fine. Actually to get a chunky poster look, "Arial Black" widely available; on Linux Chrome, Arial may map to Liberation Sans — "Arial Black" may not exist → falls to bold sans. Acceptable. Could also use SVG text? Overkill. Use font stack with weight 900; Liberation Sans has bold but not black — still bold. Fine.
Alternatively include Google Fonts CDN? Not allowed explicitly. Skip.
Let me now write the SVG taco carefully.
Hero taco SVG (viewBox 0 0 460 360):
Defs: linearGradient shellGrad (#F6C15B → #E08A2E), lettuceGrad, etc.
Composition:
- Steam: 3 wavy paths above, stroke cream/gray, opacity animated via CSS (class steam, keyframes rise: translateY + opacity).
- Fillings (drawn first, y around 90–170):
- Lettuce: wavy path across x=60..400 at y≈150: path with quadratic bumps, fill #7FBF4D, stroke darker green. e.g. M55,160 q20,-28 40,0 q20,-28 40,0 ... repeated. Then close down to y=170: L400,175 L55,175 Z. Actually just draw the zigzag strip: M55,165 Q75,130 95,165 Q115,130 135,165 ... up to 405,165 L405,180 L55,180 Z fill green.
- Kimchi chunks: red-orange rounded shapes: ellipses/rects rotated fill #E8442E with darker stroke, scattered at y 120-155, x 90..370.
- Meat: brown circles #7A4A21 with darker stroke, r 14-18 at y 130-160.
- Cilantro: small green leaf paths.
- Onion: white/purple arcs stroke.
- Shell: crescent: outer M30,170 Q230,360 430,170 → inner back Q230,268 30,170 Z. Wait inner curve should be above outer at center: outer bottom at y≈ (170+360)/2? Quadratic control at 360 gives curve bottom at (170+2*360... midpoint of quadratic = 0.25*P0 + 0.5*C + 0.25*P2 = y: 0.25*170+0.5*360+0.25*170 = 265. So outer bottom ≈265. Inner control 268 → inner bottom = 0.25*170+0.5*268+0.25*170 = 219. Shell thickness at center = 265-219 = 46. Good. Ends meet at (30,170) and (430,170) — pointed ends, typical taco. Fill shellGrad, stroke #B96A1B stroke-width 6? Stroke around whole path.
- Shell top edge line: the fillings cover area above y=170 between x 30..430; shell covers below inner curve. But between inner curve and the straight line y=170 at edges, is there a gap? The closed path includes region between outer and inner curves only. The straight closing edge from (430,170) back to (30,170) via inner curve — inner curve dips to 219 at center, so the region between y=170 line and inner curve near center (y 170..219) is NOT part of shell (it's inside the "bowl") — that region shows background, and fillings occupy it. Fillings drawn down to y≈180+ will overlap shell top area near edges (x<60 or >400) getting covered. Good — looks like fillings inside taco.
- Grill marks: 3-4 short arcs on shell: paths like M120,235 q30,18 60,22 stroke #C77B22 width 5 fill none, following curvature. Or simple curved lines: M140,240 Q230,285 320,240 etc. Add sesame seeds: small ellipses fill #FFE1A8 rotated various, on shell region (y 230-255).
- Plate: ellipse under taco: cx230 cy300 rx210 ry26 fill #fff stroke ink? Add shadow ellipse darker under. Actually taco bottom at 265; plate at cy 295. Draw plate first (before fillings/shell): ellipse fill #FDFDF8 stroke #1E1A17 4. Then shadow.
- Lime wedge at right: circle segment: path wedge at (395,265)? maybe skip or simple: green circle with segments at left (55,270) r 22 fill #BFE36B stroke green, inner lines.
- Chili pepper: small red curved path near right.
Steam paths: M180,60 q10,-18 0,-34 q-10,-16 0,-30 stroke #fff? On cream bg use #d9c9b8 or ink at low opacity. Use stroke #E8D9C5 width 6 linecap round, three at x 180,230,280, animated.
Also add sparkles: plus signs around.
Food truck SVG (viewBox 0 0 520 300):
- Body: rounded rect x40 y60 w360 h150 rx18 fill red #E8442E stroke ink 5.
- Cab: right side: path from x400: cab shape: M400,90 h60 q20,0 26,20 l10,40 q4,16 -12,16 h-84 z fill cream stroke ink. Window: rounded rect within cab fill #BFE3F0 stroke ink.
- Wheels: circles at (120,215) r26 and (430,215) r26 fill ink, inner circle cream r10. Wheel wells: arcs.
- Serving window on body: rect x80 y95 w150 h70 rx8 fill #FFF6E9 stroke ink 5; inside: tiny shelf line + hanging lamp? Add awning above window: striped: rect x70 y70 w170 h26 with scallops: use pattern of triangles: draw 6 vertical stripes alternating red/cream within a path, plus scallop circles at bottom. Simpler: awning as path: M70,96 L240,96 L232,70 L78,70 Z with stripes via clipPath — or just draw rect + circles: rect x72 y72 w166 h22 fill cream stroke ink; stripes: 5 rects width ~27 fill red alternating; bottom scallops: 6 semicircles fill matching along y=94. Manageable: I'll draw stripes as a group of rects clipped to awning shape using clipPath.
- Text on body: "KIMCHI LOCO" in SVG <text> with font-family inherit, font-weight 900, fill cream, letter-spacing. Position x255 y150 anchor middle, size 26. Plus small "KOREAN TACOS" size 11 below, and a 🌶? Use text "★" maybe. Keep text.
- Roof sign: small rect on top with "TACOS" or a pepper icon: draw chili: path. Maybe a little flag.
- Details: headlight circle on cab, bumper line, door line on cab, side stripe along body bottom (cream rect), "OPEN" sign hanging in window: small rect with text OPEN size 10 fill red.
- Ground: line/ellipse shadow.
Text in SVG uses page fonts — fine.
Now the countdown + today highlight JS:
```js
const SLOTS = [
{d:0, h:10, m:0, endH:15, endM:0, name:"Brunch Club — Riverside Park", emoji:"🌳"},
{d:2, h:11, m:30, endH:14, endM:0, name:"5th & Main — Downtown", emoji:"🏙️"},
{d:3, h:17, m:0, endH:22, endM:0, name:"Hop Yard Brewery", emoji:"🍺"},
{d:4, h:11, m:30, endH:14, endM:0, name:"City Hall Plaza", emoji:"🏛️"},
{d:5, h:17, m:0, endH:23, endM:0, name:"Neon District Night Market", emoji:"🎡"},
{d:6, h:12, m:0, endH:23, endM:0, name:"Farmers Market + Stadium Lot", emoji:"☀️"},
];
```
Day order display Mon..Sun: Monday rest card first.
Build schedule cards: for day 1..6,0 order [1,2,3,4,5,6,0] with Monday special rest card.
nextSlot(): now = new Date(); for each slot compute today's date at h:m; iterate offsets 0..7: candidate = slot on (nowDay + offset) — easier: for offset 0..7, day = (now.getDay()+offset)%7, date = new Date(now); date.setDate(now.getDate()+offset); date.setHours(h,m,0,0); if date > now → found. Compute diff seconds → format "Xd Xh Xm Xs" or if <1h "Xm Xs". Also LIVE check: if now within [start,end] of a slot today → show "LIVE NOW at {name} until {end}".
Render into #nextStop element, update every 1s via setInterval.
Menu render JS from array with category; filter buttons set active class; re-render grid with small stagger animation (cards get style animation-delay). Cart: count, update #cartCount with bump animation (re-trigger by removing/adding class). Toast: create div in #toasts, auto remove 2.2s.
Newsletter: form submit handler, preventDefault, check email regex simple, show message.
Reveal: IO on .reveal elements.
Nav mobile: I'll add a simple hamburger using <button> toggling a dropdown panel with links (works at small widths; hidden on desktop). Implement: button#burger shown ≤760px; panel absolute under nav with column links; toggle class. Clicking a link closes.
Marquee CSS:
```css
.marquee{overflow:hidden; background:var(--red); border-top/bottom:3px solid ink; transform:rotate(-1.2deg) scale(1.02);}
.marquee-track{display:flex; gap:0; width:max-content; animation:scroll 22s linear infinite;}
.marquee span{...padding:12px 0; white-space:nowrap; font display; color cream;}
@keyframes scroll{to{transform:translateX(-50%)}}
```
Track contains two identical groups each width 50%? Standard: put content twice, animate -50%. Ensure track width max-content and two spans each containing repeated text.
Hero background pattern: radial dots: background-image: radial-gradient(#e8d9c5 1.5px, transparent 1.5px); background-size: 22px 22px; on cream. Nice subtle.
Buttons: .btn {border:3px solid ink; box-shadow:5px 5px 0 ink; transition transform/shadow; } .btn:hover{transform:translate(-2px,-2px); box-shadow:8px 8px 0 ink} .btn:active{transform:translate(3px,3px); box-shadow:2px 2px 0 ink}. Primary red bg cream text; secondary cream bg ink text.
Cards similar shadow style. Section headings: eyebrow small red uppercase letter-spacing, h2 huge display with highlighted word (span with red underline swash: background linear-gradient red bottom 40%? Use box-decoration or a marker effect: background:linear-gradient(transparent 60%, #FFC531 60%) on span).
Sticky nav with backdrop? solid cream.
Colors vars:
--cream:#FFF6E9; --paper:#FFFDF6; --ink:#211A14; --red:#E8442E; --red-dark:#C22F1D; --orange:#FF7A00; --yellow:#FFC531; --green:#4E9B47; --pink:#FFD9CF;
Section paddings: 72px 0. Container: width min(1120px, 92%) margin auto.
Menu card structure:
```html
<article class="card reveal">
<div class="card-top"><span class="food-emoji">🌮</span><span class="price">$4.50</span></div>
<h3>Kimchi Carnitas</h3>
<p>desc</p>
<div class="card-foot"><span class="spice">🌶🌶</span><span class="tag">BESTSELLER</span><button class="add">+ Add</button></div>
</article>
```
Emoji circle: .food-emoji{font-size:2.6rem; background:var(--yellow) circle border ink; width 72px height 72px display grid place-items center; border:3px solid ink; box-shadow 4px 4px 0 ink; transform rotate(-4deg)}.
Spice display: if 0 → "Mild" text? Show 🌶 count or "🌱 mild". For vegan tag show "VEGAN" green tag.
Prices with .price display font red.
Filter pills: .pill border 3px ink bg paper; .active bg ink color cream.
Cart in nav: button-ish span with 🛒? Use SVG cart? Text "CART · 0" in a pill; bump animation scale.
Toast: fixed bottom center, ink bg cream text, border, shadow, animation slide up; stack column.
Reviews: cards with big quote mark “ in red, stars as ★★★★★ colored red letter-spacing, text, name + handle.
Gallery tiles: .tile with gradient backgrounds (different per tile via nth-child), big emoji, caption overlay bottom, hover scale 1.04 rotate. Height 220px. Grid 4 cols → 2 on mobile.
Newsletter section: yellow bg band with ink border top/bottom, rotated? Keep straight, big heading "GET THE LOCO DROP", form inline: input + button. Input styled border 3px ink, bg paper, padding.
CTA band before footer: red bg, big cream text "SEE YOU AT THE TRUCK 🌶", phone + button "Call to order" (tel: link — allowed? It's not window.open; tel: link fine, but in sandbox clicking does nothing harmful; fine).
Footer ink bg.
Also add "hours today" chip in hero: JS fills "Today: Brunch Club · Riverside Park · 10:00–15:00" or "Rest day — back Tuesday". Nice dynamic touch.
Add scroll-margin-top: 90px to sections.
Now, careful about first paint: everything static renders immediately; JS enhances. Good.
Let me also add subtle floating animation to hero chips and taco (gentle bob). And rotating dashed ring behind taco: absolutely positioned div with border:3px dashed red; border-radius:50%; animation spin 30s linear. Behind SVG. Plus blob bg: radial gradient circle yellow.
Hero right visual container: position relative; .halo circle bg yellow behind; svg width 100%.
Let me write the code now. I'll be thorough but mindful of length — it'll be long (~700-900 lines). That's fine.
Key structural skeleton:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Kimchi Loco — Korean Tacos Food Truck</title>
<style> ... </style>
</head>
<body>
<header class="nav"> ... </header>
<main>
<section class="hero" id="top"> ... </section>
<div class="marquee"> ... </div>
<section id="menu"> ... </section>
<section id="truck" class="schedule"> ... </section>
<section id="story"> about + truck svg </section>
<section class="gallery"> ... </section>
<section class="reviews"> ... </section>
<section class="cta-band"> ... </section>
<section class="newsletter" id="drop"> ... </section>
</main>
<footer> ... </footer>
<div id="toasts"></div>
<script> ... </script>
</body>
</html>
```
Order: maybe hero → marquee → menu → story(truck) → schedule → gallery → reviews → newsletter → cta → footer. I'll do hero, marquee, menu, schedule, story, gallery, reviews, newsletter/cta, footer.
Nav links: Menu, Truck, Story, Reviews, Drop.
Let me write CSS variables and base:
```css
:root{
--cream:#FFF6E9; --paper:#FFFCF4; --ink:#221A13; --red:#E8442E; --red-d:#B9301C;
--orange:#FF7A1A; --yellow:#FFC531; --green:#3F8F3A; --sky:#BFE3F0; --pink:#FFD9CF;
--shadow:6px 6px 0 var(--ink);
--disp:'Arial Black','Archivo Black','Helvetica Neue',Helvetica,Arial,sans-serif;
--body:system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{font-family:var(--body);background:var(--cream);color:var(--ink);overflow-x:hidden;line-height:1.55}
img,svg{display:block;max-width:100%}
.container{width:min(1140px,92%);margin-inline:auto}
section{scroll-margin-top:96px}
```
Display class: .disp{font-family:var(--disp);font-weight:900;line-height:.95;letter-spacing:-.02em; text-transform:uppercase}
Buttons, pills, cards, etc.
Nav:
```css
.nav{position:sticky;top:0;z-index:50;background:var(--cream);border-bottom:3px solid var(--ink);}
.nav-inner{display:flex;align-items:center;gap:18px;height:72px}
.logo{display:flex;align-items:center;gap:10px;font-family:var(--disp);font-weight:900;font-size:1.25rem;text-transform:uppercase;text-decoration:none;color:var(--ink)}
.logo-badge{width:42px;height:42px;background:var(--red);border:3px solid var(--ink);border-radius:50%;display:grid;place-items:center;box-shadow:3px 3px 0 var(--ink);font-size:1.3rem}
.nav-links{display:flex;gap:4px;margin-left:auto}
.nav-links a{padding:8px 14px;border-radius:999px;text-decoration:none;color:var(--ink);font-weight:700;border:3px solid transparent}
.nav-links a:hover{border-color:var(--ink);background:var(--yellow)}
.cart-pill{...}
.btn{...}
```
Hero:
```css
.hero{position:relative;padding:64px 0 80px;background-image:radial-gradient(#ecdcc6 1.6px,transparent 1.6px);background-size:24px 24px;overflow:hidden}
.hero-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:40px;align-items:center}
.eyebrow{display:inline-flex;align-items:center;gap:8px;background:var(--paper);border:3px solid var(--ink);border-radius:999px;padding:6px 14px;font-weight:800;font-size:.8rem;letter-spacing:.12em;text-transform:uppercase;box-shadow:4px 4px 0 var(--ink)}
h1{font-size:clamp(3.2rem,8.5vw,6.8rem)}
h1 .loco{color:var(--red); position relative; display:inline-block; text-shadow? } maybe -webkit-text-stroke outline style: .outline{color:transparent;-webkit-text-stroke:3px var(--ink)} for one word. Let's do "KIMCHI" solid ink, "LOCO" red with slight rotate? Keep simple: KIMCHI ink, LOCO red with underline squiggle SVG? Add .marker highlight behind LOCO: background yellow skewed. I'll do: .hl{background:linear-gradient(transparent 55%, var(--yellow) 55% 92%, transparent 92%)} hmm simpler: box-shadow inset? Use background:var(--yellow) with padding and border? Let's do highlight marker: background-image:linear-gradient(120deg, transparent 0 8%, var(--yellow) 8% 92%, transparent 92%)? Keep simple: span with background yellow, padding 0 .1em, border 3px ink? That looks sticker-like. Actually h1 with a red word is enough plus a small 🌶 SVG.
```
I'll add a hand-drawn arrow SVG near CTA? Skip.
Stats row: .stats{display:flex;gap:22px;flex-wrap:wrap;margin-top:26px} .stat b{display:block;font-family disp;font-size:1.4rem} .stat span{font-size:.85rem;font-weight:600;opacity:.8}
Today chip: #todayChip styled like eyebrow but yellow bg; JS fills text.
Hero visual:
```css
.hero-visual{position:relative;display:grid;place-items:center;min-height:380px}
.halo{position:absolute;width:min(440px,90%);aspect-ratio:1;border-radius:50%;background:var(--yellow);border:3px solid var(--ink); box-shadow:10px 10px 0 var(--pink)?}
.ring{position:absolute;width:min(500px,100%);aspect-ratio:1;border:3px dashed var(--red);border-radius:50%;animation:spin 40s linear infinite}
.taco{position:relative;width:min(480px,100%);animation:bob 5s ease-in-out infinite;filter:drop-shadow(10px 12px 0 rgba(34,26,19,.18))}
.chip{position:absolute;background:var(--paper);border:3px solid var(--ink);border-radius:999px;padding:6px 12px;font-weight:900;font-size:.78rem;letter-spacing:.08em;box-shadow:4px 4px 0 var(--ink);animation:float 4s ease-in-out infinite}
.chip.c1{top:6%;left:-2%;background:var(--red);color:var(--cream);transform:rotate(-8deg)}
...
```
Chips: "30-DAY KIMCHI", "🌶 GOCHUJANG GLAZE", "SMOKED OVER OAK". Position around.
Marquee:
```css
.marquee{background:var(--red);border-block:3px solid var(--ink);transform:rotate(-1.2deg);margin:10px -20px? }
```
To avoid horizontal overflow from rotation, wrap: .tilt{overflow:hidden; padding:18px 0; margin:-6px 0} inner .marquee rotate. Body overflow-x hidden anyway, but rotated element wider than viewport could cause scroll — overflow-x hidden on body handles it. Set .marquee{width:110%; margin-left:-5%}.
Track: two .mq-group spans identical; animation translateX(-50%). Each group: repeated "KIMCHI LOCO ✶ KOREAN BBQ TACOS ✶ HOUSE-FERMENTED KIMCHI ✶ SEOUL × MEXICO ✶ " maybe 4 times per group. Use ✶ char (renders as text). Font disp, cream color, size 1.1rem, padding 12px 0, white-space nowrap.
Menu section:
```css
.section{padding:84px 0}
.sec-head{display:flex;align-items:end;justify-content:space-between;gap:20px;flex-wrap:wrap;margin-bottom:30px}
h2{font-size:clamp(2.2rem,5vw,3.6rem)}
.sec-sub{max-width:520px;font-weight:600}
.pills{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:26px}
.pill{font:inherit;font-weight:800;padding:8px 18px;border:3px solid var(--ink);background:var(--paper);border-radius:999px;cursor:pointer;box-shadow:4px 4px 0 var(--ink);transition:...}
.pill.active{background:var(--ink);color:var(--cream);transform:translate(2px,2px);box-shadow:2px 2px 0 var(--ink)}
.menu-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:22px}
.card{background:var(--paper);border:3px solid var(--ink);border-radius:18px;box-shadow:var(--shadow);padding:20px;display:flex;flex-direction:column;gap:10px;transition:transform .18s, box-shadow .18s;animation:pop .35s both}
.card:hover{transform:translate(-3px,-3px) rotate(-.5deg);box-shadow:9px 9px 0 var(--ink)}
```
Card top row: emoji badge + price right. Name h3 disp 1.15rem uppercase. desc .9rem. foot: margin-top auto; display flex; align-items center; gap 8px; spice small; tag chip; add button margin-left auto: .add{border:3px solid ink;background:var(--yellow);font-weight:900;border-radius:999px;padding:6px 14px;cursor:pointer;box-shadow:3px 3px 0 ink} active translate.
Tag colors: .tag{font-size:.62rem;font-weight:900;letter-spacing:.08em;padding:3px 8px;border:2px solid var(--ink);border-radius:6px;background:var(--yellow)} .tag.vegan{background:#BFE3B0} .tag.new{background:var(--pink)} .tag.hot{background:var(--red);color:cream}.
Schedule:
```css
.schedule{background:var(--ink);color:var(--cream)}?
```
A dark section adds contrast. Cards on dark: bg #2E241B? Let's do section bg ink, heading cream, cards bg #2b2118 with cream border? Borders ink won't show on ink bg — use border cream? Neo-brutalist on dark: cards bg var(--paper) color ink still pops. Let's make schedule section red background? We have red marquee already. Choose: schedule section bg var(--yellow)? Yellow with ink cards... Let me assign section backgrounds for rhythm: hero cream → marquee red → menu cream → schedule ink (dark) → story cream → gallery pink? → reviews cream → newsletter yellow → footer ink. Dark schedule: heading cream, sub cream/70. Day cards: bg #2A2018 border 3px solid #000? Hmm keep border cream? Simpler: cards bg var(--paper) color ink with shadow in red: box-shadow:6px 6px 0 var(--red). Today card: bg var(--red) color cream shadow yellow, with "TODAY" badge. Live card pulse. Nice.
Next-stop banner: above grid, a pill: "⏰ NEXT STOP: ..." ticking. Style: bg var(--yellow) color ink border ink shadow cream? On dark bg, yellow pill with ink border, box-shadow 5px 5px 0 rgba(255,246,233,.25)? Use box-shadow:5px 5px 0 #000. Fine.
Day card content: .day disp 1.05rem; .loc font-weight 700 .95rem; .time .8rem opacity .8; emoji top-right big 1.6rem. Rest card: dashed border, "REST DAY — we're fermenting".
Story section: two-col: truck SVG in a bordered frame card with caption sticker "OUR TRUCK — 'LA LOCA'"; right: eyebrow "OUR STORY", h2 "ONE GRILL. TWO HOMES.", paragraphs, 3 mini stats or checklist (House-fermented kimchi 30 days / Bulgogi marinated 24h / Tortillas pressed daily). CTA link.
Gallery: heading "@KIMCHILOCO ON THE FEED" + 4 tiles. Tiles: gradient backgrounds: 1) linear-gradient(135deg,#FF7A1A,#E8442E) caption "Bulgogi burrito, mid-bite 🌯"; 2) (#FFC531,#FF7A1A) "Seoul fries 🍟"; 3) (#3F8F3A,#7CB342) "Kimchi, 30 days 🌶"; 4) (#BFE3F0,#7FB6D9) "Night market run 🎡". Big emoji center font-size 4rem with drop shadow; caption bar bottom paper border-top ink.
Reviews: 3 cards; quote mark big red disp; stars red; text; name strong + role small. Card style same paper card. Maybe rotate slightly alternating.
Newsletter: bg yellow band border-block ink; center; h2 "GET THE LOCO DROP"; p; form: input email + button red. Success: swap to "You're in! 🌶 Check your inbox for a free-truffle... " message div hidden initially. On invalid: shake input + red border + msg "Enter a real email, hungry human."
CTA band: red bg, big text "HUNGRY YET?" + "Call (555) 012-3456 or find the truck tonight." + buttons: "Call now" (tel:) paper bg; "See schedule" scroll. Put before newsletter? Put CTA band after reviews, then newsletter, then footer. Fine.
Footer: ink bg cream text; grid 3 cols: brand + blurb; "Hours" list (Tue–Thu 11:30–2 & 5–10 etc. keep simple: see schedule); "Say hi": email, phone, instagram handle @kimchiloco. Bottom bar: © year via JS? static 2025 fine — use JS new Date().getFullYear(). Small "Made with gochujang & love".
Toasts CSS:
```css
#toasts{position:fixed;left:50%;bottom:22px;transform:translateX(-50%);display:flex;flex-direction:column;gap:10px;z-index:100;align-items:center}
.toast{background:var(--ink);color:var(--cream);border:3px solid var(--ink);box-shadow:5px 5px 0 rgba(34,26,19,.25);padding:10px 18px;border-radius:999px;font-weight:800;animation:toastIn .25s ease both}
```
Reveal:
```css
.reveal{opacity:0;transform:translateY(24px);transition:opacity .6s ease, transform .6s ease}
.reveal.in{opacity:1;transform:none}
```
Careful: if JS fails, content invisible — but JS is inline and will run. Add no-js fallback? Add class via JS only: set .reveal styles only when body has .js class: body.classList.add('js') at script start; CSS: .js .reveal{...}. Safe.
Keyframes: spin, bob, float, pop, toastIn, steam.
Steam animation: .steam path{stroke-dasharray? } simpler: animate opacity/translateY: .steam{animation:steam 3s ease-in-out infinite} .steam.s2{animation-delay:1s} etc. keyframes steam{0%{transform:translateY(6px);opacity:0}30%{opacity:.7}100%{transform:translateY(-14px);opacity:0}}.
Parallax: hero-visual mousemove → taco rotate/translate small. Guard matchMedia pointer fine.
Now the taco SVG detailed code:
```html
<svg class="taco" viewBox="0 0 460 340" role="img" aria-label="A loaded Korean taco">
<defs>
<linearGradient id="shell" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#F8C766"/><stop offset="1" stop-color="#DE8A2B"/>
</linearGradient>
<linearGradient id="lettuce" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#8CCB5E"/><stop offset="1" stop-color="#5DA83C"/>
</linearGradient>
</defs>
<!-- plate -->
<ellipse cx="230" cy="306" rx="205" ry="24" fill="#FFFDF6" stroke="#221A13" stroke-width="5"/>
<ellipse cx="230" cy="302" rx="170" ry="15" fill="#F3E4CE"/>
<!-- steam -->
<g class="steam" stroke="#E4CFAF" stroke-width="7" fill="none" stroke-linecap="round">
<path d="M175 78 q12 -16 0 -32 q-10 -14 2 -28"/>
<path class="s2" d="M232 66 q12 -16 0 -32 q-10 -14 2 -28"/>
<path class="s3" d="M288 80 q12 -16 0 -32 q-10 -14 2 -28"/>
</g>
<!-- fillings -->
<g stroke="#221A13" stroke-width="4">
<!-- lettuce -->
<path d="M58 168 Q78 128 98 168 Q118 128 138 168 Q158 128 178 168 Q198 128 218 168 Q238 128 258 168 Q278 128 298 168 Q318 128 338 168 Q358 128 378 168 Q392 140 402 168 L402 178 L58 178 Z" fill="url(#lettuce)"/>
<!-- meat -->
<circle cx="105" cy="140" r="17" fill="#8A4B22"/>
<circle cx="165" cy="128" r="15" fill="#6E3A18"/>
<circle cx="235" cy="136" r="18" fill="#8A4B22"/>
<circle cx="305" cy="126" r="15" fill="#6E3A18"/>
<circle cx="360" cy="142" r="16" fill="#8A4B22"/>
<!-- kimchi -->
<rect x="128" y="112" width="34" height="26" rx="8" fill="#E8442E" transform="rotate(-12 145 125)"/>
<rect x="205" y="104" width="36" height="26" rx="8" fill="#F05A3A" transform="rotate(8 223 117)"/>
<rect x="282" y="108" width="32" height="24" rx="8" fill="#E8442E" transform="rotate(-8 298 120)"/>
<rect x="340" y="118" width="30" height="22" rx="8" fill="#F05A3A" transform="rotate(14 355 129)"/>
<rect x="70" y="120" width="30" height="24" rx="8" fill="#F05A3A" transform="rotate(10 85 132)"/>
<!-- onion arcs -->
<path d="M150 150 q12 -14 24 0" fill="none" stroke="#FFF6E9" stroke-width="5"/>
<path d="M255 152 q12 -14 24 0" fill="none" stroke="#FFF6E9" stroke-width="5"/>
<!-- cilantro leaves -->
<path d="M190 118 q8 -12 16 -2 q-10 4 -16 2Z" fill="#3F8F3A"/>
<path d="M320 140 q10 -10 16 0 q-10 5 -16 0Z" fill="#3F8F3A"/>
</g>
<!-- shell -->
<path d="M34 172 Q230 372 426 172 Q230 268 34 172 Z" fill="url(#shell)" stroke="#221A13" stroke-width="6" stroke-linejoin="round"/>
<!-- grill marks -->
<g stroke="#C77B22" stroke-width="5" fill="none" stroke-linecap="round">
<path d="M120 236 Q150 252 184 258"/>
<path d="M276 258 Q310 252 340 236"/>
<path d="M196 276 Q230 284 264 276"/>
</g>
<!-- sesame -->
<g fill="#FFE3A6" stroke="#221A13" stroke-width="2.5">
<ellipse cx="150" cy="246" rx="6" ry="3.5" transform="rotate(-18 150 246)"/>
<ellipse cx="205" cy="266" rx="6" ry="3.5" transform="rotate(10 205 266)"/>
<ellipse cx="262" cy="264" rx="6" ry="3.5" transform="rotate(-12 262 264)"/>
<ellipse cx="312" cy="246" rx="6" ry="3.5" transform="rotate(20 312 246)"/>
</g>
<!-- lime -->
<g transform="translate(52 268)">
<circle r="24" fill="#BFE36B" stroke="#221A13" stroke-width="5"/>
<circle r="16" fill="#EAF7C8" stroke="#7CB342" stroke-width="3"/>
<g stroke="#7CB342" stroke-width="3">
<path d="M0 -16 V16 M-14 -8 L14 8 M-14 8 L14 -8"/>
</g>
</g>
<!-- chili -->
<g transform="translate(408 262) rotate(-30)">
<path d="M0 0 q26 -6 34 -26 q4 -10 -6 -8 q-22 8 -30 26 q-3 8 2 8Z" fill="#E8442E" stroke="#221A13" stroke-width="4"/>
<path d="M28 -32 q8 -8 14 -2" fill="none" stroke="#3F8F3A" stroke-width="6" stroke-linecap="round"/>
</g>
</svg>
```
Check shell path: M34,172 Q230,372 426,172 (outer bottom ~ (0.25*172+0.5*372+0.25*172)=272) then Q230,268 back to 34,172 (inner bottom = 0.25*172+0.5*268+0.25*172=220). Thickness 52 at center. Fillings at y up to 178 with lettuce bottom 178 — shell top edge is the straight line between endpoints? The path closes from (426,172) via inner curve to (34,172) then Z straight line back to start (34,172) — actually Z closes from current point (34,172) to start (34,172): zero. Wait path: M34,172 → Q to 426,172 → Q to 34,172 → Z. So region enclosed between outer curve and inner curve. Top boundary near edges is pinched to points at (34,172),(426,172). The straight line y=172 between x=34..426 is NOT drawn; fillings above y~172 will show over background — but between inner curve (dips to 220) and y=172 line, the area is open (background shows) — that's the taco opening, correct, and fillings drawn there (lettuce bottom at 178, meat circles cy 126-142 r up to 18 → bottom 160) — lettuce strip bottom 178 slightly below 172 line: near center, shell inner top at 220, so lettuce at 172-178 shows against background (inside opening) — good, looks like filling inside. Near edges x=34..58 and 402..426, shell exists up to y=172 only at exact endpoints; lettuce extends to x=58..402, at x=58 shell inner curve y ≈ ? Inner curve from (426,172) Q(230,268) (34,172): at x=58, y ≈ 172 + something small (~177?). Parametrize: point on quadratic at t: B(t)=(1-t)²P0+2(1-t)tC+t²P2 with P0=(426,172),C=(230,268),P2=(34,172). x(t)=426(1-t)²+460(1-t)t+34t². At t=0.95: x=426*.0025+460*.0475+34*.9025=1.065+21.85+30.7=53.6; y=172*.0025+268*2*.05*.95? compute: (1-t)²=.0025, 2(1-t)t=.095, t²=.9025 → y=172*.0025+268*.095+172*.9025=0.43+25.46+155.23=181.1. So at x≈54, inner shell top y≈181. Lettuce at x=58 bottom 178 < 181 → tiny background gap? The shell region is below inner curve (y>181 at that x); lettuce ends at 178, so between 178 and 181 there's a 3px background sliver near edges — negligible/invisible at scale, and stroke width 6 on shell covers ±3. Fine.
Outer bottom 272 vs plate at cy 306 — taco floats above plate; move plate up: cy=288, and taco bottom 272 → 16px gap plus stroke 6 → looks like floating slightly; set plate cy 286 ry 22. Or lower taco: fine, set plate cy=290. Shadow: add ellipse under taco on plate: ellipse cx230 cy284 rx150 ry12 fill #E7D3B8. OK adjust: plate ellipse cy=292 rx=205 ry=22; inner ellipse cy=288 rx=168 ry=13 fill #F3E4CE; shadow ellipse cx230 cy=282 rx=140 ry=10 fill #E7CFAF. Taco bottom 272+stroke3=275 sits on shadow 282 — good.
Lime at translate(52,268) r24 → spans x 28..76, y 244..292 — overlaps shell left tip (34,172)? Shell at x=52: outer curve y? Outer: P0=(34,172),C=(230,372),P2=(426,172): at x=52 → t small: t=0.05: x=34*.9025+460*.095+426*.0025=30.7+43.7+1.065=75.4; y=172*.9025+372*.095+172*.0025=155.2+35.34+0.43=191. So shell at x≈75 has y≈191; at x=52, t≈0.02: x≈34*.9604+460*.0392+426*.0004=32.65+18.03+0.17=50.85, y≈172*.9604+372*.0392+172*.0004=165.2+14.58+0.07=179.9. So shell near x=52 top edge y≈180, bottom outer y at x=52: outer curve y≈180 too (near tip). Lime circle center (52,268) r24 → top at 244, below shell tip region (shell near x=52 spans y 180..~180+thin). Actually near the tip the shell is thin; lime sits below/left, overlapping plate — fine, looks like lime wedge on plate next to taco. Good. Chili at (408,262): shell right tip near (426,172); chili below-right on plate. OK.
Steam at y 14..78 above fillings (fillings top ~104). Good.
Truck SVG:
```html
<svg viewBox="0 0 560 320">
<!-- ground shadow -->
<ellipse cx="280" cy="292" rx="250" ry="16" fill="#EAD9BF"/>
<!-- body -->
<rect x="40" y="70" width="380" height="160" rx="20" fill="#E8442E" stroke="#221A13" stroke-width="6"/>
<!-- bottom stripe -->
<rect x="40" y="196" width="380" height="34" rx="17" fill="#FFC531" stroke="#221A13" stroke-width="6"/> hmm overlapping rounded corners; instead: path stripe clipped. Simpler: rect x="46" y="198" width="368" height="26" fill="#FFC531" (inside, no stroke) then border line? Let's do: <path d="M40 190 h380 v22 a20 20 0 0 1 -20 20 h-340 a20 20 0 0 1 -20 -20 Z" fill="#FFC531" stroke="#221A13" stroke-width="6"/> That draws bottom band following body bottom radius. y from 190 to 230; body bottom at 230. ok.
<!-- serving window -->
<rect x="80" y="102" width="160" height="76" rx="10" fill="#FFF6E9" stroke="#221A13" stroke-width="6"/>
<!-- window sill items: taco + drink silhouettes -->
<path d="M100 158 q20 -26 40 0 Z" fill="#F8C766" stroke="#221A13" stroke-width="4"/> mini taco
<rect x="168" y="130" width="16" height="28" rx="4" fill="#BFE3F0" stroke="#221A13" stroke-width="4"/>
<path d="M172 130 l4 -8" stroke="#E8442E" stroke-width="4" stroke-linecap="round"/> straw
<!-- OPEN sign -->
<g transform="translate(118 108)"><rect width="64" height="24" rx="6" fill="#221A13"/><text x="32" y="17" text-anchor="middle" font-size="12" font-weight="900" fill="#FFC531" font-family="inherit" letter-spacing="2">OPEN</text></g>
Hmm OPEN inside window top. Window x80..240 y102..178. Put sign hanging at top of window: translate(128,108). ok.
<!-- awning -->
<g>
<path d="M66 102 L254 102 L242 66 L78 66 Z" fill="#FFF6E9" stroke="#221A13" stroke-width="6" stroke-linejoin="round"/>
stripes: clip to awning path; rects x=78.. width 26 alternating red: use clipPath id="awn". rects: x=78,130,182,234 width 26? Let's compute: awning top edge from (78,66) to (242,66), bottom (66,102)-(254,102). Stripes vertical-ish; simpler draw 5 parallelograms? Use clipPath with the awning path, then draw rects x from 66 to 254 step 32, width 16, fill red, y 60..110. They'll be clipped slanted. Good.
scallop bottom: circles along y=102: cx=80,108,136,...,246 r=14 fill alternate? With clip too. Simpler: after stripes, draw bottom border line already from path stroke. Add scallops: <g clip-path="url(#awn)"> circles cy=102 r=15 at cx=81,113,145,177,209,241 fill matching stripe color? complicated. Alternative awning: series of semicircle scallops: draw path of arcs: M66 102 q16 -18 32 0 q16 -18 32 0 ... fill red with stroke, over cream rect. Let me simplify awning: top trapezoid cream with red stripes (clipped), bottom edge scalloped via separate path:
<path d="M66 102 q17 -20 34 0 q17 -20 34 0 q17 -20 34 0 q17 -20 34 0 q17 -20 34 0 q17 -20 34 0" ...> from x=66 to 270? width 204 → 6 scallops of 34. fill #E8442E stroke ink. That gives scalloped red edge under cream striped top. But then stripes bottom hidden. OK design: awning = cream trapezoid with red vertical stripes, plus red scallop trim at bottom. Looks classic.
</g>
<!-- brand text on body -->
<text x="300" y="150" text-anchor="middle" font-family="Arial Black, sans-serif" font-weight="900" font-size="34" fill="#FFF6E9" letter-spacing="1">KIMCHI</text>
<text x="300" y="182" text-anchor="middle" ... font-size="30" fill="#FFC531">LOCO</text>
Wait stripe band at y190..230; text above it y150/182 ok within body (body y70..230). Window occupies x80..240; text centered x=310? body x40..420, center 230 — but window on left half; put text right-center x=320. Cab starts x420. Text "KIMCHI LOCO" one line size 26 at x=325 y=160, plus "KOREAN TACOS ★ EST. 2019" size 12 y=184 fill cream. Let me: <text x="325" y="158" font-size="27">KIMCHI LOCO</text> might overflow: 11 chars * ~19px = 209px wide, centered at 325 → spans 220..430 — overlaps window (ends 240) slightly and cab. Use size 24 → ~180 wide → 235..415. Tight. Alternatively two lines: KIMCHI y=140 size 30, LOCO y=172 size 30, centered x=330: KIMCHI 6 chars*22=132 → 264..396 ok. Do two lines, cream fill, with slight stroke? fill cream, maybe paint-order stroke ink for pop: stroke #221A13 stroke-width 1? skip.
<!-- side pepper decal -->
small chili near front: skip or add ★.
<!-- cab -->
<path d="M420 100 h58 q22 0 30 22 l12 44 q6 22 -18 22 h-82 Z" fill="#FFF6E9" stroke="#221A13" stroke-width="6" stroke-linejoin="round"/>
<!-- cab window -->
<path d="M436 116 h38 q14 0 19 14 l8 26 h-65 Z" fill="#BFE3F0" stroke="#221A13" stroke-width="5"/>
<!-- door line -->
<path d="M470 116 v88" stroke="#221A13" stroke-width="4"/> hmm door seam: <line x1="468" y1="120" x2="468" y2="206" stroke="#221A13" stroke-width="4"/>
<!-- headlight -->
<circle cx="512" cy="176" r="9" fill="#FFC531" stroke="#221A13" stroke-width="4"/>
<!-- bumper -->
<path d="M508 214 h20" stroke="#221A13" stroke-width="6" stroke-linecap="round"/>
<!-- wheels -->
<g> <circle cx="130" cy="232" r="30" fill="#221A13"/><circle cx="130" cy="232" r="13" fill="#FFF6E9"/> <circle cx="470" cy="232" r="30" fill="#221A13"/><circle cx="470" cy="232" r="13" fill="#FFF6E9"/></g>
Wheel wells: body bottom at 230; wheels centered 232 → half above body? Body rect covers y70..230, wheels drawn after body → wheels overlap body bottom, looks fine (wheel in front). Add wheel arch: path over wheel: <path d="M96 230 a34 34 0 0 1 68 0" fill="#221A13"/>? That would cover wheel top with body color... skip, wheels overlapping is fine stylistically. Actually to look right, draw arch cutouts: draw circles of body red? Simplest: draw wheels after body, they sit on bottom edge — common flat illustration style. Keep.
<!-- roof sign -->
<g transform="translate(150 34)"><rect width="120" height="34" rx="8" fill="#FFC531" stroke="#221A13" stroke-width="5"/><text x="60" y="24" text-anchor="middle" font-size="16" font-weight="900" fill="#221A13">TACOS 🌶</text></g> emoji in svg text — may render; use "HOT TACOS". Add little legs: lines from sign to roof: <line x1="170" y1="68" x2="170" y2="70">. sign at y34..68, body top 70 → connect with two small rects x=160,250 y=66 h=6.
<!-- steam from window? --> small
<!-- ground line -->
<line x1="20" y1="288" x2="540" y2="288" stroke="#221A13" stroke-width="5" stroke-linecap="round"/> maybe dashed.
</svg>
```
Text font-family in SVG: use font-family="Arial Black, Arial, sans-serif" attribute.
OK. Also small pepper icon reused in logo badge: use emoji 🌶 inside .logo-badge (span). If emoji missing → box. Alternative: inline SVG pepper in badge. I'll use a tiny inline SVG chili in the badge to be safe, and emoji elsewhere decorative. Actually let me just use "🌮"? Also emoji. For the logo badge, inline SVG mini taco/chili is safer and cuter. I'll make a small chili SVG.
Menu item emojis: I'll accept emoji (Chrome sandbox typically has Noto Color Emoji). Most graders run on environments with emoji. Risk acceptable; but to hedge, each menu emoji sits in a colored circle, and I'll also include the item initial? No — keep emoji; it's standard.
Actually, let me reduce risk: use SVG-ish? Too much work for 10 items. Emoji it is. Chrome on Linux without emoji fonts shows boxes — but Google's sandbox Chrome images include fonts-noto-color-emoji typically. I'll go with emoji; also hero uses SVG so first paint is guaranteed attractive.
Now JS data:
```js
const MENU = [
{name:"Kimchi Carnitas", cat:"tacos", price:4.50, emoji:"🌮", spice:2, tags:["BESTSELLER","hot"], desc:"Slow-braised pork shoulder, 30-day house kimchi, cilantro, lime crema on a charred corn tortilla."},
{name:"Seoul Fire Chicken", cat:"tacos", price:5.00, emoji:"🍗", spice:3, tags:["NEW","hot"], desc:"Double-fried chicken thigh glazed in gochujang-honey, pickled slaw, sesame."},
{name:"Tofu Kimchi (Vegan)", cat:"tacos", price:4.25, emoji:"🥬", spice:1, tags:["VEGAN","vegan"], desc:"Crispy tofu, kimchi, vegan crema, toasted sesame. Plants never tasted this loud."},
{name:"Bulgogi Burrito", cat:"burritos", price:9.50, emoji:"🌯", spice:2, tags:["BESTSELLER","hot"], desc:"24-hour marinated ribeye, rice, melty cheese, kimchi crema, wrapped and griddled."},
{name:"Seoul Fries", cat:"sides", price:6.00, emoji:"🍟", spice:1, tags:[], desc:"Crinkle fries loaded with bulgogi bits, cheese sauce, kimchi mayo, scallions."},
{name:"Kimchi Quesadilla", cat:"sides", price:7.50, emoji:"🧀", spice:2, tags:["hot"], desc:"Flour tortilla, three cheeses, kimchi, gochujang ranch for dunking."},
{name:"Kimchi Mandu (6pc)", cat:"sides", price:7.00, emoji:"🥟", spice:1, tags:[], desc:"Hand-folded pork & kimchi dumplings, soy-ginger dipping sauce."},
{name:"Horchata", cat:"drinks", price:3.50, emoji:"🥛", spice:0, tags:[], desc:"Cinnamon rice milk, over ice. Cools the fire."},
{name:"Kimchi Lemonade", cat:"drinks", price:4.00, emoji:"🍋", spice:1, tags:["NEW"], desc:"Fresh lemon, a whisper of kimchi brine, sparkling. Trust us."},
{name:"Hotteok", cat:"sweet", price:5.00, emoji:"🍯", spice:0, tags:["SWEET"], desc:"Warm Korean sweet pancake with brown sugar, walnut & cinnamon center."},
];
```
Render function with filter. Spice render: "🌶".repeat(spice) or "mild" if 0 → show "🌿 mild"? For drinks spice 0 → hide spice, show nothing or "🧊"? Just show peppers count >0 else "—". I'll show peppers if >0 else "mild".
Tags class mapping: hot→red, vegan→green, NEW→pink, BESTSELLER→yellow, SWEET→? default yellow. Map: {BESTSELLER:'', VEGAN:'vegan', NEW:'new', ...} default ''.
Cart: count var; add buttons event delegation on grid.
Schedule rendering:
```js
const DAYS=[ // index = JS day
{d:0,name:"Sunday",...},...
];
```
I'll define slots keyed by day with display order [1,2,3,4,5,6,0]:
```js
const WEEK = [
{day:1, short:"MON", name:"Rest day", loc:"Fermenting in the kitchen", time:"—", emoji:"🌙", rest:true},
{day:2, short:"TUE", name:"Downtown", loc:"5th & Main Plaza", time:"11:30 AM – 2:00 PM", emoji:"🏙️", h:11,m:30,eh:14,em:0},
{day:3, short:"WED", name:"Brewery Row", loc:"Hop Yard Brewery", time:"5:00 PM – 10:00 PM", emoji:"🍺", h:17,m:0,eh:22,em:0},
{day:4, short:"THU", name:"City Hall", loc:"City Hall Plaza", time:"11:30 AM – 2:00 PM", emoji:"🏛️", h:11,m:30,eh:14,em:0},
{day:5, short:"FRI", name:"Night Market", loc:"Neon District", time:"5:00 PM – 11:00 PM", emoji:"🎡", h:17,m:0,eh:23,em:0},
{day:6, short:"SAT", name:"Farmers Market", loc:"Market St + Stadium Lot", time:"12:00 PM – 11:00 PM", emoji:"☀️", h:12,m:0,eh:23,em:0},
{day:0, short:"SUN", name:"Brunch Club", loc:"Riverside Park", time:"10:00 AM – 3:00 PM", emoji:"🌳", h:10,m:0,eh:15,em:0},
];
```
Render cards; mark today: idx = new Date().getDay(); card with day===idx gets .today + badge "TODAY"; if within window add .live badge "LIVE NOW".
Next stop calc:
```js
function nextStop(){
const now=new Date();
for(let off=0; off<8; off++){
for(const s of WEEK){
if(s.rest) continue;
const dt=new Date(now); dt.setDate(now.getDate()+off); dt.setHours(s.h,s.m,0,0);
if(dt>now){
const end=new Date(dt); end.setHours(s.eh,s.em,0,0);
// if off===0 and now<end → it's live now
return {start:dt, end, s, off};
}
}
}
}
```
Wait ordering: for off=0 we check all slots today with start>now; but slots earlier today already passed → skipped since dt>now false. Good; but we want earliest upcoming overall: iterate off 0..7 and within each off, all days same date — collect min. Since all same date per off, first found in WEEK order isn't necessarily earliest time — but any slot on that date with start>now works; pick min start: better loop off, then among slots compute dt, filter >now, take min. Simpler: build all candidate dates for next 8 days and sort. Fine:
```js
function computeNext(){
const now=new Date();
const cands=[];
for(let off=0; off<8; off++){
for(const s of WEEK){ if(s.rest) continue;
const dt=new Date(now.getFullYear(),now.getMonth(),now.getDate()+off,s.h,s.m,0);
if(dt.getTime()>now.getTime()) cands.push({s,start:dt});
}
}
cands.sort((a,b)=>a.start-b.start);
return cands[0];
}
```
Display: label = off===0? "TODAY" : weekday name of start. Text: `NEXT STOP — ${s.name.toUpperCase()} · ${s.loc} · ${fmt(start)} — in ${dur}`. fmt time: h%12 etc. dur: d,h,m,s. Update every second: recompute each tick (cheap).
Live check each tick: for today slots, if now between start and end → show "🔴 LIVE NOW at {loc} until {endTime}" instead. Element #nextStop.
Also hero chip #todayChip: if live → "🔴 LIVE NOW — {loc}"; else if today has future slot → "TODAY: {name} · {time}"; else "REST DAY TODAY — see you {next day}". Compute in same tick or once on load. I'll update on load and each minute.
fmt time helper:
```js
const fmtT = d => { let h=d.getHours(), m=d.getMinutes(); const ap=h>=12?'PM':'AM'; h=h%12||12; return `${h}:${String(m).padStart(2,'0')} ${ap}`; };
```
Countdown format: diff = start-now; days=..., if days>0 `${days}d ${h}h ${m}m` else `${h}h ${m}m ${s}s`. Update text `${...}` each second.
Newsletter:
```js
form.addEventListener('submit', e=>{e.preventDefault(); const v=input.value.trim(); if(!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(v)){ msg error; input.classList.add('err'); return;} form.hidden... show success div with email inserted; toast("You're on the list! 🌶")});
```
Burger menu:
```js
burger.onclick toggle nav.classList('open'); panel links click → close.
```
CSS: .nav-links and .nav-cta hidden ≤820px except burger; .mobile-panel{display:none} .nav.open .mobile-panel{display:flex} positioned absolute top:72px left 0 right 0 bg cream border-bottom ink, column padding.
Simpler: duplicate links in a .mobile-panel div inside header, hidden on desktop.
Reveal IO:
```js
const io=new IntersectionObserver(es=>es.forEach(e=>{if(e.isIntersecting){e.target.classList.add('in'); io.unobserve(e.target)}}),{threshold:.12});
document.querySelectorAll('.reveal').forEach(el=>io.observe(el));
```
Add stagger via inline transition-delay based on index within parent? For menu cards re-rendered, add style.animationDelay on pop. For reveal sections fine.
Cart bump:
```js
function bump(){ cartEl.classList.remove('bump'); void cartEl.offsetWidth; cartEl.classList.add('bump'); }
```
Toast:
```js
function toast(t){ const d=document.createElement('div'); d.className='toast'; d.textContent=t; toasts.appendChild(d); setTimeout(()=>{d.style.opacity='0'; d.style.transform='translateY(8px)';},1800); setTimeout(()=>d.remove(),2200);}
```
Parallax:
```js
const hv=document.querySelector('.hero-visual');
if(hv && matchMedia('(pointer:fine)').matches){
hv.addEventListener('mousemove',e=>{ const r=hv.getBoundingClientRect(); const x=(e.clientX-r.left)/r.width-.5, y=(e.clientY-r.top)/r.height-.5; taco.style.transform=`rotate(${x*6}deg) translate(${x*10}px, ${y*8}px)`;});
hv.addEventListener('mouseleave',()=>{taco.style.transform='';});
}
```
But .taco has animation bob (transform) — conflict: animation overrides transform. Put bob on inner wrapper, parallax on outer. Structure: <div class="taco-wrap">(parallax) <svg class="taco">(bob). Chips float separately.
Menu filter: pills with data-f; on click set active, render(filter). Render builds HTML string; attach listeners via delegation on grid (click .add → find index via data-i).
Prices format: `$${p.toFixed(2)}`.
Card HTML:
```js
`<article class="card" style="animation-delay:${i*40}ms">
<div class="card-top">
<span class="food">${m.emoji}</span>
<span class="price">$${m.price.toFixed(2)}</span>
</div>
<h3>${m.name}</h3>
<p>${m.desc}</p>
<div class="card-foot">
<span class="spice" title="spice level">${m.spice? '🌶'.repeat(m.spice) : 'mild'}</span>
${m.tags.map(t=>`<span class="tag ${tagClass(t)}">${t}</span>`).join('')}
<button class="add" data-name="${m.name}">+ ADD</button>
</div>
</article>`
```
Tag class: t==='VEGAN'→'vegan'; 'NEW'→'new'; 'BESTSELLER'→'best'; 'hot'→'hot'; 'SWEET'→'sweet'. CSS colors.
Escape: names contain parentheses fine; data-name with quotes? Names have no quotes. OK.
Now hero copy:
Eyebrow: "SEOUL ✕ MEXICO CITY — STREET FOOD, FERMENTED"
H1: "KIMCHI<br><span class="loco">LOCO</span>" — with .loco color red and maybe rotated slightly + a squiggle underline SVG. Add small chili svg after? Keep: LOCO in red with yellow marker highlight behind: .loco{color:var(--red)} and add <span class="squig"> svg underline under LOCO. I'll add an SVG wavy underline positioned under via block. Simpler: .loco{position:relative} .loco::after{content:"";position:absolute;left:0;right:0;bottom:.02em;height:.14em;background:var(--yellow);z-index:-1}. Since h1 z-index... set .loco z-index:0 and ::after z-index:-1 works if .loco creates stacking context (position relative + z-index 0). Do that.
Sub: "Korean BBQ meets street tacos — 30-day kimchi, 24-hour bulgogi, and tortillas pressed to order. One truck, zero chill."
CTAs: "SEE THE MENU" → #menu (btn primary), "FIND THE TRUCK" → #truck (btn ghost).
Today chip below CTAs: `<div class="today-chip" id="todayChip">…</div>`.
Stats: 4.9★ rating / 2,300+ reviews → "4.9 / 2,300+ reviews"; "30-day kimchi"; "Est. 2019". Stats: [{b:"4.9★",s:"2,300+ Google reviews"},{b:"30 days",s:"house-fermented kimchi"},{b:"12",s:"things on the menu"}].
Star ★ is a text glyph — fine.
Marquee text: "KIMCHI LOCO ✶ KOREAN BBQ TACOS ✶ 30-DAY KIMCHI ✶ SEOUL ✕ MEXICO CITY ✶ OPEN LATE ✶ " repeated 3x per group, two groups.
Menu heading: eyebrow "THE LINEUP", h2 "PICK YOUR <span class=hl>POISON</span>" — fun: "PICK YOUR POISON" with hl marker. Sub: "Everything is made to order at the window. Spice levels are real — ask for 'gringo mild' at your own risk." Pills: ALL, TACOS, BURRITOS, SIDES, DRINKS, SWEET.
Schedule heading: eyebrow "FIND THE TRUCK", h2 "WHERE'S <span class=hl>LA LOCA</span> TODAY?" sub: "We post up all week...". Next-stop banner #nextStop. Grid #schedGrid.
Story: eyebrow "OUR STORY", h2 "ONE GRILL. TWO HOMELANDS." paragraphs: "Kimchi Loco started in 2019 when cousins Min-ji (Seoul) and Diego (Mexico City) parked one grill..." checklist items with ✓: "Kimchi fermented 30 days in-house", "Bulgogi marinated 24 hours", "Corn tortillas pressed every morning", "Gochujang everything". Frame: truck SVG with caption sticker "LA LOCA — OUR 1987 STEP VAN".
Gallery heading: "@KIMCHILOCO" h2 "STRAIGHT FROM THE <span class=hl>FEED</span>".
Reviews: eyebrow "WORD ON THE STREET", h2 "PEOPLE ARE <span class=hl>OBSESSED</span>". 3 cards:
- "I drove 40 minutes in the rain for the Seoul Fire Chicken. I'd drive 80." — Dana R., ★5
- "The kimchi quesadilla should be illegal. Crunchy, cheesy, funky — perfect." — Marcus T.
- "Best food truck in the city, no contest. The horchata fixes everything." — Priya S.
Newsletter: h2 "GET THE <span class=hl>LOCO DROP</span>", p "Secret menu items, truck locations and free-taco flash mobs — straight to your inbox, twice a month." form.
CTA band: h2 "HUNGRY YET?" p "Call ahead and skip the line — we'll have it bagged in 10." buttons: "📞 (555) 012-3456" tel link, "SEE THE SCHEDULE".
Footer columns as planned.
Now write CSS fully. Also focus styles for a11y: :focus-visible outline 3px dashed red offset.
Media queries:
```css
@media (max-width: 960px){ .hero-grid{grid-template-columns:1fr; } .hero-visual{order:-1?} keep visual after text; min-height smaller; story grid 1fr; }
@media (max-width: 820px){ .nav-links,.nav .btn{display:none} .burger{display:grid} }
```
Wait keep cart pill visible on mobile; hide links and maybe keep CTA hidden, show burger. Cart pill + burger right.
Burger button: 3 bars spans.
Mobile panel: absolute; contains links + order btn.
Also .stats wrap.
Check horizontal overflow sources: marquee width 110% inside .tilt{overflow:hidden}. Rotated marquee corners: .tilt padding vertical 14px, overflow hidden, margin-block -? The tilt wrapper overflow hidden clips rotated band edges — band width 110% left -5% so rotation doesn't reveal gaps at edges. Good.
Hero chips at left:-2% could overflow on mobile → body overflow-x hidden covers; also set .hero-visual overflow visible but hero overflow hidden — chips near edges inside hero, hero overflow:hidden might clip chip shadows — acceptable; better keep chips inside: position them within bounds (left:0 etc.) and on small screens hide chips? Keep, adjust with media query: chips font smaller.
Gallery tiles grid: repeat(4,1fr) → 2 cols ≤900 → 2 cols mobile fine (min 150px). Use auto-fit minmax(200px,1fr).
Reviews grid: repeat(auto-fit,minmax(260px,1fr)).
Footer grid: repeat(auto-fit,minmax(220px,1fr)).
Now, "first paint meaningful": hero full of content. Good.
Let me also add a subtle noise? skip.
Write the final code. I'll aim for clean, organized CSS. Let me draft the entire HTML now carefully, ensuring no syntax errors.
Also add `<meta name="description">`.
Font sizes: base body 16px; h1 clamp(3rem, 9vw, 6.5rem). At 1280 wide: 9vw=115px capped 104px (6.5rem). Two lines "KIMCHI" "LOCO" → tall; hero grid right visual ~ fits 800 height with nav 72: hero padding 56 top; h1 two lines ~ 104*0.95*2 ≈ 198 + eyebrow 40 + sub 80 + ctas 60 + chip 40 + stats 70 ≈ 490 + paddings ~ 610 < 728. Good.
Marquee item font-size 1.05rem, padding 14px.
Section spacing 88px.
Let me write out everything now. I'll write JS at end of body.
One more detail: `scroll-margin-top` for sections: 90px.
Buttons as <a class="btn"> for nav CTAs; tel link.
Cart pill: `<button class="cart-pill" id="cartPill">🛒 <span id="cartCount">0</span></button>` — clicking cart shows toast "Checkout at the window — this is a demo truck 😉"? Cute: toast "Order at the window — online checkout coming soon!". Use SVG cart? emoji fine.
Let me finalize tagClass mapping:
```js
const TAGCLASS={VEGAN:'vegan',NEW:'new',BESTSELLER:'best',hot:'hot',SWEET:'sweet'};
```
CSS: .tag{background:var(--yellow)} .tag.vegan{background:#BFE3B0} .tag.new{background:var(--pink)} .tag.hot{background:var(--red);color:#FFF6E9} .tag.best{background:var(--yellow)} .tag.sweet{background:#E3D4FF}.
Spice: if spice>0 show 🌶 repeated; else "mild" gray.
Filter cats: all, tacos, burritos, sides, drinks, sweet.
Pills labels: ALL, TACOS, BURRITOS, SIDES, DRINKS, SWEET.
Now schedule card HTML:
```js
WEEK.map(w=>{
const isToday = w.day===today;
const live = !w.rest && now within window;
return `<div class="day-card reveal ${isToday?'today':''} ${w.rest?'rest':''}">
<div class="day-top"><span class="day-name">${w.short}</span><span class="day-emoji">${w.emoji}</span></div>
<div class="day-loc">${w.name}</div>
<div class="day-sub">${w.loc}</div>
<div class="day-time">${w.time}</div>
${isToday?`<span class="day-badge">${live?'🔴 LIVE NOW':'TODAY'}</span>`:''}
</div>`
})
```
Live pulse: .today .day-badge animation blink.
Note: reveal class on dynamically added elements — IO observes existing at load; schedule rendered by JS before IO setup if script order: render schedule first, then set up IO querying all .reveal. Since script runs at end, dynamic content exists before IO init. Good — order in script: render menu, render schedule, then IO, then tickers.
Menu cards use animation pop (not reveal) since re-rendered; give them .pop class with keyframes; initial render animates too — nice.
CSS keyframes:
```css
@keyframes pop{from{opacity:0;transform:translateY(14px) scale(.97)}to{opacity:1;transform:none}}
@keyframes bob{0%,100%{transform:translateY(0) rotate(-1deg)}50%{transform:translateY(-12px) rotate(1.5deg)}}
@keyframes float{0%,100%{transform:translateY(0) rotate(var(--r,0deg))}50%{transform:translateY(-10px) rotate(var(--r,0deg))}}
@keyframes spin{to{transform:rotate(360deg)}}
@keyframes mq{to{transform:translateX(-50%)}}
@keyframes steamUp{0%{transform:translateY(8px);opacity:0}35%{opacity:.8}100%{transform:translateY(-16px);opacity:0}}
@keyframes bump{0%{transform:scale(1)}40%{transform:scale(1.25) rotate(-6deg)}100%{transform:scale(1)}}
@keyframes toastIn{from{opacity:0;transform:translateY(14px) scale(.95)}to{opacity:1;transform:none}}
@keyframes blink{0%,100%{opacity:1}50%{opacity:.55}}
```
Chip float uses --r custom prop per chip: .c1{--r:-8deg} etc. and animation float.
Steam: .steam path{animation:steamUp 2.8s ease-in-out infinite} .s2{animation-delay:.9s} .s3{animation-delay:1.8s}. transform-origin fine.
Note: animating transform on SVG path works in Chrome. OK.
Taco bob applied to svg.taco (transform) — parallax on wrapper .taco-wrap.
Now compose marquee groups:
```html
<div class="tilt"><div class="marquee"><div class="mq-track">
<div class="mq-group">SPAN×6</div><div class="mq-group" aria-hidden="true">SPAN×6</div>
</div></div></div>
```
Each span: `<span>KIMCHI LOCO ✶ KOREAN BBQ TACOS ✶ 30-DAY KIMCHI ✶ SEOUL ✕ MEXICO CITY ✶ OPEN LATE ✶ </span>` — group display:flex; spans nowrap. Track flex; animation mq 24s linear infinite; translateX(-50%) works if two identical groups each 50% of track width — with width:max-content and two equal groups, -50% shifts exactly one group. Good.
✶ and ✕ are dingbats — render as text glyphs (present in most fonts). Fine.
Newsletter success:
```html
<form id="dropForm" class="drop-form" novalidate>
<input type="email" id="dropEmail" placeholder="you@hungry.com" aria-label="Email address">
<button class="btn btn-primary" type="submit">SIGN ME UP</button>
</form>
<p class="drop-msg" id="dropMsg"></p>
```
On success: msg.textContent=`🌶 You're in! First drop lands Friday. (We sent a confirmation to ${v} — well, we would.)`; form reset; add class ok (green). On error: msg "That email looks undercooked — try again?" class err red; input shake animation class.
Shake keyframes.
CTA band buttons: `<a class="btn btn-paper" href="tel:+15550123456">📞 CALL (555) 012-3456</a>` and `<a class="btn btn-ghost-cream" href="#truck">SEE THE SCHEDULE</a>`. On red bg, ghost cream: border cream color cream, shadow ink? shadow should be ink: box-shadow 5px 5px 0 var(--ink) still visible on red. ok.
Nav CTA "ORDER AHEAD" → href="#menu"? It's order... link to #drop? Make it scroll to menu with toast? Just href="#menu". Fine, or tel:. Keep #menu.
Burger icon: button with 3 spans.
Mobile panel markup:
```html
<div class="mobile-panel" id="mobilePanel">
<a href="#menu">Menu</a><a href="#truck">Find the truck</a><a href="#story">Story</a><a href="#reviews">Reviews</a><a href="#drop">Loco Drop</a>
</div>
```
CSS: display none; .nav.open .mobile-panel{display:flex} flex-direction column; position absolute; top 100%; left 0; right 0; background cream; border-bottom 3px ink; padding 12px 4%; gap 4px; links padding 12px; font-weight 800; border-bottom 2px dashed? simple.
Header needs position sticky and .mobile-panel absolute → header position sticky acts as containing block (sticky is positioned) — yes absolute children position relative to it. Good.
JS burger toggle + close on link click.
Now hero visual chips positions:
.c1 top:4% left:0 "30-DAY KIMCHI" red bg
.c2 top:14% right:-2% → right:0 "GOCHUJANG GLAZE" yellow
.c3 bottom:10% left:2% "SMOKED OVER OAK" paper
.c4 bottom:2% right:6% "CORN TORTILLAS" pink
Set --r rotations.
Halo behind: .halo{background:var(--yellow)} with inner? Add second offset ring: .ring dashed red spinning.
Also add small "★ 4.9" sticker circle on visual top-right? We have stats on left. Enough.
Story section layout: grid 1fr 1fr gap 48; left: .truck-frame{border:3px solid ink; background:var(--sky)? bg #FFE9D6; border-radius 20px; box-shadow var(--shadow); padding: 18px; position relative} with sticker: .sticker{position:absolute; top:-16px; left:24px; background:var(--red); color:cream; border:3px solid ink; padding:6px 14px; font-weight:900; transform:rotate(-3deg); box-shadow:4px 4px 0 ink; border-radius:8px; font-size:.8rem; letter-spacing:.1em} "LA LOCA · EST. 2019". SVG inside.
Right: eyebrow, h2, two paragraphs, checklist ul with custom ✓ (li::before content "✓" in red circle? use span). li{display:flex;gap:10px;font-weight:700} li::before{content:"✓"; color:var(--red); font-weight:900}.
Gallery tiles:
```html
<div class="tiles">
<figure class="tile t1"><span class="tile-emoji">🌯</span><figcaption>Bulgogi burrito, mid-bite</figcaption></figure>
...
</div>
```
.tile{position:relative;border:3px solid ink;border-radius:16px;overflow:hidden;box-shadow:var(--shadow);height:230px;display:grid;place-items:center;transition:transform .2s}
.tile:hover{transform:rotate(-1.5deg) scale(1.03)}
.t1{background:linear-gradient(135deg,#FF8A3D,#E8442E)} .t2{background:linear-gradient(135deg,#FFC531,#FF7A1A)} .t3{background:linear-gradient(135deg,#58B368,#2F7D32)} .t4{background:linear-gradient(135deg,#8ED0F2,#4A90C2)}
.tile-emoji{font-size:4.2rem;filter:drop-shadow(4px 6px 0 rgba(34,26,19,.35))}
figcaption{position:absolute;bottom:0;left:0;right:0;background:var(--paper);border-top:3px solid ink;padding:8px 12px;font-weight:800;font-size:.85rem}
Reviews cards: .quote-card with .stars (color red, letter-spacing 3px) "★★★★★", p quote, footer name.
CTA band: .cta{background:var(--red);border-block:3px solid ink;color:var(--cream);text-align:center;padding:70px 0} h2 huge cream with text-shadow 4px 4px 0 var(--ink)? .disp with text-shadow. Buttons row.
Newsletter: .drop{background:var(--yellow);border-bottom:3px solid ink;padding:76px 0;text-align:center} form inline-flex gap 12; input{min-width:min(320px,70vw);padding:14px 18px;border:3px solid ink;border-radius:999px;font:inherit;font-weight:700;background:var(--paper)} focus outline. Button primary.
Footer: .footer{background:var(--ink);color:var(--cream);padding:60px 0 0} grid; h4 disp .95rem letter-spacing; links cream opacity .85 hover yellow; .foot-bottom{border-top:2px solid rgba(255,246,233,.2);margin-top:40px;padding:18px 0;display:flex;justify-content:space-between;flex-wrap:wrap;gap:8px;font-size:.85rem;opacity:.8}
Logo in footer: badge + name cream.
Now, the "hl" highlight: .hl{background:linear-gradient(transparent 58%, var(--yellow) 58%, var(--yellow) 94%, transparent 94%)} — on dark section (schedule heading cream text) yellow highlight behind cream text ok. In dark section maybe use red highlight: .hl-red? For schedule h2 on ink bg, highlight yellow still fine.
Schedule section: .schedule{background:var(--ink);color:var(--cream)} .schedule .sec-sub{color:rgba(255,246,233,.75)} eyebrow on dark: bg transparent border cream color cream? .eyebrow--dark{background:transparent;color:var(--cream);border-color:var(--cream);box-shadow:4px 4px 0 rgba(255,246,233,.25)}.
Next-stop banner: #nextStop{display:inline-flex;...;background:var(--yellow);color:var(--ink);border:3px solid var(--ink);box-shadow:5px 5px 0 var(--red);padding:12px 20px;border-radius:14px;font-weight:800;max-width:100%} inner b for countdown mono? Use font-variant-numeric: tabular-nums.
Day cards on dark: .day-card{background:var(--paper);color:var(--ink);border:3px solid var(--ink);border-radius:16px;padding:16px;box-shadow:6px 6px 0 var(--red);position:relative;min-height:150px;display:flex;flex-direction:column;gap:4px}
.today{background:var(--red);color:var(--cream);box-shadow:6px 6px 0 var(--yellow)}
.today .day-sub,.today .day-time{color:rgba(255,246,233,.85)}
.rest{background:transparent;color:var(--cream);border-style:dashed;border-color:rgba(255,246,233,.5);box-shadow:none}
.day-badge{position:absolute;top:-12px;right:12px;background:var(--yellow);color:var(--ink);border:3px solid var(--ink);font-size:.65rem;font-weight:900;letter-spacing:.08em;padding:3px 8px;border-radius:999px;animation:blink 1.6s infinite}
.today .day-badge{background:var(--ink);color:var(--yellow)}? LIVE red on red bad; use ink bg yellow text. ok.
Grid: #schedGrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:18px;margin-top:26px}
day-name disp 1.1rem; day-emoji font-size 1.5rem; day-loc font-weight 900; day-sub .85rem opacity .8; day-time .8rem font-weight 800 margin-top auto.
Alright — also add id anchors: menu, truck, story, feed, reviews, drop.
Nav links: MENU #menu, TRUCK #truck, STORY #story, REVIEWS #reviews, DROP #drop.
Time to write final file. Also include `::selection{background:var(--yellow)}` cute.
Focus-visible: outline:3px dashed var(--red); outline-offset:3px.
Reduced motion: @media (prefers-reduced-motion: reduce){*{animation:none!important;transition:none!important} html{scroll-behavior:auto}} nice touch.
Let me now also double check no forbidden APIs: no localStorage etc. We use none. No external requests. Fonts system. Good.
Write JS carefully:
```js
document.body.classList.add('js');
const $=s=>document.querySelector(s);
/* MENU */
const MENU=[...];
const TAGCLASS={VEGAN:'vegan',NEW:'new',BESTSELLER:'best',hot:'hot',SWEET:'sweet'};
const grid=$('#menuGrid');
function renderMenu(f='all'){
const items=MENU.filter(m=>f==='all'||m.cat===f);
grid.innerHTML=items.map((m,i)=>`
<article class="card" style="animation-delay:${i*45}ms">
<div class="card-top"><span class="food">${m.emoji}</span><span class="price">$${m.price.toFixed(2)}</span></div>
<h3>${m.name}</h3><p>${m.desc}</p>
<div class="card-foot">
<span class="spice">${m.spice?'🌶'.repeat(m.spice):'<em>mild</em>'}</span>
${m.tags.map(t=>`<span class="tag ${TAGCLASS[t]||''}">${t}</span>`).join('')}
<button class="add" data-name="${m.name}">+ ADD</button>
</div>
</article>`).join('');
}
renderMenu();
document.querySelectorAll('.pill').forEach(p=>p.addEventListener('click',()=>{
document.querySelectorAll('.pill').forEach(x=>x.classList.remove('active'));
p.classList.add('active'); renderMenu(p.dataset.f);
}));
grid.addEventListener('click',e=>{
const b=e.target.closest('.add'); if(!b) return;
cart++; $('#cartCount').textContent=cart;
const pill=$('#cartPill'); pill.classList.remove('bump'); void pill.offsetWidth; pill.classList.add('bump');
toast(`🌮 ${b.dataset.name} added to your order`);
});
```
Cart pill click: toast("Order at the window — online checkout is coming soon!").
Schedule:
```js
const WEEK=[...as above];
const schedGrid=$('#schedGrid');
function fmtT(d){let h=d.getHours(),m=d.getMinutes();const ap=h>=12?'PM':'AM';h=h%12||12;return h+':'+String(m).padStart(2,'0')+' '+ap;}
function renderSched(){
const now=new Date(), today=now.getDay();
schedGrid.innerHTML=WEEK.map(w=>{
const isT=w.day===today;
let live=false;
if(isT&&!w.rest){const st=new Date(now);st.setHours(w.h,w.m,0,0);const en=new Date(now);en.setHours(w.eh,w.em,0,0);live=now>=st&&now<=en;}
return `<div class="day-card ${w.rest?'rest':''} ${isT?'today':''}">
${isT?`<span class="day-badge">${live?'● LIVE NOW':'TODAY'}</span>`:''}
<div class="day-top"><span class="day-name">${w.short}</span><span class="day-emoji">${w.emoji}</span></div>
<div class="day-loc">${w.name}</div>
<div class="day-sub">${w.loc}</div>
<div class="day-time">${w.time}</div>
</div>`;
}).join('');
}
renderSched();
```
Next stop ticker:
```js
function nextCand(){
const now=new Date();const c=[];
for(let off=0;off<8;off++)for(const s of WEEK){
if(s.rest)continue;
const st=new Date(now.getFullYear(),now.getMonth(),now.getDate()+off,s.h,s.m,0);
if(st>now)c.push({s,st});
}
c.sort((a,b)=>a.st-b.st);return c[0];
}
const DAYN=['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
function tick(){
const now=new Date();
// live now?
let live=null;
for(const s of WEEK){ if(s.rest||s.day!==now.getDay())continue;
const st=new Date(now);st.setHours(s.h,s.m,0,0);const en=new Date(now);en.setHours(s.eh,s.em,0,0);
if(now>=st&&now<=en){live={s,st,en};break;}
}
const ns=$('#nextStop');
if(live){
ns.innerHTML=`<span class="dot"></span> LIVE NOW — <b>${live.s.name.toUpperCase()}</b> · ${live.s.loc} · until ${fmtT(live.en)}`;
}else{
const c=nextCand(); if(!c)return;
const diff=c.st-now;
const d=Math.floor(diff/864e5),h=Math.floor(diff/36e5)%24,m=Math.floor(diff/6e4)%60,s=Math.floor(diff/1e3)%60;
const dur=d>0?`${d}d ${h}h ${m}m`:`${h}h ${m}m ${s}s`;
const when=(c.st.getDate()===now.getDate())?'TODAY':DAYN[c.st.getDay()].toUpperCase();
ns.innerHTML=`NEXT STOP — <b>${c.s.name.toUpperCase()}</b> · ${c.s.loc} · ${when} ${fmtT(c.st)} · in <b class="cd">${dur}</b>`;
}
// hero chip
const chip=$('#todayChip');
if(live){chip.innerHTML=`🔴 <b>LIVE NOW</b> at ${live.s.loc} — until ${fmtT(live.en)}`;}
else{
const todays=WEEK.filter(w=>w.day===now.getDay()&&!w.rest).sort((a,b)=>a.h*60+a.m-(b.h*60+b.m));
const up=todays.find(w=>{const st=new Date(now);st.setHours(w.h,w.m,0,0);return st>now;});
if(up){chip.innerHTML=`📍 <b>TODAY:</b> ${up.name} · ${up.loc} · ${up.time}`;}
else{const c=nextCand();chip.innerHTML=`🌙 Rest day today — back <b>${DAYN[c.st.getDay()]}</b> at ${c.s.name}, ${fmtT(c.st)}`;}
}
}
tick(); setInterval(tick,1000);
```
Note: `.dot` live indicator: red circle with blink. `<span class="dot"></span>` CSS: width 10px height 10px bg red? On yellow banner, red dot blinking. ok.
Countdown element updates each second — the `in <b class="cd">` updates. Good.
Newsletter:
```js
const form=$('#dropForm'), email=$('#dropEmail'), msg=$('#dropMsg');
form.addEventListener('submit',e=>{
e.preventDefault();
const v=email.value.trim();
if(!/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(v)){
msg.textContent='Hmm, that email looks undercooked — try again?';
msg.className='drop-msg err'; email.classList.add('shake'); setTimeout(()=>email.classList.remove('shake'),450); email.focus(); return;
}
msg.textContent=`🌶 You're in! The next Loco Drop lands in ${v}'s inbox soon.`;
msg.className='drop-msg ok'; form.reset(); toast('Welcome to the Loco Drop 🌶');
});
```
Burger:
```js
const nav=$('#nav'), burger=$('#burger');
burger.addEventListener('click',()=>nav.classList.toggle('open'));
document.querySelectorAll('.mobile-panel a').forEach(a=>a.addEventListener('click',()=>nav.classList.remove('open')));
```
Reveal IO after renders.
Parallax as planned.
Cart pill click toast.
Footer year: `$('#year').textContent=new Date().getFullYear();`
Now CSS full write-up. Let me be careful with .btn variants:
```css
.btn{display:inline-flex;align-items:center;gap:8px;font-family:var(--disp);font-weight:900;text-transform:uppercase;letter-spacing:.03em;font-size:.95rem;padding:14px 24px;border:3px solid var(--ink);border-radius:14px;background:var(--paper);color:var(--ink);text-decoration:none;cursor:pointer;box-shadow:5px 5px 0 var(--ink);transition:transform .15s,box-shadow .15s;white-space:nowrap}
.btn:hover{transform:translate(-2px,-2px);box-shadow:8px 8px 0 var(--ink)}
.btn:active{transform:translate(3px,3px);box-shadow:1px 1px 0 var(--ink)}
.btn-primary{background:var(--red);color:var(--cream)}
.btn-yellow{background:var(--yellow)}
```
Cart pill:
```css
.cart-pill{display:inline-flex;align-items:center;gap:6px;font-weight:900;border:3px solid var(--ink);background:var(--paper);border-radius:999px;padding:8px 14px;cursor:pointer;box-shadow:3px 3px 0 var(--ink);font-size:.9rem}
.cart-pill.bump{animation:bump .4s}
```
Burger:
```css
.burger{display:none;width:44px;height:44px;border:3px solid var(--ink);border-radius:12px;background:var(--yellow);box-shadow:3px 3px 0 var(--ink);cursor:pointer;place-items:center}
.burger span{display:block;width:20px;height:3px;background:var(--ink);margin:2.5px 0;border-radius:2px}
@media(max-width:860px){.nav-links,.nav-cta{display:none}.burger{display:grid}}
```
Burger inner: wrap spans in a div? Use flex column: .burger{display:none;flex-direction:column;align-items:center;justify-content:center;gap:4px}. media → display:flex.
Mobile panel CSS:
```css
.mobile-panel{display:none;position:absolute;top:100%;left:0;right:0;background:var(--cream);border-bottom:3px solid var(--ink);padding:10px 4% 16px;flex-direction:column}
.nav.open .mobile-panel{display:flex}
.mobile-panel a{padding:12px 6px;font-weight:800;text-decoration:none;color:var(--ink);border-bottom:2px dashed rgba(34,26,19,.2);font-size:1.05rem}
.mobile-panel a:last-child{border-bottom:0}
```
Nav container: header#nav.nav > .container.nav-inner.
Hero specifics:
```css
.hero{padding:64px 0 84px;position:relative;overflow:hidden;background-image:radial-gradient(#EBD9BF 1.6px,transparent 1.7px);background-size:26px 26px}
.hero-grid{display:grid;grid-template-columns:1.08fr .92fr;gap:48px;align-items:center}
h1{font-family:var(--disp);font-weight:900;text-transform:uppercase;font-size:clamp(3.4rem,8.2vw,6.6rem);line-height:.92;letter-spacing:-.015em;margin:18px 0 20px}
.loco{color:var(--red);position:relative;z-index:0;display:inline-block}
.loco::after{content:"";position:absolute;left:-.04em;right:-.04em;bottom:.04em;height:.16em;background:var(--yellow);z-index:-1;border-radius:4px}
.hero-sub{font-size:1.12rem;font-weight:600;max-width:520px}
.hero-cta{display:flex;gap:14px;flex-wrap:wrap;margin-top:26px}
.today-chip{display:inline-flex;align-items:center;gap:8px;margin-top:22px;background:var(--paper);border:3px solid var(--ink);border-radius:999px;padding:8px 16px;font-weight:700;font-size:.9rem;box-shadow:4px 4px 0 var(--ink);max-width:100%}
.today-chip b{color:var(--red)}
.stats{display:flex;gap:28px;flex-wrap:wrap;margin-top:30px;padding-top:22px;border-top:3px dashed rgba(34,26,19,.3)}
.stat b{font-family:var(--disp);font-size:1.5rem;display:block;line-height:1}
.stat span{font-size:.82rem;font-weight:700;opacity:.75}
```
Hero visual:
```css
.hero-visual{position:relative;display:grid;place-items:center;min-height:420px}
.halo{position:absolute;width:min(430px,86%);aspect-ratio:1;border-radius:50%;background:var(--yellow);border:3px solid var(--ink)}
.halo::after{content:"";position:absolute;inset:14px;border-radius:50%;border:3px dashed rgba(34,26,19,.35)}
.ring{position:absolute;width:min(500px,100%);aspect-ratio:1;border-radius:50%;border:3px dashed var(--red);animation:spin 46s linear infinite;opacity:.7}
.taco-wrap{position:relative;width:min(470px,92%);transition:transform .25s ease-out}
svg.taco{width:100%;height:auto;animation:bob 5.5s ease-in-out infinite;filter:drop-shadow(12px 14px 0 rgba(34,26,19,.16))}
.chip{position:absolute;z-index:2;background:var(--paper);border:3px solid var(--ink);border-radius:999px;padding:7px 14px;font-weight:900;font-size:.75rem;letter-spacing:.09em;box-shadow:4px 4px 0 var(--ink);animation:float 4.5s ease-in-out infinite;white-space:nowrap}
.chip.c1{top:2%;left:-1%;background:var(--red);color:var(--cream);--r:-7deg}
.chip.c2{top:12%;right:-2%;background:var(--yellow);--r:6deg;animation-delay:1.2s}
.chip.c3{bottom:16%;left:-3%;--r:5deg;animation-delay:.6s}
.chip.c4{bottom:3%;right:4%;background:var(--pink);--r:-5deg;animation-delay:1.8s}
@media(max-width:560px){.chip{font-size:.62rem;padding:5px 10px}.c3{left:0}.c2{right:0}}
```
Marquee:
```css
.tilt{overflow:hidden;padding:20px 0;margin:-4px 0}
.marquee{width:112%;margin-left:-6%;background:var(--red);border-block:3px solid var(--ink);transform:rotate(-1.4deg)}
.mq-track{display:flex;width:max-content;animation:mq 26s linear infinite}
.mq-group{display:flex}
.mq-group span{white-space:nowrap;font-family:var(--disp);font-weight:900;text-transform:uppercase;color:var(--cream);font-size:1.05rem;letter-spacing:.06em;padding:13px 0}
```
Sections & heads:
```css
.section{padding:88px 0}
.eyebrow{display:inline-block;background:var(--paper);border:3px solid var(--ink);border-radius:999px;padding:7px 16px;font-weight:900;font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;box-shadow:4px 4px 0 var(--ink)}
.sec-head{margin-bottom:34px}
h2{font-family:var(--disp);font-weight:900;text-transform:uppercase;font-size:clamp(2.1rem,4.6vw,3.4rem);line-height:1;margin-top:16px;letter-spacing:-.01em}
.sec-sub{margin-top:12px;font-weight:600;max-width:560px;font-size:1.02rem}
.hl{background:linear-gradient(transparent 60%,var(--yellow) 60%,var(--yellow) 96%,transparent 96%)}
```
Menu:
```css
.pills{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:28px}
.pill{font:inherit;font-weight:800;font-size:.85rem;padding:9px 18px;border:3px solid var(--ink);background:var(--paper);border-radius:999px;cursor:pointer;box-shadow:4px 4px 0 var(--ink);transition:transform .12s,box-shadow .12s,background .12s}
.pill:hover{background:var(--yellow)}
.pill.active{background:var(--ink);color:var(--cream);transform:translate(2px,2px);box-shadow:2px 2px 0 var(--ink)}
.menu-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(255px,1fr));gap:22px}
.card{background:var(--paper);border:3px solid var(--ink);border-radius:18px;box-shadow:6px 6px 0 var(--ink);padding:20px;display:flex;flex-direction:column;gap:8px;animation:pop .4s both;transition:transform .18s,box-shadow .18s}
.card:hover{transform:translate(-3px,-3px) rotate(-.6deg);box-shadow:9px 9px 0 var(--ink)}
.card-top{display:flex;justify-content:space-between;align-items:flex-start}
.food{width:70px;height:70px;display:grid;place-items:center;font-size:2.4rem;background:var(--yellow);border:3px solid var(--ink);border-radius:50%;box-shadow:4px 4px 0 var(--ink);transform:rotate(-6deg)}
.price{font-family:var(--disp);font-weight:900;font-size:1.35rem;color:var(--red)}
.card h3{font-family:var(--disp);font-weight:900;text-transform:uppercase;font-size:1.08rem;letter-spacing:.01em}
.card p{font-size:.9rem;font-weight:500;opacity:.85;flex:1}
.card-foot{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin-top:6px}
.spice{font-size:.85rem}
.spice em{font-style:normal;opacity:.55;font-weight:700;font-size:.78rem}
.tag{font-size:.6rem;font-weight:900;letter-spacing:.08em;padding:3px 8px;border:2px solid var(--ink);border-radius:6px;background:var(--yellow)}
.tag.vegan{background:#BFE3B0}.tag.new{background:var(--pink)}.tag.hot{background:var(--red);color:var(--cream)}.tag.sweet{background:#E4D6FF}
.add{margin-left:auto;font:inherit;font-weight:900;font-size:.78rem;padding:7px 13px;border:3px solid var(--ink);border-radius:999px;background:var(--yellow);cursor:pointer;box-shadow:3px 3px 0 var(--ink);transition:transform .12s,box-shadow .12s}
.add:hover{background:var(--red);color:var(--cream)}
.add:active{transform:translate(2px,2px);box-shadow:1px 1px 0 var(--ink)}
```
Schedule dark section as planned.
Story:
```css
.story-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:52px;align-items:center}
.truck-frame{position:relative;background:#FFE7D2;border:3px solid var(--ink);border-radius:22px;box-shadow:8px 8px 0 var(--ink);padding:26px 18px 14px}
.sticker{position:absolute;top:-18px;left:26px;background:var(--red);color:var(--cream);border:3px solid var(--ink);padding:7px 14px;font-weight:900;font-size:.75rem;letter-spacing:.12em;border-radius:10px;transform:rotate(-3deg);box-shadow:4px 4px 0 var(--ink)}
.checks{list-style:none;margin-top:22px;display:grid;gap:12px}
.checks li{display:flex;gap:12px;font-weight:700;align-items:flex-start}
.checks li::before{content:"✓";flex:0 0 auto;width:26px;height:26px;display:grid;place-items:center;background:var(--green);color:#fff;border:3px solid var(--ink);border-radius:50%;font-weight:900;font-size:.8rem}
```
Green with ink border, white check.
Tiles & reviews & cta & drop & footer as planned.
Toasts:
```css
#toasts{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);z-index:200;display:flex;flex-direction:column;align-items:center;gap:8px;pointer-events:none;width:max-content;max-width:92vw}
.toast{background:var(--ink);color:var(--cream);border:3px solid var(--ink);outline:3px solid var(--cream)? no; padding:11px 20px;border-radius:999px;font-weight:800;font-size:.9rem;box-shadow:5px 5px 0 rgba(34,26,19,.3);animation:toastIn .25s ease both;transition:opacity .4s,transform .4s;text-align:center}
```
Shake:
```css
@keyframes shake{0%,100%{transform:translateX(0)}25%{transform:translateX(-6px)}75%{transform:translateX(6px)}}
.shake{animation:shake .4s}
.drop-msg{margin-top:14px;font-weight:800;min-height:1.4em}
.drop-msg.err{color:var(--red-d)}
.drop-msg.ok{color:#2c6e27}
```
Drop form:
```css
.drop-form{display:flex;gap:12px;justify-content:center;flex-wrap:wrap;margin-top:26px}
.drop-form input{font:inherit;font-weight:700;padding:14px 20px;border:3px solid var(--ink);border-radius:999px;background:var(--paper);min-width:min(320px,80vw);box-shadow:5px 5px 0 var(--ink)}
.drop-form input:focus{outline:3px dashed var(--red);outline-offset:3px}
```
CTA band:
```css
.cta{background:var(--red);border-block:3px solid var(--ink);color:var(--cream);text-align:center;padding:78px 0}
.cta h2{font-size:clamp(2.6rem,6vw,4.6rem);text-shadow:5px 5px 0 var(--ink);margin:0 0 14px}
.cta p{font-weight:700;font-size:1.05rem;opacity:.95}
.cta-btns{display:flex;gap:14px;justify-content:center;flex-wrap:wrap;margin-top:28px}
.btn-cream{background:var(--cream)}
.btn-outline-cream{background:transparent;color:var(--cream);border-color:var(--cream);box-shadow:5px 5px 0 var(--ink)}
.btn-outline-cream:hover{box-shadow:8px 8px 0 var(--ink)}
```
Footer:
```css
.footer{background:var(--ink);color:var(--cream);padding:64px 0 0}
.foot-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:36px}
.footer h4{font-family:var(--disp);font-size:.95rem;letter-spacing:.12em;text-transform:uppercase;margin-bottom:14px;color:var(--yellow)}
.footer a{color:var(--cream);text-decoration:none;font-weight:600}
.footer a:hover{color:var(--yellow)}
.footer p,.footer li{font-size:.92rem;opacity:.85}
.footer ul{list-style:none;display:grid;gap:8px}
.foot-brand{display:flex;align-items:center;gap:10px;font-family:var(--disp);font-weight:900;font-size:1.3rem;text-transform:uppercase;margin-bottom:12px}
.foot-bottom{margin-top:46px;border-top:2px solid rgba(255,246,233,.18);padding:18px 0;display:flex;justify-content:space-between;gap:10px;flex-wrap:wrap;font-size:.82rem;opacity:.75}
```
Logo badge SVG chili (small):
```html
<span class="logo-badge"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true"><path d="M19.5 4.5c.3-1.2-.6-2.3-1.8-2.1C13 3.2 8.6 6 6.4 10.2 4.6 13.6 4 17 4.6 19.4c.2.8 1.2 1 1.7.3 1.5-2.2 3.4-3.4 5.6-4.1 3.9-1.2 6.9-4.6 7.6-11.1z" fill="#FFF6E9"/><path d="M18.6 2.6c1-.6 2.3-.2 2.7.8" fill="none" stroke="#7CB342" stroke-width="2" stroke-linecap="round"/></svg></span>
```
Hmm chili shape rough; fine as abstract pepper. Actually simpler: use a star or "K"? Let me draw a simple taco icon in badge: semicircle shell with filling dots:
```html
<svg viewBox="0 0 24 24"><path d="M3 16a9 9 0 0 1 18 0z" fill="#FFC531" stroke="#221A13" stroke-width="1.6"/><circle cx="8" cy="10" r="1.6" fill="#E8442E"/><circle cx="12" cy="8.5" r="1.6" fill="#3F8F3A"/><circle cx="16" cy="10" r="1.6" fill="#E8442E"/></svg>
```
Taco: half-circle shell (flat top at y=16? path M3 16 a9 9 0 0 1 18 0 z draws upper semicircle from (3,16) to (21,16) — that's dome; taco shell should be dome with fillings on top: circles above the dome line... circles at cy 8.5-10 are inside dome area (dome top at y=7). Fillings should peek above the flat top? A taco cross-section: dome shell with filling inside visible at top opening. Simplify: dome shell + filling circles sitting on the flat top edge (cy≈15): circles at (8,13.5),(12,12.5),(16,13.5) inside dome — looks like filled taco cross-section. Good enough for a 22px badge. Use that.
Badge CSS: .logo-badge{width:40px;height:40px;background:var(--red);border:3px solid var(--ink);border-radius:50%;display:grid;place-items:center;box-shadow:3px 3px 0 var(--ink)} svg inside.
Footer brand badge same.
OK, also add subtle "grain"? skip.
One more interactive candy: clicking logo scrolls top (href="#top", body id? add id="top" to header). fine.
Let me make sure the schedule "LIVE NOW" dot CSS: .dot{display:inline-block;width:10px;height:10px;border-radius:50%;background:var(--red);margin-right:6px;animation:blink 1.2s infinite}.
#nextStop is a div with class next-banner; content set via innerHTML each second — recreating spans each second resets blink animation; acceptable but flickery. Better: structure static spans, update text nodes:
```html
<div class="next-banner" id="nextStop"><span id="nsText">…</span></div>
```
Just set textContent of #nsText with plain text (no HTML). Use textContent: `LIVE NOW — BRUNCH CLUB · Riverside Park · until 3:00 PM` / `NEXT STOP — DOWNTOWN · 5th & Main Plaza · TODAY 11:30 AM · in 2h 14m 09s`. Simpler and no flicker. Prefix emoji 🔴/⏰ in text. Good — use textContent.
Hero chip similar: set innerHTML once per minute? It changes rarely; but tick every second rewrites innerHTML → animations inside none, fine. Keep innerHTML for chip (has <b>). It rewrites every second — no visual issue since no animation on chip. OK.
Actually tick() every second re-renders chip innerHTML — fine.
Edge: WEEK times — ensure "today" logic uses local time. Fine.
Now let me also handle `renderSched` today highlight: on load only (static). Fine.
Reveal: add .reveal to section heads, cards containers? Cards animate via pop already. Add reveal to: sec-heads, truck-frame, story-copy, tiles, quote-cards, drop inner, cta inner. I'll sprinkle class="reveal" in HTML.
IO with rootMargin '0px 0px -40px'.
Also `.js .reveal{...}` gating:
```css
.js .reveal{opacity:0;transform:translateY(26px);transition:opacity .65s ease,transform .65s ease}
.js .reveal.in{opacity:1;transform:none}
```
Now assemble the marquee spans (6 per group):
Text unit: "KIMCHI LOCO ✶ KOREAN BBQ TACOS ✶ 30-DAY KIMCHI ✶ SEOUL ✕ MEXICO CITY ✶ PRESSED-TO-ORDER TORTILLAS ✶ OPEN LATE ✶ " — repeat 3× per group to ensure width > viewport: each unit ~ 90 chars * ~11px ≈ 1000px; 3 units ≈ 3000px > 1280. Good. I'll write unit 3 times per group via 3 spans or one span with repeated text. Use one span containing text repeated 3 times? Simpler: 3 spans per group, identical content.
Write it as: `<span>KIMCHI LOCO ✶ KOREAN BBQ TACOS ✶ 30-DAY KIMCHI ✶ SEOUL ✕ MEXICO CITY ✶ OPEN LATE ✶ </span>` ×3 per group, ×2 groups. I'll literally repeat.
Menu section header row with pills below.
Also add small note under menu: "🌶 = spice level · Everything gluten-free tortillas available · Ask about the secret menu". Put as .menu-note.
Now finalize copy for story paragraphs:
"Kimchi Loco started in 2019 when cousins Min-ji from Seoul and Diego from Mexico City parked one grill, one cooler of 30-day kimchi, and a line of hungry people around the block. The line never left."
"Everything is cooked at the window: bulgogi marinated overnight, tortillas pressed every morning, kimchi fermented in the back of the truck (yes, really). Seoul flavor, Mexican soul — no fusion clichés, just really good street food."
Checklist: "Kimchi fermented 30 days in-house", "Bulgogi marinated 24 hours", "Corn tortillas pressed every morning", "Gochujang in literally everything".
Gallery captions: "Bulgogi burrito, mid-bite 🌯", "Seoul fries, extra kimchi mayo 🍟", "Day 30 kimchi, perfectly funky 🌶", "Friday night market chaos 🎡".
Reviews:
1. ★★★★★ "I drove 40 minutes in the rain for the Seoul Fire Chicken taco. I'd drive 80." — Dana R. · Regulars since day one
2. ★★★★★ "The kimchi quesadilla should be illegal. Crunchy, cheesy, funky — a perfect little disc of joy." — Marcus T. · Food blogger
3. ★★★★★ "Best truck in the city, no contest. The horchata fixes whatever the gochujang broke." — Priya S. · Sunday brunch loyalist
Footer:
- Brand: badge + KIMCHI LOCO; p "Korean BBQ street tacos, fermented with love and served from a 1987 step van named La Loca."
- TRUCK: ul links: Menu #menu, Find the truck #truck, Our story #story, Reviews #reviews
- HOURS: "Tue–Thu · 11:30–2 & 5–10"? Keep simple: "See the weekly schedule — we move daily." + "Tue–Sun · from 11:30 AM" hmm. List: "MON — rest day", "TUE–THU — lunch + dinner", "FRI–SAT — till 11 PM", "SUN — brunch till 3".
- SAY HI: hello@kimchiloco.truck (mailto), (555) 012-3456 (tel), @kimchiloco everywhere.
Bottom: "© <span id=year></span> Kimchi Loco Food Truck Co." + "Made with gochujang & love 🌶"
Newsletter heading: eyebrow "NO SPAM, JUST TACOS", h2 "GET THE LOCO DROP", sub as planned.
Hero eyebrow: "SEOUL ✕ MEXICO CITY · EST. 2019".
Alright, also the h1: "KIMCHI" line 1, "LOCO" line 2 with .loco. Maybe add trailing "!"? "KIMCHI LOCO" fits.
Let me also add aria-labels where sensible.
Potential pitfall: `grid.innerHTML` with template containing `data-name="${m.name}"` — names contain parentheses fine.
Emoji in JS strings fine (UTF-8).
Now write everything. Also ensure `<meta viewport>`. Title: "Kimchi Loco 🌶 Korean Tacos Food Truck".
Let me write the complete final answer. I'll keep code tidy. Length is large but acceptable.
One more check on schedule grid on mobile: minmax(150px,1fr) with 7 cards → wraps 2 per row at 375px (375*0.92=345 → 2 cols of ~165). Good.
Menu grid at 375: minmax(255px,1fr) → 1 col. Good.
Hero at 375: h1 clamp min 3.4rem = 54px — "KIMCHI" 6 chars * ~0.62*54 ≈ 200px fits 345. Good.
Marquee rotate: .tilt padding 20px vertical; marquee height ~ 50px; rotated 1.4deg over 112% width (~1430px) → vertical offset at edges ≈ tan(1.4°)*715 ≈ 17px — within 20px padding. OK.
Also add `overflow:hidden` on .tilt? Yes set. And body overflow-x hidden as backup.
For the dark schedule section, hl highlight yellow behind cream text: readable. eyebrow dark variant.
Also next-banner margin-bottom before grid: wrap in .sched-top{display:flex;flex-direction:column;gap:8px} with label "THIS WEEK'S STOPS".
Write final HTML now.
For the truck SVG awning clipPath:
```html
<defs><clipPath id="awnClip"><path d="M66 102 L254 102 L242 66 L78 66 Z"/></clipPath></defs>
<path d="M66 102 L254 102 L242 66 L78 66 Z" fill="#FFF6E9" stroke="#221A13" stroke-width="6" stroke-linejoin="round"/>
<g clip-path="url(#awnClip)">
<rect x="70" y="60" width="24" height="50" fill="#E8442E"/>
<rect x="118" y="60" width="24" height="50" fill="#E8442E"/>
<rect x="166" y="60" width="24" height="50" fill="#E8442E"/>
<rect x="214" y="60" width="24" height="50" fill="#E8442E"/>
</g>
<path d="M66 102 q17 -20 34 0 q17 -20 34 0 q17 -20 34 0 q17 -20 34 0 q17 -20 34 0 q17 -20 34 0" fill="#E8442E" stroke="#221A13" stroke-width="5" stroke-linejoin="round"/>
```
Wait scallop path from x=66, six scallops of 34 → ends at 270, but awning bottom edge spans 66..254 (188 wide). 188/34 ≈ 5.5. Use 5 scallops of ~37.6? Use q with 37.6? Let's just do scallops spanning 66..254: 4 scallops of 47: "M66 102 q11.75 -18 23.5 0 ..." messy. Alternative: scallops as circles: place 6 circles r=17 at cy=102, cx=83,117,151,185,219,253 — overlapping circles create scalloped edge; fill red, stroke ink — but strokes between circles create lines. Use a single path: series of arcs: `M66 102 a17 17 0 0 1 34 0 a17 17 0 0 1 34 0 ...` each arc spans 34px: from 66: 66+34*5=236, +34=270 too far. Use r=16.5, span 33: 66+33*5=231... Let me just make awning bottom 66..254 = 188; 188/4 = 47 per scallop → r=23.5: `M66 102 a23.5 23.5 0 0 1 47 0 a23.5 23.5 0 0 1 47 0 a23.5 23.5 0 0 1 47 0 a23.5 23.5 0 0 1 47 0` ends at 254. Arc sweep flag: from left to right with bulge downward: a rx ry 0 0 1 dx 0 — sweep=1 gives clockwise → bulge down? Moving +x with sweep 1: arc curves... For a semicircle below the line (bulge down), from (66,102) to (113,102), sweep-flag 1 draws the arc on the... In SVG, sweep=1 means positive angle direction (clockwise in screen coords with y down). Going from left point to right point clockwise → passes below. Yes sweep=1 bulges downward. Good.
So scallop trim: `<path d="M66 102 a23.5 23.5 0 0 1 47 0 a23.5 23.5 0 0 1 47 0 a23.5 23.5 0 0 1 47 0 a23.5 23.5 0 0 1 47 0 L254 102 Z"?` Actually just the arcs chain forms the bottom edge; close along top? I want filled scallop band: path M66 102 (arcs to 254,102) then L254 96 L66 96 Z? Simpler: draw filled shape: M66 102 arcs... to 254,102, then line back along y=102? that's zero area. Instead make trim a strip: M66 96 L254 96 L254 102 (arcs back right-to-left?) complicated.
Easier: skip scallop trim; awning = cream trapezoid with red stripes and ink outline. Clean enough. Add small circles along bottom edge as "lights"? skip. Keep stripes clipped. Good — simpler and still cute.
Awning stripe rects: awning spans x 66..254 at bottom, 78..242 at top. Vertical stripes width 24 gap 24: x=70,118,166,214 width 24 → covers 70-94,118-142,166-190,214-238; clipped to trapezoid. Fine.
Roof sign: rect x=140 y=30 w=130 h=36 rx=8 fill yellow stroke ink; text "HOT TACOS" x=205 y=54 anchor middle size 17 weight 900 fill ink, font Arial Black. Legs: rect x=155 y=64 w=8 h=8 fill ink; x=245 same. Body top y=70 — legs 64..72 overlap roof. ok.
Window sign OPEN: place inside window: window x80 y102 w160 h76. Sign: rect x=118 y=110 w=84 h=26 rx=6 fill ink; text "OPEN" x=160 y=128 middle size 13 fill #FFC531 letter-spacing 3. Mini taco below-left inside window: path M96 162 q17 -22 34 0 Z fill #F8C766 stroke ink 4 → at y 140..162 within window (bottom 178). Drink: rect x=176 y=136 w=14 h=26 rx=4 fill #BFE3F0 stroke ink 4; straw line x1=180 y1=136 x2=186 y2=126 stroke red 4.
Body text: KIMCHI at x=330 y=142 size 30 fill cream, font-family "Arial Black"; LOCO x=330 y=174 size 30 fill #FFC531. Check width: "KIMCHI" 6 chars Arial Black 30px ≈ 6*24=144 → spans 258..402; body ends 420, window ends 240 — ok no overlap (258>240). Good. Add small text "KOREAN TACOS" x=330 y=196 size 11 fill cream letter-spacing 2 — y=196 is in yellow band (190..230) → cream on yellow low contrast; use ink fill: fill #221A13. Band top at 190; text y=200 size 11 fits (band 190-230, body bottom edge 230 with radius). ok.
Cab: path M420 100 h58 q22 0 30 22 l12 44 q6 22 -18 22 h-82 Z → from (420,100) right to (478,100), curve to (508,122)... let me recompute: h58 → (478,100). q22 0 30 22 → control (500,100) end (508,122). l12 44 → (520,166). q6 22 -18 22 → control (526,188) end (502,188)? q dx dy: q6 22 -18 22 → end (520-18,166+22)=(502,188). h-82 → (420,188). Z closes up to (420,100). Cab bottom at 188, body bottom 230 — cab shorter, fine (cab sits within body height? cab bottom 188 < body 230 — looks like cab is part of same body; wheel at 470,232 below). OK.
Window: path M436 116 h36 q14 0 19 14 l7 24 h-62 Z fill sky stroke ink 5. From (436,116) h36→(472,116), q→(491,130), l7 24→(498,154), h-62→(436,154), Z. Good.
Door seam: line x1=466 y1=120 x2=466 y2=184 stroke ink 4. Handle: small rect? skip.
Headlight: circle cx=512 cy=172 r=9 — cab right edge ~502-520 region; cx 512 ok within.
Bumper: line 500,206 → 524,206? cab bottom 188... bumper below: line x1=498 y1=196 x2=522 y2=196 stroke ink 6 round. eh fine.
Wheels: cx 130 & 470, cy 232, r 30 outer ink, r 12 cream. Also wheel arch over rear wheel? skip.
Stripe band path: M40 190 h380 v22 a20 20 0 0 1 -20 20 H60 a20 20 0 0 1 -20 -20 Z — check: start (40,190), h380 → (420,190), v22 → (420,212), arc to (400,232) with r20 sweep 1 (bulge outward bottom-right corner) — body rx=20 so corner matches. H60 → (60,232), arc to (40,212), Z → up to (40,190). Good, fill yellow stroke ink 6. But stroke will draw over body edges — fine, it's a band with outline. However body's own stroke at sides y190..230 remains — double lines, acceptable.
Actually body rect stroke 6 centered on edge; band overlays bottom part. Looks like yellow skirt. Good.
Ground: line x1=24 y1=286 x2=536 y2=286 stroke ink 5 linecap round, plus small dashes? solid fine. Shadow ellipse under truck: cx=280 cy=284 rx=240 ry=12 fill #E8D5BC behind truck (draw first).
Also little steam/spark near window? skip.
Truck svg width 100% inside frame.
Taco SVG plate: adjust numbers as decided: plate ellipse cy=292 rx=205 ry=22 fill #FFFDF6 stroke ink 5; inner ellipse cy=288 rx=165 ry=13 fill #F3E4CE; shadow ellipse cx=230 cy=280 rx=140 ry=10 fill #E9D2B4. Taco outer bottom 272 + stroke 3 = 275 → sits just above shadow 280.
Lime at translate(52,268): overlaps plate left edge (plate spans 25..435) — lime on plate edge. ok. Chili at translate(408,262) rotate(-30): path drawn relative. Let me re-craft chili: simpler pepper: `<path d="M0 0 C14 2 24 -2 30 -12 C33 -17 28 -21 24 -17 C16 -8 8 -4 -2 -3 Z" fill="#E8442E" stroke="#221A13" stroke-width="4" stroke-linejoin="round"/>` plus stem `<path d="M26 -16 q6 -6 12 -3" stroke="#3F8F3A" stroke-width="6" fill="none" stroke-linecap="round"/>`. At translate(400,270). Rough but fine at small size.
Steam paths as before at y up to ~14: M175 84 q12 -16 0 -32 q-10 -14 2 -28 → top at 84-32-28=24. viewBox height 340, fine.
Fillings top: kimchi rect y=104 → fine below steam.
Everything within viewBox 0 0 460 340: plate bottom 292+22=314 ok; chili at translate(400,270) extends to ~x 430, y 250 — ok.
Now, hero visual min-height 420 and halo 430 — at mobile 375, halo min(430, 86%) = 322 fine.
Alright, also add "back to top" link in footer bottom? skip.
Potential issue: `.js .reveal` initial hidden — if IO unsupported (ancient) content hidden; Chrome fine.
Also ensure script wrapped in DOMContentLoaded? Script at end of body — DOM ready. Fine.
Let me now also handle `.nav` id: `<header class="nav" id="nav">`.
Cart pill in nav-inner: after links: `<button class="cart-pill" id="cartPill" aria-label="Your order">🧾 <span id="cartCount">0</span></button>` then `<a class="btn btn-primary nav-cta" href="#menu">Order ahead</a>` then burger button. Order: links (margin-left:auto), cart, cta, burger.
CSS: .nav-inner .nav-links{margin-left:auto}.
Mobile panel placed inside header after nav-inner.
Write final code. Also `::selection{background:var(--yellow);color:var(--ink)}`.
Let me count sections ids: hero (no id needed), menu, truck, story, feed, reviews, drop. Nav links: Menu #menu, Truck #truck, Story #story, Reviews #reviews, Drop #drop. Mobile same.
Also gallery section id="feed" not in nav — fine.
Final check on forbidden things: no alert/confirm/prompt/open/localStorage — none. No external URLs — none (fonts system). tel: and mailto: links are fine (not network requests; they're protocols — allowed, they don't fetch). href="#..." fine.
Write it.
Also small detail: `scroll-behavior:smooth` plus anchor offsets via scroll-margin-top on sections: `section[id],div[id]{scroll-margin-top:92px}` simpler: `[id]{scroll-margin-top:92px}`.
Now produce final answer: exactly one ```html code block.
Let me write out the full code mentally ensuring correctness, then output.
JS detail: `'🌶'.repeat(m.spice)` fine.
In renderMenu, `m.tags.map(...)` with TAGCLASS lookup: TAGCLASS[t] may be undefined → class "" ok.
Pills markup:
```html
<div class="pills" id="pills">
<button class="pill active" data-f="all">All</button>
<button class="pill" data-f="tacos">Tacos</button>
<button class="pill" data-f="burritos">Burritos</button>
<button class="pill" data-f="sides">Sides</button>
<button class="pill" data-f="drinks">Drinks</button>
<button class="pill" data-f="sweet">Sweet</button>
</div>
```
Uppercase via CSS text-transform.
Menu note under grid: `<p class="menu-note">🌶 = heat level · Corn or flour tortillas · Ask about today's secret menu</p>`.
Schedule section markup:
```html
<section class="section schedule" id="truck">
<div class="container">
<div class="sec-head reveal">
<span class="eyebrow eyebrow-dark">Find the truck</span>
<h2>Where's <span class="hl">La Loca</span> today?</h2>
<p class="sec-sub">One truck, seven stops a week...</p>
</div>
<div class="next-banner reveal" id="nextStop"><span id="nsText">Loading tonight's stop…</span></div>
<div id="schedGrid"></div>
</div>
</section>
```
next-banner CSS: display:inline-block;background:var(--yellow);color:var(--ink);border:3px solid var(--ink);box-shadow:6px 6px 0 var(--red);padding:13px 20px;border-radius:14px;font-weight:800;margin-bottom:26px;font-variant-numeric:tabular-nums; max-width:100%.
On dark bg, border ink invisible-ish; use border cream? box-shadow red pops. Set border:3px solid var(--ink) — against ink bg invisible, fine since yellow fill defines shape; add outline? keep, plus shadow red visible. OK.
eyebrow-dark: background:transparent;color:var(--cream);border-color:var(--cream);box-shadow:4px 4px 0 rgba(255,246,233,.25).
sec-sub in dark: color rgba cream .75 — add .schedule .sec-sub{color:rgba(255,246,233,.75)}.
Story section id="story", feed id="feed", reviews id="reviews", drop id="drop".
CTA band after reviews; drop after cta? Order: reviews → cta → drop → footer. CTA red then drop yellow adjacent — both bordered, fine. Maybe drop before cta? Either. I'll do: reviews, drop (yellow), cta (red), footer (ink). Good flow: sign up then call.
Hmm CTA red directly above footer ink — nice.
Now write everything. Also add small floating pepper decorations in hero? enough.
Double-check `@keyframes mq{to{transform:translateX(-50%)}}` with track width max-content containing 2 groups → -50% = one group width. Good.
Also add `.mq-group span{padding:13px 18px 13px 0}`? include trailing space via nbsp inside text; add padding-right 18px per span for gap. I'll add `padding:13px 22px 13px 0`.
Alright — also the "js" class gating for reveal: script first line `document.body.classList.add('js')` — but CSS `.js .reveal` hides elements; script runs at end of body, so elements render visible briefly then hide then reveal — could cause flash. Better: add class via inline tiny script in <head>: `<script>document.documentElement.classList.add('js')</script>` and CSS `html.js .reveal{...}`. Do that — head script sets class before render. Allowed (inline).
Then IO adds .in.
Edge: elements already in viewport on load get .in immediately via IO (fires on observe). Good.
Write final output now. Also include a `<noscript>` fallback? Not needed since reveal gated on html.js which requires JS anyway.
Counting size — fine.
One more: hero CTA "SEE THE MENU" href="#menu" class "btn btn-primary"; "FIND THE TRUCK" href="#truck" class "btn".
Today chip initial content: "📍 Loading today's stop…" replaced by tick().
Stats markup:
```html
<div class="stats">
<div class="stat"><b>4.9★</b><span>2,300+ reviews</span></div>
<div class="stat"><b>30-day</b><span>house kimchi</span></div>
<div class="stat"><b>2019</b><span>grilling since</span></div>
</div>
```
OK writing final.
Also ensure `button` elements have `font-family:inherit` (buttons don't inherit by default) — set in reset: `button,input{font:inherit;color:inherit}`.
Reset: `*{box-sizing:border-box;margin:0;padding:0}` then `button,input{font:inherit}`.
Let me write the document.
Also: h3 in cards uses class? `.card h3` styled.
Footer hours list:
- MON — Rest & ferment day
- TUE–THU — 11:30 AM–2 PM & 5–10 PM → but schedule says Tue lunch, Wed night, Thu lunch... inconsistent. Simplify footer hours: "MON — rest day", "TUE–SUN — see schedule above", eh. Just: `<li>Mon — rest day 🌙</li><li>Tue–Sun — check the schedule</li><li>Fri & Sat — till 11 PM</li>`. Fine.
Contact: mailto:hello@kimchiloco.truck, tel:+15550123456, "@kimchiloco — everywhere".
Now output. I'll write carefully to avoid unbalanced tags.
Also remember: exactly one code block, no text outside. Let me produce it.