/* ==========================================================================
   Back to the Root
   One typeface, square corners, hairline rules. Motion is used to move
   between states, never for decoration.
   ========================================================================== */

:root{
  --forest:#042414;
  --root:#0B3B2A;
  --root-hover:#08301F;
  --wheat:#DFB27D;
  --wheat-deep:#C08A4B;
  --leaf:#3F7A56;
  --sand:#F6F2EA;
  --paper:#FFFFFF;
  --ink:#141915;
  --muted:#6B7269;
  --line:#E6E1D6;
  --line-dark:rgba(255,255,255,.18);
  --warn:#A8452C;

  --sans:"Figtree","Helvetica Neue",Arial,sans-serif;
  --ease:cubic-bezier(.22,.7,.28,1);

  --pad:32px;
  --max:1240px;
  --nav-h:74px;
  --sp:104px;
}

*,*::before,*::after{box-sizing:border-box;border-radius:0}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{
  margin:0;font-family:var(--sans);font-size:17px;line-height:1.6;font-weight:400;
  color:var(--ink);background:var(--paper);-webkit-font-smoothing:antialiased;
  /* clip, NOT hidden.

     overflow-x:hidden on body makes body a scroll container. That breaks
     position:sticky inside it and stops scroll events reaching the window -
     which is why the scroll sequence never behaved: its listener was never
     called, so the frame and the scrollbar could not agree.

     overflow-x:clip stops sideways scrolling without creating a scroll
     container, so sticky and scroll events both work. The sideways overflow
     it was hiding is fixed properly at source now (.daysshow-stage). */
  overflow-x:clip;
}
img{max-width:100%;display:block;border:0}
a{color:var(--root);text-decoration:none;transition:color .18s var(--ease)}
a:hover{color:var(--wheat-deep)}
button,input,select,textarea{font:inherit;color:inherit}
:focus-visible{outline:2px solid var(--root);outline-offset:3px}
::selection{background:var(--wheat);color:var(--forest)}

h1,h2,h3,h4{margin:0;font-weight:600;letter-spacing:-.03em;line-height:1.05}
h1{font-size:clamp(38px,5.6vw,74px)}
h2{font-size:clamp(28px,3.6vw,46px)}
h3{font-size:clamp(19px,2vw,26px);letter-spacing:-.02em}
h4{font-size:17px;letter-spacing:-.01em}
p{margin:0 0 18px}
.lede{font-size:clamp(17px,1.4vw,20px);line-height:1.55;color:var(--muted);max-width:56ch}
.small{font-size:14px;color:var(--muted)}
.hl{font-style:normal;color:var(--wheat-deep)}
strong{font-weight:600}

/* small labels, in the same family so nothing reads as machine print */
.mono,.label-txt{font-size:12px;font-weight:600;letter-spacing:.06em;color:var(--muted)}
.eyebrow{display:block;font-size:12px;font-weight:600;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);margin:0 0 14px}

.wrap{width:100%;max-width:var(--max);margin:0 auto;padding:0 var(--pad)}
.section{padding:var(--sp) 0}
.section.tight{padding:56px 0}
.section.hair{border-top:1px solid var(--line)}
.sand{background:var(--sand)}
.dark{background:var(--forest);color:#E6E9E4}
.dark h1,.dark h2,.dark h3,.dark h4{color:#fff}
.dark .lede,.dark .small{color:#B3BDB2}
.dark a{color:var(--wheat)}
.grid{display:grid;gap:26px}
.g2{grid-template-columns:repeat(2,minmax(0,1fr))}
.g3{grid-template-columns:repeat(3,minmax(0,1fr))}
.g4{grid-template-columns:repeat(4,minmax(0,1fr))}
.split{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:60px;align-items:start}
.split.wide-left{grid-template-columns:minmax(0,1.25fr) minmax(0,1fr)}
.center{text-align:center}
.rule{height:1px;background:var(--line);border:0;margin:0}

/* ---------- motion ---------- */
.reveal{opacity:0;transform:translateY(18px);
  transition:opacity .7s var(--ease),transform .7s var(--ease);
  transition-delay:calc(var(--i,0) * 70ms)}
.reveal.in{opacity:1;transform:none}
.fade-in{animation:fadeUp .5s var(--ease) both}
@keyframes fadeUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
@keyframes fadeSide{from{opacity:0;transform:translateX(14px)}to{opacity:1;transform:none}}
@keyframes pop{from{opacity:0;transform:scale(.97)}to{opacity:1;transform:none}}

/* ---------- navigation ---------- */
.util{background:var(--forest);color:#B3BDB2;font-size:12.5px;letter-spacing:.04em}
.util .wrap{display:flex;justify-content:space-between;gap:16px;padding:10px var(--pad)}
.util a{color:var(--wheat)}
.nav{position:sticky;top:0;z-index:60;background:rgba(255,255,255,.94);
  backdrop-filter:saturate(1.2) blur(6px);border-bottom:1px solid var(--line)}
.nav-in{display:flex;align-items:center;justify-content:space-between;height:var(--nav-h);gap:24px}
.brand{display:flex;align-items:center;gap:13px;color:var(--root)}
.brand:hover{color:var(--root)}
.brand img{width:46px;height:46px;flex:none;transition:transform .4s var(--ease)}
.brand:hover img{transform:rotate(-4deg) scale(1.04)}
.brand b{display:block;font-size:15px;font-weight:700;letter-spacing:-.01em;line-height:1.2}
.brand span{display:block;font-size:11.5px;color:var(--muted);letter-spacing:.02em}
.nav-links{display:flex;align-items:center;gap:30px}
.nav-links a{font-size:15px;color:var(--ink);padding:4px 0;position:relative}
.nav-links a:not(.btn)::after{content:"";position:absolute;left:0;right:100%;bottom:-2px;height:2px;
  background:var(--wheat);transition:right .28s var(--ease)}
.nav-links a:not(.btn):hover::after,.nav-links a[aria-current="page"]::after{right:0}
.nav-toggle{display:none;background:none;border:1px solid var(--line);padding:10px 13px;
  cursor:pointer;font-size:13px;font-weight:600}

/* ---------- buttons ---------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  padding:14px 26px;border:1px solid var(--root);background:var(--root);color:#fff;
  font-family:var(--sans);font-weight:600;font-size:15px;cursor:pointer;text-align:center;
  transition:background .2s var(--ease),color .2s var(--ease),transform .2s var(--ease);
}
.btn:hover{background:var(--root-hover);color:#fff;transform:translateY(-1px)}
.btn:active{transform:translateY(0)}
.btn.ghost{background:transparent;color:var(--root)}
.btn.ghost:hover{background:var(--root);color:#fff}
.btn.wheat{background:var(--wheat);border-color:var(--wheat);color:var(--forest)}
.btn.wheat:hover{background:var(--wheat-deep);color:#fff}
.btn.light{background:transparent;border-color:rgba(255,255,255,.45);color:#fff}
.btn.light:hover{background:#fff;color:var(--forest)}
.btn.sm{padding:10px 18px;font-size:14px}
.btn.block{width:100%}
.btn[disabled]{opacity:.45;cursor:not-allowed;transform:none}
.btn-row{display:flex;gap:14px;flex-wrap:wrap}
/* the header action, white on green */
.nav-links .btn{background:var(--root);border-color:var(--root);color:#fff}
.nav-links .btn:hover{background:var(--forest);border-color:var(--forest);color:#fff}

/* ---------- surfaces ---------- */
.card{border:1px solid var(--line);background:var(--paper);padding:26px;
  transition:border-color .2s var(--ease),transform .2s var(--ease)}
.card.on-sand{background:var(--sand);border-color:transparent}
.tag{display:inline-block;font-size:12px;font-weight:600;border:1px solid var(--line);
  padding:4px 9px;color:var(--muted)}
.tag.on{border-color:var(--root);color:var(--root)}
.tag.filled{background:var(--wheat);border-color:var(--wheat);color:var(--forest)}

.facts{display:flex;border-top:1px solid var(--line);margin-top:40px}
.facts div{flex:1;padding:20px 22px 0 0}
.facts b{display:block;font-size:30px;font-weight:600;letter-spacing:-.03em;line-height:1}
.facts span{display:block;font-size:13px;color:var(--muted);margin-top:8px}

/* the moving promise strip */
.ribbon{background:var(--forest);color:var(--wheat);overflow:hidden}
.ribbon .track{display:flex;gap:44px;padding:16px 0;white-space:nowrap;width:max-content;
  animation:slide 34s linear infinite;font-size:13px;font-weight:600;letter-spacing:.1em;
  text-transform:uppercase}
.ribbon span{display:flex;align-items:center;gap:44px}
.ribbon span::after{content:"";width:5px;height:5px;background:var(--wheat-deep);flex:none}
.ribbon:hover .track{animation-play-state:paused}
@keyframes slide{from{transform:translateX(0)}to{transform:translateX(-50%)}}

/* ---------- the box label ---------- */
.label{border:1px solid var(--forest);background:var(--sand);font-size:13px}
.label .lab-top{display:flex;justify-content:space-between;gap:12px;background:var(--forest);
  color:var(--wheat);padding:11px 16px;font-size:12px;font-weight:600;letter-spacing:.08em;
  text-transform:uppercase}
.label .lab-body{padding:16px 16px 12px;line-height:1.5;font-weight:500}
.label dl{display:grid;grid-template-columns:1fr auto;gap:0 12px;margin:0;padding:0 16px}
.label dt,.label dd{padding:8px 0;border-top:1px solid rgba(4,36,20,.13)}
.label dt{color:var(--muted);font-size:13px;align-self:center}
.label dd{margin:0;text-align:right;font-weight:600}
.label .lab-foot{border-top:1px solid var(--forest);margin-top:12px;padding:11px 16px;
  font-size:12px;color:var(--muted);line-height:1.6}

/* ---------- tables ---------- */
table{width:100%;border-collapse:collapse;font-size:15px}
th,td{text-align:left;padding:15px 14px;border-bottom:1px solid var(--line)}
th{font-size:12px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
td.num,th.num{text-align:right}

/* ---------- forms ---------- */
.field{display:block;margin-bottom:20px}
.field>span{display:block;font-size:13px;font-weight:600;color:var(--muted);margin-bottom:7px}
input[type=text],input[type=email],input[type=tel],input[type=date],input[type=number],
select,textarea{width:100%;padding:13px 14px;border:1px solid var(--line);background:var(--paper);
  font-size:16px;transition:border-color .18s var(--ease)}
input:hover,select:hover,textarea:hover{border-color:var(--muted)}
input:focus,select:focus,textarea:focus{border-color:var(--root);outline:none}
input[type=range]{width:100%;accent-color:var(--root);padding:0;border:0}

/* ---------- choices ---------- */
.choice{display:grid;gap:12px}
.choice.two{grid-template-columns:1fr 1fr}
.choice button{border:1px solid var(--line);background:#fff;padding:18px;text-align:left;
  cursor:pointer;transition:border-color .2s var(--ease),background .2s var(--ease),
  transform .2s var(--ease)}
.choice button:hover{border-color:var(--root);transform:translateY(-1px)}
.choice button[aria-pressed="true"]{border-color:var(--root);background:var(--sand);
  box-shadow:inset 0 0 0 1px var(--root)}
.choice b{display:block;font-size:17px;font-weight:600;margin-bottom:4px}
.choice small{color:var(--muted);font-size:13.5px;line-height:1.45;display:block}

.chiplist{display:flex;flex-wrap:wrap;gap:9px}
.chip{border:1px solid var(--line);padding:9px 14px;font-size:14px;cursor:pointer;background:#fff;
  transition:all .18s var(--ease)}
.chip:hover{border-color:var(--root)}
.chip[aria-pressed="true"]{border-color:var(--root);background:var(--forest);color:#fff}

/* ---------- ingredient tiles ---------- */
.tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px}
.tile{position:relative;border:1px solid var(--line);background:var(--paper);padding:0;
  cursor:pointer;text-align:left;transition:border-color .2s var(--ease),transform .2s var(--ease)}
.tile:hover{border-color:var(--root);transform:translateY(-2px)}
.tile figure{margin:0;height:112px;display:flex;align-items:center;justify-content:center;
  background:var(--sand);padding:12px;overflow:hidden}
.tile img{max-height:88px;width:auto;object-fit:contain;transition:transform .35s var(--ease)}
.tile:hover img{transform:scale(1.06)}
.tile b{display:block;font-size:14.5px;font-weight:600;padding:13px 13px 0;line-height:1.25}
.tile small{display:block;font-size:12.5px;color:var(--muted);padding:5px 13px 13px}
.tile[aria-pressed="true"]{border-color:var(--root);box-shadow:inset 0 0 0 1px var(--root)}
.tile[aria-pressed="true"] figure{background:#fff}
.tile[aria-pressed="true"]::after{content:"";position:absolute;top:0;right:0;width:26px;height:26px;
  background:var(--root);animation:pop .2s var(--ease)}
.tile[aria-pressed="true"]::before{content:"";position:absolute;top:8px;right:12px;z-index:1;
  width:5px;height:11px;border:solid #fff;border-width:0 2px 2px 0;transform:rotate(45deg)}
.tile.out{opacity:.35;pointer-events:none}

/* ---------- order status ---------- */
.steps{border:1px solid var(--line)}
.step{display:grid;grid-template-columns:50px 1fr auto;gap:14px;padding:17px 20px;
  border-bottom:1px solid var(--line);align-items:center}
.step:last-child{border-bottom:0}
.step .dot{width:13px;height:13px;border:1px solid var(--line);margin-left:18px}
.step.done .dot{background:var(--root);border-color:var(--root)}
.step.now .dot{background:var(--wheat);border-color:var(--wheat-deep);animation:beat 1.6s infinite}
@keyframes beat{0%,100%{transform:scale(1)}50%{transform:scale(1.25)}}
.step b{font-size:15px;font-weight:600}
.step small{display:block;color:var(--muted);font-size:13.5px}

/* ---------- notices ---------- */
.notice{border-left:3px solid var(--root);background:var(--sand);padding:14px 16px;
  font-size:15px;margin:0 0 20px;animation:fadeUp .3s var(--ease) both}
.notice.bad{border-left-color:var(--warn);color:var(--warn)}
.notice.good{border-left-color:var(--leaf)}
.notice[hidden]{display:none}

/* ---------- footer ---------- */
.foot{background:var(--forest);color:#B3BDB2;padding:84px 0 34px}
.foot a{color:#E6E9E4}
.foot a:hover{color:var(--wheat)}
.foot .top{display:grid;grid-template-columns:1.6fr 1fr 1fr 1fr;gap:40px;
  padding-bottom:52px;border-bottom:1px solid var(--line-dark)}
.foot .mark{display:flex;align-items:center;gap:15px;margin-bottom:20px}
.foot .mark img{width:60px;height:60px}
.foot .mark b{color:#fff;font-size:15px;font-weight:700;display:block}
.foot .mark span{font-size:12px;color:var(--wheat)}
.foot h4{font-size:12px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;
  color:var(--wheat);margin-bottom:15px}
.foot ul{list-style:none;margin:0;padding:0}
.foot li{margin-bottom:10px;font-size:15px}
.foot .bottom{padding-top:22px;display:flex;justify-content:space-between;gap:16px;font-size:13px}

.hide{display:none !important}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.skip{position:absolute;left:-9999px;top:0;background:var(--root);color:#fff;padding:12px 16px;z-index:100}
.skip:focus{left:10px;top:10px}

/* ---------- responsive ---------- */
@media (max-width:1080px){
  :root{--sp:78px;--pad:24px}
  .split,.split.wide-left{grid-template-columns:1fr;gap:40px}
  .g4{grid-template-columns:repeat(2,minmax(0,1fr))}
  .foot .top{grid-template-columns:1fr 1fr;gap:30px}
}
@media (max-width:760px){
  :root{--sp:58px;--pad:18px;--nav-h:64px}
  body{font-size:16px}
  .g2,.g3,.g4{grid-template-columns:1fr}
  .choice.two{grid-template-columns:1fr}
  .nav-toggle{display:block}
  .nav-links{display:none;position:absolute;left:0;right:0;top:var(--nav-h);background:#fff;
    border-bottom:1px solid var(--line);flex-direction:column;align-items:stretch;gap:0;
    padding:6px var(--pad) 18px;animation:fadeUp .25s var(--ease) both}
  .nav-links.open{display:flex}
  .nav-links a{padding:15px 0;border-bottom:1px solid var(--line);font-size:16px}
  .nav-links a:not(.btn)::after{display:none}
  .nav-links .btn{margin-top:14px;justify-content:center}
  .brand img{width:40px;height:40px}
  .brand span{display:none}
  .facts{flex-direction:column}
  .facts div{padding:15px 0;border-bottom:1px solid var(--line)}
  .facts div:last-child{border-bottom:0}
  .foot{padding:52px 0 26px}
  .foot .top{grid-template-columns:1fr;gap:26px;padding-bottom:32px}
  .foot .bottom{flex-direction:column;gap:8px}
  .tiles{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
  .tile figure{height:94px}
}
@media (prefers-reduced-motion:reduce){
  *{animation-duration:.001ms !important;animation-iteration-count:1 !important;
    transition-duration:.001ms !important;scroll-behavior:auto !important}
  .reveal{opacity:1;transform:none}
  .ribbon .track{animation:none}
}
@media print{.nav,.util,.foot,.btn,.ribbon,.barbottom{display:none}}

/* ==========================================================================
   Ordering, the planner and the console
   ========================================================================== */

/* progress rail */
.rail{display:flex;border:1px solid var(--line);margin-bottom:40px;background:#fff;overflow:hidden}
.rail div{flex:1;padding:16px 18px;border-right:1px solid var(--line);
  transition:background .35s var(--ease),color .35s var(--ease)}
.rail div:last-child{border-right:0}
.rail b{display:block;font-size:12px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted);margin-bottom:6px;transition:color .35s var(--ease)}
.rail span{display:block;font-size:17px;font-weight:600;letter-spacing:-.02em}
.rail div.ok{background:var(--sand)}
.rail div.on{background:var(--forest)}
.rail div.on b{color:var(--wheat)}
.rail div.on span{color:#fff}

.stepbox{display:none}
.stepbox.on{display:block;animation:stepIn .45s var(--ease) both}
@keyframes stepIn{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}

/* panels that swap smoothly */
.panel{display:none}
.panel.on{display:block;animation:stepIn .35s var(--ease) both}
.console-tabs{display:flex;border-bottom:1px solid var(--line);margin-bottom:30px;
  overflow-x:auto;scrollbar-width:none}
.console-tabs::-webkit-scrollbar{display:none}
.console-tabs button{background:none;border:0;border-bottom:2px solid transparent;
  padding:14px 20px;cursor:pointer;font-size:15px;font-weight:500;color:var(--muted);
  white-space:nowrap;transition:color .2s var(--ease),border-color .2s var(--ease)}
.console-tabs button:hover{color:var(--ink)}
.console-tabs button[aria-selected="true"]{color:var(--root);border-bottom-color:var(--wheat)}

/* segmented switch for services */
.seg{display:flex;border:1px solid var(--line);background:#fff;margin-bottom:22px}
.seg button{flex:1;background:none;border:0;border-right:1px solid var(--line);padding:14px 10px;
  cursor:pointer;font-size:15px;font-weight:600;color:var(--muted);
  transition:background .25s var(--ease),color .25s var(--ease)}
.seg button:last-child{border-right:0}
.seg button[aria-pressed="true"]{background:var(--forest);color:#fff}

/* a dish row, built for a thumb */
.dishlist{display:grid;gap:12px}
.dishrow{display:grid;grid-template-columns:104px 1fr auto;gap:16px;border:1px solid var(--line);
  background:#fff;padding:0;text-align:left;cursor:pointer;align-items:stretch;
  transition:border-color .2s var(--ease),transform .2s var(--ease)}
.dishrow:hover{border-color:var(--root);transform:translateY(-2px)}
.dishrow[aria-pressed="true"]{border-color:var(--root);box-shadow:inset 0 0 0 1px var(--root)}
.dishrow .shot{position:relative;background:var(--sand);overflow:hidden;min-height:104px}
.dishrow .shot img{position:absolute;object-fit:contain}
.dishrow .shot img:nth-child(1){width:62%;left:6%;bottom:6%;max-height:74%}
.dishrow .shot img:nth-child(2){width:42%;right:5%;bottom:14%;max-height:52%}
.dishrow .shot img:nth-child(3){width:34%;left:44%;top:6%;max-height:40%}
.dishrow .shot img:nth-child(4){width:26%;left:10%;top:8%;max-height:30%}
.dishrow .body{padding:16px 0;min-width:0}
.dishrow .body b{display:block;font-size:17px;font-weight:600;letter-spacing:-.02em;margin-bottom:4px}
.dishrow .body p{font-size:14px;color:var(--muted);margin:0 0 8px;line-height:1.45}
.dishrow .macro{display:flex;gap:14px;font-size:13px;color:var(--muted);flex-wrap:wrap}
.dishrow .macro b{display:inline;font-size:13px;color:var(--root)}
.dishrow .pick{display:flex;align-items:center;padding:0 18px;color:var(--muted);font-size:14px;
  font-weight:600;white-space:nowrap}
.dishrow[aria-pressed="true"] .pick{color:var(--root)}
.dishrow .pick .box{width:24px;height:24px;border:1px solid var(--line);margin-left:10px;
  position:relative;transition:background .2s var(--ease),border-color .2s var(--ease)}
.dishrow[aria-pressed="true"] .pick .box{background:var(--root);border-color:var(--root)}
.dishrow[aria-pressed="true"] .pick .box::after{content:"";position:absolute;left:8px;top:4px;
  width:5px;height:11px;border:solid #fff;border-width:0 2px 2px 0;transform:rotate(45deg)}

.tweak{background:none;border:0;border-top:1px solid var(--line);width:100%;text-align:left;
  padding:11px 0 0;margin-top:12px;font-size:14px;font-weight:600;color:var(--root);cursor:pointer}

/* add ons */
.addon{display:grid;grid-template-columns:1fr auto;gap:18px;border:1px solid var(--line);
  background:#fff;padding:18px 20px;align-items:center;transition:border-color .2s var(--ease)}
.addon:hover{border-color:var(--root)}
.addon b{display:block;font-size:17px;font-weight:600;letter-spacing:-.02em}
.addon p{margin:4px 0 0;font-size:14px;color:var(--muted)}
.addon .price{font-size:15px;font-weight:600;margin-top:8px;display:block}
.stepper{display:flex;border:1px solid var(--line);flex:none}
.stepper button{width:44px;height:44px;border:0;background:#fff;cursor:pointer;font-size:19px;
  line-height:1;color:var(--root);transition:background .18s var(--ease)}
.stepper button:hover{background:var(--sand)}
.stepper button[disabled]{color:var(--line);cursor:default;background:#fff}
.stepper output{width:50px;height:44px;display:flex;align-items:center;justify-content:center;
  font-weight:600;border-left:1px solid var(--line);border-right:1px solid var(--line)}

/* week planner */
.week{display:grid;grid-template-columns:repeat(7,1fr);border:1px solid var(--line);background:#fff}
.week .day{border-right:1px solid var(--line);min-width:0}
.week .day:last-child{border-right:0}
.week .dayhead{padding:12px 10px;border-bottom:1px solid var(--line);text-align:center;
  font-size:13px;font-weight:600;background:var(--sand)}
.week .slot{padding:12px 10px;border-bottom:1px solid var(--line);cursor:pointer;min-height:74px;
  transition:background .2s var(--ease)}
.week .slot:last-child{border-bottom:0}
.week .slot:hover{background:var(--sand)}
.week .slot span{display:block;font-size:11px;font-weight:600;letter-spacing:.05em;
  text-transform:uppercase;color:var(--muted);margin-bottom:5px}
.week .slot b{font-size:13.5px;font-weight:500;line-height:1.3;display:block}
.week .slot.empty b{color:var(--line)}

/* the totals bar that follows you on a phone */
.barbottom{position:sticky;bottom:0;z-index:50;background:#fff;border-top:1px solid var(--line);
  padding:14px var(--pad);display:flex;align-items:center;justify-content:space-between;gap:16px;
  margin:36px calc(var(--pad) * -1) 0}
.barbottom .sum b{display:block;font-size:20px;font-weight:600;letter-spacing:-.02em}
.barbottom .sum span{font-size:13px;color:var(--muted)}
.barbottom .btn{padding:15px 28px}

/* totals */
.totals{border:1px solid var(--line);background:#fff}
.totals .line{display:flex;justify-content:space-between;gap:16px;padding:15px 20px;
  border-bottom:1px solid var(--line);font-size:15.5px}
.totals .line:last-child{border-bottom:0}
.totals .line.grand{background:var(--forest);color:#fff;font-size:19px;font-weight:600}
.totals .was{color:var(--muted);text-decoration:line-through;margin-right:10px}
.totals .free{color:var(--leaf);font-weight:600}

/* sliding sheet for editing a dish */
.sheet{position:fixed;inset:0;z-index:120;display:none}
.sheet.on{display:block}
.sheet .veil{position:absolute;inset:0;background:rgba(4,36,20,.45);animation:fadeUp .25s var(--ease) both}
.sheet .panel-in{position:absolute;right:0;top:0;bottom:0;width:min(560px,100%);background:#fff;
  overflow-y:auto;padding:28px;animation:fadeSide .3s var(--ease) both}
.sheet h3{margin-bottom:6px}
.sheet .head{display:flex;justify-content:space-between;align-items:start;gap:16px;margin-bottom:20px}
.sheet .close{background:none;border:1px solid var(--line);width:40px;height:40px;cursor:pointer;
  font-size:18px;line-height:1;flex:none}
@media (max-width:760px){
  .sheet .panel-in{top:auto;height:88vh;width:100%;animation:sheetUp .3s var(--ease) both}
  @keyframes sheetUp{from{transform:translateY(100%)}to{transform:none}}
}

/* console extras */
.metrics{display:grid;grid-template-columns:repeat(4,1fr);border:1px solid var(--line);
  margin-bottom:34px;background:#fff}
.metrics div{padding:20px 22px;border-right:1px solid var(--line)}
.metrics div:last-child{border-right:0}
.metrics b{display:block;font-size:30px;font-weight:600;letter-spacing:-.03em;line-height:1}
.metrics span{display:block;font-size:13px;color:var(--muted);margin-top:7px}
.editor{border:1px solid var(--forest);padding:26px;margin-bottom:30px;background:#fff;
  animation:stepIn .3s var(--ease) both}
.toolbar{display:flex;gap:12px;align-items:end;flex-wrap:wrap;margin-bottom:22px}
.data-table{background:#fff;border:1px solid var(--line)}
.data-table th{background:var(--sand)}
.data-table td select,.data-table td input{padding:8px 10px;font-size:14px}
.status{font-size:12px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;
  border:1px solid var(--line);padding:4px 9px;display:inline-block}
.status.placed{border-color:var(--wheat-deep);color:var(--wheat-deep)}
.status.prep,.status.cooked{border-color:var(--root);color:var(--root)}
.status.out{background:var(--wheat);border-color:var(--wheat);color:var(--forest)}
.status.delivered{background:var(--forest);border-color:var(--forest);color:#fff}
.status.cancelled{border-color:var(--warn);color:var(--warn)}
.switch{display:inline-flex;align-items:center;gap:9px;cursor:pointer;font-size:14px}
.switch input{width:auto;accent-color:var(--root);width:18px;height:18px}

@media (max-width:1080px){
  .metrics{grid-template-columns:1fr 1fr}
  .metrics div:nth-child(2n){border-right:0}
  .metrics div:nth-child(n+3){border-top:1px solid var(--line)}
  .week{grid-template-columns:1fr;border:0}
  .week .day{border:1px solid var(--line);margin-bottom:10px}
  .week .dayhead{text-align:left}
  .week .slot{display:grid;grid-template-columns:110px 1fr;gap:12px;align-items:center;min-height:0}
  .week .slot span{margin:0}
}
@media (max-width:760px){
  .rail{display:grid;grid-template-columns:1fr 1fr}
  .rail div{border-bottom:1px solid var(--line)}
  .dishrow{grid-template-columns:88px 1fr}
  .dishrow .pick{grid-column:2;padding:0 0 16px;justify-content:flex-start}
  .dishrow .body{padding:14px 0 6px}
  .addon{grid-template-columns:1fr;gap:12px}
  .data-table thead{display:none}
  .data-table tr{display:block;border-bottom:1px solid var(--line);padding:12px 0}
  .data-table td{display:flex;justify-content:space-between;gap:16px;border:0;padding:6px 14px}
  .data-table td::before{content:attr(data-label);font-size:12px;font-weight:600;color:var(--muted)}
}


/* ==========================================================================
   Motion. Everything is short, once, and switched off when the reader has
   asked for less movement.
   ========================================================================== */
[data-reveal]{opacity:0;transform:translateY(18px);
  transition:opacity .7s cubic-bezier(.2,.7,.3,1),transform .7s cubic-bezier(.2,.7,.3,1);
  transition-delay:var(--rd,0s)}
[data-reveal].seen{opacity:1;transform:none}
[data-reveal="left"]{transform:translateX(-22px)}
[data-reveal="scale"]{transform:scale(.97)}
[data-reveal].seen{transform:none}

.dish,.plan,.tile,.goalcard{transition:transform .25s ease,border-color .25s ease}
.dish:hover,.goalcard:hover{transform:translateY(-4px);border-color:var(--root)}
.tile:hover{transform:translateY(-2px)}
.dish .plate img{transition:transform .5s cubic-bezier(.2,.7,.3,1)}
.dish:hover .plate img:nth-child(1){transform:translateY(-5px)}
.dish:hover .plate img:nth-child(2){transform:translateY(-8px)}
.dish:hover .plate img:nth-child(3){transform:translateY(-3px) rotate(3deg)}
.btn{transition:background .15s linear,color .15s linear,transform .12s ease}
.btn:active{transform:translateY(1px)}
.flow li .n{transition:color .3s ease}
.flow li:hover .n{color:var(--root)}

/* the promise strip walks slowly, pauses on hover */
.ribbon{overflow:hidden}
.ribbon .track{display:flex;gap:0;width:max-content;animation:walk 38s linear infinite}
.ribbon:hover .track{animation-play-state:paused}
.ribbon .track span{display:flex;align-items:center;gap:26px;padding-right:26px;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.2em;text-transform:uppercase;
  white-space:nowrap}
.ribbon .track span::after{content:"";width:5px;height:5px;background:var(--wheat-deep);flex:none}
@keyframes walk{from{transform:translateX(0)}to{transform:translateX(-50%)}}

/* offer bar */
.offer{background:var(--wheat);color:var(--forest)}
.offer .wrap{display:flex;align-items:center;justify-content:center;gap:18px;flex-wrap:wrap;
  padding-top:11px;padding-bottom:11px;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.18em;text-transform:uppercase;text-align:center}
.offer a{color:var(--forest);text-decoration:underline;text-underline-offset:3px}

/* first visit offer */
.scrim{position:fixed;inset:0;z-index:150;background:rgba(4,36,20,.72);display:flex;
  align-items:center;justify-content:center;padding:24px;opacity:0;
  animation:scrimin .35s ease forwards}
.scrim[hidden]{display:none}
@keyframes scrimin{to{opacity:1}}
.offercard{background:var(--paper);max-width:900px;width:100%;display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,1.15fr);transform:translateY(16px);
  animation:cardin .45s cubic-bezier(.2,.7,.3,1) .05s forwards;position:relative}
@keyframes cardin{to{transform:none}}
.offercard .art{background:var(--forest);display:flex;align-items:center;justify-content:center;
  padding:40px}
.offercard .art img{width:min(58%,220px);height:auto}
.offercard .body{padding:44px 40px}
.offercard .pct{font-family:var(--serif);font-size:76px;font-weight:200;line-height:.9;
  color:var(--root);letter-spacing:-.03em;display:block;margin-bottom:14px}
.offercard h2{margin-bottom:14px}
.offercard p{font-size:15px;color:var(--muted)}
.offercard .code{display:inline-block;border:1px dashed var(--forest);background:var(--sand);
  font-family:var(--mono);font-size:13px;letter-spacing:.24em;padding:12px 18px;margin:6px 0 22px}
.offercard .close{position:absolute;top:0;right:0;width:48px;height:48px;border:0;background:none;
  cursor:pointer;font-size:20px;line-height:1;color:var(--muted)}
.offercard .close:hover{color:var(--ink)}

/* goal cards */
.goalcard{border:1px solid var(--line);background:#fff;padding:30px;text-align:left;
  cursor:pointer;display:block;width:100%;font:inherit}
.goalcard .ic{width:44px;height:44px;margin-bottom:22px;display:block}
.goalcard b{display:block;font-family:var(--serif);font-weight:400;font-size:25px;
  margin-bottom:8px;line-height:1.1}
.goalcard span{display:block;font-size:14.5px;color:var(--muted)}
.goalcard .go{display:inline-block;margin-top:20px;font-family:var(--mono);font-size:9.5px;
  letter-spacing:.2em;text-transform:uppercase;color:var(--root)}
.goalcard:hover .go{text-decoration:underline;text-underline-offset:4px}

/* comparison */
.compare{width:100%;border-collapse:collapse;border:1px solid var(--line);background:#fff}
.compare th,.compare td{padding:18px 20px;border-bottom:1px solid var(--line);font-size:15px}
.compare thead th{background:var(--forest);color:#fff;font-family:var(--mono);font-size:9.5px;
  letter-spacing:.18em;text-transform:uppercase;text-align:left}
.compare thead th:last-child{background:var(--sand);color:var(--muted)}
.compare td:first-child{font-weight:600}
.compare td.us{color:var(--root)}
.compare td.them{color:var(--muted)}
.compare .mark{font-family:var(--mono);font-size:11px;letter-spacing:.1em}

/* assessment */
.steps-rail{display:flex;gap:0;border:1px solid var(--line);margin-bottom:40px}
.steps-rail div{flex:1;padding:16px;border-right:1px solid var(--line);font-family:var(--mono);
  font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--muted);text-align:center}
.steps-rail div:last-child{border-right:0}
.steps-rail div.on{background:var(--forest);color:#fff}
.steps-rail div.ok{background:var(--sand);color:var(--root)}
.qbox{max-width:760px}
.qbox h2{margin-bottom:10px}
.qbox .lede{margin-bottom:32px}
.choices{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-bottom:32px}
.choices.two{grid-template-columns:repeat(2,1fr)}
.choices.one{grid-template-columns:1fr}
.choice{border:1px solid var(--line);background:#fff;padding:22px;text-align:left;cursor:pointer;
  font:inherit;transition:border-color .2s ease,transform .2s ease}
.choice:hover{border-color:var(--root);transform:translateY(-3px)}
.choice[aria-pressed="true"]{border-color:var(--root);box-shadow:inset 0 0 0 1px var(--root);
  background:var(--sand)}
.choice b{display:block;font-size:16px;font-weight:600;margin-bottom:6px}
.choice span{display:block;font-size:13.5px;color:var(--muted)}
.result-grid{display:grid;grid-template-columns:repeat(4,1fr);border:1px solid var(--line);
  background:#fff;margin-bottom:32px}
.result-grid div{padding:26px 22px;border-right:1px solid var(--line)}
.result-grid div:last-child{border-right:0}
.result-grid b{display:block;font-family:var(--serif);font-size:38px;font-weight:300;line-height:1}
.result-grid span{display:block;font-family:var(--mono);font-size:9.5px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--muted);margin-top:10px}
.bar-row{display:grid;grid-template-columns:110px 1fr 70px;gap:16px;align-items:center;
  padding:14px 0;border-top:1px solid var(--line)}
.bar-row .track{height:8px;background:var(--sand)}
.bar-row .fill{height:8px;background:var(--root);width:0;transition:width .9s cubic-bezier(.2,.7,.3,1)}
.bar-row .fill.wheat{background:var(--wheat-deep)}
.bar-row .fill.leaf{background:var(--leaf)}
.bar-row label{font-family:var(--mono);font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--muted)}
.bar-row .val{font-family:var(--mono);font-size:13px;text-align:right}

/* price with the offer applied */
.was{font-family:var(--mono);font-size:14px;color:var(--muted);text-decoration:line-through}
.saving{display:inline-block;background:var(--wheat);color:var(--forest);font-family:var(--mono);
  font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;padding:5px 9px;margin-top:10px}

@media (max-width:900px){
  .offercard{grid-template-columns:1fr}
  .offercard .art{padding:28px}
  .offercard .art img{width:130px}
  .offercard .body{padding:28px 24px}
  .choices,.choices.two{grid-template-columns:1fr}
  .result-grid{grid-template-columns:1fr 1fr}
  .result-grid div:nth-child(2n){border-right:0}
  .result-grid div:nth-child(n+3){border-top:1px solid var(--line)}
  .compare thead th{font-size:9px;padding:14px 12px}
  .compare td{padding:14px 12px;font-size:14px}
  .steps-rail div{font-size:8.5px;padding:12px 6px}
}
@media (prefers-reduced-motion:reduce){
  [data-reveal]{opacity:1;transform:none}
  .ribbon .track{animation:none}
  .scrim,.offercard{animation:none;opacity:1;transform:none}
}

/* ==========================================================================
   Pieces the newer pages rely on, written against the current tokens so the
   whole site stays in one voice.
   ========================================================================== */
:root{
  --serif:"Figtree","Helvetica Neue",Arial,sans-serif;
  --mono:"Figtree","Helvetica Neue",Arial,sans-serif;
}

/* one hairline running down the page with a node at each section */
.rooted{display:grid;grid-template-columns:62px minmax(0,1fr);align-items:start}
.rooted::before{content:"";grid-column:1;grid-row:1/99;justify-self:center;width:1px;
  background:var(--line);height:100%}
.rooted>*{grid-column:2}
.rooted .node{grid-column:1;grid-row:1;justify-self:center;width:9px;height:9px;
  background:var(--wheat);margin-top:12px}

/* service switch and the dish scroller */
.menu-bar{display:flex;align-items:flex-end;justify-content:space-between;gap:22px;
  flex-wrap:wrap;margin-bottom:26px}
.selectwrap{position:relative;display:inline-block;min-width:260px}
.selectwrap select{appearance:none;-webkit-appearance:none;border:1px solid var(--forest);
  background:#fff;padding:15px 54px 15px 18px;font-family:var(--sans);font-size:20px;
  font-weight:600;letter-spacing:-.02em;width:100%;cursor:pointer}
.selectwrap::after{content:"";position:absolute;right:20px;top:50%;width:9px;height:9px;
  border:solid var(--forest);border-width:0 2px 2px 0;transform:translateY(-70%) rotate(45deg);
  pointer-events:none}
.carousel-nav{display:flex;border:1px solid var(--line)}
.carousel-nav button{width:52px;height:52px;background:#fff;border:0;cursor:pointer;
  border-right:1px solid var(--line);display:flex;align-items:center;justify-content:center;
  transition:background .2s var(--ease)}
.carousel-nav button:last-child{border-right:0}
.carousel-nav button:hover{background:var(--sand)}
.carousel-nav button[disabled]{opacity:.3;cursor:default;background:#fff}
.carousel-nav i{display:block;width:9px;height:9px;border:solid var(--forest);
  border-width:0 2px 2px 0}
.carousel-nav .prev i{transform:rotate(135deg);margin-left:3px}
.carousel-nav .next i{transform:rotate(-45deg);margin-right:3px}
.carousel{display:flex;gap:20px;overflow-x:auto;scroll-snap-type:x mandatory;
  padding-bottom:10px;scrollbar-width:thin}
.carousel::-webkit-scrollbar{height:3px}
.carousel::-webkit-scrollbar-thumb{background:var(--line)}
.carousel .dish{flex:0 0 320px;scroll-snap-align:start;border:1px solid var(--line);background:#fff;
  display:flex;flex-direction:column}
.carousel .dish .plate{position:relative;height:200px;background:var(--sand);overflow:hidden}
.carousel .dish .plate img{position:absolute;object-fit:contain}
.carousel .dish .plate img:nth-child(1){width:54%;left:5%;bottom:7%;max-height:72%}
.carousel .dish .plate img:nth-child(2){width:38%;right:6%;bottom:13%;max-height:54%}
.carousel .dish .plate img:nth-child(3){width:30%;left:46%;top:7%;max-height:42%}
.carousel .dish .plate img:nth-child(4){width:24%;left:9%;top:9%;max-height:32%}
.carousel .dish .txt{padding:22px 22px 18px;flex:1}
.carousel .dish .txt h3{margin-bottom:8px}
.carousel .dish .txt p{font-size:15px;color:var(--muted);margin:0}
.carousel .dish .macro{display:grid;grid-template-columns:repeat(4,1fr);border-top:1px solid var(--line)}
.carousel .dish .macro div{padding:12px 6px;text-align:center;border-right:1px solid var(--line)}
.carousel .dish .macro div:last-child{border-right:0}
.carousel .dish .macro b{display:block;font-size:16px;font-weight:600;color:var(--root)}
.carousel .dish .macro span{font-size:11px;color:var(--muted)}

/* counters used to plan the week */
.counter{display:flex;align-items:center;justify-content:space-between;gap:20px;
  padding:20px 0;border-top:1px solid var(--line)}
.counter:last-of-type{border-bottom:1px solid var(--line)}
.counter b{display:block;font-size:20px;font-weight:600;letter-spacing:-.02em}
.counter small{color:var(--muted);font-size:14px}

/* the site text editor in the console */
.content-group{border:1px solid var(--line);margin-bottom:20px;background:#fff}
.content-group h3{padding:18px 22px;border-bottom:1px solid var(--line);margin:0}
.content-group .row{display:grid;grid-template-columns:220px 1fr auto;gap:16px;padding:16px 22px;
  border-bottom:1px solid var(--line);align-items:start}
.content-group .row:last-child{border-bottom:0}
.content-group label{font-size:12px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted);padding-top:14px}
.content-group textarea{min-height:84px;resize:vertical}

/* the offer window and the assessment inherit the type scale, so only the
   numbers need holding down */
.offercard .pct{font-weight:600;letter-spacing:-.04em}
.result-grid b,.facts b,.metrics b{letter-spacing:-.03em}

@media (max-width:1080px){
  .content-group .row{grid-template-columns:1fr}
  .content-group label{padding-top:0}
}
@media (max-width:760px){
  .rooted{grid-template-columns:1fr}
  .rooted::before,.rooted .node{display:none}
  .rooted>*{grid-column:1}
  .selectwrap{min-width:0;width:100%}
  .carousel-nav{display:none}
  .carousel .dish{flex:0 0 84%}
  .counter{flex-wrap:wrap;gap:12px}
}

/* ==========================================================================
   Phone layout corrections. Grid and flex children default to a minimum size
   of their content, which is what pushes a page sideways on a narrow screen.
   ========================================================================== */
.rooted>*{min-width:0}
@media (max-width:760px){
  .rooted{grid-template-columns:minmax(0,1fr)}
}
.split>*{min-width:0}
.grid>*{min-width:0}
.carousel{max-width:100%}
@media (max-width:760px){
  .carousel .dish{flex:0 0 min(86%,320px)}
  .util .wrap{flex-wrap:wrap;gap:4px 16px;font-size:11.5px}
  .offer .wrap{font-size:11px;letter-spacing:.12em;gap:10px}
  .btn-row{gap:10px}
  .btn-row .btn{flex:1 1 100%}
  .facts b{font-size:26px}
  .tray div{padding:12px}
  .label dd{font-size:12px}
  .steps-rail{overflow-x:auto}
  .steps-rail div{flex:0 0 auto;padding:12px 14px}
  .result-grid b{font-size:30px}
  .numrow{grid-template-columns:1fr}
  h1{letter-spacing:-.02em}
}

/* any wide table gets its own sideways scroll rather than breaking the page */
.scroll-x{overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%}
.scroll-x .compare{min-width:560px}

/* the discount line on the bill */
.line.cut span:last-child{color:var(--root);font-weight:600}
.line.cut span:first-child{color:var(--root)}
.line.hint{color:var(--muted);font-size:13px}

/* dish photography */
.shot.photo{overflow:hidden}
.shot .dishphoto{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  transition:transform .5s var(--ease)}
.dishrow:hover .shot .dishphoto{transform:scale(1.05)}
.thumbshot{display:block;width:100%;aspect-ratio:1/1;background:var(--sand);overflow:hidden;
  margin-bottom:8px}
.thumbshot img{width:100%;height:100%;object-fit:cover;display:block}

/* the kitchen thinking */
.planning{border:1px solid var(--line);background:#fff;padding:26px}
.planbar{height:3px;background:var(--sand);margin-bottom:22px}
.planbar i{display:block;height:3px;width:0;background:var(--root);
  transition:width .45s var(--ease)}
.planlines{display:grid;gap:12px}
.planline{display:grid;grid-template-columns:20px 1fr;gap:12px;align-items:center;
  font-size:15px;color:var(--muted);opacity:.35;transition:opacity .3s var(--ease),color .3s var(--ease)}
.planline.on{opacity:1;color:var(--ink)}
.planline .tick{width:14px;height:14px;border:1px solid var(--line);display:block;position:relative}
.planline.on .tick{background:var(--root);border-color:var(--root)}
.planline.on .tick::after{content:"";position:absolute;left:4px;top:1px;width:4px;height:8px;
  border:solid #fff;border-width:0 2px 2px 0;transform:rotate(45deg)}

/* the week calendar */
.day .slot .kcal{display:block;font-size:11px;color:var(--muted);margin-top:4px}
.day .slot .thumbshot{margin:6px 0 8px}

/* frequently asked questions */
.faq{border-bottom:1px solid var(--line);padding:6px 0}
.faq summary{list-style:none;cursor:pointer;padding:20px 0;display:flex;align-items:center;gap:16px}
.faq summary::-webkit-details-marker{display:none}
.faq summary h2,.faq summary h3{font-size:clamp(18px,2vw,22px);margin:0;flex:1;font-weight:600}
.faq summary::after{content:"";width:11px;height:11px;border:solid var(--root);
  border-width:0 2px 2px 0;transform:rotate(45deg);transition:transform .25s var(--ease);flex:none}
.faq[open] summary::after{transform:rotate(225deg)}
.faq p{color:var(--muted);padding:0 34px 22px 0;margin:0;max-width:70ch}

/* ============================================================ skeletons
   Placeholders for anything that arrives from Postgres. The menu is roughly
   a second behind the document on a good connection, and an empty box that
   suddenly fills is what made the site feel like it jumped.

   Everything here is square. The reset at the top of this file sets
   border-radius:0 on every element, and a rounded grey pill in the middle of
   a square-cornered site reads as a component borrowed from somewhere else.
   The colours are the two the page already uses side by side - a --line
   block on --sand - so a loading panel looks like the panel it becomes. */

.sk {
  position: relative;
  overflow: hidden;
  background: var(--line);
  display: block;
}

/* The sheen is one pass of the page's own paper colour, not white, and it is
   slow. A fast shimmer reads as a progress bar and invites someone to watch
   it; this should sit quietly until the real thing replaces it. */
.sk::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg,
              transparent, rgba(255,255,255,.55), transparent);
  animation: sk-sheen 1.6s var(--ease) infinite;
}

@keyframes sk-sheen { to { transform: translateX(100%); } }

/* Text-shaped skeletons keep the line rhythm of the copy they stand in for,
   so nothing moves when the words arrive. */
.sk-line   { height: 1em; margin: .38em 0; }
.sk-line.w80 { width: 80%; }
.sk-line.w60 { width: 60%; }
.sk-line.w40 { width: 40%; }
.sk-title  { height: 1.6em; width: 55%; margin: 0 0 .6em; }
.sk-thumb  { width: 100%; aspect-ratio: 4 / 3; }

/* A card standing in for a dish or a plan. Same padding and border as the
   real card so the grid does not re-lay itself out when the data lands. */
.sk-card {
  border: 1px solid var(--line);
  background: var(--paper);
  padding: 18px;
}
.sk-card .sk { background: var(--line); }

/* Reserve the height a list will occupy. Without this the page is short
   while it loads and grows underneath the reader's scroll position. */
[data-sk-reserve] { min-height: var(--sk-h, 320px); }

/* When the real content arrives it fades rather than appears. 160ms is under
   the threshold where a fade starts to feel like a wait. */
.sk-in { animation: sk-in .16s var(--ease) both; }
@keyframes sk-in { from { opacity: 0 } to { opacity: 1 } }

/* A skeleton is decoration for a wait, and a screen reader should be told the
   region is busy rather than read empty boxes. */
[aria-busy="true"] .sk { pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .sk::after { animation: none; }
  .sk-in { animation: none; }
}

/* ======================================================= the scroll sequence
   A frame sequence with the scrollbar as the transport. The runway is a tall
   spacer; the frame inside it is sticky, so the picture holds while the page
   scrolls normally underneath. Scrolling itself is never intercepted.

   Frames per unit of scroll is what smoothness actually is: 160 frames over
   380vh is roughly one every 2.4vh, where 80 over 460vh was one every 5.75
   and you could see the steps. */

/* The runway sets the pace. 380vh ran the whole 29 seconds past in a few
   flicks of a wheel; 760vh gives it about twice the scroll to happen in,
   which is what slowing it down actually means here. */
.seq { position: relative; height: 760vh; background: #fff; }
.seq-frame {
  position: sticky; top: 0; height: 100vh; height: 100dvh;
  display: grid; place-items: center;
  background: #fff; overflow: hidden;
}

/* The sequence is white to its edges, so letterboxing is invisible - the bars
   are the same white as the page. That is also why it can be inset on a wide
   screen without looking cropped: shrinking it only adds white, and buys a
   column each side where the text sits on clean ground instead of on food. */
/* Full bleed. It used to be inset to 62% on a wide screen to keep the text
   off the food, but that read as a box floating in the middle of the page.
   The picture now fills the viewport and the words move to the corners, where
   the frames are white anyway - the subject is centred in every one. */
.seq-canvas { display: block; width: 100%; height: 100%; transform-origin: center; }

/* No transition on these. In a scrubbed animation the scroll IS the position,
   so opacity is computed per frame; a transition would lag behind a fast
   scrub and show two phases at once. */
.seq-phase {
  position: absolute; width: min(30ch, 42vw);
  opacity: 0; pointer-events: none; will-change: transform, opacity;
}
.seq-phase .n {
  display: block; font-size: 12px; font-weight: 600; letter-spacing: .22em;
  color: var(--wheat-deep); margin-bottom: 14px;
}
.seq-phase b {
  display: block; font-size: clamp(28px, 4.4vw, 56px); font-weight: 600;
  letter-spacing: -.025em; line-height: 1.03; margin-bottom: 14px;
}
.seq-phase span.s { display: block; font-size: clamp(15px, 1.3vw, 18px); color: var(--muted); line-height: 1.5; }

/* The four corners, travelled in a loop. Every frame has its subject dead
   centre, so the corners are the reliably clear ground. */
/* Full bleed puts the subject right across the middle of the screen, so the
   text is pushed hard into the corners and given a soft white halo. The halo
   is the page's own white, not a panel: it keeps the words readable where an
   edge of the food creeps in, without drawing a box around them. */
.seq-phase { width: min(22ch, 27vw); }
.seq-phase[data-at="1"] { top: 9%;    left: 3.5vw;  text-align: left; }
.seq-phase[data-at="2"] { bottom: 11%; right: 3.5vw; text-align: right; }
.seq-phase[data-at="3"] { top: 9%;    right: 3.5vw; text-align: right; }
.seq-phase[data-at="4"] { bottom: 11%; left: 3.5vw;  text-align: left; }
/* No halo. The light/dark swap below already does the work of keeping the
   words legible, and a glow behind type on a photograph looks like a sticker
   stuck onto the picture rather than part of it. */

.seq-outro {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  opacity: 0; text-align: center; width: min(40ch, 86vw); pointer-events: none;
}
.seq-outro b {
  display: block; font-size: clamp(28px, 4.8vw, 60px); font-weight: 600;
  letter-spacing: -.03em; line-height: 1.04; color: var(--forest);
}
.seq-outro .seq-sub {
  margin: 16px auto 0; max-width: 46ch;
  font-size: clamp(15px, 1.35vw, 18px); color: var(--muted); line-height: 1.55;
}
/* The buttons are only clickable once the panel is actually on screen;
   assets/scroll.js turns pointer events on as it lands, so they can never be
   hit through a fully transparent overlay earlier in the scroll. */
/* Stacked rather than side by side. The primary label is a full sentence
   now, so a row wraps the secondary button onto its own line anyway and the
   two end up different widths and misaligned. Stacking makes that deliberate
   and keeps the order of importance obvious. */
.seq-cta { display: flex; flex-direction: column; align-items: center; gap: 10px; margin-top: 26px; }
.seq-cta .btn { min-width: min(30ch, 82vw); text-align: center; }
@media (max-width: 760px) {
  .seq-outro { width: 88vw; }
  .seq-outro .seq-sub { font-size: 15px; }
  .seq-cta { align-items: stretch; }
  .seq-cta .btn { min-width: 0; }
}

.seq-ticks { position: absolute; bottom: max(26px, env(safe-area-inset-bottom)); left: 50%; transform: translateX(-50%); display: flex; gap: 10px; }
.seq-ticks i { display: block; width: 34px; height: 2px; background: var(--line); transition: background .3s var(--ease); }
.seq-ticks i.on { background: var(--forest); }

/* ---------------------------------------------------------- on a phone

   This used to cut the screen in two - a 56% row for the picture, a 44% row
   for the words - and it was wrong twice over.

   It read as two separate things stacked, rather than as one sequence with
   captions, which is the "it splits into two" complaint. And the picture was
   being asked to fill a box roughly 1:1 with footage that is roughly 16:9,
   so it was scaled up past three times the screen width and cropped to a
   narrow strip through the middle - everything composed into the shot was
   off both sides of it.

   Now it is one screen. The canvas has the whole sticky frame and draws
   FITTED rather than filled (see blit() in scroll.js), so the shot arrives
   whole, letterboxed into the page's own white where it does not reach - and
   since the frames are white to their edges, that letterboxing is invisible.
   The caption sits over the bottom of it, on a soft white fade so it stays
   legible wherever the picture happens to be light or dark.

   The runway is shorter than the desktop's because a thumb covers more
   distance per gesture than a wheel does. */
@media (max-width: 760px) {
  .seq { height: 560vh; }
  .seq-frame { grid-template-rows: 1fr; place-items: stretch; }

  /* All four corners collapse to one place: across the bottom, over the
     picture. The corner loop is a wide-screen idea - on a phone there are no
     corners worth the name. */
  .seq-phase,
  .seq-phase[data-at="1"], .seq-phase[data-at="2"],
  .seq-phase[data-at="3"], .seq-phase[data-at="4"] {
    top: auto; bottom: 0; left: 0; right: 0; width: auto;
    padding: 92px 22px calc(56px + env(safe-area-inset-bottom));
    text-align: left;
    background: linear-gradient(to top,
      rgba(255,255,255,.97) 0%,
      rgba(255,255,255,.93) 42%,
      rgba(255,255,255,.72) 68%,
      rgba(255,255,255,0) 100%);
  }
  .seq-phase .n { margin-bottom: 10px; }
  .seq-phase b { font-size: clamp(25px, 7.2vw, 33px); margin-bottom: 10px; }
  .seq-phase span.s { font-size: 15px; }

  /* The scrim is white, so the dark-ground variant would put white type on
     white. Off, on a phone only. */
  .seq-phase.on-dark b,
  .seq-phase.on-dark span.s { color: var(--forest); }
  .seq-phase.on-dark span.s { color: var(--muted); }
  .seq-phase.on-dark .n { color: var(--wheat-deep); }

  /* Snapping is gone. The sequence is stepped by gesture now, not scrubbed
     by position, so there is nothing to snap to - and mandatory snapping
     would fight the wheel events the stepper is taking. */
  .seq-snap {
    position: absolute; left: 0; width: 1px; height: 1px;
    pointer-events: none;
    scroll-snap-align: start;
  }
}

/* .carousel also uses snap alignment, but it is its own horizontal scroll
   container - alignment applies to the nearest scrolling ancestor, so those
   dishes snap inside the carousel, never against the page. These four
   markers are the only things the rule above can act on. */
.seq-snap { position: absolute; left: 0; width: 1px; height: 1px; pointer-events: none; }

/* Asked for less motion: the last frame, all the phases as plain stacked
   text, and no scroll machinery at all. Nothing moves, nothing is lost. */
@media (prefers-reduced-motion: reduce) {
  .seq { height: auto; }
  .seq-frame { position: static; height: auto; display: block; padding: 6vh 0; }
  .seq-canvas { width: 100%; height: auto; aspect-ratio: 16 / 9; }
  .seq-phase, .seq-outro {
    position: static; opacity: 1; transform: none; width: auto;
    max-width: 60ch; margin: 26px auto; padding: 0 24px; text-align: left;
  }
  .seq-ticks { display: none; }
}

/* ------------------------------------------------- the bar and the sequence
   The sequence is the landing, and a bar pinned across the top of it makes a
   full-bleed picture look like a picture in a window. So it lifts out of the
   way while the sequence is running and comes back the moment the reader has
   scrolled through it.

   Transform and opacity only, and it keeps its space in the layout, so the
   page never jumps when it leaves or returns.

   It is only ever hidden while the sequence is genuinely on screen. Anyone
   who lands mid-page, uses reduced motion, or reaches any other page keeps a
   normal bar, and it is never hidden from the keyboard: focus anywhere
   inside brings it straight back. */
.nav, .util { transition: transform .4s var(--ease), opacity .3s var(--ease); will-change: transform; }
/* The utility strip sits above the bar and is just as much a frame around the
   picture, so it leaves with it. */
/* Both have to leave the FLOW, not just move. transform does not change
   layout, so sliding the bar up left a bar-height band of empty white at the
   top of the page with nothing in it - which is exactly the gap above the
   picture. display:none for the strip, and the bar goes fixed so it can still
   animate without holding a space open behind it. */
body.seq-hold .util { display: none; }
body.seq-hold .nav {
  position: fixed; top: 0; left: 0; right: 0;
  transform: translateY(-100%); opacity: 0; pointer-events: none;
}
body.seq-hold .nav:focus-within { transform: none; opacity: 1; pointer-events: auto; }

@media (prefers-reduced-motion: reduce) {
  .nav { transition: none; }
  body.seq-hold .util { display: block; }
  body.seq-hold .nav { position: sticky; transform: none; opacity: 1; pointer-events: auto; }
}

/* The caption over a dark frame. assets/scroll.js samples the picture beneath
   each one and adds this when the ground is dark, so the words survive a
   journey that runs from blue sky through black soil to a white studio.
   The halo flips with it - white glow on light ground, a dark one on dark. */
.seq-phase.on-dark b,
.seq-phase.on-dark span.s { color: #fff; }
.seq-phase.on-dark .n { color: var(--wheat); }


/* ===================================================================
   Loading states.

   These lived in flow.css, which only the website pages load. The
   kitchen board and the driver run load base.css and nothing else, so
   they had no spinner, no progress line and no skeleton - on the two
   screens where a tap that looks like it did nothing costs the most.
   They are here now because every page loads this file.
   =================================================================== */

/* ========================================================= busy buttons
   Anything that goes to the network says so on the button that started it.
   The label is held in place and swapped for a spinner, so the button does
   not change width and the page does not jump; it is disabled while it runs,
   so a second press cannot place a second order; and aria-busy is set so a
   screen reader hears that something is happening rather than silence. */

.btn[aria-busy="true"],
button[aria-busy="true"] {
  position: relative;
  color: transparent !important;
  pointer-events: none;
  cursor: progress;
}
.btn[aria-busy="true"] > *,
button[aria-busy="true"] > * { visibility: hidden; }
.btn[aria-busy="true"]::after,
button[aria-busy="true"]::after {
  content: "";
  position: absolute; top: 50%; left: 50%;
  width: 15px; height: 15px; margin: -8px 0 0 -8px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  color: #fff;
  animation: spin .62s linear infinite;
}
.btn.ghost[aria-busy="true"]::after,
.gbtn[aria-busy="true"]::after { color: var(--root); }
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .btn[aria-busy="true"]::after,
  button[aria-busy="true"]::after { animation-duration: 2s; }
}

/* A thin line across the top of the page for work that is not attached to a
   single button - loading a board, fetching a week. */
.workbar {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 200;
  background: transparent; pointer-events: none;
}
.workbar i {
  display: block; height: 100%; width: 0; background: var(--wheat);
  transition: width .3s var(--ease), opacity .3s var(--ease);
}

/* The shape of a thing before the thing arrives, so a board does not flash
   empty and then jump. */
.skeleton {
  background: linear-gradient(90deg, var(--line) 25%, var(--sand) 37%, var(--line) 63%);
  background-size: 400% 100%;
  animation: sheen 1.3s ease infinite;
  color: transparent !important;
}
.skeleton * { visibility: hidden; }
@keyframes sheen { from { background-position: 100% 0; } to { background-position: 0 0; } }
@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; background: var(--line); }
}

/* ===================================================== the app shell

   Only ever active when assets/appshell.js has decided this page is being
   used as an app - installed to a home screen, or reached with ?source=app.
   A normal browser visit never matches any of it.

   See the comment at the top of appshell.js for what "used as an app" means
   and why it is remembered for the session. */

/* Off with the website furniture. The utility strip and the footer are
   navigation for a page somebody scrolled to the bottom of; an app has a bar
   in reach of a thumb instead. The header goes too - the tab bar replaces it
   and a second navigation is just a smaller screen. */
.is-app .util,
.is-app .foot,
.is-app .nav { display: none; }

/* Room for the bar, plus the home indicator on an iPhone. */
.is-app body,
html.is-app body { padding-bottom: calc(66px + env(safe-area-inset-bottom)); }

.appbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 120;
  display: grid; grid-template-columns: repeat(5, 1fr);
  background: rgba(255,255,255,.94);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  backdrop-filter: saturate(180%) blur(14px);
  border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom);
}
.appbar-tab {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; padding: 9px 2px 8px;
  color: var(--muted); text-decoration: none;
  font-size: 10.5px; letter-spacing: .01em;
  -webkit-tap-highlight-color: transparent;
}
.appbar-tab svg { width: 22px; height: 22px; display: block; }
.appbar-tab.on { color: var(--root); }
/* The label alone is not enough to read at a glance on a moving bus, so the
   active tab also gets a mark above it. */
.appbar-tab.on::before {
  content: "";
  position: absolute; top: 0; left: 50%; transform: translateX(-50%);
  width: 18px; height: 2px; background: var(--root);
}
.appbar-tab { position: relative; }
.appbar-tab:active { background: var(--sand); }

/* An app is a phone-shaped thing. On a wide screen the bar would run the
   whole width of a desktop monitor, which looks wrong and is unreachable
   anyway, so it is held to a phone's width and centred - which is also what
   makes the app view legible on a laptop while it is being built. */
@media (min-width: 761px) {
  .appbar {
    left: 50%; right: auto; transform: translateX(-50%);
    width: min(430px, 100%);
    border: 1px solid var(--line); border-bottom: 0;
  }
}

/* The console's two-level navigation. The group first, the screen second, so
   nobody reads fifteen labels to find one. See the comment in admin.html. */
.console-groups {
  display: flex; gap: 6px; margin-bottom: 14px; flex-wrap: wrap;
}
.console-groups button {
  background: #fff; border: 1px solid var(--line); cursor: pointer;
  font: inherit; font-size: 14px; font-weight: 600; padding: 9px 20px;
  color: var(--muted);
}
.console-groups button:hover { color: var(--ink); border-color: var(--wheat-deep); }
.console-groups button[aria-selected="true"] {
  background: var(--forest); border-color: var(--forest); color: #fff;
}

/* ============================================== the opening, and the nudge

   The hero is a looping video sitting on top of the canvas until the reader
   scrolls. It is not part of the sequence - it is what is on screen before
   the sequence has anything to say - so it fades out over the first phase
   rather than being scrubbed.

   If the file is missing the video simply never plays and the poster frame
   shows instead, which is the old behaviour. Nothing breaks waiting for it. */
.seq-hero {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  background: #fff;
  pointer-events: none;
  transition: opacity .45s var(--ease);
}
@media (max-width: 760px) {
  /* Same reasoning as the canvas: a landscape clip cropped to a phone shows
     a quarter of itself. Fit it, and let the page's white do the rest. */
  .seq-hero { object-fit: contain; }
}

.seq-next {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: max(30px, calc(env(safe-area-inset-bottom) + 22px));
  display: flex; flex-direction: column; align-items: center; gap: 9px;
  color: var(--forest); opacity: .55;
  font-size: 11px; letter-spacing: .22em; text-transform: uppercase;
  pointer-events: none;
  transition: opacity .5s var(--ease), transform .5s var(--ease);
}
/* the line, drawn rather than an arrow glyph, so it matches the type */
.seq-next i {
  display: block; width: 1px; height: 26px;
  background: linear-gradient(to bottom, currentColor, transparent);
  animation: nudge 2.1s var(--ease) infinite;
}
@keyframes nudge {
  0%   { transform: translateY(-6px); opacity: 0; }
  35%  { opacity: 1; }
  100% { transform: translateY(10px); opacity: 0; }
}
/* Gone once it has been acted on. Removed from the flow entirely, not just
   faded, so it can never sit invisibly over the outro's buttons. */
.seq-next.gone { opacity: 0; transform: translateX(-50%) translateY(8px); }
@media (prefers-reduced-motion: reduce) {
  .seq-next i { animation: none; opacity: .8; }
}

/* While the sequence owns the screen, each scroll lands on a phase.
   Switched on and off by scroll.js as the section enters and leaves - left
   on permanently it would fight every other section on the page. */
/* seq-stepping is no longer used to snap; kept off deliberately. */
