/* Cōlab Yard design system · v1
   Palette: ink, cream, deep olive (the one accent), kraft (always means Table).
   Fonts are self-hosted so the site works even when Google is slow or blocked. */
@font-face{font-family:"Instrument Sans";src:url(/fonts/instrument-sans-400.woff2) format("woff2");font-weight:400;font-display:swap}
@font-face{font-family:"Instrument Sans";src:url(/fonts/instrument-sans-600.woff2) format("woff2");font-weight:500 600;font-display:swap}
@font-face{font-family:"Instrument Sans";src:url(/fonts/instrument-sans-700.woff2) format("woff2");font-weight:700;font-display:swap}
@font-face{font-family:"IBM Plex Mono";src:url(/fonts/ibm-plex-mono-400.woff2) format("woff2");font-weight:400;font-display:swap}
@font-face{font-family:"IBM Plex Mono";src:url(/fonts/ibm-plex-mono-500.woff2) format("woff2");font-weight:500;font-display:swap}

:root{
  --ink:#141414; --ink-soft:#57564f; --cream:#F6F3EC; --paper:#FFFDF8; --line:#DDD8CC; --line-soft:#EBE7DD;
  --olive:#4B5320; --olive-deep:#373D17; --olive-wash:#E9EADB; --olive-light:#B5BE7E;
  --kraft:#C9A878; --kraft-deep:#A7834F; --danger:#B3261E; --ok:#2E7D32;
  --sans:"Instrument Sans","Helvetica Neue",Arial,sans-serif;
  --mono:"IBM Plex Mono",ui-monospace,Menlo,Consolas,monospace;
  --r:14px; --shadow:0 10px 30px rgba(20,20,20,.10);
  /* height of the sticky top bar: anything that sticks or scrolls under it measures from here */
  --topbar:70px;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
body{margin:0;background:var(--cream);color:var(--ink);font-family:var(--sans);font-size:17px;line-height:1.55;-webkit-font-smoothing:antialiased;min-height:100dvh;display:flex;flex-direction:column}
main{flex:1}
img,svg{display:block;max-width:100%}
a{color:inherit}
button{font:inherit;color:inherit}
.wrap{max-width:1120px;margin:0 auto;padding-inline:clamp(18px,5vw,56px);width:100%}
/* A measured column, aligned to the masthead rather than floating in the middle of the window.
   The column itself is the same width it always was; what changed is that it now starts where the
   logo starts, so the page reads as one composition instead of a header, a paragraph adrift in the
   middle, and a footer. The wrap keeps the full grid; only its children are measured. */
.narrow{max-width:640px}
.wrap.narrow{max-width:1120px}
.wrap.narrow > *{max-width:640px}
.label{font-family:var(--mono);font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-soft)}
.mono{font-family:var(--mono);font-variant-numeric:tabular-nums}
h1,h2,h3{margin:0;font-weight:600;letter-spacing:-.015em;text-wrap:balance}
h1{font-size:clamp(30px,5vw,48px);line-height:1.08}
h2{font-size:clamp(24px,3.4vw,34px);line-height:1.15}
h3{font-size:19px}
p{margin:0;max-width:60ch;color:var(--ink-soft)}
.muted{color:var(--ink-soft)}
.olive{color:var(--olive)}
hr{border:0;border-top:1px solid var(--line);margin:0}
.ph{outline:1px dashed #b9b2a2;outline-offset:2px;background:rgba(0,0,0,.02)}

/* header + footer */
/* The bar is black on every page of the site, not only on the menu. It used to be cream, with the
   menu page overriding it, and a guest who ordered a coffee and then went back to the cafe page
   watched the whole top of the window change colour. One bar, one colour, everywhere: the thing
   that never changes is the thing you stop noticing, which is what a navigation bar is for. */
.top{position:sticky;top:0;z-index:20;background:#0B0B0A;color:var(--cream);
  backdrop-filter:none;-webkit-backdrop-filter:none;border-bottom:0}
.top .wrap{display:flex;align-items:center;justify-content:space-between;gap:16px;padding-block:12px}
.top .logo{width:104px;color:var(--cream)}
/* The olive lives on the action, not on the name. The bar was cream and ink from edge to edge and
   the brand colour did not appear until halfway down the page; putting it on a second logo beside
   the first only read as a stutter. Order is the one thing in this bar a guest is meant to tap, so
   it is the one thing that is ours by colour. Cream on olive is 7.4:1, well past the floor. */
.top .btn.solid{background:var(--olive);border-color:var(--olive)}
.top nav{display:flex;gap:4px;font-size:15px;overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}
.top nav::-webkit-scrollbar{display:none}
.top nav a{text-decoration:none;color:rgba(246,243,236,.78);padding:8px 10px;border-radius:999px;white-space:nowrap}
.top nav a:hover,.top nav a:focus-visible,.top nav a[aria-current]{color:var(--cream);background:rgba(246,243,236,.12)}
/* The page used to end on two hairlines forty pixels apart: the last section's bottom border and
   the footer's top border, with an empty band between them that read as a mistake. The last section
   gives up its border and the footer carries the only line, with the breathing room as padding
   above it rather than as margin between two rules. */
/* Cream, under the black. The page is black where the work is, from the bar at the top to Find the
   yard at the foot, and then it lands: the last strip is the paper the brand is printed on, with the
   wordmark on it, and it closes the page rather than continuing it. On the menu page, which is black
   from top to bottom, it is the only thing that tells you the list has ended. */
footer{background:var(--cream);color:var(--ink);border-top:0;padding-block:clamp(26px,3vw,38px) clamp(24px,2.6vw,34px)}
main > section:last-of-type{border-bottom:0}
/* The foot of the site, on the shape Abby's reference uses: the mark and a way to write to us at one
   end, two columns of where-to-go in the middle, and the accounts and the mailing list at the other.
   It is a lot for a footer, and that is the job it has taken on: the home page used to end with a
   black block repeating the address, the hours and the accounts, and the only reason that block
   existed was that the footer was three links and a tagline. One of the two had to carry it, and a
   footer is on every page while that block was on one.
   Four columns at full width, two when they will not fit, one on a phone. The brand column is wider
   than the rest because it holds the mark, and the list column is wider because it holds a text
   field: the middle two are only ever a stack of short words. */
footer .fmain{display:grid;gap:clamp(26px,3vw,38px) clamp(24px,3vw,44px);
  grid-template-columns:1fr}
@media (min-width:620px){footer .fmain{grid-template-columns:1fr 1fr}}
@media (min-width:1000px){footer .fmain{grid-template-columns:1.2fr .8fr .8fr 1.3fr}}
footer .logo{color:var(--ink);width:100px}
footer .fbrand{display:grid;gap:10px;align-content:start;justify-items:start}
footer .fbrand small{font-family:var(--mono);font-size:12px;color:var(--ink-soft)}
footer .fmail{font-size:14.5px;color:var(--ink);text-decoration:underline;text-underline-offset:3px;
  text-decoration-color:rgba(20,20,20,.28)}
footer .fmail:hover,footer .fmail:focus-visible{text-decoration-color:currentColor}
/* Stacked, not wrapped in a row. A row of six links reads as one sentence to skim; a column reads as
   a list of places, which is what it is, and it is the shape every footer of this kind uses. */
footer .fcol-links{display:grid;align-content:start;gap:11px;font-size:14.5px}
footer .fcol-links a{color:var(--ink);text-decoration:none}
footer .fcol-links a:hover,footer .fcol-links a:focus-visible{text-decoration:underline;text-underline-offset:3px}
footer .fcol-links a[aria-current]{text-decoration:underline;text-underline-offset:3px;text-decoration-color:var(--olive)}
footer .fkeep{display:grid;align-content:start;gap:16px;justify-items:start}
/* The marks are 34px circles with the glyph in the middle, so their box starts nine pixels left of
   the glyph. Pulled back by that nine, the first mark lines up with the field under it rather than
   sitting a hair inside the column. */
footer .fkeep .socrow{display:flex;gap:6px;margin-left:-9px}
/* The marks on their own, which is what everyone else does and what Abby's reference does: three
   glyphs people have known for fifteen years do not need to be told what they are. The name stays in
   the markup for screen readers, and for the day a file goes missing: onerror puts .noimg on the
   link and the word comes back, so the row reads rather than showing three broken images.

   The glyphs are the platforms' own marks, single-colour black, which is how they are published. The
   foot is black, so they are inverted here rather than anybody recolouring a mark by hand. */
.soc{display:inline-flex;align-items:center;justify-content:center;flex:none;width:34px;height:34px;
  border-radius:999px;opacity:.78;transition:opacity .15s,background .15s}
.soc:hover,.soc:focus-visible{opacity:1;background:rgba(20,20,20,.06)}
.soc img{width:19px;height:19px}
/* The files are black glyphs, which is right on the cream footer. .foot-lead was a black block on the
   home page that inverted them; it is gone, and the rule goes with it rather than waiting for the
   next person to wonder what it is for. */
.soc span{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.soc.noimg{width:auto;height:auto;border-radius:0;opacity:1;text-decoration:underline}
.soc.noimg span{position:static;width:auto;height:auto;clip-path:none}
/* The mailing list box. One field and one button on one line, because two lines of chrome for one
   email address is more than the address is worth. */
footer .fsignup{display:grid;gap:8px;width:100%;max-width:340px}
footer .fsignup label{font-size:14.5px;font-weight:600;max-width:24ch}
footer .fsub-row{display:flex;gap:8px}
footer .fsub-row input{font:inherit;font-size:16px;padding:10px 12px;border:1.5px solid var(--line);
  border-radius:10px;background:var(--paper);color:var(--ink);min-width:0;flex:1}
footer .fsub-row input:focus{outline:none;border-color:var(--ink)}
footer .fsub-row .btn{flex:none}
footer .fsub-msg{font-size:13.5px;color:var(--ink-soft)}
footer .fsub-msg:empty{display:none}
footer .fsub-msg.bad{color:var(--danger)}
/* The last strip, under a hairline and a size smaller: the copyright at one end and the two
   fine-print pages at the other, with the whole width of the page between them. The gap is the
   point. Set side by side they would read as four things of equal weight; pushed to opposite
   corners they read as the two notices a footer is legally obliged to carry, and the eye skips the
   line entirely until it is looking for one of them. */
footer .fine{display:flex;flex-wrap:wrap;gap:6px 18px;margin-top:clamp(20px,2.4vw,30px);
  padding-top:14px;border-top:1px solid var(--line);font-size:12.5px;
  justify-content:space-between;align-items:baseline;color:var(--ink-soft)}
/* One voice across the strip. The copyright was already mono, because every piece of small utility
   type on this site is, and leaving the two links in the sans made the line look like two lines that
   had landed on the same row by accident. */
footer .fine{font-family:var(--mono);font-size:12px}
footer .fine-links{display:flex;gap:18px}
footer .fine a{color:var(--ink-soft);text-decoration:underline;text-underline-offset:3px;
  text-decoration-color:rgba(87,86,79,.4)}
footer .fine a:hover,footer .fine a:focus-visible{color:var(--ink);text-decoration-color:currentColor}
footer .fine a[aria-current]{color:var(--ink);text-decoration-color:currentColor}
/* Narrow enough that the two ends would collide: the links go on top, because they are the half of
   this line anybody ever taps, and the copyright sits under them where it belongs. */
@media (max-width:560px){
  footer .fine{display:grid;justify-items:start;gap:2px}
  footer .fine-links{order:-1}
}

/* Closed, said where the order button would be. A drawn, greyed, unpressable control with the reason
   beside it, which is the same shape cta() uses for a door that is not open yet: a button you can see
   and cannot press tells a guest more than a button that is not there, because the absence of one
   reads as a site that has no ordering rather than a kitchen that is shut until seven.
   On the menu's black, so the colours are the cream side of the palette. */
.shutbar{display:grid;justify-items:start;gap:10px;padding-block:clamp(22px,3vw,34px) clamp(30px,4vw,46px)}
.menu-dark .shutbar .btn.off{background:rgba(246,243,236,.14);border-color:rgba(246,243,236,.22);
  color:rgba(246,243,236,.72)}
.menu-dark .shutbar .soon-note{color:rgba(246,243,236,.72)}
.shutbar .soon-note{font-size:14px;max-width:46ch}
.yardnote.closed{color:var(--olive-light)}

/* the fine print pages: /privacy, /terms, /legal
   One measured column and nothing else. These pages are read, not looked at, so the only decisions
   worth making are the ones that make reading easier: a line short enough to find its way back to
   the left, headings that are clearly headings without shouting, and paragraphs far enough apart to
   see where one answer ends. The headings are smaller than a section heading elsewhere on the site,
   because on this page there are twelve of them and the page is not twelve sections long. */
.legal{max-width:760px;padding-block:clamp(30px,4vw,48px) clamp(56px,8vw,96px)}
.legal h1{margin-top:8px;font-size:clamp(28px,4vw,40px)}
.legal .lead{margin-top:16px;font-size:18.5px;color:var(--ink);max-width:54ch}
.legal .stamp{margin-top:14px;font-family:var(--mono);font-size:12px;letter-spacing:.06em;
  color:var(--ink-soft);padding-bottom:26px;border-bottom:1px solid var(--line)}
/* A page with no date to stamp still needs the rule that closes the opening. The questions page is
   not a document with a version; it is answers, and a "last updated" on it would suggest the hours
   in it might be stale when they are read live out of the settings on every request. */
.legal .stamp.bare{margin-top:clamp(20px,2.6vw,30px);border-bottom:1px solid var(--line)}
.legal h2{margin-top:clamp(30px,3.4vw,40px);font-size:19px;letter-spacing:-.01em}
.legal p{margin-top:12px;max-width:66ch}
.legal ul{margin:14px 0 0;padding-left:0;list-style:none;display:grid;gap:10px;max-width:66ch}
.legal li{color:var(--ink-soft);padding-left:18px;position:relative}
.legal li::before{content:"";position:absolute;left:2px;top:.62em;width:5px;height:5px;
  border-radius:999px;background:var(--kraft)}
.legal b{color:var(--ink);font-weight:600}
/* The two documents number their clauses, and the number hangs in the margin rather than sitting in
   the heading. Somebody citing "clause 12" should be able to run a finger down the left edge and
   find it without reading a single heading. On a phone there is no margin to hang into, so it goes
   back inline. */
.legal.numbered h2{position:relative}
.legal.numbered .num{color:var(--ink-soft);font-variant-numeric:tabular-nums;margin-right:6px}
@media (min-width:900px){
  .legal.numbered h2{padding-left:0}
  .legal.numbered .num{position:absolute;left:-46px;top:.22em;width:38px;text-align:right;margin:0;
    font-family:var(--mono);font-size:13px;line-height:inherit}
}

/* The note on the front door: the one block on this site written in the first person.
   Paper on cream, so it lifts off the page as a thing somebody wrote rather than a band of the
   layout, and measured narrow: a personal paragraph set to the full width of a laptop reads as
   marketing, and the same words at 46 characters read as a note. Set a size up from body text for
   the same reason, and in ink rather than ink-soft, because the one paragraph on the page that is
   somebody speaking should not be the quietest thing on it. */
.ournote{background:var(--paper);border-bottom:0}
.ournote .wrap{display:grid;justify-items:start;gap:12px}
.ournote p{font-size:clamp(18px,1.9vw,21px);line-height:1.5;max-width:46ch;color:var(--ink);
  letter-spacing:-.005em}
.ournote .sig{font-family:var(--mono);font-size:13px;color:var(--ink-soft);letter-spacing:.02em;
  margin-top:2px}
.ournote .sig::before{content:"— "}

/* sections */
section{padding-block:clamp(44px,7vw,84px);border-bottom:1px solid var(--line-soft)}
/* Jumping to a section from the nav must land its heading below the sticky bar, not under it. */
section[id]{scroll-margin-top:calc(var(--topbar) - 8px)}
.sec-head{display:grid;gap:14px;margin-bottom:28px}
.split{display:grid;gap:36px;align-items:start}
@media (min-width:820px){.split{grid-template-columns:1fr 1fr;gap:56px}}
.lockup{width:150px;color:var(--ink)}
.strip{background:var(--ink);color:var(--cream);padding-block:18px}
.strip .wrap{display:flex;justify-content:space-between;flex-wrap:wrap;gap:12px;align-items:center}
.strip b{font-size:20px;font-weight:600}
.strip span{font-family:var(--mono);font-size:13px;opacity:.8}
.hero{padding-block:clamp(48px,9vw,112px)}
.hero .wrap{display:grid;gap:40px;align-items:center}
@media (min-width:900px){.hero .wrap{grid-template-columns:1.15fr .85fr}}
.hero .copy{display:grid;gap:22px}
.hero .date{font-family:var(--mono);font-size:14px;letter-spacing:.08em;color:var(--olive);text-transform:uppercase}
.hero p{font-size:19px}
.rings{width:100%;aspect-ratio:1;max-width:440px;justify-self:center;color:var(--olive)}
.measure{background:var(--olive);color:var(--cream);padding-block:clamp(48px,7vw,84px)}
.measure h2,.measure p{color:var(--cream)}
.measure p{opacity:.9}
.facts{display:grid;gap:22px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));border-top:1px solid rgba(246,243,236,.3);padding-top:26px;margin-top:10px}
.facts b{display:block;font-family:var(--mono);font-size:40px;font-weight:500;line-height:1}
.facts span{font-size:14px;opacity:.85}

/* buttons */
.btns{display:flex;flex-wrap:wrap;gap:12px}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:10px;padding:13px 20px;border-radius:999px;text-decoration:none;font-weight:600;font-size:15px;border:1.5px solid var(--ink);background:transparent;cursor:pointer;line-height:1.2}
.btn.solid{background:var(--ink);color:var(--cream)}
.btn.olive{background:var(--olive);border-color:var(--olive);color:var(--cream)}
.btn.kraft{background:var(--kraft);border-color:var(--kraft);color:var(--ink)}
/* The solid button for a dark band. Cream reads as ours in a way kraft does not: kraft sits close
   enough to olive in value that the button half-disappeared into the band behind it. */
.btn.c{background:var(--cream);color:var(--ink);border-color:var(--cream)}
.btn.ghost{border-color:var(--line);color:var(--ink-soft)}
.btn.sm{padding:8px 14px;font-size:14px}
.btn.lg{padding:16px 26px;font-size:17px}
.btn.block{width:100%}
.btn:disabled{opacity:.45;cursor:not-allowed}
/* A button that exists but is not ready. Flat, quiet, and not clickable, with the reason in the
   line beside it: see cta() in lib/layout.js. */
.btn.off{background:transparent;border-color:var(--line);color:var(--ink-soft);cursor:default;pointer-events:none}
.soon-note{align-self:center;font-family:var(--mono);font-size:12px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-soft)}
.btn:focus-visible,a:focus-visible{outline:3px solid var(--olive);outline-offset:3px}
.tag{display:inline-flex;align-items:center;justify-self:start;font-family:var(--mono);font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;padding:5px 10px;border-radius:999px;background:var(--olive-wash);color:var(--olive);white-space:nowrap}
.tag.now{background:var(--ink);color:var(--cream)}
.tag.kraft{background:var(--kraft);color:var(--ink)}
.tag.soon{background:var(--line-soft);color:var(--ink-soft)}
.tag.danger{background:#F6DEDB;color:var(--danger)}

/* cards */
.card{background:var(--paper);border:1px solid var(--line);border-radius:var(--r);padding:22px}
.cards{display:grid;gap:18px;grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}
/* The practical facts at the foot of the front door: where, when, how to reach us, where to look.
   They were four rounded cards that wrapped three-and-one on a laptop and left an orphan sitting
   in an empty row. Ruled columns instead, which is how a masthead sets this and which cannot
   orphan: one line above, one below, the eyebrow in mono, and the text plain underneath. */
.factrow{display:grid;border-top:1px solid var(--line)}
.factrow > div{padding:20px 0 22px;border-bottom:1px solid var(--line);display:grid;gap:8px;align-content:start}
.factrow p{font-size:15px;max-width:34ch}
.factrow .go{font-size:14px;font-weight:600;text-decoration:none;color:var(--ink);justify-self:start}
.factrow .go::after{content:" →";font-weight:400}
.factrow .go:hover{text-decoration:underline}
@media (min-width:760px){
  /* As many columns as there are facts, rather than four and a gap where the fourth used to be.
     auto-fit means dropping Say hello did not need a number changed here, and putting something
     back will not either. */
  .factrow{grid-template-columns:repeat(auto-fit,minmax(min(200px,100%),1fr));column-gap:clamp(20px,3vw,40px)}
  .factrow > div{padding:24px 0 30px}
}
/* On the home page the three columns sit straight on the footer, so a rule under each one closes the
   page. On a short page of its own the footer is pushed to the bottom of the window and those three
   rules hang in the middle of the cream with nothing under them. One rule under the whole row reads
   as a finished block instead of three unfinished ones. Phones keep the per-column rules, because
   there the columns are stacked and the rules are what separates them. */
@media (min-width:760px){
  .plainpage .factrow{border-bottom:1px solid var(--line)}
  .plainpage .factrow > div{border-bottom:0}
}
/* And no rule above it. With no heading on the page the top border was the first thing under the
   black bar, which opened the page on a hairline rather than on a word. */
.plainpage .factrow{border-top:0}
/* Four columns here, not three, so the minimum has to come down: at 200px the fourth was pushed onto
   a line of its own and Careers ended up under Where instead of beside Connect, which is the one
   thing this row was rearranged to do. */
@media (min-width:860px){
  .plainpage .factrow{grid-template-columns:repeat(auto-fit,minmax(min(168px,100%),1fr))}
}
/* Two or more .go links in one column, stacked. One beside the next reads as a pair of buttons. */
.factrow .golist{display:grid;justify-items:start;gap:7px}
.factrow .socrow{display:flex;flex-wrap:wrap;gap:6px;margin-left:-9px}
.factrow .socrow:has(.noimg){gap:16px;margin-left:0;font-size:14px}

/* .foot-lead was a black block at the end of the home page: the address, the hours and the three
   accounts, set on the same black as the top bar so the page ended where it began. It is gone. The
   footer carries all three now, on every page, which is where somebody looks for them, and a block
   halfway up the one page that has a footer was the same answer printed twice. Its rules went with
   it rather than sitting here waiting for the next person to wonder what they are for. */
/* The sticky order bar floats over the bottom of the home page, and the last line of the footer was
   underneath it. Room for it, only where it exists. */
.home footer{padding-bottom:clamp(76px,10vw,96px)}
@media (min-width:761px){.home footer{padding-bottom:clamp(30px,3.4vw,44px)}}
.card .lk{width:120px;margin-bottom:14px}
.card p{font-size:15px}
.photo{aspect-ratio:4/3;border-radius:var(--r);background:var(--olive-wash);display:grid;place-items:center;color:var(--ink-soft);font-family:var(--mono);font-size:13px;text-align:center;padding:20px}
.notice{background:var(--paper);border:1px solid var(--line);border-left:4px solid var(--olive);border-radius:10px;padding:14px 16px;font-size:15px}
.notice.warn{border-left-color:var(--kraft)}
.notice.bad{border-left-color:var(--danger)}

/* menu */
.menu-cats{position:sticky;top:var(--topbar);z-index:10;background:var(--cream);border-bottom:1px solid var(--line);margin-bottom:8px}
.menu-cats .wrap{display:flex;gap:6px;overflow-x:auto;padding-block:10px;scrollbar-width:none}
.menu-cats .wrap::-webkit-scrollbar{display:none}
.menu-cats a{white-space:nowrap;text-decoration:none;font-size:14px;padding:8px 14px;border-radius:999px;border:1px solid var(--line);background:var(--paper);color:var(--ink-soft)}
.menu-cats a.on{background:var(--ink);color:var(--cream);border-color:var(--ink)}
/* tapping a category chip must land the heading below both sticky bars, not under them */
.menu-cat{padding-block:34px 4px;scroll-margin-top:calc(var(--topbar) + 64px)}
/* Sections carry a hairline under them everywhere else on the site. A menu category must not: on a
   black band that line is cream, so it drew a pale stripe across the bottom of every photograph. */
.menu-cat{border-bottom:0}

/* ---- The menu: one black, and one picture on it -------------------------------------------------
   Everything on this page is the same black. The bar, the title, the row of category pills, the
   list and the foot are all #0B0B0A, with no glass, no blur and no hairlines between them, so the
   page is one surface from the top of the screen to the bottom of the footer.

   That is the whole of the fix, and it came out of measuring the pages this was meant to feel like.
   Their fields are flat: Dukamo's menu is rgb(9,9,9) row after row, and the dark pages that use
   more than one shade of black use two or three, each one dead flat across hundreds of pixels, with
   small steps and a clean straight edge at every boundary. Ours used to be a photograph behind the
   whole page under a scrim, which measured rgb(33) to rgb(61) and changed every row, and stacked
   four different values down the first 240px: header 29, title 47 to 60, pills 39, list 58. That is
   not shades of black, it is a photograph's tonal noise, and the eye re-adapting to it every few
   lines is what made the page feel crowded.

   So the photograph stops being a wash and becomes an object. It is graded in scripts/bands.py
   until it falls off to black on all four sides, and the mask below takes the top and bottom edges
   the last of the way, so it has no border, no radius, no scrim and no visible edge: it dissolves
   into the page the way a lit cup dissolves into a black poster. One picture, once, at the top.

   Olive is the only colour left on the page, and it is on the controls rather than in the picture:
   the category you are in, and the kcal on every drink, which is the number this menu exists to
   show. The Add buttons stay cream, because the action should be the brightest thing here. */
body.menu-dark{background:#0B0B0A}
.menu-dark .menu-cats{background:#0B0B0A;border-bottom-color:transparent;
  backdrop-filter:none;-webkit-backdrop-filter:none}
.menu-headband{position:relative;z-index:1;color:var(--cream)}
.menu-head .label{color:rgba(246,243,236,.72)}
.menu-head .yardnote{color:rgba(246,243,236,.6)}
.menu-dark .card-line{color:var(--olive-light);background:rgba(181,190,126,.14)}
/* The picture is the room the menu is in, not an object on the page.
   
   It is out of the flow entirely: absolutely positioned inside .menu-stage, which begins where the
   drinks begin, so it costs no height at all. That is what removed the gap around it. In the flow
   it needed air above and below or it read as a band, and the air was most of what made the page
   long; as a layer there is nothing to give room to, and the list simply starts under the pills
   with a photograph behind it.
   
   Held at about a quarter of full strength, which is the whole idea of atmosphere: enough that the
   room is there, not enough to compete with a price. The number is not guessed: scripts/menu-
   contrast.py measures the peak at four widths, and centring the crop pushed it from 25 to 36
   percent on its own, because the subject stopped sitting in the darker part of the left gradient. Two gradients keep it that way and they
   do different jobs. The vertical one takes it to nothing by the fourth or fifth drink, so the
   list ends on plain black. The horizontal one keeps the left dark on purpose, because that is the
   column every name, description and kcal is set in, and a photograph is at its most useful where
   there is no type over it and at its most expensive where there is.
   
   object-fit:cover on a box much taller than the picture also crops its empty sides away and
   enlarges the subject, which is the second half of closing the gap. */
.menu-stage{position:relative}
.menu-shot{position:absolute;top:0;left:0;right:0;height:clamp(440px,52vw,680px);
  /* Never taller than the list it stands behind. The height above is what the picture wants; this is
     what the page will give it. A short category, Juice and telba has three drinks, makes a stage
     shorter than 680px, and without this the rest of the picture hung below it and painted over the
     footer: the links went dim and the whole foot looked like it had a dark sheet over it. It was
     invisible until the footer turned cream, because before that it was black over black.
     Clipping rather than shrinking the picture is right: the picture is the room the list is standing
     in, so when the list is short the room is short, and the gradient still ends on the page's own
     black at the bottom of it. */
  max-height:100%;
  margin:0;z-index:0;pointer-events:none;overflow:hidden}
.menu-shot[hidden]{display:none}
.menu-shot img{width:100%;height:100%;object-fit:cover;object-position:50% 42%;
  /* Zoomed past cover on purpose. The plates were composed with the subject in the middle of a
     wide black frame, which was right when they were a band and is wrong for a background: it
     leaves a third of the screen with nothing in it. Scaling up crops that away and makes the
     subject bigger in the same breath. */
  transform:scale(1.26);transform-origin:50% 45%;
  opacity:.55;transition:opacity .2s}
/* The subject sits in the middle of every plate, so every crop is centred on the middle of the
   plate. Anything else moves the cup off-centre by a different amount on every screen width, which
   is what put it a third of the way across at 741px. */
@media (max-width:640px){
  /* Barely any extra zoom here: a phone already sees about a quarter of the plate's width, so the
     empty sides are long gone and scaling further pushes the cup off the screen entirely, which is
     what an early attempt at 66% did. It measured 8% intensity instead of 28 because the window
     was looking past the subject rather than at it. */
  .menu-shot img{object-position:50% 42%;transform:scale(1.06);transform-origin:50% 45%;
    /* And a little dimmer than a laptop, because the same crop is tighter on the lit part of the
       picture: at the laptop's setting a phone measures several points brighter. */
    opacity:.47}
}
/* Out, then in. Cutting straight from one lit subject to another in the same place reads as a
   glitch rather than as a change of subject. */
.menu-shot img.swapping{opacity:0}
@media (prefers-reduced-motion:reduce){.menu-shot img{transition:none}}
/* The two gradients. The vertical one is load-bearing: it is what lets the drinks sit on the
   picture at all, by guaranteeing the bottom of it is the page's own black rather than whatever
   the photograph happens to be there. scripts/menu-contrast.py checks the result in every
   category at every width. */
.menu-shot::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(11,11,10,.16) 0%,rgba(11,11,10,.34) 44%,rgba(11,11,10,.84) 80%,#0B0B0A 100%),
             linear-gradient(90deg,#0B0B0A 0%,rgba(11,11,10,.86) 18%,rgba(11,11,10,.46) 40%,rgba(11,11,10,0) 64%)}
/* Above the room they are standing in. */
.menu-items{position:relative;z-index:1}
/* One category at a time. The pills are what choose it, so the list is the answer to a question
   the guest asked rather than a page they have to scroll past four other sections of. The server
   renders the open one open; with the script off, the <noscript> rule on the page puts them all
   back and the pills go back to being anchors. */
.menu-items .menu-cat{display:none}
.menu-items .menu-cat.on{display:block}
/* Outlines on black, and the section you are in filled olive: it is the one thing in the row that
   moves as you scroll, so the colour tracks you down the page. */
.menu-dark .menu-cats a{background:transparent;border-color:rgba(246,243,236,.26);color:rgba(246,243,236,.8)}
.menu-dark .menu-cats a.on{background:var(--olive);border-color:var(--olive);color:var(--cream)}
@media (max-width:760px){.menu-dark .menu-btn span{background:var(--cream)}}
.menu-items.shot{color:var(--cream);padding-top:clamp(10px,1.4vw,20px)}
/* Everything the light list sets in ink, said again in cream. */
.menu-items.shot h2 small{color:rgba(246,243,236,.62)}
.menu-items.shot .item .nm small,.menu-items.shot .item .am,.menu-items.shot .item .desc,
.menu-items.shot .muted{color:rgba(246,243,236,.66)}
/* The one number this menu exists to show, so it is the one that carries the brand colour. The
   olive itself is too dark to read on black, so this is the pale end of it on a wash of the same. */
.menu-items.shot .item .kcal{background:rgba(181,190,126,.14);color:#C2CB8E}
.menu-items.shot .tag.soon{background:rgba(246,243,236,.14);color:rgba(246,243,236,.78)}
/* The one button on a black field: cream, so it is the brightest thing on the page. */
.menu-items.shot .add-btn{background:var(--cream);color:var(--ink);border-color:var(--cream)}
.menu-items.shot .add-btn:disabled{background:transparent;color:rgba(246,243,236,.5);border-color:rgba(246,243,236,.26)}
.menu-items.shot .qty{border-color:rgba(246,243,236,.5)}
.menu-items.shot .menu-cat{padding-block:clamp(26px,3vw,40px) 4px}
/* One column, and a narrow one. Two columns filled the width, which on a page whose background is
   a photograph means covering the photograph with the half of the list that could have been under
   it. One column on the left leaves the right side of every screen showing the room, and it is the
   side the picture was already lit and composed for.
   
   Capped rather than fluid: a row stretched across a laptop puts the price a hand's width from the
   name it belongs to, which is worse to read than two columns ever were. */
.menu-cat .items{display:grid;grid-template-columns:1fr;column-gap:0;max-width:600px}
.menu-cat .item{border-bottom:0;padding:19px 0}
/* No rules anywhere in a category: not under the name, not between the drinks, not between one
   section and the next. A printed menu needs them because it has no other way to group; this one
   is one unbroken black, and every line drawn across it is a fifth shade to keep flat. What
   separates one drink from the next is space, which is why the rows carry more of it now.

   The Amharic sits on the same baseline in an Ethiopic face, rather than in the mono, which has no
   Ethiopic and was falling back to whatever the device had and landing a few pixels off. */
.menu-cat h2{display:flex;align-items:baseline;gap:12px;margin-bottom:8px}
.menu-cat h2 small{font-family:"Noto Sans Ethiopic",var(--sans);font-weight:400;font-size:15px;color:var(--ink-soft)}
.item{display:grid;grid-template-columns:1fr auto auto;gap:0 14px;align-items:center;padding:15px 0;border-bottom:1px solid var(--line-soft)}
.item .nm{font-weight:600;font-size:16px;display:flex;flex-wrap:wrap;gap:6px 10px;align-items:baseline}
.item .nm small{font-weight:400;color:var(--ink-soft);font-size:14px}
.item .am{font-size:13px;color:var(--ink-soft);font-family:var(--sans)}
.item .desc{font-size:14px;color:var(--ink-soft);margin-top:2px}
.item .meta{display:flex;flex-wrap:wrap;gap:4px 10px;align-items:center;margin-top:4px}
.item .kcal{font-family:var(--mono);font-size:12.5px;color:var(--olive);background:var(--olive-wash);padding:2px 8px;border-radius:999px}
.item .price{font-family:var(--mono);font-size:15px;font-weight:500;white-space:nowrap}
.item .price.ph{padding:0 4px}
.item.out{opacity:.5}
.item .add{display:flex;align-items:center;gap:8px;justify-self:end}
.item .add .tag{white-space:nowrap}
.qty{display:inline-flex;align-items:center;border:1.5px solid var(--ink);border-radius:999px;overflow:hidden}
.qty button{width:34px;height:36px;border:0;background:transparent;font-size:20px;cursor:pointer;display:grid;place-items:center}
.qty button:disabled{opacity:.3}
.qty span{min-width:26px;text-align:center;font-family:var(--mono);font-weight:500}
.add-btn{height:36px;padding:0 15px;border-radius:999px;border:1.5px solid var(--ink);background:var(--ink);color:var(--cream);font-weight:600;font-size:14px;cursor:pointer}
.add-btn:disabled{background:transparent;color:var(--ink-soft);border-color:var(--line)}

/* cart bar + sheet */
/* Four short lines, so they are set as four short lines. The gap and the padding were built for a
   block that had a paragraph in it; with the paragraph gone the name, the word Menu and the one
   condition were floating a long way apart. The two mono lines also lose the body's 1.55 leading,
   which puts nineteen pixels of box around twelve pixels of type. */
.menu-head{display:grid;gap:4px;justify-items:start;padding-block:15px 10px}
/* Menu is smaller than the site's other h1s, and still a step above a category name: it shares the
   screen with Coffee and Tea, and a page title the same size as a section heading is no hierarchy
   at all. */
.menu-head h1{font-size:clamp(28px,3.6vw,40px)}
.menu-head .label,.menu-head .yardnote,.menu-head .card-line{line-height:1.3}
.menu-head h1{margin:0}
.menu-items{padding-bottom:32px}
.has-cart .menu-items{padding-bottom:120px}
.cartbar{position:fixed;left:0;right:0;bottom:0;z-index:30;padding:12px clamp(14px,4vw,24px) calc(12px + env(safe-area-inset-bottom));background:linear-gradient(to top,var(--cream) 70%,transparent);pointer-events:none;transform:translateY(120%);transition:transform .25s}
/* The order bar fades up out of the page it is sitting on, and on the menu that page is black. In
   cream it was a pale wash across the foot of whichever band the guest had scrolled to. */
.menu-dark .cartbar{background:linear-gradient(to top,#0B0B0A 72%,transparent)}
.cartbar.on{transform:none}
.cartbar button{pointer-events:auto;width:100%;max-width:560px;margin:0 auto;display:flex;justify-content:space-between;align-items:center;gap:12px;padding:16px 20px;border-radius:16px;border:0;background:var(--ink);color:var(--cream);font-weight:600;font-size:16px;box-shadow:var(--shadow);cursor:pointer}
.cartbar .n{display:inline-grid;place-items:center;min-width:28px;height:28px;padding:0 8px;border-radius:999px;background:var(--olive);font-family:var(--mono);font-size:14px;margin-right:10px}
.sheet-bg{position:fixed;inset:0;background:rgba(20,20,20,.45);z-index:40;opacity:0;pointer-events:none;transition:opacity .2s}
.sheet-bg.on{opacity:1;pointer-events:auto}
.sheet{position:fixed;left:0;right:0;bottom:0;z-index:50;background:var(--cream);border-radius:20px 20px 0 0;max-height:92dvh;overflow:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;padding:18px 20px calc(24px + env(safe-area-inset-bottom));transform:translateY(105%);visibility:hidden;transition:transform .28s,visibility 0s .28s;box-shadow:0 -10px 40px rgba(0,0,0,.2)}
.sheet.on{transform:none;visibility:visible;transition:transform .28s}
@media (min-width:720px){.sheet{left:50%;right:auto;width:560px;transform:translate(-50%,105%)}.sheet.on{transform:translate(-50%,0)}}
.sheet header{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}
.sheet header h2{font-size:22px}
.sheet .x{border:0;background:transparent;font-size:28px;line-height:1;cursor:pointer;padding:4px 8px}
.line{display:grid;grid-template-columns:1fr auto auto;gap:12px;align-items:center;padding:12px 0;border-bottom:1px solid var(--line-soft)}
.line .nm{font-weight:600;font-size:15px}
.line .nm small{display:block;font-weight:400;color:var(--ink-soft);font-size:13px}
.total{display:flex;justify-content:space-between;font-weight:600;padding:14px 0;font-size:18px}
.seg{position:relative;display:grid;grid-template-columns:1fr 1fr;border:1.5px solid var(--ink);border-radius:999px;overflow:hidden;margin:6px 0 14px}
.seg label{text-align:center;padding:11px;cursor:pointer;font-weight:600;font-size:15px}
.seg input{position:absolute;opacity:0;pointer-events:none}
.seg input:checked+label{background:var(--ink);color:var(--cream)}

/* forms */
form.f{display:grid;gap:14px}
.field{display:grid;gap:6px}
.field label,.field>span{font-size:14px;font-weight:600}
.field small{font-weight:400;color:var(--ink-soft)}
.field input,.field textarea,.field select{font:inherit;font-size:16px;padding:12px 14px;border:1.5px solid var(--line);border-radius:12px;background:var(--paper);color:var(--ink);width:100%}
.field input:focus,.field textarea:focus,.field select:focus{outline:none;border-color:var(--ink)}
.field textarea{min-height:88px;resize:vertical}
.row2{display:grid;gap:14px;grid-template-columns:1fr 1fr}
@media (max-width:480px){.row2{grid-template-columns:1fr}}
.check{display:flex;gap:10px;align-items:flex-start;font-size:15px}
.check input{width:20px;height:20px;margin-top:3px}
.err{color:var(--danger);font-size:14px}
.field .err:empty{display:none}
/* A field nobody can see, tab into, or be read one by a screen reader. Empty from every human, and
   anything in it came from a robot filling in whatever it found. Not display:none, which the better
   robots know to skip. */
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
/* The contact form, under the four columns and clearly a second thing rather than a fifth column.
   Measured, because a message box as wide as the page invites a paragraph nobody wants to write and
   nobody wants to read. It is the whole page now: the four columns that used to sit above it are on
   the foot of every page including this one, so here they were the same answer twice. */
.cform{max-width:560px;margin-block:clamp(26px,4vw,44px) clamp(56px,8vw,96px)}
.cform .label{margin-bottom:2px}
.cform h2{margin-top:6px}
.cform h2{font-size:clamp(21px,2.4vw,26px)}
.cform > p{margin-top:-4px}
.cform .btn{justify-self:start}
.radios{display:grid;gap:10px}
.radio{display:flex;gap:12px;align-items:center;padding:14px 16px;border:1.5px solid var(--line);border-radius:12px;background:var(--paper);cursor:pointer}
.radio:has(input:checked){border-color:var(--ink);background:var(--olive-wash)}
.radio input{width:18px;height:18px;margin:0}
.radio b{display:block;font-size:16px}
.radio small{color:var(--ink-soft);font-size:13px}
.radio .cap{margin-left:auto;font-family:var(--mono);font-size:12px;color:var(--ink-soft);white-space:nowrap}
.radio.full{opacity:.5;cursor:not-allowed}

/* status page */
.status-hero{padding-block:clamp(36px,7vw,72px)}
.code{font-family:var(--mono);font-size:clamp(56px,14vw,96px);font-weight:500;letter-spacing:-.02em;line-height:1}
.steps{display:grid;grid-template-columns:repeat(4,1fr);gap:6px;margin:26px 0}
.steps div{padding:12px 6px;border-radius:10px;text-align:center;font-family:var(--mono);font-size:12px;letter-spacing:.06em;text-transform:uppercase;background:var(--line-soft);color:var(--ink-soft)}
.steps div.on{background:var(--ink);color:var(--cream)}
.steps div.done{background:var(--olive);color:var(--cream)}
.receipt{display:grid;gap:8px}
.receipt .line{padding:8px 0}

/* utilities */
.grid{display:grid;gap:18px}
.stack{display:grid;gap:12px}
.center{text-align:center}
.center p{margin-inline:auto}
.hidden{display:none!important}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
.toast{position:fixed;left:50%;bottom:calc(90px + env(safe-area-inset-bottom));transform:translateX(-50%) translateY(20px);background:var(--ink);color:var(--cream);padding:10px 16px;border-radius:999px;font-size:14px;opacity:0;transition:.2s;z-index:60;pointer-events:none;white-space:nowrap}
.toast.on{opacity:1;transform:translateX(-50%)}

/* kitchen + admin (staff screens) */
body.staff{background:#111;color:#F6F3EC}
body.staff main{padding:0}
.kbar{display:flex;align-items:center;gap:14px;padding:12px 18px;background:#1A1A1A;border-bottom:1px solid #2a2a2a;position:sticky;top:0;z-index:5}
.kbar .logo{width:96px;color:#F6F3EC}
.kbar h1{font-size:18px;font-weight:600}
.kbar .sp{flex:1}
.kbar .stat{font-family:var(--mono);font-size:13px;color:#B5BE7E}
.kbar a,.kbar button{color:#F6F3EC;text-decoration:none;font-size:14px;background:#2a2a2a;border:0;padding:8px 14px;border-radius:999px;cursor:pointer}
.kcols{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;padding:14px;align-items:start}
@media (max-width:760px){.kcols{grid-template-columns:1fr}}
.kcol h2{font-family:var(--mono);font-size:13px;letter-spacing:.14em;text-transform:uppercase;color:#9a9a9a;padding:6px 4px 10px;display:flex;justify-content:space-between}
.kcol h2 b{color:#F6F3EC}
.ticket{background:#F6F3EC;color:var(--ink);border-radius:14px;padding:14px 16px;margin-bottom:12px;box-shadow:0 8px 24px rgba(0,0,0,.35);animation:pop .25s}
.ticket.new{border:3px solid var(--olive)}
.ticket.ready{background:var(--olive-wash)}
.ticket.done{background:#2a2a2a;color:#bbb;box-shadow:none;padding:10px 14px;animation:none}.ticket.done .code{font-size:20px;color:#ddd}.ticket.done .where{color:#8f9a60}.ticket.done .age{color:#888}.ticket.done .who{color:#999;font-size:13px;margin-top:2px}.ticket.done .acts{margin-top:8px}.ticket.done .acts button.sec{border-color:#444;color:#aaa;padding:8px 12px;font-size:13px;font-weight:600}
.kcol h2.sub{margin-top:18px;color:#666}
@keyframes pop{from{transform:scale(.96);opacity:.5}}
.ticket .th{display:flex;justify-content:space-between;align-items:baseline;gap:10px;margin-bottom:8px}
.ticket .code{font-size:34px}
.ticket .where{font-family:var(--mono);font-size:13px;letter-spacing:.08em;text-transform:uppercase;color:var(--olive);font-weight:500}
.ticket .age{font-family:var(--mono);font-size:13px;color:var(--ink-soft)}
.ticket .age.late{color:var(--danger);font-weight:500}
.ticket ul{list-style:none;margin:0;padding:0;display:grid;gap:4px}
.ticket li{display:grid;grid-template-columns:34px 1fr;gap:8px;font-size:18px;line-height:1.3}
.ticket li b{font-family:var(--mono);font-weight:500}
.ticket li small{display:block;color:var(--olive);font-size:14px}
.ticket .note{margin-top:8px;font-size:15px;background:#fff;border-radius:8px;padding:8px 10px;border-left:3px solid var(--kraft)}
.ticket .who{font-size:14px;color:var(--ink-soft);margin-top:6px}
.ticket .acts{display:flex;gap:8px;margin-top:12px}
.ticket .acts button{flex:1;padding:14px;border-radius:10px;border:0;font-weight:700;font-size:16px;cursor:pointer;background:var(--ink);color:var(--cream)}
.ticket .acts button.sec{background:transparent;border:1.5px solid var(--line);color:var(--ink-soft);flex:0 0 auto;padding-inline:14px}
.ticket .acts button.ok{background:var(--olive)}
.kempty{color:#666;font-family:var(--mono);font-size:13px;padding:24px 4px;text-align:center;border:1px dashed #333;border-radius:12px}
.pin{max-width:360px;margin:12vh auto;padding:0 20px;display:grid;gap:18px;text-align:center}
.pin .logo{width:140px;margin:0 auto;color:#F6F3EC}
.pin input{font:500 32px var(--mono);letter-spacing:.3em;text-align:center;padding:14px;border-radius:14px;border:2px solid #333;background:#1a1a1a;color:#F6F3EC;width:100%}
.pin input:focus{outline:none;border-color:var(--olive-light)}

/* admin */
body.admin{background:var(--cream);color:var(--ink)}
.abar{display:flex;align-items:center;gap:8px;padding:10px 16px;background:var(--paper);border-bottom:1px solid var(--line);position:sticky;top:0;z-index:5;overflow-x:auto}
.abar .logo{width:88px;color:var(--ink);margin-right:10px;flex:0 0 auto}
.abar a{text-decoration:none;font-size:14px;padding:8px 12px;border-radius:999px;color:var(--ink-soft);white-space:nowrap}
.abar a.on,.abar a:hover{background:var(--ink);color:var(--cream)}
.abar .sp{flex:1}
/* the admin nav in its laptop shape: one row, a hairline between the three groups */
.abar nav{display:flex;align-items:center;gap:8px;flex:1}
.agroup{display:flex;align-items:center;gap:6px}
.agroup+.agroup{border-left:1px solid var(--line);padding-left:10px;margin-left:4px}
.agroup .ah{display:none}
@media (min-width:1440px){.agroup .ah{display:inline;font-family:var(--mono);font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-soft);margin-right:2px}}
.abar .out{margin-left:auto}
.amenu,.anow,.ascrim{display:none}

/* …and its drawer shape. The row needs about 1330px to show all thirteen links plus Log out, so
   anything narrower gets the drawer rather than a bar that scrolls its last link off screen.
   Raise this whenever a link is added to NAV in admin.js: a 13in laptop is 1280 wide. */
@media (max-width:1340px){
  .abar{gap:10px;overflow:visible;z-index:60}
  .amenu{display:inline-flex;flex-direction:column;justify-content:center;gap:5px;width:44px;height:44px;margin-left:-8px;padding:11px;border:0;border-radius:12px;background:none;cursor:pointer;flex:none}
  .amenu span{display:block;height:2px;border-radius:2px;background:var(--ink);transition:transform .2s,opacity .2s}
  .abar.open .amenu span:nth-child(1){transform:translateY(7px) rotate(45deg)}
  .abar.open .amenu span:nth-child(2){opacity:0}
  .abar.open .amenu span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}
  .abar .logo,.amenu{position:relative;z-index:60}
  .anow{display:block;margin-left:auto;font-size:14px;font-weight:600;color:var(--ink-soft);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:46vw}
  .ascrim{display:block;position:fixed;inset:0;z-index:40;background:rgba(20,20,20,.45);opacity:0;visibility:hidden;transition:opacity .25s}
  .abar.open .ascrim{opacity:1;visibility:visible}
  .abar nav{position:fixed;top:0;left:0;bottom:0;z-index:50;width:min(82vw,300px);flex-direction:column;align-items:stretch;gap:2px;overflow-y:auto;
    padding:calc(72px + env(safe-area-inset-top)) 12px calc(18px + env(safe-area-inset-bottom));background:var(--paper);
    box-shadow:8px 0 40px rgba(20,20,20,.18);transform:translateX(-100%);visibility:hidden;transition:transform .25s ease,visibility .25s}
  .abar.open nav{transform:none;visibility:visible}
  .agroup{flex-direction:column;align-items:stretch;gap:2px;margin-bottom:16px}
  .agroup+.agroup{border-left:0;padding-left:0;margin-left:0}
  .agroup .ah{display:block;font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-soft);padding:4px 12px}
  .abar nav a{font-size:16px;padding:13px 12px;border-radius:10px;color:var(--ink)}
  .abar .out{margin-left:0;margin-top:auto;color:var(--ink-soft)}
  body.anav-open{overflow:hidden}
}
.awrap{max-width:1000px;margin:0 auto;padding:24px clamp(14px,3vw,32px) 80px;display:grid;gap:22px}
.awrap h1{font-size:26px}
table.t{width:100%;border-collapse:collapse;font-size:14px;background:var(--paper);border:1px solid var(--line);border-radius:12px;overflow:hidden}
table.t th,table.t td{padding:10px 12px;text-align:left;border-bottom:1px solid var(--line-soft);vertical-align:middle}
table.t .menu-sel{min-width:152px}
table.t .menu-wide{min-width:210px}
table.t .menu-unit{min-width:82px}
table.t th{font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-soft);background:var(--cream)}
table.t tr:last-child td{border-bottom:0}
table.t input,table.t select{font:inherit;font-size:14px;padding:7px 9px;border:1px solid var(--line);border-radius:8px;background:#fff;width:100%;min-width:60px}
table.t.menu{min-width:1180px}table.t.menu td:nth-child(1) input{min-width:150px}table.t.menu td:nth-child(2) input{min-width:110px}table.t.menu td:nth-child(3) input{min-width:200px}table.t.menu td:nth-child(7) input{min-width:130px}
table.t input[type=number]{width:84px}
table.t input[type=checkbox]{width:18px;height:18px}
.tscroll{overflow-x:auto}
.toolbar{display:flex;flex-wrap:wrap;gap:10px;align-items:center}
.pillrow{display:flex;flex-wrap:wrap;gap:8px}
.kv{display:grid;grid-template-columns:auto 1fr;gap:6px 16px;font-size:14px}
.kv dt{color:var(--ink-soft);font-family:var(--mono);font-size:12px}
.kv dd{margin:0}
details.box{background:var(--paper);border:1px solid var(--line);border-radius:12px;padding:14px 16px}
details.box summary{cursor:pointer;font-weight:600}
.flag{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:14px 16px;background:var(--paper);border:1px solid var(--line);border-radius:12px}
.flag b{display:block}
.flag small{color:var(--ink-soft)}
.switch{position:relative;width:52px;height:30px;flex:0 0 auto}
.switch input{position:absolute;inset:0;opacity:0;margin:0;cursor:pointer;z-index:1}
.switch i{position:absolute;inset:0;border-radius:999px;background:var(--line);transition:.15s}
.switch i::after{content:"";position:absolute;top:3px;left:3px;width:24px;height:24px;border-radius:50%;background:#fff;transition:.15s}
.switch input:checked+i{background:var(--olive)}
.switch input:checked+i::after{transform:translateX(22px)}
@media print{.top,footer,.cartbar,.sheet,.sheet-bg,.abar,.kbar{display:none!important}body{background:#fff}}

/* ---------- home v2: night yard ---------- */
body.home{background:var(--cream)}
.top .order-cta{margin-left:8px}
@media (max-width:640px){.top .order-cta{display:none}}
.btn.ghost-c{color:var(--cream);border-color:rgba(246,243,236,.55)}
.hero-c{position:relative;min-height:min(78vh,720px);display:flex;align-items:flex-end;background:var(--ink);color:var(--cream);overflow:hidden;padding:0;border:0}
.hero-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center 40%}
.hero-shade{position:absolute;inset:0;background:linear-gradient(180deg,rgba(20,20,20,.15) 0%,rgba(20,20,20,.35) 45%,rgba(20,20,20,.9) 100%)}
.hero-c-in{position:relative;display:grid;gap:26px;padding-block:clamp(40px,8vw,64px) clamp(36px,6vw,56px);align-items:end}
@media (min-width:820px){.hero-c-in{grid-template-columns:1fr auto}}
.hero-c .eyebrow{font-family:var(--mono);font-size:13px;letter-spacing:.12em;text-transform:uppercase;color:var(--olive-light)}
.hero-c h1{font-size:clamp(38px,6.4vw,76px);line-height:1;letter-spacing:-.03em;margin-top:14px;max-width:12ch}
.hero-c p{color:rgba(246,243,236,.85);font-size:clamp(16px,1.6vw,19px);margin-top:18px;max-width:46ch}
.hero-c .btns{margin-top:24px}
.hero-emblem{width:150px;color:var(--cream);justify-self:end}
@media (max-width:819px){.hero-emblem{width:96px;justify-self:start;order:-1}}
.numbers{background:var(--ink);color:var(--cream);padding-block:26px 34px;border-bottom:0}
.tiles{display:grid;gap:12px;grid-template-columns:repeat(2,1fr)}
@media (min-width:720px){.tiles{grid-template-columns:repeat(4,1fr)}}
.tiles div{background:#1E1E1E;border:1px solid #2a2a2a;border-radius:14px;padding:18px 20px}
.tiles b{display:block;font-family:var(--mono);font-size:clamp(30px,3.6vw,44px);font-weight:500;color:var(--olive-light);line-height:1}
.tiles span{display:block;font-size:14px;color:#b9b9b9;margin-top:8px}
.numbers-note{color:#9a9a9a;font-family:var(--mono);font-size:12.5px;letter-spacing:.08em;text-transform:uppercase;margin-top:18px}
section.alt{background:var(--paper)}
.ph-slot{margin:0;position:relative;border-radius:var(--r);overflow:hidden;background:var(--olive-wash);aspect-ratio:4/3}
.ph-slot.wide{aspect-ratio:16/9}
.ph-slot img{width:100%;height:100%;object-fit:cover}
.ph-slot figcaption{position:absolute;left:14px;bottom:12px;font-family:var(--mono);font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:var(--cream);background:rgba(20,20,20,.55);padding:6px 10px;border-radius:999px}

.infobar{background:var(--ink);color:var(--cream);border-top:1px solid #2a2a2a;padding-block:12px}
.infobar .wrap{display:flex;flex-wrap:wrap;gap:8px 28px;font-size:14px;color:#c9c9c9}
.infobar b{font-family:var(--mono);font-weight:500;font-size:11.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--olive-light);margin-right:6px}
.infobar a{color:var(--cream)}
.measure .tiles{grid-template-columns:1fr}
@media (min-width:560px){.measure .tiles{grid-template-columns:repeat(3,1fr)}}
.measure .tiles div{background:rgba(20,20,20,.22);border-color:rgba(246,243,236,.18)}
.measure .tiles b{color:var(--cream)}.measure .tiles span{color:rgba(246,243,236,.8)}
.order-sticky{display:none}
@media (max-width:640px){.order-sticky{display:flex;transform:translateY(120%);transition:transform .25s}.order-sticky.on{transform:none}.order-sticky{position:fixed;left:16px;right:16px;bottom:calc(14px + env(safe-area-inset-bottom));z-index:30;justify-content:center;padding:15px;border-radius:16px;background:var(--ink);color:var(--cream);font-weight:600;text-decoration:none;box-shadow:var(--shadow)}body.home footer{padding-bottom:90px}}
/* home v4: cup hero */
.hero-d{background:var(--cream);color:var(--ink);padding:0;border:0}
.hero-d-in{display:grid;gap:32px;align-items:center;padding-block:clamp(28px,5vw,56px) clamp(28px,5vw,48px)}
@media (min-width:820px){.hero-d-in{grid-template-columns:1.05fr 1fr;gap:56px}}
.hero-d .eyebrow{font-family:var(--mono);font-size:13px;letter-spacing:.12em;text-transform:uppercase;color:var(--olive)}
.hero-d h1{font-size:clamp(38px,6.2vw,74px);line-height:1;letter-spacing:-.03em;margin-top:14px;max-width:12ch}
.hero-d p{color:var(--ink-soft);font-size:clamp(16px,1.6vw,19px);margin-top:18px;max-width:46ch}
.hero-d .btns{margin-top:24px}
.hero-d figure{margin:0;border-radius:18px;overflow:hidden;aspect-ratio:4/5;max-width:100%;box-shadow:0 24px 60px rgba(20,20,20,.14)}
.hero-d figure img{width:100%;height:100%;object-fit:cover;display:block}
@media (max-width:819px){.hero-d figure{aspect-ratio:4/3}}
.hero-d h1{max-width:13ch}
.hero-d .hero-note{font-size:15px;color:var(--olive);margin-top:12px}
.hero-d p b{color:var(--ink);font-weight:600}
.hero-pics{display:grid;grid-template-columns:1fr 1fr;gap:14px;align-items:start}
.hero-pics figure{margin:0;position:relative}
.hero-pics figure:nth-child(2){margin-top:44px}
.hero-pics figcaption{position:absolute;left:12px;bottom:12px;font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--cream);background:rgba(20,20,20,.55);padding:6px 10px;border-radius:999px;backdrop-filter:blur(4px)}
@media (max-width:819px){.hero-pics{gap:10px}.hero-pics figure{aspect-ratio:4/5}.hero-pics figure:nth-child(2){margin-top:28px}.hero-pics figcaption{font-size:10px;left:8px;bottom:8px}}
@media (min-width:820px){.hero-d-in{grid-template-columns:1fr 1.1fr}}
.hero-d h1{font-size:clamp(36px,5.2vw,62px);max-width:14ch}
@media (min-width:820px){.hero-d-in{grid-template-columns:.9fr 1.1fr;gap:48px;align-items:center}}
.hero-pics figcaption{white-space:nowrap}
/* the yard: what it is for */
.uses{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}
.uses>div{background:var(--paper);border:1px solid var(--line);border-radius:14px;padding:22px 22px 20px;display:grid;gap:10px;align-content:start;justify-items:start}
.uses h3{font-size:19px;letter-spacing:-.01em;line-height:1.15}
.uses p{margin:0;color:var(--ink-soft);font-size:14.5px}
.uses .btn{margin-top:6px}
.uses-note{margin-top:22px;font-size:14.5px;color:var(--ink-soft)}
.hero-d .defn{margin:0 0 22px;padding-bottom:14px;border-bottom:1px solid var(--line);font-size:15.5px;line-height:1.5;color:var(--ink-soft);display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;max-width:46ch}
.hero-d .defn b{font-weight:700;font-size:17px;color:var(--ink);letter-spacing:-.01em}
.hero-d .defn .pr{color:var(--ink-soft)}
.hero-d .defn .bar{color:var(--line);font-weight:300}
.hero-d .defn i{font-style:italic;color:var(--olive)}
.hero-d .defn .am{font-family:"Noto Sans Ethiopic","Instrument Sans",sans-serif;color:var(--ink)}
.hero-d .defn .def{color:var(--ink-soft)}

.hero-d-in{padding-top:clamp(18px,3vw,30px)}
@media (min-width:820px){.hero-d-in{padding-top:28px}}
.hero-d h1{font-size:clamp(34px,4.8vw,58px)}
/* three-photo hero */
.hero-pics.three{grid-template-columns:1.05fr 1fr;grid-template-rows:auto auto;gap:12px}
.hero-pics.three figure{margin:0;aspect-ratio:4/3}
.hero-pics.three figure.tall{grid-row:1/3;aspect-ratio:auto;height:100%}
.hero-pics.three figure:nth-child(2){margin-top:0}
.hero-pics.three figure img{width:100%;height:100%;object-fit:cover;display:block}
@media (max-width:819px){.hero-pics.three{gap:8px}.hero-pics.three figcaption{font-size:9.5px;padding:4px 8px}}
/* seamless mosaic */
.hero-pics.three{gap:4px;background:var(--cream);border-radius:18px;overflow:hidden;position:relative;box-shadow:0 24px 60px rgba(20,20,20,.14)}
.hero-pics.three figure{border-radius:0;box-shadow:none}
.hero-pics.three figure:nth-child(2){margin-top:0}
.hero-pics.three .strip{position:absolute;left:0;right:0;bottom:0;margin:0;display:flex;gap:18px;padding:10px 16px;background:rgba(20,20,20,.55);color:var(--cream);font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;backdrop-filter:blur(4px)}
.hero-pics.three .strip span+span::before{content:"·";margin-right:18px;opacity:.6}
@media (max-width:819px){.hero-pics.three .strip{font-size:9.5px;gap:10px;padding:8px 12px}.hero-pics.three .strip span+span::before{margin-right:10px}}
.hero-pics.three .strip{top:0;bottom:auto;font-size:10.5px;padding:9px 14px;background:linear-gradient(to bottom,rgba(20,20,20,.55),rgba(20,20,20,0));backdrop-filter:none;white-space:nowrap;overflow:hidden}
.hero-pics.three .strip span{white-space:nowrap}
@media (max-width:819px){.hero-pics.three .strip{display:none}}
.hero-d .hero-pics.three .strip{max-width:none;margin:0;color:var(--cream);font-size:10.5px}
.cat-photo{margin:10px 0 6px;border-radius:12px;overflow:hidden;aspect-ratio:3/1;max-width:100%}
.cat-photo img{width:100%;height:100%;object-fit:cover;display:block}
/* hero: the yard */
/* The yard photo as the hero's background, on every screen.
   
   The photo is the backdrop and the words sit on it, so everything in the hero turns cream and a
   scrim carries the contrast. The scrim is not one flat wash: it is heaviest exactly where the text
   is and thinnest over the two lit doors, because dimming the doors evenly would flatten the one
   thing the picture is for. On a laptop that means a left-to-right gradient behind the column of
   text; on a phone, where the words run the full width, a top-to-bottom one that eases off over the
   lower third where the doors are framed. The image is nudged with object-position at each size so
   the doors land in the clear part rather than under the headline.

   It stays an <img> rather than a CSS background: that keeps fetchpriority for the largest paint,
   its alt text, and the caption, and it is the same 113 KB file either way. */
.hero-d{position:relative;overflow:hidden;background:var(--ink);color:var(--cream);isolation:isolate}
.hero-d .hero-yard{position:absolute;inset:0;margin:0;aspect-ratio:auto;max-width:none;border-radius:0;
  box-shadow:none;overflow:hidden;z-index:0;background:var(--ink)}
.hero-d .hero-yard img{width:100%;height:100%;object-fit:cover;display:block}
.hero-d .hero-yard::after{content:"";position:absolute;inset:0;pointer-events:none}
/* the photo anchors to the section, not to the centred wrap, or it would stop at 1120px and leave
   a bar of background down each side of a wide screen. The words are what gets lifted above it. */
.hero-d-in{position:static}
.hero-d-in > div:first-child{position:relative;z-index:1}

/* Two knobs, because the scrim has two jobs that pull opposite ways: --ink-text is how dark it gets
   behind the words, --ink-open how much is left over the lit doors. They are tuned by measurement,
   not by eye: scripts/hero-contrast.py renders the hero with the words hidden, samples the photo
   inside each text box and reports the contrast of cream against the lightest pixel there. */
.hero-d{--ink-text:.64;--ink-open:.42}

/* phone: the words cover the width, so the scrim runs down and lifts over the doors below them */
.hero-d .hero-yard img{object-position:60% 42%}
.hero-d .hero-yard::after{
  background:linear-gradient(180deg,
    rgba(17,17,16,var(--ink-text)) 0%,
    rgba(17,17,16,calc(var(--ink-text) - .06)) 45%,
    rgba(17,17,16,calc(var(--ink-open) + .12)) 74%,
    rgba(17,17,16,var(--ink-open)) 100%)}
@media (max-width:819px){
  /* room under the buttons so they are not sitting on the section edge */
  .hero-d-in{padding-bottom:46px}
  /* the caption would land on top of the buttons, and the alt text already says this */
  .hero-d .hero-yard figcaption{display:none}
}
@media (min-width:820px){
  /* 540 rather than 660. The words are shorter than the section and centred in it, so every pixel of
     height the photograph does not need is split above and below them: at 660 that left 77px of dark
     photograph between the bar and the first line, which reads as the page not having started. At
     540 the free space has run out at every width from 1024 up and the top padding is the gap. Below
     that the section simply grows to fit its words, which is what min-height is for. */
  .hero-d-in{grid-template-columns:.95fr 1.05fr;align-items:center;min-height:min(64vh,540px)}
  /* On a laptop the gradient runs across, so the two knobs mean what their names say: hold the left
     third dark under the words and let the doors come up almost unscrimmed. On a phone it runs down
     and the words cover the width, so there is no open region to protect and the same names want
     nearly opposite values: a lighter, flatter wash. Both sets come from scripts/hero-sweep.py. */
  .hero-d{--ink-text:.90;--ink-open:.14}
  .hero-d .hero-yard img{object-position:64% 50%}
  .hero-d .hero-yard::after{
    background:linear-gradient(95deg,
      rgba(17,17,16,calc(var(--ink-text) + .04)) 0%,
      rgba(17,17,16,var(--ink-text)) 26%,
      rgba(17,17,16,calc((var(--ink-text) + var(--ink-open)) / 2)) 48%,
      rgba(17,17,16,var(--ink-open)) 68%,
      rgba(17,17,16,calc(var(--ink-open) + .10)) 100%)}
}

/* the words, inverted */
.hero-d h1{color:var(--cream)}
.hero-d p{color:rgba(246,243,236,.86)}
.hero-d .defn{border-bottom-color:rgba(246,243,236,.28);color:rgba(246,243,236,.82)}
.hero-d .defn b{color:var(--cream)}
.hero-d .defn .pr{color:rgba(246,243,236,.7)}
.hero-d .defn .bar{color:rgba(246,243,236,.4)}
.hero-d .defn i{color:var(--olive-light)}
.hero-d .defn .am{color:var(--cream)}
.hero-d .defn .def{color:rgba(246,243,236,.82)}
.hero-d .tag.now{background:var(--cream);color:var(--ink)}
.hero-d .btn{border-color:var(--cream);color:var(--cream)}
.hero-d .btn.solid{background:var(--cream);color:var(--ink)}
.hero-d .btn:focus-visible{outline-color:var(--cream)}
/* A soft shadow under the words, not for the look of it: the scrim is measured against the 99th
   percentile of the photo behind each line, and this covers the one hot pixel above that. It buys
   the brightness back that a flatter, heavier scrim would have cost. */
.hero-d-in > div:first-child{text-shadow:0 1px 2px rgba(17,17,16,.35),0 2px 22px rgba(17,17,16,.45)}
.hero-d .btn,.hero-d .tag{text-shadow:none}
.hero-d .hero-yard figcaption{position:absolute;right:16px;bottom:14px;z-index:2;font-family:var(--mono);
  font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:rgba(246,243,236,.85);
  background:rgba(17,17,16,.45);padding:6px 10px;border-radius:999px;backdrop-filter:blur(3px)}

/* what's on */
.whatson{margin-top:22px;display:grid;gap:18px}
.whatson .day h3{font-size:15px;font-family:var(--mono);font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--olive);margin-bottom:8px}
.whatson .ev{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:14px 0;border-top:1px solid var(--line)}
.whatson .ev>div{display:grid;gap:3px}.whatson .ev b{font-size:17px}.whatson .ev small{color:var(--ink-soft);font-size:13.5px}
@media (max-width:520px){.whatson .ev{flex-direction:column;align-items:flex-start}}
.instore{margin:10px 0 0;padding:0;list-style:none;display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:6px 16px}
.instore li{display:flex;align-items:baseline;justify-content:space-between;gap:16px;padding:9px 0;border-bottom:1px solid var(--line-soft);font-size:15px}
.instore li .nm{display:flex;flex-direction:column}
.instore li small{color:var(--ink-soft);font-size:13px}
.instore li .mono{white-space:nowrap;font-weight:500}
.am-sub{font-family:"Noto Sans Ethiopic","Instrument Sans",sans-serif;font-size:17px;color:var(--olive);margin:-6px 0 4px}
/* Thumbnails, 72px square with a cream tile until the photo lands. The shop keeps them: it sells
   eggs and papaya and what a crate looks like this week is worth seeing. The menu dropped them,
   so the four-column row belongs to rows that actually carry a picture. */
.item:has(> .thumb){grid-template-columns:auto 1fr auto auto}
.item .thumb{width:72px;height:72px;border-radius:14px;object-fit:cover;background:#EFEAE0;display:block;box-shadow:inset 0 0 0 1px rgba(0,0,0,.06)}
.item.out .thumb{filter:grayscale(.6)}
@media (max-width:480px){.item .thumb{width:60px;height:60px;border-radius:12px}.item:has(> .thumb){gap:0 10px}}
/* phone nav: a hamburger on the left opening a drawer, with Menu always one tap away */
.menu-btn,.nav-primary,.nav-scrim{display:none}
/* Home is the drawer's job. On a laptop the wordmark already is the home link. */
.top nav .nav-home{display:none}
@media (max-width:760px){
  /* the blur makes the header a containing block, which would trap the fixed drawer inside it */
  .top{z-index:70}
  .top .wrap{gap:8px}
  .top .order-cta{display:none}
  /* the bar stays above the drawer, so the close button and the Menu pill are never covered */
  .top .logo,.top .nav-primary,.menu-btn{position:relative;z-index:80}
  .menu-btn{order:-1;display:inline-flex;flex-direction:column;justify-content:center;gap:5px;width:44px;height:44px;margin-left:-11px;padding:11px;border:0;border-radius:12px;background:none;cursor:pointer;flex:none;-webkit-tap-highlight-color:transparent}
  .menu-btn span{display:block;height:2px;border-radius:2px;background:var(--cream);transition:transform .2s,opacity .2s}
  .nav-open .menu-btn span:nth-child(1){transform:translateY(7px) rotate(45deg)}
  .nav-open .menu-btn span:nth-child(2){opacity:0}
  .nav-open .menu-btn span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}
  /* Same rule on a phone, where this pill is the Order button. It was a grey chip that read as one
     more nav item; olive makes it the button it always was. */
  .nav-primary{display:inline-block;margin-left:auto;text-decoration:none;font-size:15px;font-weight:600;color:var(--cream);padding:8px 14px;border-radius:999px;background:var(--olive)}
  .nav-primary[aria-current]{background:var(--olive-deep);color:var(--cream)}
  .nav-scrim{display:block;position:fixed;inset:0;z-index:50;background:rgba(20,20,20,.45);opacity:0;visibility:hidden;transition:opacity .25s}
  .nav-open .nav-scrim{opacity:1;visibility:visible}
  .top nav{display:flex;position:fixed;top:0;left:0;bottom:0;z-index:60;width:min(80vw,320px);flex-direction:column;gap:2px;overflow-y:auto;
    padding:calc(78px + env(safe-area-inset-top)) 14px calc(18px + env(safe-area-inset-bottom));background:#0B0B0A;
    box-shadow:8px 0 40px rgba(20,20,20,.18);transform:translateX(-100%);visibility:hidden;transition:transform .25s ease,visibility .25s;font-size:17px}
  .nav-open .top nav{transform:none;visibility:visible}
  .top nav .nav-home{display:block}
  /* Home sits above the places, with a hairline under it, because it is a different kind of item */
  .top nav .nav-home{margin-bottom:6px;padding-bottom:16px;border-bottom:1px solid rgba(246,243,236,.14)}
  .top nav a{padding:14px 12px;border-radius:12px;color:var(--cream);text-decoration:none}
  .top nav a[aria-current]{background:rgba(246,243,236,.12);font-weight:600}
  html.nav-open,html.nav-open body{overflow:hidden}
}
/* drink rewards */
.card-line{font-size:14.5px;color:var(--olive);background:var(--olive-wash);display:inline-block;padding:8px 14px;border-radius:999px}
.receipt .line.free .nm{color:var(--olive)}
.receipt .line.free .mono{color:var(--olive)}
.reward{margin-top:22px;padding:18px 20px;border-radius:16px;background:var(--olive-wash);display:grid;gap:6px;text-align:left}
.reward b{font-size:17px}
.reward span{font-size:14px;color:var(--ink-soft)}
.reward.win{background:var(--olive);color:var(--cream)}
.reward.win b{font-size:20px}
.reward.win span{color:rgba(246,243,236,.85)}
.reward .dots{display:flex;flex-wrap:wrap;gap:7px;margin-bottom:4px}
.reward .dots span{width:13px;height:13px;border-radius:50%;border:1.5px solid var(--olive);opacity:.45}
.reward .dots span.on{background:var(--olive);opacity:1}
.ticket .freebie{margin:8px 0 0;padding:7px 10px;border-radius:8px;background:#4B5320;color:#F6F3EC;font-size:14px;font-weight:600}
.rw-form{display:flex;flex-wrap:wrap;gap:10px;align-items:end}
.rw-form .field{margin:0}
.t form.inline{display:flex;gap:4px}
.t form.inline button{font-size:12.5px;padding:5px 9px;border-radius:8px;border:1px solid var(--line);background:var(--paper);cursor:pointer;white-space:nowrap}
.t form.inline button:hover{background:var(--olive-wash)}
/* back to an order in progress, on every page but the order page itself */
.order-bar{display:flex;align-items:center;gap:12px;padding:11px 16px;background:var(--ink);color:var(--cream);text-decoration:none;font-size:14.5px}
.order-bar.ready{background:var(--olive)}
.order-bar .c{font-family:var(--mono);font-size:13px;font-weight:500;letter-spacing:.08em;background:rgba(246,243,236,.16);padding:4px 9px;border-radius:7px}
.order-bar .go{margin-left:auto;font-weight:600;text-decoration:underline;white-space:nowrap}
/* Which counter the order is waiting at, said on the bar itself. Kraft always means Table, so a
   guest carrying both a coffee and a bag of eggs can tell the two apart without opening either.
   On a narrow phone the status words go and the counter stays: two bars reading "We are on it"
   and nothing else are two bars a guest cannot tell apart, which is the whole point of having
   two. The colour still carries ready, and tapping shows the rest. */
.order-bar .w{font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;
  color:rgba(246,243,236,.72);white-space:nowrap}
.order-bar.shop .w{color:var(--kraft)}
.order-bar.shop.ready{background:var(--kraft-deep)}
@media (max-width:430px){
  .order-bar{gap:9px;padding-inline:14px}
  .order-bar .s{display:none}
  .order-bar .go{font-size:13.5px}
}
/* The order number: the word small above, the characters people call out underneath. Both halves
   are the code, so a guest reading it off the screen gets the whole thing either way. */
.status-hero .code .pre{display:block;font-size:.34em;letter-spacing:.22em;color:var(--ink-soft);margin-bottom:2px}
.status-hero .code-note{margin-top:8px;font-family:var(--mono);font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-soft)}
.status-hero .thanks{margin-top:26px;font-size:17px;font-weight:600}
/* an order nobody has touched: the kitchen screen says so, loudly */
.stalebar{display:none}
.stalebar.on{display:block;margin:0 0 10px;padding:12px 16px;border-radius:10px;background:#8c2f1f;color:#F6F3EC;font-size:17px;font-weight:600}
.ticket.stale{border-color:#8c2f1f;box-shadow:0 0 0 2px rgba(140,47,31,.35)}
.ticket .age.stale{color:#f28b82;font-weight:700}
.ticket .waiting{margin:8px 0 0;padding:7px 10px;border-radius:8px;background:rgba(140,47,31,.15);color:#f28b82;font-size:13.5px}
.ticket .acts button.warn{border-color:#8c2f1f;color:#f28b82}
.status-hero .closed{margin-top:22px;padding:16px 18px;border-radius:14px;background:rgba(140,47,31,.1);color:#8c2f1f;font-size:15px;line-height:1.45}
.status-hero .slow{margin-top:18px;padding:14px 16px;border-radius:14px;background:var(--olive-wash);font-size:15px;line-height:1.45}
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:18px 22px;margin-top:12px}
.kpis small{display:block;margin-top:2px;font-size:12.5px;line-height:1.35}

/* Yard-only ordering: the quiet note on the menu, and the block that replaces the order button */
/* The yard-only rule. Permanent, and set in the page's own voice rather than as a muted aside:
   a guest who misses it and then cannot order is the one who ends up asking at the counter. */
/* The one condition on ordering, said in the same voice as the label above it. It used to be set
   bold in ink behind an olive bar, which made the smallest print on the page the loudest thing on
   it: a guest scanning for a drink met a rule first. */
.yardnote{font-family:var(--mono);font-size:12px;letter-spacing:.14em;text-transform:uppercase;
  font-weight:400;color:var(--ink-soft);margin:0}
.gate{background:var(--olive-wash);border-radius:12px;padding:14px 16px;margin:4px 0 12px}
.gate b{display:block;font-size:16px;margin-bottom:6px}
.gate p{margin:0;font-size:14px;line-height:1.5}
.gate p.am{margin-top:8px;color:var(--ink-soft)}
.ticket .src{font-family:var(--mono);font-size:12px;opacity:.75}
.ticket .src.store{color:var(--kraft);opacity:1;font-weight:500}
.gate .btns{margin-top:12px;display:flex;gap:8px;flex-wrap:wrap}
.gate .tiny{margin-top:8px;font-size:13px;color:var(--ink-soft)}

/* ---------- phones and other touch screens ----------
   Nearly all of this site is read on a phone held in one hand, standing in a queue or sitting at a
   table. The rules below are about the hand, not the screen size: bigger targets, no accidental
   zoom, no blue system chrome in a cream and olive room. Desktop is left alone. */

/* The default blue flash on tap is the one piece of browser chrome guests see most. Make it ours. */
a,button,label,select,summary,input[type=submit]{-webkit-tap-highlight-color:rgba(75,83,32,.14)}
/* Removes the browser's 300ms wait for a possible double-tap zoom on every control. */
a,button,label,select,summary,input,textarea{touch-action:manipulation}
/* Checkboxes and radios draw themselves in system blue unless told otherwise. */
input[type=radio],input[type=checkbox]{accent-color:var(--olive)}
/* A guest scrolling the order sheet to its end should not start dragging the menu behind it. */
body.sheet-open{overflow:hidden}

/* Phones by width, plus any touch screen: Apple and Google both put the target floor at 44px, and
   anything smaller gets mis-tapped by someone holding a phone in one hand and a cup in the other. */
@media (max-width:760px), (pointer:coarse){
  .add-btn{height:44px;padding:0 18px;font-size:15px}
  .qty button{width:42px;height:44px}
  .sheet .x{min-width:44px;min-height:44px;display:grid;place-items:center;padding:0}
  .btn.sm{padding:12px 18px}
  .menu-cats a{padding:11px 16px}
  .menu-cats .wrap{padding-block:8px}
  .nav-primary{padding:11px 16px}
  .radio{padding:16px}
  .radio input,.check input{width:22px;height:22px}
  .field input,.field select,.field textarea{padding:14px}
  /* Footer links at arm's length. The columns are already stacked, so the only thing missing is
     height: eleven pixels above and below turns a line of text into something a thumb can hit. Not
     .soc, which is a 34px circle already and would lose the mark out of the middle of it. */
  footer .fcol-links{gap:2px}
  footer .fcol-links a{padding:9px 0}
  /* Same reason one row down: two small links at the very bottom of a phone are the hardest thing on
     the page to hit, and they are the ones somebody taps when they are already annoyed. */
  footer .fine a{display:inline-block;padding:10px 0}
  /* Captions burned into photos were sized for a laptop; at arm's length they were unreadable. */
  .hero-pics figcaption,.hero-yard figcaption,.ph-slot figcaption{font-size:11.5px}
  .hero-pics.three .strip{font-size:11px}
}
/* On a tablet the horizontal nav is still there; on a phone it is a drawer with its own sizing. */
@media (pointer:coarse) and (min-width:761px){ .top nav a{padding:11px 12px} }

/* One-handed reach: on a short phone the sheet should not run to the very top of the screen, and
   the four order-status chips need to fit a 320px phone without shrinking the words. */
@media (max-width:719px){
  .sheet{max-height:88dvh}
  .steps{gap:5px}
  .steps div{padding:11px 4px;font-size:11.5px;letter-spacing:.02em}
}

/* The order button stays on screen while the guest fills in the form. Without this it sits below
   the fold on a phone and people scroll up and down looking for it. */
.sheet-act{position:sticky;bottom:0;background:var(--cream);padding:14px 0 calc(20px + env(safe-area-inset-bottom));margin-top:2px;box-shadow:0 -16px 16px -8px var(--cream)}
/* the sheet's own bottom padding now lives in that bar, so nothing scrolls into view beneath it */
.sheet{padding-bottom:0}

/* The plan of the yard, under the hero: Press, the yard, Table, left to right as you see them from
   the street. A stranger meets the names here because the navigation above says Café and Shop.
   A lit door sits on paper with a soft shadow. A dark door is drawn in dashes, dimmed, and named
   just the same: it is a door you can see and cannot open yet, which is what makes someone want
   to know more, and it carries no date, because a date is a promise. Both are links; the dark one
   opens onto a page that says plainly it is not ready, so the tag tells the truth before the tap. */
.yard-plan{padding-block:clamp(36px,5vw,60px)}
.yardmap{display:grid;gap:10px}
.door{position:relative;display:flex;flex-direction:column;gap:4px;text-decoration:none;padding:18px 18px 16px;
  border-radius:14px;border:1px solid var(--line);background:var(--paper);transition:transform .15s,box-shadow .15s,border-color .15s}
.door .tag{align-self:flex-start;margin-bottom:8px}
.door b{font-size:19px;font-weight:600;letter-spacing:-.01em}
.door span:last-child{font-size:14.5px;color:var(--ink-soft)}
.door.open{box-shadow:0 8px 26px rgba(20,20,20,.08)}
.door.open::after{content:"→";position:absolute;right:16px;top:18px;font-size:18px;opacity:.45}
.door.open:hover,.door.open:focus-visible{transform:translateY(-2px);box-shadow:0 14px 34px rgba(20,20,20,.12)}
.door.dark{background:transparent;border-style:dashed;border-color:#C9C3B4;box-shadow:none;cursor:default}
.door.dark b,.door.dark span:last-child{color:var(--ink-soft);opacity:.72}
/* No hover state on a closed door. It used to lift and brighten under the cursor, which is a card
   promising it does something, and it was an anchor at the time so it did: it said "Not yet" and
   then opened the page. It is a plain block now and it behaves like one. */
/* As many columns as there are doors. The yard's card is left out until its switch is on, so this
   is two most of the time and three when it is not; repeat(3,1fr) left an empty third of the row. */
@media (min-width:720px){.yardmap{grid-template-columns:repeat(auto-fit,minmax(min(240px,100%),1fr));gap:14px}}

/* One number on the front door. The yard-level half of "what you measure, you can change", set
   from Admin and blank by default; a fact, not a promise, and the one line that can change weekly. */
.fact{background:var(--olive);color:var(--cream);padding-block:clamp(36px,5vw,56px);border-bottom:0}
.fact .label{color:rgba(246,243,236,.72)}
.fact-big{font-family:var(--mono);font-size:clamp(24px,3.6vw,40px);font-weight:500;line-height:1.15;color:var(--cream);max-width:none;margin-top:10px;letter-spacing:-.01em}
.fact-note{margin-top:12px;color:rgba(246,243,236,.85);font-size:15px}
.fact-note a{color:var(--cream)}

/* ---------- the Today page ----------
   Colour says what to do, not how big a number is. Olive means fine, kraft means keep an eye on it,
   red means someone is waiting. Anything without a state stays neutral, so the coloured ones carry
   real weight instead of becoming wallpaper. */
.jobs{display:grid;gap:8px;margin-bottom:4px}
.job{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;
  background:var(--paper);border:1px solid var(--line);border-left:5px solid var(--line);border-radius:12px;padding:14px 16px}
.job b{display:block;font-size:16px}
.job small{display:block;color:var(--ink-soft);font-size:13.5px;margin-top:2px}
.job.act{border-left-color:var(--danger);background:#FCF1EF}
.job.act b{color:var(--danger)}
.job.watch{border-left-color:var(--kraft-deep)}
.job.ok{border-left-color:var(--olive)}
.takings .big{font-size:clamp(40px,7vw,60px);font-weight:500;line-height:1.05;letter-spacing:-.02em}
.takings p{margin-top:6px;font-size:15px}
.kpi{border-left:3px solid transparent;padding-left:12px}
.kpi .num{font-size:30px;font-weight:500;line-height:1.1;margin-top:4px}
.kpi.ok{border-left-color:var(--olive)}
.kpi.watch{border-left-color:var(--kraft-deep)}
.kpi.act{border-left-color:var(--danger)}
.kpi.act .num{color:var(--danger)}
.spark{display:block;width:100%;height:76px;margin-top:12px}
.sparkfoot{display:flex;justify-content:space-between;align-items:baseline;gap:12px;margin-top:6px;
  font-family:var(--mono);font-size:12px;color:var(--ink-soft)}

/* ---------- inventory ----------
   The state of a thing is the first thing you should see, so it colours the whole row rather than
   hiding in a column. Red is out or low, kraft is getting there, everything else stays quiet. */
.inv.out td, .inv.low td{background:#FCF1EF}
.inv.out td:first-child{box-shadow:inset 4px 0 0 var(--danger)}
.inv.low td:first-child{box-shadow:inset 4px 0 0 var(--danger)}
.inv.watch td:first-child{box-shadow:inset 4px 0 0 var(--kraft-deep)}
.restock{border-left:5px solid var(--danger)}
.invform{display:flex;gap:6px;align-items:center}
.invform input{width:70px;padding:7px 8px;font-size:14px;border:1px solid var(--line);border-radius:8px;background:#fff}
.invform select{padding:7px 8px;font-size:13px;border:1px solid var(--line);border-radius:8px;background:#fff}
.movelog{list-style:none;margin:8px 0 0;padding:0;font-size:14px}
.movelog li{padding:6px 0;border-bottom:1px solid var(--line-soft)}
.pillrow{display:flex;flex-wrap:wrap;gap:6px}
.pillrow a.tag{text-decoration:none}

/* ---------- meal plans ----------
   Four tiers people compare at a glance, so the numbers carry the weight: meals a week big, the
   price under it, and what one meal costs, because that is the comparison anyone actually makes.
   One tier is marked as the usual choice and lifts off the row slightly rather than shouting. */
.plans{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:14px}
.plan{position:relative;background:var(--paper);border:1px solid var(--line);border-radius:14px;
  padding:20px 18px;display:flex;flex-direction:column;gap:8px}
.plan.pop{border-color:var(--olive);box-shadow:0 6px 24px rgba(75,83,32,.13)}
.plan-flag{position:absolute;top:-11px;left:18px}
.plan-n{font-size:40px;font-weight:500;line-height:1}
.plan-n small,.plan-p small{display:block;font-family:var(--sans);font-size:12.5px;font-weight:400;
  color:var(--ink-soft);letter-spacing:0;margin-top:3px}
.plan-p{font-size:21px;font-weight:500;line-height:1.1}
.plan p{font-size:14px;margin:0}
.plan .btns{margin-top:auto;padding-top:6px}
.ticks{list-style:none;margin:2px 0 0;padding:0;font-size:13.5px;color:var(--ink-soft)}
.ticks li{padding:4px 0 4px 20px;position:relative}
.ticks li::before{content:"✓";position:absolute;left:0;color:var(--olive);font-weight:600}
/* How it works: numbered, because the order is the point and people count the steps before they
   read them. */
.steps-n{list-style:none;counter-reset:s;margin:18px 0 0;padding:0;display:grid;
  grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:18px}
.steps-n li{display:flex;gap:12px;align-items:flex-start}
.steps-n b{flex:0 0 32px;height:32px;border-radius:50%;background:var(--olive);color:#F6F3EC;
  display:grid;place-items:center;font-family:var(--mono);font-size:15px;font-weight:500}
.steps-n strong{display:block;font-weight:600;font-size:15px}
.steps-n span{display:block;font-size:13.5px;color:var(--ink-soft);margin-top:3px;line-height:1.45}
@media (max-width:480px){.plans{grid-template-columns:1fr}.plan-n{font-size:34px}}

/* ---- A page with a choice at the top: the head, the tabs, the panels --------------------------
   The café page is two visits, not one offer with two halves. A cup is minutes at a counter; the
   ceremony is a reserved seat and most of an afternoon. So the page asks first and answers second,
   and the row of tabs is the same control the menu uses for its categories: pills in a scrolling
   row, the one you are in filled olive, the rest outlined.

   One difference from the menu's row: it is cream, not #0B0B0A, because a second dark strip under a
   dark bar is 134px of chrome before the page starts.

   The head above it is the name of the place and what it is in Amharic, and nothing else. It held a
   headline for a while, which put a sentence between the bar and the choice, and the choice is why
   anyone is on this page. The three lines are set tight on purpose: a name, its translation and the
   controls are one block, not three things with air between them.

   The Amharic went with the headline. It was on a second line inside every pill, which doubled the
   height of the row for a word nobody reads twice, and a control is a thing you hit. One line each,
   so the pills are lozenges again, the same shape the menu uses. */
.pagehead{background:var(--paper)}
.pagehead .wrap{display:grid;gap:0;justify-items:start;padding-block:clamp(16px,2.4vw,26px) 10px}
.pagehead h1{font-size:clamp(30px,3.8vw,46px);line-height:1.05;letter-spacing:-.03em;margin:0}
.pagehead .am-sub{margin:3px 0 0}
.sec-tabs{position:sticky;top:var(--topbar);z-index:10;background:var(--paper)}
/* No rule under the row. It was drawing a line across the photograph the moment anything scrolled,
   which is the same hard edge the picture's own wash exists to avoid, turned ninety degrees. What
   replaces it is a short fall of paper below the row, so the photograph dissolves under the strip
   rather than stopping at it. At rest it lies over paper and cannot be seen at all. */
.sec-tabs::after{content:"";position:absolute;left:0;right:0;top:100%;height:20px;pointer-events:none;
  background:linear-gradient(180deg,var(--paper) 0%,rgba(255,253,248,0) 100%)}
.sec-tabs .wrap{display:flex;gap:6px;overflow-x:auto;padding-block:8px 10px;scrollbar-width:none}
.sec-tabs .wrap::-webkit-scrollbar{display:none}
.sec-tabs a{white-space:nowrap;text-decoration:none;font-size:14.5px;font-weight:600;
  padding:8px 16px;border-radius:999px;border:1px solid var(--line);background:var(--paper);color:var(--ink-soft)}
.sec-tabs a.on{background:var(--olive);border-color:var(--olive);color:var(--cream)}
.sec-tabs a:hover,.sec-tabs a:focus-visible{border-color:var(--ink-soft)}
.sec-tabs a.on:hover,.sec-tabs a.on:focus-visible{border-color:var(--olive)}
.sec-panel{display:none}
.sec-panel.on{display:block}

/* ---- The cafe page: four bands, each one a photograph and the words beside it ------------------
   Paper, olive, paper, black, in that order, so the page has a rhythm rather than a length, and the
   last one is the menu's own black because the menu is what is on the other side of that button.

   Every band is the same shape: words on the left in a measured column, a photograph on the right
   that bleeds off the edge of the window. The bleed is the whole trick. A picture inside the wrap
   is a cell in a two-column table and reads like one; a picture that runs off the side reads as a
   spread, and it is the difference between a page with photographs on it and a page made of them.

   The small vertical notes down the outer margin are decoration and are marked aria-hidden. They
   are texture, not a sentence anyone has to read, and a screen reader that announced them would be
   reading the wallpaper aloud. */
.band{border-bottom:0;padding:0;position:relative;overflow:hidden}
.band-paper{background:var(--paper);color:var(--ink)}
.band-olive{background:var(--olive);color:var(--cream)}
.band-ink{background:#0B0B0A;color:var(--cream)}
.band-in{display:grid;gap:clamp(20px,3vw,44px);align-items:center;
  padding-block:clamp(34px,5vw,74px);position:relative}
@media (min-width:900px){
  /* Words, margin, picture. The margin column is what the small notes live in, and it comes
     before the picture because the picture bleeds off the right of the window: a column after it
     is a column underneath it. Empty on a narrow screen, where a margin is a luxury the width
     cannot pay for. */
  .band-in{grid-template-columns:minmax(0,1.04fr) auto minmax(0,1fr)}
  /* The olive band has no photograph, so it has no margin column either: left to the three-column
     template its two children landed in the first and second, and the auto column sized itself to
     the tiles and squeezed the headline into one word per line. */
  .band-olive .band-in{grid-template-columns:minmax(0,1.04fr) minmax(0,1fr)}
}
.band-words{position:relative;z-index:1;max-width:46ch}
.band-words h1,.band-words h2{font-size:clamp(30px,4vw,52px);line-height:1.05;letter-spacing:-.03em;
  margin:10px 0 0;max-width:16ch}
/* A step down from the page's own h1, which now sits above the tabs. At the same size the first
   thing a guest meets is two headlines of equal weight, one under the other, both starting with the
   word Coffee, and no hierarchy at all between the page and the answer to its question. */
.band-words h2{font-size:clamp(24px,2.8vw,36px);max-width:19ch}
.band-words p{margin-top:14px;max-width:44ch}
.band-words .am-sub{margin-top:6px}
.band-words .hours{margin-top:18px;font-family:var(--mono);font-size:13px;letter-spacing:.04em}
.band-words .btns{margin-top:26px}
.band-words .notice{margin-top:18px}
.band-olive .band-words .label{color:rgba(246,243,236,.75)}
.band-ink .band-words .label{color:rgba(246,243,236,.62)}
.band-ink .band-words p,.band-olive .band-words p{color:rgba(246,243,236,.88)}
/* The picture, running off the right edge of the window. On a phone it is a normal picture again:
   there is no margin to bleed into and a half-cropped cup on a 390px screen is just a cropped cup. */
.band-pic{margin:0;border-radius:var(--r);overflow:hidden;line-height:0}
.band-pic img{width:100%;height:100%;object-fit:cover;display:block;aspect-ratio:4/3}
@media (min-width:900px){
  .band-pic{border-radius:var(--r) 0 0 var(--r);margin-right:calc(50% - 50vw);width:auto}
  .band-pic img{aspect-ratio:auto;height:clamp(300px,34vw,440px)}
}
/* The one on black is the plate the menu page uses, which is already graded into that black, so it
   gets no corner radius: a rounded corner would draw the rectangle the grading exists to remove. */
.band-ink .band-pic{border-radius:0}

/* ---- The first band: the photograph as the room, not as a panel ------------------------------
   The same move as the menu's picture, in the other direction. There the photograph dissolves into
   black; here it dissolves into paper. Either way it stops being a rectangle with four sides and
   becomes the thing the words are standing in, which is what the page has instead of a section
   break between the offer and the picture of it.

   Out of the flow, so it costs no height: the band is as tall as its words, and the photograph
   fills whatever that turns out to be.

   The gradient across it is a wash, not a feather, and that is the second correction. A feather
   held solid paper out to 43% of the band and then ramped, which meant the photograph did not
   start, it began: a soft edge is still an edge, and what it cut through was the bowl of beans,
   half a bowl on the picture and half a bowl of nothing. So the paper now thins all the way across
   instead of stopping. Behind the words it sits at about nine parts in ten, which leaves the beans
   as a pale shape somebody notices on the second look, and is not enough to cost the paragraph a
   point of contrast. scripts/press-contrast.py measures that claim at six widths down the whole
   scroll; it is not an opinion about how it looks. */
.band-atmos{isolation:isolate}
/* It starts at 28% rather than at 0, and that number is a trade, not a taste. The master is a 2:3
   portrait and object-fit crops it to whatever box it is given, so every pixel of extra width is
   paid for in height: full-bleed at this band's height shows a third of the frame and cuts the top
   off the mug. 28% is the widest the box goes while the mug keeps its whole height and the bowl of
   beans still lands under the words, which is the thing this treatment exists to show. */
.band-atmos .band-pic{position:absolute;inset:0 0 0 20%;z-index:0;margin:0;width:auto;
  border-radius:0;pointer-events:none}
.band-atmos .band-pic img{width:100%;height:100%;object-fit:cover;object-position:50% 55%;aspect-ratio:auto}
/* A heavier wash, for a photograph whose left half is dark. The hero works at the strength above
   because the words land on a pale wall and a pale plate; the cart is a black trolley and a cook in
   black under an umbrella, and the same wash put the paragraph on a man's shirt. Same idea, more
   paper, and the number comes from scripts/press-contrast.py rather than from an opinion. */
/* Higher than the hero, and for a reason that has nothing to do with composition. The cart has a
   tagline painted on its side, and it is not the one the site uses; carried at 62% it ran across the
   bottom of the band in letters a foot high. At 50% it is below the frame and what is left is the
   cart, the griddle and the trays, which is what the panel is about. */
.band-atmos.dim .band-pic img{object-position:50% 50%}
/* A third strength of wash, for the ceremony.
   The daily panel's photograph is a pale wall and a plate; the words sit on it and the default holds
   enough paper. This one is a dark cup of coffee filling the middle of the frame, and the tail of
   every line of the paragraph landed on it: measured, the paragraph ran at 1.03 against a floor of
   4.5, which is ink on coffee and about as unreadable as this palette can get. It looked "a bit
   light" and it was very nearly nothing.
   So the paper is held further across, out past where the words end, and only then let go. Measured
   with scripts/press-contrast.py: the paragraph now runs 5.3 to 6.2 across every width, the heading
   14 and up. A stronger wash again was tried and it flattened the cup into a pale rectangle, which
   is a different way of losing the photograph. */
.band-atmos.soft .band-pic::after{
  background:linear-gradient(90deg,var(--paper) 0%,rgba(255,253,248,.96) 20%,rgba(255,253,248,.86) 36%,rgba(255,253,248,.52) 56%,rgba(255,253,248,0) 80%),
             linear-gradient(180deg,var(--paper) 0%,rgba(255,253,248,0) 13%,rgba(255,253,248,0) 84%,var(--paper) 100%)}
/* The cart, the darkest of the three: a black trolley and a cook in black down the left, which is
   where the words are. It had the strongest wash already, and the new, longer paragraph reached
   further down into the dark part and measured 3.64 against a floor of 4.5. Held a little wider
   again, it runs 5.1 to 5.8. Two stronger versions were measured and both were better on paper and
   worse to look at: past this the trolley stops being a trolley. */
.band-atmos.dim .band-pic::after{
  background:linear-gradient(90deg,var(--paper) 0%,rgba(255,253,248,.94) 16%,rgba(255,253,248,.82) 38%,rgba(255,253,248,.46) 60%,rgba(255,253,248,0) 84%),
             linear-gradient(180deg,var(--paper) 0%,rgba(255,253,248,0) 13%,rgba(255,253,248,0) 84%,var(--paper) 100%)}
.band-atmos .band-pic::after{content:"";position:absolute;inset:0;
  background:linear-gradient(90deg,var(--paper) 0%,rgba(255,253,248,.60) 10%,rgba(255,253,248,.26) 30%,rgba(255,253,248,0) 54%),
             linear-gradient(180deg,var(--paper) 0%,rgba(255,253,248,0) 13%,rgba(255,253,248,0) 84%,var(--paper) 100%)}
/* static, so the photograph is positioned against the band and not against the text column. The
   column is 1120 of 1280 at a laptop, so relative here cost the picture 80px on the right: the
   spoon stopped dead against a strip of paper at the edge of the screen. */
.band-atmos .band-in{grid-template-columns:minmax(0,1fr);position:static}
/* The margin note is a sibling of the words, not a child, so it has no layer of its own.
   While the paper under it was solid that did not show; with the photograph washing all the
   way across, it was being painted over. */
.band-atmos .band-aside{position:relative;z-index:1}
/* Full ink over a photograph, not the soft grey it uses on flat paper. At --ink-soft it measured
   4.56 against a 4.5 floor on the ceremony panel, which is a margin one JPEG artefact eats. The rule
   for every small note on this page is the same: if it is legible enough to print, print it in ink;
   if it is not worth reading, take it off. */
.band-atmos .soon-note{color:var(--ink)}
@media (min-width:860px){
  /* One column on this band, because the second one would be inside the photograph. The margin
     note goes under the buttons instead, on paper, where it can be read: over the cup it measured
     1.17 against a 4.5 floor, which is decoration that has stopped being decoration. */
  /* Tall enough for the photograph to be one. The band is otherwise as tall as its words, which
     is about 420px, and a 2:3 frame in a box that shape is a horizontal slice of itself.
     Top-aligned, not centred. Centred, the words floated in the middle of all that height and left
     192px of nothing between the choice you just made and the answer to it at a wide screen, which
     reads as a page that has not loaded rather than as air. Top padding now sets that gap and the
     photograph gets the room underneath, which is what the height was bought for. */
  .band-atmos{min-height:clamp(500px,48vw,760px);display:grid;align-items:start}
  .band-atmos .band-in{grid-template-columns:minmax(0,1fr);padding-block:clamp(20px,2vw,30px) clamp(52px,6vw,96px)}
  .band-atmos .band-aside{padding-top:26px}
  /* The words stop at 39%, which is inside the picture now rather than short of it. That is the
     point: the paragraph ends over the pale side of the bowl, where the wash is still nine parts
     paper. What it must not do is run on to where the wash thins, so the cap and the ramp above are
     one measurement and moving either one alone is how this breaks. */
  .band-atmos .band-words{max-width:min(40ch,39%)}
}
/* Between the phone layout and a full laptop the same two numbers have to move together. 39% of
   900px is a 351px column, which sets the paragraph five lines deep and crowds the band; giving the
   words more room means giving the photograph a later start, or the text is over the beans again. */
@media (min-width:860px) and (max-width:1100px){
  .band-atmos .band-pic{inset:0 0 0 14%}
  .band-atmos .band-words{max-width:min(40ch,46%)}
}
/* On a phone there is no room to put the words beside the picture, so they go on top of it and the
   gradients turn: paper down the left is no use when the column is the whole screen, so the fade
   runs from the top instead and the picture lives in the lower half, under the buttons. */
@media (max-width:859px){
  /* The picture takes the foot of the band rather than the whole of it. Stretched over the full
     height it is a landscape photograph in a portrait box, so cover crops the sides away and what
     is left in the middle is the table: a screen of pale wood with a cup somewhere off the edge.
     Given a band of its own shape it frames the cup again, and it still has no sides, because the
     feather at its top is the only edge it has. */
  .band-atmos .band-pic{inset:auto 0 0 0;height:clamp(300px,74vw,420px)}
  .band-atmos .band-pic img{object-position:50% 62%}
  .band-atmos .band-pic::after{
    background:linear-gradient(180deg,var(--paper) 0%,rgba(255,253,248,.55) 34%,rgba(255,253,248,0) 72%)}
  .band-atmos .band-in{padding-bottom:clamp(286px,72vw,400px)}
}
/* Full strength, not a whisper. At .7 opacity this was grey-on-paper at 3.6:1, under the floor for
   11px type, which is a note nobody can read pretending to be a note. If it is on the page it is
   legible; if it should not be legible it should not be on the page. */
.band-aside{margin:0;align-self:start;padding-top:6px;font-family:var(--mono);font-size:11px;letter-spacing:.18em;
  text-transform:uppercase;line-height:2;color:var(--ink-soft);white-space:nowrap}
.band-olive .band-aside,.band-ink .band-aside{color:rgba(246,243,236,.72)}
@media (max-width:899px){.band-aside{display:none}}
/* An arrow on the actions, which is how the comp says "this goes somewhere". */
.btn.go::after{content:" \2192";font-weight:400}
.band-olive .tiles{grid-template-columns:repeat(2,1fr)}
@media (min-width:640px){.band-olive .tiles{grid-template-columns:repeat(3,1fr)}}
.band-olive .tiles div{background:transparent;border-color:rgba(246,243,236,.28)}
.band-olive .tiles b{color:var(--cream)}
.band-olive .tiles span{color:rgba(246,243,236,.72)}

/* ---- The curtain -----------------------------------------------------------------------------
   Black screen, the wordmark in cream, about a second, then it lifts on the yard. On the front
   door only, and once per visit: see curtain() in lib/layout.js for why, and for the few bytes in
   the head that decide it before anything paints.

   The lift is pure CSS with no JavaScript in it, so there is no state to get stuck in: the curtain
   rises on time even if scripting is off or something above it throws. It is inert to the pointer
   from the first frame, so a fast tap on the Order button underneath is never swallowed, and the
   page behind it is laid out normally the whole time rather than waiting to be told to start. */
.curtain{position:fixed;inset:0;z-index:999;display:grid;place-items:center;
  background:#101010;pointer-events:none;
  animation:curtain-lift 340ms cubic-bezier(.4,0,.2,1) 480ms forwards}
.curtain > div{width:min(210px,44vw);color:var(--cream);
  animation:curtain-name 300ms cubic-bezier(.2,.6,.3,1) both}
.curtain svg{width:100%;height:auto}
@keyframes curtain-name{from{opacity:0;transform:translateY(7px)}to{opacity:1;transform:none}}
@keyframes curtain-lift{to{opacity:0;visibility:hidden}}
/* A second page in the same visit, and anyone who asked their system for less motion. */
.nocurtain .curtain,.curtain-off .curtain{display:none}
@media (prefers-reduced-motion:reduce){.curtain{display:none}}
