Food truck websiteOne-line
Qwen3.8 Flash
by QwenReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 5 min 52 s
- Cost
- $0.014
- Output tokens
- 28,767
- Spent thinking
- 4,555 tokens
- Speed
- 83.2 tok/s
- Console errors
- 0
- First token after
- 6.3 s
- First visible text after
- 1 min 28 s
- Prompt tokens
- 417
- Code size
- 62.8 KB
- Finish reason
- stop
- Served by
- Alibaba
- Model id
qwen/qwen3.8-flash- Reasoning sent
model default- Max output
- 64,000 tokens
- Generated
- Nov 11, 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 · 1788 lines
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Kimchi Loco — Korean Taco Food Truck</title>
<style>
:root {
--bg: #120c10;
--bg-2: #1a1116;
--ink: #fff7ed;
--muted: rgba(255, 247, 237, .66);
--red: #e63b2f;
--red-2: #ff5733;
--orange: #ff8a1e;
--yellow: #ffc63f;
--lime: #c9e84d;
--green: #4bb573;
--teal: #12a5b0;
--panel: rgba(255,255,255,.065);
--panel-strong: rgba(255,255,255,.11);
--line: rgba(255,255,255,.12);
--shadow: 0 18px 50px rgba(0,0,0,.45);
--radius: 22px;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
overflow-x: hidden;
background:
radial-gradient(900px 640px at 12% 8%, rgba(230,59,47,.22), transparent 60%),
radial-gradient(760px 520px at 88% 18%, rgba(255,138,30,.16), transparent 55%),
radial-gradient(820px 620px at 60% 110%, rgba(75,181,115,.12), transparent 60%),
linear-gradient(180deg, var(--bg), var(--bg-2) 45%, #120c10 100%);
color: var(--ink);
font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial,
"Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
button, input { font: inherit; }
button { cursor: pointer; }
.container {
width: min(1180px, calc(100% - 32px));
margin-inline: auto;
}
.sr-only {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden; clip: rect(0,0,0,0);
white-space: nowrap; border: 0;
}
.nav {
position: sticky;
top: 0;
z-index: 50;
backdrop-filter: blur(18px) saturate(140%);
background: linear-gradient(to bottom, rgba(18,12,16,.82), rgba(18,12,16,.42));
border-bottom: 1px solid rgba(255,255,255,.08);
}
.nav-inner {
display: flex;
align-items: center;
gap: 14px;
min-height: 70px;
padding-block: 10px;
}
.logo {
display: inline-flex;
align-items: center;
gap: 10px;
font-weight: 900;
letter-spacing: .04em;
text-transform: uppercase;
white-space: nowrap;
}
.logo-mark {
width: 38px; height: 38px;
display: grid; place-items: center;
border-radius: 14px;
background: linear-gradient(135deg, var(--yellow), var(--red) 55%, var(--orange));
color: #210c08;
font-size: 20px;
font-weight: 1000;
box-shadow: 0 0 22px rgba(255,198,63,.22), inset 0 1px 0 rgba(255,255,255,.4);
}
.logo small {
display: block;
font-size: 11px;
font-weight: 800;
color: var(--yellow);
letter-spacing: .18em;
margin-top: -4px;
}
.nav-links {
display: flex;
align-items: center;
gap: 4px;
margin-left: auto;
flex-wrap: wrap;
justify-content: flex-end;
}
.nav-links a {
padding: 10px 13px;
border-radius: 999px;
color: var(--muted);
font-weight: 800;
font-size: 13px;
letter-spacing: .03em;
text-transform: uppercase;
transition: background .22s ease, color .22s ease, transform .22s ease;
}
.nav-links a:hover { color: var(--ink); background: rgba(255,255,255,.08); transform: translateY(-1px); }
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 9px;
border: 0;
border-radius: 999px;
padding: 13px 22px;
font-weight: 950;
letter-spacing: .03em;
transition: transform .2s ease, box-shadow .2s ease, background .2s ease, border-color .2s ease;
white-space: nowrap;
}
.btn-primary {
background: linear-gradient(135deg, var(--red), var(--orange) 55%, var(--yellow));
color: #1f0703;
box-shadow: 0 14px 34px rgba(230,59,47,.28), inset 0 1px 0 rgba(255,255,255,.38);
}
.btn-primary:hover { transform: translateY(-2px) scale(1.02); box-shadow: 0 18px 44px rgba(255,138,30,.32); }
.btn-ghost {
background: rgba(255,255,255,.05);
color: var(--ink);
border: 1px solid rgba(255,255,255,.15);
}
.btn-ghost:hover { background: rgba(255,255,255,.1); transform: translateY(-2px); }
.btn-sm { padding: 10px 15px; font-size: 13px; }
.hero {
position: relative;
min-height: calc(100svh - 82px);
display: grid;
align-items: center;
padding-block: 42px 74px;
overflow: hidden;
}
.hero-grid {
display: grid;
grid-template-columns: minmax(320px, 1.05fr) minmax(320px, 1fr);
gap: clamp(22px, 5vw, 70px);
align-items: center;
}
.live-pill {
display: inline-flex;
align-items: center;
gap: 10px;
border-radius: 999px;
padding: 9px 16px;
background: rgba(75,181,115,.16);
border: 1px solid rgba(120,235,166,.24);
color: #d9ffe9;
font-weight: 950;
font-size: 13px;
letter-spacing: .08em;
text-transform: uppercase;
}
.dot {
width: 9px; height: 9px;
border-radius: 50%;
background: var(--lime);
box-shadow: 0 0 0 0 rgba(201,232,77,.72);
animation: pulse 1.8s infinite;
}
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(201,232,77,.7); }
70% { box-shadow: 0 0 0 12px rgba(201,232,77,0); }
100% { box-shadow: 0 0 0 0 rgba(201,232,77,0); }
}
h1 {
margin: 18px 0 14px;
font-size: clamp(44px, 8.4vw, 96px);
line-height: .86;
letter-spacing: -.05em;
font-weight: 1000;
}
.line {
display: block;
}
.line.korean {
font-size: .42em;
letter-spacing: .22em;
color: var(--yellow);
font-weight: 950;
text-transform: uppercase;
margin-bottom: 6px;
}
.grad {
background: linear-gradient(90deg, var(--yellow), var(--red-2) 38%, var(--lime) 72%, var(--yellow));
background-size: 220% 100%;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
animation: shimmer 6s linear infinite;
}
@keyframes shimmer {
0% { background-position: 0% 50%; }
100% { background-position: 220% 50%; }
}
.hero p {
max-width: 580px;
color: var(--muted);
font-size: clamp(16px, 2.3vw, 20px);
margin: 18px 0 26px;
}
.hero-actions {
display: flex;
gap: 12px;
flex-wrap: wrap;
align-items: center;
}
.hero-stats {
display: grid;
grid-template-columns: repeat(3, minmax(0,1fr));
gap: 12px;
margin-top: 34px;
max-width: 620px;
}
.stat {
padding: 14px 16px;
border-radius: 18px;
background: rgba(255,255,255,.045);
border: 1px solid rgba(255,255,255,.08);
box-shadow: inset 0 1px 0 rgba(255,255,255,.07);
}
.stat b {
display: block;
font-size: clamp(22px, 4vw, 34px);
line-height: 1;
letter-spacing: -.04em;
}
.stat span { color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: .09em; font-weight: 900; }
.hero-visual {
position: relative;
min-height: 430px;
display: grid;
place-items: center;
}
.truck-scene {
width: 100%;
max-width: 620px;
filter: drop-shadow(0 30px 40px rgba(0,0,0,.45));
animation: truckFloat 5.8s ease-in-out infinite;
}
@keyframes truckFloat {
0%, 100% { transform: translateY(0) rotate(-.15deg); }
50% { transform: translateY(-14px) rotate(.3deg); }
}
.smoke {
position: absolute;
inset: auto auto 20% 36%;
width: 280px;
height: 320px;
pointer-events: none;
opacity: .9;
}
.smoke i {
position: absolute;
width: 28px; height: 28px;
border-radius: 50%;
background: rgba(255,255,255,.22);
filter: blur(9px);
animation: rise 3.8s ease-in infinite;
}
.smoke i:nth-child(1){ left: 20px; animation-delay: 0s; }
.smoke i:nth-child(2){ left: 62px; animation-delay: .9s; transform: scale(1.4); }
.smoke i:nth-child(3){ left: 112px; animation-delay: 1.6s; transform: scale(.8); }
.smoke i:nth-child(4){ left: 156px; animation-delay: 2.3s; transform: scale(1.2); }
.smoke i:nth-child(5){ left: 100px; animation-delay: 3.0s; transform: scale(1.6); }
@keyframes rise {
0% { transform: translateY(0) scale(.8); opacity: 0; }
18% { opacity: .8; }
100% { transform: translateY(-180px) scale(2.2); opacity: 0; }
}
.ticker-band {
overflow: hidden;
border-block: 1px solid rgba(255,255,255,.08);
background: rgba(255,255,255,.03);
}
.ticker-track {
display: flex;
width: max-content;
gap: 34px;
padding: 12px 0;
animation: marquee 26s linear infinite;
}
.ticker-track span {
display: inline-flex;
align-items: center;
gap: 12px;
color: var(--muted);
font-weight: 950;
text-transform: uppercase;
letter-spacing: .14em;
font-size: 12px;
white-space: nowrap;
}
.ticker-track b { color: var(--yellow); }
.ticker-track .sep { color: var(--red); font-size: 18px; }
@keyframes marquee {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
section { padding-block: clamp(62px, 9vw, 106px); }
.section-head {
display: grid;
gap: 14px;
max-width: 880px;
margin-bottom: 34px;
}
.eyebrow {
font-size: 12px;
letter-spacing: .18em;
text-transform: uppercase;
font-weight: 1000;
color: var(--yellow);
}
.section-head h2 {
margin: 0;
font-size: clamp(34px, 6vw, 64px);
line-height: .92;
letter-spacing: -.045em;
font-weight: 1000;
}
.section-head p { margin: 0; color: var(--muted); font-size: 17px; }
.menu-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 16px;
}
.menu-card {
position: relative;
overflow: hidden;
padding: 22px;
border-radius: var(--radius);
background: linear-gradient(180deg, rgba(255,255,255,.08), rgba(255,255,255,.035));
border: 1px solid rgba(255,255,255,.09);
box-shadow: var(--shadow);
transition: transform .24s ease, border-color .24s ease, background .24s ease;
min-height: 235px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.menu-card:hover { transform: translateY(-8px); border-color: rgba(255,198,63,.35); }
.menu-card::after {
content: "";
position: absolute;
inset: -45%;
background: radial-gradient(circle, rgba(255,198,63,.12), transparent 50%);
opacity: 0;
transition: opacity .3s ease;
pointer-events: none;
}
.menu-card:hover::after { opacity: 1; }
.badge {
position: absolute;
right: 14px; top: 14px;
font-size: 10px;
letter-spacing: .12em;
text-transform: uppercase;
font-weight: 1000;
padding: 7px 10px;
border-radius: 999px;
background: rgba(255,198,63,.15);
color: var(--yellow);
border: 1px solid rgba(255,198,63,.28);
}
.badge.hot { background: rgba(230,59,47,.18); color: #ffd1cb; border-color: rgba(255,120,90,.34); }
.badge.green { background: rgba(75,181,115,.16); color: #c9f5dc; border-color: rgba(116,222,152,.28); }
.badge.blue { background: rgba(18,165,176,.18); color: #bdf6fb; border-color: rgba(68,212,226,.28); }
.menu-card h3 {
margin: 0 0 9px;
font-size: clamp(23px, 4vw, 34px);
line-height: 1.02;
letter-spacing: -.045em;
font-weight: 1000;
}
.menu-card p {
margin: 0 0 18px;
color: var(--muted);
font-size: 14.5px;
min-height: 63px;
}
.card-foot {
display: flex;
justify-content: space-between;
align-items: end;
gap: 14px;
margin-top: auto;
}
.price {
font-size: clamp(23px, 4vw, 34px);
font-weight: 1000;
letter-spacing: -.05em;
color: var(--yellow);
line-height: 1;
}
.spice {
display: flex;
align-items: center;
gap: 5px;
color: var(--muted);
font-size: 10.5px;
text-transform: uppercase;
letter-spacing: .11em;
font-weight: 1000;
}
.spice i {
width: 8px; height: 8px;
border-radius: 50%;
background: rgba(255,255,255,.18);
display: inline-block;
}
.spice i.on { background: var(--red); box-shadow: 0 0 10px rgba(230,59,47,.6); }
.build-wrap {
display: grid;
grid-template-columns: minmax(320px, 1.02fr) minmax(300px, .88fr);
gap: 18px;
align-items: start;
}
.panel {
border-radius: var(--radius);
background: linear-gradient(180deg, rgba(255,255,255,.09), rgba(255,255,255,.038));
border: 1px solid rgba(255,255,255,.1);
box-shadow: var(--shadow);
overflow: hidden;
}
.panel-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 18px 20px;
border-bottom: 1px solid rgba(255,255,255,.08);
background: rgba(0,0,0,.16);
}
.panel-head h3 {
margin: 0;
font-size: 22px;
letter-spacing: -.03em;
font-weight: 1000;
}
.panel-body { padding: 20px; }
.taco-stage {
position: relative;
background:
radial-gradient(circle at 50% 80%, rgba(255,198,63,.14), transparent 42%),
repeating-linear-gradient(90deg, rgba(255,255,255,.035) 0 1px, transparent 1px 44px),
repeating-linear-gradient(180deg, rgba(255,255,255,.035) 0 1px, transparent 1px 44px);
border-radius: 24px;
min-height: 330px;
display: grid;
place-items: center;
padding: 16px;
}
.taco-svg {
width: min(100%, 460px);
height: auto;
filter: drop-shadow(0 24px 28px rgba(0,0,0,.42));
}
.taco-texture {
position: absolute;
inset: auto 0 18px;
text-align: center;
color: rgba(255,255,255,.38);
font-size: 11px;
text-transform: uppercase;
letter-spacing: .18em;
font-weight: 1000;
}
.group-title {
margin: 0 0 10px;
font-size: 11px;
text-transform: uppercase;
letter-spacing: .16em;
color: var(--muted);
font-weight: 1000;
}
.choice-row {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 16px;
}
.opt {
border: 1px solid rgba(255,255,255,.14);
background: rgba(255,255,255,.04);
color: var(--ink);
border-radius: 999px;
padding: 10px 13px;
font-weight: 950;
font-size: 13px;
transition: transform .18s ease, background .18s ease, border-color .18s ease, color .18s ease;
}
.opt:hover { transform: translateY(-1px); border-color: rgba(255,198,63,.5); }
.opt.active {
background: linear-gradient(135deg, rgba(255,198,63,.96), rgba(230,59,47,.86));
color: #200803;
border-color: transparent;
box-shadow: 0 10px 24px rgba(230,59,47,.18);
}
.opt .plus {
opacity: .62;
font-size: 11px;
margin-left: 5px;
}
.opt.active .plus { opacity: .8; }
.order-meta {
display: grid;
gap: 12px;
margin-top: 14px;
padding: 16px;
border-radius: 20px;
background: rgba(0,0,0,.22);
border: 1px solid rgba(255,255,255,.08);
}
.order-line {
display: flex;
justify-content: space-between;
gap: 12px;
color: var(--muted);
font-size: 14px;
}
.order-line strong { color: var(--ink); }
.order-total {
font-size: 34px;
line-height: 1;
font-weight: 1000;
letter-spacing: -.05em;
color: var(--yellow);
}
.basket-list {
margin: 12px 0 16px;
display: grid;
gap: 9px;
}
.basket-item {
display: flex;
justify-content: space-between;
gap: 14px;
padding: 12px 14px;
border-radius: 15px;
background: rgba(255,255,255,.04);
border: 1px solid rgba(255,255,255,.08);
font-size: 13px;
}
.basket-item span:first-child { color: var(--muted); }
.basket-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.toast {
margin-top: 12px;
min-height: 20px;
color: #d8ffe8;
font-size: 13px;
font-weight: 800;
opacity: 0;
transform: translateY(6px);
transition: .24s ease;
}
.toast.show { opacity: 1; transform: translateY(0); }
.find-grid {
display: grid;
grid-template-columns: minmax(300px, .85fr) minmax(320px, 1.15fr);
gap: 18px;
}
.schedule {
padding: 8px;
}
.schedule-row {
display: grid;
grid-template-columns: 82px 1fr auto;
gap: 14px;
align-items: center;
padding: 14px 15px;
border-radius: 18px;
color: var(--muted);
transition: background .22s ease, border-color .22s ease, color .22s ease, transform .22s ease;
border: 1px solid transparent;
}
.schedule-row strong {
color: var(--ink);
letter-spacing: -.02em;
text-transform: uppercase;
font-size: 13px;
}
.schedule-row .time {
font-variant-numeric: tabular-nums;
font-size: 13px;
font-weight: 900;
}
.schedule-row.today {
background: rgba(255,198,63,.11);
border-color: rgba(255,198,63,.22);
color: #ffe7a4;
}
.schedule-row.closed { opacity: .55; }
.map-panel {
position: relative;
min-height: 360px;
border-radius: var(--radius);
overflow: hidden;
border: 1px solid rgba(255,255,255,.1);
box-shadow: var(--shadow);
background: #101318;
}
.map-svg {
width: 100%;
height: 100%;
min-height: 360px;
display: block;
}
.pin-pulse {
position: absolute;
left: 50%;
top: 45%;
transform: translate(-50%, -50%);
width: 16px; height: 16px;
border-radius: 50%;
background: var(--lime);
box-shadow: 0 0 0 0 rgba(201,232,77,.55);
animation: pinPulse 2.1s infinite;
}
@keyframes pinPulse {
0% { box-shadow: 0 0 0 0 rgba(201,232,77,.55), 0 0 0 6px rgba(255,198,63,.35); }
70% { box-shadow: 0 0 0 30px rgba(201,232,77,0), 0 0 0 18px rgba(255,198,63,0); }
100% { box-shadow: 0 0 0 52px rgba(201,232,77,0), 0 0 0 28px rgba(255,198,63,0); }
}
.map-overlay {
position: absolute;
left: 16px; right: 16px; bottom: 16px;
padding: 16px 18px;
border-radius: 20px;
background: rgba(16,13,17,.76);
border: 1px solid rgba(255,255,255,.12);
backdrop-filter: blur(14px);
display: flex;
justify-content: space-between;
gap: 16px;
align-items: end;
flex-wrap: wrap;
}
.map-overlay b { display: block; font-size: 17px; letter-spacing: -.025em; }
.map-overlay span { color: var(--muted); font-size: 13px; }
.reasons {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16px;
}
.reason {
padding: 26px;
border-radius: 24px;
background: rgba(255,255,255,.04);
border: 1px solid rgba(255,255,255,.08);
position: relative;
overflow: hidden;
}
.reason::before {
content: "";
position: absolute;
inset: auto -40px -60px auto;
width: 140px; height: 140px;
border-radius: 50%;
background: rgba(255,198,63,.08);
filter: blur(28px);
}
.icon {
width: 52px; height: 52px;
display: grid; place-items: center;
border-radius: 18px;
background: linear-gradient(135deg, rgba(255,198,63,.25), rgba(230,59,47,.2));
border: 1px solid rgba(255,198,63,.2);
font-size: 24px;
font-weight: 1000;
margin-bottom: 16px;
color: var(--yellow);
}
.reason h3 {
margin: 0 0 10px;
font-size: 27px;
letter-spacing: -.04em;
font-weight: 1000;
line-height: 1.02;
}
.reason p { margin: 0; color: var(--muted); }
.reviews {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 16px;
}
.review {
padding: 24px;
border-radius: 24px;
background: rgba(255,255,255,.045);
border: 1px solid rgba(255,255,255,.08);
}
.stars {
color: var(--yellow);
letter-spacing: .12em;
font-size: 18px;
margin-bottom: 12px;
}
.review p {
margin: 0 0 18px;
color: var(--ink);
font-size: 16px;
}
.who {
display: flex;
align-items: center;
gap: 12px;
color: var(--muted);
font-size: 13px;
font-weight: 900;
}
.avatar {
width: 38px; height: 38px;
display: grid; place-items: center;
border-radius: 50%;
background: linear-gradient(135deg, var(--teal), var(--green));
color: #071410;
font-weight: 1000;
}
.cta {
display: grid;
gap: 16px;
padding: clamp(24px, 5vw, 52px);
border-radius: 32px;
background:
radial-gradient(600px 320px at 8% 0%, rgba(255,198,63,.22), transparent 55%),
linear-gradient(135deg, rgba(230,59,47,.35), rgba(18,12,16,.65));
border: 1px solid rgba(255,255,255,.12);
box-shadow: var(--shadow);
align-items: center;
}
.cta-copy h2 {
margin: 0 0 10px;
font-size: clamp(32px, 6vw, 62px);
line-height: .92;
letter-spacing: -.05em;
font-weight: 1000;
}
.cta-copy p { margin: 0; color: var(--muted); font-size: 16px; }
.notify {
display: flex;
gap: 10px;
flex-wrap: wrap;
min-width: min(100%, 440px);
}
.notify input {
flex: 1 1 220px;
min-width: 0;
padding: 15px 18px;
border-radius: 999px;
border: 1px solid rgba(255,255,255,.18);
background: rgba(0,0,0,.25);
color: var(--ink);
outline: none;
transition: border-color .2s ease, box-shadow .2s ease;
}
.notify input:focus {
border-color: rgba(255,198,63,.7);
box-shadow: 0 0 0 4px rgba(255,198,63,.12);
}
.inline-note {
min-height: 22px;
font-size: 13px;
font-weight: 900;
color: #d9ffe9;
opacity: 0;
transform: translateY(5px);
transition: .24s ease;
}
.inline-note.show { opacity: 1; transform: translateY(0); }
footer {
padding-block: 34px 52px;
color: var(--muted);
border-top: 1px solid rgba(255,255,255,.07);
}
.foot {
display: flex;
justify-content: space-between;
align-items: center;
gap: 18px;
flex-wrap: wrap;
}
.socials {
display: flex;
gap: 8px;
align-items: center;
}
.socials span {
padding: 9px 12px;
border-radius: 999px;
background: rgba(255,255,255,.04);
border: 1px solid rgba(255,255,255,.08);
font-size: 12px;
font-weight: 1000;
letter-spacing: .08em;
color: var(--ink);
}
@media (max-width: 980px) {
.hero-grid, .build-wrap, .find-grid, .reasons { grid-template-columns: 1fr; }
.hero { padding-bottom: 48px; }
.hero-visual { min-height: 360px; }
.reasons { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
.nav-links { display: none; }
.hero-stats { grid-template-columns: 1fr; }
.section-head h2 { font-size: 40px; }
.panel-head { padding: 15px 16px; }
.panel-body { padding: 16px; }
.map-overlay { position: static; margin: 12px; }
.cta { border-radius: 24px; }
}
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: .01ms !important;
animation-iteration-count: 1 !important;
transition-duration: .01ms !important;
scroll-behavior: auto !important;
}
}
</style>
</head>
<body>
<nav class="nav">
<div class="container nav-inner">
<a class="logo" href="#top" aria-label="Kimchi Loco home">
<span class="logo-mark">K</span>
<span>
Kimchi Loco
<small>Seoul × Baja</small>
</span>
</a>
<div class="nav-links" aria-label="Primary navigation">
<a href="#menu">Menu</a>
<a href="#build">Build</a>
<a href="#find">Find Us</a>
<a href="#story">Story</a>
</div>
<a class="btn btn-primary btn-sm" href="#build">Build a Taco</a>
</div>
</nav>
<header class="hero" id="top">
<div class="container hero-grid">
<div>
<div class="live-pill"><span class="dot"></span> <span id="liveStatus">Fire lit · rolling soon</span></div>
<h1>
<span class="line korean">김치 로코</span>
<span class="line">Korean heat.</span>
<span class="line grad">Baja soul.</span>
</h1>
<p>
Handmade corn tortillas, slow-braised bulgogi, house-fermented kimchi, and gochujang crema
built on a tiny truck made for big lines. Come hungry. Leave spicy.
</p>
<div class="hero-actions">
<a class="btn btn-primary" href="#menu">See the Menu</a>
<a class="btn btn-ghost" href="#find">Where is the truck today?</a>
</div>
<div class="hero-stats">
<div class="stat"><b>4</b><span>Weekly stops</span></div>
<div class="stat"><b>9</b><span>Build-your-own toppings</span></div>
<div class="stat"><b>18</b><span>Min average line</span></div>
</div>
</div>
<div class="hero-visual" aria-hidden="true">
<div class="smoke"><i></i><i></i><i></i><i></i><i></i></div>
<svg class="truck-scene" viewBox="0 0 640 390">
<defs>
<linearGradient id="body" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#e73f2d" />
<stop offset="55%" stop-color="#ff7a1f" />
<stop offset="100%" stop-color="#ffc63f" />
</linearGradient>
<linearGradient id="window" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#53e6ff" />
<stop offset="100%" stop-color="#0d3b56" />
</linearGradient>
<linearGradient id="awning" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#fff3c7" />
<stop offset="100%" stop-color="#ffc63f" />
</linearGradient>
<filter id="soft" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="10" />
</filter>
</defs>
<ellipse cx="320" cy="338" rx="220" ry="24" fill="rgba(0,0,0,.34)" filter="url(#soft)" />
<!-- cargo box -->
<path d="M56 128 Q56 92 92 92 H384 V262 H78 Q56 262 56 240 Z" fill="url(#body)" stroke="#260c09" stroke-width="4" />
<rect x="92" y="86" width="310" height="18" rx="8" fill="#210c0a" />
<!-- cab -->
<path d="M384 120 H488 Q528 120 548 154 L586 220 Q594 238 574 246 H384 Z" fill="url(#body)" stroke="#260c09" stroke-width="4" />
<path d="M404 138 H478 Q506 138 518 166 L536 214 H404 Z" fill="url(#window)" stroke="#102739" stroke-width="4" />
<rect x="548" y="210" width="42" height="18" rx="8" fill="#ffdf70" />
<circle cx="568" cy="220" r="7" fill="#fff2aa" />
<!-- wheels -->
<circle cx="158" cy="276" r="40" fill="#0b0809" />
<circle cx="158" cy="276" r="18" fill="#887566" />
<circle cx="468" cy="276" r="40" fill="#0b0809" />
<circle cx="468" cy="276" r="18" fill="#887566" />
<!-- service window -->
<rect x="122" y="128" width="180" height="94" rx="16" fill="#131015" stroke="#fff0b8" stroke-width="5" />
<rect x="122" y="222" width="180" height="14" rx="7" fill="url(#awning)" />
<rect x="142" y="148" width="48" height="38" rx="10" fill="#ff9f34" />
<rect x="202" y="148" width="78" height="44" rx="10" fill="#4bb573" />
<circle cx="182" cy="210" r="11" fill="#e63b2f" />
<circle cx="212" cy="210" r="10" fill="#ffc63f" />
<circle cx="242" cy="210" r="9" fill="#c9e84d" />
<!-- awning / sign -->
<rect x="86" y="48" width="276" height="46" rx="16" fill="#210c0a" stroke="#ffc63f" stroke-width="3" />
<text x="224" y="79" text-anchor="middle" font-size="26" font-weight="1000" letter-spacing="1.5" fill="#fff6d8" font-family="ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Arial">KIMCHI LOCO</text>
<path d="M368 96 L434 96 L454 132 L368 132 Z" fill="url(#awning)" opacity=".88" stroke="#260c09" stroke-width="3" />
<path d="M86 96 L368 96 L368 112 L74 112 Z" fill="#260c09" opacity=".2" />
</svg>
</div>
</div>
</header>
<div class="ticker-band" aria-hidden="true">
<div class="ticker-track">
<span><b>Bulgogi Taco</b> <em class="sep">•</em></span>
<span><b>Kimchi Loco Classic</b> <em class="sep">•</em></span>
<span><b>Gochujang Carnitas</b> <em class="sep">•</em></span>
<span><b>Doenjang Pork</b> <em class="sep">•</em></span>
<span><b>Ssam Jackfruit</b> <em class="sep">•</em></span>
<span><b>Yuja Churros</b> <em class="sep">•</em></span>
<span><b>Born on the truck</b> <em class="sep">•</em></span>
<span><b>Folded by hand</b> <em class="sep">•</em></span>
<span><b>Bulgogi Taco</b> <em class="sep">•</em></span>
<span><b>Kimchi Loco Classic</b> <em class="sep">•</em></span>
<span><b>Gochujang Carnitas</b> <em class="sep">•</em></span>
<span><b>Doenjang Pork</b> <em class="sep">•</em></span>
<span><b>Ssam Jackfruit</b> <em class="sep">•</em></span>
<span><b>Yuja Churros</b> <em class="sep">•</em></span>
<span><b>Born on the truck</b> <em class="sep">•</em></span>
<span><b>Folded by hand</b> <em class="sep">•</em></span>
</div>
</div>
<main>
<section id="menu">
<div class="container">
<div class="section-head">
<div class="eyebrow">Best sellers · $9–11</div>
<h2>The menu we want you<br>to line up for.</h2>
<p>Every taco is finished on the flattop, dressed in real produce, and built around the house condiments. If you don’t know what to order, start with the classic.</p>
</div>
<div class="menu-grid">
<article class="menu-card">
<div>
<div class="badge">Staff pick</div>
<h3>Kimchi Loco Classic</h3>
<p>Pork belly, aged kimchi, cilantro, pickled onion, sesame crema.</p>
</div>
<div class="card-foot">
<div class="price">$9.50</div>
<div class="spice" aria-label="Spice level 3 out of 3"><span>Spice</span><i class="on"></i><i class="on"></i><i class="on"></i></div>
</div>
</article>
<article class="menu-card">
<div>
<h3>Bulgogi Taco</h3>
<p>Marinated ribeye, pear salsa, scallion, toasted sesame, gochujang crema.</p>
</div>
<div class="card-foot">
<div class="price">$10.50</div>
<div class="spice" aria-label="Spice level 2 out of 3"><span>Spice</span><i class="on"></i><i class="on"></i><i></i></div>
</div>
</article>
<article class="menu-card">
<div>
<div class="badge hot">Fire up</div>
<h3>Gochujang Carnitas</h3>
<p>Slow-confit shoulder, charred cabbage, lime, Korean chili oil.</p>
</div>
<div class="card-foot">
<div class="price">$10.00</div>
<div class="spice" aria-label="Spice level 3 out of 3"><span>Spice</span><i class="on"></i><i class="on"></i><i class="on"></i></div>
</div>
</article>
<article class="menu-card">
<div>
<div class="badge blue">Chef favorite</div>
<h3>Doenjang Pork</h3>
<p>Deep, savory fermented soy paste glaze with daikon relish.</p>
</div>
<div class="card-foot">
<div class="price">$9.75</div>
<div class="spice" aria-label="Spice level 1 out of 3"><span>Spice</span><i class="on"></i><i></i><i></i></div>
</div>
</article>
<article class="menu-card">
<div>
<div class="badge green">Vegan</div>
<h3>Ssam Jackfruit</h3>
<p>Smoky braised jackfruit, ssamjang aioli, lettuce wrap crunch.</p>
</div>
<div class="card-foot">
<div class="price">$9.00</div>
<div class="spice" aria-label="Spice level 1 out of 3"><span>Spice</span><i class="on"></i><i></i><i></i></div>
</div>
</article>
<article class="menu-card">
<div>
<h3>Yuja Churros</h3>
<p>Warm cinnamon-sugar sticks with yuzu-kijotu dip and toasted rice powder.</p>
</div>
<div class="card-foot">
<div class="price">$7.50</div>
<div class="spice"><span>Sweet</span><b>Yes</b></div>
</div>
</article>
</div>
</div>
</section>
<section id="build" style="padding-top: 0;">
<div class="container">
<div class="section-head">
<div class="eyebrow">Interactive</div>
<h2>Build your taco before you<br>get to the window.</h2>
<p>Pick a base, choose your protein, add toppings, and send it to the counter.</p>
</div>
<div class="build-wrap">
<div class="panel">
<div class="panel-head">
<h3>Build Station</h3>
<span class="badge green">Demo live</span>
</div>
<div class="panel-body">
<div class="taco-stage">
<svg class="taco-svg" viewBox="0 0 420 300" aria-label="Taco preview">
<defs>
<linearGradient id="cornShell" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#ffd873" />
<stop offset="70%" stop-color="#e8a93b" />
<stop offset="100%" stop-color="#c8811f" />
</linearGradient>
<linearGradient id="flourShell" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#ffe6c5" />
<stop offset="100%" stop-color="#d9ac74" />
</linearGradient>
<linearGradient id="lettuceShell" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#b9ec6c" />
<stop offset="100%" stop-color="#2f8a45" />
</linearGradient>
<filter id="blur2"><feGaussianBlur stdDeviation="5" /></filter>
</defs>
<!-- shadow -->
<ellipse cx="210" cy="266" rx="128" ry="18" fill="rgba(0,0,0,.34)" filter="url(#blur2)" />
<!-- sauce layers behind fillings -->
<g id="sauceGochujang" data-layer="sauce-gochujang">
<path d="M112 174 C134 158 164 182 190 166 C216 150 238 178 266 162 C288 150 304 170 310 168"
fill="none" stroke="#ff6b4a" stroke-width="10" stroke-linecap="round" opacity=".92" />
<path d="M118 192 C148 176 180 198 212 182 C244 166 268 192 300 180"
fill="none" stroke="#ffe6a1" stroke-width="6" stroke-linecap="round" opacity=".7" />
</g>
<g id="sauceSalsa" data-layer="sauce-salsa">
<path d="M118 178 C148 160 182 184 210 166 C238 148 262 180 298 164"
fill="none" stroke="#ff4b3e" stroke-width="9" stroke-linecap="round" opacity=".9" />
<path d="M126 194 C156 176 186 200 218 182 C252 164 274 194 302 182"
fill="none" stroke="#b9ff6a" stroke-width="5" stroke-linecap="round" opacity=".72" />
</g>
<g id="sauceNone" data-layer="sauce-none" style="display:none">
<path d="M118 178 C148 160 182 184 210 166 C238 148 262 180 298 164"
fill="none" stroke="#fff0c4" stroke-width="6" stroke-linecap="round" opacity=".3" />
</g>
<!-- proteins -->
<g data-layer="protein-bulgogi">
<path d="M110 168 C114 208 142 222 184 220 C226 218 294 202 302 160 C302 136 194 132 110 168Z"
fill="#b5572c" />
<path d="M132 196 c14-22 40-31 68-24 24 6 34-2 52 10" stroke="#792819" stroke-width="10" fill="none" stroke-linecap="round" opacity=".8"/>
<circle cx="160" cy="180" r="14" fill="#e7834a" />
<circle cx="228" cy="184" r="18" fill="#d56633" />
</g>
<g data-layer="protein-carnitas" style="display:none">
<path d="M106 168 C116 208 142 222 184 220 C226 218 294 202 304 162 C304 136 196 132 106 168Z"
fill="#e07f34" />
<path d="M140 202 c20-18 42-18 64-8 18 9 40 2 58 14" stroke="#6a3518" stroke-width="9" fill="none" stroke-linecap="round"/>
<path d="M126 186 c28-18 78-18 104-2" stroke="#ffd072" stroke-width="6" fill="none" stroke-linecap="round" opacity=".7"/>
</g>
<g data-layer="protein-doenjang" style="display:none">
<path d="M108 166 C118 208 146 224 188 222 C232 220 292 202 304 160 C304 136 194 132 108 166Z"
fill="#a6592e" />
<path d="M136 208 c20-18 46-18 68-6 18 10 42 2 58 14" stroke="#3e1d10" stroke-width="10" fill="none" stroke-linecap="round"/>
<circle cx="208" cy="180" r="16" fill="#cf7b38" />
</g>
<g data-layer="protein-jackfruit" style="display:none">
<path d="M110 168 C116 208 144 224 186 222 C228 220 292 202 304 160 C304 136 194 132 110 168Z"
fill="#d59d42" />
<path d="M146 204 c14-16 30-12 48-2 16 10 40 8 60-8" stroke="#84581b" stroke-width="9" fill="none" stroke-linecap="round"/>
<path d="M128 180 c26-10 52 2 74-2" stroke="#f2ca74" stroke-width="6" fill="none" stroke-linecap="round"/>
</g>
<g data-layer="protein-tofu" style="display:none">
<path d="M110 168 C116 208 144 224 186 222 C228 220 292 202 304 160 C304 136 194 132 110 168Z"
fill="#efd49b" />
<path d="M144 200 l26-18 26 20 28-24 32 14" stroke="#b2773d" stroke-width="9" fill="none" stroke-linecap="round"/>
<rect x="166" y="178" width="30" height="26" rx="7" fill="#f9e3ab" />
</g>
<!-- toppings -->
<g data-layer="topping-kimchi">
<rect x="132" y="166" width="56" height="18" rx="9" fill="#ff7b59" transform="rotate(-16 160 175)" />
<rect x="180" y="184" width="72" height="18" rx="9" fill="#e74b33" transform="rotate(-7 216 193)" />
<rect x="238" y="164" width="46" height="16" rx="8" fill="#ff8861" transform="rotate(13 261 172)" />
<circle cx="196" cy="172" r="4" fill="#ffcf8b" />
<circle cx="264" cy="188" r="4" fill="#ffcf8b" />
</g>
<g data-layer="topping-cilantro" style="display:none">
<circle cx="144" cy="160" r="8" fill="#57c667" />
<circle cx="186" cy="152" r="9" fill="#83e268" />
<circle cx="232" cy="158" r="8" fill="#45ac5b" />
<circle cx="274" cy="170" r="9" fill="#73d955" />
<circle cx="166" cy="190" r="6" fill="#a6ff75" />
</g>
<g data-layer="topping-onion" style="display:none">
<rect x="140" y="152" width="28" height="8" rx="4" fill="#fff7fb" transform="rotate(-20 154 156)" />
<rect x="200" y="160" width="34" height="8" rx="4" fill="#fff7fb" transform="rotate(-5 217 164)" />
<rect x="248" y="150" width="24" height="8" rx="4" fill="#ffeaf2" transform="rotate(18 260 154)" />
<rect x="170" y="192" width="26" height="8" rx="4" fill="#fff7fb" transform="rotate(7 183 196)" />
</g>
<g data-layer="topping-avocado" style="display:none">
<path d="M132 188 C138 160 182 150 196 170 C210 190 176 216 132 188Z" fill="#96d95b" stroke="#5d9f3c" stroke-width="5"/>
<path d="M228 190 C236 162 282 152 296 172 C310 192 274 216 228 190Z" fill="#b0eb74" stroke="#5d9f3c" stroke-width="5"/>
</g>
<g data-layer="topping-cheese" style="display:none">
<rect x="156" y="150" width="18" height="12" rx="4" fill="#ffd453" transform="rotate(-28 165 156)" />
<rect x="202" y="168" width="18" height="12" rx="4" fill="#fff0a3" transform="rotate(14 211 174)" />
<rect x="250" y="150" width="18" height="12" rx="4" fill="#ffd453" transform="rotate(26 259 156)" />
<rect x="188" y="194" width="18" height="12" rx="4" fill="#fff0a3" transform="rotate(-14 197 200)" />
</g>
<g data-layer="topping-jalapeno" style="display:none">
<circle cx="154" cy="178" r="10" fill="#3fa059" stroke="#62c25d" stroke-width="3"/>
<circle cx="218" cy="166" r="10" fill="#3fa059" stroke="#62c25d" stroke-width="3"/>
<circle cx="274" cy="186" r="10" fill="#3fa059" stroke="#62c25d" stroke-width="3"/>
</g>
<!-- outer shells -->
<g data-layer="base-corn">
<path d="M64 54 C30 140 68 228 186 228 C304 228 342 140 308 54 L278 54 C266 150 230 186 186 186 C142 186 106 150 94 54 Z"
fill="url(#cornShell)" stroke="#7b4c15" stroke-width="5" />
<path d="M94 74 C110 160 150 188 186 188" stroke="#fff6ca" stroke-width="7" fill="none" stroke-linecap="round" opacity=".32" />
<path d="M278 74 C262 160 222 188 186 188" stroke="#fff6ca" stroke-width="7" fill="none" stroke-linecap="round" opacity=".32" />
</g>
<g data-layer="base-flour" style="display:none">
<path d="M64 54 C30 140 68 228 186 228 C304 228 342 140 308 54 L278 54 C266 150 230 186 186 186 C142 186 106 150 94 54 Z"
fill="url(#flourShell)" stroke="#a07446" stroke-width="5" />
<path d="M116 94 C136 150 160 166 186 166 C212 166 236 150 256 94"
stroke="#c78c4f" stroke-width="8" fill="none" stroke-linecap="round" opacity=".28" />
</g>
<g data-layer="base-lettuce" style="display:none">
<path d="M64 54 C30 140 68 228 186 228 C304 228 342 140 308 54 L278 54 C266 150 230 186 186 186 C142 186 106 150 94 54 Z"
fill="url(#lettuceShell)" stroke="#2c6f38" stroke-width="5" />
<path d="M98 90 C124 154 148 178 186 180 C224 178 248 154 274 90"
stroke="#e9ffd6" stroke-width="7" fill="none" stroke-linecap="round" opacity=".24" />
</g>
</svg>
<div class="taco-texture">Live preview · built by hand</div>
</div>
<div style="margin-top:18px">
<h4 class="group-title">Base</h4>
<div class="choice-row" data-group="base">
<button class="opt" data-value="corn">Corn <span class="plus">$3.50</span></button>
<button class="opt" data-value="flour">Flour <span class="plus">$4.00</span></button>
<button class="opt" data-value="lettuce">Lettuce wrap <span class="plus">$4.50</span></button>
</div>
<h4 class="group-title">Protein</h4>
<div class="choice-row" data-group="protein">
<button class="opt" data-value="bulgogi">Bulgogi <span class="plus">+$4.00</span></button>
<button class="opt" data-value="carnitas">Carnitas <span class="plus">+$3.50</span></button>
<button class="opt" data-value="doenjang">Doenjang pork <span class="plus">+$3.75</span></button>
<button class="opt" data-value="jackfruit">Jackfruit <span class="plus">+$3.00</span></button>
<button class="opt" data-value="tofu">Crispy tofu <span class="plus">+$2.50</span></button>
</div>
<h4 class="group-title">Toppings</h4>
<div class="choice-row" data-group="topping">
<button class="opt" data-value="kimchi">House kimchi <span class="plus">+$1.50</span></button>
<button class="opt" data-value="cilantro">Cilantro <span class="plus">+$0.50</span></button>
<button class="opt" data-value="onion">Pickled onion <span class="plus">+$0.75</span></button>
<button class="opt" data-value="avocado">Avocado <span class="plus">+$1.75</span></button>
<button class="opt" data-value="cheese">Aged cheese <span class="plus">+$1.00</span></button>
<button class="opt" data-value="jalapeno">Jalapeño <span class="plus">+$0.75</span></button>
</div>
<h4 class="group-title">Sauce</h4>
<div class="choice-row" data-group="sauce">
<button class="opt" data-value="gochujang">Gochujang crema <span class="plus">+$1.00</span></button>
<button class="opt" data-value="salsa">Baja salsa <span class="plus">+$0.75</span></button>
<button class="opt" data-value="none">No sauce <span class="plus">$0</span></button>
</div>
</div>
</div>
</div>
<div class="panel">
<div class="panel-head">
<h3>Your Ticket</h3>
<span id="basketCount" class="badge">0 tacos</span>
</div>
<div class="panel-body">
<div class="order-meta">
<div class="order-line"><span>Base</span><strong id="lineBase">Corn</strong></div>
<div class="order-line"><span>Protein</span><strong id="lineProtein">Bulgogi</strong></div>
<div class="order-line"><span>Toppings</span><strong id="lineToppings">Kimchi, Cilantro</strong></div>
<div class="order-line"><span>Sauce</span><strong id="lineSauce">Gochujang crema</strong></div>
<div class="order-line"><span>Unit price</span><strong id="unitPrice">$9.50</strong></div>
<div class="order-line"><span>Basket total</span><span class="order-total" id="basketTotal">$0.00</span></div>
</div>
<div class="basket-list" id="basketList" aria-live="polite">
<div class="basket-item" style="color: var(--muted);">
<span>Order list</span><span>Empty for now</span>
</div>
</div>
<div class="basket-actions">
<button class="btn btn-primary" id="addBtn">Add to Order</button>
<button class="btn btn-ghost" id="clearBtn">Clear</button>
</div>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
</div>
</div>
</div>
</div>
</section>
<section id="find" style="padding-top: 0;">
<div class="container">
<div class="section-head">
<div class="eyebrow">On the road</div>
<h2>Find the truck.</h2>
<p>Kimchi Loco moves. This week’s rotation is below — the map and counter status update live with the current schedule.</p>
</div>
<div class="find-grid">
<div class="panel schedule" aria-label="Weekly schedule">
<div class="panel-head">
<h3>Weekly Rotation</h3>
<span class="badge blue">Auto</span>
</div>
<div class="panel-body" style="padding: 10px;">
<div id="scheduleRows"></div>
</div>
</div>
<div class="map-panel">
<svg class="map-svg" viewBox="0 0 920 460" aria-label="Abstract street map of current location">
<defs>
<pattern id="grid" width="44" height="44" patternUnits="userSpaceOnUse">
<path d="M44 0 H0 V44" fill="none" stroke="rgba(255,255,255,.06)" stroke-width="1" />
</pattern>
<linearGradient id="street" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#3a4653" />
<stop offset="100%" stop-color="#26303a" />
</linearGradient>
</defs>
<rect width="920" height="460" fill="#0d1117" />
<rect width="920" height="460" fill="url(#grid)" />
<rect x="70" y="70" width="260" height="120" rx="18" fill="#151c24" stroke="#24313f" stroke-width="3"/>
<rect x="570" y="60" width="250" height="150" rx="18" fill="#151c24" stroke="#24313f" stroke-width="3"/>
<rect x="130" y="270" width="220" height="130" rx="18" fill="#151c24" stroke="#24313f" stroke-width="3"/>
<rect x="550" y="270" width="300" height="130" rx="18" fill="#151c24" stroke="#24313f" stroke-width="3"/>
<rect x="0" y="208" width="920" height="58" fill="url(#street)" opacity=".9"/>
<rect x="452" y="0" width="58" height="460" fill="url(#street)" opacity=".9"/>
<path d="M0 237 H920" stroke="#ffd257" stroke-width="5" stroke-dasharray="28 22" opacity=".8"/>
<path d="M481 0 V460" stroke="#fff0b8" stroke-width="4" stroke-dasharray="24 18" opacity=".75"/>
<circle cx="481" cy="237" r="58" fill="rgba(255,198,63,.09)" />
<circle cx="481" cy="237" r="30" fill="rgba(255,198,63,.12)" />
<text x="481" y="248" text-anchor="middle" font-size="30" fill="#fff1c3" font-weight="1000" font-family="ui-sans-serif, system-ui">▲</text>
</svg>
<div class="pin-pulse" aria-hidden="true"></div>
<div class="map-overlay">
<div>
<b id="currentSpot">Check today’s stop</b>
<span id="currentStatus">Updating location…</span>
</div>
<a class="btn btn-ghost btn-sm" href="#menu">See what’s hot</a>
</div>
</div>
</div>
</div>
</section>
<section id="story">
<div class="container">
<div class="section-head">
<div class="eyebrow">Why it works</div>
<h2>Built for the curb,<br>not the gimmick.</h2>
<p>Korean tacos can be a mashup cliché. We made them a food truck obsession by focusing on ferments, char, acid, and texture — all served fast, from a small truck.</p>
</div>
<div class="reasons">
<article class="reason">
<div class="icon"> 발효 </div>
<h3>Ferment-forward</h3>
<p>The house kimchi is aged 10 days, the crema is cultured, and the salsa gets a little funk from doenjang at the right moment.</p>
</article>
<article class="reason">
<div class="icon"> 火 </div>
<h3>Live-fire tortillas</h3>
<p>Corn masa is pressed to order and kissed on the comal. You can smell it two blocks away — that’s the whole point.</p>
</article>
<article class="reason">
<div class="icon"> 🧡 </div>
<h3>Fast line, high care</h3>
<p>A tight menu means less waiting, better ingredients, and tacos that actually stay hot on the walk back to your car.</p>
</article>
</div>
</div>
</section>
<section style="padding-top: 0;">
<div class="container">
<div class="section-head">
<div class="eyebrow">People keep coming back</div>
<h2>Line talk.</h2>
</div>
<div class="reviews">
<article class="review">
<div class="stars">★★★★★</div>
<p>“The kimchi taco made me walk two blocks over for seconds. I’m not ashamed.”</p>
<div class="who"><span class="avatar">J</span> Jess · regular at Brewery District</div>
</article>
<article class="review">
<div class="stars">★★★★★</div>
<p>“Best late-night stop. The bulgogi taco is weirdly comforting in the most dangerous way.”</p>
<div class="who"><span class="avatar">O</span> Owen · night market crowd</div>
</article>
<article class="review">
<div class="stars">★★★★☆</div>
<p>“I came for the churros and stayed because the sauce list is criminally good.”</p>
<div class="who"><span class="avatar">R</span> Rachel · beach boardwalk</div>
</article>
</div>
</div>
</section>
<section style="padding-top: 0;">
<div class="container">
<div class="cta">
<div class="cta-copy">
<div class="eyebrow">Be first in line</div>
<h2>Get the daily drop.<br>We’ll tell you when<br>the truck is close.</h2>
<p>Short, spicy updates only. No spam. Just location, specials, and “it’s happening right now.”</p>
</div>
<form class="notify" id="notifyForm" novalidate>
<label class="sr-only" for="email">Email address</label>
<input id="email" type="email" placeholder="you@hungry.com" autocomplete="email" />
<button class="btn btn-primary" type="submit">Notify Me</button>
<div class="inline-note" id="notifyNote" aria-live="polite"></div>
</form>
</div>
</div>
</section>
</main>
<footer>
<div class="container foot">
<div>
<strong>Kimchi Loco</strong><br>
Korean taco food truck · Seoul heat, Baja coast<br>
<span style="opacity:.72">@kimchiloco · hello@kimchiloco.com</span>
</div>
<div class="socials" aria-label="Social channels">
<span>Instagram</span>
<span>TikTok</span>
<span>Text alerts</span>
</div>
</div>
</footer>
<script>
(() => {
const money = n => `$${n.toFixed(2)}`;
const baseData = {
corn: { name: 'Corn', price: 3.5, layer: 'base-corn' },
flour: { name: 'Flour', price: 4.0, layer: 'base-flour' },
lettuce: { name: 'Lettuce wrap', price: 4.5, layer: 'base-lettuce' }
};
const proteinData = {
bulgogi: { name: 'Bulgogi', price: 4.0, layer: 'protein-bulgogi' },
carnitas: { name: 'Gochujang carnitas', price: 3.5, layer: 'protein-carnitas' },
doenjang: { name: 'Doenjang pork', price: 3.75, layer: 'protein-doenjang' },
jackfruit: { name: 'Ssam jackfruit', price: 3.0, layer: 'protein-jackfruit' },
tofu: { name: 'Crispy tofu', price: 2.5, layer: 'protein-tofu' }
};
const toppingData = {
kimchi: { name: 'House kimchi', price: 1.5, layer: 'topping-kimchi' },
cilantro: { name: 'Cilantro', price: .5, layer: 'topping-cilantro' },
onion: { name: 'Pickled onion', price: .75, layer: 'topping-onion' },
avocado: { name: 'Avocado', price: 1.75, layer: 'topping-avocado' },
cheese: { name: 'Aged cheese', price: 1.0, layer: 'topping-cheese' },
jalapeno: { name: 'Jalapeño', price: .75, layer: 'topping-jalapeno' }
};
const sauceData = {
gochujang: { name: 'Gochujang crema', price: 1.0, layer: 'sauceGochujang' },
salsa: { name: 'Baja salsa', price: .75, layer: 'sauceSalsa' },
none: { name: 'No sauce', price: 0, layer: 'sauceNone' }
};
const state = {
base: 'corn',
protein: 'bulgogi',
toppings: new Set(['kimchi', 'cilantro']),
sauce: 'gochujang'
};
const order = [];
let userInteracted = false;
const lineBase = document.getElementById('lineBase');
const lineProtein = document.getElementById('lineProtein');
const lineToppings = document.getElementById('lineToppings');
const lineSauce = document.getElementById('lineSauce');
const unitPrice = document.getElementById('unitPrice');
const basketTotal = document.getElementById('basketTotal');
const basketList = document.getElementById('basketList');
const basketCount = document.getElementById('basketCount');
const toast = document.getElementById('toast');
function randomOf(list) {
return list[Math.floor(Math.random() * list.length)];
}
function setActiveButton(group, value) {
document.querySelectorAll(`[data-group="${group}"] .opt`).forEach(btn => {
btn.classList.toggle('active', btn.dataset.value === value);
});
}
function showLayer(id, visible) {
const el = document.getElementById(id);
if (el) el.style.display = visible ? '' : 'none';
}
function updateBuilderVisuals() {
Object.values(baseData).forEach(d => showLayer(d.layer, false));
Object.values(proteinData).forEach(d => showLayer(d.layer, false));
Object.values(toppingData).forEach(d => showLayer(d.layer, false));
Object.values(sauceData).forEach(d => showLayer(d.layer, false));
showLayer(baseData[state.base].layer, true);
showLayer(proteinData[state.protein].layer, true);
state.toppings.forEach(key => {
showLayer(toppingData[key].layer, true);
});
showLayer(sauceData[state.sauce].layer, true);
setActiveButton('base', state.base);
setActiveButton('protein', state.protein);
setActiveButton('sauce', state.sauce);
document.querySelectorAll('[data-group="topping"] .opt').forEach(btn => {
btn.classList.toggle('active', state.toppings.has(btn.dataset.value));
});
const toppings = [...state.toppings].map(t => toppingData[t].name);
lineBase.textContent = baseData[state.base].name;
lineProtein.textContent = proteinData[state.protein].name;
lineSauce.textContent = sauceData[state.sauce].name;
lineToppings.textContent = toppings.length ? toppings.join(', ') : 'None';
const total =
baseData[state.base].price +
proteinData[state.protein].price +
sauceData[state.sauce].price +
[...state.toppings].reduce((sum, t) => sum + toppingData[t].price, 0);
unitPrice.textContent = money(total);
renderBasket();
}
function renderBasket() {
basketCount.textContent = `${order.length} taco${order.length === 1 ? '' : 's'}`;
const sum = order.reduce((a, b) => a + b.price, 0);
basketTotal.textContent = money(sum);
if (!order.length) {
basketList.innerHTML = `
<div class="basket-item" style="color: var(--muted);">
<span>Order list</span><span>Empty for now</span>
</div>`;
return;
}
const visible = order.slice(-4).reverse();
basketList.innerHTML = visible.map(item => `
<div class="basket-item">
<span>${item.label}</span><strong>${money(item.price)}</strong>
</div>`).join('') + (order.length > 4 ? `
<div class="basket-item">
<span>+ ${order.length - 4} earlier tacos</span><span>in queue</span>
</div>` : '');
}
function showToast(message) {
toast.textContent = message;
toast.classList.add('show');
clearTimeout(showToast.t);
showToast.t = setTimeout(() => toast.classList.remove('show'), 1800);
}
function applyDemoChoices() {
state.base = randomOf(Object.keys(baseData));
state.protein = randomOf(Object.keys(proteinData));
state.sauce = randomOf(Object.keys(sauceData));
const toppingKeys = Object.keys(toppingData);
const shuffled = [...toppingKeys].sort(() => Math.random() - .5);
const count = 2 + Math.floor(Math.random() * 3);
state.toppings = new Set(shuffled.slice(0, count));
updateBuilderVisuals();
}
document.querySelectorAll('[data-group="base"] .opt').forEach(btn => {
btn.addEventListener('click', () => {
userInteracted = true;
state.base = btn.dataset.value;
updateBuilderVisuals();
});
});
document.querySelectorAll('[data-group="protein"] .opt').forEach(btn => {
btn.addEventListener('click', () => {
userInteracted = true;
state.protein = btn.dataset.value;
updateBuilderVisuals();
});
});
document.querySelectorAll('[data-group="sauce"] .opt').forEach(btn => {
btn.addEventListener('click', () => {
userInteracted = true;
state.sauce = btn.dataset.value;
updateBuilderVisuals();
});
});
document.querySelectorAll('[data-group="topping"] .opt').forEach(btn => {
btn.addEventListener('click', () => {
userInteracted = true;
const key = btn.dataset.value;
if (state.toppings.has(key)) state.toppings.delete(key);
else state.toppings.add(key);
updateBuilderVisuals();
});
});
document.getElementById('addBtn').addEventListener('click', () => {
userInteracted = true;
const price = parseFloat(unitPrice.textContent.replace('$', '')) || 0;
const toppings = [...state.toppings].map(t => toppingData[t].name);
const label = `${baseData[state.base].name} · ${proteinData[state.protein].name}${toppings.length ? ` · ${toppings.join(', ')}` : ''}`;
order.push({ label, price });
renderBasket();
showToast('Added to your truck ticket. Fire it when ready.');
});
document.getElementById('clearBtn').addEventListener('click', () => {
order.length = 0;
renderBasket();
showToast('Ticket cleared.');
});
applyDemoChoices();
updateBuilderVisuals();
const demoTimer = setInterval(() => {
if (userInteracted) {
clearInterval(demoTimer);
return;
}
applyDemoChoices();
}, 2800);
// Schedule + live status
const schedule = [
{ day: 'Sun', name: 'Sunday', open: false, close: 0, spot: 'Resting for rice', time: 'Closed' },
{ day: 'Mon', name: 'Monday', open: true, startHour: 11, endHour: 20, spot: 'Tech Park Food Plaza', time: '11:00a–8:00p' },
{ day: 'Tue', name: 'Tuesday', open: true, startHour: 11, endHour: 20, spot: 'Riverside Farmers Market', time: '11:00a–8:00p' },
{ day: 'Wed', name: 'Wednesday', open: true, startHour: 12, endHour: 22, spot: 'Brewery District', time: '12:00p–10:00p' },
{ day: 'Thu', name: 'Thursday', open: true, startHour: 11, endHour: 21, spot: 'University Loop', time: '11:00a–9:00p' },
{ day: 'Fri', name: 'Friday', open: true, startHour: 16, endHour: 24, spot: 'Night Market @ Dockside', time: '4:00p–midnight' },
{ day: 'Sat', name: 'Saturday', open: true, startHour: 12, endHour: 22, spot: 'Beach Boardwalk', time: '12:00p–10:00p' }
];
const scheduleRows = document.getElementById('scheduleRows');
const currentSpot = document.getElementById('currentSpot');
const currentStatus = document.getElementById('currentStatus');
const liveStatus = document.getElementById('liveStatus');
function renderScheduleRows(todayIndex) {
scheduleRows.innerHTML = schedule.map((row, i) => {
const cls = `schedule-row${i === todayIndex ? ' today' : ''}${!row.open ? ' closed' : ''}`;
return `
<div class="${cls}">
<strong>${row.day}</strong>
<span>${row.spot}</span>
<span class="time">${row.time}</span>
</div>`;
}).join('');
}
function formatDuration(ms) {
const totalMinutes = Math.max(0, Math.floor(ms / 60000));
const days = Math.floor(totalMinutes / 1440);
const hours = Math.floor((totalMinutes % 1440) / 60);
const minutes = totalMinutes % 60;
if (days > 0) return `${days}d ${hours}h ${minutes}m`;
if (hours > 0) return `${hours}h ${minutes}m`;
return `${minutes}m`;
}
function updateStatus() {
const now = new Date();
const dayIndex = now.getDay();
const row = schedule[dayIndex];
renderScheduleRows(dayIndex);
if (!row.open) {
currentSpot.textContent = 'Truck is off duty today';
currentStatus.textContent = `Next stop: ${schedule[(dayIndex + 1) % 7].spot}`;
liveStatus.textContent = 'Closed today · back soon';
return;
}
const openTime = new Date();
openTime.setHours(row.startHour, 0, 0, 0);
let closeTime = new Date();
closeTime.setHours(row.endHour, 0, 0, 0);
if (row.endHour === 24) {
closeTime.setDate(closeTime.getDate() + 1);
closeTime.setHours(0, 0, 0, 0);
}
currentSpot.textContent = row.spot;
if (now < openTime) {
currentStatus.textContent = `Opens in ${formatDuration(openTime - now)}`;
liveStatus.textContent = `Opens in ${formatDuration(openTime - now)}`;
} else if (now >= openTime && now < closeTime) {
currentStatus.textContent = `Serving now · closes in ${formatDuration(closeTime - now)}`;
liveStatus.textContent = `Serving now at ${row.spot}`;
} else {
let d = 1;
let next = schedule[(dayIndex + d) % 7];
while (!next.open && d < 7) {
d++;
next = schedule[(dayIndex + d) % 7];
}
currentStatus.textContent = next.open ? `Closed today · next at ${next.spot}` : 'Closed today · check weekly rotation';
liveStatus.textContent = next.open ? `Closed today · back ${next.day}` : 'Closed today';
}
}
updateStatus();
setInterval(updateStatus, 30000);
// Notify form
const form = document.getElementById('notifyForm');
const emailInput = document.getElementById('email');
const note = document.getElementById('notifyNote');
form.addEventListener('submit', e => {
e.preventDefault();
const value = emailInput.value.trim();
const ok = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
note.classList.remove('show');
note.style.color = ok ? '#d9ffe9' : '#ffd6d6';
note.textContent = ok
? 'Nice. You’re on the daily spice drop list.'
: 'That email looks a little undercooked — try again.';
requestAnimationFrame(() => note.classList.add('show'));
if (ok) emailInput.value = '';
});
})();
</script>
</body>
</html>Reasoning trace (4,555 tokens)
Need respond with exactly one fenced code block HTML. User wants website for Korean taco food truck Kimchi Loco. Need self-contained, appealing, demo maybe interactive. Need include something visible, maybe animated, menu, truck location, CTA, maybe mini interactive taco builder? It says Games... but website not game. Need no external, but fonts allowed? Probably system fonts. Need no network requests. Could include inline SVG, CSS animations, JS. Need avoid alert etc. Make it engaging. Could add "now serving" popup ticker, map mock, menu cards, taco builder, order notification not alert. Ensure responsive 1280x800, no horizontal scrollbar. Need high quality visual design. Korean/Mexican fusion identity. Colors: deep charcoal, gochujang red, corn masa yellow, cilantro green, lime. Use pattern? Inline SVG? Could make hero with truck silhouette and animated steam. Add menu highlights: Bulgogi Taco, Kimchi Loco Classic, Gochujang Carnitas, Doenjang Pork, Ssam Vegetable, Churros with yuja? Locations: weekly schedule, live status toggle. Interactive "Build Your Taco" that updates price, visual layers in SVG. Self-playing? Since not game maybe no need. But maybe a little auto animation in taco builder? Need something interesting in first seconds. Could add animated queue "now at...". Also maybe a confetti? no external. Need keyboard? no.
Need output exactly one code block. Let's craft full HTML.
Consider layout:
- sticky nav with logo "Kimchi Loco" (한글? maybe Korean/Mexican). Nav links: Menu, Truck, Build, Find Us, Story. CTA Order.
- Hero: gradient background with inline SVG pattern, big headline "Korean heat. Baja soul." Subtext. Animated truck? CSS/SVG. Badge "Rolling out at 5:00". Stats. Buttons. Floating taco emojis? Avoid emojis maybe. Use inline SVG chips.
- Marquee: infinite scroll with menu items. CSS animation.
- Menu grid: categories, cards with hover, price tags, spice meters, tags.
- Live taco builder: 3 columns. Choose base (corn, flour, lettuce), protein, toppings, sauces. SVG taco layers update. Price. "Add to order" adds to basket. Basket shows count, total. Auto demo: every 2.5s cycles toppings/proteins? Could set auto builder until user interacts. Need first screenshot meaningful. Use auto animation changing selection and maybe visual steam.
- Find us: schedule, map-ish with pin, "Today's Spot". Maybe countdown to next service using fake time? Use current time.
- Reviews/social proof: cards.
- Newsletter/order bar. Need interactive: email input with validation, success message inline.
- Footer.
Need no errors. Use system fonts. Use CSS variables. Ensure no horizontal scrollbar: overflow-x hidden. But marquee inside overflow hidden. Responsive.
Potential issue iframe sandbox with no network. Fine.
Need maybe self-contained SVG. Use inline <svg> for truck. Need careful sizing.
Could create dynamic "live" elements with setInterval, but don't overdo. Need screenshot at 3s: maybe hero, marquee, maybe menu? If page first visible only hero. That's okay. But maybe interesting: animated truck, steam, counter. Could auto scroll? Better not.
Let's design. Use max-width 1280 centered. Hero full screen height maybe 92vh. At 1280x800 enough visible.
HTML:
<!doctype html>
<html lang=en>
head meta viewport, title, style.
body.
Background: dark charcoal #151214? Accent: #ff3d3d? Let's define:
--bg:#140f12;
--ink:#fffaf2;
--red:#e33b2f (gochujang)
--orange:#ff7a18
--yellow:#ffc94a
--green:#57b47a
--lime:#c6e24a
--panel: rgba(255,255,255,.07)
Typography: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial; maybe Korean glyphs: "Malgun Gothic", "Apple SD Gothic Neo". No external.
Hero: grid two columns: text, visual. Visual: taco builder preview? maybe big animated taco stack. Could use CSS layered divs? SVG easier. Maybe hero visual: stylized truck with smoke and floating shells. But also first screen could show "Kimchi Loco". Use animated text shimmer.
Add "Now serving" badge with pulsing dot. Maybe "At: Sunset + 5th".
Menu cards: use grid auto-fit minmax(260px).
Taco builder: interactive controls as buttons. Need update price. SVG layers: group shells and fillings. Could use transform scale/opacity toggles. Auto demo cycles: pick base/protein/topping/sauce. On user click, stop auto? Set userInteracted true.
Build SVG: viewBox 0 0 360 260. Taco shape: two half circles? Draw shell path, inner fill. Need toggles for base: corn shell yellow, flour shell tan, lettuce green. Protein layer: brown/red/orange/bean. Toppings: circles/rects. Sauce: zigzag path maybe toggles. For simplicity use CSS classes .hide {display:none}. Update data attributes.
Auto demo: setTimeout every 2000 random options; but if user interacts disable. Also maybe update order basket every 5 sec automatically adds? Could be too much. Keep only selection changes.
Add-to-order button: create list item in basket; max visible maybe. Use no alert. Basket count. Toast: show inline message.
Find us: schedule table. Maybe countdown: calculate next opening from simple weekly schedule. Could show "opens in 2h 14m" based on current. Need no timezone issues. Use current Date. Schedule object hours:
Mon-Fri 11:00-19:00? Food truck. Sat 12-21, Sun closed. But current time can be after hours. Compute next open date.
Implementation:
const schedule = [ {day:0,closed:true}, {1: open:11, close:19}, ...] day index 0 Sun. For each day, check if current before open -> next open today; if after close -> next scheduled day.
Simpler create array of days: Sun closed, Mon open 11 close 20, Tue... Fri same, Sat 12-22. Then find. Need update every minute.
Map: SVG city blocks with truck pin, animated pulse. Address text changes with schedule? Could map static.
Reviews: 3 cards.
Footer CTA: input + button "Notify me" no alert, inline success.
Accessibility: labels, aria-live for builder.
Need maybe "Order Now" button scrolls to build.
No external images. Inline icons maybe SVG.
Let's craft code carefully. Ensure syntax.
CSS details:
* box-sizing.
html,body margin 0, overflow-x hidden, background gradient.
body color.
.container max-width 1180? 1200 padding 20.
.section h2.
.nav fixed/sticky top, backdrop blur, border-bottom.
logo: bold.
links hidden on small? Use horizontal scroll? Need no overflow. Could simple flex wrap.
.btn styles.
Marquee:
.marquee {overflow hidden; mask?} inner flex animation 28s linear infinite. Duplicate items.
Need if reduced motion? Could media reduce-motion.
Hero SVG: Use CSS animation float. Truck path:
<svg class="truck" viewBox="0 0 520 300">
- wheels circles, body rounded rect, window, roof sign "KIMCHI LOCO" text maybe SVG text? Could be simple. Smoke paths. Use text in SVG with system font.
But truck SVG in hero. Need avoid horizontal overflow: width 100%, max-height 480.
Maybe a more elegant hero visual: taco cross-section? But truck communicates food truck. Let's do truck with awning and steam. It may be large. Use simple shapes:
rect cab? Hmm. Better stylized van:
<path body rounded: M 50 190 ...>.
SVG:
<g class="truck-bounce">
<rect x="30" y="105" width="360" height="115" rx="24" fill="#d72638"/>
<path d="M360 125h70l45 65v65H360z" fill="#d72638" stroke="#d72638" stroke-width="4" stroke-linejoin="round"/>
<rect window x=370 y=135 width=80 height=45 rx=8 fill="#0b2a3a" />
<rect service window x=110 y=130 width=140 height=70 rx=12 fill="#ffd06a" />
<rect counter x=110 y=200 width=140 height=14 fill="#fff7d6"/>
<circle wheel cx=120 cy=220 r=32/> etc.
<text "KIMCHI LOCO"> on body maybe small.
Smoke: ellipses with opacity animation.
Steam:
<g class="steam"> paths/circles.
Awning stripes? Use rect top.
Need maybe responsive: on mobile, hero single column.
Taco builder SVG:
viewBox 0 0 320 220.
Base group: paths for shells and lettuce.
Corn shell: path shell left/right? A classic taco: U-shaped folded shell.
Path: M50,40 C30,40 25,180 160,180 C295,180 290,40 270,40 L270,60 C270,120 240,150 160,150 C80,150 50,120 50,60 Z. Maybe.
Better: shell outer: path d="M42 35 C15 120 45 180 160 180 C275 180 305 120 278 35 C258 14 240 28 225 55 C210 80 195 104 160 104 C125 104 110 80 95 55 C80 28 62 14 42 35Z" fill #eab04a. Hmm complicated.
Simpler: draw as two arcs: outer U path: M60 40 C60 180 120 190 160 190 C200 190 260 180 260 40 L240 40 C240 160 190 168 160 168 C130 168 80 160 80 40Z fill shell. That gives folded shell with inner gap. For flour and lettuce same with colors toggled. But shell thickness okay.
Fillings: ellipses/rects:
Protein: path area: M105 120 C120 155 200 155 215 120 C210 95 110 95 105 120Z fill. Toggle protein colors. Maybe multiple blobs.
Toppings:
- cilantro: green circles.
- onion: white rings? small rects.
- salsa: orange path dots.
- cheese: yellow small rects.
- kimchi: red/orange shreds.
- avocado: green semicircle.
Need toggles by class id groups.
Sauce drizzles: path zigzag. Maybe multiple classes.
Could create groups data-topping="..." each hidden except selected? But toppings multi-select? User can toggle on/off. Base single, protein single, sauce maybe choose one? Could have toppings toggles: kimchi, cilantro, onion, avocado, cheese? Price additions. Need simple.
Taco visual groups: base-corn, base-flour, base-lettuce; protein-xxx; topping-xxx visible if selected. Auto demo toggles.
Use array selected toppings set? But visual complexity. For simplicity, toppings are chips that toggle. Price +$1 each. Auto select random. Good.
Builder JS:
const basePrices={corn:3.5,flour:4,lettuce:4.5}; proteins={...}. toppingPrices=...; saucePrices? sauces add .5.
Update total. Add to basket.
Button groups: .opt with data-type, data-value. On click, for single types set selected and aria-pressed. For multi toggle.
Visual update: set all option buttons active; set SVG groups display.
Auto: if !userInteracted. Choose base/protein/sauce from lists; toppings random count. Every 2600ms. Need initial random. Maybe animate steam. Could update basket with "chef's demo"? Maybe no.
Find us: schedule card with today highlighted. Countdown. Use JS to render list from data. Need not too long.
Potential issue: setInterval with no clear not needed.
Reduced motion: media query.
Now craft final HTML. Need one fenced block. Ensure no text outside.
Let's write detailed code.
Need ensure no horizontal scroll from SVG text or elements. Use overflow hidden. Buttons wrap.
Maybe use emojis? Task asks self-contained web demo, okay. Use Korean glyphs like "김치 로코". Good.
Review section: no external. Use gradient stars inline? Maybe unicode ★.
"Kimchi Loco" tagline: "Seoul streets, Baja coast." Good.
Add sections IDs: top, menu, build, find, story.
Could include "spice meter" with spans dots.
Order basket: small fixed? No, within builder.
Add sticky bottom bar on mobile? maybe not.
Need first paint meaningful. Maybe auto "live queue" count in hero? But at 3 sec hero only. Add animated truck and badge.
CSS animations:
float truck: translateY -4 to 4.
steam: rise opacity.
pulse dot.
marquee: translateX -50%.
text gradient shimmer? subtle.
Potential syntax pitfalls:
- SVG animation using CSS transform-origin: center.
- Use `pathLength`? no.
- `mask-image` might be unsupported? It's okay with -webkit? We can skip mask.
Let's formulate.
JS functions:
const fmt = n => `$${n.toFixed(2)}`.
state = {base:'corn', protein:'bulgogi', toppings:new Set(['kimchi','cilantro']), sauce:'gochujang'};
baseData = {corn:{name:'Corn',price:3.5, cls:'base-corn'}, flour:...}; proteinData...
toppingData = {kimchi:{name:'House kimchi',price:1.5,cls:'topping-kimchi'}, cilantro:{...}, onion, avocado, cheese, jalapeno?}; sauceData = {gochujang:{name:'Gochujang crema',price:.75,cls:'sauce-gochujang'}, salsa:{name:'Baja salsa',price:0,cls:'sauce-salsa'}, none:{price:0,cls:null}}
updateUI:
document.querySelectorAll('[data-group="base"]... toggle .active). For base/protein/sauce, check. For toppings, .toggle.
SVG groups: querySelectorAll('.taco [data-layer]').style.display='none' for layers not selected. Simpler set visibility:
for group in base/protein/sauce: if state.x set element data-layer=x. For topping groups: if selected show.
But SVG groups need IDs/classes. Use `data-layer="base-corn"` etc.
Add CSS `[data-layer]{transition: opacity .35s ease, transform .35s ease; transform-origin:center; opacity:1}` `.hidden-layer{opacity:0;transform:translateY(6px) scale(.96); pointer-events:none}`.
In JS set hidden class accordingly.
Total: base + protein + toppings + sauce.
Add basket: array items. Show list up to last 4. Count total items and total price. "Clear".
Notify: `aria-live` div.
Auto builder:
function applyDemo(){ base random; protein random; sauce random; toppings random set. Update UI. If userInteracted stop. } setInterval(applyDemo, 2800). But if auto changes too quickly? 2.8 ok. It may distract before screenshot but okay. Could only auto change toppings and proteins not bases? Fine.
Need if user clicks builder, userInteracted=true.
Find us schedule:
const locations = [{day:'Monday', spot:'Sunset & 5th', time:'11:00a–8:00p', openHour:11, closeHour:20}, ...]. Use current day. Highlight today. Countdown:
function nextOpening(){ for (offset=0; offset<8; offset++){ date = new Date(); date.setDate(date.getDate()+offset); date.setHours(loc.openHour,0,0,0); if(loc.open && date > now) return date; } }
But schedule by weekday. For offset day index (getDay). Need if offset>0 set 12:00 not current time. For offset=0 set openHour. If now before open, return; else if after close no. For offset>0 return open time. Simpler:
function findNextOpen(){ const now=new Date(); for(d=0; d<7; d++){ const day=(now.getDay()+d)%7; const loc=locations[day]; if(!loc.open) continue; const target = new Date(now); target.setDate(now.getDate()+d); target.setHours(loc.openHour,0,0,0); if(target > now) return {date: target, loc}; } return null; }
Update every 30s. For after close today it finds next day. Display location and countdown. If now open, could show serving? Actually findNextOpen returns today if current before open. If currently within open, target may be today's open in past so false; then find future open. We want "Currently serving at ... closes in ..." if within open. Need handle:
for offset=0: if loc.open: open = new Date(today openHour); close = new Date(today closeHour); if now>=open && now<close => currently serving. else if now<open => opens in. else after close find next day. For offset>0 find. Implement updateFindUs:
const day=now.getDay(); loc=locations[day]; open,close. If open && now<open: opens today in. Else if open && now>=open && now<close: serving now closes in. Else find next day.
Countdown format: days/hours/min.
Locations list: Sunday closed "Resting for rice". Monday "Tech Park Food Plaza", Tue "Riverside Farmers Market", Wed "Brewery District", Thu "University Loop", Fri "Night Market @ Dockside", Sat "Beach Boardwalk". Good.
Map SVG: simple abstract street grid, pin pulse. Use CSS animation.
Story/Why section: maybe 3 cards: Ferment-forward, Handmade tortillas, Live fire.
Reviews: small.
CTA notify: input, button, message. Validate email regex simple. Success inline. No alert.
Footer.
Need ensure no console errors. Query selectors exist. Use `document.getElementById` safe.
Potential issue `Set` used in SVG update. Fine.
Let's write final code now.
Need maybe include `html {scroll-behavior:smooth}`.
Need careful with CSS and HTML escaping. No external fonts.
Use SVG text in truck: Might font-size responsive. Could include "KIMCHI LOCO" with letter-spacing.
Hero visual: Maybe use `filter: drop-shadow`. Good.
Let's produce final. Ensure code block only.