/* Eraman's design layer, on top of Bootstrap 5.3.
 *
 * Load AFTER public/vendor/bootstrap.min.css. Bootstrap supplies the components and the
 * accessibility work inside them - focus management, ARIA state, keyboard handling,
 * dropdown positioning. This file supplies the design.
 *
 * The model is Stripe, read off docs.stripe.com and stripe.com in Chrome on 2026-09-14
 * by measuring their computed styles rather than guessing at them. What that gave:
 *
 *   - Text is never black. Headings #1a1f36, body #3c4257, secondary #697386. Black is
 *     for display type only, and there is none here.
 *   - One accent hue, used only for things you can act on and for status. Their rule is
 *     "don't introduce a new hue when a neutral and a weight change will do". Ours is
 *     Eraman's green rather than their blurple.
 *   - Small radii. Their buttons are 4px, not pillowy.
 *   - Few boxes. Content sits on the page and is separated by space and headings.
 *   - Tables with no vertical rules, no header fill, no outer border: a 13px/500 muted
 *     uppercase header, 16px cell padding, and one hairline between rows.
 *   - Chromatic shadows - rgba(50,50,93,...), a blue-grey, never neutral black.
 *   - Density under control: the data is packed, the chrome around it is not.
 *
 * There is no build step; the vendored Bootstrap files are never edited.
 *
 * Rules for editing this file:
 *   - Nothing gets a hand-picked value. Use the scales below.
 *   - Never restate a Bootstrap colour as a literal. Set the token.
 *   - Our class names are the ones the pages already used. Only two collided with
 *     Bootstrap and were renamed: `.row` -> `.fields`, `.grid` -> `.autogrid`.
 */

/* ---- scales ------------------------------------------------------------------------- */
:root {
  /* Space, on a 4px base. */
  --s1: .25rem; --s2: .5rem; --s3: .75rem; --s4: 1rem;
  --s5: 1.25rem; --s6: 1.5rem; --s8: 2rem; --s10: 2.5rem;

  /* Type. Their interface runs at 14px and their prose at 16/26; both are here, because
     a table of clients and a paragraph explaining it are not the same kind of reading. */
  --t-micro: .75rem;    /* 12 - badges, captions */
  --t-small: .8125rem;  /* 13 - column headers, help text */
  --t-body:  .875rem;   /* 14 - the interface */
  --t-read:  .9375rem;  /* 15 - prose */
  --t-title: 1.25rem;   /* 20 - the name of a section */
  --t-page:  1.75rem;   /* 28 - the name of the page */

  /* Chromatic, as Stripe's are - a neutral grey shadow reads as dirt - but tinted towards
     Eraman's near-black rather than Stripe's navy. */
  --e1: 0 1px 1px rgba(36, 40, 40, .07), 0 1px 2px rgba(0, 0, 0, .04);
  --e2: 0 2px 5px rgba(36, 40, 40, .10), 0 1px 2px rgba(0, 0, 0, .05);
  --e3: 0 13px 27px rgba(36, 40, 40, .18), 0 8px 16px rgba(0, 0, 0, .07);

  --r-control: .25rem;  /* 4 */
  --r-card: .5rem;      /* 8 */
  --r-badge: .25rem;    /* 4 */

  --measure: 68ch;      /* prose never runs wider than this */
}

/* ---- colour --------------------------------------------------------------------------
 * Eraman's own palette, read off eraman.coop on 2026-09-14 by sampling the computed
 * styles of the live page: the mint #6bdbc5 that fills their call-to-action pill, sits
 * behind their strapline and underlines the wordmark, on near-black #242828 and white.
 * (Everything before this used a forest green that was never theirs.)
 *
 * The mint cannot carry text. Against white it is about 1.9:1 - their marketing site sets
 * white on it and gets away with it at display size, but a working tool cannot. So the
 * brand splits in two, which is the normal thing to do with a light brand colour:
 *
 *   --er-mint    the fill. Primary buttons, highlights, the selected state. Dark text
 *                sits on it at about 11:1.
 *   --er-accent  the same hue taken down until it reads on white (4.9:1). This is what
 *                links, the active nav item and focus rings use.
 *
 * Everything else is neutral, and colour otherwise means status and nothing else.
 */
:root,
[data-bs-theme='light'] {
  --er-mint: #6bdbc5;       /* the brand fill, straight off their site */
  --er-mint-hover: #57cfb7;
  --er-mint-ink: #08211c;   /* what sits on the mint */
  --er-green: #0f7a66;      /* the mint, darkened until it reads on white */
  --er-green-rgb: 15, 122, 102;
  --er-green-hover: #0b6252;
  --er-green-ink: #fff;
  --er-green-wash: #eafaf5;
  --er-warn: #983705;
  --er-warn-wash: #fdf3e7;
  --er-bad: #a41c14;
  --er-bad-wash: #fdeceb;
  --er-ok: #0f7a66;

  --er-ink: #242828;        /* headings - their near-black */
  --er-panel: #fff;
  --er-hover: #f3f8f6;      /* a row under the cursor */
  --er-rule: #ebf1ef;       /* between rows: lighter than a border */

  /* Stripe's ground is a cool blue-grey, which fights a mint accent. Same idea - a tinted
     ground so white cards read as surfaces - carrying a trace of Eraman's hue instead. */
  --bs-body-bg: #f5f9f8;
  --bs-tertiary-bg: #fff;
  --bs-body-color: #3d4644;
  --bs-secondary-color: #66706d;   /* dark enough to pass 4.5:1 on the tinted ground too */
  --bs-border-color: #e2e8e6;
  --bs-border-color-translucent: #e2e8e6;

  --bs-primary: var(--er-green);
  --bs-primary-rgb: var(--er-green-rgb);
  --bs-link-color: var(--er-green);
  --bs-link-color-rgb: var(--er-green-rgb);
  --bs-link-hover-color: var(--er-green-hover);
  --bs-danger: var(--er-bad);
  --bs-warning: var(--er-warn);

  --bs-border-radius: var(--r-control);
  --bs-border-radius-lg: var(--r-card);
  --bs-body-font-size: var(--t-body);
  --bs-body-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;

  --bs-focus-ring-color: rgba(var(--er-green-rgb), .22);
  --bs-focus-ring-width: 3px;
}

[data-bs-theme='dark'] {
  --er-mint: #6bdbc5;
  --er-mint-hover: #82e5d3;
  --er-mint-ink: #08211c;
  --er-green: #5fd0ba;      /* on a dark ground the mint itself already reads */
  --er-green-rgb: 95, 208, 186;
  --er-green-hover: #7ee0cd;
  --er-green-ink: #08211c;
  --er-green-wash: #122a26;
  --er-warn: #e0a962;
  --er-warn-wash: #2a2117;
  --er-bad: #e8837d;
  --er-bad-wash: #2b1917;
  --er-ok: #46b57e;

  --er-ink: #f0f2f6;
  --er-panel: #1a1f2b;
  --er-hover: #212736;
  --er-rule: #262d3d;

  --bs-body-bg: #11151f;
  --bs-tertiary-bg: #1e2431;
  --bs-body-color: #c4cbd9;
  --bs-secondary-color: #8b93a5;
  --bs-border-color: #2a3142;
  --bs-border-color-translucent: #2a3142;

  --e1: 0 1px 1px rgba(0, 0, 0, .4);
  --e2: 0 2px 5px rgba(0, 0, 0, .45);
  --e3: 0 13px 27px rgba(0, 0, 0, .55), 0 8px 16px rgba(0, 0, 0, .35);
}

/* ---- element defaults -----------------------------------------------------------------
 * Both pages build most of their DOM in JavaScript - some two hundred createElement and
 * innerHTML sites - writing bare <input>, <select>, <button>, <table>. Rather than hang a
 * class on every one, the bare elements carry the design here, so the whole app moves
 * when this file does.
 */
* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bs-body-bg);
  color: var(--bs-body-color);
  font: var(--t-body)/1.45 var(--bs-body-font-family);
  -webkit-font-smoothing: antialiased;
}

/* Prose gets the larger size and the looser leading; the interface does not. */
p { margin: 0 0 var(--s3); max-width: var(--measure); font-size: var(--t-read); line-height: 1.65; }

a { color: var(--er-green); text-decoration: none; }
a:hover { color: var(--er-green-hover); text-decoration: underline; }

input:not([type='checkbox']):not([type='radio']):not([type='range']):not([type='file']),
select,
textarea {
  width: 100%;
  min-height: 2.25rem;
  padding: var(--s2) var(--s3);
  border: 1px solid var(--bs-border-color);
  border-radius: var(--r-control);
  background: var(--bs-tertiary-bg);
  color: var(--bs-body-color);
  font: inherit;
  box-shadow: var(--e1);
  transition: border-color .12s ease, box-shadow .12s ease;
}

input:hover:not(:disabled),
select:hover:not(:disabled),
textarea:hover:not(:disabled) { border-color: var(--bs-secondary-color); }

input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: 0;
  border-color: var(--er-green);
  box-shadow: 0 0 0 var(--bs-focus-ring-width) var(--bs-focus-ring-color);
}

/* A select must be readable at a glance - that is the whole reason it is a select rather
   than a text field. Room for the caret, and never squeezed below legibility. */
select {
  min-width: 7.5rem;
  padding-right: var(--s6);
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath fill='none' stroke='%23697386' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round' d='M1 1l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--s3) center;
}

textarea { min-height: 5rem; resize: vertical; font-family: Menlo, Consolas, monospace; font-size: var(--t-small); }

/* A field heading: small, quiet, and always there. A placeholder is not a label - it
   disappears exactly when the reader needs it. */
label {
  display: block;
  margin-bottom: var(--s1);
  color: var(--bs-body-color);
  font-size: var(--t-small);
  font-weight: 500;
}

/* ...but a label wrapping its own control is a phrase, not a heading. */
label:has(> input[type='checkbox']),
label:has(> input[type='radio']) {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  margin-bottom: 0;
  font-weight: 400;
  cursor: pointer;
}

input[type='checkbox'], input[type='radio'] { width: .875rem; height: .875rem; accent-color: var(--er-green); cursor: pointer; }

button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  min-height: 2.25rem;
  padding: var(--s2) var(--s3);
  border: 1px solid var(--bs-border-color);
  border-radius: var(--r-control);
  background: var(--bs-tertiary-bg);
  color: var(--bs-body-color);
  font: inherit;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: var(--e1);
  transition: background-color .12s ease, border-color .12s ease, box-shadow .12s ease;
}
button:hover:not(:disabled) { background: var(--er-hover); color: var(--er-ink); }
button:active:not(:disabled) { box-shadow: none; }
button:focus-visible { outline: 0; box-shadow: 0 0 0 var(--bs-focus-ring-width) var(--bs-focus-ring-color); }
button:disabled { opacity: .5; box-shadow: none; cursor: default; }

/* The primary action is their pill: the mint fill, with dark text on it. */
button.primary, .btn-primary {
  --bs-btn-bg: var(--er-mint);
  --bs-btn-border-color: var(--er-mint);
  --bs-btn-hover-bg: var(--er-mint-hover);
  --bs-btn-color: var(--er-mint-ink);
  background: var(--er-mint);
  border-color: var(--er-mint);
  color: var(--er-mint-ink);
  font-weight: 600;
}
button.primary:hover:not(:disabled) { background: var(--er-mint-hover); border-color: var(--er-mint-hover); color: var(--er-mint-ink); }

/* Destructive actions say so in a word as well as a colour. */
button.danger { color: var(--er-bad); }
button.danger:hover:not(:disabled) { background: var(--er-bad-wash); border-color: var(--er-bad); color: var(--er-bad); }

/* ---- tables -----------------------------------------------------------------------------
 * Measured off docs.stripe.com: a 13px/500 uppercase muted header with no fill and no
 * outer border, 16px cell padding, and one hairline between rows. No vertical rules at
 * all - the alignment does that work, and every rule you remove is noise removed.
 */
table { width: 100%; border-collapse: collapse; }

th {
  padding: 0 var(--s4) var(--s2);
  color: var(--bs-secondary-color);
  font-size: var(--t-small);
  font-weight: 500;
  text-align: left;
  text-transform: uppercase;
  white-space: nowrap;
}

td {
  padding: var(--s4);
  border-top: 1px solid var(--er-rule);
  color: var(--bs-body-color);
  text-align: left;
  vertical-align: middle;
}

tbody tr { transition: background-color .1s ease; }
tbody tr:hover td { background: var(--er-hover); }

td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---- page frame --------------------------------------------------------------------------
 * The top bar is chrome: thin, white, quiet, and it stays. Everything that matters is
 * below it.
 */
header {
  position: sticky;
  top: 0;
  z-index: 1030;
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s3) var(--s6);
  background: var(--er-panel);
  border-bottom: 1px solid var(--bs-border-color);
}
header h1 {
  margin: 0;
  color: var(--er-ink);
  font-size: var(--t-read);
  font-weight: 600;
  letter-spacing: -.01em;
}
header a, header .who {
  margin-left: auto;
  color: var(--bs-secondary-color);
  font-size: var(--t-small);
}
header a:hover { color: var(--er-green); }

main { max-width: 84rem; margin: 0 auto; padding: var(--s8) var(--s6); }

/* A card, kept deliberately quiet: a hairline and the faintest lift. Stripe's instinct is
   to draw no box at all, and the only reason there is one here is that this admin shows
   several unrelated things at once and the reader needs to know where one ends. */
.panel {
  margin-bottom: var(--s6);
  padding: var(--s6);
  background: var(--er-panel);
  border: 1px solid var(--bs-border-color);
  border-radius: var(--r-card);
  box-shadow: var(--e1);
}

/* The name of a section, in the heading ink and tightly tracked - the two things that make
   Stripe's headings read as engineered rather than decorative. */
h2 {
  margin: 0 0 var(--s2);
  color: var(--er-ink);
  font-size: var(--t-title);
  font-weight: 600;
  letter-spacing: -.015em;
  line-height: 1.3;
}

/* The sentence under a section title, explaining what it is for. */
.panel > h2 + p { margin: 0 0 var(--s5); color: var(--bs-secondary-color); }

/* A table runs to the card's edges: its own hairlines are the separator, so the card's
   padding would only hold it away from its title. */
.panel > table { width: calc(100% + 2 * var(--s6)); margin: var(--s5) calc(-1 * var(--s6)) calc(-1 * var(--s6)); }
.panel > table th:first-child, .panel > table td:first-child { padding-left: var(--s6); }
.panel > table th:last-child,  .panel > table td:last-child  { padding-right: var(--s6); }

/* A row of fields that wraps rather than squeezing. Named `.fields` because Bootstrap owns
   `.row`. `.tight` opts a child out of growing - for buttons beside a full-width field. */
.fields { display: flex; gap: var(--s3); align-items: flex-end; flex-wrap: wrap; }
.fields > * { flex: 1 1 13.75rem; min-width: 0; }
.fields > .tight { flex: 0 0 auto; }

.autogrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(9.375rem, 1fr)); gap: var(--s3); }

.muted { color: var(--bs-secondary-color); font-size: var(--t-small); }
.bad { color: var(--er-bad); font-weight: 500; }
.warn { color: var(--er-warn); font-weight: 500; }
.saved { color: var(--er-ok); font-size: var(--t-micro); font-weight: 500; }
.hidden { display: none !important; }

/* An identifier - an account key, an email - is one unbreakable token. Wrapping it mid-word
   turns "aleko_crops4life@demo.invalid" into three unreadable lines, so it gets one line and
   an ellipsis, with the whole value in a tooltip. */
.ident {
  display: block;
  overflow: hidden;
  color: var(--bs-secondary-color);
  font-size: var(--t-small);
  text-overflow: ellipsis;
  white-space: nowrap;
}
.strong { display: block; color: var(--er-ink); font-weight: 500; }

/* A badge states a fact about its row. Colour here means status and nothing else: which
   tariff applied, or that nothing will be charged. */
.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  padding: .0625rem var(--s2);
  border: 0;
  border-radius: var(--r-badge);
  background: var(--er-hover);
  color: var(--bs-secondary-color);
  font-size: var(--t-micro);
  font-weight: 500;
  white-space: nowrap;
}
td .pill { background: var(--er-green-wash); color: var(--er-green); }
td:has(.bad) .pill { background: var(--er-bad-wash); color: var(--er-bad); }

.notice {
  margin: var(--s4) 0;
  padding: var(--s3) var(--s4);
  border-left: 2px solid var(--er-warn);
  border-radius: 0 var(--r-control) var(--r-control) 0;
  background: var(--er-warn-wash);
  font-size: var(--t-body);
}

.linkish {
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  color: var(--er-green);
  font-size: var(--t-small);
  font-weight: 500;
}
.linkish:hover:not(:disabled) { background: none; border: 0; color: var(--er-green-hover); text-decoration: underline; }

.sup { display: inline-flex; align-items: center; gap: var(--s2); margin-right: var(--s3); font-size: var(--t-body); }
.pick { display: inline-flex; align-items: center; gap: var(--s2); margin-right: var(--s4); font-size: var(--t-body); cursor: pointer; }

/* A repeated sub-card inside a section - one time slot, one package type. */
.subcard {
  margin-bottom: var(--s4);
  padding: var(--s5);
  background: var(--er-panel);
  border: 1px solid var(--bs-border-color);
  border-radius: var(--r-card);
}

/* ---- the address combobox -----------------------------------------------------------------
 * A text input that filters the saved addresses. A combobox rather than a select because the
 * list is long and typing is faster than scrolling - the rule in reference/ui-guidelines.md
 * is a searchable control from about fifteen options up.
 *
 * placeMenu() flips the menu above the input when there is no room below, so it never opens
 * off-screen.
 */
.combo { position: relative; }

.menu {
  position: absolute;
  z-index: 1055;
  left: 0; right: 0;
  top: calc(100% + var(--s1));
  padding: var(--s1);
  max-height: 21rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--er-panel);
  border: 1px solid var(--bs-border-color);
  border-radius: var(--r-card);
  box-shadow: var(--e3);
}
.menu.up { top: auto; bottom: calc(100% + var(--s1)); }

.menu .group {
  padding: var(--s2) var(--s2) var(--s1);
  color: var(--bs-secondary-color);
  font-size: var(--t-small);
  font-weight: 500;
  text-transform: uppercase;
}

/* The whole row is the target, not just its text, and it is tall enough to hit with a thumb. */
.menu .item {
  display: block;
  width: 100%;
  min-height: 2.75rem;
  padding: var(--s2) var(--s3);
  border: 0;
  border-radius: var(--r-control);
  background: none;
  box-shadow: none;
  font: inherit;
  font-weight: 400;
  text-align: left;
  white-space: normal;
}
.menu .item:hover, .menu .item.on { background: var(--er-hover); border: 0; }
.menu .item .nm { display: block; color: var(--er-ink); font-weight: 500; }
.menu .item .ad { display: block; color: var(--bs-secondary-color); font-size: var(--t-small); }
.menu .none { padding: var(--s3); color: var(--bs-secondary-color); font-size: var(--t-small); }

/* ---- tags -----------------------------------------------------------------------------------
 * Chosen tags read as pressed toggles: weight and a filled ground, never colour alone.
 */
.tags { margin-top: var(--s3); }
.tag {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-height: 1.875rem;
  margin: 0 var(--s2) var(--s2) 0;
  padding: var(--s1) var(--s3);
  border: 1px solid var(--bs-border-color);
  border-radius: var(--r-control);
  background: var(--bs-tertiary-bg);
  font-size: var(--t-small);
  box-shadow: none;
}
.tag .dot { display: inline-block; width: .5rem; height: .5rem; border-radius: 50%; }
.tag[aria-pressed='true'] { background: var(--er-green-wash); border-color: var(--er-green); color: var(--er-green); font-weight: 500; }

/* ---- the admin sidebar -------------------------------------------------------------------
 * Stripe's navigation is a plain list of text. No pills, no slabs, no boxes: the active
 * item is the accent colour and a rule down its edge, and that is enough. A coloured block
 * behind the item you are already on spends attention on the one thing you do not need to
 * find.
 */
.admin { display: grid; grid-template-columns: 15rem minmax(0, 1fr); gap: var(--s8); align-items: start; }

.side { position: sticky; top: 4.5rem; }
.side a, .side .soon {
  position: relative;
  display: block;
  padding: var(--s2) var(--s3);
  border-left: 2px solid transparent;
  color: var(--bs-body-color);
  text-decoration: none;
}
.side strong { display: block; font-size: var(--t-body); font-weight: 400; }
.side span { display: block; margin-top: 1px; color: var(--bs-secondary-color); font-size: var(--t-micro); line-height: 1.4; }
.side a:hover { color: var(--er-ink); text-decoration: none; }
.side a:hover strong { color: var(--er-ink); }

.side a.on { border-left-color: var(--er-mint); }
.side a.on strong { color: var(--er-green); font-weight: 600; }
.side a.on span { color: var(--bs-secondary-color); }

.side .elsewhere { margin-top: var(--s5); padding-top: var(--s4); border-top: 1px solid var(--bs-border-color); }
.side .elsewhere p {
  margin: 0 0 var(--s2);
  padding: 0 var(--s3);
  color: var(--bs-secondary-color);
  font-size: var(--t-micro);
  font-weight: 500;
  letter-spacing: .03em;
  text-transform: uppercase;
}
.side .soon { opacity: .45; cursor: default; }

/* ---- the clients table ---------------------------------------------------------------------
 * Left to itself the browser gave the email column 289px and the two selects an admin
 * actually operates 81px and 58px, so "Comercio local" read as "Comercio loc". The widths
 * are declared instead, and the email earns the least: the account key is already printed
 * under the name.
 */
table.clients { table-layout: fixed; }
table.clients .cClient { width: 21%; }
table.clients .cMail   { width: 22%; }
table.clients .cCat    { width: 19%; }
table.clients .cOwn    { width: 21%; }
table.clients .cEff    { width: 18%; }

@media (max-width: 75rem) {
  .panel:has(> table.clients) { overflow-x: auto; }
  table.clients { table-layout: auto; min-width: 56rem; }
}

/* ---- the order form's two columns ------------------------------------------------------------
 * The stops and the price stay in view while the form scrolls: they are what you are checking
 * as you type.
 */
.cols { display: grid; grid-template-columns: minmax(0, 1fr) minmax(21rem, 26rem); gap: var(--s6); align-items: start; }
.colSide {
  position: sticky;
  top: 4.5rem;
  max-height: calc(100vh - 6rem);
  overflow-y: auto;
  /* Both axes are stated. Setting only overflow-y makes the other axis `auto` too, and the
     vertical scrollbar then narrows the column while the panel inside keeps its width -
     which is exactly enough to raise a horizontal scrollbar under the stops. The gutter is
     reserved so the column does not jump the moment the list grows past the fold. */
  overflow-x: hidden;
  scrollbar-gutter: stable;
  overscroll-behavior: contain;
}

.total {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-top: var(--s4);
  padding-top: var(--s4);
  border-top: 1px solid var(--bs-border-color);
  color: var(--er-ink);
  font-size: var(--t-title);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.015em;
}
.totals { display: flex; justify-content: space-between; color: var(--bs-secondary-color); font-size: var(--t-small); }
.breakdown td { padding: var(--s1) 0; border: 0; font-size: var(--t-small); }
.breakdown tr:hover td { background: none; }

/* Tabs: Stripe underlines rather than encloses. */
.tabs { display: flex; gap: var(--s5); margin-bottom: var(--s6); border-bottom: 1px solid var(--bs-border-color); }
.tab {
  min-height: 0;
  padding: 0 0 var(--s3);
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  background: none;
  box-shadow: none;
  color: var(--bs-secondary-color);
  font-size: var(--t-body);
  font-weight: 500;
}
.tab:hover:not(:disabled) { background: none; border-bottom-color: var(--bs-border-color); color: var(--er-ink); }
.tab.on { border-bottom-color: var(--er-mint); color: var(--er-green); }

.zone { color: var(--bs-secondary-color); font-size: var(--t-micro); }
.zone.none { color: var(--er-warn); }

/* An unpriced row says so rather than reading 0,00 EUR. */
tr.unpriced td { color: var(--er-warn); }

/* An address we are not sure of: amber, and it says why. Never silently accepted. */
tr.doubt td, tr.doubt:hover td { background: var(--er-warn-wash); }
.doubtNote { margin-top: var(--s1); color: var(--er-warn); font-size: var(--t-micro); }

.detail, .detail:hover td { background: var(--bs-body-bg); }
.detail td { padding: var(--s4); }

.goods { margin-top: var(--s3); }
.good { display: flex; align-items: center; gap: var(--s2); margin-bottom: var(--s2); }
.good .nm { flex: 1; font-size: var(--t-body); }
.step { width: 1.875rem; min-width: 1.875rem; padding: 0; }
.qty { width: 3rem; min-width: 3rem; padding: var(--s1); text-align: center; font-variant-numeric: tabular-nums; }
.qty.on { border-color: var(--er-mint); box-shadow: 0 0 0 2px var(--er-green-wash); font-weight: 600; }

.remember { margin-top: var(--s1); font-size: var(--t-micro); }
.nameBox { display: flex; gap: var(--s2); margin-top: var(--s2); }

/* ---- the pricing rule card ---------------------------------------------------------------------
 * Numbered and draggable, because under "the first rule that matches" the order of the rules
 * *is* the price.
 */
.rulecard {
  display: flex;
  gap: var(--s4);
  align-items: flex-start;
  margin-bottom: var(--s3);
  padding: var(--s5);
  background: var(--er-panel);
  border: 1px solid var(--bs-border-color);
  border-radius: var(--r-card);
  transition: border-color .12s ease, box-shadow .12s ease;
}
.rulecard:hover { box-shadow: var(--e2); }
.rulecard.dragging { opacity: .4; }
.rulecard.over { border-color: var(--er-green); box-shadow: 0 0 0 3px var(--bs-focus-ring-color); }
.rulecard .handle {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s1);
  min-width: 1.75rem;
  color: var(--bs-secondary-color);
  cursor: grab;
  user-select: none;
}
.rulecard .handle .pos { font-size: var(--t-small); font-weight: 600; }
.rulecard .handle .arrows { font-size: var(--t-read); line-height: 1; }
.rulecard .rulemain { flex: 1 1 auto; min-width: 0; }
.rulecard .scope { margin: 0 0 var(--s3); max-width: none; color: var(--bs-secondary-color); font-size: var(--t-small); }
.rulecard .condline { margin-bottom: var(--s2); }
.rulecard .priceRow { margin-top: var(--s4); padding-top: var(--s4); border-top: 1px solid var(--er-rule); }
.rulecard .rmRule {
  min-height: 0;
  padding: var(--s1) var(--s2);
  border: 0;
  background: none;
  box-shadow: none;
  color: var(--bs-secondary-color);
  font-size: var(--t-title);
  line-height: 1;
}
.rulecard .rmRule:hover:not(:disabled) { background: var(--er-bad-wash); border: 0; color: var(--er-bad); }

/* ---- the weekday grid ---------------------------------------------------------------------------
 * Each delivery range carries its own weekdays, so each range gets its own row of seven.
 */
.days { display: flex; flex-wrap: wrap; gap: var(--s2) var(--s3); }
.days label { display: inline-flex; align-items: center; gap: var(--s1); margin: 0; font-size: var(--t-micro); font-weight: 400; }

/* ---- motion ----------------------------------------------------------------------------------
 * Nothing animates for longer than a breath, and nothing animates at all for a reader who has
 * asked their system for less of it.
 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

/* ---- narrow screens ------------------------------------------------------------------------------ */

@media (max-width: 62rem) {
  main { padding: var(--s5) var(--s4); }
  .cols { grid-template-columns: minmax(0, 1fr); }
  .colSide { position: static; max-height: none; overflow: visible; }
}
@media (max-width: 56rem) {
  .admin { grid-template-columns: minmax(0, 1fr); gap: var(--s5); }
  .side { position: static; }
}
