/* Owner Hub.
   Petrol blue keeps the accent clear of green, amber and red, so those three
   can keep meaning open, warning and stopped. Signed off 2026-09-13. */

/* --ink-3, the quiet grey, was #6C7D82: 3.66:1 on --surface-2 and 3.83:1 on
   the page, under the 4.5:1 small text needs. #5D6B70 is 4.7:1 on the darkest
   of the three and still well short of --ink-2 (owner, 2026-09-24). The dark
   theme's already passed. test-takings.php holds both. */
:root{
  --paper:#EEF3F4; --surface:#FFFFFF; --surface-2:#E7EEF0;
  --line:#CCD9DC; --line-soft:#DFE8EA;
  --ink:#0C1417; --ink-2:#3B4A4E; --ink-3:#5D6B70;
  --accent:#0B6E7A; --accent-ink:#FFFFFF; --accent-soft:#D8EDEF;
  --good:#1C7A4A; --good-soft:#D9F0E3; --good-ink:#18703F;
  --warn:#8F550C; --warn-soft:#FAE9D2;
  --crit:#A62420; --crit-soft:#F9DCDA;
}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --paper:#080E10; --surface:#121B1E; --surface-2:#1A262A;
    --line:#2C393E; --line-soft:#212D31;
    --ink:#E9F0F1; --ink-2:#B0C1C5; --ink-3:#7E9197;
    --accent:#3FB3C2; --accent-ink:#04191C; --accent-soft:#0E323A;
    --good:#5FD08C; --good-soft:#0F2E1E; --good-ink:#5FD08C;
    --warn:#E0A155; --warn-soft:#33240F;
    --crit:#FF7F73; --crit-soft:#3B1714;
  }
}

*{box-sizing:border-box}

/* `hidden` has to win.
 *
 * The browser's own rule is [hidden]{display:none}, which is one attribute
 * selector - the same weight as any class here, and it comes first. So .btn's
 * display:inline-block quietly beat it, and `<button class="btn" hidden>` was
 * on screen the whole time.
 *
 * That is not cosmetic: the Save button on the menu's category order is meant to
 * appear only once something has actually moved, and instead it sat there
 * inviting people to save an order they had not changed. Found 2026-09-15 while
 * restyling the bar. */
[hidden]{display:none !important}
body{
  margin:0;background:var(--paper);color:var(--ink);line-height:1.55;
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;
  -webkit-font-smoothing:antialiased;
}
a{color:var(--accent)}
.mono{font-family:ui-monospace,"SF Mono",Menlo,Consolas,monospace;font-variant-numeric:tabular-nums}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:5px}

/* THE TOP BAR
 *
 * Written phone first: the base rules ARE the phone layout, and the one
 * min-width block below collapses it onto a single row once there is room.
 * Nothing here is a phone-shaped exception to a desktop design.
 *
 * (The table block further down is still the other way round - a max-width
 * override on a desktop default. It works and is tested, so it was left alone
 * rather than churned while restyling this. Worth flipping next time that
 * screen is opened.)
 *
 * Nine screens is more than a row of plain links can carry. Three things fix
 * that, and none of them is decoration:
 *
 *   - The screen you are on is a filled pill. Before this the only way to tell
 *     where you were was to read the heading.
 *   - Your name and Sign out are a separate group, because they are not screens
 *     of the restaurant - and on a phone they must not scroll away with the nav.
 *   - The bar sticks to the top. Menu and Orders are long, and a nav you have to
 *     scroll back up to find is a nav you stop using mid-service.
 */
.bar{
  background:var(--surface);border-bottom:1px solid var(--line);
  display:flex;flex-wrap:wrap;align-items:center;
  padding:6px 0 0
}

.bar .brand{
  font-weight:700;font-size:16px;letter-spacing:-.01em;
  color:var(--ink);text-decoration:none;flex:none;
  padding:0 14px 6px
}
.bar .brand:hover{color:var(--accent)}

/* You, and the way out. Beside the brand on a phone, so the row below is
   nothing but screens and can scroll freely. */
.bar .acct{
  display:flex;align-items:center;gap:4px;
  margin-left:auto;flex:none;padding:0 10px 6px
}

.bar .who{
  display:flex;align-items:center;gap:7px;
  padding:5px 10px 5px 5px;min-height:44px;
  border-radius:999px;text-decoration:none;color:var(--ink-2);font-size:13px;
  transition:background .12s ease
}
.bar .who:hover{background:var(--surface-2);color:var(--ink)}
.bar .who.on{background:var(--accent-soft);color:var(--accent)}

/* An initial, so the bar still says who is signed in when the name is too long
   to show - which on a phone is always. */
.bar .who .ini{
  width:27px;height:27px;border-radius:50%;flex:none;
  background:var(--accent);color:var(--accent-ink);
  display:flex;align-items:center;justify-content:center;
  font-size:12px;font-weight:700;letter-spacing:0
}
.bar .who .nm{
  max-width:130px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap
}

.bar .out{
  font-size:13px;color:var(--ink-3);text-decoration:none;white-space:nowrap;
  padding:10px 8px;min-height:44px;display:flex;align-items:center
}
.bar .out:hover{color:var(--crit)}
/* Sign out is a button that posts (owner, 2026-09-26) - a plain link let any
   other website sign you out by sending you to it. It still looks like one. */
.bar .out-form{margin:0;display:flex}
.bar button.out{background:none;border:0;font-family:inherit;cursor:pointer}
/* Your password, said in words beside Sign out (owner, 2026-09-26): the only
   way there was your initial, which on a phone is all the bar shows. */
.bar .pw-link{
  font-size:13px;color:var(--ink-3);text-decoration:none;white-space:nowrap;
  padding:10px 8px;min-height:44px;display:flex;align-items:center
}
.bar .pw-link:hover,.bar .pw-link.on{color:var(--accent)}

/* The screens. A full-width row that scrolls sideways rather than wrapping,
   because wrapping breaks labels mid-word ("Add-" / "ons"). _foot.php scrolls
   the current pill into view, or the last screen would open with its marker
   just past the right-hand edge. */
.bar nav{
  order:3;width:100%;
  display:flex;gap:4px;align-items:center;font-size:14px;
  overflow-x:auto;overflow-y:hidden;
  scrollbar-width:none;-webkit-overflow-scrolling:touch;
  padding:0 14px 6px;
  border-top:1px solid var(--line-soft)
}
.bar nav::-webkit-scrollbar{display:none}

.bar nav a{
  flex:none;display:flex;align-items:center;
  min-height:44px;padding:0 13px;margin-top:6px;border-radius:9px;
  color:var(--ink-2);text-decoration:none;font-weight:500;
  white-space:nowrap;
  transition:background .12s ease,color .12s ease
}
.bar nav a:hover{background:var(--surface-2);color:var(--ink)}

/* The screen you are on. A filled pill rather than an underline: an underline
   on a row that scrolls sideways disappears the moment it is half off-screen. */
.bar nav a.on{background:var(--accent);color:var(--accent-ink);font-weight:600}
.bar nav a.on:hover{background:var(--accent);color:var(--accent-ink)}
.bar nav a .pill{margin-left:6px}

/* Narrow phones: the name goes, the initial stays. A circle with a D in it is
   enough to tell two people apart on a shared tablet, and it leaves room for
   the way out - which is the thing you actually need on somebody else's phone. */
@media (max-width:420px){
  .bar .who .nm{display:none}
}

/* One row, once nine labels plus the brand and the account actually fit. */
@media (min-width:1100px){
  /* One row is thin enough to be worth pinning. Two rows on a phone are not:
     that is 14% of the screen, permanently, on the device this is built for. */
  .bar{
    flex-wrap:nowrap;padding:9px 20px;gap:14px;
    position:sticky;top:0;z-index:20
  }
  .bar .brand{padding:0}

  .bar nav{
    order:0;width:auto;margin-left:6px;min-width:0;
    padding:0;border-top:none;gap:2px;font-size:13.5px
  }
  .bar nav a{min-height:34px;padding:0 11px;margin-top:0;border-radius:8px}

  .bar .acct{
    order:1;padding:0 0 0 12px;gap:8px;
    border-left:1px solid var(--line-soft)
  }
  .bar .who{min-height:34px}
  .bar .out,.bar .pw-link{min-height:34px;padding:6px 4px}
}

/* Going back, and the one link that is really a control.
 *
 * Both were plain accent text with nothing to aim at. On a phone the only way
 * to leave a screen is the back link at the top, so it has to look like a thing
 * you press and be big enough to press - 44px, like everything else. */
/* Going back up a level.

   This used to be a bare word on the page background, which the owner reported
   twice: transparent on --paper is the same colour as nothing, so the one
   control every deep screen has was the hardest thing on it to see. It now sits
   on --surface with a border, the same treatment as every card, which is the
   only thing on these screens that reads as "you can press me". */
.back{margin:0 0 14px}
.back a{
  display:inline-flex;align-items:center;gap:5px;
  min-height:44px;padding:0 14px 0 11px;
  border-radius:999px;
  background:var(--surface);border:1px solid var(--line);
  color:var(--ink-2);text-decoration:none;font-size:14px;font-weight:600;
  transition:background .12s ease,color .12s ease,border-color .12s ease
}
.back a:hover{background:var(--surface-2);border-color:var(--ink-3);color:var(--ink)}

/* Which slice of a list is on screen, as a row of chips. One is always on.

   A link rather than a button because it IS a different address - it can be
   bookmarked, reloaded and sent to somebody, which a button firing a script
   cannot. aria-current marks the one you are looking at; colour alone would
   leave anyone who cannot see it with three identical links. */
.chips{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 16px}
.chip{
  display:inline-flex;align-items:center;min-height:38px;padding:0 14px;
  border-radius:999px;border:1px solid var(--line);background:var(--surface);
  color:var(--ink-2);text-decoration:none;font-size:13px;font-weight:600;
  transition:background .12s ease,color .12s ease,border-color .12s ease
}
.chip:hover{background:var(--surface-2);color:var(--ink)}
.chip.on{background:var(--accent);border-color:var(--accent);color:#fff}
.chip.on:hover{background:var(--accent);color:#fff}

/* A row where the whole row opens the thing, not just the word that is a link.

   The link's ::after covers the row, so the target is the row - reported by the
   owner, whose complaint was having to hit a four-character order number on a
   phone. There is still ONE tab stop and one accessible name per row, which a
   link in every cell would not give, and the focus ring is drawn on the row so
   a keyboard user can see where they are.

   z-index on the pill keeps it above the overlay: it is not a link, but it must
   still be readable and selectable rather than buried under one. */
tr.opens{position:relative}
tr.opens:hover{background:var(--surface-2)}
tr.opens:focus-within{
  outline:2px solid var(--accent);outline-offset:-2px;background:var(--surface-2)
}
tr.opens a.stretch:focus-visible{outline:none}

/* An order's whole row in its status's colour (owner, 2026-09-23): green for
   completed, amber for refunded, red for cancelled or failed; anything still
   in between stays plain. Everything on the row must still read at 4.5:1 on
   the tint, in both themes - test-takings.php checks it:
   - the quiet grey text (the customer, the time, the phone labels) is too
     faint on a tint (3.3:1), so it goes one step darker here (7:1 and up);
   - the pills sit on the page colour, so they still read as pills;
   - hovering marks the edge instead of darkening the row, which would take
     the order number under 4.5:1 on red. */
tr.opens.tone-ok{background:var(--good-soft)}
tr.opens.tone-wait{background:var(--warn-soft)}
tr.opens.tone-bad{background:var(--crit-soft)}
tr.opens.tone-ok:hover{box-shadow:inset 4px 0 0 var(--good-ink)}
tr.opens.tone-wait:hover{box-shadow:inset 4px 0 0 var(--warn)}
tr.opens.tone-bad:hover{box-shadow:inset 4px 0 0 var(--crit)}
tr.opens[class*="tone-"] td .sub,
tr.opens[class*="tone-"] td[data-label]::before{color:var(--ink-2)}
tr.opens[class*="tone-"] .pill.status{background:var(--surface)}

/* The overlay is only painted once a script has confirmed the browser puts it
   where we think it goes.

   position:relative on a <tr> did not make the row a containing block before
   Safari 16. There, inset:0 escapes to the nearest ancestor that IS positioned,
   every row's overlay covers the whole table, and whichever paints last takes
   every click - so the orders list would open one order whatever you tapped.
   Rather than guess at versions, index.php measures one overlay against its row
   and sets .rows-stretch only if it matches; without it the order number stays
   the target, which is where this started.

   Phones never had the problem - table.stack makes the row display:block below
   640px - but they get the same measured answer. */
.rows-stretch tr.opens a.stretch::after{content:"";position:absolute;inset:0}

/* The badge sits above the overlay so it stays readable, but must not swallow
   the click: a row where everything opens the order except the one word an
   owner is most likely to aim at reads as a broken app. */
.rows-stretch tr.opens .pill{position:relative;z-index:1;pointer-events:none}

/* Two or three things you can do to whatever this screen is about, side by side
   on a wide screen and stacked on a phone. Stacked is the base: a phone is where
   an owner actually uses this. */
.doers{display:flex;flex-direction:column;gap:9px;margin:0 0 18px}
.doers .btn{text-align:center}

@media (min-width:640px){
  .doers{flex-direction:row;flex-wrap:wrap;align-items:center}
  .doers .btn{text-align:left}
}

/* The money on an order, laid out so the column adds up to the total the
   customer paid. Right-aligned figures, because a column of prices that does
   not line up is a column nobody checks.

   min-width:0 is not tidiness. Every other table here is a grid of columns that
   needs 640px to be readable, and `table` sets that minimum globally - which on
   a 375px phone pushed this table's right-hand column, the figures, clean off
   the screen. Two words and a number does not need 640px. */
/* No rule between one line of money and the next, only the dashed ones between
   sections - as on the printed docket (owner, 2026-09-24). The line under every
   cell elsewhere comes from the plain td rule. */
table.money{width:100%;min-width:0;border-collapse:collapse;font-size:14px}
table.money td{padding:6px 0;color:var(--ink-2);border-bottom:none}
table.money td:last-child{text-align:right;color:var(--ink);white-space:nowrap}
table.money tr.sum td{
  border-top:1px dashed var(--line);padding-top:10px;
  font-weight:700;color:var(--ink);font-size:15px
}
/* An order laid out like the docket that came off the printer (design, screen
   29): the number across the top, a line per dish, then - each after a dashed
   rule - the charges and total, how it was paid, and what has gone back.
   Quiet text on it is ink-2: the usual grey is 4.3:1 on a white card. */
.docket{border:1px solid var(--line);border-radius:12px;overflow:hidden;background:var(--surface)}
.docket .dh{
  display:flex;align-items:center;justify-content:space-between;gap:8px;
  padding:10px 14px;background:var(--surface-2);border-bottom:1px solid var(--line)
}
.docket .dh .no{font-size:14px;font-weight:700;color:var(--ink)}
.docket .dh .count{font-size:13px;color:var(--ink-2)}
.docket .db{padding:8px 14px 14px}
.docket .li{display:flex;align-items:baseline;gap:10px;padding:6px 0;font-size:14.5px}
.docket .li .q{flex:none;min-width:30px;text-align:right;color:var(--ink-2);font-weight:600}
.docket .li .n{flex:1;min-width:0;overflow-wrap:anywhere;font-weight:600;color:var(--ink)}
.docket .li .p{flex:none;white-space:nowrap;color:var(--ink)}
/* What was chosen on a dish, under its name, as the printed docket has it. */
.docket .adds{list-style:none;margin:2px 0 0;padding:0;font-size:13px;font-weight:400;line-height:1.45;color:var(--ink-2)}
.docket .adds .k{font-weight:600}
.docket .note{margin:8px 0 2px;padding:9px 11px;border-radius:8px;background:var(--surface-2);font-size:13.5px;color:var(--ink)}
.docket table.money{margin-top:10px;border-top:1px dashed var(--line)}
.docket table.money tr:first-child td{padding-top:10px}

/* Under the total: refunds in the "refunded" amber (6:1 and up), and a
   refund's reason in ink-2 - too faint in the usual grey at 12.5px. */
table.money-more{margin-top:12px;border-top:1px dashed var(--line)}
table.money-more tr:first-child td{padding-top:12px}
table.money-more td{vertical-align:top}
table.money-more td.out{color:var(--warn)}
table.money-more .why{display:block;font-size:12.5px;color:var(--ink-2);margin-top:1px}

/* The add-on form's type-specific blocks.
 *
 * They are VISIBLE by default and hidden by script, never the other way round:
 * a field that only appears when JavaScript runs is a field an owner on a bad
 * connection cannot fill in. The line saying which kind a block belongs to is
 * the opposite - only useful when the blocks are all on screen at once, so the
 * script hides it as its first act. */
.only-says{display:block;margin-top:2px;font-style:italic}
.js-on .only-says{display:none}

/* A control that only exists because a script might not run, such as the
   arrows that order a list nobody can drag without one. */
.js-on .no-js-do{display:none}

/* And the mirror of it: a control that only WORKS once a script runs, such as
   kitchen time's - and + (its number can be typed without one). Off by
   default, so a browser that never runs one is not offered a dead button. */
.with-js{display:none}
.js-on .with-js{display:inline}

/* "Add another" under a list of sizes, add-on choices or postcodes.

   It was a small ghost button sitting inline, so the hint that follows ran
   straight on from it on the same line - "+ Add another size Clear a row to
   drop that size..." - and read as one broken sentence. Reported by the owner.

   Now it takes its own full-width line, the way an "add a row" control
   normally does: a dashed outline says "this adds to the list above" without
   competing with Save, and the hint drops to the line below where it belongs.
   44px tall because it is pressed with a thumb. */
.add-row{
  display:flex;align-items:center;justify-content:center;gap:6px;
  width:100%;min-height:44px;margin:2px 0 10px;padding:0 14px;
  border:1.5px dashed var(--line);border-radius:10px;
  background:transparent;color:var(--accent);
  font:inherit;font-size:14px;font-weight:600;cursor:pointer;
  transition:background .12s ease,border-color .12s ease
}
.add-row:hover{background:var(--surface-2);border-color:var(--accent)}
.add-row:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* The hint under it matches every other hint on these screens. It sat outside a
   .field, so it never picked up `.field .hint` and rendered at full body size -
   hidden while it ran on beside the button, obvious once it had its own line. */
.add-row + .hint{display:block;font-size:12px;color:var(--ink-3);line-height:1.45}

/* The empty row under a list that already has items.

   The owner reported it: a dish with three sizes showed a fourth, blank one,
   which looks like something is missing. With a script running it is hidden,
   and "Add another" is how a row is added.

   It stays in the page rather than being dropped, because without a script
   that button does nothing - and this empty row is then the only way to add a
   size at all. A list with nothing in it yet still shows its box, because
   there is nothing else to type into.

   !important because these rows carry an inline display:flex, which beats any
   ordinary rule; without it the row stayed on screen. */
/* Taking one size or one add-on choice off the list.

   Red from the start. It was grey on a white row - the same colour as what it
   sat on, so the thing an owner was looking for was the thing hardest to see,
   and it only admitted what it did once the pointer was already on it. A
   pointer is not how you FIND a button. Reported 2026-09-20.

   40px so it is a thumb target. Filled on hover, outlined the rest of the
   time, so the row still reads as a name and a price rather than a row of
   alarms. */
.row-remove{
  flex:none;width:40px;min-height:40px;padding:0;
  border:1px solid var(--crit);border-radius:9px;
  background:var(--crit-soft);color:var(--crit);
  font:inherit;font-size:17px;line-height:1;cursor:pointer;
  transition:color .12s ease,border-color .12s ease,background .12s ease
}
.row-remove:hover{background:var(--crit);color:var(--surface);border-color:var(--crit)}
.row-remove:focus-visible{outline:2px solid var(--accent);outline-offset:1px}

/* A shared group's choices cannot be edited from a dish, so its button is
   disabled - and a disabled button that is still bright red looks like the one
   thing on the screen worth pressing. */
.row-remove[disabled]{
  border-color:var(--line);background:var(--surface);
  color:var(--ink-3);cursor:not-allowed
}

.js-on .postcode-row.spare,
.js-on .size-row.spare,
.js-on .choice-row.spare{display:none !important}

/* One box per postcode. Upper case because postcodes are, and seeing "ca3"
   turn into "CA3" as you type is the screen agreeing with you rather than
   correcting you after you press save. */
input.pc{text-transform:uppercase}
input.pc::placeholder{text-transform:none}

/* The notice editor. A page you type on, with a bar of things you can do to it,
   instead of a box of tags - the owner is writing a sentence for their menu,
   not markup. */
.editor{border:1px solid var(--line);border-radius:9px;background:var(--surface);overflow:hidden}
.editor-bar{
  display:flex;flex-wrap:wrap;align-items:center;gap:6px;
  padding:7px 8px;border-bottom:1px solid var(--line-soft);background:var(--surface-2)
}
.editor-bar .ed{
  min-width:34px;height:34px;padding:0 9px;
  border:1px solid var(--line);border-radius:7px;background:var(--surface);
  color:var(--ink);font:inherit;font-size:13px;line-height:1;cursor:pointer
}
.editor-bar .ed:hover{background:var(--surface-2)}
.editor-bar .ed:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.editor-bar .ed.ink{width:28px;min-width:28px;height:28px;padding:0;border-radius:999px;border-color:rgba(0,0,0,.18)}
.editor-bar .ed-sep{width:1px;height:22px;background:var(--line)}
/* The notice as the menu shows it (owner, 2026-09-26): the theme's white card,
   centred, in its #2c2c2c at 16px - in the Hub's light and dark themes alike,
   because the menu does not change with them. A colour set in wp-admin comes
   in as an inline background (shop-settings.php). */
.editor-page{
  min-height:96px;padding:20px 25px;font-size:16px;color:#2c2c2c;background:#fff;
  line-height:1.6;text-align:center;outline:none
}
.editor-page:focus{box-shadow:inset 0 0 0 2px var(--accent)}

.wrap{max-width:960px;margin:0 auto;padding:28px 20px 64px}
.narrow{max-width:420px}

h1{font-size:26px;letter-spacing:-.02em;margin:0 0 6px}
h2{font-size:18px;letter-spacing:-.01em;margin:30px 0 10px}
.lede{color:var(--ink-2);margin:0 0 22px;font-size:15px}
/* Read aloud, not shown: a heading a screen reader lists, or a word that makes
   a badge a sentence ("Wanted: For 19:30"). */
.vh{
  position:absolute !important;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0
}

/* THE TOP OF ONE ORDER (owner, 2026-09-23 and -24): its number, then in a row
   of badges what the kitchen asks first - collection or delivery, where it
   stands, when they want it. */
.order-head{margin-bottom:18px}
.order-head h1{margin-bottom:8px}
.order-head .order-meta{margin-bottom:0}
.order-tags{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:0 0 10px}
/* Collection or delivery in the accent colour - 4.9:1 in light, 5.5:1 in dark.
   The status beside it is in its pill's colours, which test-takings.php holds
   to 4.5:1 in both themes. */
.fulfil-badge,.status-badge,.when-badge{
  display:inline-flex;align-items:center;gap:7px;
  padding:6px 13px 6px 10px;border-radius:999px;
  font-size:14px;font-weight:700;letter-spacing:.02em;line-height:1.3
}
.fulfil-badge svg,.when-badge svg{flex:none}
.fulfil-badge{background:var(--accent-soft);color:var(--accent)}
.status-badge{padding-left:13px}
.status-badge.ok{background:var(--good-soft);color:var(--good-ink)}
.status-badge.wait{background:var(--warn-soft);color:var(--warn)}
.status-badge.bad{background:var(--crit-soft);color:var(--crit)}
.status-badge.off{background:var(--surface-2);color:var(--ink-2)}
.when-badge{background:var(--surface);color:var(--ink);border:1px solid var(--line);font-weight:600}
/* Who ordered and when: the name carries the line, the time sits after it. */
.order-meta{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px}
.order-meta strong{color:var(--ink);font-weight:650}
.order-meta .dot{color:var(--ink-3)}

/* TWO COLUMNS ON A WIDE SCREEN, ONE ON A PHONE (owner, 2026-09-24).
   Shopify's order screen: the order and its history in the main column, the
   customer, the payment and the refund in a narrower one beside it - where the
   docket alone ran 920px across. On a phone the two columns step aside
   (display:contents) so every card is in one list, and what happened moves to
   the end of it: the customer and the refund are what a phone is used for. */
.order-grid{display:flex;flex-direction:column;gap:14px}
.order-main,.order-side{display:contents}
.order-grid .timeline{order:1}
.order-grid .card{margin-bottom:0}
@media (min-width:760px){
  .order-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(260px,320px);gap:16px;align-items:start}
  .order-main,.order-side{display:flex;flex-direction:column;gap:16px;min-width:0}
}
.card-h{font-size:15px;letter-spacing:0;margin:0 0 10px}
.order-grid .cust-name{margin:0 0 4px;font-size:15px;font-weight:650;color:var(--ink)}
.order-grid .cust-line{display:flex;align-items:flex-start;gap:8px;margin:6px 0 0;color:var(--ink);overflow-wrap:anywhere}
.order-grid .cust-line svg{flex:none;margin-top:3px;color:var(--ink-2)}
.order-grid .cust-line a{font-weight:600}
.order-grid table.money.paid-by td{padding-top:0}
/* A card provider's name can be long, and the column is narrow: let it wrap. */
.order-grid table.money.paid-by td:last-child{white-space:normal;overflow-wrap:anywhere;padding-left:12px}
.order-grid .refund .msg:last-child{margin-bottom:0}

/* What happened to an order, oldest first, down a line of dots in the status
   colours. The dots are only decoration: the words say it all. */
.events{list-style:none;margin:0;padding:0}
.events .ev{position:relative;padding:0 0 14px 22px}
.events .ev:last-child{padding-bottom:0}
.events .ev::before{
  content:"";position:absolute;left:3px;top:6px;width:10px;height:10px;
  border-radius:50%;background:var(--ink-3)
}
.events .ev::after{content:"";position:absolute;left:7.5px;top:20px;bottom:2px;width:1px;background:var(--line)}
.events .ev:last-child::after{display:none}
.events .ev.tone-ok::before{background:var(--good)}
.events .ev.tone-wait::before{background:var(--warn)}
.events .ev.tone-bad::before{background:var(--crit)}
.events .what{display:block;font-size:14px;font-weight:600;color:var(--ink)}
.events .when{display:block;font-size:12.5px;color:var(--ink-2)}
.events .why{display:block;font-size:13px;color:var(--ink-2);margin-top:2px}

/* What is wrong with a figure, said under its box as it is typed. */
.field-error{font-size:13px;font-weight:600;color:var(--crit)}
.field-error:empty{display:none}
/* The box a refused form came back over (owner, 2026-09-24). */
input[aria-invalid="true"],textarea[aria-invalid="true"]{border-color:var(--crit)}
/* A form on its way: see /assets/unsaved.js. */
.btn[aria-disabled="true"]{opacity:.75;cursor:progress}
.field input[aria-invalid="true"]{border-color:var(--crit);box-shadow:0 0 0 1px var(--crit)}

.card{
  background:var(--surface);border:1px solid var(--line);border-radius:11px;
  padding:16px;margin-bottom:14px
}
.card h3{margin:0 0 4px;font-size:16px}
.card p{margin:0;color:var(--ink-2);font-size:14px}

.field{display:flex;flex-direction:column;gap:5px;margin-bottom:14px}
.field label{font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3)}
.field input,.field select{
  border:1px solid var(--line);border-radius:9px;padding:10px 12px;font-size:15px;
  background:var(--surface);color:var(--ink);font-family:inherit;width:100%
}
.field .hint{font-size:12px;color:var(--ink-3)}
/* A hint straight in a card, under the boxes rather than one of them: the
   limits on a shared add-on, and its options when there is no Add option
   button to follow. They rendered at 16px beside the 12px hints around them
   (found 2026-09-26). */
.card > .hint{display:block;font-size:12px;color:var(--ink-3);line-height:1.45}
/* A text box in a field, like the boxes beside it. The review text box had
   only the browser's own - white, in a typewriter font (owner, 2026-09-26);
   the others each carry the same style inline. */
.field textarea{
  border:1px solid var(--line);border-radius:9px;padding:10px 12px;font:inherit;font-size:14px;
  background:var(--surface);color:var(--ink);width:100%
}
/* What changed: one compact line a change (owner, 2026-09-26) - the change in
   bold, its value under it, who and when in small print. Support's changes
   keep the accent at the edge. */
.history{list-style:none;margin:0;padding:0;border:1px solid var(--line);border-radius:11px;background:var(--surface);overflow:hidden}
.history li{padding:10px 13px;border-top:1px solid var(--line-soft)}
.history li:first-child{border-top:none}
.history li.by-us{box-shadow:inset 3px 0 0 var(--accent)}
.history .what{display:block;font-size:14px;font-weight:600;line-height:1.35;overflow-wrap:anywhere}
.history .now{display:block;font-size:12.5px;color:var(--ink-2);margin-top:2px;overflow-wrap:anywhere}
.history .who{display:block;font-size:12px;color:var(--ink-3);margin-top:3px}
.history .who .us{color:var(--accent)}
/* A home page row taken off on the screen, waiting for Save (home-form.js). */
.home-row.is-gone{border-style:dashed}
.home-row-gone{display:flex;align-items:center;flex-wrap:wrap;gap:10px}
.home-row-gone[hidden]{display:none}

.btn{
  border:none;border-radius:9px;padding:11px 16px;font-size:14px;font-weight:700;
  background:var(--accent);color:var(--accent-ink);cursor:pointer;font-family:inherit;
  text-decoration:none;display:inline-block;text-align:center
}
.btn.ghost{background:var(--surface);color:var(--ink);border:1px solid var(--line)}
/* A second action on a row, quieter than Save: "Add to dishes" on each shared
   add-on in the list (owner, 2026-09-24). */
.btn.soft{background:var(--accent-soft);color:var(--accent);border:1px solid var(--accent)}
.btn.soft:hover{background:var(--accent);color:var(--accent-ink)}
/* What a screen is for, in a box of its own above the form: on a shared
   add-on, how many dishes it is on and "Add to dishes" (owner, 2026-09-24:
   "it should show its importance and should have its own styling"). */
.next-step{
  display:flex;align-items:center;flex-wrap:wrap;gap:12px 16px;
  padding:14px 16px;margin:0 0 16px;border-radius:12px;
  background:var(--accent-soft);border:1px solid var(--accent)
}
.next-step .grow{flex:1 1 220px;min-width:0}
.next-step b{display:block;font-size:15px;color:var(--ink)}
.next-step .s{display:block;margin-top:2px;font-size:13px;color:var(--ink-2)}
.next-step .btn{flex:0 0 auto}
@media (max-width:520px){.next-step .btn{flex:1 1 100%}}
.btn.danger{background:var(--crit);color:#fff}
.btn.wide{width:100%}
.btn.sm{padding:7px 11px;font-size:13px}
.row-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}

.msg{border-radius:10px;padding:11px 13px;font-size:14px;margin-bottom:18px}
.msg.ok{background:var(--good-soft);color:var(--good)}
.msg.warn{background:var(--warn-soft);color:var(--warn)}
.msg.bad{background:var(--crit-soft);color:var(--crit)}

.pill{
  font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
  padding:3px 9px;border-radius:999px;white-space:nowrap;display:inline-block
}
.pill.ok{background:var(--good-soft);color:var(--good)}
.pill.bad{background:var(--crit-soft);color:var(--crit)}
.pill.wait{background:var(--warn-soft);color:var(--warn)}
.pill.off{background:var(--surface-2);color:var(--ink-3)}
/* An order's status is read at a glance, at 11px: at least 4.5:1 in both
   themes. The shared green (4.46:1) and grey (3.66:1) fall short in light,
   so these two get stronger text here only, not on every pill in the Hub. */
.pill.status.ok{color:var(--good-ink)}
.pill.status.off{color:var(--ink-2)}

.tablewrap{overflow-x:auto;border:1px solid var(--line);border-radius:11px;background:var(--surface)}
table{border-collapse:collapse;width:100%;min-width:640px;font-size:14px}
th{
  text-align:left;font-size:11px;letter-spacing:.07em;text-transform:uppercase;
  color:var(--ink-3);font-weight:700;padding:11px 13px;background:var(--surface-2);
  border-bottom:1px solid var(--line);white-space:nowrap
}
td{padding:12px 13px;border-bottom:1px solid var(--line-soft);vertical-align:middle}
tbody tr:last-child td{border-bottom:none}
td .sub{display:block;color:var(--ink-3);font-size:12.5px;margin-top:2px}
a.pill{text-decoration:none}
td.versions .v{display:block;white-space:nowrap}
td.versions .v + .v{color:var(--ink-2)}

/* The health check on a restaurant's page, one line per check (2026-09-27). */
.health-list{list-style:none;margin:12px 0 0;padding:0;display:flex;flex-direction:column;gap:10px}
.health-list li{display:flex;gap:10px;align-items:flex-start;font-size:14px}
.health-list .pill{flex:0 0 76px;text-align:center}
.health-list .says{display:block;color:var(--ink-2)}
.health-list .sub{display:block;color:var(--ink-3);font-size:12.5px;margin-top:2px;overflow-wrap:anywhere}

/* ============================================================
   The app furniture from the design board.
   ============================================================ */

/* The state of the shop, as the first thing on the screen. Colour carries the
   meaning here, so the words say it too - nobody should have to know that green
   means open. */
.hero{
  border-radius:11px;padding:15px;margin-bottom:14px;
  display:flex;flex-direction:column;gap:3px;
  background:var(--good-soft);border:1px solid transparent
}
.hero.shut{background:var(--crit-soft)}
.hero.unknown{background:var(--surface-2)}
/* "TAKING ORDERS" is 10.5px: the shared green is 4.46:1 on its tint, the
   status pills' darker one 5.11:1. */
.hero .lbl{
  font-size:10.5px;letter-spacing:.11em;text-transform:uppercase;
  font-weight:700;color:var(--good-ink)
}
.hero.shut .lbl{color:var(--crit)}
.hero.unknown .lbl{color:var(--ink-3)}
.hero strong{font-size:21px;letter-spacing:-.015em;line-height:1.2}
.hero span:last-child{font-size:13px;color:var(--ink-2)}
/* When the website last checked in, as a line under the status rather than a
   card of its own at the foot of Today (owner, 2026-09-24). A small capsule
   with a dot, not loose grey text (owner, 2026-10-07: "has no styling") -
   green when it is in touch, grey before it ever has been. Only shown when
   the website answered: when it did not, the warning above says so. */
.checked-in{
  display:flex;align-items:center;gap:7px;width:fit-content;
  margin:-4px 0 14px;padding:4px 11px 4px 9px;
  font-size:12.5px;color:var(--ink-2);
  background:var(--surface-2);border:1px solid var(--line-soft);border-radius:999px
}
.checked-in::before{
  content:"";flex:none;width:7px;height:7px;border-radius:50%;
  background:var(--good);box-shadow:0 0 0 3px var(--good-soft)
}
.checked-in.none::before{background:var(--ink-3);box-shadow:none}
/* The same capsule says when the knock last ran, on Restaurants: amber when
   it is late (owner, 2026-10-07). */
.checked-in.late::before{background:var(--warn);box-shadow:0 0 0 3px var(--warn-soft)}
#knock{margin:0 0 14px}

/* A dish off the menu is a link to it, where its switch is. Underlined, in
   the box's own colour, so it reads as a link without leaving the warning. */
.msg.off-menu a{color:inherit;font-weight:600;text-decoration:underline;text-underline-offset:2px}

.stat-row{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:14px}
.stat{
  background:var(--surface-2);border-radius:10px;padding:12px 13px;
  display:flex;flex-direction:column;gap:1px
}
.stat b{font-size:24px;line-height:1.1;letter-spacing:-.02em}
.stat span{font-size:11.5px;color:var(--ink-3);font-weight:600}
/* Today's two figures open today's orders (owner, 2026-09-24). */
a.stat{color:var(--ink);text-decoration:none;border:1px solid transparent;transition:border-color .12s ease}
a.stat:hover{border-color:var(--accent)}

/* Written twice so it wins inside a card too: `.card p` is the stronger rule,
   and a <p class="sechead"> in a card came out 14px and bright - the sizes
   heading on Add a dish, "How is this priced?" on a dish (owner, 2026-09-24). */
.sechead,.card .sechead{
  font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--ink-3);font-weight:700;margin:20px 0 8px
}

/* A row that goes somewhere. Big enough to hit with a thumb. */
a.row,.row{
  display:flex;align-items:center;gap:11px;padding:13px;margin-bottom:8px;
  background:var(--surface);border:1px solid var(--line);border-radius:10px;
  text-decoration:none;color:var(--ink)
}
a.row:hover{border-color:var(--accent)}
.row .grow{flex:1;min-width:0;display:flex;flex-direction:column}
.row .t{font-size:14px;font-weight:600;line-height:1.3}
.row .s{font-size:12px;color:var(--ink-3);margin-top:2px;line-height:1.35}
.row .chev{color:var(--ink-3);font-size:18px;line-height:1}

/* Kitchen time. A stepper beside the box: it is changed with one thumb, in a
   hurry, and five minutes is always the right step. */
.numrow{
  display:flex;align-items:center;gap:11px;padding:10px 13px;
  background:var(--surface);border:1px solid var(--line);border-radius:10px
}
.numrow .nlbl{flex:1;min-width:0}
.numrow .nlbl b{display:block;font-size:13.5px;font-weight:600;line-height:1.3}
.numrow .nlbl span{display:block;font-size:12px;color:var(--ink-3);margin-top:1px}
.numrow .ctl{display:flex;align-items:center;gap:4px;flex:none;margin:0}
.numrow .ctl button{
  width:34px;height:34px;border:1px solid var(--line);background:var(--surface);
  border-radius:8px;font-size:17px;font-weight:700;color:var(--ink);cursor:pointer;
  line-height:1;padding:0;font-family:inherit
}
.numrow .ctl button:hover:not(:disabled){border-color:var(--accent);color:var(--accent)}
.numrow .ctl button:disabled{opacity:.3;cursor:not-allowed}
.numrow .val{
  width:58px;height:34px;text-align:center;font-weight:700;font-size:15px;
  font-family:ui-monospace,Menlo,Consolas,monospace;font-variant-numeric:tabular-nums;
  border:1px solid var(--line);border-radius:8px;background:var(--surface);color:var(--ink);padding:0 4px
}

.btn.danger{background:var(--crit);color:#fff}
.btn.danger:hover{filter:brightness(1.08)}

/* ------------------------------------------------------------------ switch
 *
 * The control from the design board, and the one an owner uses most. Green and
 * to the right is on; grey and to the left is off.
 *
 * A check box, input.sw, inside a form and saved with everything else when the
 * owner presses Save. There was a second shape, a button that saved the moment
 * it was pressed; nothing in the Hub saves itself now (owner, 2026-10-05).
 *
 * 42x25 with a 20px knob, the sizes the design specified, wrapped in a 44px tap
 * target because that is the smallest thing a thumb hits reliably.
 */
.sw{
  width:42px;height:25px;border-radius:999px;background:var(--line);
  flex:none;position:relative;cursor:pointer;border:none;padding:0;margin:0;
  appearance:none;-webkit-appearance:none;
  transition:background .18s ease
}
.sw::after{
  content:"";position:absolute;top:2.5px;left:2.5px;width:20px;height:20px;
  border-radius:50%;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.3);
  transition:transform .18s ease
}
.sw:checked{background:var(--good)}
.sw:checked::after{transform:translateX(17px)}
.sw:hover{filter:brightness(1.06)}
.sw:disabled{opacity:.45;cursor:not-allowed}

/* The label beside a switch, and the tap target around the pair.
 *
 * The overrides below are not belt-and-braces. Inside a .field, `.field input`
 * sets width:100% and `.field label` sets 11px uppercase - both more specific
 * than a bare .sw - so without them the switch stretches the width of the
 * screen and its label shouts in small caps. */
.swrow,
.field > .swrow{
  display:flex;flex-direction:row;align-items:center;gap:10px;min-height:44px;
  cursor:pointer;margin:0;
  font-size:13.5px;font-weight:500;letter-spacing:0;text-transform:none;color:var(--ink)
}
.field .sw,
.swrow .sw{width:42px;min-width:42px;height:25px;flex:none}
.swrow .swtext{flex:1;min-width:0}
.swtext b{display:block;font-size:13.5px;font-weight:600;line-height:1.3;text-transform:none;letter-spacing:0;color:var(--ink)}
.swtext span{display:block;font-size:12px;color:var(--ink-3);margin-top:1px;text-transform:none;letter-spacing:0;font-weight:400}
.swstate{
  font-size:12px;font-weight:600;color:var(--ink-3);min-width:26px;text-align:left
}

/* Search. One box, no button - it filters as you type, so a button would only
   be something else to hit. */
.srch{
  display:flex;align-items:center;gap:9px;margin:14px 0 6px;
  border:1px solid var(--line);border-radius:10px;padding:10px 12px;background:var(--surface)
}
.srch:focus-within{border-color:var(--accent)}
.srch input{
  border:none;background:none;outline:none;flex:1;min-width:0;
  font-size:15px;font-family:inherit;color:var(--ink)
}
.srch input::placeholder{color:var(--ink-3)}
.srch .mag{color:var(--ink-3);font-size:15px}
#searchCount{margin:0 0 12px;font-size:12.5px;color:var(--ink-3)}

/* A menu category. <details> rather than a script, so it still collapses if the
   JavaScript never arrives. */
details.category{margin-bottom:12px}
details.category > summary{
  display:flex;align-items:center;gap:9px;cursor:pointer;list-style:none;
  padding:11px 13px;background:var(--surface-2);border:1px solid var(--line);
  border-radius:10px;font-weight:700;font-size:14px
}
details.category[open] > summary{border-radius:10px 10px 0 0;border-bottom:none}
details.category > summary::-webkit-details-marker{display:none}
details.category > summary::before{
  content:"\25B8";color:var(--ink-3);font-size:11px;transition:transform .15s ease
}
details.category[open] > summary::before{transform:rotate(90deg)}
details.category > summary:hover{border-color:var(--accent)}
details.category .secname{flex:1;min-width:0}
details.category .seccount{
  font-size:11px;font-weight:700;color:var(--ink-3);background:var(--surface);
  border:1px solid var(--line);border-radius:999px;padding:1px 8px
}
/* "1 of 9 on" - a category a shared add-on is on somewhere, found at a glance
   with every heading shut (owner, 2026-09-24). */
details.category .seccount.has{color:var(--accent);background:var(--accent-soft);border-color:var(--accent)}
details.category[open] .tablewrap{border-radius:0 0 10px 10px;border-top:none}

.pill.bad{background:var(--crit-soft);color:var(--crit)}

/* Phones.
 *
 * Every table here has a 640px minimum, which on a 375px phone put the Price
 * column at x=387 and the on/off switch at x=543 - both past the right edge,
 * reachable only by scrolling the table sideways, with nothing on screen to
 * suggest there was anything there. The menu is the one screen an owner opens
 * mid-service, on a phone, in a kitchen, so a hidden control is the same as no
 * control (7.5).
 *
 * Below 640px each row becomes its own block and each cell carries its column
 * heading, so nothing needs finding. */
@media (max-width:640px){
  table.stack{min-width:0;display:block}
  table.stack thead{display:none}
  table.stack tbody,table.stack tr,table.stack td{display:block;width:auto}
  table.stack tr{border-bottom:1px solid var(--line);padding:6px 0}
  table.stack tbody tr:last-child{border-bottom:none}
  table.stack td{border-bottom:none;padding:7px 13px}
  table.stack td[data-label]::before{
    content:attr(data-label);display:block;
    font-size:11px;letter-spacing:.07em;text-transform:uppercase;
    color:var(--ink-3);font-weight:700;margin-bottom:5px
  }
}

/* THE ORDER LIST (owner, 2026-09-24).
 *
 * On a wide screen a table, the name under the number and the badges under
 * that. On a phone an order was a card a third of the screen tall - every value
 * under a heading of its own - so two fitted on the screen. Now three short
 * lines, laid out on the row itself:
 *
 *   942  Abdullah Ergun               £18.40
 *   13 hours ago · 23 Sep, 22:27      Visa ending in 4242
 *   COLLECTION  COMPLETED  REFUNDED £2.00
 *
 * The order cell steps aside (display:contents) so its two halves - who, and
 * the badges - can sit on different lines. The row keeps position:relative, so
 * the link still covers all of it. */
table.orders .o-id{display:block}
table.orders .o-tags{display:flex;flex-wrap:wrap;gap:5px;margin-top:5px}
.pill.fulfil{background:var(--accent-soft);color:var(--accent)}
/* The search's one line of help, in the size the Hub's other hints are. */
.find-hint{display:block;margin-top:9px;font-size:12.5px;color:var(--ink-3)}

@media (max-width:640px){
  table.orders tr.opens{
    display:grid;grid-template-columns:minmax(0,1fr) auto;
    gap:3px 12px;padding:11px 13px
  }
  table.orders td{padding:0}
  table.orders td[data-label]::before{content:none}
  table.orders td.o-order{display:contents}
  table.orders .o-id{grid-column:1;grid-row:1;min-width:0}
  table.orders tr.opens .o-id .who{display:inline;margin:0 0 0 6px;font-size:14px;color:var(--ink)}
  table.orders td.o-total{grid-column:2;grid-row:1;text-align:right;font-weight:650}
  table.orders td.o-when{grid-column:1;grid-row:2;min-width:0;font-size:12.5px;color:var(--ink-2)}
  table.orders td.o-when .sub{display:inline;margin:0;font-size:inherit;color:inherit}
  table.orders td.o-when .sub::before{content:"\00B7  "}
  table.orders td.o-paid{grid-column:2;grid-row:2;text-align:right;font-size:12.5px;color:var(--ink-2)}
  table.orders .o-tags{grid-column:1 / -1;grid-row:3;margin-top:4px}
}

.keybox{
  font-family:ui-monospace,Menlo,Consolas,monospace;font-size:13px;
  background:var(--surface-2);border:1px solid var(--line);border-radius:9px;
  padding:12px 13px;word-break:break-all;color:var(--ink-2);line-height:1.6
}

.empty{
  border:1px dashed var(--line);border-radius:11px;padding:26px;text-align:center;
  color:var(--ink-3);font-size:14px
}

/* One restaurant: its screens as a row of links under the two actions (owner,
   2026-09-26) - they were eight more buttons, the same as "Check it now". */
.site-screens{display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;margin-top:12px;font-size:14px}
.site-screens .lbl{color:var(--ink-3);font-size:13px;margin-right:4px}
.site-screens a{
  color:var(--accent);text-decoration:none;font-weight:600;
  padding:6px 8px;min-height:34px;display:inline-flex;align-items:center;border-radius:7px
}
.site-screens a:hover{background:var(--accent-soft)}
/* An owner's new password, set by an admin: a box like every other one, and
   in plain text, because it is read out to them (owner, 2026-09-26). */
.pw-set{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.pw-set input{
  border:1px solid var(--line);border-radius:8px;padding:7px 9px;font:inherit;font-size:13px;
  background:var(--surface);color:var(--ink);width:170px;max-width:100%
}
.pw-set .hint{flex-basis:100%;font-size:12px;color:var(--ink-3)}
/* A password box with "Show" inside its right edge (show-password.js). */
.pw-wrap{position:relative;display:block}
.field .pw-wrap input{padding-right:72px}
.pw-show{
  position:absolute;right:6px;top:50%;transform:translateY(-50%);
  min-height:34px;padding:0 11px;border-radius:7px;
  border:1px solid var(--line);background:var(--surface-2);color:var(--ink-2);
  font:inherit;font-size:13px;font-weight:600;cursor:pointer
}
.pw-show:hover{color:var(--ink);border-color:var(--accent)}
.pw-show[hidden]{display:none}
.signin{min-height:100vh;display:grid;place-items:center;padding:20px}
.signin .box{width:100%;max-width:380px}
.signin h1{text-align:center;margin-bottom:2px}
.signin .lede{text-align:center}

/* ------------------------------------------- drag-to-reorder, and a tag
 *
 * The grip is a big target on purpose: it is the only thing that starts a drag,
 * so the rest of the row stays an ordinary link you can tap to open. */
.drag{display:flex;flex-direction:column;gap:7px}
/* Only the grip keeps touch-action:none. The whole row had it, so on a phone a
   swipe that started on a row did not scroll the page - on a menu of 25
   categories, most of the screen (owner, 2026-09-24). A drag only ever starts on
   the grip (drag.js), and the browser decides about scrolling from where a
   touch begins, so that is the only place that needs to stop it. */
.drag .h{
  display:flex;align-items:center;gap:10px;padding:12px 13px;
  border:1px solid var(--line);border-radius:10px;background:var(--surface);
  font-size:14px;font-weight:600
}
.drag .h a{text-decoration:none;color:var(--ink);flex:1;min-width:0}
.drag .h a:hover{color:var(--accent)}
.drag .h .grip{
  color:var(--ink-3);font-size:15px;cursor:grab;padding:4px 6px;margin:-4px -2px;
  letter-spacing:1px;flex:none;touch-action:none
}
.drag .h .grip:active{cursor:grabbing}
.drag .h .n{font-size:12px;color:var(--ink-3);font-weight:500;flex:none}
/* How many dishes in a category are switched off, in the "refunded" amber
   (5.9:1 and up in both themes). */
.drag .h .n .off{color:var(--warn);font-weight:600}

/* THE MENU'S CATEGORIES (owner, 2026-09-24): the whole row opens the category,
   not only its name - "4 dishes ›" looked like a link and was not. The name's
   link covers the row; the grip, which is still the only thing that starts a
   drag, and the no-script arrows sit above it. */
.drag.categories .h{position:relative}
.drag.categories .h > a::after{content:"";position:absolute;inset:0;border-radius:10px}
.drag.categories .h .grip,.drag.categories .h .arrows{position:relative;z-index:1}
.drag.categories .h:hover{border-color:var(--accent)}
/* The line under an area another area takes customers from (owner, 2026-09-25). */
a.row .s.taken{display:block;margin-top:3px;color:var(--warn)}

/* Check a postcode, at the top of the delivery areas (owner, 2026-09-24): the
   box and its button on one line, the answer under it. */
.postcode-check{margin:0 0 14px}
.postcode-check-row{display:flex;gap:8px}
.postcode-check-row input{flex:1;min-width:0}
.postcode-check-row .btn{flex:0 0 auto}

/* OPENING HOURS, ONE TIDY BLOCK PER DAY (owner, 2026-09-24). The day and what
   it means on one line, the two times side by side under it, and the switch
   after them - at the end of the row where it fits, under it on a phone. */
.hours-day{margin-bottom:10px}
.hours-day.is-today{border-color:var(--accent)}
.hours-day.has-problem{border-color:var(--crit)}
.hours-head{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 8px;margin-bottom:10px}
.hours-head .sub{flex-basis:100%;margin:0}
.hours-row{display:flex;flex-wrap:wrap;align-items:flex-end;gap:10px 16px}
.hours-times{display:flex;align-items:flex-end;gap:8px}
.hours-times .field{margin:0}
.hours-times input{width:120px}
.hours-dash{padding-bottom:11px;color:var(--ink-3)}
.hours-shut{margin-left:auto;white-space:nowrap}
.hours-shut span{font-size:13px;color:var(--ink-2);font-weight:500}
/* Closed all day: the times are kept but greyed, and cannot be typed into. */
.hours-day.is-closed .hours-times{opacity:.45}
/* Up to five openings a day (Foodie 1.3.0): one row each, stacked. */
.hours-openings{display:flex;flex-direction:column;gap:8px}
.hours-openings .hours-times .field label{font-size:12px}
.hours-more{align-self:flex-start}
@media (max-width:520px){.hours-shut{margin-left:0}}

/* A shared add-on's row opens it the same way; "Add to dishes" sits above
   the link (owner, 2026-09-24). */
.row.shared-row{position:relative}
.row.shared-row .grow > a::after{content:"";position:absolute;inset:0;border-radius:10px}
.row.shared-row .btn{position:relative;z-index:1}
.row.shared-row:hover{border-color:var(--accent)}
.drag-hint{margin:0 0 10px;font-size:12.5px;color:var(--ink-3)}

/* Which categories a dish goes under: a tick each, the ticked ones in the accent
   tint. Not the uppercase .field label - these are choices, not a heading. */
fieldset.category-pick{border:0;padding:0;min-width:0}
.category-pick legend{
  padding:0;margin-bottom:6px;font-size:11px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-3)
}
.category-pick .pick{
  display:flex;align-items:center;gap:10px;padding:10px 12px;margin:0;
  border:1px solid var(--line);border-radius:9px;background:var(--surface);cursor:pointer;
  font-size:14px;font-weight:500;letter-spacing:0;text-transform:none;color:var(--ink)
}
.category-pick .pick:has(input:checked){border-color:var(--accent);background:var(--accent-soft)}
.category-pick .pick input{width:18px;height:18px;margin:0;flex:none;accent-color:var(--accent)}
/* The categories as a dropdown (owner, 2026-09-24): a box that says what is
   picked, opening onto the ticks - a tick each was a screen and a half on a
   menu of twenty. Without a script the box is never shown and the ticks are
   simply listed. */
.category-pick .pick-toggle{
  display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:10px 12px;
  border:1px solid var(--line);border-radius:9px;background:var(--surface);color:var(--ink);
  font:inherit;font-size:15px;text-align:left;cursor:pointer
}
.category-pick .pick-toggle[aria-expanded="true"]{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent)}
.category-pick .pick-said{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Not .empty - that is the Hub's dashed "nothing here" panel, and it took this over. */
.category-pick .pick-said.unpicked{color:var(--ink-3)}
.category-pick .pick-caret{display:inline-block;flex:none;color:var(--ink-2);font-size:12px;transition:transform .15s ease}
.category-pick .pick-toggle[aria-expanded="true"] .pick-caret{transform:rotate(180deg)}
.category-pick .pick-options{display:flex;flex-direction:column;gap:6px}
.js-on .category-pick .pick-panel{margin-top:2px;padding:8px;border:1px solid var(--line);border-radius:9px;background:var(--surface-2)}
.js-on .category-pick .pick-options{max-height:264px;overflow-y:auto}
.category-pick .pick-find{margin-bottom:8px}
.category-pick .pick-nothing{margin:6px 2px 0;font-size:13px;color:var(--ink-2)}

/* A dish inside a category: the same draggable row as a category on the menu
   screen, but carrying two more things - what it costs, and the switch that
   takes it off the menu. */
.drag .h.dish{align-items:center;gap:9px}

/* THE WHOLE ROW OPENS THE DISH (owner, 2026-09-24), as a category's row does on
   the menu screen - the name was a strip 22px tall in a row six times that.
   The grip, the no-script arrows and the switch sit above the row's link, so
   each is still its own thing to press. */
.drag.dishes .h{position:relative}
.drag.dishes .h > a.what::after{content:"";position:absolute;inset:0;border-radius:10px}
.drag.dishes .h .grip,.drag.dishes .h .arrows,.drag.dishes .h .onoff{position:relative;z-index:1}
.drag.dishes .h:hover{border-color:var(--accent)}

/* A dish that is off: the row greyed, where it had a red "Off the menu" badge
   beside a switch that already said Off. Its name and price in the quiet grey,
   which is 4.7:1 on this grey in both themes - fading with opacity would have
   taken them under what small text needs. */
.drag .h.dish[data-off]{background:var(--surface-2)}
.drag .h.dish[data-off] .what .t,.drag .h.dish[data-off] .cost{color:var(--ink-3)}
.foot-link{margin-top:22px}
/* A DISH'S SAVE BUTTON STAYS IN REACH (owner, 2026-09-24): stuck to the foot of
   the screen while its form is on it - on a phone it was 990px down, below
   everything it saves - with "Not saved yet" beside it once something changes.
   The bar is the page colour, so the form scrolls under it cleanly. */
.save-bar{
  position:sticky;bottom:0;z-index:5;display:flex;align-items:center;gap:12px;
  margin:0 -4px;padding:10px 4px 12px;background:var(--paper)
}
.save-note{font-size:13px;font-weight:600;color:var(--warn)}
/* The dish's photo on the row that opens it. */
.row-thumb{width:44px;height:44px;flex:none;border-radius:8px;object-fit:cover;background:var(--surface-2)}
/* A description box that grows with its text (dish-form.js) needs no handle. */
textarea.grow{resize:none;overflow:hidden;min-height:78px}
.drag .h.dish .what{display:block;min-width:0}
.drag .h.dish .what .t{display:flex;align-items:center;gap:7px;flex-wrap:wrap}

/* The price is a column, the way it was in the table this list replaced: its
   own box, right-aligned, one font, so a menu of twenty dishes is a column of
   figures somebody can run their eye down. Folded into a line under the name it
   was none of those things. */
.drag .h.dish .cost{
  flex:none;text-align:right;min-width:74px;
  font-size:14px;font-weight:600;color:var(--ink)
}
.drag .h.dish .cost .per{font-size:12px;font-weight:500;color:var(--ink-3)}

.drag .h.dish .onoff{flex:none;touch-action:auto}
.drag .h.dish .swrow{display:flex;align-items:center;gap:8px;margin:0}
.drag .h.dish .swstate{font-size:12px;color:var(--ink-3);font-weight:600}

/* The up and down arrows: the way to order a list when no script is running.
   Both lists that can be dragged carry them - categories on the menu screen and
   dishes inside a category - so the rule is written once for `.drag .h` rather
   than twice.

   .no-js-do takes them away the moment a script runs, so a working browser sees
   the row as it has always looked.

   The hiding is spelled out rather than left to `.js-on .no-js-do`, which the
   layout rule below out-specifies: three classes beat two, so the arrows stayed
   on screen beside a working drag handle. Caught in the browser, not in the
   stylesheet. */
.drag .h .arrows{display:flex;flex-direction:column;gap:2px;flex:none}
.js-on .drag .h .arrows{display:none}
.drag .h .arrow{
  width:30px;height:22px;padding:0;line-height:1;font-size:10px;
  border:1px solid var(--line);border-radius:6px;
  background:var(--surface);color:var(--ink-2);cursor:pointer
}
.drag .h .arrow:hover:not(:disabled){background:var(--surface-2);color:var(--ink)}
.drag .h .arrow:disabled{opacity:.35;cursor:default}

@media (max-width:520px){
  /* Narrow: one line still - grip, name, price, switch (owner, 2026-09-24).
     This used to wrap the price onto a line of its own and the switch onto a
     third, 133px a dish, so nine dishes were four screens. A long name wraps
     inside its own column instead. The switch's "On"/"Off" word goes: the
     switch and the greyed row both say it, and the room goes to the name. */
  .drag .h.dish{gap:8px;padding:10px 11px}
  .drag .h.dish .what{flex:1 1 auto}
  .drag .h.dish .cost{min-width:0}
  .drag .h.dish .swstate{display:none}
}

.sect-tag{
  font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
  color:var(--ink-3);background:var(--surface-2);padding:2px 8px;border-radius:999px;
  display:inline-block;white-space:nowrap
}

/* A choice between two answers, as on "does it come in different types?".
   A label wrapping a radio, so the whole row is the target - not the 13px dot. */
.row.choice{cursor:pointer;align-items:flex-start}
.row.choice:hover{border-color:var(--accent)}
.row.choice input[type=radio]{margin-top:3px;flex:none;width:18px;height:18px;accent-color:var(--accent)}
.row.choice:has(input:checked){border-color:var(--accent);background:var(--accent-soft)}

/* Add-on types: the customer example is part of the type's clickable label. */
.row.choice.addon-kind{
  display:grid;grid-template-columns:18px minmax(0,1fr);gap:10px 12px;
  margin-bottom:10px;align-items:start
}
.addon-kind > .grow{min-width:0}
.addon-preview{
  display:block;grid-column:2;min-width:0;padding:11px 12px;
  border:1px solid var(--line);border-radius:8px;background:var(--surface);
  color:var(--ink);font-size:12px;line-height:1.4;pointer-events:none
}
.addon-preview-caption{display:block;color:var(--ink-3);font-size:10px;font-weight:600;margin-bottom:5px}
.addon-preview-title{display:block;font-weight:650;margin-bottom:8px;overflow-wrap:anywhere}
.addon-preview-options{display:grid;gap:7px}
.addon-preview-option{display:flex;align-items:center;gap:7px;min-width:0;flex-wrap:wrap}
.addon-preview-name{flex:1;min-width:40px;overflow-wrap:anywhere}
.addon-preview-price{font-size:11px;color:var(--ink-2);overflow-wrap:anywhere}
.addon-preview-mark{
  display:inline-block;width:13px;height:13px;flex:none;border:1px solid var(--ink-3);
  border-radius:50%;position:relative
}
.addon-preview-mark.is-selected{border-color:var(--accent)}
.addon-preview-mark.is-selected::after{
  content:"";position:absolute;inset:3px;border-radius:50%;background:var(--accent)
}
.addon-preview-mark.square{border-radius:3px}
.addon-preview-mark.square.is-selected{background:var(--accent)}
.addon-preview-mark.square.is-selected::after{
  inset:auto;left:3px;top:1px;width:4px;height:7px;background:none;border-radius:0;
  border:solid var(--accent-ink);border-width:0 1.5px 1.5px 0;transform:rotate(45deg)
}
.addon-preview-select{
  display:flex;justify-content:space-between;gap:8px;border:1px solid var(--accent);
  border-radius:5px;padding:6px 8px;color:var(--ink-2);
  box-shadow:0 0 0 2px var(--accent-soft)
}
.addon-preview[data-preview-kind="dropdown"] .addon-preview-options{gap:4px}
.addon-preview-menu{
  display:grid;min-width:0;padding:4px;border:1px solid var(--line);
  border-radius:5px;background:var(--surface);box-shadow:0 4px 12px rgba(15,23,42,.14)
}
.addon-preview-menu .addon-preview-option{padding:6px 8px;border-radius:3px}
.addon-preview-menu .addon-preview-option:first-child{background:var(--accent-soft)}
.addon-preview-counter{
  display:inline-flex;flex:none;align-items:center;border:1px solid var(--line);
  border-radius:5px;overflow:hidden;font-variant-numeric:tabular-nums
}
.addon-preview-counter span{min-width:21px;padding:3px;text-align:center}
.addon-preview-counter span:first-child,.addon-preview-counter span:last-child{background:var(--surface-2)}
.addon-preview-more{display:block;margin-top:7px;font-size:10px;color:var(--ink-3)}
.addon-limits{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin-bottom:8px}
.addon-limits .field{min-width:0;margin:0}
.addon-limits .field label{letter-spacing:0;text-transform:none;font-size:12px}
.addon-limits-quantity{grid-template-columns:1fr}
@media (min-width:560px){
  .addon-limits-quantity{grid-template-columns:repeat(3,minmax(0,1fr))}
}
@media (min-width:700px){
  .row.choice.addon-kind{grid-template-columns:18px minmax(180px,1fr) minmax(240px,1fr)}
  .addon-preview{grid-column:3;grid-row:1}
}
