/* Matches Olfactory Coffee Roasters' live theme: Montserrat (700) headings with
   wide tracking, Nunito Sans body, near-black text on a warm off-white background. */

/* The fonts are asked for in views/partials/head.ejs, not here. An @import
   can't begin until this file has arrived and been parsed, which put the
   fonts a whole round trip behind where they should be. */

:root {
  --ink: #1c1c1c;
  --paper: #fdfcfa;
  --paper-muted: #f3f1ec;
  --border: rgba(28, 28, 28, 0.15);
  --accent: #1c1c1c;
  --accent-text: #ffffff;
  --success-bg: #e8f3e2;
  --success-text: #2f5d1f;
  --warn-bg: #fdf1df;
  --warn-text: #8a5a12;
  --heading-font: 'Montserrat', sans-serif;
  --body-font: 'Nunito Sans', sans-serif;
}

* { box-sizing: border-box; }

/* Any rule that sets `display` outranks the browser's own [hidden] rule, so
   an element with both a display-setting class and the hidden attribute
   stays stubbornly visible. That's bitten this project twice; make `hidden`
   always win so toggling it is reliable wherever it's used. */
[hidden] { display: none !important; }

body {
  margin: 0;
  font-family: var(--body-font);
  font-size: 15px;
  letter-spacing: 0.02em;
  color: var(--ink);
  background: var(--paper);
  line-height: 1.6;
}

h1, h2, h3, h4 {
  font-family: var(--heading-font);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin: 0 0 0.6em;
  line-height: 1.3;
}

h1 { font-size: 1.6rem; }
h2 { font-size: 1.2rem; }
h3 { font-size: 1rem; }

a { color: var(--ink); }

.topbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.7rem 1rem;
  padding: 1.1rem 1.5rem;
  border-bottom: 1px solid var(--border);
  background: var(--paper);
}

.topbar .brand {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--heading-font);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-size: 0.95rem;
  text-decoration: none;
  color: var(--ink);
  white-space: nowrap;
}
/* The Olfactory logo in place of the written name (Angel, 1 Oct). */
.brand-logo { display: block; height: 18px; width: auto; }
.auth-logo { margin: 0 0 0.6rem; text-align: center; line-height: 0; }
.auth-logo img { display: inline-block; width: min(260px, 80%); height: auto; }

.topbar nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem 1.3rem;
}

.topbar nav a {
  text-decoration: none;
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
  opacity: 0.75;
  padding: 0.5rem 0.1rem;
}
.topbar nav a:hover { opacity: 1; }
.topbar nav form { margin: 0; }
/* The menu's icons (the office's gear; the customer's bell, trolley and
   person): each centred in a box as tall as the words beside it and big
   enough to tap. They stay one colour and show you're on them with a soft
   square behind, never by brightening - changing an icon's opacity on
   hover is what made them wiggle, as the browser redraws a faded thing on
   a layer of its own and can land it half a pixel over (Angel, 27 Sept).
   The colour is the ink at about the strength the icons had, as a solid
   colour so crossing lines in a drawing don't show darker. */
.topbar nav .nav-icon { display: inline-flex; align-items: center; justify-content: center; min-width: 32px; min-height: 32px; padding: 0.3rem; border-radius: 4px; color: #3e3e3d; opacity: 1; }
.topbar nav .nav-icon:hover, .nav-menu[open] > .nav-icon { background: var(--paper-muted); color: var(--ink); opacity: 1; }
.topbar nav .nav-icon svg { display: block; }
.topbar nav .nav-icon:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
/* The customer's three icons as one group, closer to each other than the
   words are (Angel, 27 Sept - "get the icons slightly closer"). */
.topbar nav .nav-icons { display: flex; align-items: center; gap: 0.6rem; }
/* The basket's bubble sits off its top right corner, like every shop's -
   clear of the icon, since a trolley facing left has its handle right there
   (Angel, 27 Sept: "the bubble overlaps"). The ring in the page's colour
   keeps its edge clean against anything behind it, and the extra margin -
   only while there's a bubble, or the gaps look uneven - keeps it off the
   next icon. */
.topbar nav a.nav-counted { position: relative; }
.topbar nav a.nav-counted.has-count { margin-right: 0.6rem; }
.nav-counted .nav-count { position: absolute; top: -0.5rem; right: -0.95rem; margin-left: 0; box-shadow: 0 0 0 2px var(--paper); }
/* The bell's comes in closer, at its shoulder: the bell narrows towards
   the top, so there's room there that the trolley's handle doesn't leave
   (Angel, 27 Sept - "slightly closer to the bell"). Same height as the
   trolley's, so the two numbers line up across the top ("aligned upwards
   with the basket"). */
.nav-bell .nav-count { right: -0.55rem; }
.topbar nav a.nav-bell.has-count { margin-right: 0.3rem; }
/* The customer's person menu: Account, Settings and Log out under one
   icon. The list drops below it, right-aligned to the icon. */
.nav-menu { position: relative; }
.nav-menu > summary { list-style: none; cursor: pointer; }
.nav-menu > summary::-webkit-details-marker { display: none; }
.nav-menu-list { position: absolute; right: 0; top: calc(100% + 0.4rem); z-index: 50; min-width: 11rem; width: max-content; max-width: min(20rem, 90vw); display: flex; flex-direction: column; padding: 0.35rem; background: var(--paper); border: 1px solid var(--border); border-radius: 6px; box-shadow: 0 8px 24px rgba(28, 28, 28, 0.1); }
.nav-menu-list form { margin: 0; }
.nav-menu-who { display: block; padding: 0.55rem 0.8rem 0.6rem; margin-bottom: 0.25rem; border-bottom: 1px solid var(--border); font-size: 0.8rem; line-height: 1.4; color: var(--ink); opacity: 0.75; text-transform: none; letter-spacing: normal; overflow-wrap: anywhere; }
.nav-menu-who strong { display: block; opacity: 1; font-weight: 600; }
.topbar nav .nav-menu-list a, .nav-menu-list .nav-menu-item { display: block; width: 100%; text-align: left; padding: 0.6rem 0.8rem; border: 0; border-radius: 4px; background: none; color: var(--ink); font-family: var(--body-font); font-weight: 400; font-size: 0.8rem; letter-spacing: 0.06em; text-transform: uppercase; line-height: 1.4; opacity: 0.85; cursor: pointer; }
.topbar nav .nav-menu-list a:hover, .nav-menu-list .nav-menu-item:hover { background: var(--paper-muted); opacity: 1; }
/* The catalogue's Show dropdown, where the category buttons were. */
.catalog-show { margin: 0 0 1.5rem; }

/* Your order: Update and Remove side by side, Empty order under the table. */
.cart-qty { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; }
.cart-clear { margin: 0.8rem 0 0; text-align: right; }

@media (max-width: 640px) {
  /* The store name is set nowrap so it can't break mid-title on a desktop
     bar. On a phone that made it wider than the screen, which dragged the
     whole page sideways - every page, not just this one. */
  .topbar .brand { white-space: normal; font-size: 0.85rem; }
  .brand-logo { height: 15px; }
  .topbar {
    flex-direction: column;
    align-items: flex-start;
  }
  .topbar nav {
    width: 100%;
    gap: 0.9rem 1.1rem;
  }
}

.container {
  max-width: 780px;
  margin: 0 auto;
  padding: 2.5rem 1.5rem 4rem;
}

.container--wide { max-width: 1080px; }

.card {
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 1.5rem;
}

.auth-shell {
  max-width: 380px;
  margin: 4.5rem auto;
  padding: 0 1.5rem;
}

label {
  display: block;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-bottom: 0.35rem;
  opacity: 0.75;
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="search"],
textarea,
select {
  width: 100%;
  padding: 0.65rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: 4px;
  font-family: var(--body-font);
  font-size: 0.95rem;
  background: #fff;
  color: var(--ink);
  margin-bottom: 1rem;
}
/* The field you're in shows a dark border rather than the browser's own
   blue ring, which looked out of place and stayed on the Show dropdown
   until you clicked somewhere else (Angel, 27 Sept). The same in every
   browser, and still plain to see for someone moving round with the Tab
   key. Drawn as an outline laid over the border rather than by changing
   the border, so fields with borders of their own get it too. */
input[type="text"]:focus,
input[type="email"]:focus,
input[type="password"]:focus,
input[type="number"]:focus,
input[type="search"]:focus,
textarea:focus,
select:focus {
  outline: 1px solid var(--ink);
  outline-offset: -1px;
}

textarea { min-height: 80px; resize: vertical; }
/* Safari draws a search box as a rounded pill of its own; this makes it
   match every other box. */
input[type="search"] { -webkit-appearance: none; appearance: none; }
.list-search { max-width: 420px; margin: 0.5rem 0 1.25rem; }

.field-row { display: flex; gap: 1rem; }
.field-row > div { flex: 1; }

button, .btn {
  display: inline-block;
  font-family: var(--heading-font);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-size: 0.78rem;
  /* Without this, the two ways a button gets written render at different
     heights: an <a class="btn"> inherits the body's 1.6, while a real
     <button> takes the browser's `normal` for form controls (~1.2). Same
     padding, same font, 5px apart - visible whenever a link-button and a
     form-button sit side by side, as Edit and Remove do in every table. */
  line-height: 1.2;
  /* A real <button> centres its words; an <a class="btn"> would sit them
     to the left - unseen on one line, lopsided the moment a narrow screen
     wraps the words onto two ("TEAM / TASKS" beside a centred "SET A /
     TASK"). */
  text-align: center;
  padding: 0.75rem 1.4rem;
  border-radius: 4px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: var(--accent-text);
  cursor: pointer;
  text-decoration: none;
}
button:hover, .btn:hover { opacity: 0.85; }
button:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}
button:disabled:hover { opacity: 0.3; }

.btn-secondary {
  background: transparent;
  color: var(--ink);
}

.btn-small { padding: 0.4rem 0.8rem; font-size: 0.7rem; }

.error-msg {
  background: #fbe6e6;
  color: #7a1f1f;
  padding: 0.7rem 1rem;
  border-radius: 4px;
  font-size: 0.85rem;
  margin-bottom: 1rem;
}

.notice-msg {
  background: var(--warn-bg);
  color: var(--warn-text);
  padding: 0.9rem 1.1rem;
  border-radius: 4px;
  font-size: 0.9rem;
  margin-bottom: 1.2rem;
}

.success-msg {
  background: var(--success-bg);
  color: var(--success-text);
  padding: 0.9rem 1.1rem;
  border-radius: 4px;
  font-size: 0.9rem;
  margin-bottom: 1.2rem;
}

/* Same warm-amber warning language as elsewhere on the site - makes the
   dashboard's action list read as "this needs you", not just another card
   with a heading. */
.needs-attention { background: var(--warn-bg); border-color: transparent; }
.needs-attention h2 { color: var(--warn-text); }

.muted { opacity: 0.65; font-size: 0.85rem; }

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.88rem;
}
th, td {
  text-align: left;
  padding: 0.7rem 0.6rem;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
th {
  text-transform: uppercase;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  opacity: 0.6;
}

/* Products: each category under its own name, set like a small heading -
   it's what tells one group from the next, not a heavy rule between them. */
.product-list .group-row th {
  padding: 2.2rem 0.6rem 0.6rem;
  font-family: var(--heading-font);
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  opacity: 1;
}
.product-list tbody:first-of-type .group-row th { padding-top: 1.4rem; }

/* A product's photo in a list: always the same square, which says so when
   there's no photo, or when the saved one won't load (the page marks it
   is-broken) - a blank gap looked like a picture still on its way. */
.thumb {
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border-radius: 4px; overflow: hidden;
  background: var(--paper-muted);
  font-family: var(--heading-font); font-size: 0.52rem; font-weight: 700;
  letter-spacing: 0.06em; line-height: 1.25; text-transform: uppercase;
  text-align: center; color: rgba(28, 28, 28, 0.5);
}
.thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.thumb-note, .thumb.is-broken img { display: none; }
.thumb.is-broken { background: var(--warn-bg); color: var(--warn-text); }
.thumb.is-broken .thumb-note { display: block; }
.thumb--empty { background: none; border: 1px dashed var(--border); }

.product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 1.4rem;
  margin-top: 1.5rem;
}

.catalog-section-heading {
  margin-top: 2.5rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--border);
}
.catalog-section-heading:first-of-type {
  margin-top: 2rem;
}

.category-filter {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 1.8rem;
}
.category-chip {
  display: inline-block;
  padding: 0.4rem 1rem;
  border-radius: 100px;
  border: 1px solid var(--border);
  background: #fff;
  color: var(--ink);
  text-decoration: none;
  font-family: var(--heading-font);
  font-weight: 700;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.category-chip.active {
  background: var(--accent);
  color: var(--accent-text);
  border-color: var(--accent);
}
.category-chip:hover:not(.active) {
  border-color: var(--ink);
}

.product-card {
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
  background: #fff;
  display: flex;
  flex-direction: column;
}

.product-card img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  background: var(--paper-muted);
  display: block;
}

.product-card-link {
  color: inherit;
  text-decoration: none;
}
.product-card h3 .product-card-link:hover {
  text-decoration: underline;
}

.product-card .body {
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  flex: 1;
}
.product-card .body p {
  white-space: pre-line;
}

.product-detail {
  display: flex;
  gap: 2rem;
  flex-wrap: wrap;
  margin-top: 1rem;
}
/* The whole photo, in its own shape - this is where a customer looks at
   the product, so nothing is cropped off it. align-self keeps it that
   size: left to stretch, it grew to the height of a long description
   beside it and was cut down to fill that, zoomed in on the middle. */
.product-detail img {
  width: 320px;
  max-width: 100%;
  height: auto;
  align-self: flex-start;
  border-radius: 6px;
  background: var(--paper-muted);
}
.product-detail-body {
  flex: 1;
  min-width: 260px;
}
.product-detail-body h1 { margin-bottom: 0.6rem; }
.product-detail-body .price {
  font-family: var(--heading-font);
  font-weight: 700;
  font-size: 1.15rem;
  margin-bottom: 1rem;
}
.product-detail-intro {
  font-size: 1.05rem;
  color: #555;
  margin-bottom: 1rem;
  white-space: pre-line;
}
.product-detail-description {
  white-space: pre-line;
  line-height: 1.6;
  margin-bottom: 1.5rem;
}
.product-detail-body form {
  max-width: 320px;
}

.product-card .price {
  font-family: var(--heading-font);
  font-weight: 700;
  font-size: 0.95rem;
}

.product-card form {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: auto;
}
.product-card input[type="number"] { margin-bottom: 0; }
.product-card form label {
  flex: 1 1 100%;
  margin-bottom: 0;
}
.product-card form select {
  flex: 1 1 100%;
  margin-bottom: 0;
  appearance: none;
  -webkit-appearance: none;
  background-color: #fff;
  color: var(--ink);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23222' stroke-width='1.5' fill='none'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.8rem center;
  padding-right: 2rem;
}
.product-card form input[type="number"] {
  flex: 1 1 0;
  width: auto;
  min-width: 0;
}

.order-card {
  padding: 0;
  margin-bottom: 0.8rem;
}
.order-card summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  cursor: pointer;
  padding: 0.9rem 1.2rem;
  list-style: none;
}
.order-card summary::-webkit-details-marker { display: none; }
.order-card-title,
.order-card-meta {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
}
.order-card-chevron {
  font-size: 0.8rem;
  opacity: 0.5;
  transition: transform 0.15s ease;
}
.order-card[open] .order-card-chevron { transform: rotate(180deg); }
.order-card-body {
  padding: 0 1.2rem 1.2rem;
  border-top: 1px solid var(--border);
}
.order-card-body table { margin-top: 1rem; }

.item-edit-control {
  display: none;
}
#items-section.editing-items .item-edit-control {
  display: flex;
}
#items-section.editing-items .qty-view {
  display: none;
}

.nav-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.15rem;
  height: 1.15rem;
  padding: 0 0.3rem;
  margin-left: 0.3rem;
  border-radius: 100px;
  background: #c0392b;
  color: #fff;
  font-family: var(--body-font);
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: none;
  letter-spacing: normal;
  vertical-align: 2px;
}

/* A subtitle cell - an email under a company. The Orders list lets an
   address fold after its @ (a <wbr> there), which is enough room from 900px
   up; below that it may break mid-word as well, so what badges and the
   company's For collection pill keep for themselves comes out of the
   address rather than off the side of the page. Only there: allowed to
   break at any width, the table shares its room out as if the address were
   tiny and folds it even where it fits. Below 761px the table is cards and
   it has a line to itself. */
@media (min-width: 761px) and (max-width: 899px) {
  td.cell-sub { overflow-wrap: anywhere; }
}

/* nowrap: a badge is one label, and a pill folded in two ("AWAITING" over
   "PAYMENT") reads as two - the column widens to fit it instead. */
.badge {
  display: inline-block;
  padding: 0.2rem 0.55rem;
  border-radius: 100px;
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
  white-space: nowrap;
}
.badge-new { background: var(--warn-bg); color: var(--warn-text); }
.badge-processing { background: #e6edf7; color: #244a7a; }
.badge-invoiced { background: #efe6f7; color: #5a2a7a; }
.badge-awaiting_payment { background: #fdf6d8; color: #6e5a10; }
.badge-paid { background: #dff2ee; color: #146b58; }
/* Packed reaches the customer now - it used to report as "processing", so a
   box sitting ready looked the same as one nobody had started. Sits between
   processing's blue and despatched's green. */
.badge-packed { background: #dceeee; color: #1c5f66; }
.badge-sent { background: var(--success-bg); color: var(--success-text); }
/* Collected is an ending, like sent - settled rather than bright. */
.badge-collected { background: #e4ebe2; color: #3f5537; }
.badge-ready_for_collection { background: #e6e6fb; color: #3d3d99; }
.badge-rejected { background: #fbe7e7; color: #8a2626; }
.badge-cancelled { background: #efefef; color: #666; }

/* Fulfillment status - one clearly different colour per step still to
   do, and plain grey once it's done, the way Shopify's order list works:
   the eye goes to what needs doing, and a column of finished orders stops
   shouting. Each step sits on a different part of the colour wheel from the
   ones either side of it - orange, blue, yellow, purple - because the old
   set had four purples, two greens and two oranges, and they ran together
   (Angel, 19 Sept). Every pair reads at 6:1 or better. */
.fulfillment-new { background: #fddcc8; color: #8a3408; }
.fulfillment-processing { background: #dde7fa; color: #1f4a8a; }
.fulfillment-packed { background: #f6efb8; color: #5c4700; }
.fulfillment-ready_for_collection { background: #ebe2fb; color: #55309a; }
.fulfillment-despatched,
.fulfillment-collected { background: #ecebe6; color: #4d4a44; }
/* Part dispatched: some has gone, the rest is still to do - so a colour of
   its own rather than done's grey, rose, away from the orange, yellow and
   purple either side of it. The customer's badge wears the same. */
.fulfillment-part_despatched,
.badge-part_sent { background: #fbe0ea; color: #8c1f4a; }

/* An order sent in parts, as a section of its own - tinted in Part
   dispatched's rose so it reads as that status's own record, with each part
   a block of its own and what's still to go at the foot. It was a line of
   small text before and got lost (Angel, 19 Sept). */
/* .panel.parts-panel: .panel is set further down this file, and at equal
   weight the later rule won - the section came out plain paper. */
.panel.parts-panel { background: #fdf0f5; border-color: #e7b3c7; border-width: 1px 1px 1px 4px; }
.panel.parts-panel .panel-h h2 { color: #8c1f4a; }
.part { padding: 0.9rem 0; border-top: 1px solid #efcddb; }
.part-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.3rem 0.8rem; }
.part-no {
  font-family: var(--heading-font); font-size: 0.66rem; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase;
  padding: 0.15rem 0.5rem; border-radius: 100px; background: #fbe0ea; color: #8c1f4a;
}
.part-date { font-size: 1rem; }
.part-head .part-edit-toggle { margin-left: auto; }
.part-items { list-style: none; margin: 0.5rem 0 0; padding: 0; display: grid; gap: 0.25rem; }
.part-items li { font-size: 0.95rem; }
.part-note { margin: 0.4rem 0 0; font-size: 0.85rem; opacity: 0.75; }
/* Still to go wears the same kind of label as Part 1, in plain grey: the
   next part, not one that has gone. */
.part--left .part-head strong {
  font-family: var(--heading-font); font-size: 0.66rem; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase;
  padding: 0.15rem 0.5rem; border-radius: 100px; background: #ecebe6; color: #4d4a44;
}
.part-edit { margin-top: 0.9rem; }
.part-edit .card { background: var(--paper); }
.part-edit .table-flat { margin-bottom: 1rem; }
.part-delete { margin-top: 0.6rem; }
/* Send part: a secondary button that opens into the form below it. */
.send-part > summary { display: inline-block; list-style: none; cursor: pointer; }
.send-part > summary::-webkit-details-marker { display: none; }
.send-part[open] > summary { margin-bottom: 0.8rem; }
.send-part-form .table-flat { margin-bottom: 1rem; }
.send-part-box { margin-bottom: 0.8rem; }

/* Invoiced is about the money, not where the order has got to, so in the
   office it's an outline rather than one more filled pill beside the
   status - a different kind of mark, not a sixth colour to tell apart. */
.badge.badge--outline { background: transparent; color: #4d4a44; box-shadow: inset 0 0 0 1px rgba(28, 28, 28, 0.3); }

.stat-row { display: flex; gap: 1rem; margin: 1.5rem 0 2rem; flex-wrap: wrap; }
.stat {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 1rem 1.4rem;
  min-width: 140px;
}
.stat .n { font-family: var(--heading-font); font-size: 1.6rem; font-weight: 700; }
.stat .label { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.06em; opacity: 0.6; }
.stat .delta { font-size: 0.75rem; margin-top: 0.15rem; }
.stat .delta-up { color: var(--success-text); }
.stat .delta-down { color: var(--warn-text); }
/* "Comparison from 19 Sept" - where a percentage will be, once there's an
   earlier stretch to set it against. */
.stat .delta-pending { opacity: 0.55; }
/* On a phone, two to a row at an even width. Left to size themselves they
   went one per row, each as wide as its own words - five ragged boxes
   stacked down the screen before the chart. */
@media (max-width: 640px) {
  .stat-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.7rem; }
  .stat { min-width: 0; padding: 0.9rem 1rem; }
  .stat .n { font-size: 1.35rem; }
}

.page-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.5rem;
  flex-wrap: wrap;
  gap: 1rem;
}

.credential-box {
  background: var(--paper-muted);
  border: 1px dashed var(--border);
  border-radius: 6px;
  padding: 1rem 1.2rem;
  font-family: monospace;
  font-size: 0.9rem;
  margin-bottom: 1.5rem;
}

/* ---- "Visible to" customer picker (product form) ---- */
.visibility-toggle { display: flex; gap: 0.6rem; margin-bottom: 0.8rem; flex-wrap: wrap; }
.visibility-option {
  display: flex; align-items: center; gap: 0.5rem; margin: 0;
  padding: 0.6rem 1rem; border: 1px solid var(--border); border-radius: 100px;
  cursor: pointer; background: #fff; opacity: 1;
  font-size: 0.85rem; text-transform: none; letter-spacing: normal;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.visibility-option input { width: auto; margin: 0; accent-color: var(--ink); }
.visibility-option:has(input:checked) { border-color: var(--ink); background: var(--paper-muted); }

.customer-picker { position: relative; max-width: 440px; margin-bottom: 0.6rem; }
.customer-chips { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 0.5rem; }
.customer-chip {
  display: inline-flex; align-items: center; gap: 0.35rem;
  padding: 0.3rem 0.4rem 0.3rem 0.75rem; border-radius: 100px;
  background: var(--paper-muted); border: 1px solid var(--border); font-size: 0.78rem;
}
.customer-chip-remove {
  all: unset; cursor: pointer; opacity: 0.5; line-height: 1; font-size: 0.9rem;
  padding: 0.15rem 0.35rem; border-radius: 50%;
}
.customer-chip-remove:hover { opacity: 1; background: rgba(28, 28, 28, 0.08); }

.customer-picker-trigger {
  display: flex; align-items: center; justify-content: space-between; gap: 0.6rem;
  width: 100%; padding: 0.65rem 0.9rem; border: 1px solid var(--border); border-radius: 4px;
  background: #fff; color: var(--ink); cursor: pointer; text-align: left;
  font-family: var(--body-font); font-weight: 400; font-size: 0.9rem;
  text-transform: none; letter-spacing: normal;
}
.customer-picker-trigger:hover { border-color: var(--ink); background: #fff; color: var(--ink); }
.customer-picker.is-open .customer-picker-trigger { border-color: var(--ink); }
.customer-picker-chevron { font-size: 0.65rem; opacity: 0.5; transition: transform 0.15s ease; }
.customer-picker.is-open .customer-picker-chevron { transform: rotate(180deg); }

.customer-picker-panel {
  position: absolute; z-index: 20; left: 0; right: 0; margin-top: 0.4rem;
  border: 1px solid var(--border); border-radius: 6px; background: #fff;
  box-shadow: 0 10px 26px rgba(28, 28, 28, 0.12); overflow: hidden;
}
/* Scoped under the picker so a form's own field style (.ops-form on a
   notification) can't box the search in. */
.customer-picker .customer-picker-search {
  display: block; width: 100%; margin: 0; border: none; border-radius: 0;
  border-bottom: 1px solid var(--border); padding: 0.7rem 0.9rem; font-size: 0.88rem; background: #fff;
}
.customer-picker .customer-picker-search:focus { outline: none; background: var(--paper-muted); }
.customer-picker-list { max-height: 230px; overflow-y: auto; padding: 0.35rem 0; }
.customer-picker-row {
  display: flex; align-items: center; gap: 0.6rem; margin: 0; cursor: pointer;
  padding: 0.5rem 0.9rem; font-size: 0.86rem; text-transform: none; letter-spacing: normal; opacity: 1;
}
.customer-picker-row:hover { background: var(--paper-muted); }
.customer-picker-row input { width: auto; margin: 0; accent-color: var(--ink); }
.customer-picker-empty { margin: 0; padding: 0.7rem 0.9rem; font-size: 0.85rem; opacity: 0.6; }

/* The Team page's switches for one office account (views/partials/
   permission-switches.ejs): a tick, then the name in bold with what it
   covers underneath. Written as ordinary sentences, not the site's
   uppercase field labels, so the explanations can be read. */
.permission-switches { border: 1px solid var(--border); border-radius: 6px; padding: 1rem 1.1rem 0.4rem; margin: 0.5rem 0 1.2rem; }
.permission-switches legend { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.08em; opacity: 0.75; padding: 0 0.4rem; }
.permission-switch {
  display: flex; align-items: flex-start; gap: 0.7rem; margin: 0 0 0.9rem; cursor: pointer;
  font-size: 0.92rem; text-transform: none; letter-spacing: normal; opacity: 1;
}
.permission-switch input { width: auto; margin: 0.2rem 0 0; accent-color: var(--ink); flex: 0 0 auto; }
.permission-switch strong { display: block; font-weight: 600; }
.permission-switch .muted { display: block; font-size: 0.84rem; margin-top: 0.1rem; }
/* Under "Staff" on the Team list, only when something's switched off. */
.role-limits { display: block; font-size: 0.78rem; margin-top: 0.15rem; color: var(--warn-text); }

/* A row of table actions (Edit / Duplicate / Hide, etc.). nowrap is doing
   real work here: it makes the cell's min-content width the sum of the
   buttons, so the table has to give the actions column enough room and
   takes it from the title instead. Left to wrap, the column gets squeezed
   to the widest single button and the last action drops to its own line. */
.row-actions { display: flex; flex-wrap: nowrap; align-items: center; gap: 0.6rem; white-space: nowrap; }
.row-actions form { margin: 0; }
/* On a narrow table (few columns, so the actions column ends up very wide)
   left-aligned buttons float in the middle of empty space, disconnected
   from the row's right edge. Pin them to the right instead. */
.row-actions--end { justify-content: flex-end; }

/* A select (or input) paired with a small button beside it, e.g. the stock
   Category picker with its "+ New" escape hatch. The field takes the space,
   the button stays its natural width. */
.picker-row { display: flex; align-items: center; gap: 0.5rem; }
.picker-row select,
.picker-row input[type="text"] { flex: 1; margin-bottom: 0; }
/* A number box in a row (Shipping) sits level with the dropdown beside it:
   its form spacing underneath pushed it up (Angel, 13 Oct). */
.picker-row input[type="number"] { margin-bottom: 0; }
.picker-row button,
.picker-row .btn { flex: 0 0 auto; white-space: nowrap; }

/* Below tablet there genuinely isn't room for one line - wrap whole
   buttons rather than letting the row overflow the screen. */
@media (max-width: 820px) {
  .row-actions { flex-wrap: wrap; }
  .row-actions--end { justify-content: flex-end; }
}

/* ---- Back-office (Control Room) ---- */
/* ===== Back-office (control room) ===== */
/* Spacing lives on the head so a page without a lede still breathes; a
   lede directly after it tucks back up under the title. */
.ops-head { display:flex; flex-wrap:wrap; align-items:baseline; justify-content:space-between; gap:0.8rem 1.5rem; margin-bottom:1.8rem; }
.ops-head + .ops-lede { margin-top:-1.4rem; }
/* The same head as the floor's: the title and the page's main button on
   one line, button at the right, and the tabs under the title on the left
   rather than out at the far side. */
.ops-head { align-items:center; }
.ops-head .ops-subnav { flex-basis:100%; order:3; }
.ops-head:has(.ops-subnav) + .ops-lede { margin-top:-0.8rem; }
/* Wraps rather than running off the side. Eight sections never fitted one
   line on a phone, and the ones past the edge could only be reached by
   sliding the page sideways - which nothing on screen suggested you could
   do, so they were effectively missing on the floor. */
/* Read as tabs (Angel, 29 Sept: they got lost): bigger and darker, each
   with an icon, sitting on a line across the page that the one you're on
   underlines thickly. */
.ops-subnav { display:flex; flex-wrap:wrap; gap:0 1.7rem; border-bottom:1px solid var(--border); }
.ops-subnav a { display:inline-flex; align-items:center; gap:0.45rem; text-decoration:none; color:var(--ink);
  font-family:var(--heading-font); font-size:0.8rem; font-weight:600; letter-spacing:0.07em; text-transform:uppercase;
  opacity:0.62; padding:0.6rem 0.1rem 0.7rem; margin-bottom:-1px; border-bottom:3px solid transparent; }
.ops-subnav a svg { flex:0 0 auto; }
.ops-subnav a:hover { opacity:1; }
.ops-subnav a.is-active { opacity:1; font-weight:700; border-bottom-color:var(--ink); }
/* On the floor the tabs sit under the page's heading rather than inside
   it, so they bring their own space below - the same gap the office's
   heading leaves - instead of the first panel butting up against them. */
.page-head + .ops-subnav { margin-bottom:1.8rem; }
.ops-lede { max-width:60ch; opacity:0.75; margin:0.2rem 0 2rem; }

.tiles { display:grid; grid-template-columns:repeat(4,1fr); gap:1rem; margin-bottom:2rem; }
.tile { border:1px solid var(--border); border-radius:6px; padding:1.2rem 1.3rem; display:flex; flex-direction:column; gap:0.35rem; background:var(--paper); text-decoration:none; color:inherit; }
a.tile:hover { border-color:var(--ink); }
.tile--warn:hover, .tile--alert:hover { border-color:transparent; opacity:0.9; }
.tile-label { font-family:var(--heading-font); font-size:0.66rem; letter-spacing:0.1em; text-transform:uppercase; opacity:0.6; }
.tile-figure { font-family:var(--heading-font); font-size:1.7rem; letter-spacing:0.02em; }
.tile-figure .per { font-size:0.9rem; opacity:0.5; }
.tile-sub { font-size:0.78rem; opacity:0.6; }
.tile--warn { background:var(--warn-bg); border-color:transparent; }
.tile--warn .tile-label, .tile--warn .tile-sub { color:var(--warn-text); opacity:0.85; }
.tile--warn .tile-figure { color:var(--warn-text); }
.tile--alert { background:#fbe7e3; border-color:transparent; }
.tile--alert .tile-figure, .tile--alert .tile-label, .tile--alert .tile-sub { color:#8a2c1a; }

/* Same warm-amber warning language as low stock rows and notices - makes
   the dashboard's action list read as "this needs you" against the plain
   cards around it, not just another card with a heading. */
.needs-attention { background:var(--warn-bg); border-color:transparent; }
.needs-attention h2 { color:var(--warn-text); }

.ops-grid { display:grid; grid-template-columns:1fr 1fr; gap:1.2rem; }
.ops-grid .card--full { grid-column:1 / -1; }
.ops-grid .card h2 { font-size:0.85rem; margin-bottom:1rem; }
.card-head { display:flex; align-items:center; justify-content:space-between; margin-bottom:1rem; }
.card-head h2 { margin-bottom:0; }
.stack { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; }
.stack .row { display:flex; align-items:center; justify-content:space-between; gap:1rem; padding:0.65rem 0; border-top:1px solid var(--border); }
.stack .row:first-child { border-top:none; }
.row-sub { display:block; font-size:0.76rem; opacity:0.6; }
/* row-sub is a block sub-line meant for a <span> inside a cell. Put straight
   on a <td> the block display drops that cell out of the table layout, and
   every cell after it stacks underneath instead of sitting in its own column
   - which is why stock history showed notes under "By" and left the Note
   column empty. Keep the small muted type; put the cell back. */
td.row-sub { display:table-cell; }
.row-note { display:block; font-size:0.74rem; color:var(--warn-text); margin-top:0.15rem; }
.row-link { color:inherit; text-decoration:none; }
.row-link:hover strong { text-decoration:underline; }

/* Briefly highlight a table row jumped to via #anchor link, e.g. from
   "Reorder soon" on the Control Room to its row on the Stock page. */
tr:target { animation: target-flash 2.5s ease-out; }
@keyframes target-flash {
  from { background:var(--warn-bg); }
  to { background:transparent; }
}

.pill { font-family:var(--heading-font); font-size:0.6rem; letter-spacing:0.08em; text-transform:uppercase; padding:0.25rem 0.55rem; border-radius:100px; background:var(--paper-muted); white-space:nowrap; }
.pill--warn { background:var(--warn-bg); color:var(--warn-text); }
.pill--good { background:var(--success-bg); color:var(--success-text); }
.pill--alert { background:#fbe7e3; color:#8a2c1a; }
.qty { font-family:var(--heading-font); font-size:0.82rem; }
/* Amounts in and out, bold in the design's red and green (Angel, 3 Oct). */
.qty--out { color:#8e1b1b; font-weight:700; font-variant-numeric:tabular-nums; }
.qty--in { color:#0f5129; font-weight:700; font-variant-numeric:tabular-nums; }
.inline { display:inline; margin:0; }

.ops-table { width:100%; border-collapse:collapse; margin-bottom:2.2rem; }
.ops-table th { text-align:left; font-family:var(--heading-font); font-size:0.66rem; letter-spacing:0.08em; text-transform:uppercase; opacity:0.55; padding:0.5rem 0.7rem; border-bottom:1px solid var(--border); }
.ops-table td { padding:0.7rem 0.7rem; border-bottom:1px solid var(--border); vertical-align:top; }
.ops-table .num { text-align:right; white-space:nowrap; }
/* A date is read, not totted up, so it stays left under its heading like
   every other date in the Hub - .num is for figures you scan down a column. */
.ops-table .date { white-space:nowrap; }
/* A highlighted row - overdue, running low - is a rounded band set in from
   the lines above and below it, rather than a block of colour running into
   them (Angel, 28 Sept - "keep it free from the separating lines"). Each
   cell paints its stretch of the band behind its words; the first and last
   round its ends. A faded cell (.row-sub) is set in grey instead of faded,
   or its stretch of the band would fade with it. On a phone, where a row
   becomes a card and each cell's ::before is its label, the whole card
   carries one band on its ::after instead (below). */
@media (min-width: 761px) {
  .ops-table tr.is-low td { position:relative; z-index:0; }
  .ops-table tr.is-low td::before { content:''; position:absolute; top:5px; bottom:5px; left:0; right:0; background:var(--warn-bg); z-index:-1; }
  .ops-table tr.is-low td:first-child::before { left:4px; border-radius:6px 0 0 6px; }
  .ops-table tr.is-low td:last-child::before { right:4px; border-radius:0 6px 6px 0; }
  .ops-table tr.is-low td:only-child::before { border-radius:6px; }
  .ops-table tr.is-low td.row-sub { opacity:1; color:rgba(28, 28, 28, 0.6); }
}
/* A binned batch reads as struck through rather than shaded: it stays in the
   day's list because it happened, but nothing about it counts as stock. */
.ops-table tr.is-binned td { opacity:0.62; }
.ops-table tr.is-binned strong { text-decoration:line-through; }
.ops-table tfoot td { border-bottom:none; border-top:2px solid var(--border); padding-top:0.6rem; }
/* One page, several tables stacked as sections: without a fixed layout each
   sizes its own columns from its own content, so the headings step in and
   out across sections. Pair with a <colgroup> giving every column but the
   first an explicit width - the first absorbs the slack, so the columns to
   its right line up whether or not the optional ones are present. */
.ops-table--fixed { table-layout:fixed; }
.ops-table--fixed td { overflow-wrap:anywhere; }
/* A section divider, not a label. Type (the group) and category (a tag on
   a row) were reading at similar weight, which made it look like two goes
   at the same idea - a rule and full contrast put the group clearly one
   level up. */
.group-head {
  font-size:0.95rem;
  opacity:1;
  margin:2.6rem 0 0.9rem;
  padding-top:1.2rem;
  border-top:1px solid var(--border);
}
/* The first section opens the page; it has nothing to be divided from. */
.group-head:first-of-type { border-top:none; padding-top:0; margin-top:1.5rem; }

.roast { padding:1.1rem 1.2rem; }
/* The weights and the costs share one band rather than stacking as two
   separate panels - a roast is a single fact, and three tinted blocks per
   batch made a handful of them fill the screen. */
/* Green in → roasted out reads as one statement: the two figures stay
   close together with an arrow big enough to carry the relationship. */
.flow-head { font-family:var(--heading-font); font-size:0.6rem; letter-spacing:0.1em; text-transform:uppercase; opacity:0.55; display:block; margin-bottom:0.15rem; }
@media (max-width:520px){ .roast-flow { gap:0.9rem; } .flow-big { font-size:1.25rem; } .flow-arrow { font-size:1.2rem; } }
.flow-breakdown { margin-top:0.7rem; padding-top:0.7rem; border-top:1px solid var(--border); font-size:0.82rem; }
/* Marked off with a rule down its side so a note reads as a note, not as
   a continuation of the date/roaster line above it. */
.green-locked { background:var(--paper-muted); border-radius:6px; padding:1rem 1.1rem; margin-bottom:0.5rem; }
.green-locked .form-hint { margin-bottom:0; }
.flow-breakdown-line { display:flex; justify-content:space-between; gap:1rem; padding:0.15rem 0; opacity:0.75; }

@media (max-width:820px){ .tiles{grid-template-columns:repeat(2,1fr);} .ops-grid{grid-template-columns:1fr;} }

/* ===== Back-office forms ===== */
.banner { padding:0.8rem 1.1rem; border-radius:6px; margin-bottom:1.5rem; font-size:0.9rem; }
.banner--good { background:var(--success-bg); color:var(--success-text); }
.ops-form { display:flex; flex-direction:column; gap:1.1rem; max-width:720px; }
.ops-form .field { display:flex; flex-direction:column; gap:0.35rem; }
.ops-form .field > span { font-family:var(--heading-font); font-size:0.66rem; letter-spacing:0.08em; text-transform:uppercase; opacity:0.65; }
.ops-form .field > span em { font-style:normal; opacity:0.5; text-transform:none; letter-spacing:0; }
.ops-form input, .ops-form select { font-family:var(--body-font); font-size:0.95rem; padding:0.6rem 0.7rem; border:1px solid var(--border); border-radius:5px; background:var(--paper); color:var(--ink); }
/* Only where a hint follows. The control's global margin-bottom stacked on
   the field's own flex gap, so a hint sat an inch below the thing it
   explains - while the row beneath crowded up against it. Drop the margin so
   the hint tucks under its control, and put the space below the hint
   instead, where it separates one row from the next.

   Scoped with :has() rather than applied to every control, so fields
   without a hint keep the spacing they already had. */
.ops-form .field:has(> span.form-hint) input,
.ops-form .field:has(> span.form-hint) select,
.ops-form .field:has(> span.form-hint) textarea { margin-bottom:0; }
.ops-form .field > span.form-hint { margin-bottom:0.9rem; }
/* A select is the browser's own control unless told otherwise, so the same
   page renders flat in Chrome and as a bevelled grey bubble in Safari. One
   product card already normalised its own; this lifts that treatment - and
   its chevron - to every select, so they match each other whatever you open
   them in. Both selectors are listed so this outranks the .ops-form
   background shorthand above, which would otherwise wipe the chevron out. */
select,
.ops-form select {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23222' stroke-width='1.5' fill='none'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.8rem center;
  padding-right: 2.2rem;
}
.ops-form input:focus, .ops-form select:focus { outline:2px solid var(--ink); outline-offset:1px; }
/* Who did something is taken from the login, not typed. Same metrics as an
   input so it still lines up in a .field-row, but tinted and borderless so
   it reads as a fact about the form rather than a box waiting to be filled. */
.ops-form .field-static {
  font-family:var(--body-font); font-size:0.95rem;
  padding:0.6rem 0.7rem; border-radius:5px;
  background:var(--paper-muted); color:var(--ink);
  margin:0; opacity:0.8;
  overflow-wrap:anywhere;
  /* Inside a .field-row it fills its column and lines up with the input
     beside it. On its own it would otherwise stretch the full form width
     and read as an empty box, so cap it just above a column's width. */
  max-width:22rem;
}
/* Scoped to Hub forms. Unscoped, this two-column grid overrode the flex
   .field-row the rest of the admin uses, and any row with three fields - the
   product form's price, unit and minimum order - wrapped the third onto a
   line of its own. */
.ops-form .field-row { display:grid; grid-template-columns:1fr 1fr; gap:1rem; }
.rule { border:none; border-top:1px solid var(--border); margin:0.3rem 0; }
.seg { display:flex; gap:0.5rem; }
.seg-opt { flex:1; display:flex; align-items:center; gap:0.5rem; padding:0.7rem 0.9rem; border:1px solid var(--border); border-radius:6px; cursor:pointer; font-size:0.9rem; }
.seg-opt input { accent-color:var(--ink); }
/* "Went out in 1 × Small box" on a packed order, read from the stock record. */
.packed-with { margin:1rem 0 0; padding:0.7rem 0.9rem; border-radius:6px; background:var(--success-bg); color:var(--success-text); font-size:0.9rem; }
.packing-row { display:flex; flex-wrap:wrap; align-items:center; gap:0.6rem; padding:0.6rem; border:1px solid var(--border); border-radius:6px; margin-bottom:0.6rem; }
.packing-row select { flex:1 1 200px; width:auto; margin-bottom:0; }
.packing-row input[type="number"] { flex:0 0 70px; width:70px; margin-bottom:0; }
.packing-row button { flex:0 0 auto; margin-left:auto; }
/* A goods-in line: what came, how many, what each cost. Same shape as a
   packing row, but with two number fields rather than one, so the price gets
   room a quantity doesn't need. */
.goods-row { display:flex; flex-wrap:wrap; align-items:center; gap:0.6rem 0.9rem; padding:0.6rem; border:1px solid var(--border); border-radius:6px; margin-bottom:0.6rem; }
/* Direct children only: the new-item panel that opens inside this row has a
   select of its own, and the flex sizing meant for the line picker stretched
   it to fill the panel's height.
   min-width:0 lets the select shrink instead of shouldering Remove onto a
   line of its own - a flex item won't go below its content width otherwise,
   and a long coffee name is wide. */
.goods-row > select { flex:1 1 12rem; min-width:0; width:auto; margin-bottom:0; }
/* The number keeps its meaning after it's typed; a placeholder wouldn't. */
.goods-row-field { display:flex; align-items:center; gap:0.4rem; margin:0; flex:0 0 auto; }
.goods-row-field > span { font-size:0.7rem; letter-spacing:0.04em; opacity:0.6; white-space:nowrap; }
.goods-row-field input { flex:0 0 5.5rem; width:5.5rem; margin-bottom:0; }
/* A dropdown in a line (Arrived ok?, VAT) sits level with the boxes beside
   it: without this it kept the space every dropdown has under it on a form,
   and was pushed up out of line (Angel, 29 Sept). */
.goods-row-field select { margin-bottom:0; width:auto; }
.goods-row > button { flex:0 0 auto; }
/* A line's notes (last paid, the total with VAT) take a row of their own
   only when they say something: empty, each still made a row and its gap,
   and the line sat high in a box twice its height (Angel, 13 Oct). */
.goods-row > .form-hint:empty { display:none; }
/* The floor's line for something not stocked yet: opens on its own row inside
   the delivery line, tinted so it reads as belonging to the row above rather
   than as a second form below it. */
.goods-new { flex:1 1 100%; margin:0.2rem 0 0; padding:0.8rem 0.9rem 0.2rem; border-radius:6px;
             background:var(--paper-muted); border:1px solid var(--border); }
.goods-new .field-row:last-child { margin-bottom:0.6rem; }

/* A new product needs more than a line can hold - what it is, as well as how
   much came and what it cost. Boxed as a card so several of them on one
   delivery stay visibly separate, with the quantity and cost along the
   bottom, where the restock rows keep theirs. */
.goods-card { border:1px solid var(--border); border-radius:6px; padding:0.9rem 0.9rem 0.2rem; margin-bottom:0.6rem; }
.goods-card-foot { display:flex; align-items:center; flex-wrap:wrap; gap:0.6rem 0.9rem;
                   padding-top:0.2rem; margin-bottom:0.9rem; }
/* Pushes Remove to the far edge, so it can't be mistaken for part of the
   cost field beside it. */
.goods-card-foot button { margin-left:auto; }

/* "ex VAT / inc VAT" beside a price, and what it comes to without the VAT
   (partials/vat-script.ejs). Only as wide as its words, in whichever row it
   sits - the line picker's stretch and a select's usual full width are both
   for the item, not for this. */
.goods-row > select.vat-pick,
.picker-row select.vat-pick,
.ops-form select.vat-pick { flex:0 0 auto; width:auto; margin-bottom:0; }
.vat-net { font-size:0.75rem; opacity:0.65; white-space:nowrap; }
.vat-net:empty { display:none; }

/* Make a batch: what the batch comes to, worked out as it's typed, and each
   ingredient's shelf beside it so a slipped digit shows before it's saved. */
.batch-cost { margin:1rem 0 0; font-family:var(--heading-font); font-weight:700; font-size:0.9rem; }
.batch-cost:empty { display:none; }
.batch-cost--warn { color:var(--warn-text); }
.goods-row .input-onhand:empty, .goods-row .input-unit:empty { display:none; }
.form-actions { display:flex; gap:0.8rem; align-items:center; }
.form-hint { font-size:0.78rem; opacity:0.6; margin:0; }
/* A hint placed inside a .field is still a direct-child span, so it would
   otherwise inherit the uppercase, letter-spaced label styling above. Put it
   back to ordinary sentence text. */
.ops-form .field > span.form-hint {
  font-family:var(--body-font); font-size:0.78rem;
  text-transform:none; letter-spacing:normal; opacity:0.6;
}
/* An order packed without its stock coming off. Sits above the Hub's figures
   because it's the reason those figures are wrong, so it's tinted and ruled
   to read as a problem rather than another panel. */
.stock-miss {
  /* The alert palette, not the amber the tiles use. Low stock and requests
     waiting are counters you glance at; these two blocks mean a figure below
     is wrong until someone acts. Sharing a colour made a problem read as one
     more counter. */
  background:#fbe7e3; color:#8a2c1a;
  border-radius:6px;
  padding:1.1rem 1.3rem; margin-bottom:1.8rem;
}
.stock-miss h2 { margin:0 0 0.3rem; font-size:1rem; }
.stock-miss > p { margin:0 0 1rem; max-width:70ch; font-size:0.9rem; }
.stock-miss .ops-table { margin-bottom:0; background:transparent; }
.stock-miss .ops-table th { color:inherit; opacity:0.7; }
.stock-miss .ops-table td { border-color:rgba(138,44,26,0.18); }
/* .ops-table cells are top-aligned, which suits a list of stacked rows but
   not this one: the item carries a second line, so the row is taller than
   its other cells and the quantity and supplier floated up away from the
   price fields. Centre them all on one axis instead. */
.stock-miss .ops-table td { vertical-align:middle; }
/* Pricing a delivery inline - two small fields and a button on one line, so
   clearing the list doesn't mean a page per delivery. */
/* Centred, not bottom-aligned: the label sits beside its input here rather
   than above it, and each .field is a <label> carrying the global
   margin-bottom - so aligning on the bottom put the button that margin's
   worth below the boxes. */
.price-form { display:flex; align-items:center; gap:0.6rem; flex-wrap:wrap; }
.price-form .field { display:flex; align-items:center; gap:0.4rem; margin:0; }
.price-form .field > span {
  font-family:var(--heading-font); font-size:0.6rem; letter-spacing:0.06em;
  text-transform:uppercase; opacity:0.7;
}
/* The unit label is the item's own - "per kg" against "per roll" - so it
   changes width from row to row, and every box after it used to shift with
   it. Fixed box, right-aligned, so the label still sits against its input
   while the inputs and Save buttons line up down the column. */
.price-form .field:first-child > span { min-width:5.5rem; text-align:right; }

/* Numbers typed straight into a table cell, sized to the figures they hold
   so the column still reads as a column rather than a row of wide boxes.
   Qualified with the element so it outweighs the base input[type=number]
   rule, which sets width:100%. */
input.cell-input { width:6rem; margin:0; text-align:right; display:inline-block; }

/* A word about the figure above it - quieter than a pill, which in a table
   that already carries status pills would read as a status of its own.
   Same heading font, size and tracking as the column headers, so it reads as
   a label on the number rather than as more data. */
.price-note { display:block; margin-top:0.25rem; font-family:var(--heading-font);
              font-size:0.62rem; font-weight:700; letter-spacing:0.08em; text-transform:uppercase; }
.price-note--good { color:var(--success-text); }
.price-note--warn { color:var(--warn-text); }

/* Not a status - where the order goes. Solid ink so it reads as a different
   class of fact from the amber/green status pills beside it, and so nobody
   loads a collection onto a van. */
.pill--collect { background:var(--ink); color:var(--accent-text); font-weight:700; }
/* A name and its For collection pill: the pill on the right of the name, on
   one line, wherever there's room (Angel, 14 Sept). The gap belongs to the
   pair, not the pill - the pill once carried its own left margin, so when a
   long name pushed it underneath it landed indented, out of line with the
   name. Now, squeezed, it wraps flush under the name instead. */
.name-with-flag { display:inline-flex; flex-wrap:wrap; align-items:center; column-gap:0.5rem; row-gap:0.3rem; }
/* On a screen with the room, the pair never breaks: a table shares its width
   out by what each column could fold to, and left to fold, the name column
   was always the one squeezed until the pill went under. Held on one line,
   the room comes from columns that can fold instead - the date onto two
   lines, a second badge under the first. */
/* From 1120px: the width at which .container--wide (1080px) stops growing,
   so every screen at least that wide lays the list out the same - and the
   Orders list, its widest, fits with the pair held together. */
@media (min-width: 1120px) {
  .name-with-flag { flex-wrap: nowrap; white-space: nowrap; }
}
/* In a table, the pill sits at the right-hand edge of its column rather
   than straight after the name, so down a list they line up in one column
   (Angel, 30 Sept - "for tidy's sake"). Not on a phone card, where the
   pill travels with the badges instead. */
@media (min-width: 761px) {
  td > .name-with-flag { display:flex; justify-content:space-between; width:100%; }
}
/* The pill's second copy, in an order's badges cell, for a phone card only
   (see "Tables on a phone") - on a desktop the one beside the name says it. */
.pill--on-card { display: none; }

/* Tabs that narrow a list to one question. The count sits inside the tab so
   the size of each pile is readable without opening it. */
.filter-tabs { display:flex; flex-wrap:wrap; gap:0.4rem; margin:1.5rem 0 1.4rem; }
.filter-tabs a { display:inline-flex; align-items:center; gap:0.45rem; padding:0.4rem 0.85rem;
                 border:1px solid var(--border); border-radius:100px; text-decoration:none;
                 font-family:var(--heading-font); font-size:0.7rem; letter-spacing:0.06em;
                 text-transform:uppercase; color:var(--ink); }
.filter-tabs a span { font-size:0.68rem; opacity:0.55; font-variant-numeric:tabular-nums; }
.filter-tabs a:hover { background:var(--paper-muted); }
.filter-tabs a.is-on { background:var(--ink); color:var(--accent-text); border-color:var(--ink); }
.filter-tabs a.is-on span { opacity:0.75; }
/* A full-width strip under the heading, never a compact block: black with
   uppercase lettering is exactly what a button looks like here, and at the
   size of its two words it would read as one. */
.collect-banner { flex-basis:100%; order:1; margin:0 0 0.5rem;
                  padding:0.75rem 1.1rem; border-radius:6px;
                  background:var(--ink); color:var(--accent-text); }
.collect-banner strong { font-family:var(--heading-font); letter-spacing:0.06em; text-transform:uppercase; font-size:0.8rem; }
/* Edit order (30 Sept): one button opens how it leaves, the items and the
   note together, saved from the bar at the foot. */
/* An order's history at its foot (30 Sept): a line down the side with a
   dot for each thing that happened, grouped by day, newest first. */
.order-history { margin-top:2.6rem; }
.history-day { margin:1.3rem 0 0.5rem; font-size:0.72rem; letter-spacing:0.08em; text-transform:uppercase; opacity:0.6; }
.history-list { list-style:none; margin:0; padding:0 0 0 0.35rem; border-left:2px solid var(--border); }
.history-item { position:relative; display:flex; align-items:baseline; gap:1rem; padding:0.45rem 0 0.45rem 1.1rem; font-size:0.92rem; }
.history-dot { position:absolute; left:-0.72rem; top:0.85rem; width:10px; height:10px; border-radius:50%; background:var(--paper); border:2px solid #b9b4a9; }
.history-email .history-dot { border-color:#5a7fa8; }
.history-placed .history-dot, .history-fulfillment .history-dot, .history-part .history-dot { border-color:var(--ink); background:var(--ink); }
.history-item.is-failed .history-dot { border-color:#a33; background:#a33; }
.history-item.is-failed .history-text { color:#7a1f1f; }
.history-text { flex:1; min-width:0; overflow-wrap:anywhere; }
.history-by { display:block; margin-top:0.1rem; font-size:0.8rem; opacity:0.6; }
.history-time { flex:none; font-size:0.8rem; opacity:0.6; font-variant-numeric:tabular-nums; }

/* The order's own heading, with Edit order beside it. */
.order-section-head { display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:0.6rem 1rem; margin:2rem 0 0.9rem; }
.order-section-title { margin:0; font-size:1.05rem; }
.order-edit-btn { display:inline-flex; align-items:center; gap:0.45rem; margin:0; }
.editing-order .order-edit-btn { display:none; }
.order-edit-only { display:none; }
.editing-order .order-edit-only { display:flex; }
.editing-order .order-view { display:none; }
.method-form { flex-direction:column; gap:0.6rem; max-width:30rem; margin:0 0 1.2rem; padding:1rem; border:1px solid var(--border); border-radius:6px; }
.method-form .seg-opt { margin:0; }
.order-edit-bar { z-index:5; }
.order-edit-bar .row-actions button { margin:0; }
.editing-order #note-form { display:flex; flex-direction:column; }
.unit-suffix { font-size:0.8rem; opacity:0.55; margin-left:0.35rem; }
.price-form input {
  width:6.5rem; font-family:var(--body-font); font-size:0.9rem;
  padding:0.35rem 0.5rem; border:1px solid rgba(138,44,26,0.3);
  border-radius:4px; background:var(--paper); color:var(--ink); margin:0;
}

/* The roast log, a day at a time. A busy day is 15-25 batches, so the day
   view is a dense table with the day's totals above it - the card treatment
   it replaced was ~180px per roast, which is four thousand pixels of
   scrolling for one day's work. */
.roast-day-head {
  display:flex; flex-wrap:wrap; align-items:flex-end; justify-content:space-between;
  gap:1rem; margin-bottom:1.2rem;
}
.roast-day-nav { display:flex; align-items:center; gap:0.8rem; }
.roast-day-nav [aria-disabled="true"] { opacity:0.3; cursor:default; }
/* Date and "back to today" side by side, baseline-aligned. The min-width is
   what stops the forward arrow shifting as you step: the link only exists on
   days that aren't today, so without a reserved width the arrow would jump
   left the moment you arrived back. */
.roast-day-when { display:flex; align-items:baseline; gap:0.8rem; min-width:15rem; }
/* 15rem plus the two arrows is wider than a phone, which pushed the forward
   arrow past the page's edge. There the date takes whatever's left between
   the arrows instead - which still pins the forward one in place. */
@media (max-width:520px){ .roast-day-nav { width:100%; } .roast-day-when { min-width:0; flex:1; flex-wrap:wrap; } }
.roast-day-when strong { font-family:var(--heading-font); font-size:1.05rem; }
/* A date input isn't in the global input rules above, so unlike a select it
   stays inline-sized and lands flush against its own label. Lay the pair out
   as an explicit row rather than relying on incidental inline spacing. */
.roast-day-jump .field { display:flex; align-items:center; gap:0.7rem; margin:0; }
.roast-day-jump .field > span {
  font-family:var(--heading-font); font-size:0.66rem; letter-spacing:0.08em;
  text-transform:uppercase; opacity:0.65;
}
.roast-day-jump input {
  font-family:var(--body-font); font-size:0.9rem; padding:0.45rem 0.6rem;
  border:1px solid var(--border); border-radius:5px; background:var(--paper); color:var(--ink);
}
/* The day's figures read before the rows that make them up: you roast to a
   yield, so the day's loss is the number worth seeing first. */
.roast-day-totals {
  display:flex; flex-wrap:wrap; gap:2.4rem;
  background:var(--paper-muted); border-radius:6px;
  padding:1rem 1.3rem; margin-bottom:1.4rem;
}
.roast-day-totals > div { display:flex; flex-direction:column; gap:0.2rem; }
.roast-day-empty { margin:0 0 1.4rem; }
.roast-day-foot { margin:1.2rem 0 0; font-size:0.85rem; }
.roast-table td { vertical-align:top; }
/* The full batch, expanded under its row. This is the card treatment the
   dense rows replaced - right for one roast you're looking at, wrong as the
   default for twenty-five. Some of these rules were removed as dead when the
   cards went; they're live again here, in a panel rather than a card. */
/* Paper, not the muted fill the day totals use. Both tinted the same made a
   page-level summary and one row's detail read as the same kind of thing;
   the rule down the left marks this as hanging off the row above instead. */
/* The whole panel tinted, not a rule down its edge - the fill is what marks
   it as belonging to the row above. Uses the palette's own pale green, the
   same one behind despatched badges: an opened roast is something you asked
   to see, so it reads calm against the day's grey totals and the red the
   Hub keeps for problems. */
.roast-detail > td { background:var(--success-bg); padding:0; }
.roast-panel { display:flex; flex-wrap:wrap; gap:1.6rem 2.6rem; padding:1.2rem 1.4rem; }
.roast-flow { display:flex; align-items:center; flex-wrap:wrap; gap:1.4rem; }
.roast-flow > div { display:flex; flex-direction:column; gap:0.1rem; }
.flow-big { font-family:var(--heading-font); font-weight:700; font-size:1.25rem; }
.flow-arrow { opacity:0.4; font-size:1.1rem; align-self:center; }
.roast-panel-stats { flex-direction:row !important; gap:1.8rem !important; margin-left:1rem; }
.roast-panel-stats > div { display:flex; flex-direction:column; gap:0.1rem; }
.roast-panel-meta { display:flex; flex-direction:column; gap:0.35rem; min-width:15rem; }
.roast-panel-meta .flow-breakdown { margin:0; }
.roast-panel-note { margin:0; font-size:0.9rem; max-width:52ch; }
.roast-panel-foot { flex-basis:100%; margin:0; font-size:0.76rem; opacity:0.55; }

.roast-filter {
  /* Centred, not bottom-aligned: flex-end lines up margin edges, and a select
     carries the global input margin-bottom that a date field doesn't. */
  display:flex; flex-wrap:wrap; align-items:center; gap:1rem; margin-bottom:1.4rem;
}
/* Label beside its control, not above it. A select stretches to full width
   and pushes its label onto the line above; a date input doesn't - so left
   alone, a filter row with both reads as two different layouts. */
.roast-filter .field { display:flex; align-items:center; gap:0.5rem; margin:0; min-width:0; }
.roast-filter select { width:auto; min-width:11rem; margin:0; }
.roast-filter input[type="date"] {
  font-family:var(--body-font); font-size:0.9rem; padding:0.45rem 0.6rem;
  border:1px solid var(--border); border-radius:5px; background:var(--paper); color:var(--ink); margin:0;
}
.roast-filter .field > span {
  font-family:var(--heading-font); font-size:0.66rem; letter-spacing:0.08em;
  text-transform:uppercase; opacity:0.65;
}
.roast-filter select {
  font-family:var(--body-font); font-size:0.9rem; padding:0.45rem 0.6rem;
  border:1px solid var(--border); border-radius:5px; background:var(--paper); color:var(--ink);
}
.pager { margin-top:1rem; font-size:0.85rem; opacity:0.7; }

/* One received delivery: what came, and the carriage that belongs across it. */
.delivery { margin-bottom:1.4rem; }
.delivery-head { display:flex; flex-wrap:wrap; align-items:flex-start; justify-content:space-between; gap:1rem; margin-bottom:1rem; }
.delivery-totals { display:flex; gap:2rem; }
.delivery-totals > span { display:flex; flex-direction:column; gap:0.1rem; font-family:var(--heading-font); }
.delivery .ops-table { margin-bottom:1rem; }
.delivery-foot { display:flex; align-items:center; gap:0.9rem; flex-wrap:wrap; padding-top:0.9rem; }

.mini-head { font-size:0.75rem; margin:0.3rem 0 0; }
/* A sub-section within a page: small heading, a line saying what it's for,
   then its table. Sets the rhythm in one place so sections don't drift
   apart on inline margins, and gives the explanation room to breathe
   before the table starts. */
.sub-section { margin-bottom:2.8rem; }
.sub-section:last-of-type { margin-bottom:0; }
.sub-section > .mini-head { margin:0 0 0.4rem; }
.sub-section > .sub-lede { margin:0 0 1.4rem; max-width:78ch; }
.sub-section > .ops-table { margin-bottom:0; }

/* How to order from a supplier - shown on their page and again on the
   raise-a-request form. Tinted and ruled so it reads as an instruction to
   follow rather than more description, and preserves the line breaks it
   was typed with. */
.supplier-instructions {
  white-space:pre-line;
  margin:0 0 1rem;
  max-width:72ch;
  background:var(--paper-muted);
  border-left:3px solid var(--border);
  border-radius:0 4px 4px 0;
  padding:0.9rem 1.1rem;
  font-size:0.9rem;
}
.green-row { display:grid; grid-template-columns:1fr 120px auto; gap:0.6rem; margin-bottom:0.6rem; align-items:center; }
.roast-preview { display:grid; grid-template-columns:repeat(3,1fr); gap:1rem; padding:1.1rem; background:var(--paper-muted); border-radius:6px; }
.roast-preview--4 { grid-template-columns:repeat(4,1fr); }
.roast-preview--2 { grid-template-columns:repeat(2,1fr); }
.roast-preview > div { display:flex; flex-direction:column; gap:0.25rem; }
.prev-val { font-family:var(--heading-font); font-size:1.15rem; }
.prev-hero { color:var(--success-text); }
.ops-actions { display:flex; gap:0.7rem; margin-bottom:1.5rem; }
/* Stock's headline figure and its primary action, side by side. */
.stock-head { display:flex; align-items:center; gap:1.2rem; margin-bottom:1.8rem; flex-wrap:wrap; }
.stock-head .tile { min-width:240px; }
@media (max-width:520px){ .stock-head .btn { width:100%; text-align:center; } }
@media (max-width:820px){ .ops-form .field-row{grid-template-columns:1fr;} .green-row{grid-template-columns:1fr;} .roast-preview, .roast-preview--4, .roast-preview--2{grid-template-columns:1fr;} }
.tiles--three { grid-template-columns:repeat(3,1fr); }
@media (max-width:820px){ .tiles--three{grid-template-columns:1fr;} }

/* ---- Tasks ----------------------------------------------------------- */
/* The strip at the top of whichever screen you land on.
   Drawn the same as the "For you" box on the Tasks page - white and lifted -
   because it is the same idea, and the two looking different was the
   inconsistency. White rather than tinted for the same reason as there: the
   rows use colour to say overdue, and a tint behind them muddies it.
   Only renders when something is outstanding, so it can afford the room.
   Scoped throughout - an unscoped class redefinition has silently overridden
   the base admin twice on this project. */
.task-strip {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1.05rem 1.3rem 0.5rem;
  margin-bottom: 1.8rem;
  box-shadow: 0 1px 2px rgba(28, 28, 28, 0.04), 0 6px 18px rgba(28, 28, 28, 0.05);
}
.task-strip h2 {
  font-size: 1.05rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink); margin: 0 0 0.5rem;
  display: flex; align-items: center; gap: 0.6rem;
}
.task-strip .task-count {
  background: var(--ink); color: #fff; border-radius: 100px;
  padding: 0.1rem 0.6rem; font-size: 0.8rem; letter-spacing: 0.02em;
}
.task-strip ul { list-style: none; margin: 0; padding: 0; }
.task-strip li {
  display: flex; align-items: flex-start; gap: 0.85rem;
  padding: 0.65rem 0.5rem; border-top: 1px solid var(--border);
  border-radius: 4px;
}
.task-strip li:first-child { border-top: none; }
.task-strip form { margin: 0; }

/* Reads as a control to press, not a badge saying the job is finished. The
   tick sits faint inside an empty ring until you go near it, then the ring
   fills - an unticked box that becomes a ticked one. Big enough to hit with
   a thumb, which is how it gets used in the roastery. */
.task-tick {
  width: 1.9rem; height: 1.9rem; flex: none; padding: 0;
  border: 1.5px solid var(--ink); background: transparent; color: var(--ink);
  border-radius: 50%; cursor: pointer; font-size: 0.95rem; line-height: 1;
  opacity: 0.35; transition: opacity 0.12s, background 0.12s, color 0.12s;
}
.task-tick:hover, .task-tick:focus-visible {
  opacity: 1; background: var(--ink); color: #fff;
}
@media (prefers-reduced-motion: reduce) { .task-tick { transition: none; } }

.task-strip .task-body { display: flex; flex-direction: column; gap: 0.1rem; }
.task-strip .task-detail { font-size: 0.86rem; opacity: 0.75; }
.task-strip .task-meta { font-size: 0.78rem; opacity: 0.55; }
/* Overdue carries the same amber as an overdue row on the Tasks page, so the
   two places say it the same way - and the whole row, not just the words. */
.task-strip li.is-overdue, .team-list li.is-overdue { position: relative; z-index: 0; }
.task-strip li.is-overdue::before, .team-list li.is-overdue::before { content: ''; position: absolute; top: 5px; bottom: 5px; left: 0; right: 0; border-radius: 6px; background: var(--warn-bg); z-index: -1; }
.task-strip li.is-overdue .task-meta { opacity: 0.85; }
.task-strip li.is-overdue .task-meta strong { color: #8a2c1a; }
.task-strip li.is-today .task-meta strong { color: var(--warn-text); }

/* A completed task should read as completed on its own, not only by which
   table it happens to be sitting in. Green because it's the one place in the
   Hub where green means "this is finished" rather than "this is fine".
   Filled rather than tinted: a pale wash at this size read as a smudge from
   any distance, and this is meant to be the thing you see first. It sits in
   its own gutter column, so it can't shunt the task titles out of line with
   the table above. */
.task-done-tick {
  display: flex; align-items: center; justify-content: center;
  width: 1.35rem; height: 1.35rem;
  border-radius: 50%; background: var(--success-text); color: #fff;
  font-size: 0.8rem; line-height: 1; font-weight: 700;
}

/* The counterpart to the done tick: same shape and gutter, deliberately grey
   and hollow so a cancelled row never reads as an achievement at a glance. */
.task-cancelled-tick {
  display: flex; align-items: center; justify-content: center;
  width: 1.35rem; height: 1.35rem;
  border-radius: 50%; border: 1.5px solid var(--border); color: var(--ink);
  opacity: 0.45; font-size: 0.8rem; line-height: 1; font-weight: 700;
}

/* A count beside a section heading. Same shape as the nav badge but quiet -
   it reports a size, it isn't asking for attention. */
.count-chip {
  display: inline-block; background: var(--paper-muted); color: var(--ink);
  border: 1px solid var(--border); border-radius: 100px;
  padding: 0.1rem 0.6rem; font-size: 0.8rem; letter-spacing: 0.02em;
  vertical-align: 0.1em; opacity: 0.85;
}

/* The hand-over picker sits in a row of buttons, so it has to read as one of
   them rather than as a form field: same height, same weight, no stray margin
   from the global input rule. */
.hand-over select {
  width: auto; margin: 0; padding: 0.4rem 0.5rem;
  font-family: var(--heading-font); font-weight: 700;
  font-size: 0.7rem; letter-spacing: 0.08em;
  /* No text-transform: it shouted the names in the list. The placeholder is
     written in caps instead, so the control matches the buttons next to it
     and people are still called what they were called. */
  border: 1px solid var(--accent); border-radius: 4px;
  background: transparent; color: var(--ink); cursor: pointer;
}

/* A folded section on the Tasks page - the closed records, which are there to
   be consulted rather than read every time. Styled as a heading rather than a
   form control: same rank as the sections above it, just shut. */
.task-fold { margin-top: 2.5rem; }
.task-fold > summary {
  font-family: var(--heading-font); font-weight: 700;
  font-size: 1.2rem; letter-spacing: 0.08em; text-transform: uppercase;
  cursor: pointer; list-style: none; display: flex; align-items: center; gap: 0.6rem;
  opacity: 0.55;
}
.task-fold > summary:hover { opacity: 0.8; }
.task-fold[open] > summary { opacity: 1; margin-bottom: 0.6em; }
/* The default triangle differs per browser; draw our own so it matches. */
.task-fold > summary::-webkit-details-marker { display: none; }
.task-fold > summary::after {
  content: '▸'; font-size: 0.8rem; opacity: 0.6; transition: transform 0.15s;
}
.task-fold[open] > summary::after { content: '▾'; }
@media (prefers-reduced-motion: reduce) { .task-fold > summary::after { transition: none; } }

/* The two halves of your open work, each in its own box so the boundary is
   unmistakable.
   White, not tinted: the rows already use colour to mean something - amber
   for overdue, green for done - and a tinted panel behind them turned that
   into competing washes. So the box is drawn with an edge and a lift instead
   of a fill, and colour stays reserved for meaning.
   Yours is a raised white card; what you're waiting on is a flat outline.
   Both obviously rectangles, one obviously nearer - the lift does that work,
   so no accent edge is needed on top of it. */
.task-section {
  border-radius: 10px;
  padding: 1.15rem 1.35rem 0.85rem;
  margin-top: 1.7rem;
  border: 1px solid var(--border);
}
.task-section:first-of-type { margin-top: 1.6rem; }
.task-section > h2 {
  font-size: 1.05rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink); margin: 0 0 0.55rem;
  display: flex; align-items: center; gap: 0.6rem;
}
.task-section--mine {
  background: #fff;
  box-shadow: 0 1px 2px rgba(28, 28, 28, 0.04), 0 6px 18px rgba(28, 28, 28, 0.05);
}
/* Flat and unfilled - present, clearly a step back from the card above it. */
.task-section--waiting { background: transparent; }
.task-section--waiting > h2 { opacity: 0.5; }
/* Inside a box, the table's own outer rules read as stray lines and its
   bottom margin stacks with the box's padding into a slack gap. */
.task-section .ops-table { margin-bottom: 0; }
.task-section .ops-table tbody tr:last-child td { border-bottom: none; }
.task-section .section-empty { margin: 0 0 0.7rem; }

/* ---- Tables on a phone ------------------------------------------------ */
/* Six columns never fitted a phone, and sliding a table sideways to find
   the rest of a row - or the button at the end of it - was the wrong answer
   everywhere, not just on Tasks. So below this width every table with
   column headings stops being a grid and becomes a stack of cards, one per
   row: the row's name on top, then its figures, each under a small label
   taken from its column heading, then its buttons at the right.

   The script in foot.ejs does the part CSS can't - it copies each heading
   onto the cells beneath it as data-label, and marks the row's name
   (cell-lead), its buttons (cell-actions) and anything empty (is-blank).
   It adds `cards` to the tables it has done that for; anything it passes
   over keeps the scroll box below.

   A template can steer this: class="cell-lead" on the cells that name the
   row when that isn't simply the first one (an order is its number AND its
   company); class="cell-sub" on one that belongs under the title as a
   subtitle; data-label="" on a cell whose content explains itself, like a
   status badge or a date; class="table-flat" on a table that fits a phone
   as it is. */
@media (max-width: 760px) {
  table.cards, table.cards tbody, table.cards tfoot { display: block; }
  table.cards thead, table.cards colgroup { display: none; }

  table.cards tr {
    /* Figures sit level along their last line, whatever size each is set
       in, and a badge sits level with the figures rather than their labels.
       flex-end first for a browser that doesn't know `last baseline`. */
    display: flex; flex-wrap: wrap;
    align-items: flex-end; align-items: last baseline;
    column-gap: 1rem;
    padding: 0.85rem 0.6rem;
    border-bottom: 1px solid var(--border);
  }
  /* display:block also beats `td.row-sub { display: table-cell }`. */
  table.cards td {
    display: block; order: 2;
    min-width: 0; max-width: 100%;
    margin-top: 0.45rem; padding: 0; border: none;
    text-align: left; overflow-wrap: break-word;
  }
  /* Figures are right-aligned in a column so they tot up; in a card there's
     no column, and a figure pushed right under its label looks misplaced. */
  table.cards td.num { text-align: left; }
  /* A small second line in a narrow column - the time under a date - runs
     on beside it instead; under the title it stays a line of its own. */
  table.cards tbody td:not(.cell-lead) .row-sub { display: inline; margin-left: 0.3rem; }
  table.cards td.is-blank { display: none; }
  /* A cell spanning the whole row - "Nothing yet", or a roast's fold-out
     panel - is the whole card. */
  table.cards tbody td[colspan] { flex-basis: 100%; }

  /* The row's name first, on a line of its own. The zero-height ::before
     sits between it and the rest (order 1) and, being full width, is what
     forces the break. */
  table.cards td.cell-lead { order: 0; margin-top: 0; align-self: center; font-weight: 600; }
  /* Two cells naming one row - "#95" and "Melinsey Mill" - read as one title. */
  table.cards td.cell-lead:not(.is-blank) + td.cell-lead { margin-left: -0.5rem; }
  table.cards td.cell-lead .row-sub,
  table.cards td.cell-lead .muted { font-weight: 400; }
  table.cards tr.has-lead::before { content: ""; order: 1; flex-basis: 100%; height: 0; }
  /* class="cell-sub": a subtitle under the title, on its own line - an
     email under the company it belongs to. */
  table.cards td.cell-sub {
    order: 1; flex-basis: 100%; margin-top: 0.1rem;
    font-size: 0.82rem; opacity: 0.65;
  }

  /* Labels sit above their figures, so a row of numbers reads like the
     little stat blocks it is: ON HAND 12 kg · UNIT COST £8.20 · VALUE £98. */
  table.cards td[data-label]:not([data-label=""]):not(.cell-lead)::before {
    content: attr(data-label);
    display: block; margin-bottom: 0.1rem;
    font-family: var(--heading-font); font-size: 0.6rem; font-weight: 700;
    letter-spacing: 0.08em; text-transform: uppercase; white-space: nowrap;
    opacity: 0.5;
  }
  /* A floor under each labelled block, so short figures on one card line up
     with the ones on the next instead of each block hugging its own. */
  table.cards td[data-label]:not([data-label=""]):not(.cell-lead) { min-width: 4.8rem; }

  /* Buttons last, pushed to the right edge as they are on a desktop - each
     group of them, so one that wraps onto a line of its own stays right too. */
  table.cards td.cell-actions { order: 3; margin-left: auto; }
  table.cards .row-actions { flex-wrap: wrap; justify-content: flex-end; }

  /* Row highlights move from the cells to the card, so a low-stock or
     overdue row is one tinted block rather than tinted patches. */
  table.cards tr.is-low { position: relative; z-index: 0; }
  table.cards:not(.product-list) tr.is-low::after { content: ''; position: absolute; top: 5px; bottom: 5px; left: 0; right: 0; border-radius: 8px; background: var(--warn-bg); z-index: -1; }
  table.cards.product-list tr.is-low { background: var(--warn-bg); }

  /* A category's name heading its products - a line to itself, not a card. */
  table.cards tr.group-row { padding: 1.8rem 0.6rem 0.5rem; }
  table.cards tbody:first-of-type tr.group-row { padding-top: 0.4rem; }
  table.cards tr.group-row th { flex-basis: 100%; padding: 0; border: none; }

  /* Totals read like the bottom of a receipt: what it is on the left, the
     figure on the right, on one line. */
  table.cards tfoot { border-top: 2px solid var(--border); padding-top: 0.3rem; }
  table.cards tfoot tr { align-items: baseline; padding: 0.3rem 0.6rem; border-bottom: none; }
  table.cards tfoot td { order: 0; margin-top: 0; flex-basis: auto; }
  table.cards tfoot td:first-child { flex: 1 1 auto; text-align: right; }
  table.cards tfoot td.cell-actions { flex-basis: 100%; margin: 0.3rem 0 0; text-align: right; }

  /* class="actions-top": the row's buttons sit up on its title line, at
     the right - "View" beside the order it opens - instead of trailing
     after the details, where they landed on whichever line the badges
     happened to leave. The title takes the room left beside them and wraps
     inside it rather than pushing them down. */
  table.cards.actions-top td.cell-actions { order: 0; margin: 0 0 0 auto; }
  table.cards.actions-top td.cell-lead:not(:has(~ td.cell-lead)) { flex: 1 1 0; }
  /* Everything on the title line level with its first line of words, so a
     name that wraps ("C-Bay Apartments" over its For collection flag)
     doesn't leave the order number floating halfway down beside it. */
  table.cards.actions-top td.cell-lead,
  table.cards.actions-top td.cell-actions,
  table.cards.actions-top td.status-cell { align-self: baseline; }
  /* class="cell-line": a detail with a whole line to itself, so it's in the
     same place on every card - a date after badges, however many there
     are. */
  table.cards td.cell-line { flex-basis: 100%; margin-top: 0.35rem; }

  /* class="status-cell" (with is-active when it is): an account's status
     beside its name. Active is the norm and goes unsaid on a card; only a
     disabled one shows, as a pill by the name. */
  table.cards td.status-cell { order: 0; margin: 0 0 0 0.6rem; align-self: center; }
  table.cards td.status-cell.is-active { display: none; }

  /* An order's For collection pill. Beside the company on a card's title
     line it had no room - View is there too - and wrapped under the name,
     indented by the order number, out of line with everything below it. So
     where a row carries the card copy (pill--on-card), that one leads the
     badges instead, flush left like them (Angel, 14 Sept). display:contents
     lets its badges and the Fulfillment one flow as one set, evenly spaced
     and wrapping only when they run out of room: kept as a box, a cell that
     wrapped at all took the whole line and pushed the next badge under it. */
  table.cards tr:has(.pill--on-card) .name-with-flag .pill--collect { display: none; }
  table.cards .pill--on-card { display: inline-block; }
  table.cards td.badge-cell:not(.is-blank) { display: contents; }
  table.cards td.badge-cell > * { order: 2; margin-top: 0.45rem; }

  /* Customers: a contact card - company and View / edit, then the person,
     their email and their phone, a line each. */
  table.cards.customer-list td.cell-line { margin-top: 0.15rem; }
  table.cards.customer-list td.cell-line:nth-child(2) { margin-top: 0.3rem; }

  /* Team: a person per card - name and role, the email under them, and the
     buttons as an even grid across the bottom, two to a row at one width,
     instead of wrapping wherever the row happened to run out. */
  table.cards.team-list td.cell-line { margin-top: 0.2rem; }
  table.cards.team-list td.role-cell { order: 0; margin: 0 0 0 0.6rem; align-self: center; font-size: 0.8rem; }
  table.cards.team-list td.cell-actions { flex-basis: 100%; margin: 0.85rem 0 0; }
  table.cards.team-list .row-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; }
  table.cards.team-list .row-actions form { margin: 0; }
  table.cards.team-list .row-actions .btn,
  table.cards.team-list .row-actions button { display: block; width: 100%; }

  /* Products: the arrows beside the product's name (they move it up and
     down the list, so that's where they belong), then its three facts on
     one line, then Edit, Duplicate and Hide together as one neat group -
     never spread apart, whatever the width. Its own running order, since
     the arrows come first in the row but go up on the name's line:
     name 1, arrows 2, break 3, facts 4, break 5, buttons 6. */
  table.cards.product-list tr { align-items: flex-start; }
  table.cards.product-list td.cell-lead { order: 1; }
  table.cards.product-list td.cell-lead:not(:has(~ td.cell-lead)) { flex: 1 1 0; }
  table.cards.product-list td.cell-actions:first-child { order: 2; margin: 0 0 0 0.8rem; align-self: center; }
  table.cards.product-list td.cell-actions:first-child .btn-small { padding-left: 0.55rem; padding-right: 0.55rem; }
  table.cards.product-list tr.has-lead::before { order: 3; }
  table.cards.product-list td:not(.cell-lead):not(.cell-actions) { order: 4; }
  table.cards.product-list tr::after { content: ""; order: 5; flex-basis: 100%; height: 0; }
  table.cards.product-list td.cell-actions:last-child { order: 6; margin: 0.85rem 0 0; }
  table.cards.product-list td.cell-actions:last-child .row-actions { justify-content: flex-start; gap: 0.5rem; }
  /* The facts share their line, but only up to a column's width each: on
     a phone turned sideways they sit as even columns rather than drifting
     to the far edges. */
  table.cards.product-list td[data-label]:not([data-label=""]):not(.cell-lead) { min-width: 0; flex: 1 1 auto; max-width: 10rem; }
}

/* ---- Wide tables on a phone that stay tables -------------------------- */
/* A table wider than the screen used to drag the whole page sideways with
   it, so headings and buttons sat off-screen with nothing to say they were
   there. Most tables become cards now (above); what's left - a table with
   no headings, or one marked table-flat - becomes its own scroll box if it
   still doesn't fit, so the page stays put and only the table slides.
   display:block makes the table a block container whose rows lay themselves
   out in an anonymous table box - that box sizes to its content and can
   overflow, which is exactly what we want it to do. */
@media (max-width: 760px) {
  /* The fixed percentage columns that keep these tables aligned on a desktop
     turn into slivers at phone width, and `overflow-wrap: anywhere` then
     breaks words a letter at a time - "Prin / t and / send". On a phone the
     columns size to their content instead. */
  .ops-table--fixed:not(.cards) { table-layout: auto; }
  .ops-table--fixed:not(.cards) td, .ops-table--fixed:not(.cards) th { overflow-wrap: normal; }

  .container table:not(.cards) {
    display: block;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    /* A shadow at whichever edge still has content behind it, so a table
       you can slide looks like one. Two fixed gradients paint the shadows
       and two that scroll with the content cover them up when you reach an
       end - the trick being `local` vs `scroll` attachment, which means no
       JavaScript has to measure anything. Buttons live at the right-hand
       edge of most of these tables, so without a hint they'd simply look
       missing. */
    background:
      linear-gradient(to right, var(--paper) 40%, rgba(253, 252, 250, 0)) left center / 28px 100% no-repeat local,
      linear-gradient(to left, var(--paper) 40%, rgba(253, 252, 250, 0)) right center / 28px 100% no-repeat local,
      radial-gradient(farthest-side at 0 50%, rgba(28, 28, 28, 0.16), rgba(28, 28, 28, 0)) left center / 13px 100% no-repeat scroll,
      radial-gradient(farthest-side at 100% 50%, rgba(28, 28, 28, 0.16), rgba(28, 28, 28, 0)) right center / 13px 100% no-repeat scroll;
  }
}

/* ---- Task rows on a phone --------------------------------------------- */
/* Five columns and two buttons never fitted a phone. Sliding a table to
   reach Done is the wrong answer on the page people open most, so each task
   stops being a row and becomes a block: title, then the facts, then the
   buttons. The column headings go, and each cell names itself instead. */
@media (max-width: 760px) {
  .task-section .ops-table,
  .task-section .ops-table tbody,
  .task-section .ops-table tr,
  .task-section .ops-table td { display: block; width: auto; }
  .task-section .ops-table thead { display: none; }
  .task-section .ops-table colgroup { display: none; }
  /* Stacked, these never slide, so the sliding table's edge shading has
     nothing to hint at - and painted in the page colour it showed as two
     pale stripes down the sides of the white For you box. */
  .container .task-section .ops-table { background: none; overflow: visible; }

  .task-section .ops-table tr {
    padding: 0.85rem 0;
    border-bottom: 1px solid var(--border);
  }
  .task-section .ops-table tr:last-child { border-bottom: none; }
  /* An overdue task is one band, set in from the lines (see .ops-table
     tr.is-low); its ::after, as each cell's ::before is its label. */
  .task-section .ops-table tr.is-low { position: relative; z-index: 0; padding-left: 0.6rem; padding-right: 0.6rem; }
  .task-section .ops-table tr.is-low::after { content: ''; position: absolute; top: 5px; bottom: 5px; left: 0; right: 0; border-radius: 8px; background: var(--warn-bg); z-index: -1; }
  .task-section .ops-table td {
    border: none; padding: 0.1rem 0; min-width: 0;
  }
  .task-section .ops-table td[data-label]::before {
    content: attr(data-label) " ";
    font-family: var(--heading-font); font-size: 0.62rem;
    letter-spacing: 0.08em; text-transform: uppercase;
    opacity: 0.45; margin-right: 0.35rem;
  }
  /* The facts read as one line each rather than a heading and a value on
     two, so a stacked row stays short enough to scan. */
  .task-section .ops-table td .row-sub { display: inline; margin-left: 0.3rem; }
  .task-section .ops-table td strong + .row-sub { display: block; margin-left: 0; }
  .task-section .ops-table .row-actions {
    justify-content: flex-start; margin-top: 0.6rem;
  }
}

/* ---- Task notes ------------------------------------------------------- */
/* A task title opens the task. Styled as the title, not as a link - it's
   the thing you tap, and underlining every task on the page would be noise. */
.task-link { color: inherit; text-decoration: none; }
.task-link:hover strong, .task-link:hover { text-decoration: underline; text-underline-offset: 0.18em; }

/* How many notes a task has. Quiet when it's just history; in the same
   russet as the alert pills when something's unread, because that's the one
   asking for you. */
.note-pill {
  display: inline-block; margin-left: 0.45rem; vertical-align: 0.1em;
  padding: 0.05rem 0.5rem; border-radius: 100px;
  font-family: var(--heading-font); font-size: 0.62rem; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase; text-decoration: none;
  background: var(--paper-muted); color: var(--ink); border: 1px solid var(--border);
  white-space: nowrap;
}
.note-pill--new { background: #fbe7e3; color: #8a2c1a; border-color: transparent; }

/* The task's own page. */
.task-title { text-transform: none; letter-spacing: 0.01em; font-size: 1.5rem; margin-bottom: 0.7rem; }
.task-facts { display: flex; flex-wrap: wrap; gap: 0.35rem 1.4rem; font-size: 0.92rem; }
.fact-label {
  font-family: var(--heading-font); font-size: 0.64rem; letter-spacing: 0.08em;
  text-transform: uppercase; opacity: 0.5; margin-right: 0.25rem;
}
.fact-overdue { color: #8a2c1a; font-weight: 600; }
.task-brief {
  margin: 1.1rem 0 0; padding: 0.8rem 1rem; max-width: 60ch;
  background: var(--paper-muted); border-radius: 6px;
}
.task-detail-actions { margin-top: 1.2rem; }
.task-detail-actions .row-actions { justify-content: flex-start; }
.task-closed { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem 0.8rem; margin-top: 1.2rem; font-weight: 600; }
.task-closed form { margin: 0; }

.task-notes { margin-top: 2.4rem; }
.task-notes h2 { margin-bottom: 0.9rem; }
.note-log { list-style: none; margin: 0 0 1.4rem; padding: 0; }
.note-log li {
  padding: 0.8rem 1rem; margin-bottom: 0.6rem;
  background: #fff; border: 1px solid var(--border); border-radius: 8px;
}
/* What you hadn't seen before opening the page - so you can find the new
   part of a long log without rereading all of it. */
.note-log li.is-new { border-color: #e7b3a8; box-shadow: 0 0 0 3px #fbe7e3; }
.note-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.3rem 0.7rem; margin-bottom: 0.3rem; }
.note-head .note-pill { margin-left: 0; }
/* pre-line keeps the line breaks someone typed; overflow-wrap stops a long
   pasted link forcing the page wider than a phone. */
.note-body { white-space: pre-line; overflow-wrap: anywhere; max-width: 65ch; }
.note-form { max-width: 60ch; }
.note-form textarea { min-height: 90px; margin-bottom: 0.7rem; }
.note-form .form-hint { margin-top: 0.5rem; }

/* The second list in the home strip: updates on tasks you gave out. */
.task-strip h2.strip-second { margin-top: 1.1rem; }
.task-strip li.note-update { padding-left: 0.5rem; }
.task-strip .note-quote { font-style: normal; opacity: 0.85; }

/* ---- Team tasks ------------------------------------------------------- */
/* A box per person, so "who's on what" and "who's free" read at a glance.
   Yours is lifted like the For you box on the Tasks page; everyone else's
   is a flat outline, the same two ranks used there. */
.team-person {
  border: 1px solid var(--border); border-radius: 10px;
  padding: 1rem 1.3rem 0.6rem; margin-top: 1.3rem;
}
.team-person--you {
  background: #fff;
  box-shadow: 0 1px 2px rgba(28, 28, 28, 0.04), 0 6px 18px rgba(28, 28, 28, 0.05);
}
.team-person h2 {
  font-size: 1rem; letter-spacing: 0.08em; margin: 0 0 0.6rem;
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem;
}
.team-you, .team-where {
  font-family: var(--body-font); font-weight: 600; font-size: 0.72rem;
  letter-spacing: 0.04em; text-transform: none; opacity: 0.55;
}
.team-you { opacity: 1; background: var(--ink); color: #fff; border-radius: 100px; padding: 0.05rem 0.5rem; }
.team-free { margin: 0 0 0.5rem; }
.team-list { list-style: none; margin: 0; padding: 0; }
.team-list li {
  display: flex; flex-direction: column; gap: 0.12rem;
  padding: 0.6rem 0.5rem; border-top: 1px solid var(--border); border-radius: 4px;
}
.team-list li:first-child { border-top: none; }
.team-meta { font-size: 0.8rem; opacity: 0.6; }
.team-latest {
  font-size: 0.86rem; margin-top: 0.2rem; padding-left: 0.6rem;
  border-left: 2px solid var(--border); overflow-wrap: anywhere;
}
.team-latest strong { font-weight: 600; }

/* Said plainly on a task that isn't yours, where the buttons would be. */
.task-readonly { margin-top: 1.2rem; opacity: 0.7; font-size: 0.9rem; }

/* ---- Stock: one page for what you hold, what's coming, and what to do ----
   A row is a sentence and a bar: the bar fills with what's actually on the
   shelf, the striped part is what's on its way, and the upright mark is the
   level you said to reorder at. Reading a level stops being arithmetic. */
.sr-only { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }
.tiles--two { grid-template-columns:repeat(2,1fr); }
.stock-find { flex:1; min-width:180px; margin:0; }
.stock-find input { width:100%; margin-bottom:0; }
.stock-list .group-head { display:flex; align-items:baseline; justify-content:space-between; gap:1rem; }
/* The group's worth, set as a figure rather than a footnote: it's the one
   number on the heading anyone looks for. */
.group-sum { display:flex; align-items:baseline; flex-wrap:wrap; justify-content:flex-end; column-gap:0.5rem; font-family:var(--body-font); letter-spacing:0; text-transform:none; text-align:right; }
.group-sum-label { font-size:0.72rem; font-weight:400; opacity:0.6; }
.group-sum-figure { font-size:1.35rem; font-weight:700; color:var(--ink); font-variant-numeric:tabular-nums; }
.group-sum-note { flex-basis:100%; font-size:0.72rem; font-weight:600; color:var(--warn-text); }
.stock-group[hidden] { display:none; }
.stock-off-row { display:flex; flex-wrap:wrap; align-items:baseline; gap:0.2rem 0.9rem; padding:0.7rem 0.9rem; border:1px solid var(--border); border-radius:6px; margin-bottom:0.4rem; }
.stock-off .row-sub:last-child { margin-left:auto; }
/* Fixed tracks rather than "auto": each row is its own box, so without them a
   long name or a wider pill shifted that row's figures out of line with the
   one above. Four columns across, and one line of detail underneath spanning
   the lot - so there is one left edge for the small print, not two. */
.stock-row { display:grid; grid-template-columns:minmax(0,1fr) 6rem 13rem 8.5rem;
  grid-template-areas:"name qty bar state" "sub sub sub sub";
  gap:0.3rem 1.2rem; align-items:center; padding:0.8rem 1rem; margin-bottom:0.5rem; border:1px solid var(--border); border-radius:6px; background:var(--paper); text-decoration:none; color:inherit; }
.stock-row:hover, .stock-row:focus-visible { border-color:var(--ink); }
.stock-row[hidden] { display:none; }
.st-name { grid-area:name; min-width:0; }
/* Ends on the same line all the way down: lining the figures up is most of
   what makes a list of them readable. */
.st-qty { grid-area:qty; text-align:right; font-variant-numeric:tabular-nums; font-weight:600; }
.st-unit { font-weight:400; opacity:0.72; }
.st-bar { grid-area:bar; }
.st-state { grid-area:state; text-align:right; }
.st-sub { grid-area:sub; font-size:0.78rem; opacity:0.72; }
/* The track and its fills are clipped to the rounded ends in .lvl-fill, so
   the minimum line can stand proud of the bar above and below - a line
   inside a 10px bar, black on dark brown, was easy to miss (Angel, 19 Sept). */
.lvl { position:relative; display:block; height:10px; }
.lvl-fill { display:flex; height:100%; border-radius:100px; background:var(--paper-muted); overflow:hidden; }
.lvl-here { background:var(--success-text); }
.is-ordered .lvl-here, .is-low .lvl-here { background:var(--warn-text); }
.is-out .lvl-here { background:#8a2c1a; }
.lvl-coming { background:repeating-linear-gradient(45deg, rgba(28,28,28,0.28) 0 4px, rgba(28,28,28,0.10) 4px 8px); }
.lvl-mark { position:absolute; top:-5px; bottom:-5px; width:3px; margin-left:-1.5px; border-radius:2px; background:var(--ink); box-shadow:0 0 0 2px var(--paper); }
.lvl-text { display:block; margin-top:0.45rem; font-size:0.78rem; opacity:0.72; }
.stock-none { margin:2rem 0; opacity:0.72; }
/* Inventory's More menu (1 Oct): the jobs needed now and then. */
.more-menu { position:relative; }
.more-menu > summary { list-style:none; display:inline-flex; align-items:center; gap:0.35rem; cursor:pointer; }
.more-menu > summary::-webkit-details-marker { display:none; }
.more-menu[open] > summary svg { transform:rotate(180deg); }
.more-menu-list { position:absolute; right:0; top:calc(100% + 0.4rem); z-index:50; width:max-content; max-width:min(20rem, 90vw); display:flex; flex-direction:column;
  padding:0.35rem; background:var(--paper); border:1px solid var(--border); border-radius:6px; box-shadow:0 8px 24px rgba(28,28,28,0.1); }
.more-menu-list a { display:flex; flex-direction:column; gap:0.15rem; padding:0.6rem 0.8rem; border-radius:4px; color:var(--ink); text-decoration:none; }
.more-menu-list a:hover { background:var(--paper-muted); }
.more-menu-list strong { font-size:0.9rem; }
.more-menu-list span { font-size:0.78rem; opacity:0.65; }
/* Hidden items at the foot of Inventory, each with the way back. */
.stock-hidden { margin-top:2rem; font-size:0.9rem; }
.stock-hidden > summary { cursor:pointer; opacity:0.75; }
.stock-hidden-list { list-style:none; margin:0.6rem 0 0; padding:0; max-width:36rem; }
.stock-hidden-list li { display:flex; align-items:center; justify-content:space-between; gap:1rem; padding:0.45rem 0; border-bottom:1px solid var(--border); }
.stock-hidden-list form { margin:0; }
/* A product page's foot: Save and Cancel, then Archive / Delete at the far end. */
.prod-actions { display:flex; flex-wrap:wrap; align-items:center; gap:0.6rem; margin-top:1.5rem; }
.prod-actions-end { margin-left:auto; display:flex; flex-wrap:wrap; align-items:center; gap:0.6rem; }
.prod-actions-note { font-size:0.8rem; opacity:0.72; }

/* Products' Status: Active or Hidden (Active ticked off), 1 Oct. */
.badge-product-active { background: var(--success-bg); color: var(--success-text); }
.badge-product-hidden { background: #efefef; color: #5c5c5c; }
.badge-product-archived { background: #efe9df; color: #6b5a3e; }

@media (max-width:1100px) { .stock-row { grid-template-columns:minmax(0,1fr) 5.5rem minmax(0,9rem) 8.5rem; } }
@media (max-width:760px) {
  /* Name, then the amount and the word that says what to do beside it; the
     bar goes across underneath, where a short one still reads. */
  .stock-row { grid-template-columns:minmax(0,1fr) auto;
    grid-template-areas:"name state" "qty state" "bar bar" "sub sub"; padding:0.9rem; }
  .st-qty { text-align:left; }
  .st-state { align-self:start; }
}
/* On a phone the three figures stack into a screenful before the list. Value
   takes the top line, and the two counts sit beside each other under it. */
@media (max-width:820px) {
  .tiles--three { grid-template-columns:repeat(2,1fr); }
  .tiles--three .tile:first-child { grid-column:span 2; }
}

/* ---- Roasting, above the log: what to roast, and how it's been going ----
   The panels read left to right like the job does: the coffee, how much is
   left, the button with the amount already on it. */
.panel { border:1px solid var(--border); border-radius:6px; padding:1.2rem 1.3rem; margin-bottom:1.6rem; background:var(--paper); }
.panel-h { display:flex; flex-wrap:wrap; align-items:baseline; gap:0.4rem 0.9rem; margin-bottom:1rem; }
.panel-h h2 { margin:0; }
.panel-h p { margin:0; font-size:0.8rem; opacity:0.72; }
/* One grid for the whole panel, with each row's cells flowing into it
   (display:contents). A grid per row sized its own columns to its own
   contents, so a wide button on one line pushed that line's bar out of step
   with the rest - which is exactly what you notice first. */
/* Only what needs doing, until the toggle says otherwise. A row is
   display:contents on the wide layout, so it's its cells that go. */
.roast-next.only-todo .rn-row--fine > * { display:none; }
.plan-none { margin:0; opacity:0.72; }
.panel-h .plan-toggle { margin-left:auto; }
.roast-next { display:grid; grid-template-columns:minmax(0,1.1fr) minmax(0,1.5fr) auto; gap:1rem 1.4rem; align-items:center; }
.rn-row { display:contents; }
.rn-bar .lvl { margin:0; }
.rn-do { justify-self:end; text-align:right; }
.rn-do .btn-small { white-space:nowrap; }
.is-low .lvl-here { background:var(--warn-text); }
@media (max-width:820px) {
  /* Too narrow for three columns: each row becomes its own small grid again,
     name and button on one line, the bar across the next. Stretched, or the
     centring the three-column layout needs would shrink each row to its own
     width and step them all in from the left (Angel, 20 Sept, on a phone). */
  .roast-next { display:flex; flex-direction:column; align-items:stretch; gap:1.1rem; }
  .roast-next.only-todo .rn-row--fine { display:none; }
  .rn-row { display:grid; grid-template-columns:minmax(0,1fr) auto; gap:0.5rem 1rem; align-items:center; }
  .rn-bar { grid-column:1 / -1; }
}

/* A save bar that follows you down a long list of rows to type into. */
.save-bar { position:sticky; bottom:0; display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:1rem; margin-top:1.4rem; padding:0.9rem 1.1rem; border:1px solid var(--border); border-radius:6px; background:var(--paper); box-shadow:0 -6px 18px rgba(28,28,28,0.06); }
.plan-warn { margin:-0.4rem 0 1rem; padding:0.6rem 0.8rem; border-radius:6px; background:var(--warn-bg); color:var(--warn-text); font-size:0.85rem; }
.plan-warn a { color:inherit; }
/* Under the pick list it follows rows rather than a heading, so it wants
   room of its own instead of the tuck-up the panels are after. */
/* The pick list folded to its heading. */
/* A firmer outline than the other panels, so the pick list stands out at
   the top of the floor's Orders (Angel, 28 Sept - "a bit unnoticeable",
   then "slightly less bold"). */
.panel.pick-panel { border:1.5px solid rgba(28, 28, 28, 0.55); }
.panel.pick-panel > summary:hover .pick-toggle { opacity:1; }
.pick-panel > summary { list-style:none; cursor:pointer; margin-bottom:0; }
.pick-panel > summary::-webkit-details-marker { display:none; }
.pick-panel[open] > summary { margin-bottom:1rem; }
.pick-toggle { margin-left:auto; width:0.6rem; height:0.6rem; border-right:2px solid currentColor; border-bottom:2px solid currentColor; transform:rotate(45deg); transition:transform 0.15s; opacity:0.6; }
.pick-panel[open] .pick-toggle { transform:rotate(-135deg); }
.pick-list + .plan-warn, .plan-warn + .plan-warn { margin-top:1.4rem; padding:0.9rem 1.1rem; line-height:1.55; }

/* ---- Counting the shelves ----
   A row you can work down with one hand on the keyboard: what the system
   says, what you counted, and the size of the disagreement. */
.count-list { display:flex; flex-direction:column; gap:0.4rem; }
.count-group[hidden] { display:none; }
.count-row { display:grid; grid-template-columns:minmax(0,1fr) 9rem 9rem 7rem; gap:0.6rem 1rem; align-items:center; padding:0.7rem 1rem; border:1px solid var(--border); border-radius:6px; background:var(--paper); margin-bottom:0.4rem; }
.count-row.is-diff { border-color:var(--warn-text); background:var(--warn-bg); }
.count-row.is-same { border-color:var(--success-text); }
.count-label { display:block; font-family:var(--heading-font); font-size:0.6rem; letter-spacing:0.08em; text-transform:uppercase; opacity:0.72; }
.count-figure { font-variant-numeric:tabular-nums; }
.count-field { margin:0; }
.count-field input { margin:0; width:100%; font-variant-numeric:tabular-nums; }
.count-diff { font-family:var(--heading-font); font-size:0.8rem; text-align:right; font-variant-numeric:tabular-nums; }
.is-diff .count-diff { color:var(--warn-text); }
.is-same .count-diff { color:var(--success-text); }
@media (max-width:760px) {
  .count-row { grid-template-columns:1fr 7rem; }
  .count-name { grid-column:1 / -1; }
  .count-diff { text-align:left; }
}

/* ---- The pick list: one walk to the shelves for all the waiting orders ---- */
.pick-list { display:flex; flex-direction:column; gap:0.35rem; }
.pick-row { display:grid; grid-template-columns:7rem minmax(0,1fr) auto; gap:0.6rem 1rem; align-items:center; padding:0.55rem 0.7rem; border-radius:6px; background:var(--paper-muted); }
.pick-row.is-short { background:var(--warn-bg); }
.pick-qty { font-family:var(--heading-font); font-size:1.05rem; font-variant-numeric:tabular-nums; }
.pick-name { font-size:1rem; }
.pick-have { text-align:right; }
@media (max-width:640px) {
  .pick-row { grid-template-columns:5.5rem minmax(0,1fr); }
  .pick-have { grid-column:1 / -1; text-align:left; }
}
/* A tick box beside a row, not inside it: the row is a link to the thing.
   Only where there is one - the floor can't order, and a two-column grid
   holding a single row put that row in the "auto" column, where it shrank to
   fit its own words. That is what made the floor's cards each a different
   width while the office's lined up. */
.stock-line { display:block; }
.stock-line--tick { display:grid; grid-template-columns:auto minmax(0,1fr); align-items:center; gap:0.7rem; }
.stock-line[hidden], .stock-line--tick[hidden] { display:none; }
.stock-line .stock-row { margin-bottom:0; }
.stock-list .stock-line + .stock-line { margin-top:0.5rem; }
.stock-tick { width:22px; height:22px; margin:0; accent-color:var(--ink); }
.stock-tick-space { width:22px; }
@media (max-width:520px) { .stock-tick, .stock-tick-space { width:26px; height:26px; } }

/* A tick and its sentence, reading as one line rather than a stray box. */
.check-line { display:flex; align-items:center; gap:0.6rem; margin:0 0 1.2rem; cursor:pointer; }
.check-line input { width:20px; height:20px; margin:0; accent-color:var(--ink); flex:none; }

/* ---- What a made thing is made of, on its own page ---- */
.recipe-line { display:grid; grid-template-columns:minmax(0,1fr) 9rem; gap:0.4rem 1.2rem; align-items:baseline;
  padding:0.5rem 0; border-bottom:1px solid var(--border); }
.recipe-line:last-of-type { border-bottom:0; }
.recipe-amount { text-align:right; font-variant-numeric:tabular-nums; font-weight:600; }

/* ---- What's on its way, on the floor's Goods in ---- */
/* Fixed tracks so the dates and the buttons line up down the page, the same
   reason the stock rows have them. */
.expect-row { display:grid; grid-template-columns:minmax(0,1fr) 10rem auto; gap:0.6rem 1.2rem; align-items:center;
  padding:0.9rem 1rem; margin-bottom:0.5rem; border:1px solid var(--border); border-radius:6px; background:var(--paper); }
.expect-row.is-late { border-color:var(--warn-text); background:var(--warn-bg); }
.expect-what { min-width:0; }
.expect-what strong { display:block; }
.expect-what .row-sub { display:block; opacity:0.72; }
.expect-when { text-align:right; }
@media (max-width:640px) {
  .expect-row { grid-template-columns:minmax(0,1fr) auto; }
  .expect-when { grid-column:2; grid-row:1; }
  .expect-row .btn { grid-column:1 / -1; justify-self:start; }
}

/* ---- Undo: a few seconds of "actually, no" after a save ---- */
.undo-bar { display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:0.8rem; margin-bottom:1.4rem; padding:0.8rem 1rem; border-radius:6px; background:var(--success-bg); color:var(--success-text); }
.undo-bar form { margin:0; }
/* On the orders list the page comes back scrolled to where the change was
   made, so a bar at the top would be off screen. It floats at the bottom
   instead, over the list, until it times out. */
.undo-bar--float {
  position:fixed; z-index:20; left:50%; bottom:1rem; transform:translateX(-50%);
  width:max-content; max-width:calc(100vw - 2rem); margin:0;
  box-shadow:0 6px 20px rgba(28,28,28,0.18);
}
.undo-bar--float[hidden] { display:none; }

/* An order's status, changed where it's listed: the badge itself is the
   dropdown, in the badge's own colours, with a chevron to say it opens.
   Tall enough to hit with a thumb on the floor's tablet. One width for
   every row, sized to the longest status, so the pills line up down the
   column instead of each being as wide as its own longest option. Written
   as people read them - New, Processing - not in capitals. */
.quick-status { position:relative; display:inline-block; margin:0; }
select.status-pick {
  width:12rem; max-width:100%; margin:0; min-height:2.25rem;
  padding:0.35rem 1.9rem 0.35rem 0.85rem;
  border:0; border-radius:100px;
  font-family:var(--body-font); font-size:0.85rem; font-weight:600;
  text-transform:none; letter-spacing:0;
  text-overflow:ellipsis;
  /* Restated: the status colours are set with the background shorthand,
     which would otherwise wipe out the chevron every select has. */
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23222' stroke-opacity='0.6' stroke-width='1.5' fill='none'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-position:right 0.75rem center;
  cursor:pointer;
}
/* No ring once it's been pressed: a browser counts a click on a dropdown as
   the kind of focus that draws one, so it stayed round the pill after the
   choice was made. Hovering darkens it slightly instead, to say it opens. */
select.status-pick:focus, select.status-pick:focus-visible { outline:none; }
select.status-pick:hover { filter:brightness(0.97); }
/* Packed asks which box first: a small card under the dropdown, over the
   rows below, so the table doesn't jump wider while it's open. */
.quick-pack {
  position:absolute; z-index:10; top:calc(100% + 0.4rem); left:0;
  display:flex; flex-wrap:wrap; gap:0.5rem; align-items:center;
  width:19rem; padding:0.75rem;
  background:#fff; border:1px solid var(--border); border-radius:6px;
  box-shadow:0 6px 20px rgba(28,28,28,0.14);
}
.quick-pack[hidden] { display:none; }
.quick-pack select { flex:1 1 100%; margin:0; }
.quick-pack input[type="number"] { width:4.5rem; margin:0; }
/* In a card on a phone there's room below, and a card floating over the
   next order would hide it - so it opens in place. */
@media (max-width: 760px) {
  .quick-status { display:block; }
  .quick-pack { position:static; width:auto; margin-top:0.5rem; box-shadow:none; }
}

/* ---- One thing's page: what it is, then what to do about it ----
   It used to open with three separate toggles before saying how much there
   was. The level leads, the money sits beside it, the actions come next, and
   every setting lives in one form behind Edit details. */
.item-head { display:grid; grid-template-columns:minmax(0,1fr) auto; gap:1.2rem 2.4rem; align-items:center; padding:1.3rem 1.4rem; margin-bottom:1.2rem; border:1px solid var(--border); border-radius:6px; background:var(--paper); }
.item-head.is-low { background:var(--warn-bg); border-color:transparent; }
.item-head.is-out { background:#fbe7e3; border-color:transparent; }
.item-figure { display:flex; align-items:baseline; gap:0.6rem; margin-bottom:0.7rem; }
.item-qty { font-family:var(--heading-font); font-size:2.4rem; line-height:1; font-variant-numeric:tabular-nums; }
.item-unit { font-family:var(--heading-font); font-size:1rem; opacity:0.72; }
.item-figures { display:flex; gap:2.4rem; }
.item-fig { display:flex; flex-direction:column; gap:0.2rem; max-width:15rem; }
.item-money { font-family:var(--heading-font); font-size:1.4rem; font-variant-numeric:tabular-nums; }
.item-actions { display:flex; flex-wrap:wrap; gap:0.6rem; margin-bottom:1.6rem; }
.item-section { margin-top:2.4rem; }
.item-section .panel-h { margin-bottom:0.9rem; }
.sold-list { display:flex; flex-direction:column; gap:0.4rem; }
/* A wrong amount and the way to change one, under the row they belong to. */
.sold-fix, .sold-edit { grid-column:1 / -1; }
.sold-fix { display:flex; flex-wrap:wrap; align-items:center; gap:0.5rem 0.9rem; margin:0; padding:0.6rem 0.8rem; border-radius:6px; background:var(--warn-bg); color:var(--warn-text); font-size:0.88rem; }
.sold-edit summary { cursor:pointer; font-size:0.82rem; opacity:0.72; }
.sold-edit form { display:flex; flex-wrap:wrap; align-items:flex-end; gap:0.4rem 0.9rem; margin:0.6rem 0 0; }
.sold-edit .field { margin:0; }
.sold-edit input[type=number] { max-width:8rem; margin:0; }
/* Recipes: what you buy at the top, what you make underneath. */
.make-ing { display:grid; gap:0.4rem; }
.make-ing-row { display:grid; grid-template-columns:minmax(0,1fr) auto; gap:0.2rem 1rem; padding:0.7rem 0.9rem; border:1px solid var(--border); border-radius:6px; text-decoration:none; color:inherit; }
.make-ing-row:hover { border-color:var(--ink); }
.make-ing-row strong, .make-ing-row .row-sub { grid-column:1; }
.make-ing-qty { grid-column:2; grid-row:1 / span 2; align-self:center; justify-self:end; text-align:right; font-variant-numeric:tabular-nums; }
.make-prod { padding:1.1rem 0; border-top:1px solid var(--border); }
.make-prod:first-of-type { border-top:none; padding-top:0.2rem; }
.make-prod-head { display:flex; flex-wrap:wrap; align-items:baseline; gap:0.3rem 0.9rem; margin-bottom:0.7rem; }
.make-line { display:flex; flex-wrap:wrap; align-items:center; gap:0.5rem; margin-bottom:0.5rem; }
.make-line select { flex:1; min-width:12rem; margin:0; }
.make-line input[type=number] { max-width:7rem; margin:0; }
.make-actions { display:flex; flex-wrap:wrap; gap:0.6rem; margin-top:0.6rem; }
.split-sizes { margin:0 0 1.2rem; padding:0.8rem 1rem; border:1px solid var(--border); border-radius:6px; }
.split-sizes summary { cursor:pointer; font-weight:700; }
.split-sizes select { margin:0; min-width:12rem; }
.split-sizes .table-wrap { overflow-x:auto; }
.merge-box { margin-top:2.6rem; }
.merge-box form { flex-direction:column; align-items:flex-start; }
.merge-box select { max-width:420px; margin:0; }
.sizes-list { margin:0 0 0.8rem; padding-left:1.1rem; }
.sizes-list li { margin:0.2rem 0; }
.sizes-panel .row-sub { margin-left:0.6rem; }
/* An amount with its unit beside the box: "650 g", "1 unit". */
.qty-with-unit { display:flex; align-items:center; gap:0.4rem; }
.qty-with-unit input { margin:0; }
.qty-unit { font-size:0.85rem; opacity:0.72; min-width:2.2rem; }
.sold-row { display:grid; grid-template-columns:minmax(0,1fr) 9rem auto; gap:1rem; align-items:center; padding:0.7rem 0.9rem; border:1px solid var(--border); border-radius:6px; }
.item-end { display:flex; flex-wrap:wrap; align-items:center; gap:0.8rem 1.2rem; margin-top:2.6rem; padding-top:1.2rem; border-top:1px solid var(--border); }
.item-end .row-sub { flex:1; min-width:16rem; }
.item-end form { margin:0; }
.mini-head + .field-row { margin-top:0.6rem; }
h3.mini-head { margin-top:1.4rem; }
@media (max-width:760px) {
  .item-head { grid-template-columns:1fr; }
  .item-figures { gap:1.6rem; }
  .sold-row { grid-template-columns:minmax(0,1fr) auto; }
  .sold-row .row-sub { grid-column:1; }
}

/* ---- A product's set-up, starting from the product (Angel, 29 Sept) ---- */
/* On the product form, after its Active tick and set off by a line (30 Sept):
   Inventory and what one costs side by side, each a panel with its title and
   its one control across the top; what it goes out in sits at Inventory's
   foot (13 Oct). */
.prod-panels { display:flex; flex-wrap:wrap; gap:1rem; margin-top:2rem; padding-top:1.5rem; border-top:1px solid var(--border); }
.prod-panel { flex:1 1 15rem; min-width:0; padding:1rem 1.2rem 1.1rem; border:1px solid var(--border); border-radius:6px; background:var(--paper); }
.prod-panel[hidden] { display:none; }
.prod-panel-head { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:0.5rem 1rem; min-height:1.9rem; margin-bottom:0.85rem; }
.prod-panel-head > h3.mini-head { margin:0; font-size:0.8rem; }
.prod-panel-note { margin:0; font-size:0.9rem; opacity:0.7; }
.prod-panel-note[hidden] { display:none; }
.prod-panel .prod-field > label { font-size:0.68rem; margin-bottom:0.3rem; }
.prod-panel input[type=number], .prod-panel select { margin:0; }
.inv-track { display:flex; align-items:center; gap:0.5rem; margin:0; font-size:0.9rem; font-weight:600;
  text-transform:none; letter-spacing:normal; opacity:1; cursor:pointer; }
.inv-track input { width:17px; height:17px; margin:0; accent-color:var(--ink); }
.prod-panel--inv input[type=number] { max-width:8rem; }
.inv-fields { display:flex; flex-wrap:wrap; align-items:flex-start; gap:0.9rem 1.2rem; }
.inv-fields[hidden], .inv-off[hidden] { display:none; }
.inv-line { margin:0 0 0.35rem; font-size:0.92rem; }
.inv-setup { display:flex; align-items:flex-end; gap:0.6rem 1.2rem; margin-top:1rem; padding-top:0.9rem; border-top:1px solid var(--border); }
.inv-setup .setup-sum { flex:1; }
.inv-setup-change { font-size:0.85rem; white-space:nowrap; }
/* A button that reads as a link in a sentence: Set it up and Change save
   the product before they go, so they're buttons of its form. */
.prod-panel button.linkish { display:inline; padding:0; border:0; border-radius:0; background:none; color:inherit;
  font:inherit; letter-spacing:normal; text-transform:none; text-decoration:underline; line-height:inherit; cursor:pointer; }
.prod-panel button.linkish.inv-setup-change { font-size:0.85rem; white-space:nowrap; }
.cost-row { display:flex; flex-wrap:wrap; align-items:flex-end; gap:0.9rem 1.2rem; }
.inv-money { display:inline-flex; align-items:center; gap:0.35rem; }
.inv-money input[type=number] { width:6.5rem; }
.cost-vat { display:inline-flex; align-items:center; gap:0.5rem; }
.cost-vat select { width:auto; }
.inv-vat-amount { font-size:0.85rem; opacity:0.7; white-space:nowrap; }
/* Profit and margin on a band of their own under what's typed. */
.cost-figures { flex:1 0 100%; display:flex; flex-wrap:wrap; gap:0.4rem 2rem; padding:0.6rem 0.85rem; border-radius:4px; background:var(--paper-muted); }
.cost-figure { display:flex; align-items:baseline; gap:0.55rem; }
.cost-figure > span { font-family:var(--heading-font); font-size:0.68rem; letter-spacing:0.08em; text-transform:uppercase; opacity:0.65; }
.cost-figure > strong { font-size:1.05rem; font-variant-numeric:tabular-nums; }
.cost-when { align-self:center; margin-left:auto; font-size:0.78rem; opacity:0.65; }
.cost-figure > strong.is-loss { color:#7a1f1f; }
.setup-sum { display:grid; grid-template-columns:repeat(auto-fit, minmax(9.5rem, 1fr)); gap:0.9rem 1.4rem; margin:0; font-size:0.92rem; }
.setup-sum > div { min-width:0; }
.setup-sum dt { font-family:var(--heading-font); font-size:0.68rem; letter-spacing:0.08em; text-transform:uppercase; opacity:0.65; margin-bottom:0.25rem; }
.setup-sum dd { margin:0; overflow-wrap:anywhere; }
@media (max-width:520px) { .prod-panel { padding:0.9rem 1rem 1rem; } }

/* The Products list: how many are still to go, and a line under each name. */
.setup-invite { display:flex; align-items:center; flex-wrap:wrap; gap:0.6rem 1rem; }
.setup-invite > span { flex:1; min-width:16rem; }
.setup-line-sum { display:block; margin-top:0.2rem; font-size:0.76rem; font-weight:400; color:var(--ink); opacity:0.6; text-decoration:none; }
.setup-line-sum:hover { opacity:1; text-decoration:underline; }
.setup-line-sum.is-todo { opacity:1; color:var(--warn-text); text-decoration:underline; }
.qty-short { color:#7a1f1f; font-weight:700; }

/* The set-up page: two questions, each a card. */
.setup-progress { display:flex; flex-wrap:wrap; align-items:center; gap:0.5rem 1rem; margin-bottom:1.8rem; font-size:0.85rem; }
.setup-progress-label { font-family:var(--heading-font); font-size:0.68rem; letter-spacing:0.08em; text-transform:uppercase; opacity:0.72; }
.setup-bar { flex:1 1 8rem; height:6px; border-radius:3px; background:var(--paper-muted); overflow:hidden; }
.setup-bar > span { display:block; height:100%; background:var(--ink); }
.setup-progress-count { font-variant-numeric:tabular-nums; }
.setup-back { margin-bottom:1rem; }
.setup-head { display:flex; align-items:center; gap:1rem; margin-bottom:1.6rem; }
.setup-head img { width:64px; height:64px; object-fit:cover; border-radius:6px; flex:0 0 64px; }
.setup-head h1 { margin:0; }
.setup-head p { margin:0.25rem 0 0; font-size:0.88rem; }
.setup-form { display:flex; flex-direction:column; gap:1.2rem; }
.setup-q h2 { font-size:1.05rem; margin:0 0 1rem; }
.setup-q-hint { margin:-0.5rem 0 1rem; }
.setup-modes { flex-wrap:wrap; margin-bottom:1.3rem; }
.setup-modes .seg-opt { flex:1 1 11rem; }
.setup-modes .seg-opt:has(input:checked) { border-color:var(--ink); background:var(--paper-muted); font-weight:600; }
.setup-say { margin:0 0 0.8rem; }
.setup-line, .setup-row { display:flex; flex-wrap:wrap; align-items:center; gap:0.5rem 0.7rem; margin-bottom:0.7rem; }
.setup-line input, .setup-line select, .setup-row input, .setup-row select { margin-bottom:0; width:auto; }
.setup-line input[type=number], .setup-row input[type=number] { width:5.5rem; }
.setup-pick { flex:1 1 10rem; min-width:0; }
.setup-new { flex:1 1 9rem; min-width:0; }
/* Packing (29 Sept): the five kinds of packaging supplies as tiles, each
   opening a page of its own (lib/packaging.js), with an icon beside each. */
.pack-group { margin-bottom:2.8rem; }
/* The two groups stand out above their tiles (Angel, 29 Sept). */
.pack-group-head { font-family:var(--heading-font); font-size:1.25rem; font-weight:700; letter-spacing:0.05em; text-transform:uppercase;
  margin:0 0 1rem; }
.pack-group-note { font-family:var(--body-font); font-size:0.9rem; text-transform:none; letter-spacing:0; font-weight:400; opacity:0.65; margin-left:0.6rem; }
.pack-tiles { display:grid; grid-template-columns:repeat(auto-fill, minmax(17rem, 1fr)); gap:0.9rem; }
.pack-tile { display:flex; align-items:center; gap:1rem; padding:1.1rem 1.2rem; border:1px solid var(--border); border-radius:6px;
  background:var(--paper); color:var(--ink); text-decoration:none; }
.pack-tile:hover, .pack-tile:focus-visible { border-color:var(--ink); background:var(--paper-muted); }
.pack-tile-icon { flex:0 0 auto; display:flex; align-items:center; justify-content:center; width:48px; height:48px;
  border-radius:50%; background:var(--paper-muted); }
.pack-tile:hover .pack-tile-icon { background:var(--paper); }
.pack-tile-text { display:flex; flex-direction:column; gap:0.3rem; min-width:0; }
.pack-tile-text strong { font-size:1rem; }
.pack-tile-text em { font-style:normal; font-size:0.78rem; font-weight:600; margin-top:0.2rem; }
.pack-icon { display:block; }

/* One kind's own page, reached from the tiles on Packing. */
.pack-title { display:flex; align-items:center; gap:1rem; margin-bottom:1.4rem; }
.pack-title h2 { margin:0; }
.pack-title p { margin:0.25rem 0 0; max-width:62ch; font-size:0.9rem; }
.pack-table td { vertical-align:middle; }
.pack-move { margin:0; }
.pack-move select { margin:0; width:auto; font-size:0.8rem; padding:0.3rem 1.8rem 0.3rem 0.5rem; }
.pack-none { margin:0 0 0.8rem; font-size:0.9rem; }
.pack-title-text { flex:1; min-width:0; }
.pack-add-btn { flex:none; margin-left:auto; }
.pack-low { display:block; color:var(--warn-text); font-weight:700; }
@media (max-width:640px) { .pack-title { flex-wrap:wrap; } .pack-add-btn { margin-left:0; } }
/* Adding a packaging supply (1 Oct): its details in sections, a card each,
   two fields to a row where there's room. */
.pn-head { display:flex; align-items:center; gap:1rem; margin-bottom:1.4rem; }
.pn-head h1 { margin:0; }
.pn-head p { margin:0.3rem 0 0; max-width:62ch; }
.pn-form { display:flex; flex-direction:column; gap:1rem; }
.pn-section { display:flex; flex-direction:column; gap:0.9rem; padding:1.2rem 1.4rem; }
.pn-title { margin:0; font-size:0.95rem; }
.pn-grid { display:grid; grid-template-columns:repeat(auto-fit, minmax(13rem, 1fr)); gap:0.9rem 1.2rem; }
.pn-grid[hidden] { display:none; }
.pn-wide { grid-column:1 / -1; }
.pn-grid--name { grid-template-columns:minmax(0, 2fr) minmax(0, 1fr); }
@media (max-width:540px) { .pn-grid--name { grid-template-columns:minmax(0, 1fr); } }
.pn-field { display:flex; flex-direction:column; gap:0.35rem; margin:0; opacity:1; font-size:inherit; letter-spacing:normal; text-transform:none; }
.pn-field > span:first-child { font-family:var(--heading-font); font-size:0.66rem; letter-spacing:0.08em; text-transform:uppercase; opacity:0.7; }
.pn-field em { font-style:normal; font-family:var(--body-font); font-size:0.75rem; letter-spacing:0; text-transform:none; opacity:0.85; margin-left:0.2rem; }
.pn-field input, .pn-field select, .pn-field textarea { margin:0; }
.pn-field textarea { min-height:0; }
.pn-money { display:flex; align-items:center; gap:0.4rem; }
.pn-money input { flex:1; min-width:0; }
.pn-money select { width:auto; flex:none; }
.pn-pound { flex:none; }
.pn-check { margin:0; font-size:0.92rem; text-transform:none; letter-spacing:normal; opacity:1; }
.pn-actions { display:flex; flex-wrap:wrap; gap:0.7rem; padding-top:0.3rem; }
.pn-actions button, .pn-actions .btn { margin:0; }
.pack-box { margin-bottom:0.9rem; padding:1rem 1.2rem; }
.pack-box-head { display:flex; align-items:center; justify-content:space-between; gap:1rem; margin-bottom:0.5rem; }
.pack-use-box { display:flex; align-items:center; flex-wrap:wrap; gap:0.6rem 1rem; margin:0.4rem 0 0; }
.pack-with { list-style:none; margin:0 0 0.7rem; padding:0; }
.pack-with li { display:flex; align-items:baseline; gap:0.8rem; padding:0.35rem 0; border-bottom:1px solid var(--border); font-size:0.92rem; }
.pack-with li > span { flex:1; }
.pack-with li:last-child { border-bottom:0; }
.pack-line { display:flex; flex-wrap:wrap; align-items:center; gap:0.5rem 0.7rem; margin:0; }
.pack-line select, .pack-line input { margin-bottom:0; width:auto; }
.pack-line input[type=number] { width:5.5rem; }
.pack-pick { flex:1 1 14rem; min-width:0; }
.pack-extras { margin-top:3rem; }
.pack-extras > .mini-head { margin:0 0 0.4rem; }
.pack-unsorted > summary { cursor:pointer; font-size:0.88rem; opacity:0.75; }

/* A made thing's ingredients, set in under its row. */
.setup-made { margin-bottom:0.4rem; }
.setup-ings { margin:0 0 1rem 1.2rem; padding:0.2rem 0 0.2rem 1rem; border-left:2px solid var(--border); }
.setup-ings-head { margin:0 0 0.6rem; font-size:0.9rem; }
.setup-ings .form-hint { margin-top:0.4rem; }
.setup-add-ing { font-size:0.85rem; opacity:0.8; }
.setup-add-hint { margin-top:0.5rem; }
.setup-fields { display:grid; grid-template-columns:1fr 1fr; gap:1rem; }
.setup-field { display:flex; flex-direction:column; gap:0.35rem; margin:0; }
.setup-field > span em { font-style:normal; opacity:0.6; text-transform:none; letter-spacing:0; }
.setup-field input, .setup-field select { margin-bottom:0; }
.setup-sub { font-family:var(--heading-font); font-size:0.7rem; letter-spacing:0.08em; text-transform:uppercase; margin:1.2rem 0 0.6rem; }
.setup-actions { flex-wrap:wrap; }
.setup-stop { margin-left:auto; font-size:0.85rem; }
@media (max-width:560px) {
  .setup-fields { grid-template-columns:1fr; }
  .setup-stop { margin-left:0; }
}

.inline-form { display:inline; margin:0; }
.link-button { background:none; border:0; padding:0; margin:0; width:auto; min-height:0; color:inherit;
  font-family:var(--body-font); font-weight:400; font-size:0.78rem; letter-spacing:normal; text-transform:none;
  text-decoration:underline; opacity:0.6; cursor:pointer; }
.link-button:hover, .link-button:focus-visible { opacity:1; }

/* Merge, hide and delete: rare, so folded under More at the foot. */
.item-more { margin-top:2.6rem; }
.item-more > summary { cursor:pointer; font-size:0.85rem; opacity:0.72; }
.item-more .merge-box, .item-more .item-end { margin-top:1.2rem; }

/* ---- Inventory as a table, the way Katana lays out Stock (27 Sept) ---- */
/* Four figures that line up down the page, the one that matters - what's
   left after the orders waiting - marked red when it goes below nothing, and
   the job that fixes it at the end of the row. */
.inv-find { display:block; max-width:420px; margin:0 0 1rem; }
.inv-table { margin-top:1rem; }
.inv-table .num { font-variant-numeric:tabular-nums; }
.inv-table td.num .row-sub { text-align:right; }
.inv-table .inv-zero { opacity:0.4; }
.inv-table .inv-tick { width:2.2rem; padding-right:0; }
.inv-table .inv-tick input { width:18px; height:18px; margin:0.15rem 0 0; accent-color:var(--ink); }
.inv-table .inv-act { text-align:right; white-space:nowrap; }
.inv-table .group-row th { padding-top:1.6rem; font-size:0.72rem; opacity:1; }
.inv-table .group-row th span:first-child { opacity:0.7; }
.inv-group-sum { float:right; text-transform:none; letter-spacing:normal; font-family:var(--body-font); font-size:0.8rem; opacity:0.75; }
.inv-left { display:inline-block; font-weight:700; padding:0.1rem 0.45rem; border-radius:4px; }
.inv-left.is-short { background:#fbe6e6; color:#7a1f1f; }
.inv-left.is-low { background:var(--warn-bg); color:var(--warn-text); }
.inv-left.is-fine { font-weight:600; padding-left:0; padding-right:0; }
.inv-table .inv-row[hidden], .inv-table .inv-group[hidden] { display:none; }
/* Find and Show on one line above the Inventory table (and Show alone on
   Adjustments). */
.inv-tools { display:flex; flex-wrap:wrap; align-items:center; gap:0.8rem 1.2rem; margin:0 0 1rem; }
.inv-tools .inv-find { flex:1 1 260px; max-width:420px; margin:0; }
/* Show and its dropdown, on the catalogue and the office's Stock pages. At
   full strength: the page's label style faded the whole thing, dropdown
   included, and Show was faded again on top, so it looked lost beside the
   box (Angel, 27 Sept - "make bold/bigger"). */
.inv-show { display:flex; align-items:center; gap:0.7rem; margin:0; opacity:1; font-size:inherit; letter-spacing:normal; text-transform:none; }
.inv-show > span { font-family:var(--heading-font); font-size:0.8rem; font-weight:700; letter-spacing:0.1em; text-transform:uppercase; line-height:1; opacity:0.8; }
.inv-show select { width:auto; min-width:13rem; margin:0; }
/* Integrations: one card per connected system, the whole card the link. */
.integration { display:grid; grid-template-columns:1fr auto; gap:0.4rem 1rem; align-items:center; text-decoration:none; color:inherit; }
.integration:hover { border-color:var(--ink); }
.integration-name { font-family:var(--heading-font); font-weight:700; letter-spacing:0.06em; text-transform:uppercase; }
.integration-what { grid-column:1 / -1; font-size:0.9rem; opacity:0.8; }
/* What Shopify has sent (2 Oct): when, what, and taken or turned away. */
.integration-sub { margin-top:1.4rem; }
.hook-log { list-style:none; margin:0 0 1rem; padding:0; font-size:0.9rem; }
.hook-log li { display:flex; flex-wrap:wrap; align-items:center; gap:0.3rem 1rem; padding:0.45rem 0; border-bottom:1px solid var(--border); }
.hook-log-when { min-width:8.5rem; opacity:0.72; font-variant-numeric:tabular-nums; }
.hook-log-what { flex:1; min-width:10rem; }
.integration-hooks { margin-top:0.6rem; font-size:0.9rem; }
.integration-hooks > summary { cursor:pointer; opacity:0.75; }
.integration-hooks .integration-url { margin-top:0.5rem; }
.hook-log-more { margin:-0.4rem 0 1rem; }
.hook-log-more .hook-log { margin-top:0.4rem; }
/* The office's order page: what the customer was emailed, in a line. */
.customer-emails { display: flex; flex-wrap: wrap; gap: 0.3rem 1rem; align-items: baseline; font-size: 0.88rem; margin: 0 0 1rem; }
.customer-email.is-failed { color: #7a1f1f; }
/* A customer's own settings, read-only on their office page. */
.settings-read { list-style: none; margin: 0; padding: 0; }
.settings-read li { display: grid; grid-template-columns: 9.5rem minmax(0, 1fr); gap: 0.2rem 1rem; padding: 0.45rem 0; border-bottom: 1px solid var(--border); font-size: 0.9rem; }
.settings-read li:last-child { border-bottom: 0; }
.settings-read li > span { opacity: 0.65; }
@media (max-width: 480px) { .settings-read li { grid-template-columns: 1fr; } }
/* The customer's Settings: whole sentences beside the ticks read better in
   ordinary case, and each hint belongs to the field above it, with room
   before the next. */
.settings-form .check-line { text-transform: none; letter-spacing: normal; font-size: 0.95rem; align-items: flex-start; line-height: 1.45; }
.settings-form .check-line input { margin-top: 0.1rem; }
.settings-form .form-hint { margin: 0.35rem 0 1.2rem; }
.settings-form .card > .form-hint:last-child { margin-bottom: 0; }

/* ---- News & updates, behind the customer's bell (27 Sept) ---- */
/* Posts as cards, order updates as quiet one-line rows between them; what's
   arrived since they last looked is marked New. */
.news-feed { display: flex; flex-direction: column; gap: 0.8rem; }
/* Each post a line to click: picture, date and title, opening in full on
   its own page (Angel, 27 Sept). What's new says
   New, and the line stays plain - "not the whole thing in green". */
.news-row { display: flex; align-items: center; gap: 1rem; padding: 0.9rem 1rem; border: 1px solid var(--border); border-radius: 6px; background: var(--paper); text-decoration: none; color: inherit; }
.news-row:hover { border-color: var(--ink); }
.news-row-thumb { flex: none; width: 88px; height: 66px; object-fit: cover; border-radius: 4px; display: block; }
.news-row-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.2rem; }
.news-row-meta { display: flex; align-items: center; gap: 0.5rem; font-size: 0.8rem; opacity: 0.75; }
.news-row-title { font-size: 1rem; }
.news-row-go { flex: none; font-size: 1.6rem; line-height: 1; opacity: 0.45; }
.news-row:hover .news-row-go { opacity: 0.9; }
@media (max-width: 520px) { .news-row-thumb { width: 64px; height: 48px; } }
/* The office's lists of the same posts: the customer's line, with the
   picture and words opening it for editing and its buttons at the end. */
/* An order to a supplier is wider than other forms, so a line - item,
   quantity, unit, price, VAT, line total - fits on one row as it does on
   the invoice being copied from. */
.ops-form#prForm { max-width: 1040px; }
.goods-row-field .pr-vat { width: 6.4rem; flex: 0 0 6.4rem; margin: 0; }
/* The VAT that rate comes to, beside it, as the invoice's VAT amount column. */
.pr-vat-amount { min-width: 4.2rem; font-variant-numeric: tabular-nums; font-size: 0.92rem; white-space: nowrap; }
.pr-shipping .pr-vat-amount { align-self: center; }
/* An order's totals, as a supplier's invoice sets them out (Angel, 29 Sept):
   figures to the right, the total on a line of its own. */
.pr-totals { display: flex; flex-direction: column; gap: 0.35rem; max-width: 22rem; margin: 1.2rem 0 1.4rem auto; font-variant-numeric: tabular-nums; }
.pr-totals > div { display: flex; justify-content: space-between; gap: 1.5rem; font-size: 0.92rem; }
.pr-totals > div span { opacity: 0.72; }
.pr-totals .pr-grand { border-top: 1px solid var(--border); padding-top: 0.5rem; margin-top: 0.2rem; font-size: 1.05rem; }
.pr-totals .pr-grand span { opacity: 1; font-weight: 600; }
.news-row-main { display: flex; align-items: center; gap: 1rem; flex: 1; min-width: 0; text-decoration: none; color: inherit; }
.news-email-note { margin: 0.4rem 0 1rem; }
.news-email-note .form-hint { margin: 0.2rem 0 0; }
.news-mail-failures { margin: 0; padding-left: 1.1rem; font-size: 0.9rem; line-height: 1.6; }
/* Preview (Angel, 28 Sept): who it reaches and the ways on, then the email
   as it lands and the notification as the portal shows it, side by side
   where there's room. */
.preview-summary { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 1rem; margin-bottom: 1.6rem; }
.preview-facts { display: flex; flex-direction: column; gap: 0.2rem; min-width: 0; }
.preview-title { font-size: 1.05rem; }
.preview-summary .preview-actions { flex-wrap: wrap; }
.preview-panes { display: grid; gap: 1.6rem; align-items: start; }
.preview-panes--two { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
@media (max-width: 900px) { .preview-panes--two { grid-template-columns: minmax(0, 1fr); } }
.preview-pane .mini-head { margin-top: 0; }
.preview-portal { border: 1px solid var(--border); border-radius: 6px; padding: 1.5rem; background: var(--paper); }
.preview-portal .news-article h1 { font-size: 1.3rem; }
.preview-email { display: block; width: 100%; min-height: 420px; border: 1px solid var(--border); border-radius: 6px; background: #f3f1ec; }
/* Marketing > Order emails (30 Sept): the switch for all of them, the words
   of one on the left, and the email itself on the right as it's typed. */
.oe-status { display:flex; flex-wrap:wrap; align-items:center; gap:0.6rem 0.9rem; margin:0 0 1.4rem; padding:0.8rem 1rem; border:1px solid var(--border); border-radius:6px; background:var(--paper); }
.oe-status-dot { width:10px; height:10px; border-radius:50%; background:#b9b4a9; flex:none; }
.oe-status.is-on .oe-status-dot { background:#3f7d2a; }
.oe-status-text { flex:1 1 12rem; font-size:0.92rem; }
.oe-status button { margin:0; }
/* The four emails as one bar, each with whether it's sent; Look and
   sign-off beside it, for all of them. */
.oe-nav { display:flex; flex-wrap:wrap; align-items:stretch; gap:0.8rem; margin:0 0 1.4rem; }
.oe-emails { flex:1 1 32rem; display:grid; grid-template-columns:repeat(4, minmax(0, 1fr)); border:1px solid var(--border); border-radius:8px; overflow:hidden; background:var(--paper); }
.oe-email { display:flex; flex-direction:column; gap:0.2rem; padding:0.65rem 0.9rem; color:var(--ink); text-decoration:none; border-left:1px solid var(--border); }
.oe-email:first-child { border-left:0; }
.oe-email:hover { background:var(--paper-muted); }
.oe-email-name { font-weight:600; font-size:0.92rem; }
.oe-email-state { display:inline-flex; align-items:center; gap:0.35rem; font-size:0.75rem; opacity:0.7; }
.oe-email-state::before { content:""; width:7px; height:7px; border-radius:50%; background:#b9b4a9; }
.oe-email-state.is-on::before { background:#3f7d2a; }
.oe-email.is-active { background:var(--ink); color:var(--paper); }
.oe-email.is-active .oe-email-state { opacity:0.8; }
.oe-look { flex:0 0 auto; display:flex; align-items:center; gap:0.7rem; padding:0.65rem 1rem; border:1px dashed var(--border); border-radius:8px; color:var(--ink); text-decoration:none; background:var(--paper); }
.oe-look span { display:flex; flex-direction:column; gap:0.15rem; }
.oe-look strong { font-size:0.92rem; }
.oe-look em { font-style:normal; font-size:0.75rem; opacity:0.65; }
.oe-look:hover { border-style:solid; border-color:var(--ink); }
.oe-look.is-active { background:var(--ink); color:var(--paper); border-style:solid; border-color:var(--ink); }
.oe-grid { display:grid; grid-template-columns:minmax(0, 26rem) minmax(0, 1fr); gap:1.4rem; align-items:start; }
.oe-form { display:flex; flex-direction:column; gap:1rem; padding:1.3rem 1.4rem; }
.oe-form input[type=text], .oe-form textarea { margin:0; }
.oe-form textarea { min-height:0; }
.oe-form .check-line { margin:0; font-size:0.92rem; text-transform:none; letter-spacing:normal; opacity:1; }
.oe-when { margin:0; font-size:0.9rem; opacity:0.72; }
.oe-on { padding-bottom:0.9rem; border-bottom:1px solid var(--border); font-weight:600; }
.oe-field { display:flex; flex-direction:column; gap:0.35rem; margin:0; opacity:1; font-size:inherit; letter-spacing:normal; text-transform:none; }
.oe-field > span { font-family:var(--heading-font); font-size:0.66rem; letter-spacing:0.08em; text-transform:uppercase; opacity:0.65; }
.oe-field > span em { font-style:normal; opacity:0.7; text-transform:none; letter-spacing:0; font-family:var(--body-font); font-size:0.75rem; }
.oe-row { display:grid; grid-template-columns:1fr 1fr; gap:0.8rem; align-items:end; }
.oe-checks { display:flex; flex-wrap:wrap; gap:0.6rem 1.4rem; }
.oe-insert { display:flex; flex-wrap:wrap; align-items:center; gap:0.4rem; font-size:0.82rem; }
.oe-insert > span { opacity:0.7; margin-right:0.2rem; }
.oe-chip { margin:0; padding:0.25rem 0.6rem; border:1px dashed var(--border); border-radius:999px; background:none; color:var(--ink); font-family:var(--body-font); font-size:0.8rem; font-weight:600; letter-spacing:normal; text-transform:none; cursor:pointer; }
.oe-chip:hover { border-style:solid; border-color:var(--ink); }
.oe-insert + .form-hint { margin-top:-0.6rem; }
.oe-actions { display:flex; flex-wrap:wrap; align-items:center; gap:0.6rem 0.8rem; padding-top:0.4rem; }
.oe-actions button { margin:0; }
.oe-reset { margin-left:auto !important; font-size:0.85rem; }
.oe-test-msg { margin:0; font-size:0.85rem; }
.oe-test-msg:empty { display:none; }
/* The message for a delivery and for a collection, a box each. */
.oe-variants { display:flex; flex-direction:column; gap:0.6rem; }
.oe-variants-head { font-family:var(--heading-font); font-size:0.66rem; letter-spacing:0.08em; text-transform:uppercase; opacity:0.65; }
.oe-variants-head em { font-style:normal; font-family:var(--body-font); font-size:0.75rem; letter-spacing:0; text-transform:none; opacity:0.85; margin-left:0.3rem; }
.oe-variant { display:flex; flex-direction:column; gap:0.45rem; margin:0; padding:0.7rem 0.8rem 0.8rem; border:1px solid var(--border); border-radius:6px; background:var(--paper-muted);
  font-size:inherit; letter-spacing:normal; text-transform:none; opacity:1; }
.oe-variant.is-shown { border-color:var(--ink); }
.oe-variant-head { display:inline-flex; align-items:center; gap:0.45rem; font-weight:700; font-size:0.88rem; }
.oe-grow { resize:none; overflow:hidden; }
.oe-preview { position:sticky; top:1rem; min-width:0; padding:0; overflow:hidden; }
.oe-preview-empty { margin:0; padding:1.3rem 1.4rem; }
.oe-preview-head { display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:0.5rem 1rem; padding:0.75rem 1rem; }
.oe-preview-on { font-size:0.85rem; opacity:0.8; }
.pair-toggle button svg { vertical-align:-3px; margin-right:0.2rem; }
.pair-toggle { display:inline-flex; border:1px solid var(--border); border-radius:999px; overflow:hidden; }
.pair-toggle button { margin:0; padding:0.3rem 0.8rem; border:0; border-radius:0; background:none; color:var(--ink); font-family:var(--body-font); font-size:0.8rem; font-weight:600; letter-spacing:normal; text-transform:none; cursor:pointer; }
.pair-toggle button.is-active { background:var(--ink); color:var(--paper); }
.oe-subject { margin:0; padding:0.55rem 1rem; border-top:1px solid var(--border); border-bottom:1px solid var(--border); background:var(--paper-muted); font-size:0.9rem; }
.oe-subject > span { font-family:var(--heading-font); font-size:0.66rem; letter-spacing:0.08em; text-transform:uppercase; opacity:0.6; margin-right:0.4rem; }
.oe-frame { display:block; width:100%; min-height:520px; border:0; background:#fff; }
@media (max-width:900px) {
  .oe-grid { grid-template-columns:minmax(0, 1fr); }
  .oe-preview { position:static; }
}
@media (max-width:640px) {
  .oe-emails { grid-template-columns:repeat(2, minmax(0, 1fr)); }
  .oe-email:nth-child(3) { border-left:0; }
  .oe-email:nth-child(n+3) { border-top:1px solid var(--border); }
  .oe-look { flex:1 1 100%; }
}
@media (max-width:480px) { .oe-row { grid-template-columns:1fr; } }
@media (max-width: 640px) { .news-row--office { flex-wrap: wrap; } .news-row--office .row-actions { width: 100%; } }
/* The post in full. */
.news-back { margin: 0 0 1.4rem; font-size: 0.9rem; }
.news-back a { color: inherit; }
.news-article-date { margin: 0 0 0.4rem; font-size: 0.85rem; }
.news-article h1 { margin-bottom: 1.2rem; }
.news-article p { line-height: 1.65; max-width: 62ch; }
/* The post's picture sized to its words, about the email's width, and never
   taller than a screenful's worth; kept whole, not cropped, since a poster
   carries words of its own (Angel, 2 Oct: "those bell notifications are
   huge!"). */
.news-article .news-image { width: auto; max-width: min(100%, 520px); max-height: 420px; height: auto; object-fit: contain; margin-bottom: 1.4rem; }
.news-image { display: block; width: 100%; max-height: 360px; object-fit: cover; border-radius: 4px; margin: 0 0 1rem; }
.news-update { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0.2rem 1rem; padding: 0.75rem 1rem; border: 1px solid var(--border); border-radius: 6px; text-decoration: none; color: inherit; font-size: 0.92rem; }
.news-update:hover { border-color: var(--ink); }
.news-new { color: var(--success-text); font-weight: 700; }

/* ---- Marketing (27 Sept) ---- */
.news-form { margin-bottom: 0.5rem; }
.tool-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 1rem; }
.tool-card { margin: 0; display: flex; flex-direction: column; gap: 0.6rem; }
.tool-open { display: flex; flex-direction: column; gap: 0.3rem; text-decoration: none; color: inherit; flex: 1; }
.tool-open strong { font-family: var(--heading-font); letter-spacing: 0.04em; text-transform: uppercase; font-size: 0.85rem; }
.tool-go { margin-top: auto; padding-top: 0.5rem; font-size: 0.8rem; font-weight: 600; }
.tool-open:hover .tool-go { text-decoration: underline; }
.tool-edit > summary { cursor: pointer; font-size: 0.78rem; opacity: 0.6; }
.tool-edit[open] > summary { margin-bottom: 0.6rem; }
.plan-text { font-family: var(--body-font); line-height: 1.6; min-height: 22rem; }

/* An icon's name, shown the moment you hover or tab to it (Angel, 27 Sept -
   "for hovering on the icons, let's have it say what they are"). The
   browser's own title tip waits about a second and is easy to miss. Below
   the icon, centred, in the page's ink. Plain CSS every current browser
   draws the same. It appears at once rather than fading in, as a fade is
   drawn on a layer of its own and nudged the icon with it; it's centred
   with auto margins rather than a shift of half its width for the same
   reason. Only for a mouse: a phone has no hover, and a tap would leave
   the label stuck on. The keyboard still gets it. */
.has-tip { position: relative; }
.has-tip::after {
  content: attr(data-tip);
  position: absolute; top: calc(100% + 6px); left: -100px; right: -100px; width: max-content; margin: 0 auto;
  z-index: 60; padding: 0.3rem 0.55rem; border-radius: 4px; white-space: nowrap; pointer-events: none;
  background: var(--ink); color: var(--paper);
  font-family: var(--body-font); font-size: 0.72rem; font-weight: 600; letter-spacing: 0.02em; text-transform: none; line-height: 1.3;
  opacity: 0;
}
@media (hover: hover) { .has-tip:hover::after { opacity: 1; } }
.has-tip:focus-visible::after { opacity: 1; }
/* The person menu's own list says the same thing once it's open. */
.nav-menu[open] > .has-tip::after { display: none; }

/* Integrations: Shopify's two halves and the steps still to do (1 Oct). */
.integration-card { display:flex; flex-direction:column; gap:0.8rem; }
.integration-head { display:flex; align-items:center; justify-content:space-between; gap:1rem; }
.integration-checks { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:0.6rem; font-size:0.92rem; }
.integration-checks li { position:relative; padding-left:1.6rem; line-height:1.5; }
.integration-checks li::before { content:""; position:absolute; left:0; top:0.3rem; width:0.9rem; height:0.9rem; border-radius:50%; border:2px solid #b9b4a9; }
.integration-checks li.is-done::before { border-color:#3f7d2a; background:#3f7d2a; }
.integration-steps { margin:0; padding:0.9rem 1rem 0.9rem 2.2rem; border-radius:6px; background:var(--paper-muted); display:flex; flex-direction:column; gap:0.8rem; font-size:0.9rem; line-height:1.55; }
.integration-url { display:flex; flex-wrap:wrap; align-items:center; gap:0.5rem; margin:0.4rem 0; }
.integration-url code { padding:0.3rem 0.5rem; border-radius:4px; background:var(--paper); border:1px solid var(--border); font-size:0.8rem; overflow-wrap:anywhere; }
.integration-url button { margin:0; }

/* Web shop orders on both Orders lists (1 Oct). */
.web-lede { max-width:62ch; margin:0 0 1.2rem; font-size:0.9rem; }
.web-head { margin:1.6rem 0 0.6rem; font-size:1rem; }
.web-head span { font-size:0.8rem; opacity:0.55; margin-left:0.3rem; }
.web-item { display:block; font-size:0.9rem; }
.floor-orders tbody tr.is-done { opacity:0.55; }

/* ------------------------------------------------------------------
   The office frame (Angel, 3 Oct look refresh, designed on the canvas
   first): a white top bar over a light side menu, the page beside it in
   a lighter grey, the two meeting the bar in soft rounded corners. Only
   office pages have .of-side, so the floor and the customers' portal are
   untouched. Colours, each meaning one thing: blue new, yellow to do,
   red needing attention. The dark espresso is for what you press.
   ------------------------------------------------------------------ */
body.of-page { padding: 64px 0 0 228px; background: #f3f3f2; letter-spacing: 0; }
body.of-page::before { content: ""; position: fixed; z-index: 45; top: 64px; right: 0; width: 18px; height: 18px; background: radial-gradient(circle at 0 100%, transparent 17.5px, #ffffff 18px); pointer-events: none; }
body.of-page::after { content: ""; position: fixed; z-index: 44; top: 64px; left: 228px; right: 0; height: 18px; border-top-right-radius: 18px; box-shadow: inset 0 7px 10px -7px rgba(58, 48, 42, 0.12); pointer-events: none; }

.of-top { position: fixed; z-index: 50; top: 0; left: 0; right: 0; height: 64px; display: flex; align-items: center; gap: 16px; padding: 0 18px 0 26px; background: #ffffff; color: #1f1f1f; }
.of-brand { flex: 0 0 186px; display: flex; align-items: center; }
.of-brand img { display: block; height: 15px; width: auto; }
.of-search-wrap { flex: 1 1 auto; display: flex; align-items: center; gap: 10px; max-width: 600px; margin: 0 auto; }
.of-search { flex: 1; display: flex; align-items: center; gap: 10px; height: 40px; margin: 0; padding: 0 16px; border: 1px solid #e4e1dd; border-radius: 999px; background: #f3f3f2; color: #1f1f1f; }
.of-search:focus-within { border-color: #8c8c8c; background: #ffffff; }
.of-top .of-search input { flex: 1; min-width: 0; height: auto; margin: 0; padding: 0; border: 0; border-radius: 0; outline: 0; background: none; color: #1f1f1f; font: inherit; font-size: 14px; box-shadow: none; }
.of-search input::placeholder { color: #6b6b6b; opacity: 1; }
.of-round { position: relative; flex: 0 0 40px; width: 40px; height: 40px; display: grid; place-items: center; border: 1px solid #e4e1dd; border-radius: 50%; background: #f3f3f2; color: #1f1f1f; text-decoration: none; cursor: pointer; list-style: none; }
.of-round:hover { background: #e9e7e4; color: #1f1f1f; }
.of-round::-webkit-details-marker, .of-acct::-webkit-details-marker { display: none; }
.of-dot { position: absolute; top: 9px; right: 10px; width: 8px; height: 8px; border-radius: 50%; background: #f0a020; box-shadow: 0 0 0 2px #f3f3f2; }
.of-end { flex: 0 0 auto; display: flex; align-items: center; justify-content: flex-end; gap: 10px; }
.of-pop { position: relative; }
.of-acct { display: flex; align-items: center; gap: 10px; height: 40px; padding: 0 16px 0 4px; border: 1px solid #e4e1dd; border-radius: 999px; background: #f3f3f2; color: #1f1f1f; font-weight: 700; font-size: 14px; cursor: pointer; list-style: none; }
.of-acct:hover { background: #e9e7e4; }
.of-avatar { width: 32px; height: 32px; display: grid; place-items: center; border-radius: 50%; background: #1c1c1c; color: #ffffff; font-weight: 800; font-size: 13px; }
.of-pop-list { position: absolute; z-index: 60; top: calc(100% + 8px); right: 0; min-width: 230px; display: flex; flex-direction: column; padding: 6px; border-radius: 16px; background: #ffffff; box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12), 0 0 0 1px rgba(0, 0, 0, 0.05); }
.of-pop-list a, .of-pop-list button { display: flex; align-items: center; gap: 10px; min-height: 38px; margin: 0; padding: 0 12px; border: 0; border-radius: 10px; background: none; color: #1f1f1f; font: inherit; font-size: 14px; font-weight: 600; text-align: left; text-decoration: none; cursor: pointer; }
.of-pop-list a:hover, .of-pop-list button:hover { background: #f3f3f2; }
.of-pop-list form { margin: 0; }
.of-pop-none, .of-pop-who { margin: 0; padding: 8px 12px; color: #666666; font-size: 13px; }

.of-side { position: fixed; z-index: 40; top: 64px; left: 0; bottom: 0; width: 228px; display: flex; flex-direction: column; gap: 1px; padding: 14px 12px; overflow-y: auto; background: #ebebe9; border-top-left-radius: 18px; box-shadow: inset 0 7px 10px -7px rgba(58, 48, 42, 0.12); }
.of-nav { display: flex; align-items: center; gap: 10px; min-height: 30px; padding: 0 14px; border-radius: 999px; color: #1f1f1f; font-size: 12.5px; font-weight: 600; text-decoration: none; letter-spacing: 0; }
.of-nav svg { flex: 0 0 16px; width: 16px; height: 16px; }
.of-nav:hover { background: #e1e1df; color: #1f1f1f; }
.of-nav.is-on, .of-nav.is-on:hover { background: #ffffff; color: #1f1f1f; font-weight: 800; }
.of-nav.is-open { font-weight: 800; }
.of-count { margin-left: auto; min-width: 22px; height: 18px; padding: 0 6px; display: grid; place-items: center; border-radius: 999px; background: #dededc; color: #1f1f1f; font-size: 11px; font-weight: 700; }
.of-pop-list .of-count { margin-left: 0; }
.of-sub { position: relative; display: flex; flex-direction: column; gap: 1px; padding: 2px 0 4px; }
.of-sub .of-nav { min-height: 27px; padding: 0 14px 0 40px; font-size: 12px; }
.of-sub::before { content: ""; position: absolute; z-index: 1; left: 21px; top: -5px; width: 12px; height: calc(var(--sel, 0) * 28px + 21px); border-left: 1.5px solid #9d9d9f; border-bottom: 1.5px solid #9d9d9f; border-bottom-left-radius: 8px; pointer-events: none; }
.of-side-foot { margin-top: auto; padding-top: 10px; border-top: 1px solid #dededc; }
.c-blue { background: #dcecff; color: #0b4a80; }
.c-yellow { background: #fff1b8; color: #5e4b00; }
.c-red { background: #fde0de; color: #8e1b1b; }
.of-dock { display: none; }

/* The side menu replaces each section's row of tabs. */
body.of-page .ops-subnav:not(.ops-subnav--marketing) { display: none; }
/* Marketing keeps its two tabs, Notifications and Email, as pills. */
:where(body.of-page) .ops-subnav--marketing { display: inline-flex; gap: 4px; margin: 0 0 16px; padding: 4px; border: 0; border-radius: 999px; background: #e9e7e4; }
:where(body.of-page) .ops-subnav--marketing a { display: inline-flex; align-items: center; gap: 8px; min-height: 34px; margin: 0; padding: 0 16px; border: 0; border-radius: 999px; color: #555555; font-size: 14px; font-weight: 700; text-decoration: none; }
:where(body.of-page) .ops-subnav--marketing a.is-active { background: #ffffff; color: #1f1f1f; box-shadow: 0 1px 2px rgba(58, 48, 42, 0.08); }
:where(body.of-page) .ops-subnav--marketing a svg { width: 15px; height: 15px; }

/* Search results (views/admin/search.ejs). */
.search-group { margin-bottom: 1.2rem; }
.search-group h2 { margin-top: 0; }
.search-list { list-style: none; margin: 0; padding: 0; }
.search-list li { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; padding: 0.6rem 0; border-top: 1px solid var(--border); }
.search-list li:first-child { border-top: 0; }
.search-list a { color: var(--ink); text-decoration: none; }
.search-list a:hover { text-decoration: underline; }

@media (max-width: 760px) {
  body.of-page { padding: 64px 0 96px; }
  body.of-page::before, body.of-page::after { display: none; }
  .of-top { gap: 8px; padding: 0 10px; }
  .of-brand { flex: 0 0 auto; }
  .of-brand img { height: 12px; }
  .of-acct { padding: 0 4px; }
  .of-acct-name { display: none; }
  .of-side { display: none; }
  .of-side.is-open { display: flex; top: 64px; width: auto; right: 0; z-index: 70; gap: 2px; padding: 18px 14px 110px; border-radius: 0; background: #ffffff; box-shadow: none; }
  .of-side.is-open .of-nav { min-height: 50px; gap: 16px; padding: 0 16px; border-radius: 16px; font-size: 17px; font-weight: 700; }
  .of-side.is-open .of-nav svg { flex-basis: 22px; width: 22px; height: 22px; stroke-width: 2.1; }
  .of-side.is-open .of-nav.is-on { background: #efefed; }
  .of-side.is-open .of-sub { padding-left: 38px; }
  .of-side.is-open .of-sub::before { display: none; }
  .of-side.is-open .of-sub .of-nav { min-height: 42px; font-size: 15px; font-weight: 600; padding-left: 16px; }
  .of-side.is-open .of-count { min-width: 24px; height: 22px; font-size: 12.5px; }
  .of-side.is-open .of-side-foot { margin-top: 12px; }
  .of-dock { position: fixed; z-index: 75; left: 12px; right: 12px; bottom: 16px; display: flex; align-items: center; justify-content: space-around; height: 56px; padding: 0 10px; border-radius: 999px; background: #1c1c1c; box-shadow: 0 8px 22px rgba(0, 0, 0, 0.28); }
  .of-dock-item { width: 42px; height: 42px; display: grid; place-items: center; border: 0; border-radius: 50%; background: none; color: #ffffff; cursor: pointer; }
  .of-dock-item.is-on, body.of-menu-open #of-menu-toggle { background: #ffffff; color: #1f1f1f; }
  body.of-menu-open .of-dock-item.is-on:not(#of-menu-toggle) { background: none; color: #ffffff; }
}

/* ------------------------------------------------------------------
   The office pages in the new look (Angel, 3 Oct look refresh, step 2).
   Each rule is written behind :where(body.of-page), which adds no
   weight: it matches only office pages, wins over the base rule it
   replaces by coming later in this file, and still gives way to any
   component's own more particular rule. Upper and lower case everywhere
   ("keep it upper and lower case across"); pills, rounded cards with a
   soft border and a shadow on hover; the dark espresso is what you press.
   ------------------------------------------------------------------ */
:where(body.of-page) { font-size: 14.5px; line-height: 1.5; color: #1f1f1f; }
:where(body.of-page) .container * { text-transform: none !important; letter-spacing: normal !important; }
:where(body.of-page) .container { max-width: 900px; padding: 28px 32px 64px; }
:where(body.of-page) .container--wide { max-width: 1140px; }
:where(body.of-page) h1 { margin: 0 0 0.5em; font-family: var(--heading-font); font-size: 28px; font-weight: 700; line-height: 1.2; color: #1a1a1a; }
:where(body.of-page) h2 { font-family: var(--body-font); font-size: 16px; font-weight: 800; line-height: 1.3; }
:where(body.of-page) h3, :where(body.of-page) h4 { font-family: var(--body-font); font-size: 14.5px; font-weight: 800; }
:where(body.of-page) .mini-head { font-size: 15px; }
:where(body.of-page) .muted, :where(body.of-page) .row-sub, :where(body.of-page) .form-hint { opacity: 1; color: #666666; }
:where(body.of-page) .ops-lede { opacity: 1; color: #666666; }

/* Cards, panels and tiles: white, rounded, a soft border, lifted on hover. */
:where(body.of-page) .card,
:where(body.of-page) .panel,
:where(body.of-page) .tile { border: 1px solid #e7e4e0; border-radius: 20px; background: #ffffff; padding: 20px 22px; transition: box-shadow .2s ease, border-color .2s ease; }
:where(body.of-page) .card:hover,
:where(body.of-page) .panel:hover,
:where(body.of-page) .tile:hover { border-color: #dedad5; box-shadow: 0 6px 18px rgba(58, 48, 42, 0.07); }
:where(body.of-page) .tile-label { opacity: 1; color: #666666; font-family: var(--body-font); font-size: 13px; font-weight: 600; }
:where(body.of-page) .tile-figure { font-family: var(--heading-font); font-size: 22px; font-weight: 700; }
:where(body.of-page) .tile-sub { opacity: 1; color: #666666; font-size: 12.5px; }
:where(body.of-page) .tile--warn { background: #fff8db; border-color: #f3e3a2; }
:where(body.of-page) .tile--alert { background: #fdecea; border-color: #f6cfcb; }
:where(body.of-page) .panel-h p { opacity: 1; color: #666666; font-size: 13px; }

/* Buttons: pills. The plain button is the espresso one, Secondary is white. */
:where(body.of-page .container) button,
:where(body.of-page .container) .btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 40px; padding: 0 18px; border: 1px solid #1c1c1c; border-radius: 999px; background: #1c1c1c; color: #ffffff; font-family: var(--body-font); font-size: 14px; font-weight: 700; line-height: 1.2; }
:where(body.of-page .container) button:hover,
:where(body.of-page .container) .btn:hover { opacity: 1; background: #000000; border-color: #000000; }
:where(body.of-page .container) .btn-secondary { border-color: #dcdcda; background: #ffffff; color: #1f1f1f; }
:where(body.of-page .container) .btn-secondary:hover { border-color: #1c1c1c; background: #ffffff; color: #1f1f1f; }
:where(body.of-page .container) .btn-small { min-height: 34px; padding: 0 14px; font-size: 13px; }

/* Fields: pills for one line, a rounded box for more. Labels in plain words. */
:where(body.of-page) label { opacity: 1; color: #1f1f1f; font-size: 13px; font-weight: 700; }
:where(body.of-page) input[type="text"],
:where(body.of-page) input[type="email"],
:where(body.of-page) input[type="password"],
:where(body.of-page) input[type="number"],
:where(body.of-page) input[type="search"],
:where(body.of-page) input[type="date"],
:where(body.of-page) input[type="url"],
:where(body.of-page) select { min-height: 42px; padding: 0 16px; border: 1px solid #dcdcda; border-radius: 999px; background-color: #ffffff; font-size: 14px; }
:where(body.of-page) select { -webkit-appearance: none; appearance: none; padding-right: 44px; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231f1f1f' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 18px center; background-size: 14px; cursor: pointer; }
:where(body.of-page) textarea { padding: 12px 16px; border: 1px solid #dcdcda; border-radius: 16px; background: #ffffff; font-size: 14px; }
/* A dropdown on a Stock form is a pill like the boxes beside it: .ops-form's
   own select rule outranked the one above, so they stayed square on a beige
   ground (Angel, 13 Oct: "off center vat selector"). */
:where(body.of-page) .ops-form select { min-height: 42px; padding: 0 44px 0 16px; border: 1px solid #dcdcda; border-radius: 999px; background-color: #ffffff; font-size: 14px; }
:where(body.of-page) input:focus, :where(body.of-page) select:focus, :where(body.of-page) textarea:focus { outline: none; border-color: #1f1f1f; }
:where(body.of-page) input[type="checkbox"] { width: 18px !important; min-width: 18px; height: 18px; padding: 0; margin: 0; flex: none; -webkit-appearance: none; appearance: none; border: 1.5px solid #b9b9bc; border-radius: 6px; background: #ffffff; cursor: pointer; vertical-align: middle; transition: background-color .15s, border-color .15s; }
:where(body.of-page) input[type="checkbox"]:hover { border-color: #8a8a8c; }
:where(body.of-page) input[type="checkbox"]:checked { border-color: #1c1c1c; background: #1c1c1c url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12.5 4.5 4.5L19 7.5'/%3E%3C/svg%3E") center/80% no-repeat; }
:where(body.of-page) input[type="radio"] { width: 18px !important; min-width: 18px; height: 18px; padding: 0; margin: 0; flex: none; -webkit-appearance: none; appearance: none; border: 1.5px solid #b9b9bc; border-radius: 50%; background: #ffffff; cursor: pointer; vertical-align: middle; }
:where(body.of-page) input[type="radio"]:checked { border: 5.5px solid #1c1c1c; }

/* Tables: on a white rounded card of their own, quiet headings, a soft
   line between rows. A table already inside a card just sits in it. */
:where(body.of-page) table { border-collapse: separate; border-spacing: 0; font-size: 14px; font-variant-numeric: tabular-nums; }
:where(body.of-page) .container > table,
:where(body.of-page) .ops-table { overflow: hidden; border: 1px solid #e7e4e0; border-radius: 20px; background: #ffffff; }
:where(body.of-page) .card table,
:where(body.of-page) .panel table,
:where(body.of-page) .card .ops-table,
:where(body.of-page) .panel .ops-table { border: 0; border-radius: 0; background: none; }
:where(body.of-page) th,
:where(body.of-page) .ops-table th { padding: 11px 16px; border-bottom: 1px solid #eeeeec; opacity: 1; color: #777777; font-family: var(--body-font); font-size: 12.5px; font-weight: 700; }
:where(body.of-page) td,
:where(body.of-page) .ops-table td { padding: 13px 16px; border-bottom: 1px solid #f2f2f0; }
:where(body.of-page) tbody tr:last-child td { border-bottom: 0; }
:where(body.of-page) tbody tr:hover td { background: #fafaf9; }
:where(body.of-page) td strong, :where(body.of-page) .row-link strong { font-weight: 600; }

/* Tabs that narrow a list: pills, the chosen one in espresso. */
:where(body.of-page) .filter-tabs { gap: 6px; }
:where(body.of-page) .filter-tabs a { min-height: 36px; padding: 0 14px; border: 0; border-radius: 999px; color: #555555; font-family: var(--body-font); font-size: 14px; font-weight: 700; }
:where(body.of-page) .filter-tabs a:hover { background: #ebebe9; color: #1f1f1f; }
:where(body.of-page) .filter-tabs a.is-on { background: #1c1c1c; color: #ffffff; }
:where(body.of-page) .filter-tabs a span { font-size: 13px; font-weight: 600; }

/* Status tags: no dots, one colour each for what it means. Blue is new,
   yellow is under way, green is ready, red is money or a problem, rose is
   part sent, grey is done. */
:where(body.of-page) .badge,
:where(body.of-page) .pill { display: inline-block; height: 24px; line-height: 24px; padding: 0 10px; border-radius: 999px; background: #ececea; color: #3d3d3d; font-family: var(--body-font); font-size: 12px; font-weight: 700; }
/* Written in small letters in the pages, so the first one is raised here. */
:where(body.of-page) .badge::first-letter, :where(body.of-page) .pill::first-letter { text-transform: uppercase; }
:where(body.of-page) .badge-new, :where(body.of-page) .fulfillment-new { background: #dcecff; color: #0b4a80; }
:where(body.of-page) .badge-processing, :where(body.of-page) .badge-packed,
:where(body.of-page) .fulfillment-processing, :where(body.of-page) .fulfillment-packed,
:where(body.of-page) .pill--warn { background: #fff1b8; color: #5e4b00; }
:where(body.of-page) .badge-ready_for_collection, :where(body.of-page) .fulfillment-ready_for_collection,
:where(body.of-page) .pill--good { background: #d4f5dd; color: #0f5129; }
:where(body.of-page) .badge-awaiting_payment, :where(body.of-page) .badge-rejected,
:where(body.of-page) .pill--alert { background: #fde0de; color: #8e1b1b; }
:where(body.of-page) .badge-part_sent, :where(body.of-page) .fulfillment-part_despatched { background: #fbe3ef; color: #8a1c4f; }
:where(body.of-page) .badge-paid, :where(body.of-page) .badge-invoiced, :where(body.of-page) .badge-sent,
:where(body.of-page) .badge-collected, :where(body.of-page) .badge-cancelled,
:where(body.of-page) .fulfillment-despatched, :where(body.of-page) .fulfillment-collected { background: #ececea; color: #3d3d3d; }

/* Messages: soft and rounded. */
:where(body.of-page) .error-msg, :where(body.of-page) .notice-msg,
:where(body.of-page) .success-msg, :where(body.of-page) .banner { padding: 12px 16px; border-radius: 16px; font-size: 14px; }
:where(body.of-page) .error-msg { background: #fde0de; color: #8e1b1b; }
:where(body.of-page) .notice-msg { background: #fff6d1; color: #4d3d00; }
:where(body.of-page) .success-msg { background: #d4f5dd; color: #0f5129; }
:where(body.of-page) .needs-attention { background: #fff8db; border-color: #f3e3a2; }

/* Home in the new look (views/admin/dashboard.ejs, 3 Oct). */
.home-hero { position: relative; overflow: hidden; display: flex; flex-direction: column; justify-content: space-between; gap: 24px; min-height: 220px; margin-bottom: 16px; padding: 28px 30px; border: 1px solid #e7e4e0; border-radius: 20px; background: #ffffff; }
.home-contours { position: absolute; top: 0; right: 0; width: 620px; max-width: none; height: 100%; object-fit: cover; object-position: right center; opacity: 0.55; pointer-events: none; }
.home-hero-text, .home-actions { position: relative; }
.home-date { margin: 0; color: #666666; font-size: 13px; font-weight: 700; }
:where(body.of-page) .home-hero h1 { margin: 6px 0 0; font-size: 30px; text-wrap: balance; }
.home-hero-text > p:last-child { max-width: 520px; margin: 8px 0 0; color: #555555; font-size: 15px; }
.home-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.home-stats { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 16px; }
.home-stat { flex: 1 1 170px; min-width: 0; display: flex; align-items: center; gap: 14px; padding: 16px 18px; border: 1px solid #e7e4e0; border-radius: 20px; background: #ffffff; color: #1f1f1f; text-decoration: none; transition: box-shadow .2s ease, border-color .2s ease; }
.home-stat:hover { border-color: #dedad5; box-shadow: 0 6px 18px rgba(58, 48, 42, 0.07); }
/* A tile you can press lifts on hover (Angel, 4 Oct: "a bit more shadow", then "a touch less", as it ran over the tiles beside it). */
a.home-stat:hover { border-color: #d6d1cb; box-shadow: 0 5px 12px rgba(58, 48, 42, 0.12); }
.home-ic { flex: 0 0 44px; width: 44px; height: 44px; display: grid; place-items: center; border-radius: 50%; }
.c-rose { background: #fbe3ef; color: #8a1c4f; }
.c-green { background: #d4f5dd; color: #0f5129; }
.home-stat b { display: block; font-family: var(--heading-font); font-size: 21px; font-weight: 700; line-height: 1.15; font-variant-numeric: tabular-nums; }
.home-stat small { display: block; color: #666666; font-size: 13px; line-height: 1.3; }
.home-figures { margin-bottom: 16px; }
.home-figures .stat-row { margin: 14px 0 18px; }
.home-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 16px; }
.home-card-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 6px; }
:where(body.of-page) .home-card-head h2 { margin: 0; }
.home-rows { list-style: none; margin: 0; padding: 0; }
.home-rows li { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 11px 0; border-top: 1px solid #f0f0ee; font-variant-numeric: tabular-nums; }
.home-rows li:first-child { border-top: 0; }
.home-rows li > span:first-child { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.home-rows small { color: #666666; font-size: 12.5px; }
.home-rows a { color: #1f1f1f; text-decoration: none; }
.home-rows a:hover { text-decoration: underline; }
.home-rows b { white-space: nowrap; font-weight: 700; }
@media (max-width: 760px) {
  .home-hero { padding: 22px 20px; }
  :where(body.of-page) .home-hero h1 { font-size: 24px; }
  .home-contours { opacity: 0.3; }
  .home-stats { gap: 10px; }
  .home-stat { flex-basis: calc(50% - 5px); gap: 10px; padding: 14px; }
  .home-ic { flex-basis: 38px; width: 38px; height: 38px; }
}
:where(body.of-page) .category-chip { min-height: 36px; padding: 0 14px; border: 0; border-radius: 999px; background: transparent; color: #555555; font-family: var(--body-font); font-size: 14px; font-weight: 700; }
:where(body.of-page) .category-chip:hover { background: #ebebe9; color: #1f1f1f; }
:where(body.of-page) .category-chip.active { background: #1c1c1c; border-color: #1c1c1c; color: #ffffff; }
:where(body.of-page) .stat-row .stat { border: 1px solid #e7e4e0; border-radius: 16px; background: #fafaf9; }

/* Lists on one card with their tabs (Orders first, 3 Oct). */
.page-head-row { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 16px; margin-bottom: 20px; }
:where(body.of-page) .page-head-row h1 { margin: 0; }
.page-lede { margin: 4px 0 0; color: #666666; }
:where(body.of-page) .list-card { padding: 0; overflow: hidden; }
:where(body.of-page) .list-tabs { margin: 0; padding: 14px 16px; border-bottom: 1px solid #f0f0ee; }
.tab-count { min-width: 22px; height: 20px; padding: 0 7px; display: inline-grid; place-items: center; border-radius: 999px; font-size: 12px; font-weight: 800; }
:where(body.of-page) .filter-tabs a.is-on .tab-count { opacity: 1; }
.list-card-body { padding: 16px 20px 20px; }
.list-empty { padding: 20px 22px; margin: 0; }
.order-no, .order-co { color: #1a1a1a; text-decoration: none; }
/* Underlined only where it opens something: the floor's customer names don't (Angel, 3 Oct). */
a.order-no:hover, a.order-co:hover { text-decoration: underline; }
.note-flag { display: inline-flex; align-items: center; gap: 4px; height: 22px; margin-left: 8px; padding: 0 8px; border-radius: 999px; background: #fff1b8; color: #5e4b00; font-size: 12px; font-weight: 700; text-decoration: none; vertical-align: middle; }
.note-flag:hover { background: #ffe58a; }
:where(body.of-page) .pill--collect { background: #ebe5ff; color: #4b2a9a; }
.list-pager { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 20px 16px; border-top: 1px solid #f2f2f0; color: #666666; font-size: 13px; }
.list-pager span:last-child { display: flex; gap: 8px; }

/* The order page in two columns (views/admin/request-detail.ejs, 3 Oct). */
.order-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 16px; margin-bottom: 20px; }
.order-title { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
:where(body.of-page) .order-title h1 { margin: 0; }
.order-title .note-flag { margin-left: 0; height: 24px; }
.order-cols { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 16px; align-items: start; }
.order-main, .order-side { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
:where(body.of-page) .order-card { padding: 20px 22px; }
:where(body.of-page) .order-card-title, :where(body.of-page) .order-section-title { margin: 0 0 12px; font-family: var(--body-font); font-size: 16px; font-weight: 800; }
.order-card-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
:where(body.of-page) .order-card-head .order-card-title { margin: 0; }
:where(body.of-page) .order-card .order-section-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 0 0 8px; }
:where(body.of-page) .order-card .order-section-head .order-section-title { margin: 0; }
.order-card p { margin: 0 0 10px; }
/* The customer's note: who it's from on top, in a discreet frame so it
   isn't lost on the page (Angel, 3 Oct). */
.order-cust-note { padding: 12px 14px; border: 1px solid #e2ddd6; border-radius: 14px; background: #fbfaf8; font-size: 14px; white-space: pre-line; }
.order-cust-note small { display: block; margin: 0 0 4px; color: #666666; font-size: 12.5px; font-weight: 700; white-space: normal; }
:where(body.of-page) #order-status select { width: 100%; margin-bottom: 10px; }
.order-invoiced { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 14px 0 0; padding-top: 14px; border-top: 1px solid #f0f0ee; }
:where(body.of-page) .order-history { margin: 0; }
.order-parts:empty { display: none; }
.order-side-note { margin: 0; font-size: 13px; }
.order-delete { margin: 0; }
:where(body.of-page .container) .order-delete button { border-color: #e9c8c5; background: #ffffff; color: #8e1b1b; }
:where(body.of-page .container) .order-delete button:hover { border-color: #8e1b1b; background: #ffffff; }
@media (max-width: 1100px) { .order-cols { grid-template-columns: minmax(0, 1fr); } }
/* The copy of For collection that rides with a phone card's tags stays
   hidden on a computer, as before the new tag styles. */
:where(body.of-page) .pill--on-card { display: none; }
@media (max-width: 760px) { :where(body.of-page) table.cards .pill--on-card { display: inline-block; } }
/* Figures typed inside a table row: smaller pills, so a price fits. */
:where(body.of-page) td input[type="number"], :where(body.of-page) td input[type="text"] { min-height: 36px; padding: 0 10px; }

/* A product and a customer in two columns (3 Oct). */
.pf-cols, .cust-cols { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 16px; align-items: start; margin-bottom: 16px; }
.pf-main, .pf-side, .cust-side { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
:where(body.of-page) .pf-cols h2, :where(body.of-page) .cust-cols h2 { margin: 0 0 12px; }
:where(body.of-page) .pf-cols .card > :last-child { margin-bottom: 0; }
:where(body.of-page) .pf-cols .field-row { flex-wrap: wrap; }
.cust-head { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; margin-bottom: 20px; }
:where(body.of-page) .cust-head h1 { margin: 0; }
.cust-av { flex: 0 0 52px; width: 52px; height: 52px; display: grid; place-items: center; border-radius: 50%; background: #ececea; color: #3d3d3d; font-family: var(--heading-font); font-size: 17px; font-weight: 700; }
.cust-orders-head { margin-top: 8px; }
@media (max-width: 1100px) { .pf-cols, .cust-cols { grid-template-columns: minmax(0, 1fr); } }
/* The little labels on a phone's table cards come from ::before; normal case there too. */
:where(body.of-page) .container *::before, :where(body.of-page) .container *::after { text-transform: none !important; letter-spacing: normal !important; }
:where(body.of-page) .ops-head .ops-subnav--marketing { flex-basis: auto; width: max-content; max-width: 100%; }
:where(body.of-page) .send-part > summary { display: inline-flex; align-items: center; }
/* The Note flag stays on the line with its order number. */
:where(body.of-page) td:has(> .note-flag) { white-space: nowrap; }
/* On a phone's table cards, each detail starts at the top of its line, so a
   long address doesn't push the item list beside it halfway down. */
@media (max-width: 760px) { :where(body.of-page) table.cards tr { align-items: flex-start; } }

/* Roasting and Making in the new look: the plan's rows line up along their
   first line, the day's arrows sit either side of the day, and the day's
   roasts sit on a card of their own, as designed. */
:where(body.of-page) .roast-next { align-items: start; }
:where(body.of-page) .rn-bar { padding-top: 7px; }
:where(body.of-page) .rn-do { align-self: start; }
:where(body.of-page) .roast-day-when { min-width: 0; }
:where(body.of-page) .roast-day-when strong { font-size: 18px; }
:where(body.of-page) .roast-day { padding: 18px 22px; border: 1px solid #e7e4e0; border-radius: 20px; background: #ffffff; }
:where(body.of-page) .roast-day-head { align-items: center; }
:where(body.of-page) .roast-day-jump .field > span { color: #666666; font-size: 13px; font-weight: 700; }
:where(body.of-page) .roast-day-jump input { margin: 0; }
:where(body.of-page) .roast-day-empty { color: #555555; }
:where(body.of-page) .roast-day-foot { margin: 14px 0 0; padding-top: 12px; border-top: 1px solid #f2f2f0; }
:where(body.of-page) .roast-day-foot a { font-weight: 700; text-decoration: none; }
/* Button words stay on one line; on a narrow screen a row of buttons wraps
   onto a second line instead of squashing each one (Tasks on a phone). */
:where(body.of-page .container) button, :where(body.of-page .container) .btn { white-space: nowrap; }
:where(body.of-page) .ops-actions, :where(body.of-page) .head-actions, :where(body.of-page) .page-head .row-actions, :where(body.of-page) .ops-head .row-actions { flex-wrap: wrap; }

/* The Menu button is a real button, so the old button padding is taken off
   or its circle sits off-centre round the icon. */
.of-dock-item { padding: 0; }
@media (max-width: 760px) { .of-dock { padding: 0 12px; } }
/* On a phone, a row of page buttons is a size smaller so it fits on one line. */
@media (max-width: 760px) {
  :where(body.of-page) .ops-actions { gap: 8px; }
  :where(body.of-page .container) .ops-actions > .btn, :where(body.of-page .container) .ops-actions > button,
  :where(body.of-page .container) .page-head .row-actions .btn, :where(body.of-page .container) .ops-head .row-actions .btn { min-height: 36px; padding: 0 13px; font-size: 13px; }
}

/* Home's top row, This month and Your tasks (3 Oct, from the canvas). */
.home-top { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 16px; margin-bottom: 16px; }
.home-top .home-hero { margin-bottom: 0; }
.home-top:not(:has(.home-month)) { grid-template-columns: minmax(0, 1fr); }
:where(body.of-page) .home-month { display: flex; flex-direction: column; gap: 6px; }
.home-big { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; font-variant-numeric: tabular-nums; }
.home-big strong { font-family: var(--heading-font); font-size: 30px; font-weight: 700; color: #1a1a1a; white-space: nowrap; }
.home-big-sub { margin: 0 0 4px; font-size: 12.5px; }
.chg { display: inline-flex; align-items: center; height: 22px; padding: 0 8px; border-radius: 999px; background: #d4f5dd; color: #0f5129; font-size: 12px; font-weight: 800; }
.chg.down { background: #fde0de; color: #8e1b1b; }
.home-tasks li { justify-content: flex-start; }
.home-tick { margin: 0; flex: none; }
:where(body.of-page .container) .home-tick-box { width: 20px; height: 20px; min-height: 20px; padding: 0; border: 1.5px solid #b9b9bc; border-radius: 6px; background: #ffffff; cursor: pointer; }
:where(body.of-page .container) .home-tick-box:hover { border-color: #1c1c1c; background: #f3f3f2; }
.home-task-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.home-ic--plain { border: 1px solid #e4e4e2; color: #1f1f1f; }
.c-violet { background: #ebe5ff; color: #4b2a9a; font-weight: 800; }
.cust-stats { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 16px; }
.cust-stats .home-stat { cursor: default; }
@media (max-width: 1180px) { .home-top { grid-template-columns: minmax(0, 1fr); } }

/* Reports (views/admin/reports.ejs). */
.report-range select { min-width: 190px; margin: 0; }
/* The range as a dropdown with a calendar in it, Shopify's way (Angel, 4
   Oct), on Home's chart and Reports alike. */
.period-pick { position: relative; display: inline-flex; align-items: center; margin: 0; }
.period-pick > svg { position: absolute; left: 15px; color: #1f1f1f; pointer-events: none; }
.period-pick select { width: auto; min-width: 190px; margin: 0; padding-left: 42px; font-weight: 700; color: #1f1f1f; }
.home-figures.is-loading #trend-chart, .home-figures.is-loading .stat { opacity: .4; transition: opacity .2s ease; }
/* Reports' own dates, and its Export menu (Angel, 4 Oct). */
.report-range { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0; }
.report-custom { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.report-custom[hidden] { display: none; }
.report-custom input[type="date"] { width: auto; min-height: 42px; margin: 0; padding: 0 12px; border: 1px solid #dcdcda; border-radius: 999px; background: #ffffff; color: #1f1f1f; font-family: var(--body-font); font-size: 14px; }
.report-export > summary { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.report-export .list-menu a .muted { font-size: 12px; font-weight: 400; }
@media (prefers-reduced-motion: reduce) { .home-figures.is-loading #trend-chart, .home-figures.is-loading .stat { transition: none; } }
.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 16px; margin-bottom: 16px; }
:where(body.of-page) .kpi { padding: 16px 18px; }
.kpi small { display: block; color: #666666; font-size: 13px; }
.kpi b { display: block; margin: 4px 0 6px; font-family: var(--heading-font); font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
:where(body.of-page) .report-chart { margin-bottom: 16px; }
.report-chart-head, .report-card-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 10px; }
:where(body.of-page) .report-chart-head h2, :where(body.of-page) .report-card-head h2 { margin: 0; }
.report-card-head p { margin: 2px 0 0; font-size: 12.5px; }
:where(body.of-page) .list-card .report-card-head { padding: 18px 20px 4px; margin: 0; }
.report-card-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.report-pick { margin: 0; }
:where(body.of-page) .report-pick select { min-height: 34px; height: 34px; margin: 0; padding-top: 0; padding-bottom: 0; font-size: 13px; }
:where(body.of-page) .list-card .report-card-head { align-items: center; }
.report-svg { display: block; width: 100%; height: 200px; }
/* The hover over the sales chart, as on Home's (public/js/report-chart.js). */
.report-plot { position: relative; }
.report-hover-line { position: absolute; width: 1px; background: var(--border); transform: translateX(-0.5px); pointer-events: none; }
.report-hover-dot { position: absolute; width: 8px; height: 8px; margin: -4px 0 0 -4px; border-radius: 50%; background: #1a73e8; pointer-events: none; }
.report-hover-dot.prev { width: 10px; height: 10px; margin: -5px 0 0 -5px; background: #ffffff; border: 2px solid #9db7d6; box-sizing: border-box; }
.report-hover-line[hidden], .report-hover-dot[hidden] { display: none; }
.report-axis { display: flex; justify-content: space-between; padding-top: 6px; color: #666666; font-size: 12px; }
.report-legend { display: flex; flex-wrap: wrap; gap: 18px; padding-top: 10px; color: #666666; font-size: 12.5px; }
.report-legend i { display: inline-block; width: 16px; height: 0; margin-right: 6px; vertical-align: middle; border-top: 2.5px solid #1a73e8; }
.report-legend i.prev { border-top: 2.5px dotted #9db7d6; }
.report-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(380px, 1fr)); gap: 16px; align-items: start; }
.bars { list-style: none; margin: 0; padding: 4px 0 0; }
.bars li { display: grid; grid-template-columns: minmax(0, 160px) minmax(0, 1fr) 70px; align-items: center; gap: 12px; padding: 7px 0; font-variant-numeric: tabular-nums; }
.bars .bar { height: 10px; overflow: hidden; border-radius: 999px; background: #efedea; }
.bars .bar i { display: block; height: 100%; border-radius: 999px; background: #1a73e8; }
.bars .bar i.red { background: #e0645a; }
.bars b { font-weight: 600; text-align: right; }
.share { display: inline-block; width: 60px; height: 6px; margin-right: 8px; overflow: hidden; border-radius: 999px; background: #efedea; vertical-align: middle; }
.share i { display: block; height: 100%; background: #1a73e8; }
@media (max-width: 760px) { .report-grid { grid-template-columns: minmax(0, 1fr); } .bars li { grid-template-columns: minmax(0, 110px) minmax(0, 1fr) 60px; } }
@media (max-width: 760px) {
  .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  :where(body.of-page) .kpi { padding: 14px; }
  .kpi b { font-size: 19px; }
  .cust-stats { gap: 10px; }
  .cust-stats .home-stat { flex-basis: calc(50% - 5px); gap: 10px; padding: 14px; }
}

/* The order page's Status card: room between the button and what went out,
   and the box note in the card's own quiet style rather than a green block. */
:where(body.of-page) #order-status { display: flex; flex-direction: column; align-items: stretch; gap: 12px; }
:where(body.of-page) #order-status > button { align-self: flex-start; }
:where(body.of-page) #order-status > label { margin: 0; }
:where(body.of-page) #order-status select { margin: 0; }
:where(body.of-page) #order-status > p, :where(body.of-page) #order-status .muted { margin: 0; }
:where(body.of-page) .packed-with { align-self: stretch; margin: 2px 0 0; padding: 10px 14px; border-radius: 14px; background: #f3f8f4; color: #2f4a35; font-size: 13.5px; }
:where(body.of-page) .packed-with strong { font-weight: 700; }
/* Done tasks: the tick sits above the row's hover colour. */
.task-done-tick, .task-cancelled-tick { position: relative; z-index: 1; }

/* Web shop orders among the wholesale ones on Orders: just a small rose
   tag by the number, so they read as Shopify's, there to follow. The row
   itself stays like any other (Angel, 3 Oct: "no need for the website
   orders to be in pink the whole thing"). */
.web-flag { display: inline-flex; align-items: center; height: 20px; margin-left: 8px; padding: 0 7px; border-radius: 999px; background: #fbe3ef; color: #8a1c4f; font-size: 11.5px; font-weight: 700; vertical-align: middle; white-space: nowrap; }
:where(body.of-page) td:has(> .web-flag) { white-space: nowrap; }

/* Orders as designed (3 Oct): today's figures, then one bar holding the
   tabs, a More menu for the rarer questions and a box to find an order. */
.order-stats .home-stat { cursor: default; }
/* The More menu drops out over the card's edge, so this card doesn't clip;
   its last row keeps the rounded corners instead. */
:where(body.of-page) .list-card--menu { overflow: visible; }
:where(body.of-page) .list-card--menu > table tbody tr:last-child td:first-child { border-bottom-left-radius: 18px; }
:where(body.of-page) .list-card--menu > table tbody tr:last-child td:last-child { border-bottom-right-radius: 18px; }
.order-stats a.home-stat { cursor: pointer; }
.c-grey { background: #ececea; color: #3d3d3d; }
.list-bar { display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-bottom: 1px solid #f0f0ee; }
.list-tablist { flex: 1; min-width: 0; display: flex; align-items: center; gap: 6px; overflow-x: auto; scrollbar-width: none; }
.list-tablist::-webkit-scrollbar { display: none; }
.list-tab { display: flex; align-items: center; gap: 6px; min-height: 36px; padding: 0 14px; border-radius: 999px; color: #555555; font-size: 14px; font-weight: 700; text-decoration: none; white-space: nowrap; cursor: pointer; }
.list-tab:hover { background: #f3f3f2; color: #1f1f1f; }
.list-tab.is-on, .list-tab.is-on:hover { background: #1c1c1c; color: #ffffff; }
.list-more { position: relative; flex: none; }
.list-more summary { list-style: none; }
.list-more summary::-webkit-details-marker { display: none; }
.list-more summary svg { transition: transform .15s; }
.list-more[open] summary:not(.is-on) { background: #f3f3f2; color: #1f1f1f; }
.list-more[open] summary svg { transform: rotate(180deg); }
.list-menu { position: absolute; z-index: 20; top: calc(100% + 6px); right: 0; min-width: 240px; display: flex; flex-direction: column; padding: 6px; border-radius: 16px; background: #ffffff; box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12), 0 0 0 1px rgba(0, 0, 0, 0.05); }
.list-menu a { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 36px; padding: 0 12px; border-radius: 10px; color: #1f1f1f; font-size: 14px; font-weight: 600; text-decoration: none; white-space: nowrap; }
.list-menu a:hover, .list-menu a.is-on { background: #f3f3f2; }
.list-find { flex: none; display: flex; align-items: center; gap: 8px; height: 36px; margin: 0; padding: 0 14px; border: 1px solid #e4e4e2; border-radius: 999px; background: #ffffff; color: #555555; }
.list-find:focus-within { border-color: #8c8c8c; }
:where(body.of-page) .list-find input { width: 130px; min-height: 0; height: auto; margin: 0; padding: 0; border: 0; border-radius: 0; background: none; box-shadow: none; outline: 0; color: #1f1f1f; font: inherit; font-size: 14px; }
.list-pager-btns { display: flex; gap: 8px; }
.list-round { width: 36px; height: 36px; display: grid; place-items: center; border: 1px solid #e4e4e2; border-radius: 50%; background: #ffffff; color: #1f1f1f; text-decoration: none; }
.list-round:hover { border-color: #1c1c1c; }
.list-round.is-off { opacity: 0.4; }
.list-round.is-off:hover { border-color: #e4e4e2; }
@media (max-width: 980px) { .list-find { display: none; } }
@media (max-width: 760px) {
  .order-stats .home-stat { flex-basis: calc(50% - 5px); gap: 10px; padding: 14px; }
  .list-bar { padding: 12px; }
  .list-tablist { flex: 0 1 auto; }
}

/* On a phone or a narrow window (3 Oct, after going live): the side menu
   folds away and a menu button takes the logo's place at the top left,
   opening the menu over the page. No dock at the foot: the page gets the
   whole screen. */
.of-burger-btn { display: none; }
@media (max-width: 1024px) {
  body.of-page { padding: 64px 0 24px; }
  body.of-page::before, body.of-page::after { display: none; }
  .of-top { gap: 10px; padding: 0 12px; }
  .of-burger-btn { flex: none; display: grid; place-items: center; width: 42px; height: 42px; padding: 0; border: 0; border-radius: 50%; background: transparent; color: #1f1f1f; cursor: pointer; }
  .of-burger-btn:hover, body.of-menu-open .of-burger-btn { background: #f3f3f2; }
  .of-brand { display: none; }
  .of-search-wrap { margin: 0; max-width: none; }
  .of-acct { padding: 0 4px; }
  .of-acct-name { display: none; }
  .of-side { display: none; }
  .of-side.is-open { display: flex; top: 64px; left: 0; right: 0; bottom: 0; width: auto; z-index: 70; gap: 2px; padding: 18px 14px 40px; border-radius: 0; background: #ffffff; box-shadow: none; }
  .of-side.is-open .of-nav { min-height: 50px; gap: 16px; padding: 0 16px; border-radius: 16px; font-size: 17px; font-weight: 700; }
  .of-side.is-open .of-nav svg { flex-basis: 22px; width: 22px; height: 22px; stroke-width: 2.1; }
  .of-side.is-open .of-nav.is-on { background: #efefed; }
  .of-side.is-open .of-sub { padding-left: 38px; }
  .of-side.is-open .of-sub::before { display: none; }
  .of-side.is-open .of-sub .of-nav { min-height: 42px; padding-left: 16px; font-size: 15px; font-weight: 600; }
  .of-side.is-open .of-count { min-width: 24px; height: 22px; font-size: 12.5px; }
  .of-side.is-open .of-side-foot { margin-top: 12px; }
  body.of-menu-open { overflow: hidden; }
}
@media (max-width: 760px) {
  :where(body.of-page) .container { padding: 18px 12px 40px; }
}

/* Home's chart card, as designed: the range across the top, the figure,
   then Revenue / Orders / Average order as one pill, the line below. */
:where(body.of-page) .category-filter { flex-wrap: nowrap; margin-top: 0; overflow-x: auto; scrollbar-width: none; }
:where(body.of-page) .category-filter::-webkit-scrollbar { display: none; }
:where(body.of-page) .home-periods { margin-bottom: 12px; }
:where(body.of-page) .home-metric-row { display: block; margin: 0 0 12px; }
:where(body.of-page) #stat-metric { padding: 0; border: 0; background: none; }
:where(body.of-page) #stat-metric .n { font-family: var(--heading-font); font-size: 30px; font-weight: 700; color: #1a1a1a; }
:where(body.of-page) #stat-metric .label { color: #666666; font-size: 13px; }
:where(body.of-page) .home-metrics { display: inline-flex; max-width: 100%; gap: 4px; padding: 4px; border-radius: 999px; background: #f3f3f2; }
:where(body.of-page) .home-metrics .category-chip { min-height: 32px; white-space: nowrap; }
:where(body.of-page) .home-metrics .category-chip:not(.active):hover { background: #e9e7e4; }

/* The top bar's arrow is the way back on every screen size; a page's own
   "Back to ..." link steps aside (its address goes to the arrow). */
:where(body.of-page) .page-back { display: none; }
@media (max-width: 1024px) { .of-search-wrap { gap: 8px; } }

/* The Packing slip button beside an order's title (3 Oct). */
.head-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.head-actions .btn, .slip-btn { display: inline-flex; align-items: center; gap: 8px; }
.slip-btn { margin-left: auto; }

/* Create order from Orders: who it's for, at the top of the form. */
.order-for { max-width: 32rem; margin: 0 0 1.2rem; }
.co-av { flex: 0 0 34px; width: 34px; height: 34px; display: grid; place-items: center; border-radius: 50%; background: #ececea; color: #3d3d3d; font-size: 12px; font-weight: 800; }

/* Lists whose rows open their page (public/js/row-links.js). */
table.row-links tbody tr[data-href] { cursor: pointer; }
.co { display: inline-flex; align-items: center; gap: 10px; }

/* A customer as designed (views/admin/customer-detail.ejs, 3 Oct). */
.cust-head { margin-bottom: 0; }
.cust-title { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
:where(body.of-page) .cust-title h1 { margin: 0; }
.cust-cols .card h2 { font-size: 16px; }
.kv { list-style: none; margin: 0; padding: 0; }
.kv li { padding: 9px 0; border-top: 1px solid #f0f0ee; overflow-wrap: anywhere; }
.kv li:first-child { border-top: 0; padding-top: 2px; }
.kv small { display: block; color: #666666; font-size: 12.5px; }
.kv .pre { white-space: pre-line; }
.cust-form { display: none; }
.cust-edit.is-editing .cust-form { display: block; }
.cust-edit.is-editing .cust-read, .cust-edit.is-editing .cust-edit-btn { display: none; }
.cust-card-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; margin-top: 12px; }
.cust-card-actions--start { justify-content: flex-start; margin-top: 4px; }
.cust-card-actions form { margin: 0; }
/* Archive, restore and delete under the account's own buttons (4 Oct). */
.cust-put-away { margin-top: 12px; padding-top: 12px; border-top: 1px solid #f0f0ee; }
.cust-put-away + .form-hint { margin: 8px 0 0; }
:where(body.of-page) .cust-notes textarea { margin: 0; }
:where(body.of-page .container) button.btn-danger-soft { border-color: #e9c8c5; color: #8e1b1b; }

/* A product previewed from the office (views/product.ejs). */
.preview-band { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; margin: 0 0 1.5rem; padding: 12px 16px; border-radius: 14px; background: #fff1b8; color: #5e4b00; }

/* Inventory as designed (views/admin/ops-stock.ejs, 3 Oct): the tabs are
   buttons that narrow the list, styled as the other lists' tabs. */
:where(body.of-page .container) button.list-tab { min-height: 36px; padding: 0 14px; border: 0; border-radius: 999px; background: transparent; color: #555555; font-size: 14px; font-weight: 700; box-shadow: none; }
:where(body.of-page .container) button.list-tab:hover { background: #f3f3f2; color: #1f1f1f; }
:where(body.of-page .container) button.list-tab.is-on { background: #1c1c1c; color: #ffffff; }
:where(body.of-page) .inv-card .inv-table { margin: 0; }
:where(body.of-page) .inv-card .stock-none { padding: 20px 22px; margin: 0; }
.home-stat[data-filter] { cursor: pointer; }

/* A badge given one of the colours (Inventory's status, a customer's
   Active or Disabled) keeps it over the general badge style above. */
.badge.c-blue { background: #dcecff; color: #0b4a80; }
.badge.c-yellow { background: #fff1b8; color: #5e4b00; }
.badge.c-red { background: #fde0de; color: #8e1b1b; }
.badge.c-green { background: #d4f5dd; color: #0f5129; }
.badge.c-rose { background: #fbe3ef; color: #8a1c4f; }
.badge.c-grey { background: #ececea; color: #3d3d3d; }

/* Order numbers in every list, office and floor, wholesale and web shop,
   equally bold (Angel, 3 Oct). */
.order-no { font-weight: 700; }

/* When an order was placed stays on one line in the order lists, office
   and floor (Angel, 3 Oct: "date gets squished"). On a phone the cards lay
   it out themselves. */
@media (min-width: 761px) {
  :where(body.of-page) .order-list td.cell-line, :where(body.of-page) .order-list td.addr-cell { white-space: nowrap; }
}

/* An order's Note and Web shop tags sit under its number, so a tag never
   widens the Order column and pushes the rest along (Angel, 3 Oct). */
.order-cell .note-flag, .order-cell .web-flag { display: flex; width: max-content; margin: 5px 0 0; }
:where(body.of-page) td.order-cell { white-space: nowrap; }
/* The floor's Wholesale and Web shop lists share their column widths, so
   switching tabs moves nothing. */
@media (min-width: 761px) {
  table.floor-orders { table-layout: fixed; width: 100%; }
  table.floor-orders th:nth-child(1) { width: 10%; }
  table.floor-orders th:nth-child(2) { width: 15%; }
  table.floor-orders th:nth-child(3) { width: 16%; }
  table.floor-orders th:nth-child(4) { width: 21%; }
  table.floor-orders th:nth-child(5) { width: 22%; }
  table.floor-orders th:nth-child(6) { width: 16%; }
  table.floor-orders select.status-pick { width: 100%; }
}
/* On a narrower window the address and the date wrap inside their own
   columns rather than running into the next. */
@media (min-width: 761px) and (max-width: 1199px) {
  :where(body.of-page) table.floor-orders td.addr-cell, :where(body.of-page) table.floor-orders td.cell-line { white-space: normal; }
}

/* The office's Orders: the same column widths on every tab (Angel, 3 Oct).
   On a narrower window its short columns lay themselves out. */
@media (min-width: 1200px) {
  table.office-orders { table-layout: fixed; width: 100%; }
  table.office-orders th:nth-child(1) { width: 10%; }
  table.office-orders th:nth-child(2) { width: 14%; }
  table.office-orders th:nth-child(3) { width: 20%; }
  table.office-orders th:nth-child(4) { width: 9%; }
  table.office-orders th:nth-child(5) { width: 12%; }
  table.office-orders th:nth-child(6) { width: 13%; }
  table.office-orders th:nth-child(7) { width: 9%; }
  table.office-orders th:nth-child(8) { width: 13%; }
  table.office-orders--no-money th:nth-child(1) { width: 11%; }
  table.office-orders--no-money th:nth-child(2) { width: 15%; }
  table.office-orders--no-money th:nth-child(3) { width: 22%; }
  table.office-orders--no-money th:nth-child(4) { width: 13%; }
  table.office-orders--no-money th:nth-child(5) { width: 14%; }
  table.office-orders--no-money th:nth-child(6) { width: 10%; }
  table.office-orders--no-money th:nth-child(7) { width: 15%; }
  table.office-orders td { overflow-wrap: anywhere; }
}

/* Integrations, tidied (views/admin/ops-integrations.ejs, 3 Oct): three
   short tiles for what's connected, a compact list of what Shopify sent. */
:where(body.of-page) .integration-card { gap: 18px; padding: 22px 24px; }
:where(body.of-page) .integration-title { margin: 0; font-size: 18px; }
.int-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; }
.int-tile { display: flex; gap: 12px; align-items: flex-start; padding: 14px 16px; border: 1px solid #ece9e4; border-radius: 16px; background: #fbfaf8; font-size: 13.5px; }
.int-tile b { display: block; font-size: 14px; font-weight: 800; }
.int-tile span { display: block; color: #555555; }
.int-tile a { display: inline-block; margin-top: 4px; color: #1f1f1f; font-weight: 700; }
.int-tile .int-ic { flex: 0 0 28px; width: 28px; height: 28px; display: grid; place-items: center; border-radius: 50%; background: #ececea; color: #777777; }
.int-tile.is-on .int-ic { background: #d4f5dd; color: #0f5129; }
.int-section { padding-top: 16px; border-top: 1px solid #f0f0ee; }
:where(body.of-page) .int-sub { margin: 0 0 8px; font-size: 15px; font-weight: 800; }
:where(body.of-page) .integration-card .hook-log { margin: 0; font-size: 13.5px; }
:where(body.of-page) .integration-card .hook-log li { display: grid; grid-template-columns: 9.5rem 1fr auto auto; gap: 12px; align-items: center; padding: 9px 0; border-bottom: 1px solid #f2f2f0; }
:where(body.of-page) .integration-card .hook-log li:last-child { border-bottom: 0; }
.hook-log-order { color: #555555; font-variant-numeric: tabular-nums; }
.int-more { margin: 6px 0 0; font-size: 13.5px; }
.int-more > summary { display: inline-flex; cursor: pointer; color: #555555; font-weight: 700; }
.int-more > summary:hover { color: #1f1f1f; }
.int-setup { padding-top: 12px; border-top: 1px solid #f0f0ee; }
.int-event { min-width: 9rem; font-weight: 700; }
@media (max-width: 760px) {
  :where(body.of-page) .integration-card .hook-log li { grid-template-columns: 1fr auto; }
  .hook-log-when { grid-column: 1 / -1; }
}

/* Settings' backups: five to a page under the table (3 Oct). */
:where(body.of-page) .backup-pager { padding: 12px 0 14px; border-top: 0; }

/* A task's buttons (partials/task-actions.ejs, 3 Oct): Mark done dark with a
   tick, Hand over a rounded picker like the other buttons. */
.task-done-btn { display: inline-flex; align-items: center; gap: 6px; }
:where(body.of-page) .hand-over select { min-height: 34px; height: 34px; margin: 0; padding: 0 34px 0 14px; border: 1px solid #dcdcda; border-radius: 999px; background-color: #ffffff; color: #1f1f1f; font-family: var(--body-font); font-size: 13px; font-weight: 700; letter-spacing: 0; text-transform: none; cursor: pointer; }
:where(body.of-page) .hand-over select { -webkit-appearance: none; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231f1f1f' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; background-size: 13px; }
:where(body.of-page) .hand-over select:hover { border-color: #1c1c1c; }

/* The page's two top corners, where the white top bar meets it, drawn from
   the top bar itself so they're the same at every size: the left one no
   longer comes from the side menu, where it left a notch at the window's
   edge, and on a phone or narrow window the corners and the soft shade under
   the bar show too (Angel, 3 Oct). */
.of-top::before, .of-top::after { content: ""; position: absolute; top: 100%; width: 18px; height: 18px; pointer-events: none; }
.of-top::before { left: 0; background: radial-gradient(circle at 100% 100%, transparent 17.5px, #ffffff 18px); }
.of-top::after { right: 0; background: radial-gradient(circle at 0 100%, transparent 17.5px, #ffffff 18px); }
body.of-page::before { display: none; }
.of-side { border-top-left-radius: 0; }
@media (max-width: 1024px) {
  body.of-page::after { display: block; left: 0; border-top-left-radius: 18px; }
}

/* Tasks as designed (partials/task-manager.ejs, 3 Oct): one line to set a
   task, then rows that open each task. */
:where(body.of-page) .task-set { margin-bottom: 16px; padding: 14px 16px; }
.task-set-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
:where(body.of-page) .task-set-row input[name="title"] { flex: 1 1 260px; margin: 0; }
:where(body.of-page) .task-set-row select { flex: 0 1 210px; width: auto; margin: 0; }
:where(body.of-page) .task-set-row input[type="date"] { flex: 0 1 170px; width: auto; margin: 0; }
:where(body.of-page .container) .task-set-row button[type="submit"] { margin: 0; }
:where(body.of-page .container) button.task-set-more { flex: none; width: 44px; height: 44px; min-height: 0; padding: 0; display: grid; place-items: center; border: 0; border-radius: 50%; background: #f3f3f2; color: #1f1f1f; }
:where(body.of-page .container) button.task-set-more[aria-expanded="true"] { background: #1c1c1c; color: #ffffff; }
:where(body.of-page) .task-set-detail { margin: 10px 0 0; }
:where(body.of-page) .task-card { margin-bottom: 16px; }
:where(body.of-page) .task-card h2 { display: flex; align-items: center; gap: 8px; }
.task-list { list-style: none; margin: 0; padding: 0 8px 8px; }
.task-list li + li { border-top: 1px solid #f2f2f0; }
.task-row { display: flex; align-items: center; gap: 14px; padding: 14px 12px; border-radius: 14px; color: #1f1f1f; text-decoration: none; }
.task-row:hover { background: #fafaf9; }
.task-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.task-row-title { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-weight: 700; }
.task-row-sub { color: #666666; font-size: 13px; }
.task-row > .badge { flex: none; white-space: nowrap; }
.task-due--none { background: transparent; color: #777777; font-weight: 600; }

/* Office Orders on a narrower window: the item count steps aside (the order
   page has the items) and the columns sit closer, so nothing runs past the
   card's edge (Angel, 3 Oct). */
@media (min-width: 761px) and (max-width: 1199px) {
  table.office-orders .col-items { display: none; }
  :where(body.of-page) table.office-orders th, :where(body.of-page) table.office-orders td { padding-left: 10px; padding-right: 10px; }
  :where(body.of-page) table.office-orders th:first-child, :where(body.of-page) table.office-orders td:first-child { padding-left: 20px; }
  :where(body.of-page) table.office-orders td.cell-line { white-space: normal; }
}

/* A web shop order's two Shopify tags, side by side on every row (Angel,
   3 Oct: "maybe not stacked"). */
.status-stack { display: inline-flex; flex-wrap: nowrap; align-items: center; gap: 6px; white-space: nowrap; }

/* On a phone's order cards the Note and Web shop tags ride on the number's
   own line, so they don't push the card down (Angel, 3 Oct). */
/* On a phone's order cards: number, customer, then its Note or Web shop
   tag (Angel, 3 Oct), from a copy that sits in the customer's cell. */
.flag-after { display: none; }
@media (max-width: 760px) {
  .order-cell .note-flag, .order-cell .web-flag { display: inline-flex; vertical-align: middle; margin: 0 0 0 8px; }
  .office-orders .order-cell .note-flag, .office-orders .order-cell .web-flag, .floor-orders .order-cell .note-flag { display: none; }
  .note-flag.flag-after, .web-flag.flag-after { display: inline-flex; vertical-align: middle; margin: 0 0 0 8px; }
}

/* Office Orders between a phone and a wide window: fixed columns, so the
   table always fits its card and text wraps inside its own column (Angel,
   3 Oct: "when squeezing"). Items is hidden here, above. */
@media (min-width: 761px) and (max-width: 1199px) {
  table.office-orders { table-layout: fixed; width: 100%; }
  table.office-orders th.c-order { width: 14%; }
  table.office-orders th.c-placed { width: 12%; }
  table.office-orders th.c-cust { width: 19%; }
  table.office-orders th.c-total { width: 11%; }
  table.office-orders th.c-pay { width: 13%; }
  table.office-orders th.c-status { width: 15%; }
  table.office-orders th.c-deliv { width: 16%; }
  table.office-orders--no-money th.c-order { width: 15%; }
  table.office-orders--no-money th.c-placed { width: 14%; }
  table.office-orders--no-money th.c-cust { width: 21%; }
  table.office-orders--no-money th.c-pay { width: 15%; }
  table.office-orders--no-money th.c-status { width: 17%; }
  table.office-orders--no-money th.c-deliv { width: 18%; }
  table.office-orders td { overflow-wrap: break-word; }
  table.office-orders td.num { white-space: nowrap; }
  table.office-orders .badge { white-space: normal; text-align: left; height: auto; min-height: 22px; padding-top: 3px; padding-bottom: 3px; line-height: 1.25; border-radius: 11px; }
}

/* Products' order arrows: small and quiet, as they're only used now and
   then (Angel, 3 Oct), clearer when the row is pointed at. */
.move-cell { width: 1%; white-space: nowrap; }
.move-cell form { display: inline; margin: 0; }
table.product-list button.move-btn, :where(body.of-page .container) button.move-btn { width: 26px; height: 26px; min-height: 0; padding: 0; display: inline-grid; place-items: center; border: 0; border-radius: 50%; background: transparent; color: #b5b2ad; font-size: 14px; font-weight: 600; line-height: 1; box-shadow: none; }
table.product-list tr:hover button.move-btn:not([disabled]) { color: #555555; }
table.product-list button.move-btn:not([disabled]):hover { background: #ececea; color: #1f1f1f; }
table.product-list button.move-btn[disabled] { opacity: 0.3; cursor: default; }

/* Marketing as designed (views/admin/marketing-news.ejs, 3 Oct): the new one
   on the left, drafts and what's been sent on the right. */
.mk-cols { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); gap: 16px; align-items: start; }
.mk-side { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
:where(body.of-page) .mk-new { margin: 0; padding: 22px 24px; }
:where(body.of-page) .mk-new h2 { margin: 0 0 6px; font-size: 16px; font-weight: 800; }
.mk-label { display: block; margin-bottom: 6px; font-weight: 700; font-size: 13.5px; }
.mk-drop { position: relative; display: flex; align-items: center; gap: 10px; min-height: 48px; padding: 0 16px; border: 1.5px dashed #d3d0cb; border-radius: 14px; color: #555555; font-size: 14px; cursor: pointer; }
.mk-drop strong { color: #1a73e8; font-weight: 700; }
.mk-drop:hover, .mk-drop.is-over { border-color: #1c1c1c; background: #fafaf9; }
.mk-drop.has-file { border-style: solid; color: #1f1f1f; }
.mk-drop input[type="file"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.mk-email { margin-top: 6px; padding-top: 12px; border-top: 1px solid #f0f0ee; }
.mk-actions { justify-content: flex-end; }
:where(body.of-page .container) .mk-actions button { display: inline-flex; align-items: center; gap: 8px; }
.mk-list { list-style: none; margin: 0; padding: 0 8px 8px; }
.mk-list li + li { border-top: 1px solid #f2f2f0; }
.mk-row { display: flex; align-items: center; gap: 14px; padding: 12px; border-radius: 14px; color: #1f1f1f; text-decoration: none; }
.mk-row:hover { background: #fafaf9; }
.mk-thumb { flex: 0 0 56px; width: 56px; height: 56px; display: grid; place-items: center; overflow: hidden; border-radius: 14px; background: #ececea; color: #8a8a8a; }
.mk-thumb img { width: 100%; height: 100%; object-fit: cover; }
.mk-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.mk-text small { color: #666666; font-size: 12.5px; line-height: 1.35; }
.mk-text b { font-weight: 600; }
.mk-more { padding: 0 8px 10px; }
.mk-more > summary { display: block; padding: 10px 12px 4px; text-align: right; font-weight: 700; cursor: pointer; list-style: none; }
.mk-more > summary::-webkit-details-marker { display: none; }
.mk-more[open] > summary { display: none; }
.news-delete { margin: 12px 0 0; }
@media (max-width: 1100px) { .mk-cols { grid-template-columns: minmax(0, 1fr); } }

/* A figure tile never lets its number spill out: the words beside the icon
   can shrink, and a long figure steps down a size (Angel, 3 Oct). */
.home-stat > span:last-child { min-width: 0; }
.home-stat b { font-size: clamp(17px, 1.45vw, 21px); overflow-wrap: anywhere; }

/* Settings' rows as on the canvas (3 Oct): an icon in a circle, the name and
   what it's for, and an arrow. */
.set-list { list-style: none; margin: 0; padding: 0; }
.set-list li + li { border-top: 1px solid #f2f2f0; }
.set-row { display: flex; align-items: center; gap: 16px; padding: 14px 6px; border-radius: 14px; color: #1f1f1f; text-decoration: none; }
a.set-row:hover { background: #fafaf9; }
.set-ic { flex: 0 0 44px; width: 44px; height: 44px; display: grid; place-items: center; border: 1px solid #e4e4e2; border-radius: 50%; color: #1f1f1f; }
.set-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.set-text strong { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-weight: 700; }
.set-text > span { color: #666666; font-size: 13.5px; }
/* Integrations: a box each, one line apiece - logo, name, how it stands,
   Open (4 Oct). On a phone the status drops under the name. */
.int-boxes { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
.int-box { display: flex; align-items: center; gap: 16px; color: #1f1f1f; text-decoration: none; transition: box-shadow .2s ease, border-color .2s ease; }
.int-box:hover { border-color: #d6d1cb; box-shadow: 0 5px 12px rgba(58, 48, 42, 0.12); }
.int-box:focus-visible { outline: 2px solid #1c1c1c; outline-offset: 3px; }
.int-box-logo { flex: 0 0 48px; width: 48px; height: 48px; display: grid; place-items: center; border: 1px solid #e4e4e2; border-radius: 50%; background: #ffffff; }
.int-box-logo svg { display: block; }
.int-box-name { flex: 0 0 auto; display: flex; align-items: center; gap: 8px; font-size: 16px; font-weight: 800; white-space: nowrap; }
.int-box-lines { flex: 1 1 auto; min-width: 0; color: #666666; font-size: 13.5px; }
.int-box-open { flex: 0 0 auto; display: flex; align-items: center; gap: 4px; font-size: 13.5px; font-weight: 700; }
@media (max-width: 760px) {
  .int-box { flex-wrap: wrap; gap: 6px 14px; }
  .int-box-lines { order: 3; flex-basis: 100%; padding-left: 62px; }
  .int-box-open { margin-left: auto; }
}
@media (prefers-reduced-motion: reduce) { .int-box { transition: none; } }
.set-chev { flex: none; color: #8a8a8a; }

/* The floor's lists: the customer and the address wrap inside their own
   columns at every width, so a long name never runs into the address next
   to it (Angel, 3 Oct: "when squeezed"). */
@media (min-width: 761px) {
  :where(body.of-page) table.floor-orders td.cell-lead:not(.order-cell), :where(body.of-page) table.floor-orders td.addr-cell { white-space: normal; overflow-wrap: break-word; }
}

/* One text size across the office and the floor, close to the menu's
   (Angel, 3 Oct: "text everywhere can be similar size to the menu, no need
   for large typing"): 13px for reading, headings a step down, and typing
   boxes at 16px on a phone so it doesn't zoom in on them. */
body.of-page { font-size: 13px; }
body.of-page .container { font-size: 13px; }
body.of-page .container h1 { font-size: 22px; }
body.of-page .container h2 { font-size: 14.5px; }
body.of-page .container h3 { font-size: 13.5px; }
body.of-page .container table { font-size: 13px; }
body.of-page .container th { font-size: 11.5px; }
body.of-page .container label, body.of-page .container .field > span, body.of-page .container .mk-label { font-size: 12px; }
body.of-page .container input, body.of-page .container select, body.of-page .container textarea { font-size: 13px; }
body.of-page .container button, body.of-page .container .btn { font-size: 12.5px; }
body.of-page .container .list-tab, body.of-page .container button.list-tab, body.of-page .container .list-menu a { font-size: 12.5px; }
body.of-page .container .badge, body.of-page .container .pill, body.of-page .container .note-flag, body.of-page .container .web-flag { font-size: 11px; }
body.of-page .container .row-sub, body.of-page .container .muted, body.of-page .container small, body.of-page .container .form-hint { font-size: 12px; }
body.of-page .container .home-stat b { font-size: clamp(16px, 1.3vw, 19px); }
body.of-page .container .home-stat small { font-size: 12px; }
body.of-page .container .home-hero h1 { font-size: 24px; }
body.of-page .container .task-row-sub, body.of-page .container .mk-text small, body.of-page .container .set-text > span, body.of-page .container .kv small { font-size: 12px; }
@media (max-width: 760px) {
  body.of-page .container input, body.of-page .container select, body.of-page .container textarea { font-size: 16px; }
}

/* Side by side rather than one under the other (Angel, 3 Oct: "avoid
   putting stuff under each other in general"). A figure tile reads "7
   Orders today" on one line. */
.home-stat > span:last-child { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 7px; row-gap: 0; }
body.of-page .container .home-stat b { display: inline; }
body.of-page .container .home-stat small { display: inline; font-size: 13px; }
/* An order's Note or Web shop tag goes after its customer at every size,
   as on a phone, rather than under the number. */
.office-orders .order-cell .note-flag, .office-orders .order-cell .web-flag, .floor-orders .order-cell .note-flag { display: none; }
.office-orders .flag-after, .floor-orders .flag-after { display: inline-flex; vertical-align: middle; margin: 0 0 0 8px; }
/* Room for the number and its words on one line: tiles take what they need
   and wrap to another row on a narrower window rather than squeezing. */
.home-stats { display: grid; grid-template-columns: repeat(auto-fill, minmax(188px, 1fr)); gap: 12px; }
.home-stats .home-stat { gap: 11px; padding: 14px 15px; }
body.of-page .container .home-stat small { white-space: nowrap; font-size: 12px; }
.home-stats .home-stat .home-ic { flex: 0 0 38px; width: 38px; height: 38px; }
/* On a phone, Home's tiles two to a row only where every label fits on one
   line; narrower, they stack, each the full width (Angel, 4 Oct: "expand
   these boxes and stack if text overflows"). */
@media (max-width: 760px) { .home-stats { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 10px; } body.of-page .container .home-stat small { white-space: nowrap; } }
/* A customer cell wraps, so a tag that doesn't fit after the name moves to
   the next line rather than into the next column. */
:where(body.of-page) table.office-orders td.cell-lead:not(.order-cell) { white-space: normal; }
/* Number and label on one line on a computer (Angel, 3 Oct): each tile as
   wide as what it says, sharing the row, so nothing sits under anything. */
@media (min-width: 761px) {
  .home-stats { display: flex; flex-wrap: wrap; }
  .home-stats .home-stat { flex: 1 1 auto; min-width: 0; padding: 12px 14px; gap: 10px; }
  .home-stats .home-stat .home-ic { flex: 0 0 34px; width: 34px; height: 34px; }
  .home-stat > span:last-child { flex-wrap: nowrap; }
}
/* The floor's stock search: a magnifying glass inside the box (Angel, 3 Oct). */
.inv-find { position: relative; }
.inv-find .find-ic { position: absolute; left: 16px; top: 50%; transform: translateY(-50%); color: #777777; pointer-events: none; }
.inv-find input[type=search] { padding-left: 42px; }
/* Log a roast and Make a batch: bigger and bolder, with more room under
   them, office and floor (Angel, 3 Oct). */
body.of-page .container .btn.btn-main { min-height: 46px; padding: 0 24px; font-size: 15px; font-weight: 800; }
/* Whichever way the title is written, it sits level with the button, the
   same on Roasting and Making (Angel, 3 Oct: "roasting and making
   positioning inconsistent"). */
body.of-page .container :is(.page-head, .page-head-row, .ops-head):has(.btn-main) { align-items: center; margin-bottom: 30px; }
body.of-page .container :is(.page-head, .page-head-row, .ops-head):has(.btn-main) h1 { margin: 0; }
/* Log out in the account menu reads like Account beside it (Angel, 3 Oct). */
body .of-pop-list button, body .of-pop-list a { text-transform: none; letter-spacing: normal; font-family: var(--body-font); }
/* A web order's second line in the customer cell: town, then the Web shop tag. */
.office-orders .cust-sub { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; margin-top: 3px; }
.office-orders .cust-town { color: #777777; font-size: 12px; }
.office-orders .cust-sub .web-flag { display: inline-flex; margin: 0; }
/* All, Wholesale or Web shop: a small pill switch, on Reports and Home (Angel, 3 Oct). */
.src-switch { display: inline-flex; flex-wrap: nowrap; align-items: center; gap: 2px; padding: 3px; border-radius: 999px; background: #efefed; }
.src-switch a, .src-switch button { display: inline-flex; align-items: center; min-height: 32px; margin: 0; padding: 0 13px; border: 0; border-radius: 999px; background: transparent; color: #555555; font: inherit; font-size: 13px; font-weight: 700; text-decoration: none; white-space: nowrap; cursor: pointer; }
body.of-page .container .src-switch button { min-height: 32px; padding: 0 13px; border: 0; background: transparent; color: #555555; font-size: 13px; }
.src-switch a:hover, body.of-page .container .src-switch button:hover { background: #e2e2df; color: #1f1f1f; }
.src-switch a.is-on, body.of-page .container .src-switch button.is-on { background: #1c1c1c; color: #ffffff; }
.report-source { margin: 0; }
.home-figures-top { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 16px; }
.home-figures-top .home-periods { margin: 0; }
/* A customer and its Note side by side, office and floor (Angel, 3 Oct): a
   long name wraps within its own space and the Note stays to its right,
   never under it. */
.cust-line { display: flex; align-items: center; gap: 8px; min-width: 0; max-width: 100%; }
.cust-line .order-co { flex: 0 1 auto; min-width: 0; white-space: normal; overflow-wrap: anywhere; }
.office-orders .cust-line .flag-after, .floor-orders .cust-line .flag-after { flex: none; margin: 0; }
/* More room for the customer, so a name and its Note sit side by side
   (Angel, 3 Oct), taken from columns with room to spare. */
@media (min-width: 761px) {
  table.floor-orders th:nth-child(1) { width: 8%; }
  table.floor-orders th:nth-child(2) { width: 24%; }
  table.floor-orders th:nth-child(3) { width: 15%; }
  table.floor-orders th:nth-child(4) { width: 21%; }
  table.floor-orders th:nth-child(5) { width: 17%; }
  table.floor-orders th:nth-child(6) { width: 15%; }
}
@media (min-width: 1200px) {
  table.office-orders th:nth-child(1) { width: 8%; }
  table.office-orders th:nth-child(2) { width: 13%; }
  table.office-orders th:nth-child(3) { width: 24%; }
  table.office-orders th:nth-child(4) { width: 9%; }
  table.office-orders th:nth-child(5) { width: 12%; }
  table.office-orders th:nth-child(6) { width: 15%; }
  table.office-orders th:nth-child(7) { width: 8%; }
  table.office-orders th:nth-child(8) { width: 11%; }
  table.office-orders--no-money th:nth-child(1) { width: 9%; }
  table.office-orders--no-money th:nth-child(2) { width: 14%; }
  table.office-orders--no-money th:nth-child(3) { width: 30%; }
  table.office-orders--no-money th:nth-child(4) { width: 13%; }
  table.office-orders--no-money th:nth-child(5) { width: 13%; }
  table.office-orders--no-money th:nth-child(6) { width: 9%; }
  table.office-orders--no-money th:nth-child(7) { width: 12%; }
  /* A long tag wraps inside its own column rather than running over. */
  table.office-orders .badge, table.office-orders .pill--collect { max-width: 100%; white-space: normal; text-align: left; height: auto; min-height: 22px; padding-top: 3px; padding-bottom: 3px; line-height: 1.25; border-radius: 11px; }
}
@media (min-width: 761px) and (max-width: 1199px) {
  table.office-orders th.c-order { width: 11%; }
  table.office-orders th.c-placed { width: 12%; }
  table.office-orders th.c-cust { width: 25%; }
  table.office-orders th.c-total { width: 10%; }
  table.office-orders th.c-pay { width: 12%; }
  table.office-orders th.c-status { width: 14%; }
  table.office-orders th.c-deliv { width: 16%; }
  table.office-orders--no-money th.c-order { width: 12%; }
  table.office-orders--no-money th.c-placed { width: 13%; }
  table.office-orders--no-money th.c-cust { width: 28%; }
  table.office-orders--no-money th.c-pay { width: 14%; }
  table.office-orders--no-money th.c-status { width: 15%; }
  table.office-orders--no-money th.c-deliv { width: 18%; }
}
table.office-orders .badge, table.office-orders .pill--collect { overflow-wrap: normal; word-break: normal; }
/* Office Orders: nothing under anything (Angel, 3 Oct: "no text under
   another"). Every column but the customer keeps to one line at its own
   width, and the customer takes what's left, its Note beside it. On a
   narrower window the item count steps aside first, then the time placed
   (both are on the order's page); the card scrolls sideways before
   anything overlaps. */
@media (min-width: 761px) {
  body.of-page table.office-orders { table-layout: auto; width: 100%; }
  body.of-page table.office-orders th { width: auto; }
  body.of-page table.office-orders th.c-cust { width: 100%; }
  body.of-page table.office-orders td:not(.cell-lead), body.of-page table.office-orders th { white-space: nowrap; }
  body.of-page table.office-orders .badge, body.of-page table.office-orders .pill--collect { white-space: nowrap; max-width: none; height: auto; min-height: 22px; border-radius: 999px; }
  body.of-page table.office-orders td.cell-lead:not(.order-cell), body.of-page table.office-orders .cust-line .order-co { overflow-wrap: normal; word-break: normal; }
  body.of-page table.office-orders .deliv-text { display: inline-block; max-width: 130px; overflow: hidden; text-overflow: ellipsis; vertical-align: middle; }
  :where(body.of-page) .list-card:has(table.office-orders) { overflow-x: auto; }
}
@media (min-width: 761px) and (max-width: 1439px) {
  body.of-page table.office-orders .col-items { display: none; }
}
/* The time placed stays on a narrower window too (Angel, 4 Oct: "when page
   squeezed, the date of order disappears"), as just its day - Today, 28
   Sept - with the time back where there's room. */
@media (min-width: 761px) and (max-width: 1279px) {
  body.of-page table.office-orders .placed-time { display: none; }
}
.cust-line .cust-town { flex: none; color: #777777; font-size: 12px; }
/* Finished states with a little colour, so they don't get lost (Angel,
   3 Oct): Invoiced peach, Paid teal, Dispatched, Collected and the web
   shop's Fulfilled a soft indigo. Cancelled stays grey. */
body.of-page .badge-invoiced { background: #fde6d3; color: #8a4410; }
body.of-page .badge-paid, body.of-page .badge.c-teal { background: #d6f0ec; color: #0d5f55; }
body.of-page .fulfillment-despatched, body.of-page .fulfillment-collected, body.of-page .badge-sent, body.of-page .badge-collected, body.of-page .badge.c-indigo { background: #e1e7f8; color: #2f3f87; }
/* Office Orders as cards (a narrow window or a phone): each card uses its
   whole width, nothing under anything (Angel, 3 Oct: "should go to the
   end"). The number, customer and its tag, with the time at the far end;
   then the total, payment, status, items and delivery spread along the
   line, without the small labels over them. */
@media (max-width: 760px) {
  body.of-page table.cards.office-orders tr { align-items: center; justify-content: space-between; column-gap: 14px; padding: 14px 16px; }
  body.of-page table.cards.office-orders td.cell-lead { order: -1; }
  body.of-page table.cards.office-orders td.col-placed { order: 0; flex-basis: auto; margin: 0 0 0 auto; align-self: center; white-space: nowrap; }
  body.of-page table.cards.office-orders td { margin-top: 10px; }
  body.of-page table.cards.office-orders td.cell-lead, body.of-page table.cards.office-orders td.col-placed { margin-top: 0; }
  body.of-page table.cards.office-orders td[data-label]::before { display: none; }
  body.of-page table.cards.office-orders td[data-label] { min-width: 0; }
  body.of-page table.cards.office-orders .cust-line { flex-wrap: nowrap; }
}
@media (max-width: 520px) { body.of-page table.cards.office-orders td.col-items { display: none; } }
/* The floor's Orders: the order number, the status and the time keep to
   one line at their own width; the items take what's left (Angel, 3 Oct:
   "date getting squished"). */
@media (min-width: 761px) {
  body.of-page table.floor-orders { table-layout: auto; width: 100%; }
  body.of-page table.floor-orders th { width: auto; }
  body.of-page table.floor-orders th:nth-child(4) { width: 100%; }
  body.of-page table.floor-orders td:nth-child(1), body.of-page table.floor-orders td:nth-child(5), body.of-page table.floor-orders td:nth-child(6) { white-space: nowrap; }
  body.of-page table.floor-orders td:nth-child(2) { min-width: 9em; }
  body.of-page table.floor-orders td:nth-child(3) { min-width: 7.5em; }
  body.of-page table.floor-orders td:nth-child(4) { min-width: 9em; }
  body.of-page table.floor-orders select.status-pick { width: auto; min-width: 150px; }
  :where(body.of-page) .list-card:has(table.floor-orders) { overflow-x: auto; }
}
@media (min-width: 761px) {
  body.of-page table.floor-orders td:nth-child(2) .order-co, body.of-page table.floor-orders td:nth-child(2) > strong { display: inline-block; min-width: 8.5em; overflow-wrap: normal; word-break: normal; }
}
/* The Note and Web shop tags at the right of the customer's column, next to
   the total, so they line up down the list (Angel, 3 Oct). */
@media (min-width: 761px) {
  body.of-page table.office-orders .cust-line, body.of-page table.floor-orders .cust-line { width: 100%; justify-content: space-between; }
}
@media (min-width: 761px) { body.of-page table.floor-orders th { white-space: nowrap; } }

/* Suppliers, Purchase orders, Packaging and Making as on the canvas
   (Angel, 3 Oct): the same figures, tabs and list cards as Orders and
   Inventory. */
.co-name { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.co-name small, small.sub-line { display: block; color: #666666; font-size: 12px; white-space: normal; }
:where(body.of-page) .supplier-list td.cell-lead { white-space: normal; min-width: 220px; }
.pill-stack { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
a.badge { text-decoration: none; }
a.badge:hover { filter: brightness(0.96); }

/* Purchase orders: who it's from beside the tabs; what's coming as cards. */
.list-pick { flex: none; margin: 0; }
:where(body.of-page) .list-pick select { min-height: 36px; height: 36px; padding: 0 38px 0 14px; border-color: #e4e4e2; background-position: right 14px center; font-size: 12.5px; font-weight: 700; }
.section-head { margin: 24px 4px 10px; font-size: 14.5px; font-weight: 800; }
.section-head small { margin-left: 6px; color: #666666; font-weight: 600; }
:where(body.of-page) .po { margin-top: 12px; padding: 0; overflow: hidden; }
.po-head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 14px; padding: 18px 20px 0; }
:where(body.of-page) .po-head h2 { margin: 0; }
.po-head small { display: block; margin-top: 2px; color: #666666; }
.po-figs { display: flex; flex-wrap: wrap; align-items: center; gap: 18px; white-space: nowrap; }
.po-figs > span > small { display: block; margin: 0; color: #666666; font-weight: 700; }
.po-figs b { font-family: var(--heading-font); font-size: 16px; font-weight: 700; font-variant-numeric: tabular-nums; }
.po-due { margin: 8px 20px 0; color: #555555; }
.po-due.late { color: #8e1b1b; font-weight: 700; }
.po-scroll { overflow-x: auto; }
:where(body.of-page) .po-lines { width: 100%; margin-top: 6px; }
:where(body.of-page) .po-lines td, :where(body.of-page) .po-lines th { padding-top: 10px; padding-bottom: 10px; }
:where(body.of-page) .po-lines td:first-child, :where(body.of-page) .po-lines th:first-child { padding-left: 20px; }
:where(body.of-page) .po-lines td:last-child, :where(body.of-page) .po-lines th:last-child { padding-right: 20px; }
:where(body.of-page) .po .po-lines tbody tr:hover td { background: none; }
.po-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 16px; padding: 12px 20px 16px; border-top: 1px solid #f2f2f0; }
.po-expected { display: flex; align-items: center; gap: 8px; margin: 0; }
:where(body.of-page) .po-expected label { margin: 0; color: #666666; font-size: 12px; }
:where(body.of-page) .po-expected input[type="date"] { min-height: 34px; height: 34px; padding: 0 12px; }
.po-buttons { display: flex; flex-wrap: wrap; gap: 8px; margin-left: auto; }
.po-buttons form { margin: 0; }
/* What already happened: a row each, opening to show what was on it. */
:where(body.of-page) .po-history { width: 100%; }
.po-row { cursor: pointer; }
:where(body.of-page) .po-history td.cell-lead { white-space: normal; }
.po-open-col { width: 52px; text-align: right; }
:where(body.of-page .container) button.po-open { width: 32px; min-height: 32px; height: 32px; padding: 0; display: inline-grid; place-items: center; border: 1px solid #e4e4e2; border-radius: 50%; background: #ffffff; color: #1f1f1f; }
:where(body.of-page .container) button.po-open:hover { border-color: #1c1c1c; background: #ffffff; }
.po-open svg { transition: transform .15s; }
.po-row.is-open .po-open svg { transform: rotate(180deg); }
:where(body.of-page) .po-row.is-open td { border-bottom-color: transparent; background: #fafaf9; }
:where(body.of-page) .po-detail > td { padding: 0 0 12px; background: #fafaf9; }
:where(body.of-page) .po-detail:hover > td { background: #fafaf9; }
:where(body.of-page) .po-detail .po-lines { margin: 0; }
:where(body.of-page) .po-detail .po-lines td, :where(body.of-page) .po-detail .po-lines th { background: none; }
.po-detail-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; padding: 8px 20px 0; }
.po-detail-foot .btn { margin-left: auto; }

/* Packaging: a tile per kind, saying when something in it runs low. */
:where(body.of-page) .pack-group { margin-bottom: 22px; }
:where(body.of-page) .pack-group-head { margin: 0 4px 12px; font-family: var(--body-font); font-size: 14.5px; font-weight: 800; letter-spacing: 0; text-transform: none; }
:where(body.of-page) .pack-group-note { margin-left: 8px; color: #666666; font-size: 12px; font-weight: 400; opacity: 1; }
:where(body.of-page) .pack-group-note a { color: inherit; }
:where(body.of-page) .pack-tiles { grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 16px; }
:where(body.of-page) .pack-tile { flex-direction: column; align-items: stretch; gap: 14px; padding: 18px 20px; border: 1px solid #e7e4e0; border-radius: 20px; background: #ffffff; color: #1f1f1f; text-decoration: none; }
:where(body.of-page) .pack-tile:hover, :where(body.of-page) .pack-tile:focus-visible { border-color: #dedad5; background: #ffffff; box-shadow: 0 6px 18px rgba(58, 48, 42, 0.07); }
.pack-tile-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
:where(body.of-page) .pack-tile-icon { width: 44px; height: 44px; border: 1px solid #e4e4e2; border-radius: 50%; background: #ffffff; }
:where(body.of-page) .pack-tile:hover .pack-tile-icon { background: #ffffff; }
:where(body.of-page) .pack-tile-text { gap: 2px; }
:where(body.of-page) .pack-tile-text strong { font-size: 14px; font-weight: 800; }
:where(body.of-page) .pack-tile-text em { margin: 0; color: #666666; font-size: 12px; font-weight: 400; }
.pack-low-card { margin-bottom: 16px; }
:where(body.of-page) .pack-low-table { width: 100%; }
.qty-low { color: #8a5a00; font-weight: 700; }
:where(body.of-page) .pack-unsorted { padding: 16px 20px; }
:where(body.of-page) .pack-unsorted > summary { color: #1f1f1f; font-size: 13px; font-weight: 800; opacity: 1; }
:where(body.of-page) .pack-unsorted[open] > summary { margin-bottom: 8px; }
/* The Add packaging menu, as Inventory's More. */
:where(body.of-page) .more-menu-list { padding: 6px; border: 0; border-radius: 16px; background: #ffffff; box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12), 0 0 0 1px rgba(0, 0, 0, 0.05); }
:where(body.of-page) .more-menu-list a { border-radius: 10px; }
:where(body.of-page) .more-menu-list a:hover { background: #f3f3f2; }

/* Making: the bar's key, and Recently made on a card. */
.plan-key { display: inline-flex; flex-wrap: wrap; gap: 14px; margin-left: auto; color: #666666; font-size: 12px; }
.plan-key i { display: inline-block; width: 3px; height: 12px; margin-right: 6px; vertical-align: -2px; border-radius: 2px; background: var(--ink); }
.plan-key i.sw { width: 14px; height: 8px; vertical-align: 0; border-radius: 999px; background: var(--warn-text); }
.made-card { margin-top: 16px; }
:where(body.of-page) .made-table { width: 100%; }
:where(body.of-page) .made-table td.made-inputs { white-space: normal; min-width: 220px; }
:where(body.of-page) :is(.po-lines, .po-history, .made-table, .pack-low-table, .supplier-list) :is(td, th).num { text-align: right; }
@media (max-width: 760px) {
  .list-bar:has(.list-pick) { flex-wrap: wrap; }
  .list-bar .list-pick { flex: 1 1 100%; }
  :where(body.of-page) .list-bar .list-pick select { width: 100%; }
  :where(body.of-page) .po-lines td:first-child, :where(body.of-page) .po-lines th:first-child { padding-left: 14px; }
  :where(body.of-page) .po-lines td:last-child, :where(body.of-page) .po-lines th:last-child { padding-right: 14px; }
  :where(body.of-page) .po-lines td, :where(body.of-page) .po-lines th { padding-left: 8px; padding-right: 8px; }
  .po-head, .po-actions { padding-left: 14px; padding-right: 14px; }
  .po-due { margin-left: 14px; margin-right: 14px; }
}
/* A past delivery's lines, opened under its row. */
.po-dl { list-style: none; margin: 0; padding: 4px 20px 0; }
.po-dl li { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 12px; padding: 8px 0; border-top: 1px solid #efefed; font-variant-numeric: tabular-nums; }
.po-dl--money li { grid-template-columns: minmax(0, 2fr) repeat(3, minmax(0, 1fr)); }
.po-dl li > span:not(:first-child) { text-align: right; }
.po-dl li.po-dl-head { border-top: 0; padding-bottom: 4px; color: #777777; font-size: 11.5px; font-weight: 700; }
@media (max-width: 760px) {
  .container table.po-lines { display: table; width: 100%; }
  :where(body.of-page) .pack-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  :where(body.of-page) .pack-tile { padding: 14px; gap: 10px; }
  .pack-tile-top { flex-wrap: wrap; }
  .po-dl { padding: 4px 4px 0; }
  .po-detail-foot { padding: 8px 4px 0; }
}
@media (max-width: 760px) {
  :where(body.of-page) table.cards .po-row.is-open td { background: none; }
  table.cards tr.po-row.is-open, table.cards tr.po-detail { background: #fafaf9; }
}
/* Orders' tags: the line fills the tag, so the words sit in the middle
   rather than at the top of a tag made taller than they are (Angel, 3 Oct:
   "the text seems misaligned inside the pills"). */
body.of-page table.office-orders .badge, body.of-page table.office-orders .pill--collect { line-height: 16px; padding-top: 3px; padding-bottom: 3px; }

/* Orders on a phone, as the phone design on the canvas (Angel, 3 Oct: "all
   this looks a bit much on mobile"): each card two sides. On the left the
   number and customer (and its Note or Web shop tag), then when it was
   placed, then how it goes when that's worth saying; on the right the total,
   then the payment and status tags. Plain "Delivery" is left out, as most
   orders go that way. */
@media (max-width: 760px) {
  /* Three lines that each keep their own room: number, customer, total;
     when, payment, status; how it goes. */
  body.of-page table.cards.office-orders tr { display: flex; flex-wrap: wrap; align-items: center; column-gap: 8px; row-gap: 6px; padding: 12px 14px; }
  body.of-page table.cards.office-orders tr::before { content: ""; display: block; order: 4; flex-basis: 100%; height: 0; }
  body.of-page table.cards.office-orders td { margin: 0; min-width: 0; }
  body.of-page table.cards.office-orders td.order-cell { order: 1; flex: none; }
  body.of-page table.cards.office-orders td.cell-lead:not(.order-cell) { order: 2; flex: 1 1 0; font-weight: 600; }
  body.of-page table.cards.office-orders td.num { order: 3; flex: none; margin-left: auto; font-weight: 700; white-space: nowrap; }
  body.of-page table.cards.office-orders td.col-placed { order: 5; flex: 1 1 auto; margin: 0; font-size: 12px; }
  /* Payment and status: the fourth and third cells from the end, with or
     without a Total. */
  body.of-page table.cards.office-orders tr > td:nth-last-child(4) { order: 6; flex: none; }
  body.of-page table.cards.office-orders tr > td:nth-last-child(3) { order: 7; flex: none; }
  body.of-page table.cards.office-orders td.c-deliv-cell { order: 9; flex: 0 0 100%; font-size: 12px; }
  body.of-page table.cards.office-orders td.deliv-plain, body.of-page table.cards.office-orders td.col-items { display: none; }
  body.of-page table.cards.office-orders .cust-line { flex-wrap: wrap; row-gap: 4px; column-gap: 8px; }
  body.of-page table.cards.office-orders .badge { font-size: 10.5px; }

  /* The figures across the top of a list: one row to swipe along rather
     than boxes stacked two by two, so the list starts near the top. */
  .home-stats.order-stats { display: flex; flex-wrap: nowrap; gap: 8px; margin: 0 -12px 14px; padding: 0 12px 2px; overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
  .order-stats::-webkit-scrollbar { display: none; }
  .order-stats .home-stat { flex: 0 0 auto; gap: 8px; padding: 10px 14px 10px 10px; border-radius: 16px; }
  .order-stats .home-ic { flex-basis: 32px; width: 32px; height: 32px; }
  .order-stats .home-ic svg { width: 17px; height: 17px; }
  body.of-page .container .order-stats .home-stat b { font-size: 16px; }
  body.of-page .container .order-stats .home-stat small { white-space: nowrap; }
}

/* The web shop's mark: a small grey globe just after the name (Angel,
   3 Oct), in place of the "Web shop" tag. */
.web-mark, .wholesale-mark { display: inline-flex; align-items: center; margin-left: 6px; color: #8a8a8c; vertical-align: -2px; }
.web-mark svg, .wholesale-mark svg, .wholesale-mark img { flex: none; display: block; }
/* The figures across the top of a list keep to one row at every width:
   stretched to fill a wide window, swiped along when there isn't room,
   rather than one tile left alone on a row of its own (Angel, 3 Oct: "the
   spacing on reducing pages width"). */
@media (min-width: 761px) {
  .home-stats.order-stats { flex-wrap: nowrap; gap: 10px; overflow-x: auto; scrollbar-width: none; margin: -2px -4px 10px; padding: 2px 4px 8px; }
  .home-stats.order-stats::-webkit-scrollbar { display: none; }
  .home-stats.order-stats .home-stat { flex: 1 0 auto; padding: 12px; }
}
@media (min-width: 761px) and (max-width: 1199px) {
  .home-stats.order-stats .home-stat { gap: 8px; padding: 10px 12px; }
  .home-stats.order-stats .home-stat .home-ic { flex-basis: 30px; width: 30px; height: 30px; }
  .home-stats.order-stats .home-ic svg { width: 17px; height: 17px; }
}

/* A sweep of every page at a phone, a tablet, a small laptop and a
   desktop (Angel, 3 Oct: "check all pages for widths and proper
   alignment"). */
/* Buttons in a row wrap to a second line rather than running off the
   screen (a news post's Save draft / Preview / Send it / Cancel). */
:where(body.of-page) .form-actions { flex-wrap: wrap; }
/* Team on a phone: the buttons' words in the middle of each button. */
@media (max-width: 760px) {
  table.cards.team-list .row-actions .btn, table.cards.team-list .row-actions button { display: flex; align-items: center; justify-content: center; }
}
/* Inventory on a tablet or a small laptop: the headings may take two lines,
   so the table fits its card; if it still can't, the card scrolls rather
   than the page. */
@media (max-width: 1199px) {
  :where(body.of-page) .inv-table th { white-space: normal; }
  :where(body.of-page) .inv-card { overflow-x: auto; }
}
/* A figure tile on a phone: the number stays beside its words, which take
   two lines when they must ("2  Web shop / unfulfilled"), as the others. */
@media (max-width: 760px) {
  .home-stat > span:last-child { flex-wrap: nowrap; align-items: center; }
  body.of-page .container .home-stat small { white-space: normal; line-height: 1.25; }
}
/* An order's page: one even space between its cards, and no gap where
   there are no parts sent yet. */
:where(body.of-page) .order-main > .card, :where(body.of-page) .order-side > .card { margin-bottom: 0; }
.order-parts:not(:has(*)) { display: none; }
@media (max-width: 760px) {
  /* Products' order arrows at the end of a product's card, at their size. */
  table.cards.product-list td.move-cell { width: auto; flex: none; }
  /* A row of tabs swipes along rather than wrapping onto a second line. */
  :where(body.of-page) .filter-tabs { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  :where(body.of-page) .container > .filter-tabs { margin-left: -12px; margin-right: -12px; padding-left: 12px; padding-right: 12px; }
  :where(body.of-page) .filter-tabs::-webkit-scrollbar { display: none; }
  :where(body.of-page) .filter-tabs a { flex: none; }
}
/* A customer's orders on a phone, as Orders: the number with the total on
   the right, then when it was placed with its status on the right. */
@media (max-width: 760px) {
  body.of-page table.cards.cust-order-list tr { display: flex; flex-wrap: wrap; align-items: center; column-gap: 8px; row-gap: 6px; padding: 12px 14px; }
  body.of-page table.cards.cust-order-list tr::before { content: ""; display: block; order: 3; flex-basis: 100%; height: 0; }
  body.of-page table.cards.cust-order-list td { margin: 0; min-width: 0; }
  body.of-page table.cards.cust-order-list td.order-cell { order: 1; flex: 1 1 auto; }
  body.of-page table.cards.cust-order-list td.c-total { order: 2; flex: none; margin-left: auto; font-weight: 700; }
  body.of-page table.cards.cust-order-list td.cell-line { order: 4; flex: 1 1 auto; font-size: 12px; }
  body.of-page table.cards.cust-order-list td.c-status { order: 5; flex: none; }
  body.of-page table.cards.cust-order-list td.c-items { display: none; }
  body.of-page table.cards.cust-order-list td[data-label]::before { display: none; }
}
/* Reports' figures on a phone: compact, and an odd last one takes the
   whole row rather than sitting alone in half of it. */
@media (max-width: 760px) {
  .kpis { gap: 8px; }
  :where(body.of-page) .kpi { padding: 10px 12px; border-radius: 16px; }
  .kpi b { margin: 2px 0 2px; font-size: 17px; }
  .kpis > .kpi:last-child:nth-child(odd) { grid-column: 1 / -1; }
}
@media (max-width: 760px) {
  /* Setting a task on a phone: who it's for takes the line, and the date
     and Set share the next. */
  :where(body.of-page) .task-set-row select { flex: 1 1 100%; }
  :where(body.of-page) .task-set-row input[type="date"] { flex: 1 1 auto; }
  /* Settings: a row with a button (Monday summary) puts the button under
     its words rather than squeezing them into a narrow column. */
  .set-row:has(> form) { flex-wrap: wrap; }
  .set-row:has(> form) > .set-text { flex: 1 1 calc(100% - 70px); }
  .set-row > form { margin-left: 62px !important; }
}
/* A stock item's figures at the top of its page, on a card like the rest. */
:where(body.of-page) .item-head { border: 1px solid #e7e4e0; border-radius: 20px; background: #ffffff; }

/* Angel's phone notes, 3 Oct evening. */
/* A web shop name's last word and its globe stay together. */
.name-mark-end { white-space: nowrap; }
/* A tile's number never breaks ("12" read as 1 over 2): the words wrap
   beside it instead. */
.home-stat > span:last-child > b { flex: none; white-space: nowrap; }
/* The task form's date box: a calendar and "Date" inside it until a date
   is picked. */
.date-find { position: relative; display: flex; margin: 0; }
.task-set-row .date-find { flex: 0 1 190px; }
.date-find .find-ic { position: absolute; left: 16px; top: 50%; transform: translateY(-50%); color: #777777; pointer-events: none; }
:where(body.of-page) .date-find input[type="date"] { width: 100%; margin: 0; padding-left: 42px; }
.date-find-text { position: absolute; left: 42px; top: 50%; transform: translateY(-50%); color: #8a8a8c; pointer-events: none; display: none; }
.date-find.is-empty .date-find-text { display: block; }
/* Empty and not being typed in: the box's own date text goes, so only
   "Deadline" shows. Safari puts today's date in grey in each part of an
   empty box and Firefox puts dd/mm/yyyy, both under the word (Angel, 11
   Oct: "numbers seem muddled") - so the box and every part of it. Being
   typed in, the word goes instead. */
.date-find.is-empty input[type="date"]:not(:focus),
.date-find.is-empty input[type="date"]:not(:focus)::-webkit-datetime-edit,
.date-find.is-empty input[type="date"]:not(:focus)::-webkit-datetime-edit-fields-wrapper,
.date-find.is-empty input[type="date"]:not(:focus)::-webkit-datetime-edit-text,
.date-find.is-empty input[type="date"]:not(:focus)::-webkit-datetime-edit-day-field,
.date-find.is-empty input[type="date"]:not(:focus)::-webkit-datetime-edit-month-field,
.date-find.is-empty input[type="date"]:not(:focus)::-webkit-datetime-edit-year-field { color: transparent !important; -webkit-text-fill-color: transparent; }
.date-find.is-empty:focus-within .date-find-text { display: none; }
@media (max-width: 760px) { .task-set-row .date-find { flex: 1 1 auto; } }
/* Products' sections (Coffee, Pods, Chai) read as headings. */
body.of-page .container .product-list .group-row th { color: #1a1a1a; font-family: var(--heading-font); font-size: 16px; font-weight: 700; letter-spacing: 0; text-transform: none; opacity: 1; }
/* Roasts: the figures bigger and bolder, what came out green and what was
   lost red; the day's totals the same. */
body.of-page .container .roast-table td.roast-fig { color: #1a1a1a; font-size: 14px; font-weight: 700; }
body.of-page .container .roast-table td.roast-out, .roast-day-totals .tile-out { color: #0f5129; }
body.of-page .container .roast-table td.roast-loss, .roast-day-totals .tile-loss { color: #8e1b1b; }
@media (max-width: 760px) {
  body.of-page .container table.cards.roast-table td.roast-fig { font-size: 16px; }
  body.of-page .container table.cards.roast-table td.roast-fig::before { color: #1f1f1f; }
}
/* Make next and Roast next on a phone: each row the card's full width, so
   the level bar reaches the right-hand edge and the button sits at the end. */
@media (max-width: 760px) {
  :where(body.of-page) .roast-next { align-items: stretch; }
}
/* Stock and Production in the menu: on a computer their pages show while
   you're in the section, as before; on a phone or narrow window an arrow
   beside each opens and closes them (Angel, 3 Oct). */
.of-group, .of-group-head { display: contents; }
.of-group:not(.is-expanded) > .of-sub { display: none; }
.of-expand { display: none; }
@media (max-width: 1024px) {
  .of-side.is-open .of-group { display: block; }
  .of-side.is-open .of-group-head { display: flex; align-items: center; gap: 4px; }
  .of-side.is-open .of-group-head > .of-nav { flex: 1 1 auto; min-width: 0; }
  .of-side.is-open .of-expand { display: grid; place-items: center; flex: none; width: 48px; height: 48px; padding: 0; border: 0; border-radius: 50%; background: transparent; color: #1f1f1f; cursor: pointer; }
  .of-side.is-open .of-expand:hover, .of-side.is-open .of-expand:focus-visible { background: #f3f3f2; }
  .of-side.is-open .of-expand svg { transition: transform .15s; }
  .of-side.is-open .of-group.is-expanded .of-expand svg { transform: rotate(180deg); }
}
/* Orders: the phone's copy of the Note tag, beside the payment and status. */
table.office-orders td.c-flags { display: none; }
@media (max-width: 760px) {
  body.of-page table.cards.office-orders td.c-flags:not(.is-blank) { display: block; order: 6; flex: none; }
  body.of-page table.cards.office-orders td.c-flags .note-flag { margin: 0; }
  body.of-page table.cards.office-orders .cust-line .note-flag.flag-after { display: none; }
  body.of-page table.cards.office-orders tr > td:nth-last-child(4) { order: 7; }
  body.of-page table.cards.office-orders tr > td:nth-last-child(3) { order: 8; }
}
@media (max-width: 760px) {
  /* The payment cell keeps its own place (it was dissolved into the card,
     so its tag landed on the top line). */
  body.of-page table.cards.office-orders td.badge-cell:not(.is-blank) { display: block; }
}
@media (max-width: 760px) { body.of-page table.cards.office-orders td.badge-cell > * { margin-top: 0; } }
@media (max-width: 760px) {
  /* The tags keep to one line: the date gives way first. */
  body.of-page table.cards.office-orders td.col-placed { flex: 1 1 0; min-width: 64px; }
  body.of-page table.cards.office-orders .badge, body.of-page table.cards.office-orders td.c-flags .note-flag { padding-left: 8px; padding-right: 8px; }
  body.of-page table.cards.office-orders tr { column-gap: 6px; }
}
body.of-page .container .date-find-text { font-size: 13px; font-weight: 400; }
@media (max-width: 760px) { body.of-page .container .date-find-text { font-size: 16px; } }
/* Products' order arrows, plain to see but small (Angel, 3 Oct: "way too
   discrete now", "they take way too much space", "why in circles?"): two
   chevrons, up over down, dark grey with no circle; a soft square under the
   one you point at; the one that can't go further stays faint. */
body.of-page table.product-list td.move-cell { width: 1%; padding-left: 10px; padding-right: 2px; }
body.of-page table.product-list td.move-cell form { display: block; }
body.of-page table.product-list button.move-btn { display: grid; place-items: center; width: 26px; height: 20px; border: 0; border-radius: 6px; background: transparent; color: #4a4a4a; }
body.of-page table.product-list button.move-btn:not([disabled]):hover { background: #ececea; color: #1f1f1f; }
body.of-page table.product-list button.move-btn[disabled] { opacity: 0.25; }
@media (max-width: 760px) {
  body.of-page table.cards.product-list td.move-cell { display: flex; flex-direction: column; width: auto; flex: none; padding: 0 0 0 6px; }
  body.of-page table.cards.product-list button.move-btn { width: 32px; height: 26px; }
}
/* Recently made's heading starts where the cards above it do (3 Oct). */
:where(body.of-page) .made-card .report-card-head { padding: 20px 22px 4px; }
/* The floor's Web shop list has no Delivery to (Angel, 3 Oct: Shopify ships
   them), so its items are the third column and the status keeps to one
   line. Widths are set below, by column. */
@media (min-width: 761px) {
  body.of-page table.floor-orders.web-table td:nth-child(3) { min-width: 9em; }
  body.of-page table.floor-orders.web-table td:nth-child(4) { min-width: 0; white-space: nowrap; }
}
/* Office Orders: the columns stay put whichever tab is open, where they are
   on All (Angel, 4 Oct: "keep the total, payment, status etc in equal
   distance. Don't move them around"). Each short column has a set width,
   enough for the longest it holds (Payment's "awaiting payment", Status's
   "Ready for collection"), so no tab's rows can push them about; the
   customer takes the rest. Smaller below 1200px, where the tags are. */
@media (min-width: 761px) {
  body.of-page table.office-orders th.c-order { width: 72px; min-width: 72px; }
  body.of-page table.office-orders th.c-total { width: 76px; min-width: 76px; }
  body.of-page table.office-orders th.c-pay { width: 136px; min-width: 136px; }
  body.of-page table.office-orders th.c-status { width: 144px; min-width: 144px; }
  body.of-page table.office-orders th.c-deliv { width: 140px; min-width: 140px; }
}
@media (min-width: 1200px) {
  body.of-page table.office-orders th.c-order { width: 84px; min-width: 84px; }
  body.of-page table.office-orders th.c-placed { width: 140px; min-width: 140px; }
  body.of-page table.office-orders th.c-total { width: 96px; min-width: 96px; }
  body.of-page table.office-orders th.c-pay { width: 148px; min-width: 148px; }
  body.of-page table.office-orders th.c-status { width: 164px; min-width: 164px; }
  body.of-page table.office-orders th.col-items { width: 90px; min-width: 90px; }
  body.of-page table.office-orders th.c-deliv { width: 156px; min-width: 156px; }
}
/* The floor's Orders: the columns stay put whichever tab is open, as on the
   office's (Angel, 4 Oct: "everything should be mirrored"). Each column but
   the items has a set width - the customer enough for a name and its Note,
   Status for its picker or Shopify's two tags - and the items take the
   rest, so Web shop, without Delivery to, only starts its items sooner.
   Below 1200px the address and the items give up some room, and the time
   placed goes under its day, so the list fits its card. */
@media (min-width: 761px) {
  body.of-page table.floor-orders thead th.c-order { width: 72px; min-width: 72px; }
  body.of-page table.floor-orders thead th.c-cust { width: 210px; min-width: 210px; }
  body.of-page table.floor-orders thead th.c-deliv { width: 100px; min-width: 100px; }
  body.of-page table.floor-orders thead th.c-items { width: 100%; }
  body.of-page table.floor-orders thead th.c-status { width: 196px; min-width: 196px; }
  body.of-page table.floor-orders thead th.c-placed { width: 134px; min-width: 134px; }
  body.of-page table.floor-orders td:nth-child(4), body.of-page table.floor-orders.web-table td:nth-child(3) { min-width: 7em; }
}
@media (min-width: 1200px) {
  body.of-page table.floor-orders thead th.c-order { width: 84px; min-width: 84px; }
  body.of-page table.floor-orders thead th.c-deliv { width: 150px; min-width: 150px; }
  body.of-page table.floor-orders thead th.c-placed { width: 144px; min-width: 144px; }
}
@media (min-width: 761px) and (max-width: 1199px) {
  body.of-page table.floor-orders thead th.c-placed { width: 96px; min-width: 96px; }
  body.of-page table.floor-orders td:nth-child(6), body.of-page table.floor-orders.web-table td:nth-child(5) { white-space: normal; }
}
/* Office Orders on a narrower window: the day placed, and Payment and
   Delivery a little narrower, so the customer keeps room for a name and
   its Note now the date stays (4 Oct). A rare wider tag, "awaiting
   payment", widens its column rather than wrapping. */
@media (min-width: 761px) and (max-width: 1279px) {
  body.of-page table.office-orders th.c-placed { width: 80px; min-width: 80px; }
  body.of-page table.office-orders th.c-pay { width: 108px; min-width: 108px; }
  body.of-page table.office-orders th.c-deliv { width: 116px; min-width: 116px; }
  body.of-page table.office-orders .deliv-text { max-width: 96px; }
}
/* Tabs that don't fit beside More and Find no longer slide under them,
   clipped (Angel, 4 Oct): what doesn't fit drops to its own line, at the
   right, so every tab shows. A phone still swipes its tabs. */
@media (min-width: 761px) {
  .list-bar { flex-wrap: wrap; row-gap: 10px; }
  .list-bar .list-tablist { flex: 1 0 auto; max-width: 100%; flex-wrap: wrap; row-gap: 6px; }
  .list-bar .list-find { margin-left: auto; }
}
/* A customer's addresses in their lines, as QuickBooks keeps them, and the
   note on one split into lines by guess (4 Oct). */
.cust-edit.is-editing .cust-check { display: none; }
.cust-check { margin: 0 0 10px; padding: 8px 12px; border-radius: 10px; background: #fff1b8; color: #5e4b00; font-size: 13px; }
:where(body.of-page) .cust-form .addr-set { min-width: 0; margin: 0 0 14px; padding: 0; border: 0; }
:where(body.of-page) .cust-form .addr-set legend { margin: 6px 0 4px; padding: 0; color: #1f1f1f; font-size: 14px; font-weight: 700; }
:where(body.of-page) .cust-form .addr-same { display: flex; align-items: center; gap: 8px; margin: 2px 0 6px; font-weight: 500; }
:where(body.of-page) .cust-form .addr-same input { width: auto; min-height: 0; margin: 0; }
:where(body.of-page) .cust-form .addr-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0 10px; }
:where(body.of-page) .cust-form .addr-f { display: block; min-width: 0; }
:where(body.of-page) .cust-form .addr-line1, :where(body.of-page) .cust-form .addr-line2 { grid-column: 1 / -1; }
/* QuickBooks (4 Oct): its card on Integrations, the matching page and the
   order page's invoice. */
#quickbooks .integration-head { justify-content: flex-start; flex-wrap: wrap; gap: 8px; }
#quickbooks .integration-head .integration-title { margin-right: auto; }
.int-note { margin: 10px 0 14px; color: #555555; }
.int-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 14px; }
.int-actions form { margin: 0; }
.qb-keys { display: grid; gap: 6px; max-width: 520px; margin-top: 6px; }
.qb-keys label { font-weight: 600; font-size: 13.5px; }
.qb-keys button { justify-self: start; margin-top: 8px; }
.qb-env { margin: 8px 0 0; padding: 0; border: 0; display: grid; gap: 6px; }
.qb-env legend { margin-bottom: 4px; font-weight: 600; font-size: 13.5px; }
.qb-env label { display: flex; align-items: center; gap: 8px; font-weight: 400; }
.qb-env input { width: auto; margin: 0; }
.qb-card { margin-bottom: 16px; }
/* The connection box on QuickBooks' page, the same distance from the box under it as the rest (Angel, 4 Oct). */
.integration-card#quickbooks { margin-bottom: 16px; }
.qb-card h2 { margin-bottom: 4px; }
.qb-rows { display: grid; }
.qb-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr); align-items: center; gap: 8px 16px; padding: 10px 0; border-top: 1px solid #f0f0ee; }
.qb-row:first-child { border-top: 0; }
.qb-what { font-weight: 600; min-width: 0; overflow-wrap: anywhere; }
.qb-what small { display: block; color: #666666; font-size: 12px; font-weight: 400; }
.qb-what .badge { margin-top: 4px; }
.qb-row select { width: 100%; min-width: 0; margin: 0; }
.qb-pick { display: flex; gap: 8px; align-items: center; min-width: 0; }
.qb-pick select { flex: 1 1 auto; }
.qb-pick .btn-small { flex: none; white-space: nowrap; }
/* Save at the end of the page, where it sits, not floating over it (Angel, 4 Oct). */
.qb-save { display: flex; justify-content: flex-end; padding: 4px 0 12px; }
.order-qb { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 12px; }
.order-qb .form-hint { flex-basis: 100%; margin: 0; }
.order-qb form { margin: 0; }
/* Marking invoiced by hand, once QuickBooks makes the invoices: a quiet line under it. */
.order-qb .order-qb-byhand { flex-basis: 100%; }
.order-qb .order-qb-byhand .link-button { font-size: inherit; }
/* Tying an order invoiced by hand to its QuickBooks invoice (4 Oct). */
.order-qb .order-qb-link { flex-basis: 100%; display: flex; flex-direction: column; gap: 6px; }
.order-qb .order-qb-link label { margin: 0; font-size: 13px; font-weight: 700; }
.order-qb-link-row { display: flex; gap: 8px; }
.order-qb-link-row input { flex: 1 1 auto; min-width: 0; max-width: 220px; margin: 0; }
/* The QuickBooks page's Payments box. */
.qb-pay-tiles { margin: 12px 0; }
.qb-pay-tiles .int-tile b { font-size: 22px; }
.qb-missing { margin-top: 14px; }
.qb-missing > summary h3 { margin: 0; font-size: 15px; }
a.qb-missing-row { color: #1f1f1f; text-decoration: none; }
a.qb-missing-row:hover .qb-what { text-decoration: underline; }
@media (max-width: 760px) {
  .qb-row { grid-template-columns: minmax(0, 1fr); }
  .qb-pick { flex-wrap: wrap; }
}
/* The terms of use and privacy pages (4 Oct): the login page's column,
   widened for reading. */
.auth-shell.legal-page { max-width: 680px; }
.legal-page .auth-logo { margin-bottom: 12px; }
.legal-page .auth-logo img { max-width: 100%; height: auto; }
.legal-nav { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 18px; margin: 0 0 28px; font-size: 14px; }
.legal-nav a[aria-current="page"] { font-weight: 700; text-decoration: none; }
.legal-page h2 { margin-top: 1.6em; font-size: 1.1rem; }
.legal-page p, .legal-page li { line-height: 1.6; }
/* A customer's place in QuickBooks, on their Accounts card, and the
   matching page's "In QuickBooks, not in the portal" (4 Oct). */
.cust-qb > span, .cust-qb > a { display: block; }
.cust-qb > a { margin-top: 2px; }
.cust-qb-error { margin-top: 6px; padding: 6px 10px; border-radius: 8px; background: #fbe7e3; color: #8a2c1a; font-size: 13px; }
.cust-qb form { margin: 8px 0 0; }
/* A matching section that folds away (4 Oct): its heading, how it stands,
   and an arrow that turns when it's open. */
.qb-fold > summary { display: flex; align-items: center; gap: 10px; list-style: none; cursor: pointer; }
.qb-fold > summary::-webkit-details-marker { display: none; }
.qb-fold > summary h2 { margin: 0; }
.qb-fold > summary .qb-chev { margin-left: auto; color: #666666; transition: transform .2s ease; }
.qb-fold[open] > summary { margin-bottom: 10px; }
.qb-fold[open] > summary .qb-chev { transform: rotate(180deg); }
.qb-fold > summary:focus-visible { outline: 2px solid #1c1c1c; outline-offset: 4px; border-radius: 8px; }
@media (prefers-reduced-motion: reduce) { .qb-fold > summary .qb-chev { transition: none; } }
/* Customers: the last order's date and the year's spend on one line each (Angel, 4 Oct: "date in one line please"). */
table.customer-list .c-when { white-space: nowrap; }
/* An order's discount (Angel, 4 Oct): Add discount / Change opens a small
   form beside the totals. */
.discount-pick { position: relative; display: inline-block; text-align: left; }
.discount-pick > summary { list-style: none; cursor: pointer; white-space: nowrap; }
.discount-pick > summary::-webkit-details-marker { display: none; }
.discount-form { position: absolute; z-index: 30; right: 0; top: calc(100% + 6px); width: 260px; display: flex; flex-direction: column; gap: 6px; padding: 14px; border-radius: 16px; background: #ffffff; box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12), 0 0 0 1px rgba(0, 0, 0, 0.05); }
.discount-form label { margin: 0; font-size: 12px; font-weight: 700; }
.discount-fields { display: flex; gap: 6px; }
.discount-fields input { flex: 1 1 auto; min-width: 0; margin: 0; }
.discount-fields select { flex: 0 0 76px; width: 76px; min-width: 0; margin: 0; }
.discount-form > input { margin: 0; }
.discount-actions { display: flex; gap: 8px; margin-top: 4px; }
.discount-form .form-hint { margin: 0; font-size: 12px; }
.discount-row td { color: #146b58; }
/* Home's tiles on a phone (Angel, 5 Oct: "these can be more compact", "no
   need for one in a row"): two to a row, slimmer, each figure above its
   label so a long label wraps inside the tile rather than past it. The
   Orders page's own row of tiles keeps its look. */
@media (max-width: 760px) {
  .home-stats:not(.order-stats) { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .home-stats:not(.order-stats) .home-stat { align-items: center; padding: 10px 12px; gap: 10px; border-radius: 14px; }
  .home-stats:not(.order-stats) .home-stat .home-ic { flex: 0 0 30px; width: 30px; height: 30px; }
  .home-stats:not(.order-stats) .home-stat .home-ic svg { width: 16px; height: 16px; }
  .home-stats:not(.order-stats) .home-stat > span:last-child { flex-direction: column; flex-wrap: nowrap; align-items: flex-start; row-gap: 1px; }
  .home-stats:not(.order-stats) .home-stat b { font-size: 18px; line-height: 1.1; }
  body.of-page .container .home-stats:not(.order-stats) .home-stat small { white-space: normal; line-height: 1.25; overflow-wrap: anywhere; }
}
/* A stock item's Move across (5 Oct), and Undo in its history. */
.move-box form { display: flex; flex-direction: column; gap: 8px; }
.move-fields { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.move-fields select { flex: 1 1 220px; width: auto; margin: 0; }
.move-fields input { width: 110px; margin: 0; }
.move-box form > input[type="text"] { margin: 0; }
.move-box form > button { align-self: flex-start; }
.undo-move { display: inline; margin: 0; }

/* ---- Searchable item picker (public/js/item-picker.js, 13 Oct) ----
   In place of a long dropdown on a supplier order's lines: type to search,
   grouped and alphabetical, "+ Add something new" pinned at the foot. */
.ip { position:relative; min-width:0; }
.goods-row > .ip { flex:1 1 14rem; }
.ip .ip-input { width:100%; margin:0; padding-right:2.2rem;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%231c1c1c' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.5-3.5'/%3E%3C/svg%3E");
  background-repeat:no-repeat; background-position:right 0.85rem center; background-size:15px; }
.ip-panel { position:absolute; z-index:40; top:calc(100% + 6px); left:0; width:max(100%, 26rem); max-width:min(34rem, calc(100vw - 2rem));
  display:flex; flex-direction:column; max-height:min(27rem, 62vh); overflow:hidden;
  background:var(--paper); border:1px solid var(--border); border-radius:12px; box-shadow:0 14px 34px rgba(28, 28, 28, 0.14); }
.ip-panel[hidden] { display:none; }
/* No padding at the top: a group's heading sticks at the list's inner edge,
   so padding there left a strip the names scrolled through above it. */
.ip-list { list-style:none; margin:0; padding:0 0 0.4rem; overflow-y:auto; flex:1 1 auto; }
.ip-group { position:sticky; top:0; z-index:1; padding:0.6rem 0.95rem 0.3rem; background:var(--paper); box-shadow:0 1px 0 var(--border);
  font-family:var(--heading-font); font-size:0.64rem; font-weight:700; letter-spacing:0.09em; text-transform:uppercase; color:rgba(28, 28, 28, 0.55); }
.ip-option { display:flex; align-items:baseline; justify-content:space-between; gap:1rem; padding:0.48rem 0.95rem; cursor:pointer; font-size:0.9rem; line-height:1.35; }
.ip-option.is-active { background:var(--paper-muted); }
.ip-option[aria-selected="true"] .ip-name { font-weight:700; }
.ip-name { min-width:0; overflow-wrap:anywhere; }
.ip-meta { flex:0 0 auto; font-size:0.78rem; color:rgba(28, 28, 28, 0.6); white-space:nowrap; font-variant-numeric:tabular-nums; }
.ip-none { padding:0.8rem 0.95rem; font-size:0.9rem; color:rgba(28, 28, 28, 0.6); }
.ip .ip-new { flex:0 0 auto; display:block; width:100%; margin:0; padding:0.8rem 0.95rem; border:0; border-top:1px solid var(--border); border-radius:0;
  background:var(--paper); color:var(--ink); text-align:left; font-family:var(--body-font); font-size:0.9rem; font-weight:700; letter-spacing:normal; text-transform:none; line-height:1.3; }
.ip .ip-new:hover, .ip .ip-new.is-active { background:var(--paper-muted); opacity:1; }
@media (max-width:600px) { .ip-panel { width:100%; max-width:none; } }

/* Cost per item in Pricing, under the price (13 Oct): the boxes, then
   Profit and Margin on their band, then where the figure comes from. */
.pf-cost { margin-top:0.4rem; padding-top:1rem; border-top:1px solid var(--border); }
.pf-cost .prod-field > label, .pf-cost-label { display:block; font-size:0.68rem; margin-bottom:0.3rem; font-weight:700; }
.pf-cost input[type=number], .pf-cost select { margin:0; }
.pf-cost-worked { display:block; font-size:1.25rem; font-variant-numeric:tabular-nums; line-height:1.4; }
.pf-cost-parts { margin:0.6rem 0 0; }

/* Creating an order for a customer (14 Oct): search to add a product, and
   each one a line - its grind, quantity, price and total. */
.ob-add { margin-bottom:0.8rem; }
.ob-add .ip { width:100%; }
.ob-line .ob-name { flex:1 1 14rem; min-width:0; font-weight:600; }
.goods-row > select.ob-grind { flex:0 0 auto; width:auto; margin:0; }
.ob-line .ob-each { font-size:0.85rem; color:rgba(28, 28, 28, 0.65); white-space:nowrap; font-variant-numeric:tabular-nums; }
.ob-line .ob-sum { min-width:4.5rem; text-align:right; font-variant-numeric:tabular-nums; }
.ob-empty { margin:0.2rem 0 0; }

/* How invoices are made, on the QuickBooks page (15 Oct): one choice of three. */
.qb-invoicing { display:flex; flex-direction:column; align-items:flex-start; gap:0.6rem; }
.qb-way { display:flex; align-items:flex-start; gap:0.6rem; margin:0; text-transform:none; letter-spacing:normal; font-weight:400; cursor:pointer; }
.qb-way input { margin-top:0.2rem; }
.qb-way span { display:flex; flex-direction:column; gap:0.1rem; }
.qb-way small { font-size:0.82rem; color:rgba(28, 28, 28, 0.62); }

/* Home's email alert (15 Oct): what's wrong, the reason, what to do. */
.mail-alert { display:flex; flex-direction:column; gap:0.35rem; margin-bottom:1.2rem; }
.mail-alert-why { font-size:0.85rem; }
.mail-alert a { color:inherit; }
