Initial commit: PRD, build tooling, and design mockups
Foodster is a self-hosted dinner log and meal suggester for one household. Stage 1 (eating history) is in development; stage 2 (the suggester) follows once there is enough history to weight against. Replace the PRD's original stack (Nuxt, Postgres, Drizzle, Pico CSS) with Go 1.27, net/http, templ, Datastar and SQLite — one static binary, no Node.js in the build. Sections 3, 4, 5, 9, 10 and 11 are rewritten to match. Record the decisions made while reviewing mockups: - the UI is written in Finnish; PRD, code and comments stay English - access is one shared password over HTTP Basic rather than open on the LAN - images are CalVer vYYYYMMDD-N, built with Podman, run under Docker Compose - registry coordinates live in .env, so no infrastructure detail is committed and the MIT publication option stays open mockups/ holds standalone HTML design studies. log-fi.html is the current one; the others are superseded exploration kept for reference.
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
<!doctype html>
|
||||
<html lang="en" data-theme="auto">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Foodster — A · Chit rail</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Martian+Mono:wght@300;500;700&family=Public+Sans:wght@400;600&family=Saira+Condensed:wght@600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root{
|
||||
color-scheme: light dark;
|
||||
--ground: light-dark(#E7E8E3, #131417);
|
||||
--chit: light-dark(#FBFBF8, #1F2126);
|
||||
--ink: light-dark(#15171B, #E7E8E2);
|
||||
--muted: light-dark(#6E7269, #8C9088);
|
||||
--rail: light-dark(#A8ACA2, #4A4E54);
|
||||
--line: light-dark(#D3D5CD, #32353B);
|
||||
--stamp: light-dark(#1F3FBF, #7D97FF);
|
||||
--meat: light-dark(#B23A2E, #E2705F);
|
||||
--chicken: light-dark(#A97511, #E0A93A);
|
||||
--fish: light-dark(#1F6FA8, #64ACDC);
|
||||
--vegetarian:light-dark(#3C7A45, #7CBB86);
|
||||
}
|
||||
html[data-theme="light"]{ color-scheme: only light; }
|
||||
html[data-theme="dark"] { color-scheme: only dark; }
|
||||
|
||||
*{box-sizing:border-box;}
|
||||
body{
|
||||
margin:0; background:var(--ground); color:var(--ink);
|
||||
font-family:"Public Sans",system-ui,sans-serif; font-size:16px; line-height:1.5;
|
||||
-webkit-font-smoothing:antialiased;
|
||||
}
|
||||
.wrap{max-width:1180px; margin:0 auto; padding:0 20px 80px;}
|
||||
|
||||
/* ---- masthead ---- */
|
||||
.top{display:flex; align-items:baseline; gap:20px; flex-wrap:wrap;
|
||||
padding:26px 0 20px; border-bottom:1px solid var(--line);}
|
||||
.logo{font-family:"Martian Mono",monospace; font-weight:700; font-size:15px;
|
||||
letter-spacing:.06em; text-transform:uppercase;}
|
||||
.logo b{color:var(--stamp); font-weight:700;}
|
||||
nav{display:flex; gap:2px; margin-left:auto;}
|
||||
nav a{font-family:"Martian Mono",monospace; font-size:11px; letter-spacing:.04em;
|
||||
text-transform:uppercase; color:var(--muted); text-decoration:none;
|
||||
padding:7px 12px; border:1px solid transparent; border-radius:2px;}
|
||||
nav a[aria-current]{color:var(--ink); border-color:var(--line); background:var(--chit);}
|
||||
nav a:hover{color:var(--ink);}
|
||||
.themebtn{font-family:"Martian Mono",monospace; font-size:11px; letter-spacing:.04em;
|
||||
text-transform:uppercase; background:none; border:1px solid var(--line);
|
||||
color:var(--muted); padding:7px 10px; border-radius:2px; cursor:pointer;}
|
||||
.themebtn:hover{color:var(--ink);}
|
||||
|
||||
/* ---- header ---- */
|
||||
header.lede{padding:44px 0 30px; display:flex; align-items:flex-end; gap:28px; flex-wrap:wrap;}
|
||||
h1{font-family:"Saira Condensed",sans-serif; font-weight:700; font-size:clamp(46px,8vw,86px);
|
||||
line-height:.9; letter-spacing:-.015em; margin:0; text-transform:uppercase;}
|
||||
.lede p{margin:0 0 6px; max-width:34ch; color:var(--muted); font-size:15px;}
|
||||
.regen{margin-left:auto; font-family:"Martian Mono",monospace; font-size:11px;
|
||||
letter-spacing:.05em; text-transform:uppercase; background:var(--stamp); color:#fff;
|
||||
border:0; padding:13px 20px; border-radius:2px; cursor:pointer;}
|
||||
.regen:hover{filter:brightness(1.12);}
|
||||
|
||||
/* ---- warning ---- */
|
||||
.notice{display:flex; gap:12px; align-items:flex-start; margin:0 0 34px;
|
||||
padding:13px 16px; background:var(--chit); border-left:3px solid var(--meat);
|
||||
border-radius:0 2px 2px 0; font-size:14px;}
|
||||
.notice b{font-family:"Martian Mono",monospace; font-size:11px; letter-spacing:.05em;
|
||||
text-transform:uppercase; color:var(--meat); white-space:nowrap; padding-top:2px;}
|
||||
|
||||
/* ---- the rail ---- */
|
||||
.rail{position:relative; padding-top:22px;}
|
||||
.rail::before{content:""; position:absolute; top:14px; left:-12px; right:-12px; height:3px;
|
||||
background:var(--rail); border-radius:2px;}
|
||||
.chits{display:grid; gap:18px; grid-template-columns:repeat(auto-fill,minmax(248px,1fr));}
|
||||
|
||||
.chit{position:relative; background:var(--chit); border:1px solid var(--line);
|
||||
border-top:0; border-radius:0 0 3px 3px; padding:26px 16px 14px;}
|
||||
.chit::before{content:""; position:absolute; top:0; left:0; right:0; height:7px;
|
||||
background:radial-gradient(circle at 5px 0, var(--ground) 4px, transparent 4.5px) repeat-x;
|
||||
background-size:12px 7px;}
|
||||
.chit::after{content:""; position:absolute; top:-14px; left:50%; margin-left:-5px;
|
||||
width:10px; height:18px; background:var(--rail); border-radius:2px;}
|
||||
|
||||
.cat{display:flex; gap:5px; margin:0 0 12px;}
|
||||
.cat span{font-family:"Martian Mono",monospace; font-size:9px; font-weight:500;
|
||||
letter-spacing:.08em; text-transform:uppercase; color:#fff; padding:3px 6px; border-radius:2px;}
|
||||
.c-meat{background:var(--meat);} .c-chicken{background:var(--chicken);}
|
||||
.c-fish{background:var(--fish);} .c-vegetarian{background:var(--vegetarian);}
|
||||
|
||||
.dish{font-family:"Saira Condensed",sans-serif; font-weight:600; font-size:29px;
|
||||
line-height:1.02; margin:0 0 10px; text-transform:uppercase; letter-spacing:-.005em;}
|
||||
.sides{list-style:none; margin:0 0 14px; padding:12px 0 0; border-top:1px dashed var(--line);
|
||||
font-size:14px; color:var(--ink);}
|
||||
.sides li{display:flex; gap:8px;}
|
||||
.sides li::before{content:"+"; color:var(--muted);}
|
||||
.nosides{margin:0 0 14px; padding:12px 0 0; border-top:1px dashed var(--line);
|
||||
font-family:"Martian Mono",monospace; font-size:10px; letter-spacing:.04em;
|
||||
text-transform:uppercase; color:var(--muted);}
|
||||
.last{font-family:"Martian Mono",monospace; font-size:10px; letter-spacing:.02em;
|
||||
color:var(--muted); margin:0 0 14px;}
|
||||
.swaps{display:flex; gap:6px;}
|
||||
.swaps button{flex:1; font-family:"Martian Mono",monospace; font-size:10px; letter-spacing:.03em;
|
||||
text-transform:uppercase; background:none; color:var(--muted);
|
||||
border:1px solid var(--line); border-radius:2px; padding:8px 4px; cursor:pointer;}
|
||||
.swaps button:hover:not(:disabled){color:var(--stamp); border-color:var(--stamp);}
|
||||
.swaps button:disabled{opacity:.35; cursor:not-allowed;}
|
||||
|
||||
/* ---- log strip ---- */
|
||||
.logstrip{margin-top:56px; border-top:1px solid var(--line); padding-top:20px;}
|
||||
.logstrip h2{font-family:"Martian Mono",monospace; font-size:11px; letter-spacing:.06em;
|
||||
text-transform:uppercase; color:var(--muted); margin:0 0 14px; font-weight:500;}
|
||||
.logrow{display:flex; gap:16px; align-items:baseline; padding:9px 0;
|
||||
border-bottom:1px solid var(--line); font-size:15px;}
|
||||
.logrow time{font-family:"Martian Mono",monospace; font-size:11px; color:var(--muted);
|
||||
min-width:74px;}
|
||||
.logrow .w{width:8px; height:8px; border-radius:1px; align-self:center;}
|
||||
.logrow em{color:var(--muted); font-style:normal; font-size:13px;}
|
||||
|
||||
:focus-visible{outline:2px solid var(--stamp); outline-offset:2px;}
|
||||
@media (max-width:560px){ .rail::before,.chit::after{display:none;} }
|
||||
@media (prefers-reduced-motion:reduce){ *{transition:none!important;} }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
|
||||
<div class="top">
|
||||
<div class="logo">Food<b>ster</b></div>
|
||||
<nav>
|
||||
<a href="#" aria-current="page">Plan</a>
|
||||
<a href="#">Log</a>
|
||||
<a href="#">Catalog</a>
|
||||
</nav>
|
||||
<button class="themebtn" id="t">Theme: auto</button>
|
||||
</div>
|
||||
|
||||
<header class="lede">
|
||||
<h1>Seven<br>dinners</h1>
|
||||
<p>Drawn from what this house actually eats. Swap anything that doesn't appeal — nothing here is a schedule.</p>
|
||||
<button class="regen">New seven</button>
|
||||
</header>
|
||||
|
||||
<div class="notice">
|
||||
<b>No fish</b>
|
||||
<span>Every fish dish was eaten in the last 14 days. Fish sits this week out — shorten the cooldown in Catalog if that's too strict.</span>
|
||||
</div>
|
||||
|
||||
<div class="rail">
|
||||
<div class="chits">
|
||||
|
||||
<article class="chit">
|
||||
<div class="cat"><span class="c-meat">meat</span></div>
|
||||
<h3 class="dish">Jauheliha­kastike</h3>
|
||||
<ul class="sides"><li>Perunamuusi</li><li>Vihersalaatti</li></ul>
|
||||
<p class="last">last eaten 23 days ago</p>
|
||||
<div class="swaps"><button>Swap similar</button><button>Swap anything</button></div>
|
||||
</article>
|
||||
|
||||
<article class="chit">
|
||||
<div class="cat"><span class="c-chicken">chicken</span></div>
|
||||
<h3 class="dish">Broileri­kastike</h3>
|
||||
<ul class="sides"><li>Riisi</li></ul>
|
||||
<p class="last">last eaten 31 days ago</p>
|
||||
<div class="swaps"><button>Swap similar</button><button>Swap anything</button></div>
|
||||
</article>
|
||||
|
||||
<article class="chit">
|
||||
<div class="cat">
|
||||
<span class="c-meat">meat</span><span class="c-chicken">chicken</span>
|
||||
<span class="c-fish">fish</span><span class="c-vegetarian">veg</span>
|
||||
</div>
|
||||
<h3 class="dish">Tortillat</h3>
|
||||
<p class="nosides">served on its own</p>
|
||||
<p class="last">last eaten 40 days ago</p>
|
||||
<div class="swaps">
|
||||
<button disabled title="No other dish covers all four categories">Swap similar</button>
|
||||
<button>Swap anything</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="chit">
|
||||
<div class="cat"><span class="c-vegetarian">vegetarian</span></div>
|
||||
<h3 class="dish">Kasvis­pyörykät</h3>
|
||||
<ul class="sides"><li>Perunamuusi</li><li>Höyrytetyt Porkkanat</li></ul>
|
||||
<p class="last">last eaten 52 days ago</p>
|
||||
<div class="swaps"><button>Swap similar</button><button>Swap anything</button></div>
|
||||
</article>
|
||||
|
||||
<article class="chit">
|
||||
<div class="cat"><span class="c-meat">meat</span></div>
|
||||
<h3 class="dish">Makaroni­laatikko</h3>
|
||||
<p class="nosides">served on its own</p>
|
||||
<p class="last">last eaten 19 days ago</p>
|
||||
<div class="swaps"><button>Swap similar</button><button>Swap anything</button></div>
|
||||
</article>
|
||||
|
||||
<article class="chit">
|
||||
<div class="cat"><span class="c-vegetarian">vegetarian</span></div>
|
||||
<h3 class="dish">Hernekeitto</h3>
|
||||
<p class="nosides">served on its own</p>
|
||||
<p class="last">last eaten 27 days ago</p>
|
||||
<div class="swaps"><button>Swap similar</button><button>Swap anything</button></div>
|
||||
</article>
|
||||
|
||||
<article class="chit">
|
||||
<div class="cat"><span class="c-meat">meat</span></div>
|
||||
<h3 class="dish">Lihapullat</h3>
|
||||
<ul class="sides"><li>Perunamuusi</li><li>Vihersalaatti</li></ul>
|
||||
<p class="last">last eaten 16 days ago</p>
|
||||
<div class="swaps"><button>Swap similar</button><button>Swap anything</button></div>
|
||||
</article>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="logstrip">
|
||||
<h2>Recently eaten</h2>
|
||||
<div class="logrow"><time>Thu 3 Sep</time><i class="w c-fish"></i><span>Lohikeitto</span><em>Ruisleipä</em></div>
|
||||
<div class="logrow"><time>Wed 2 Sep</time><i class="w c-chicken"></i><span>Kanacurry</span><em>Riisi</em></div>
|
||||
<div class="logrow"><time>Tue 1 Sep</time><i class="w c-meat"></i><span>Uunimakkara</span><em>Perunamuusi · Vihersalaatti</em></div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
const t=document.getElementById('t'), h=document.documentElement, m=['auto','light','dark'];
|
||||
t.onclick=()=>{const n=m[(m.indexOf(h.dataset.theme)+1)%3]; h.dataset.theme=n; t.textContent='Theme: '+n;};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,214 @@
|
||||
<!doctype html>
|
||||
<html lang="en" data-theme="auto">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Foodster — B · Enamel tile</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,[email protected],500;12..96,700;12..96,800&family=Karla:wght@400;500;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root{
|
||||
color-scheme: light dark;
|
||||
--grout: light-dark(#D9D6CE, #191A1C);
|
||||
--card: light-dark(#FFFFFF, #232529);
|
||||
--ink: light-dark(#1B1C18, #EDEDE8);
|
||||
--muted: light-dark(#71736B, #94968D);
|
||||
--line: light-dark(#C7C4BB, #32343A);
|
||||
--glaze: light-dark(rgba(255,255,255,.30), rgba(255,255,255,.10));
|
||||
--meat: light-dark(#A8452F, #8E3826);
|
||||
--chicken: light-dark(#C68A16, #A87211);
|
||||
--fish: light-dark(#2C6B92, #23566F);
|
||||
--vegetarian:light-dark(#4E7A38, #3F6430);
|
||||
--on-tile:#FFFCF4;
|
||||
}
|
||||
html[data-theme="light"]{ color-scheme: only light; }
|
||||
html[data-theme="dark"] { color-scheme: only dark; }
|
||||
|
||||
*{box-sizing:border-box;}
|
||||
body{margin:0; background:var(--grout); color:var(--ink);
|
||||
font-family:Karla,system-ui,sans-serif; font-size:16px; line-height:1.5;
|
||||
-webkit-font-smoothing:antialiased;}
|
||||
.wrap{max-width:1120px; margin:0 auto; padding:0 20px 80px;}
|
||||
|
||||
.top{display:flex; align-items:center; gap:18px; flex-wrap:wrap; padding:22px 0;}
|
||||
.logo{font-family:"Bricolage Grotesque",sans-serif; font-weight:800; font-size:22px;
|
||||
letter-spacing:-.03em;}
|
||||
nav{display:flex; gap:4px; margin-left:auto;}
|
||||
nav a{font-size:14px; font-weight:500; color:var(--muted); text-decoration:none;
|
||||
padding:7px 14px; border-radius:999px;}
|
||||
nav a[aria-current]{background:var(--card); color:var(--ink);}
|
||||
nav a:hover{color:var(--ink);}
|
||||
.themebtn{font-family:Karla,sans-serif; font-size:13px; background:var(--card);
|
||||
border:1px solid var(--line); color:var(--muted); padding:7px 13px;
|
||||
border-radius:999px; cursor:pointer;}
|
||||
.themebtn:hover{color:var(--ink);}
|
||||
|
||||
header.lede{padding:34px 0 22px; max-width:44ch;}
|
||||
h1{font-family:"Bricolage Grotesque",sans-serif; font-weight:700; font-size:clamp(38px,6vw,60px);
|
||||
line-height:1.0; letter-spacing:-.035em; margin:0 0 12px;}
|
||||
.lede p{margin:0; color:var(--muted); font-size:16px;}
|
||||
|
||||
/* ---- signature: coverage bar ---- */
|
||||
.coverage{margin:26px 0 8px;}
|
||||
.covbar{display:flex; height:10px; border-radius:3px; overflow:hidden; gap:2px;}
|
||||
.covbar i{display:block;}
|
||||
.covkey{display:flex; gap:16px; flex-wrap:wrap; margin-top:10px;
|
||||
font-size:13px; color:var(--muted);}
|
||||
.covkey span{display:flex; align-items:center; gap:7px;}
|
||||
.covkey b{width:9px; height:9px; border-radius:2px;}
|
||||
.covkey em{font-style:normal; color:var(--ink); font-weight:500;}
|
||||
|
||||
.actions{display:flex; gap:10px; margin:26px 0 22px; flex-wrap:wrap;}
|
||||
.regen{font-family:Karla,sans-serif; font-weight:700; font-size:15px; background:var(--ink);
|
||||
color:var(--grout); border:0; padding:12px 22px; border-radius:8px; cursor:pointer;}
|
||||
.regen:hover{opacity:.86;}
|
||||
|
||||
/* ---- tiles ---- */
|
||||
.tiles{display:grid; gap:6px; grid-template-columns:repeat(auto-fill,minmax(232px,1fr));}
|
||||
.tile{position:relative; border-radius:5px; padding:20px 18px 16px; color:var(--on-tile);
|
||||
min-height:196px; display:flex; flex-direction:column; overflow:hidden;}
|
||||
.tile::before{content:""; position:absolute; inset:0;
|
||||
background:linear-gradient(158deg, var(--glaze) 0%, transparent 46%); pointer-events:none;}
|
||||
.t-meat{background:var(--meat);} .t-chicken{background:var(--chicken);}
|
||||
.t-fish{background:var(--fish);} .t-vegetarian{background:var(--vegetarian);}
|
||||
.tile.wild{background:linear-gradient(112deg,
|
||||
var(--meat) 0 25%, var(--chicken) 25% 50%, var(--fish) 50% 75%, var(--vegetarian) 75% 100%);}
|
||||
|
||||
.tag{font-size:11px; font-weight:700; letter-spacing:.09em; text-transform:uppercase;
|
||||
opacity:.82; margin:0 0 auto;}
|
||||
.dish{font-family:"Bricolage Grotesque",sans-serif; font-weight:700; font-size:27px;
|
||||
line-height:1.05; letter-spacing:-.03em; margin:16px 0 8px;}
|
||||
.sides{margin:0 0 12px; font-size:14px; opacity:.88;}
|
||||
.last{font-size:12px; opacity:.7; margin:0 0 14px;}
|
||||
.swaps{display:flex; gap:6px; position:relative;}
|
||||
.swaps button{flex:1; font-family:Karla,sans-serif; font-size:12px; font-weight:700;
|
||||
background:rgba(255,255,255,.16); color:var(--on-tile); border:0;
|
||||
padding:9px 6px; border-radius:6px; cursor:pointer; backdrop-filter:blur(2px);}
|
||||
.swaps button:hover:not(:disabled){background:rgba(255,255,255,.30);}
|
||||
.swaps button:disabled{opacity:.4; cursor:not-allowed;}
|
||||
|
||||
/* ---- log ---- */
|
||||
.logstrip{margin-top:44px;}
|
||||
.logstrip h2{font-family:"Bricolage Grotesque",sans-serif; font-weight:700; font-size:19px;
|
||||
letter-spacing:-.02em; margin:0 0 12px;}
|
||||
.logrow{display:flex; gap:14px; align-items:center; background:var(--card);
|
||||
border-radius:7px; padding:11px 15px; margin-bottom:5px; font-size:15px;}
|
||||
.logrow time{color:var(--muted); font-size:13px; min-width:78px;}
|
||||
.logrow i{width:10px; height:10px; border-radius:2px;}
|
||||
.logrow em{color:var(--muted); font-style:normal; font-size:13px; margin-left:auto;}
|
||||
.k-meat{background:var(--meat);} .k-chicken{background:var(--chicken);}
|
||||
.k-fish{background:var(--fish);} .k-vegetarian{background:var(--vegetarian);}
|
||||
|
||||
:focus-visible{outline:2.5px solid var(--ink); outline-offset:2px;}
|
||||
@media (prefers-reduced-motion:reduce){ *{transition:none!important;} }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
|
||||
<div class="top">
|
||||
<div class="logo">Foodster</div>
|
||||
<nav><a href="#" aria-current="page">Plan</a><a href="#">Log</a><a href="#">Catalog</a></nav>
|
||||
<button class="themebtn" id="t">Theme: auto</button>
|
||||
</div>
|
||||
|
||||
<header class="lede">
|
||||
<h1>Seven dinners, no schedule.</h1>
|
||||
<p>Pick any of these on any night. Swap what doesn't appeal.</p>
|
||||
</header>
|
||||
|
||||
<div class="coverage">
|
||||
<div class="covbar" role="img" aria-label="This week covers meat, chicken, fish and vegetarian">
|
||||
<i class="t-meat" style="flex:3"></i>
|
||||
<i class="t-chicken" style="flex:1"></i>
|
||||
<i class="t-fish" style="flex:1"></i>
|
||||
<i class="t-vegetarian"style="flex:2"></i>
|
||||
</div>
|
||||
<div class="covkey">
|
||||
<span><b class="t-meat"></b><em>Meat</em> ×3</span>
|
||||
<span><b class="t-chicken"></b><em>Chicken</em> ×1</span>
|
||||
<span><b class="t-fish"></b><em>Fish</em> ×1</span>
|
||||
<span><b class="t-vegetarian"></b><em>Vegetarian</em> ×2</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions"><button class="regen">New seven</button></div>
|
||||
|
||||
<div class="tiles">
|
||||
|
||||
<article class="tile t-meat">
|
||||
<p class="tag">Meat</p>
|
||||
<h3 class="dish">Jauhelihakastike</h3>
|
||||
<p class="sides">Perunamuusi · Vihersalaatti</p>
|
||||
<p class="last">Last eaten 23 days ago</p>
|
||||
<div class="swaps"><button>Similar</button><button>Anything</button></div>
|
||||
</article>
|
||||
|
||||
<article class="tile t-chicken">
|
||||
<p class="tag">Chicken</p>
|
||||
<h3 class="dish">Broilerikastike</h3>
|
||||
<p class="sides">Riisi</p>
|
||||
<p class="last">Last eaten 31 days ago</p>
|
||||
<div class="swaps"><button>Similar</button><button>Anything</button></div>
|
||||
</article>
|
||||
|
||||
<article class="tile wild">
|
||||
<p class="tag">Meat · Chicken · Fish · Veg</p>
|
||||
<h3 class="dish">Tortillat</h3>
|
||||
<p class="sides">Served on its own</p>
|
||||
<p class="last">Last eaten 40 days ago</p>
|
||||
<div class="swaps">
|
||||
<button disabled title="Nothing else covers all four">Similar</button>
|
||||
<button>Anything</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="tile t-fish">
|
||||
<p class="tag">Fish</p>
|
||||
<h3 class="dish">Uunilohi</h3>
|
||||
<p class="sides">Riisi · Vihersalaatti</p>
|
||||
<p class="last">Last eaten 34 days ago</p>
|
||||
<div class="swaps"><button>Similar</button><button>Anything</button></div>
|
||||
</article>
|
||||
|
||||
<article class="tile t-vegetarian">
|
||||
<p class="tag">Vegetarian</p>
|
||||
<h3 class="dish">Kasvispyörykät</h3>
|
||||
<p class="sides">Perunamuusi · Höyrytetyt Porkkanat</p>
|
||||
<p class="last">Last eaten 52 days ago</p>
|
||||
<div class="swaps"><button>Similar</button><button>Anything</button></div>
|
||||
</article>
|
||||
|
||||
<article class="tile t-meat">
|
||||
<p class="tag">Meat</p>
|
||||
<h3 class="dish">Makaronilaatikko</h3>
|
||||
<p class="sides">Served on its own</p>
|
||||
<p class="last">Last eaten 19 days ago</p>
|
||||
<div class="swaps"><button>Similar</button><button>Anything</button></div>
|
||||
</article>
|
||||
|
||||
<article class="tile t-vegetarian">
|
||||
<p class="tag">Vegetarian</p>
|
||||
<h3 class="dish">Hernekeitto</h3>
|
||||
<p class="sides">Served on its own</p>
|
||||
<p class="last">Last eaten 27 days ago</p>
|
||||
<div class="swaps"><button>Similar</button><button>Anything</button></div>
|
||||
</article>
|
||||
|
||||
</div>
|
||||
|
||||
<section class="logstrip">
|
||||
<h2>Recently eaten</h2>
|
||||
<div class="logrow"><time>Thu 3 Sep</time><i class="k-fish"></i><span>Lohikeitto</span><em>Ruisleipä</em></div>
|
||||
<div class="logrow"><time>Wed 2 Sep</time><i class="k-chicken"></i><span>Kanacurry</span><em>Riisi</em></div>
|
||||
<div class="logrow"><time>Tue 1 Sep</time><i class="k-meat"></i><span>Uunimakkara</span><em>Perunamuusi · Vihersalaatti</em></div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
const t=document.getElementById('t'), h=document.documentElement, m=['auto','light','dark'];
|
||||
t.onclick=()=>{const n=m[(m.indexOf(h.dataset.theme)+1)%3]; h.dataset.theme=n; t.textContent='Theme: '+n;};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,199 @@
|
||||
<!doctype html>
|
||||
<html lang="en" data-theme="auto">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Foodster — C · Fridge board</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Kalam:wght@400;700&family=Figtree:wght@400;500;700;800&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root{
|
||||
color-scheme: light dark;
|
||||
--board: light-dark(#E3E7E3, #1A1D1B);
|
||||
--card: light-dark(#FCFCFA, #24272A);
|
||||
--ink: light-dark(#1D2724, #E6E9E5);
|
||||
--muted: light-dark(#6F7A75, #8E9994);
|
||||
--line: light-dark(#D2D8D3, #33383A);
|
||||
--marker:light-dark(#16403C, #6FD3C4);
|
||||
--tape: light-dark(#E8D48A, #6E6134);
|
||||
--meat: light-dark(#AF4230, #E07561);
|
||||
--chicken: light-dark(#BE8410, #DFA83B);
|
||||
--fish: light-dark(#25688F, #63AAD8);
|
||||
--vegetarian:light-dark(#457A3C, #82BE7A);
|
||||
}
|
||||
html[data-theme="light"]{ color-scheme: only light; }
|
||||
html[data-theme="dark"] { color-scheme: only dark; }
|
||||
|
||||
*{box-sizing:border-box;}
|
||||
body{margin:0; background:var(--board); color:var(--ink);
|
||||
font-family:Figtree,system-ui,sans-serif; font-size:16px; line-height:1.5;
|
||||
-webkit-font-smoothing:antialiased;}
|
||||
.wrap{max-width:1100px; margin:0 auto; padding:0 20px 80px;}
|
||||
|
||||
.top{display:flex; align-items:center; gap:18px; flex-wrap:wrap; padding:22px 0 0;}
|
||||
.logo{font-family:Kalam,cursive; font-weight:700; font-size:26px; color:var(--marker);}
|
||||
nav{display:flex; gap:6px; margin-left:auto;}
|
||||
nav a{font-size:14px; font-weight:500; color:var(--muted); text-decoration:none; padding:6px 2px;
|
||||
border-bottom:2px solid transparent;}
|
||||
nav a[aria-current]{color:var(--ink); border-color:var(--marker);}
|
||||
nav a:hover{color:var(--ink);}
|
||||
.themebtn{font-family:Figtree,sans-serif; font-size:13px; background:none;
|
||||
border:1px solid var(--line); color:var(--muted); padding:6px 12px;
|
||||
border-radius:6px; cursor:pointer;}
|
||||
.themebtn:hover{color:var(--ink);}
|
||||
|
||||
header.lede{padding:38px 0 8px; max-width:46ch;}
|
||||
h1{font-family:Figtree,sans-serif; font-weight:800; font-size:clamp(34px,5.5vw,52px);
|
||||
line-height:1.05; letter-spacing:-.03em; margin:0 0 10px;}
|
||||
.lede p{margin:0; color:var(--muted);}
|
||||
.handnote{font-family:Kalam,cursive; font-size:19px; color:var(--marker);
|
||||
transform:rotate(-1.1deg); margin:18px 0 0;}
|
||||
|
||||
.actions{display:flex; gap:10px; margin:24px 0 26px;}
|
||||
.regen{font-family:Figtree,sans-serif; font-weight:700; font-size:15px;
|
||||
background:var(--marker); color:var(--board); border:0; padding:12px 22px;
|
||||
border-radius:7px; cursor:pointer;}
|
||||
.regen:hover{filter:brightness(1.12);}
|
||||
|
||||
/* ---- cards on the board ---- */
|
||||
.cards{display:grid; gap:22px; grid-template-columns:repeat(auto-fill,minmax(238px,1fr));}
|
||||
.card{position:relative; background:var(--card); border-radius:3px; padding:26px 18px 16px;
|
||||
box-shadow:0 1px 2px rgba(0,0,0,.10), 0 6px 14px -8px rgba(0,0,0,.22);}
|
||||
.card:nth-child(3n+1){transform:rotate(-.55deg);}
|
||||
.card:nth-child(3n+2){transform:rotate(.4deg);}
|
||||
.card:nth-child(3n+3){transform:rotate(-.2deg);}
|
||||
.card::before{content:""; position:absolute; top:-7px; left:50%; margin-left:-7px;
|
||||
width:14px; height:14px; border-radius:50%; background:var(--mag,var(--muted));
|
||||
box-shadow:inset 0 -2px 3px rgba(0,0,0,.28);}
|
||||
.m-meat{--mag:var(--meat);} .m-chicken{--mag:var(--chicken);}
|
||||
.m-fish{--mag:var(--fish);} .m-vegetarian{--mag:var(--vegetarian);}
|
||||
.card.wild::before{background:conic-gradient(var(--meat) 0 25%, var(--chicken) 25% 50%,
|
||||
var(--fish) 50% 75%, var(--vegetarian) 75% 100%);}
|
||||
|
||||
.tag{font-size:11px; font-weight:700; letter-spacing:.08em; text-transform:uppercase;
|
||||
color:var(--muted); margin:0;}
|
||||
.dish{font-family:Figtree,sans-serif; font-weight:700; font-size:25px; line-height:1.08;
|
||||
letter-spacing:-.025em; margin:8px 0 8px;}
|
||||
.sides{margin:0 0 10px; font-size:14px; color:var(--ink);}
|
||||
.sides.none{color:var(--muted); font-style:italic;}
|
||||
.last{font-size:12.5px; color:var(--muted); margin:0 0 14px;}
|
||||
.swaps{display:flex; gap:6px; border-top:1px solid var(--line); padding-top:12px;}
|
||||
.swaps button{flex:1; font-family:Figtree,sans-serif; font-size:12.5px; font-weight:600;
|
||||
background:none; color:var(--muted); border:1px solid var(--line);
|
||||
border-radius:6px; padding:8px 5px; cursor:pointer;}
|
||||
.swaps button:hover:not(:disabled){color:var(--marker); border-color:var(--marker);}
|
||||
.swaps button:disabled{opacity:.4; cursor:not-allowed;}
|
||||
|
||||
/* ---- the split: handwriting = what we actually ate ---- */
|
||||
.logstrip{margin-top:56px; border-top:2px dashed var(--line); padding-top:24px;}
|
||||
.logstrip h2{font-family:Figtree,sans-serif; font-weight:800; font-size:18px;
|
||||
letter-spacing:-.02em; margin:0 0 4px;}
|
||||
.logstrip .sub{color:var(--muted); font-size:14px; margin:0 0 18px;}
|
||||
.logrow{display:flex; gap:14px; align-items:baseline; padding:10px 0;
|
||||
border-bottom:1px solid var(--line);}
|
||||
.logrow time{font-size:13px; color:var(--muted); min-width:80px;}
|
||||
.logrow .hand{font-family:Kalam,cursive; font-size:22px; color:var(--marker); line-height:1.2;}
|
||||
.logrow em{font-family:Kalam,cursive; font-style:normal; font-size:17px;
|
||||
color:var(--muted); margin-left:auto;}
|
||||
|
||||
:focus-visible{outline:2.5px solid var(--marker); outline-offset:3px;}
|
||||
@media (max-width:560px){ .card{transform:none!important;} }
|
||||
@media (prefers-reduced-motion:reduce){ *{transition:none!important;} }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
|
||||
<div class="top">
|
||||
<div class="logo">Foodster</div>
|
||||
<nav><a href="#" aria-current="page">Plan</a><a href="#">Log</a><a href="#">Catalog</a></nav>
|
||||
<button class="themebtn" id="t">Theme: auto</button>
|
||||
</div>
|
||||
|
||||
<header class="lede">
|
||||
<h1>Seven dinners on the door.</h1>
|
||||
<p>Take them in any order. Swap what nobody's in the mood for.</p>
|
||||
<p class="handnote">— last regenerated Sunday</p>
|
||||
</header>
|
||||
|
||||
<div class="actions"><button class="regen">New seven</button></div>
|
||||
|
||||
<div class="cards">
|
||||
|
||||
<article class="card m-meat">
|
||||
<p class="tag">Meat</p>
|
||||
<h3 class="dish">Jauhelihakastike</h3>
|
||||
<p class="sides">Perunamuusi · Vihersalaatti</p>
|
||||
<p class="last">Last eaten 23 days ago</p>
|
||||
<div class="swaps"><button>Swap similar</button><button>Swap anything</button></div>
|
||||
</article>
|
||||
|
||||
<article class="card m-chicken">
|
||||
<p class="tag">Chicken</p>
|
||||
<h3 class="dish">Broilerikastike</h3>
|
||||
<p class="sides">Riisi</p>
|
||||
<p class="last">Last eaten 31 days ago</p>
|
||||
<div class="swaps"><button>Swap similar</button><button>Swap anything</button></div>
|
||||
</article>
|
||||
|
||||
<article class="card wild">
|
||||
<p class="tag">Meat · Chicken · Fish · Veg</p>
|
||||
<h3 class="dish">Tortillat</h3>
|
||||
<p class="sides none">Served on its own</p>
|
||||
<p class="last">Last eaten 40 days ago</p>
|
||||
<div class="swaps">
|
||||
<button disabled title="Nothing else covers all four">Swap similar</button>
|
||||
<button>Swap anything</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="card m-fish">
|
||||
<p class="tag">Fish</p>
|
||||
<h3 class="dish">Uunilohi</h3>
|
||||
<p class="sides">Riisi · Vihersalaatti</p>
|
||||
<p class="last">Last eaten 34 days ago</p>
|
||||
<div class="swaps"><button>Swap similar</button><button>Swap anything</button></div>
|
||||
</article>
|
||||
|
||||
<article class="card m-vegetarian">
|
||||
<p class="tag">Vegetarian</p>
|
||||
<h3 class="dish">Kasvispyörykät</h3>
|
||||
<p class="sides">Perunamuusi · Höyrytetyt Porkkanat</p>
|
||||
<p class="last">Last eaten 52 days ago</p>
|
||||
<div class="swaps"><button>Swap similar</button><button>Swap anything</button></div>
|
||||
</article>
|
||||
|
||||
<article class="card m-meat">
|
||||
<p class="tag">Meat</p>
|
||||
<h3 class="dish">Makaronilaatikko</h3>
|
||||
<p class="sides none">Served on its own</p>
|
||||
<p class="last">Last eaten 19 days ago</p>
|
||||
<div class="swaps"><button>Swap similar</button><button>Swap anything</button></div>
|
||||
</article>
|
||||
|
||||
<article class="card m-vegetarian">
|
||||
<p class="tag">Vegetarian</p>
|
||||
<h3 class="dish">Hernekeitto</h3>
|
||||
<p class="sides none">Served on its own</p>
|
||||
<p class="last">Last eaten 27 days ago</p>
|
||||
<div class="swaps"><button>Swap similar</button><button>Swap anything</button></div>
|
||||
</article>
|
||||
|
||||
</div>
|
||||
|
||||
<section class="logstrip">
|
||||
<h2>What we actually ate</h2>
|
||||
<p class="sub">Printed above is the app guessing. Below is the house, on the record.</p>
|
||||
<div class="logrow"><time>Thu 3 Sep</time><span class="hand">Lohikeitto</span><em>ruisleipä</em></div>
|
||||
<div class="logrow"><time>Wed 2 Sep</time><span class="hand">Kanacurry</span><em>riisi</em></div>
|
||||
<div class="logrow"><time>Tue 1 Sep</time><span class="hand">Uunimakkara</span><em>perunamuusi, vihersalaatti</em></div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
const t=document.getElementById('t'), h=document.documentElement, m=['auto','light','dark'];
|
||||
t.onclick=()=>{const n=m[(m.indexOf(h.dataset.theme)+1)%3]; h.dataset.theme=n; t.textContent='Theme: '+n;};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,345 @@
|
||||
<!doctype html>
|
||||
<html lang="fi" data-theme="auto">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Foodster — kirjaus ja historia</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Archivo:wght@400;500;600;700&family=Martian+Mono:wght@300;500&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root{
|
||||
color-scheme: light dark;
|
||||
--paper: light-dark(#ECEDE8, #121316);
|
||||
--card: light-dark(#FFFFFF, #1C1E22);
|
||||
--sunk: light-dark(#E3E4DE, #17181B);
|
||||
--ink: light-dark(#14161A, #E9EAE5);
|
||||
--muted: light-dark(#6B6F6A, #8B8F89);
|
||||
--line: light-dark(#D5D6D0, #2C2F34);
|
||||
--accent:light-dark(#15616D, #58C6D2);
|
||||
--onacc: light-dark(#FFFFFF, #0C1417);
|
||||
--warn: light-dark(#AF4230, #DE7561);
|
||||
--liha: light-dark(#AF4230, #DE7561);
|
||||
--kana: light-dark(#B57E10, #DFA83B);
|
||||
--kala: light-dark(#25688F, #63AAD8);
|
||||
--kasvis:light-dark(#457A3C, #82BE7A);
|
||||
--tap: 48px;
|
||||
}
|
||||
html[data-theme="light"]{color-scheme:only light;}
|
||||
html[data-theme="dark"] {color-scheme:only dark;}
|
||||
*{box-sizing:border-box; -webkit-tap-highlight-color:transparent;}
|
||||
body{margin:0; background:var(--sunk); color:var(--ink);
|
||||
font-family:Archivo,system-ui,sans-serif; font-size:16px; line-height:1.45;
|
||||
-webkit-font-smoothing:antialiased;}
|
||||
button,input{font-family:inherit;}
|
||||
:focus-visible{outline:2.5px solid var(--accent); outline-offset:2px;}
|
||||
@media (prefers-reduced-motion:reduce){*{transition:none!important;}}
|
||||
|
||||
.dot{width:9px; height:9px; border-radius:2px; flex:none; display:inline-block;}
|
||||
.d-liha{background:var(--liha);} .d-kana{background:var(--kana);}
|
||||
.d-kala{background:var(--kala);} .d-kasvis{background:var(--kasvis);}
|
||||
.d-sek{background:conic-gradient(var(--liha) 0 25%,var(--kana) 25% 50%,
|
||||
var(--kala) 50% 75%,var(--kasvis) 75% 100%);}
|
||||
|
||||
/* ---- comparison rig (desktop only) ---- */
|
||||
.rig{padding:20px; max-width:1400px; margin:0 auto;}
|
||||
.rigtop{display:flex; align-items:center; gap:14px; flex-wrap:wrap; margin-bottom:18px;}
|
||||
.rigtop h1{font-size:17px; font-weight:700; letter-spacing:-.02em; margin:0;}
|
||||
.rigtop p{margin:0; font-size:13px; color:var(--muted);}
|
||||
.themebtn{font-size:12px; background:var(--card); border:1px solid var(--line);
|
||||
color:var(--muted); padding:7px 12px; border-radius:7px; cursor:pointer; margin-left:auto;}
|
||||
.switch{display:none; gap:6px; margin-bottom:14px;}
|
||||
.switch button{font-size:14px; font-weight:600; background:var(--card);
|
||||
border:1px solid var(--line); color:var(--muted); padding:10px 12px;
|
||||
border-radius:8px; cursor:pointer; flex:1;}
|
||||
.switch button[aria-pressed="true"]{background:var(--accent); border-color:var(--accent); color:var(--onacc);}
|
||||
.frames{display:flex; gap:22px; align-items:flex-start; overflow-x:auto; padding-bottom:14px;}
|
||||
.framewrap{flex:none;}
|
||||
.framelbl{font-size:13px; font-weight:600; margin:0 0 9px; letter-spacing:-.01em;}
|
||||
.framelbl span{font-weight:400; color:var(--muted);}
|
||||
.phone{width:390px; height:788px; background:var(--paper); border:1px solid var(--line);
|
||||
border-radius:26px; overflow:hidden; display:flex; flex-direction:column;}
|
||||
|
||||
/* ---- app chrome ---- */
|
||||
.screen{flex:1; overflow-y:auto; overscroll-behavior:contain; position:relative;}
|
||||
.appbar{position:sticky; top:0; z-index:5; background:var(--paper);
|
||||
border-bottom:1px solid var(--line); padding:14px 16px 12px;}
|
||||
.appbar h2{margin:0; font-size:22px; font-weight:700; letter-spacing:-.03em;}
|
||||
.appbar .meta{font-size:12.5px; color:var(--muted); margin:2px 0 0;}
|
||||
.pad{padding:16px;}
|
||||
.tabbar{flex:none; display:flex; background:var(--card); border-top:1px solid var(--line);
|
||||
padding-bottom:env(safe-area-inset-bottom);}
|
||||
.tabbar a{flex:1; text-align:center; text-decoration:none; color:var(--muted);
|
||||
font-size:11.5px; font-weight:600; padding:11px 0 13px;}
|
||||
.tabbar a[aria-current]{color:var(--accent);}
|
||||
.tabbar i{display:block; font-style:normal; font-size:18px; line-height:1.3;}
|
||||
.primary{display:block; width:100%; min-height:var(--tap); background:var(--accent);
|
||||
color:var(--onacc); border:0; border-radius:11px; font-size:16.5px; font-weight:700;
|
||||
cursor:pointer; letter-spacing:-.01em;}
|
||||
.ghost{display:block; width:100%; min-height:var(--tap); background:none; color:var(--muted);
|
||||
border:0; font-size:15px; cursor:pointer;}
|
||||
|
||||
/* ---- tap board ---- */
|
||||
.dayseg{display:flex; gap:6px; margin-top:11px;}
|
||||
.dayseg button{flex:1; min-height:42px; font-size:14px; font-weight:600; background:var(--card);
|
||||
border:1px solid var(--line); color:var(--ink); border-radius:9px; cursor:pointer;}
|
||||
.dayseg button[aria-pressed="true"]{background:var(--ink); border-color:var(--ink); color:var(--paper);}
|
||||
.dayseg input{flex:none; width:52px; font-size:16px; background:var(--card); color:var(--ink);
|
||||
border:1px solid var(--line); border-radius:9px; padding:0 8px;}
|
||||
.filter{width:100%; min-height:var(--tap); font-size:16px; background:var(--card);
|
||||
color:var(--ink); border:1px solid var(--line); border-radius:10px;
|
||||
padding:0 14px; margin-bottom:14px;}
|
||||
.board{display:flex; flex-wrap:wrap; gap:8px;}
|
||||
.pill{display:flex; align-items:center; gap:8px; background:var(--card);
|
||||
border:1px solid var(--line); border-radius:11px; cursor:pointer; color:var(--ink);
|
||||
font-weight:600; letter-spacing:-.022em; min-height:var(--tap);}
|
||||
.pill .n{font-family:"Martian Mono",monospace; font-weight:300; color:var(--muted); font-size:10px;}
|
||||
.pill.xl{font-size:22px; padding:14px 18px; flex:1 1 100%;}
|
||||
.pill.lg{font-size:18px; padding:12px 16px;}
|
||||
.pill.md{font-size:15.5px; padding:11px 14px;}
|
||||
.pill.sm{font-size:14px; padding:10px 13px; color:var(--muted);}
|
||||
.pill.picked{background:var(--accent); border-color:var(--accent); color:var(--onacc);}
|
||||
.pill.picked .n{color:var(--onacc); opacity:.65;}
|
||||
|
||||
.sheet{position:absolute; left:0; right:0; bottom:0; z-index:9; background:var(--card);
|
||||
border-top:1px solid var(--line); border-radius:18px 18px 0 0; padding:8px 16px 16px;
|
||||
box-shadow:0 -10px 30px -14px rgba(0,0,0,.4);}
|
||||
.grab{width:38px; height:4px; border-radius:3px; background:var(--line); margin:0 auto 13px;}
|
||||
.sheet h3{margin:0 0 2px; font-size:19px; letter-spacing:-.025em;}
|
||||
.sheet .q{margin:0 0 12px; font-size:13px; color:var(--muted);}
|
||||
.chips{display:flex; gap:7px; flex-wrap:wrap; margin-bottom:14px;}
|
||||
.chips button{font-size:14.5px; min-height:42px; background:var(--sunk);
|
||||
border:1px solid var(--line); color:var(--ink); padding:0 14px;
|
||||
border-radius:999px; cursor:pointer;}
|
||||
.chips button[aria-pressed="true"]{background:var(--accent); border-color:var(--accent); color:var(--onacc);}
|
||||
|
||||
/* ---- already-logged state ---- */
|
||||
.logged{background:var(--card); border:1px solid var(--line); border-radius:14px; padding:18px;}
|
||||
.logged .k{font-family:"Martian Mono",monospace; font-size:10px; letter-spacing:.09em;
|
||||
text-transform:uppercase; color:var(--accent); margin:0 0 10px;}
|
||||
.logged .nm{font-size:26px; font-weight:700; letter-spacing:-.035em; margin:0 0 3px;
|
||||
display:flex; align-items:center; gap:10px;}
|
||||
.logged .sd{font-size:14.5px; color:var(--muted); margin:0 0 16px;}
|
||||
.logged .pair{display:flex; gap:8px;}
|
||||
.logged .pair button{flex:1; min-height:var(--tap); font-size:15px; font-weight:600;
|
||||
background:var(--sunk); border:1px solid var(--line); color:var(--ink);
|
||||
border-radius:10px; cursor:pointer;}
|
||||
.logged .pair button.del{color:var(--warn);}
|
||||
.orlog{margin:22px 0 0; font-size:14px; color:var(--muted); text-align:center;}
|
||||
.orlog button{background:none; border:0; color:var(--accent); font:inherit;
|
||||
font-weight:600; text-decoration:underline; cursor:pointer; min-height:38px;}
|
||||
|
||||
/* ---- journal ---- */
|
||||
.entry{display:flex; gap:12px; align-items:center; padding:14px 0;
|
||||
border-bottom:1px solid var(--line); min-height:var(--tap);}
|
||||
.entry time{font-family:"Martian Mono",monospace; font-size:11px; color:var(--muted);
|
||||
min-width:54px; flex:none;}
|
||||
.entry .nm{font-size:17px; font-weight:600; letter-spacing:-.025em;
|
||||
display:flex; align-items:center; gap:8px;}
|
||||
.entry .sd{font-size:12.5px; color:var(--muted); margin-top:1px;}
|
||||
.entry .chev{margin-left:auto; color:var(--muted); font-size:19px; flex:none;}
|
||||
.gapline{display:flex; gap:12px; align-items:center; padding:12px 0;
|
||||
border-bottom:1px dashed var(--line); font-size:13.5px; color:var(--muted);
|
||||
min-height:var(--tap);}
|
||||
.gapline time{font-family:"Martian Mono",monospace; font-size:11px; min-width:54px; flex:none;}
|
||||
.gapline button{margin-left:auto; font-size:13.5px; background:none; border:0;
|
||||
color:var(--accent); font-weight:600; cursor:pointer; min-height:38px; padding:0 4px;}
|
||||
.monthrule{font-family:"Martian Mono",monospace; font-size:10px; letter-spacing:.12em;
|
||||
text-transform:uppercase; color:var(--muted); padding:22px 0 5px;}
|
||||
|
||||
@media (max-width:900px){
|
||||
body{background:var(--paper);}
|
||||
.rig{padding:0;}
|
||||
.rigtop{padding:12px 16px 0; margin-bottom:10px;}
|
||||
.switch{display:flex; padding:0 16px;}
|
||||
.frames{display:block; overflow:visible; padding:0;}
|
||||
.framewrap{display:none;} .framewrap.on{display:block;}
|
||||
.framelbl{display:none;}
|
||||
.phone{width:auto; height:calc(100svh - 118px); border:0; border-radius:0;}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="rig">
|
||||
|
||||
<div class="rigtop">
|
||||
<h1>Foodster · vaihe 1</h1>
|
||||
<p>390 px · Kirjaa, Historia, ja jo kirjattu ‑tila</p>
|
||||
<button class="themebtn" id="t">Teema: auto</button>
|
||||
</div>
|
||||
|
||||
<div class="switch">
|
||||
<button aria-pressed="true" data-v="f1">Kirjaa</button>
|
||||
<button aria-pressed="false" data-v="f2">Kirjattu</button>
|
||||
<button aria-pressed="false" data-v="f3">Historia</button>
|
||||
</div>
|
||||
|
||||
<div class="frames">
|
||||
|
||||
<!-- ============ 1 · KIRJAA ============ -->
|
||||
<div class="framewrap on" id="f1">
|
||||
<p class="framelbl">1 · Kirjaa <span>— napauta ruoka, valitse lisukkeet</span></p>
|
||||
<div class="phone">
|
||||
<div class="screen">
|
||||
<div class="appbar">
|
||||
<h2>Mitä syötiin?</h2>
|
||||
<div class="dayseg">
|
||||
<button aria-pressed="true">Tänään</button>
|
||||
<button aria-pressed="false">Eilen</button>
|
||||
<input type="date" value="2026-09-05" aria-label="Muu päivä">
|
||||
</div>
|
||||
</div>
|
||||
<div class="pad" style="padding-bottom:280px">
|
||||
<input class="filter" type="search" placeholder="Etsi" aria-label="Etsi">
|
||||
<div class="board">
|
||||
<button class="pill xl"><i class="dot d-liha"></i>Lihapullat <span class="n">12</span></button>
|
||||
<button class="pill xl"><i class="dot d-liha"></i>Jauhelihakastike <span class="n">11</span></button>
|
||||
<button class="pill lg picked"><i class="dot d-kala"></i>Lohikeitto <span class="n">9</span></button>
|
||||
<button class="pill lg"><i class="dot d-kana"></i>Kanacurry <span class="n">8</span></button>
|
||||
<button class="pill lg"><i class="dot d-liha"></i>Makaronilaatikko <span class="n">7</span></button>
|
||||
<button class="pill lg"><i class="dot d-kana"></i>Broilerikastike <span class="n">6</span></button>
|
||||
<button class="pill md"><i class="dot d-kala"></i>Uunilohi <span class="n">5</span></button>
|
||||
<button class="pill md"><i class="dot d-kasvis"></i>Kasvispyörykät <span class="n">5</span></button>
|
||||
<button class="pill md"><i class="dot d-sek"></i>Tortillat <span class="n">4</span></button>
|
||||
<button class="pill md"><i class="dot d-kasvis"></i>Hernekeitto <span class="n">4</span></button>
|
||||
<button class="pill md"><i class="dot d-liha"></i>Uunimakkara <span class="n">3</span></button>
|
||||
<button class="pill sm"><i class="dot d-liha"></i>Kaalilaatikko <span class="n">2</span></button>
|
||||
<button class="pill sm"><i class="dot d-sek"></i>Kotipizza <span class="n">2</span></button>
|
||||
<button class="pill sm"><i class="dot d-kala"></i>Kalapuikot <span class="n">1</span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sheet">
|
||||
<div class="grab"></div>
|
||||
<h3>Lohikeitto</h3>
|
||||
<p class="q">Lisukkeita?</p>
|
||||
<div class="chips">
|
||||
<button aria-pressed="true">Ruisleipä</button>
|
||||
<button aria-pressed="false">Perunamuusi</button>
|
||||
<button aria-pressed="false">Riisi</button>
|
||||
<button aria-pressed="false">Vihersalaatti</button>
|
||||
</div>
|
||||
<button class="primary">Tallenna</button>
|
||||
<button class="ghost">Peruuta</button>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="tabbar">
|
||||
<a href="#" aria-current="page"><i>▦</i>Kirjaa</a>
|
||||
<a href="#"><i>≡</i>Historia</a>
|
||||
<a href="#"><i>◇</i>Ruoat</a>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ============ 2 · JO KIRJATTU ============ -->
|
||||
<div class="framewrap" id="f2">
|
||||
<p class="framelbl">2 · Päivä jo kirjattu <span>— yksi merkintä per päivä</span></p>
|
||||
<div class="phone">
|
||||
<div class="screen">
|
||||
<div class="appbar">
|
||||
<h2>Mitä syötiin?</h2>
|
||||
<div class="dayseg">
|
||||
<button aria-pressed="true">Tänään</button>
|
||||
<button aria-pressed="false">Eilen</button>
|
||||
<input type="date" value="2026-09-05" aria-label="Muu päivä">
|
||||
</div>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<div class="logged">
|
||||
<p class="k">Tänään kirjattu</p>
|
||||
<p class="nm"><i class="dot d-kala"></i>Lohikeitto</p>
|
||||
<p class="sd">Ruisleipä</p>
|
||||
<div class="pair">
|
||||
<button>Muokkaa</button>
|
||||
<button class="del">Poista</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="orlog">Väärä päivä? <button>Kirjaa toinen päivä</button></p>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="tabbar">
|
||||
<a href="#" aria-current="page"><i>▦</i>Kirjaa</a>
|
||||
<a href="#"><i>≡</i>Historia</a>
|
||||
<a href="#"><i>◇</i>Ruoat</a>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ============ 3 · HISTORIA ============ -->
|
||||
<div class="framewrap" id="f3">
|
||||
<p class="framelbl">3 · Historia <span>— lista, ei kalenteria</span></p>
|
||||
<div class="phone">
|
||||
<div class="screen">
|
||||
<div class="appbar">
|
||||
<h2>Historia</h2>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<div class="monthrule">Syyskuu</div>
|
||||
<div class="gapline"><time>pe 4.9.</time><span>Ei merkintää</span><button>Merkitse</button></div>
|
||||
<div class="entry">
|
||||
<time>to 3.9.</time>
|
||||
<div><div class="nm"><i class="dot d-liha"></i>Lihapullat</div><div class="sd">Vihersalaatti</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
<div class="entry">
|
||||
<time>ke 2.9.</time>
|
||||
<div><div class="nm"><i class="dot d-kala"></i>Lohikeitto</div><div class="sd">Ruisleipä</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
<div class="entry">
|
||||
<time>ti 1.9.</time>
|
||||
<div><div class="nm"><i class="dot d-kana"></i>Kanacurry</div><div class="sd">Riisi</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
|
||||
<div class="monthrule">Elokuu</div>
|
||||
<div class="entry">
|
||||
<time>ma 31.8.</time>
|
||||
<div><div class="nm"><i class="dot d-liha"></i>Uunimakkara</div><div class="sd">Perunamuusi</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
<div class="entry">
|
||||
<time>su 30.8.</time>
|
||||
<div><div class="nm"><i class="dot d-kasvis"></i>Kasvispyörykät</div><div class="sd">Ei lisukkeita</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
<div class="entry">
|
||||
<time>la 29.8.</time>
|
||||
<div><div class="nm"><i class="dot d-liha"></i>Lihapullat</div><div class="sd">Perunamuusi</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
<div class="gapline"><time>pe 28.8.</time><span>Ei merkintää</span><button>Merkitse</button></div>
|
||||
<div class="entry">
|
||||
<time>to 27.8.</time>
|
||||
<div><div class="nm"><i class="dot d-kana"></i>Kanacurry</div><div class="sd">Riisi</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
<div class="entry">
|
||||
<time>ke 26.8.</time>
|
||||
<div><div class="nm"><i class="dot d-liha"></i>Jauhelihakastike</div><div class="sd">Perunamuusi, vihersalaatti</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="tabbar">
|
||||
<a href="#"><i>▦</i>Kirjaa</a>
|
||||
<a href="#" aria-current="page"><i>≡</i>Historia</a>
|
||||
<a href="#"><i>◇</i>Ruoat</a>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
const h=document.documentElement, tb=document.getElementById('t'), m=['auto','light','dark'];
|
||||
tb.onclick=()=>{const n=m[(m.indexOf(h.dataset.theme)+1)%3];h.dataset.theme=n;tb.textContent='Teema: '+n;};
|
||||
document.querySelectorAll('.switch button').forEach(b=>b.onclick=()=>{
|
||||
document.querySelectorAll('.switch button').forEach(x=>x.setAttribute('aria-pressed',x===b));
|
||||
document.querySelectorAll('.framewrap').forEach(f=>f.classList.toggle('on',f.id===b.dataset.v));
|
||||
});
|
||||
document.querySelectorAll('.chips button,.dayseg button').forEach(b=>b.onclick=()=>
|
||||
b.setAttribute('aria-pressed', b.getAttribute('aria-pressed')!=='true'));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,440 @@
|
||||
<!doctype html>
|
||||
<html lang="en" data-theme="auto">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Foodster — stage 1 log · mobile layouts</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Archivo:wght@400;500;600;700&family=Martian+Mono:wght@300;500&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
/* ============ shared skin ============ */
|
||||
:root{
|
||||
color-scheme: light dark;
|
||||
--paper: light-dark(#ECEDE8, #121316);
|
||||
--card: light-dark(#FFFFFF, #1C1E22);
|
||||
--sunk: light-dark(#E3E4DE, #17181B);
|
||||
--ink: light-dark(#14161A, #E9EAE5);
|
||||
--muted: light-dark(#6B6F6A, #8B8F89);
|
||||
--line: light-dark(#D5D6D0, #2C2F34);
|
||||
--accent:light-dark(#15616D, #58C6D2);
|
||||
--onacc: light-dark(#FFFFFF, #0C1417);
|
||||
--meat: light-dark(#AF4230, #DE7561);
|
||||
--chicken: light-dark(#B57E10, #DFA83B);
|
||||
--fish: light-dark(#25688F, #63AAD8);
|
||||
--vegetarian:light-dark(#457A3C, #82BE7A);
|
||||
--tap: 48px; /* minimum touch target */
|
||||
}
|
||||
html[data-theme="light"]{color-scheme:only light;}
|
||||
html[data-theme="dark"] {color-scheme:only dark;}
|
||||
*{box-sizing:border-box; -webkit-tap-highlight-color:transparent;}
|
||||
body{margin:0; background:var(--sunk); color:var(--ink);
|
||||
font-family:Archivo,system-ui,sans-serif; font-size:16px; line-height:1.45;
|
||||
-webkit-font-smoothing:antialiased;}
|
||||
button,input{font-family:inherit;}
|
||||
:focus-visible{outline:2.5px solid var(--accent); outline-offset:2px;}
|
||||
@media (prefers-reduced-motion:reduce){*{transition:none!important;}}
|
||||
|
||||
.dot{width:9px; height:9px; border-radius:2px; flex:none; display:inline-block;}
|
||||
.d-meat{background:var(--meat);} .d-chicken{background:var(--chicken);}
|
||||
.d-fish{background:var(--fish);} .d-vegetarian{background:var(--vegetarian);}
|
||||
.d-wild{background:conic-gradient(var(--meat) 0 25%,var(--chicken) 25% 50%,
|
||||
var(--fish) 50% 75%,var(--vegetarian) 75% 100%);}
|
||||
|
||||
/* ============ comparison rig (desktop only) ============ */
|
||||
.rig{padding:20px; max-width:1400px; margin:0 auto;}
|
||||
.rigtop{display:flex; align-items:center; gap:14px; flex-wrap:wrap; margin-bottom:18px;}
|
||||
.rigtop h1{font-size:17px; font-weight:700; letter-spacing:-.02em; margin:0;}
|
||||
.rigtop p{margin:0; font-size:13px; color:var(--muted);}
|
||||
.themebtn{font-size:12px; background:var(--card); border:1px solid var(--line);
|
||||
color:var(--muted); padding:7px 12px; border-radius:7px; cursor:pointer; margin-left:auto;}
|
||||
.switch{display:none; gap:6px; margin-bottom:14px; flex-wrap:wrap;}
|
||||
.switch button{font-size:14px; font-weight:600; background:var(--card);
|
||||
border:1px solid var(--line); color:var(--muted); padding:10px 14px;
|
||||
border-radius:8px; cursor:pointer; flex:1;}
|
||||
.switch button[aria-pressed="true"]{background:var(--accent); border-color:var(--accent); color:var(--onacc);}
|
||||
.frames{display:flex; gap:22px; align-items:flex-start; overflow-x:auto; padding-bottom:14px;}
|
||||
.framewrap{flex:none;}
|
||||
.framelbl{font-size:13px; font-weight:600; margin:0 0 9px; letter-spacing:-.01em;}
|
||||
.framelbl span{font-weight:400; color:var(--muted);}
|
||||
|
||||
.phone{width:390px; height:788px; background:var(--paper); border:1px solid var(--line);
|
||||
border-radius:26px; overflow:hidden; display:flex; flex-direction:column;}
|
||||
|
||||
/* ============ in-app chrome ============ */
|
||||
.screen{flex:1; overflow-y:auto; overscroll-behavior:contain;}
|
||||
.appbar{position:sticky; top:0; z-index:5; background:var(--paper);
|
||||
border-bottom:1px solid var(--line); padding:14px 16px 12px;}
|
||||
.appbar h2{margin:0; font-size:22px; font-weight:700; letter-spacing:-.03em;}
|
||||
.appbar .meta{font-size:12.5px; color:var(--muted); margin:2px 0 0;}
|
||||
.pad{padding:16px;}
|
||||
|
||||
.tabbar{flex:none; display:flex; background:var(--card); border-top:1px solid var(--line);
|
||||
padding-bottom:env(safe-area-inset-bottom);}
|
||||
.tabbar a{flex:1; text-align:center; text-decoration:none; color:var(--muted);
|
||||
font-size:11.5px; font-weight:600; padding:11px 0 13px; letter-spacing:.01em;}
|
||||
.tabbar a[aria-current]{color:var(--accent);}
|
||||
.tabbar i{display:block; font-style:normal; font-size:18px; line-height:1.3;}
|
||||
|
||||
.primary{display:block; width:100%; min-height:var(--tap); background:var(--accent);
|
||||
color:var(--onacc); border:0; border-radius:11px; font-size:16.5px; font-weight:700;
|
||||
cursor:pointer; letter-spacing:-.01em;}
|
||||
.ghost{display:block; width:100%; min-height:var(--tap); background:none; color:var(--muted);
|
||||
border:0; font-size:15px; cursor:pointer;}
|
||||
|
||||
/* ============ 1 · CALENDAR-LED ============ */
|
||||
.mini{display:grid; grid-template-columns:repeat(7,1fr); gap:4px;}
|
||||
.mini .wn{font-size:9.5px; letter-spacing:.06em; text-transform:uppercase;
|
||||
color:var(--muted); text-align:center; padding-bottom:3px;}
|
||||
.mini button{aspect-ratio:1; background:var(--card); border:1px solid var(--line);
|
||||
border-radius:8px; cursor:pointer; display:flex; flex-direction:column;
|
||||
align-items:center; justify-content:center; gap:4px; padding:0; color:var(--muted);
|
||||
font-size:11px;}
|
||||
.mini button .dot{width:11px; height:11px; border-radius:3px;}
|
||||
.mini button.empty{background:none; border-style:dashed;}
|
||||
.mini button.empty::after{content:"+"; font-size:14px; opacity:.45;}
|
||||
.mini button.today{border:2px solid var(--accent); color:var(--accent); font-weight:700;}
|
||||
.mini button.future{opacity:.3; border-color:transparent; background:none;}
|
||||
.tally{display:flex; align-items:baseline; gap:8px; margin:14px 0 0; font-size:12.5px;
|
||||
color:var(--muted);}
|
||||
.tally b{color:var(--ink); font-size:14px;}
|
||||
.bar{flex:1; height:5px; border-radius:3px; background:var(--line); overflow:hidden;}
|
||||
.bar i{display:block; height:100%; background:var(--accent);}
|
||||
.tonight{background:var(--card); border:1px solid var(--line); border-radius:13px;
|
||||
padding:16px; margin:18px 0 0;}
|
||||
.tonight .k{font-family:"Martian Mono",monospace; font-size:10px; letter-spacing:.08em;
|
||||
text-transform:uppercase; color:var(--muted); margin:0 0 9px;}
|
||||
.dayrow{display:flex; gap:12px; align-items:center; padding:13px 0;
|
||||
border-bottom:1px solid var(--line); min-height:var(--tap);}
|
||||
.dayrow time{font-family:"Martian Mono",monospace; font-size:11px; color:var(--muted);
|
||||
min-width:56px; flex:none;}
|
||||
.dayrow .nm{font-size:16px; font-weight:600; letter-spacing:-.02em;}
|
||||
.dayrow .sd{font-size:12.5px; color:var(--muted);}
|
||||
.dayrow .chev{margin-left:auto; color:var(--muted); font-size:18px;}
|
||||
.sechead{font-family:"Martian Mono",monospace; font-size:10px; letter-spacing:.09em;
|
||||
text-transform:uppercase; color:var(--muted); margin:24px 0 4px;}
|
||||
|
||||
/* ============ 2 · TAP BOARD ============ */
|
||||
.dayseg{display:flex; gap:6px; margin-top:11px;}
|
||||
.dayseg button{flex:1; min-height:42px; font-size:14px; font-weight:600; background:var(--card);
|
||||
border:1px solid var(--line); color:var(--ink); border-radius:9px; cursor:pointer;}
|
||||
.dayseg button[aria-pressed="true"]{background:var(--ink); border-color:var(--ink); color:var(--paper);}
|
||||
.dayseg input{flex:none; width:52px; font-size:16px; background:var(--card); color:var(--ink);
|
||||
border:1px solid var(--line); border-radius:9px; padding:0 8px;}
|
||||
.filter{width:100%; min-height:var(--tap); font-size:16px; background:var(--card);
|
||||
color:var(--ink); border:1px solid var(--line); border-radius:10px;
|
||||
padding:0 14px; margin-bottom:14px;}
|
||||
.board{display:flex; flex-wrap:wrap; gap:8px;}
|
||||
.pill{display:flex; align-items:center; gap:8px; background:var(--card);
|
||||
border:1px solid var(--line); border-radius:11px; cursor:pointer; color:var(--ink);
|
||||
font-weight:600; letter-spacing:-.022em; min-height:var(--tap);}
|
||||
.pill .n{font-family:"Martian Mono",monospace; font-weight:300; color:var(--muted); font-size:10px;}
|
||||
.pill.xl{font-size:22px; padding:14px 18px; flex:1 1 100%;}
|
||||
.pill.lg{font-size:18px; padding:12px 16px;}
|
||||
.pill.md{font-size:15.5px; padding:11px 14px;}
|
||||
.pill.sm{font-size:14px; padding:10px 13px; color:var(--muted);}
|
||||
.pill.picked{background:var(--accent); border-color:var(--accent); color:var(--onacc);}
|
||||
.pill.picked .n{color:var(--onacc); opacity:.65;}
|
||||
|
||||
.sheetwrap{position:relative;}
|
||||
.sheet{position:absolute; left:0; right:0; bottom:0; z-index:9; background:var(--card);
|
||||
border-top:1px solid var(--line); border-radius:18px 18px 0 0; padding:8px 16px 16px;
|
||||
box-shadow:0 -10px 30px -14px rgba(0,0,0,.4);}
|
||||
.grab{width:38px; height:4px; border-radius:3px; background:var(--line); margin:0 auto 13px;}
|
||||
.sheet h3{margin:0 0 2px; font-size:19px; letter-spacing:-.025em;}
|
||||
.sheet .q{margin:0 0 12px; font-size:13px; color:var(--muted);}
|
||||
.chips{display:flex; gap:7px; flex-wrap:wrap; margin-bottom:14px;}
|
||||
.chips button{font-size:14.5px; min-height:42px; background:var(--sunk);
|
||||
border:1px solid var(--line); color:var(--ink); padding:0 14px;
|
||||
border-radius:999px; cursor:pointer;}
|
||||
.chips button[aria-pressed="true"]{background:var(--accent); border-color:var(--accent); color:var(--onacc);}
|
||||
|
||||
/* ============ 3 · JOURNAL ============ */
|
||||
.jtonight{background:var(--accent); color:var(--onacc); border-radius:14px;
|
||||
padding:16px; margin-bottom:20px;}
|
||||
.jtonight .k{font-family:"Martian Mono",monospace; font-size:10px; letter-spacing:.09em;
|
||||
text-transform:uppercase; opacity:.75; margin:0 0 5px;}
|
||||
.jtonight p{margin:0 0 13px; font-size:19px; font-weight:600; letter-spacing:-.025em;}
|
||||
.jtonight button{width:100%; min-height:var(--tap); background:var(--onacc); color:var(--accent);
|
||||
border:0; border-radius:10px; font-size:16px; font-weight:700; cursor:pointer;}
|
||||
.entry{display:flex; gap:12px; align-items:center; padding:14px 0;
|
||||
border-bottom:1px solid var(--line); min-height:var(--tap);}
|
||||
.entry time{font-family:"Martian Mono",monospace; font-size:11px; color:var(--muted);
|
||||
min-width:52px; flex:none;}
|
||||
.entry .nm{font-size:17px; font-weight:600; letter-spacing:-.025em;
|
||||
display:flex; align-items:center; gap:8px;}
|
||||
.entry .sd{font-size:12.5px; color:var(--muted); margin-top:1px;}
|
||||
.entry .chev{margin-left:auto; color:var(--muted); font-size:19px; flex:none;}
|
||||
.gapline{display:flex; gap:12px; align-items:center; padding:12px 0;
|
||||
border-bottom:1px dashed var(--line); font-size:13.5px; color:var(--muted);
|
||||
min-height:var(--tap);}
|
||||
.gapline time{font-family:"Martian Mono",monospace; font-size:11px; min-width:52px; flex:none;}
|
||||
.gapline button{margin-left:auto; font-size:13.5px; background:none; border:0;
|
||||
color:var(--accent); font-weight:600; cursor:pointer; min-height:38px; padding:0 4px;}
|
||||
.monthrule{font-family:"Martian Mono",monospace; font-size:10px; letter-spacing:.12em;
|
||||
text-transform:uppercase; color:var(--muted); padding:22px 0 5px;}
|
||||
|
||||
/* ============ real phone: drop the rig, go full bleed ============ */
|
||||
@media (max-width:900px){
|
||||
body{background:var(--paper);}
|
||||
.rig{padding:0;}
|
||||
.rigtop{padding:12px 16px 0; margin-bottom:10px;}
|
||||
.switch{display:flex; padding:0 16px;}
|
||||
.frames{display:block; overflow:visible; padding:0;}
|
||||
.framewrap{display:none;}
|
||||
.framewrap.on{display:block;}
|
||||
.framelbl{display:none;}
|
||||
.phone{width:auto; height:calc(100svh - 118px); border:0; border-radius:0;}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="rig">
|
||||
|
||||
<div class="rigtop">
|
||||
<h1>Foodster · stage 1 log</h1>
|
||||
<p>390 px. Three structures, one skin.</p>
|
||||
<button class="themebtn" id="t">Theme: auto</button>
|
||||
</div>
|
||||
|
||||
<div class="switch">
|
||||
<button aria-pressed="true" data-v="f1">Calendar</button>
|
||||
<button aria-pressed="false" data-v="f2">Tap board</button>
|
||||
<button aria-pressed="false" data-v="f3">Journal</button>
|
||||
</div>
|
||||
|
||||
<div class="frames">
|
||||
|
||||
<!-- ================= 1 · CALENDAR-LED ================= -->
|
||||
<div class="framewrap on" id="f1">
|
||||
<p class="framelbl">1 · Calendar-led <span>— history first, calendar navigates</span></p>
|
||||
<div class="phone">
|
||||
<div class="screen">
|
||||
<div class="appbar">
|
||||
<h2>What we ate</h2>
|
||||
<p class="meta">Last five weeks · 3 Aug – 6 Sep</p>
|
||||
</div>
|
||||
<div class="pad">
|
||||
|
||||
<div class="mini" aria-hidden="true">
|
||||
<div class="wn">M</div><div class="wn">T</div><div class="wn">W</div><div class="wn">T</div>
|
||||
<div class="wn">F</div><div class="wn">S</div><div class="wn">S</div>
|
||||
</div>
|
||||
<div class="mini">
|
||||
<button>3<i class="dot d-meat"></i></button>
|
||||
<button>4<i class="dot d-fish"></i></button>
|
||||
<button class="empty">5</button>
|
||||
<button>6<i class="dot d-meat"></i></button>
|
||||
<button>7<i class="dot d-wild"></i></button>
|
||||
<button>8<i class="dot d-vegetarian"></i></button>
|
||||
<button>9<i class="dot d-fish"></i></button>
|
||||
|
||||
<button>10<i class="dot d-chicken"></i></button>
|
||||
<button>11<i class="dot d-vegetarian"></i></button>
|
||||
<button>12<i class="dot d-meat"></i></button>
|
||||
<button class="empty">13</button>
|
||||
<button>14<i class="dot d-chicken"></i></button>
|
||||
<button>15<i class="dot d-meat"></i></button>
|
||||
<button>16<i class="dot d-fish"></i></button>
|
||||
|
||||
<button>17<i class="dot d-meat"></i></button>
|
||||
<button>18<i class="dot d-vegetarian"></i></button>
|
||||
<button>19<i class="dot d-meat"></i></button>
|
||||
<button class="empty">20</button>
|
||||
<button>21<i class="dot d-wild"></i></button>
|
||||
<button>22<i class="dot d-chicken"></i></button>
|
||||
<button>23<i class="dot d-meat"></i></button>
|
||||
|
||||
<button>24<i class="dot d-fish"></i></button>
|
||||
<button>25<i class="dot d-vegetarian"></i></button>
|
||||
<button>26<i class="dot d-meat"></i></button>
|
||||
<button>27<i class="dot d-chicken"></i></button>
|
||||
<button class="empty">28</button>
|
||||
<button>29<i class="dot d-meat"></i></button>
|
||||
<button>30<i class="dot d-vegetarian"></i></button>
|
||||
|
||||
<button>31<i class="dot d-meat"></i></button>
|
||||
<button>1<i class="dot d-chicken"></i></button>
|
||||
<button>2<i class="dot d-fish"></i></button>
|
||||
<button>3<i class="dot d-meat"></i></button>
|
||||
<button class="empty">4</button>
|
||||
<button class="today">5</button>
|
||||
<button class="future">6</button>
|
||||
</div>
|
||||
|
||||
<div class="tally">
|
||||
<b>30</b><span>of 35 logged</span>
|
||||
<span class="bar"><i style="width:86%"></i></span>
|
||||
</div>
|
||||
|
||||
<div class="tonight">
|
||||
<p class="k">Tonight · Sat 5 Sep</p>
|
||||
<button class="primary">Log tonight's dinner</button>
|
||||
</div>
|
||||
|
||||
<p class="sechead">Recent</p>
|
||||
<div class="dayrow">
|
||||
<time>Thu 3</time>
|
||||
<div><div class="nm">Lihapullat</div><div class="sd">Vihersalaatti</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
<div class="dayrow">
|
||||
<time>Wed 2</time>
|
||||
<div><div class="nm">Lohikeitto</div><div class="sd">Ruisleipä</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
<div class="dayrow">
|
||||
<time>Tue 1</time>
|
||||
<div><div class="nm">Kanacurry</div><div class="sd">Riisi</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="tabbar">
|
||||
<a href="#" aria-current="page"><i>▦</i>Log</a>
|
||||
<a href="#"><i>≡</i>History</a>
|
||||
<a href="#"><i>◇</i>Catalog</a>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================= 2 · TAP BOARD ================= -->
|
||||
<div class="framewrap" id="f2">
|
||||
<p class="framelbl">2 · Tap board <span>— fastest entry, sheet in the thumb zone</span></p>
|
||||
<div class="phone">
|
||||
<div class="screen sheetwrap">
|
||||
<div class="appbar">
|
||||
<h2>Tap what you ate</h2>
|
||||
<div class="dayseg">
|
||||
<button aria-pressed="true">Today</button>
|
||||
<button aria-pressed="false">Yesterday</button>
|
||||
<input type="date" value="2026-09-05" aria-label="Another date">
|
||||
</div>
|
||||
</div>
|
||||
<div class="pad" style="padding-bottom:270px">
|
||||
<input class="filter" type="search" placeholder="Filter dishes…" aria-label="Filter dishes">
|
||||
<div class="board">
|
||||
<button class="pill xl"><i class="dot d-meat"></i>Lihapullat <span class="n">12</span></button>
|
||||
<button class="pill xl"><i class="dot d-meat"></i>Jauhelihakastike <span class="n">11</span></button>
|
||||
<button class="pill lg picked"><i class="dot d-fish"></i>Lohikeitto <span class="n">9</span></button>
|
||||
<button class="pill lg"><i class="dot d-chicken"></i>Kanacurry <span class="n">8</span></button>
|
||||
<button class="pill lg"><i class="dot d-meat"></i>Makaronilaatikko <span class="n">7</span></button>
|
||||
<button class="pill lg"><i class="dot d-chicken"></i>Broilerikastike <span class="n">6</span></button>
|
||||
<button class="pill md"><i class="dot d-fish"></i>Uunilohi <span class="n">5</span></button>
|
||||
<button class="pill md"><i class="dot d-vegetarian"></i>Kasvispyörykät <span class="n">5</span></button>
|
||||
<button class="pill md"><i class="dot d-wild"></i>Tortillat <span class="n">4</span></button>
|
||||
<button class="pill md"><i class="dot d-vegetarian"></i>Hernekeitto <span class="n">4</span></button>
|
||||
<button class="pill md"><i class="dot d-meat"></i>Uunimakkara <span class="n">3</span></button>
|
||||
<button class="pill sm"><i class="dot d-meat"></i>Kaalilaatikko <span class="n">2</span></button>
|
||||
<button class="pill sm"><i class="dot d-wild"></i>Kotipizza <span class="n">2</span></button>
|
||||
<button class="pill sm"><i class="dot d-fish"></i>Kalapuikot <span class="n">1</span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sheet">
|
||||
<div class="grab"></div>
|
||||
<h3>Lohikeitto</h3>
|
||||
<p class="q">Anything on the side?</p>
|
||||
<div class="chips">
|
||||
<button aria-pressed="true">Ruisleipä</button>
|
||||
<button aria-pressed="false">Perunamuusi</button>
|
||||
<button aria-pressed="false">Riisi</button>
|
||||
<button aria-pressed="false">Vihersalaatti</button>
|
||||
</div>
|
||||
<button class="primary">Save Saturday</button>
|
||||
<button class="ghost">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="tabbar">
|
||||
<a href="#" aria-current="page"><i>▦</i>Log</a>
|
||||
<a href="#"><i>≡</i>History</a>
|
||||
<a href="#"><i>◇</i>Catalog</a>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================= 3 · JOURNAL ================= -->
|
||||
<div class="framewrap" id="f3">
|
||||
<p class="framelbl">3 · Journal <span>— one column, gaps called out inline</span></p>
|
||||
<div class="phone">
|
||||
<div class="screen">
|
||||
<div class="appbar">
|
||||
<h2>Dinner journal</h2>
|
||||
<p class="meta">One line per night</p>
|
||||
</div>
|
||||
<div class="pad">
|
||||
|
||||
<div class="jtonight">
|
||||
<p class="k">Tonight · Sat 5 Sep</p>
|
||||
<p>Nothing written down yet.</p>
|
||||
<button>What did we eat?</button>
|
||||
</div>
|
||||
|
||||
<div class="monthrule">September</div>
|
||||
|
||||
<div class="gapline"><time>Fri 4</time><span>Not logged</span><button>Fill in</button></div>
|
||||
|
||||
<div class="entry">
|
||||
<time>Thu 3</time>
|
||||
<div><div class="nm"><i class="dot d-meat"></i>Lihapullat</div><div class="sd">Vihersalaatti</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
<div class="entry">
|
||||
<time>Wed 2</time>
|
||||
<div><div class="nm"><i class="dot d-fish"></i>Lohikeitto</div><div class="sd">Ruisleipä</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
<div class="entry">
|
||||
<time>Tue 1</time>
|
||||
<div><div class="nm"><i class="dot d-chicken"></i>Kanacurry</div><div class="sd">Riisi</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
|
||||
<div class="monthrule">August</div>
|
||||
|
||||
<div class="entry">
|
||||
<time>Mon 31</time>
|
||||
<div><div class="nm"><i class="dot d-meat"></i>Uunimakkara</div><div class="sd">Perunamuusi</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
<div class="entry">
|
||||
<time>Sun 30</time>
|
||||
<div><div class="nm"><i class="dot d-vegetarian"></i>Kasvispyörykät</div><div class="sd">Served on its own</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
<div class="entry">
|
||||
<time>Sat 29</time>
|
||||
<div><div class="nm"><i class="dot d-meat"></i>Lihapullat</div><div class="sd">Perunamuusi</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
<div class="gapline"><time>Fri 28</time><span>Not logged</span><button>Fill in</button></div>
|
||||
<div class="entry">
|
||||
<time>Thu 27</time>
|
||||
<div><div class="nm"><i class="dot d-chicken"></i>Kanacurry</div><div class="sd">Riisi</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="tabbar">
|
||||
<a href="#" aria-current="page"><i>▦</i>Log</a>
|
||||
<a href="#"><i>≡</i>History</a>
|
||||
<a href="#"><i>◇</i>Catalog</a>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const h=document.documentElement, tb=document.getElementById('t'), m=['auto','light','dark'];
|
||||
tb.onclick=()=>{const n=m[(m.indexOf(h.dataset.theme)+1)%3];h.dataset.theme=n;tb.textContent='Theme: '+n;};
|
||||
document.querySelectorAll('.switch button').forEach(b=>b.onclick=()=>{
|
||||
document.querySelectorAll('.switch button').forEach(x=>x.setAttribute('aria-pressed',x===b));
|
||||
document.querySelectorAll('.framewrap').forEach(f=>f.classList.toggle('on',f.id===b.dataset.v));
|
||||
});
|
||||
document.querySelectorAll('.chips button,.dayseg button').forEach(b=>b.onclick=()=>
|
||||
b.setAttribute('aria-pressed', b.getAttribute('aria-pressed')!=='true'));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user