/* ============================================================================
   DayFood 2.0 — components. Ported 1:1 in structure from Arena's Editorial Calm
   2.0 (arena-ops app/assets/stylesheets/ec2/components.css); section numbers
   follow that sheet where a component exists there, so the two stay comparable.
   Rules carried over:
   - ONE component per job. Before adding one, reuse one below.
   - Components read SEMANTIC tokens only (--df-ink, --df-accent…), never a ramp
     step and never a literal colour (test/lint/df2_tokens_test.rb).
   - Every primary and phone control is ≥ 48 (--df-touch) on coarse pointers; the rest ≥ 44.
   Markup for the repeated ones comes from Df2UiHelper / Df2FormHelper.
   ============================================================================ */

/* ── 0. base: one focus ring for every interactive element; controls inherit the font ── */
.df2 :is(a, button, summary, [role="button"], [tabindex]:not([tabindex="-1"])):focus-visible {
  outline: 2px solid var(--df-accent);
  outline-offset: 2px;
}
.df2 :where(input, select, textarea, button) { font-family: inherit; }
.df2 :where(.df-ic) { flex: none; }

/* ── 1. buttons — tall pill CTA (56), quiet press. ONE primary per view. ──
     .df-btn            primary: accent fill, white ink
     .df-btn--outline   secondary: white, accent-strong ink, accent stroke
     .df-btn--quiet     tertiary (Back, Cancel): no fill, ink, hover wash
     .df-btn--sm        44 — a secondary inside a sub-form or a compact bar
     .df-btn--block     full width */
.df2 .df-btn {
  box-sizing: border-box;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--df-space-2);
  min-height: var(--df-cta-h); padding: 0 28px;
  border: 1px solid transparent; border-radius: var(--df-radius-pill);
  background: var(--df-accent); color: var(--df-on-accent);
  font-size: var(--df-text-md); font-weight: 600; line-height: 1.2; text-decoration: none; white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--df-dur-2) var(--df-ease-out), border-color var(--df-dur-2) var(--df-ease-out), scale var(--df-dur-2) var(--df-ease-out);
}
@media (hover: hover) { .df2 .df-btn:not(:disabled, [aria-disabled="true"], .df-btn--outline, .df-btn--quiet, .df-btn--danger-quiet):hover { background: var(--df-accent-strong); } }
.df2 .df-btn:active:not(:disabled, [aria-disabled="true"]) { scale: var(--df-press); }
/* disabled reads NEUTRAL, never a faded red; aria-disabled (a busy button that keeps focus) reads the same */
.df2 .df-btn:is(:disabled, [aria-disabled="true"]) { background: var(--df-surface-alt); color: var(--df-muted); border-color: transparent; box-shadow: none; cursor: not-allowed; }
/* the outline button shares the select's and the chip's stroke and differs only in weight */
.df2 .df-btn--outline { background: var(--df-surface); color: var(--df-accent-strong); border-color: transparent; box-shadow: inset 0 0 0 1.5px var(--df-ctl-line); }
@media (hover: hover) { .df2 .df-btn--outline:not(:disabled, [aria-disabled="true"]):hover { background: var(--df-accent-softer); } }
.df2 .df-btn--quiet { min-height: 44px; padding: 0 var(--df-space-3); background: none; color: var(--df-accent-strong); border-radius: var(--df-radius); }
.df2 .df-btn--quiet .df-ic { color: var(--df-muted); }
@media (hover: hover) { .df2 .df-btn--quiet:not(:disabled, [aria-disabled="true"]):hover { background: var(--df-accent-softer); } }
.df2 .df-btn--danger-quiet { min-height: 44px; padding: 0 var(--df-space-3); background: none; color: var(--df-danger); }
@media (hover: hover) { .df2 .df-btn--danger-quiet:not(:disabled, [aria-disabled="true"]):hover { background: var(--df-danger-bg); } }
.df2 .df-btn--sm { min-height: var(--df-cta-h-sm); padding-inline: var(--df-space-5); font-size: var(--df-text-sm); }
.df2 .df-btn--block { display: flex; width: 100%; }
/* a label with a long and a short form ("Add to quote" / "Add"): the short one shows where the card is narrow */
.df2 .df-btn__short { display: none; }

/* ── 2. outline card — THE card skin (white + hairline + soft lift, squircle). Anything tappable;
   a whole-card link is one <a class="df-card">. Sizes: (default) r-card · --df-card-pad ·
   --sm r-card-sm · 20/24 · --flush (the card's parts inset themselves) · --recessed (a card that
   recedes onto the canvas: out of stock, past order — never opacity-dimmed). ── */
.df2 :is(.df-card, .df-empty, .df-formcard) {
  background: var(--df-surface);
  border: 1px solid var(--df-hairline);
  border-radius: var(--df-r-card);
  box-shadow: var(--df-shadow-card);
  transition: border-color var(--df-dur-2) var(--df-ease-out), box-shadow var(--df-dur-2) var(--df-ease-out);
}
.df2 :where(a, label, button).df-card { display: block; color: inherit; text-decoration: none; text-align: inherit; font: inherit; }
.df2 .df-card:not(.df-card--flush) { padding: var(--df-card-pad); }
.df2 .df-card--sm { border-radius: var(--df-r-card-sm); }
.df2 .df-card--sm:not(.df-card--flush) { padding: var(--df-space-5) var(--df-space-6); }
.df2 .df-card--flush { overflow: hidden; }
.df2 .df-card--recessed { background: var(--df-canvas); box-shadow: none; }
@media (max-width: 860px) { .df2 .df-card--sm:not(.df-card--flush) { padding: var(--df-space-5); } }
@media (hover: hover) {
  .df2 :is(a.df-card, label.df-card, button.df-card, .df-card--lift):hover { border-color: var(--df-hairline-strong); box-shadow: var(--df-shadow-card-hover); }
}
.df2 :is(a.df-card, button.df-card, .df-card[tabindex]):focus-visible { outline: none; box-shadow: var(--df-focus-ring); }
/* RADIO card (label.df-card wrapping its own visually-hidden input — a pack size, a delivery slot) */
.df2 label.df-card { cursor: pointer; }
.df2 label.df-card:has(> input:checked) { border-color: var(--df-accent); box-shadow: 0 0 0 1px var(--df-accent), var(--df-shadow-card); }
.df2 label.df-card:has(> input:focus-visible) { box-shadow: var(--df-focus-ring); }
.df2 label.df-card:has(> input:disabled) { cursor: default; background: var(--df-canvas); box-shadow: none; }
@media (hover: hover) {
  .df2 label.df-card:has(> input:disabled):hover { border-color: var(--df-hairline); box-shadow: none; }
  .df2 label.df-card:has(> input:checked):hover { border-color: var(--df-accent); box-shadow: 0 0 0 1px var(--df-accent), var(--df-shadow-card); }
}
/* a card's media well (product photo): flush to the card's top, its own canvas */
.df2 .df-card__media { display: block; aspect-ratio: 1; background: var(--df-surface-alt); }
.df2 .df-card__media > img { width: 100%; height: 100%; object-fit: contain; mix-blend-mode: multiply; }
.df2 .df-card__body { padding: var(--df-space-4) var(--df-space-5) var(--df-space-5); }
/* a stacked body: name, meta and link one under another (the all-categories cards) */
.df2 .df-card__body--stack { display: flex; flex-direction: column; gap: var(--df-space-2); padding: calc((var(--df-space-3) + var(--df-space-4)) / 2) var(--df-space-4) var(--df-space-4); line-height: 1.5; }
.df2 .df-card__body--stack .df-meta { line-height: inherit; }
@media (max-width: 860px) { .df2 .df-card--inset { padding: var(--df-space-4); } }

/* ── 3. tint summary — "your order", recessed: tint, edge, NO shadow ── */
.df2 .df-sum {
  padding: var(--df-card-pad);
  background: color-mix(in srgb, var(--df-accent) 5%, var(--df-surface));
  border: 1px solid rgba(var(--df-accent-rgb), .16);
  border-radius: var(--df-r-card);
}
.df2 .df-sum--sm { padding: var(--df-space-6); border-radius: var(--df-r-card-sm); }
.df2 .df-sum--sticky { position: sticky; top: calc(var(--df-sitebar-h) + var(--df-space-6)); }
/* in one column the summary is the last block, with nothing to stay beside */
@media (max-width: 860px) { .df2 .df-sum--sm { padding: var(--df-space-5); } .df2 .df-sum--sticky { position: static; } }
/* the summary groups: the heading over its lines, the help tucked under the total, and the action
   lifted off the list it acts on */
.df2 .df-sum > .df-key { margin-bottom: var(--df-space-2); }
.df2 .df-sum__total + .df-help { margin-top: var(--df-space-1); }
.df2 .df-sum > :is(.df-btn, .df-actionbar) { margin-top: var(--df-space-5); }
/* a label beside a short value; a long name wraps, including when it is the line's only child */
.df2 .df-sum__line > * { min-width: 0; overflow-wrap: anywhere; }
.df2 .df-sum__line > :last-child:not(:first-child) { flex: none; max-width: 60%; text-align: end; }
.df2 .df-sum__line { display: flex; justify-content: space-between; gap: var(--df-space-4); padding-block: var(--df-space-1); font-size: var(--df-text-sm); color: var(--df-text-2); font-variant-numeric: tabular-nums; }
.df2 .df-sum__rule { height: 1px; margin-block: var(--df-space-4); border: 0; background: rgba(var(--df-accent-rgb), .16); }
.df2 .df-sum__total { display: flex; align-items: baseline; justify-content: space-between; gap: var(--df-space-4); font-size: var(--df-text-md); font-weight: 600; color: var(--df-ink); font-variant-numeric: tabular-nums; }

@supports (corner-shape: squircle) {
  .df2 :is(.df-card, .df-sum, .df-empty, .df-formcard, .df-note) { corner-shape: squircle; }
}

/* ── 4. column + section rhythm — 1240 / 32 → 1176 content; 64 / 40 between sections ── */
.df2 .df-col { box-sizing: border-box; width: 100%; max-width: var(--df-col); margin-inline: auto; padding-inline: var(--df-col-inset); }
.df2 .df-sec + .df-sec { margin-top: var(--df-gap); }
/* a listing page's first section sits a full gap under the page head */
.df2 .df-col--listing > .df-phead + .df-sec { margin-top: var(--df-gap); }
/* except a category page's sibling tabs: they are the head's second line, not a section, so they
   sit at the head's own 24 below it and the full gap stays under them, before the results */
.df2 .df-col--listing > .df-phead + .df-sec:has(> .df-tabsbar) { margin-top: 0; }
.df2 .df-sechead { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--df-space-4); margin: 0 0 var(--df-head); }
.df2 .df-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr)); gap: var(--df-grid); }
/* main column + summary rail; the rail drops under the main column on phones */
.df2 .df-split { display: grid; grid-template-columns: minmax(0, 1fr) var(--df-rail-w); gap: var(--df-space-10); align-items: start; }
@media (max-width: 860px) { .df2 .df-split { grid-template-columns: minmax(0, 1fr); gap: var(--df-space-6); } }
.df2 .df-stack { display: flex; flex-direction: column; gap: var(--df-space-6); }

/* ── 5. site bar — ONE bar on every desktop screen: canvas, hairline foot, sticky, content on the
   1176 column. Phones on a flow screen use the flow header (§19) instead. ── */
.df2 .df-sitebar {
  position: sticky; top: 0; z-index: 40;
  box-sizing: border-box; height: var(--df-sitebar-h);
  display: flex; align-items: center; justify-content: space-between; gap: var(--df-space-6);
  padding-inline: max(var(--df-col-inset), calc((100% - var(--df-content)) / 2));
  background: var(--df-glass); border-bottom: 1px solid var(--df-hairline);
  -webkit-backdrop-filter: saturate(1.4) blur(12px); backdrop-filter: saturate(1.4) blur(12px);
}
/* the inner row: the logo, the search and the nav on the content column (.df-col supplies the inset) */
.df2 .df-sitebar:has(> .df-sitebar__in) { padding-inline: 0; }
.df2 .df-sitebar__in { display: flex; align-items: center; gap: 28px; height: 100%; }
.df2 .df-sitebar__nav { display: flex; align-items: center; gap: 6px; }
.df2 .df-sitebar__in .df-sitebar__nav { margin-inline-start: auto; }
.df2 .df-sitebar__nav a { display: inline-flex; align-items: center; gap: var(--df-space-2); min-height: 44px; padding: 0 14px; border-radius: var(--df-radius-pill); font-size: 15px; font-weight: 600; color: var(--df-accent-strong); text-decoration: none; }
.df2 .df-sitebar__nav a[aria-current="page"] { color: var(--df-accent-strong); background: var(--df-accent-soft); }
@media (hover: hover) { .df2 .df-sitebar__nav a:hover { background: var(--df-accent-softer); color: var(--df-accent-strong); } .df2 .df-sitebar__nav a[aria-current="page"]:hover { background: var(--df-accent-soft); } }
@media (max-width: 860px) { .df2 .df-sitebar__nav a:not(.df-sitebar__quote, .df-sitebar__back) { display: none; } }
/* the BRAND LOCKUP — rendered only by Df2UiHelper#df_brand: brand-red mark · "DayFood" 18/700 · "· sub" muted */
.df2 .df-brand {
  display: inline-flex; align-items: center; gap: var(--df-space-2); min-height: 44px;
  color: var(--df-ink); text-decoration: none; white-space: nowrap;
  font-size: var(--df-text-lg); font-weight: 700; line-height: 1.2; letter-spacing: -.01em;
}
.df2 .df-brand__mark {
  display: inline-grid; place-items: center; flex: none; width: 28px; height: 28px;
  border-radius: var(--df-radius); background: var(--df-brand); color: var(--df-on-accent);
  font-size: var(--df-text-xs); font-weight: 800; letter-spacing: -.02em;
}
.df2 .df-brand__sub { font-weight: 600; color: var(--df-muted); }

/* ── 6. chip + chip bar — a filter toggle (category, brand, "In stock"). A chip is a real
   <button aria-pressed> or a link with aria-current; picked = accent tint + accent-strong ink.
   The bar scrolls sideways on phones, never wraps into a wall. ── */
.df2 .df-chipbar { display: flex; flex-wrap: wrap; gap: var(--df-space-2); }
.df2 .df-sec > .df-chipbar { margin-bottom: var(--df-space-4); }
@media (max-width: 860px) {
  .df2 .df-chipbar { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; margin-inline: calc(-1 * var(--df-col-inset)); padding-inline: var(--df-col-inset); }
}
.df2 .df-chip {
  display: inline-flex; align-items: center; gap: var(--df-space-2); flex: none;
  min-height: 44px; padding: 0 var(--df-space-4);
  border: 1px solid var(--df-ctl-line); border-radius: var(--df-radius-pill); background: var(--df-surface);
  font-size: var(--df-text-sm); font-weight: 600; color: var(--df-accent-strong); text-decoration: none; white-space: nowrap; cursor: pointer;
  transition: background-color var(--df-dur-1) var(--df-ease-out), border-color var(--df-dur-1) var(--df-ease-out);
}
@media (pointer: coarse) { .df2 .df-chip { min-height: var(--df-touch); } }
@media (hover: hover) { .df2 .df-chip:hover { border-color: var(--df-accent-strong); background: var(--df-accent-softer); } }
.df2 .df-chip:is([aria-pressed="true"], [aria-current="page"], [aria-current="true"]) {
  background: var(--df-accent); border-color: var(--df-accent); color: var(--df-on-accent); font-weight: 600;
}
.df2 .df-chip__n { font-weight: 500; color: var(--df-muted); font-variant-numeric: tabular-nums; }
.df2 .df-chip:is([aria-pressed="true"], [aria-current="page"], [aria-current="true"]) .df-chip__n { color: var(--df-on-accent); }

/* ── 9. step trail (DESKTOP) — quiet typographic trail; the current step carries the accent
   rule. Phones use the flow header (§19) — never both. Done steps carry a visually hidden
   ", done" (the check icon is decorative). ── */
.df2 .df-trail { display: none; }
@media (min-width: 861px) {
  .df2 .df-trail {
    display: flex; flex-wrap: wrap; gap: 0 var(--df-space-4); margin: 0; padding: 0; list-style: none;
    border-bottom: 1px solid var(--df-hairline); font-size: var(--df-text-sm); line-height: 1.4;
  }
  .df2 .df-trail__step { position: relative; display: flex; align-items: center; gap: var(--df-space-2); padding: var(--df-space-2) 0 var(--df-space-3); color: var(--df-muted); }
  .df2 .df-trail__step + .df-trail__step::before { content: "\00B7"; position: absolute; left: calc(var(--df-space-4) / -2); translate: -50% 0; color: var(--df-muted); }
  .df2 .df-trail__step > a { display: inline-flex; align-items: center; gap: var(--df-space-2); color: inherit; text-decoration: none; }
  @media (hover: hover) { .df2 .df-trail__step > a:hover { color: var(--df-accent-strong); text-decoration: underline; text-underline-offset: 3px; } }
  .df2 .df-trail__step .df-ic { color: var(--df-muted); }
  .df2 .df-trail__step--done { font-weight: 500; }
  .df2 .df-trail__step--done .df-trail__ok { color: var(--df-ok); }
  .df2 .df-trail__step[aria-current="step"] { color: var(--df-ink); font-weight: 500; box-shadow: inset 0 -2px 0 var(--df-accent); margin-bottom: -1px; padding-bottom: calc(var(--df-space-3) + 1px); }
  .df2 .df-trail__step[aria-current="step"] .df-ic { color: var(--df-accent); }
}

/* ── 9b. in-page actions — a short single-card form with no footer bar: one centred row,
   the quiet secondary first, the primary hugging its label ── */
.df2 .df-pageacts { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--df-space-4) var(--df-space-6); margin-top: var(--df-space-6); }

/* ── 10. footer action bar — THE one footer-action component on a form / flow screen.
     .df-actionbar          desktop: sticky on the viewport bottom inside its column (white,
                            hairline top, bar shadow): note/summary LEFT, actions RIGHT.
                            phones: docked FIXED full-bleed — row 1 summary + secondary,
                            row 2 one full-width primary; its parent reserves the space.
     --rail                 desktop: untouched (the CTA lives in a summary rail); phones: the dock.
     --deferred             hidden until a radio in its form is picked (CSS :has, no JS).
   Parts: __sum · __note · __sec (secondary text link) · __primary ── */
.df2 .df-actionbar:not(.df-actionbar--rail) {
  position: sticky; bottom: 0; z-index: 45;
  box-sizing: border-box; min-height: var(--df-bar-h); margin-top: var(--df-space-10);
  padding: var(--df-space-4) 0 calc(var(--df-space-4) + env(safe-area-inset-bottom, 0px));
  display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--df-space-4) var(--df-space-6);
  /* the surface (a 15px soft shadow, the hairline, then white) bleeds to the viewport edges as
     border-image ink overflow — no horizontal scroll, and the bar's BOX stays on its column */
  background: none; border: 0; box-shadow: none;
  border-image: linear-gradient(to bottom, transparent, color-mix(in srgb, var(--df-ink) 6%, transparent) 15px, var(--df-hairline) 15px 16px, var(--df-surface) 16px) fill 0 / / 15px 100vw 0;
}
.df2 .df-actionbar:not(.df-actionbar--rail) > :is(.df-actionbar__sum, .df-actionbar__note) { flex: 1 1 0; min-width: 0; margin: 0; }
.df2 .df-actionbar__sum { font-size: var(--df-text-md); font-weight: 600; color: var(--df-ink); font-variant-numeric: tabular-nums; }
.df2 .df-actionbar__sum .df-key { display: block; margin-bottom: 2px; }
.df2 .df-actionbar__note { font-size: var(--df-text-sm); color: var(--df-muted); }
.df2 :is(a, button).df-actionbar__sec {
  display: inline-flex; align-items: center; gap: var(--df-space-2); min-height: 44px; padding: 0; border: 0; background: none; cursor: pointer;
  font-size: var(--df-text-sm); font-weight: 600; color: var(--df-accent-strong); text-decoration: none;
}
@media (hover: hover) { .df2 :is(a, button).df-actionbar__sec:hover { color: var(--df-ink); } }
.df2 .df-actionbar--deferred:where(form:not(:has(input[type="radio"]:checked)) *) { opacity: 0; visibility: hidden; translate: 0 100%; }
.df2 .df-actionbar--deferred { transition: translate var(--df-dur-3) var(--df-ease-out), opacity var(--df-dur-3) var(--df-ease-out), visibility 0s linear var(--df-dur-3); }

@media (max-width: 860px) {
  .df2 .df-actionbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
    box-sizing: border-box; min-height: 0; margin: 0;
    display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: var(--df-space-3) var(--df-space-3);
    padding: var(--df-space-2) var(--df-space-4) max(env(safe-area-inset-bottom, 0px), var(--df-space-3));
    background: var(--df-surface); border: 0; border-top: 1px solid var(--df-hairline); border-radius: 0; border-image: none;
    box-shadow: var(--df-shadow-bar);
  }
  .df2 .df-actionbar > :is(.df-actionbar__sum, .df-actionbar__note) { grid-row: 1; grid-column: 1; min-width: 0; padding-top: var(--df-space-2); font-size: var(--df-text-sm); }
  .df2 .df-actionbar:not(:has(.df-actionbar__sec)) > :is(.df-actionbar__sum, .df-actionbar__note) { grid-column: 1 / -1; }
  .df2 .df-actionbar .df-actionbar__sec { grid-row: 1; grid-column: 2; justify-self: end; }
  .df2 .df-actionbar .df-actionbar__primary { grid-column: 1 / -1; width: 100%; }
  .df2 .df-actionbar .df-amount { font-size: var(--df-text-xl); }
  /* the last content must scroll clear of the dock. The bar's parent reserves it (::after) —
     except a --rail bar, whose parent is the summary card: a spacer there is an empty tinted
     block, so a --rail page reserves at the body instead */
  .df2 :has(> .df-actionbar:not(.df-actionbar--rail))::after { content: ""; display: block; height: calc(var(--df-dock-h) - var(--df-space-3) + max(env(safe-area-inset-bottom, 0px), var(--df-space-3))); }
  .df2 :has(> .df-actionbar:not(.df-actionbar--rail, :has(.df-actionbar__sum, .df-actionbar__note, .df-actionbar__sec)))::after { height: calc(var(--df-dock-h-1) - var(--df-space-3) + max(env(safe-area-inset-bottom, 0px), var(--df-space-3))); }
  .df2 body:has(.df-actionbar--rail:not([hidden] *)) { padding-bottom: calc(var(--df-dock-h) - var(--df-space-3) + max(env(safe-area-inset-bottom, 0px), var(--df-space-3))); }
}

/* ── 12. success head — centred badge (56 / 48) + display h1 + muted lede. Static: no pop. ── */
.df2 .df-success { display: flex; flex-direction: column; align-items: center; max-width: 600px; margin: 0 auto var(--df-head); text-align: center; }
.df2 .df-success .df-lede { margin-inline: auto; }
.df2 .df-badge {
  display: inline-grid; place-items: center; flex: none; width: 72px; height: 72px; margin: 0 0 var(--df-space-6);
  border-radius: 50%; background: var(--df-ok); color: var(--df-on-accent);
}
.df2 .df-badge .df-ic { width: 24px; height: 24px; stroke-width: 2.25; }
.df2 .df-badge--sm { width: 24px; height: 24px; margin: 0; box-shadow: none; }
.df2 .df-badge--sm .df-ic { width: 14px; height: 14px; }
.df2 .df-success--compact { margin-bottom: var(--df-space-6); }
.df2 .df-success--compact .df-badge { margin-bottom: var(--df-space-5); }
.df2 .df-success--compact .df-lede { margin-top: var(--df-space-2); }

/* ── 13. empty state — one outline card: icon well + title + muted line + actions ── */
.df2 .df-empty { display: flex; flex-direction: column; align-items: center; gap: var(--df-space-3); max-width: 560px; margin-inline: auto; padding: var(--df-space-10) var(--df-space-6); text-align: center; }
.df2 .df-empty__ic { display: inline-grid; place-items: center; width: 72px; height: 72px; margin-bottom: var(--df-space-1); border-radius: var(--df-r-card); background: var(--df-accent-soft); color: var(--df-accent-strong); }
.df2 .df-empty__t { font-size: var(--df-text-lg); font-weight: 700; letter-spacing: -.01em; color: var(--df-ink); }
.df2 .df-empty__p { max-width: 46ch; font-size: var(--df-text-md); line-height: 1.55; color: var(--df-text-2); }
.df2 .df-empty__act { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--df-space-3); margin-top: var(--df-space-3); }
@media (max-width: 860px) { .df2 .df-empty__act { width: 100%; flex-direction: column; } }

/* ── 16. touch hit-area — text links keep their visual size but get a ≥ 44 target on coarse
   pointers. Opt any other inline control in with .df-hit. ── */
@media (pointer: coarse) {
  .df2 :is(.df-link, .df-hit, .df-trail a, .df-sechead a) { position: relative; }
  .df2 :is(.df-link, .df-hit, .df-trail a, .df-sechead a)::after { content: ""; position: absolute; left: 50%; top: 50%; width: max(100%, 44px); height: max(100%, 44px); translate: -50% -50%; }
}

/* ── 17. form card — THE data-entry surface. The CARD carries no inline padding; its head and
   each field row do, so the hairlines between rows run to the same inset. A field row is a
   <label> (the whole row is the tap target): small key label over a borderless 16/600 value.
   Focus lights the row (accent-softer fill + a 3px accent bar) instead of boxing the input. ── */
.df2 .df-formcard { border-radius: var(--df-r-card-sm); padding: 0 0 var(--df-space-2); font-size: var(--df-text-md); color: var(--df-ink); overflow: clip; }
.df2 .df-formcard__head { display: flex; flex-direction: column; align-items: flex-start; gap: var(--df-space-1); padding: var(--df-space-6) var(--df-fc-x) var(--df-space-1); }
.df2 .df-formcard__title { font-size: var(--df-text-lg); font-weight: 700; letter-spacing: -.01em; color: var(--df-ink); }
.df2 .df-formcard__hint { font-size: var(--df-text-sm); line-height: 1.5; color: var(--df-muted); }
/* a headless card: its first row clears the corner */
.df2 .df-formcard:not(:has(> .df-formcard__head)) { padding-top: var(--df-space-2); }
.df2 .df-field { position: relative; display: block; padding: var(--df-fc-y) var(--df-fc-x); }
.df2 .df-formcard > :is(.df-field, .df-field-row) + :is(.df-field, .df-field-row)::before {
  content: ""; position: absolute; top: 0; left: var(--df-fc-x); right: var(--df-fc-x); height: 1px; background: var(--df-hairline);
}
.df2 .df-field__label { display: flex; align-items: center; gap: var(--df-space-2); font-size: var(--df-key-size); font-weight: 600; color: var(--df-muted); }
.df2 .df-field__opt { font-weight: 500; color: var(--df-muted); }
.df2 .df-field__help { font-size: var(--df-key-size); color: var(--df-muted); }
/* required marker — auto-applied to a row whose control is [required] (no per-field markup) */
.df2 .df-field:has(:is(input, select, textarea):required) .df-field__label::after { content: "*"; margin-left: -4px; color: var(--df-danger); font-weight: 700; }
.df2 .df-field :is(input:not([type="radio"], [type="checkbox"]), select, textarea) {
  display: block; box-sizing: border-box; width: 100%; margin: 0; padding: var(--df-space-1) 0 0;
  border: 0; outline: none; background: none; appearance: none;
  font-size: var(--df-text-md); font-weight: 600; color: var(--df-ink);
}
.df2 .df-field textarea { resize: vertical; min-height: 3lh; line-height: 1.5; }
.df2 .df-field :is(input, textarea)::placeholder { color: var(--df-muted); font-weight: 400; opacity: 1; }
.df2 .df-field select { cursor: pointer; }
.df2 .df-field:focus-within { background: var(--df-accent-softer); }
.df2 .df-field:focus-within::after { content: ""; position: absolute; left: 0; top: 8px; bottom: 8px; width: 3px; border-radius: 0 3px 3px 0; background: var(--df-accent); }
.df2 .df-field:focus-within .df-field__label { color: var(--df-accent-strong); }
.df2 .df-field-row { position: relative; display: flex; }
.df2 .df-field-row > .df-field { flex: 1 1 0; min-width: 0; }
.df2 .df-field-row > .df-field + .df-field { border-left: 1px solid var(--df-hairline); }
@media (max-width: 560px) {
  .df2 .df-field-row { flex-direction: column; }
  .df2 .df-field-row > .df-field + .df-field { border-left: 0; }
  .df2 .df-field-row > .df-field + .df-field::before { content: ""; position: absolute; top: 0; left: var(--df-fc-x); right: var(--df-fc-x); height: 1px; background: var(--df-hairline); }
}
@media (max-width: 860px) {
  .df2 .df-formcard__head { padding-top: var(--df-space-5); }
  .df2 .df-formcard__title { font-size: var(--df-text-md); }
}
/* the card's foot: its own actions (Add more, Clear) on the text rail; the destructive one at the far end */
.df2 .df-formcard__foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--df-space-4); padding: var(--df-space-4) var(--df-fc-x); border-top: 1px solid var(--df-hairline); }
.df2 .df-formcard__foot > .df-btn--danger-quiet { margin-inline-start: auto; }
/* an invalid field: the card takes the danger edge, the error note sits in the card */
.df2 .df-formcard:has([aria-invalid="true"]) { border-color: var(--df-danger); }
.df2 .df-field > .df-note[role="alert"]:only-child { margin-top: 0; }
/* segmented control — 2–4 mutually exclusive options inside a field (Delivery / Pickup) */
.df2 .df-seg { display: flex; margin-top: var(--df-space-2); padding: var(--df-space-1); border-radius: var(--df-radius-pill); background: var(--df-surface-alt); }
.df2 .df-seg > :is(button, label) {
  flex: 1 1 0; display: grid; place-items: center; height: 40px; border: 0; border-radius: var(--df-radius-pill); background: none; cursor: pointer;
  font-size: var(--df-text-sm); font-weight: 600; color: var(--df-accent-strong);
}
@media (pointer: coarse) { .df2 .df-seg > :is(button, label) { height: var(--df-touch); } }
.df2 .df-seg > :is(button[aria-pressed="true"], label:has(> input:checked)) { background: var(--df-accent); color: var(--df-on-accent); box-shadow: none; }
.df2 .df-seg > label:has(> input:focus-visible) { outline: 2px solid var(--df-accent); outline-offset: 2px; }
.df2 .df-field:focus-within .df-seg { background: var(--df-hairline); }

/* ── 18. phone tab bar — ONE full-width bar docked on the viewport foot (phones only): a hairline
   top edge, an equal-width grid of tabs (22 icon over a 12/600 label), the current tab in the
   accent with a bar on its top edge. A screen that docks a footer action bar hides it. ── */
.df2 .df-tabbar { display: none; }
@media (max-width: 860px) {
  .df2 .df-tabbar {
    position: fixed; z-index: 44; left: 0; right: 0; bottom: 0;
    box-sizing: border-box; display: flex; min-height: var(--df-tabbar-h); margin: 0;
    padding: 0 0 env(safe-area-inset-bottom, 0px);
    border: 0; border-top: 1px solid var(--df-hairline); border-radius: 0;
    background: var(--df-surface);
  }
  .df2 .df-tabbar__item {
    position: relative; flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    min-height: 60px; font-size: var(--df-text-xs); font-weight: 600; line-height: 1.2; color: var(--df-muted); text-decoration: none;
    transition: color var(--df-dur-1) var(--df-ease-out);
  }
  .df2 .df-tabbar__item .df-ic { width: 22px; height: 22px; }
  .df2 .df-tabbar__item[aria-current="page"] { color: var(--df-accent-strong); }
  .df2 .df-tabbar__item[aria-current="page"]::before { content: ""; position: absolute; top: 0; left: 30%; right: 30%; height: 3px; border-radius: 0 0 3px 3px; background: var(--df-accent); }
  .df2 .df-tabbar__ic { position: relative; display: inline-flex; }
  /* a count on a tab (cart): a small brand-red pill on the icon's corner */
  .df2 .df-tabbar__ic .df-tabbar__n { top: -6px; left: 14px; }
  .df2 .df-tabbar__n { position: absolute; top: 4px; left: calc(50% + 4px); min-width: 18px; height: 18px; padding: 0 5px; box-sizing: border-box; border-radius: var(--df-radius-pill); background: var(--df-accent); color: var(--df-on-accent); font-size: var(--df-text-2xs); font-weight: 700; line-height: 18px; text-align: center; font-variant-numeric: tabular-nums; }
  /* a bar inside a [hidden] block (an empty quote's summary) does not count: that screen keeps its tab bar */
  .df2 body:has(.df-actionbar:not(.df-actionbar--deferred, [hidden] *)) .df-tabbar { display: none; }
  /* content scrolls clear of the floating bar */
  .df2 body:has(> .df-tabbar) { padding-bottom: calc(var(--df-tabbar-clear) + env(safe-area-inset-bottom, 0px)); }
  /* ...but a docked rail bar replaces the tab bar, so the page clears the dock, not the tab bar */
  .df2 body:has(> .df-tabbar):has(.df-actionbar--rail:not([hidden] *)) { padding-bottom: calc(var(--df-dock-h) - var(--df-space-3) + max(env(safe-area-inset-bottom, 0px), var(--df-space-3))); }
}

/* ── 19. phone flow header + meter — ONE header for every phone flow screen (checkout, quote):
   on the canvas, 56 tall; back chevron (44; 48 on touch) + "Step 2 of 3 · Delivery" + a 2- or 3-seg meter. The
   display h1 below is the page title. Desktop keeps the trail (§9). ── */
.df2 .df-meter { display: flex; gap: 4px; width: 100%; max-width: 120px; }
.df2 .df-meter__seg { flex: 1 1 0; height: 4px; border-radius: 2px; background: var(--df-hairline); }
.df2 .df-meter__seg:is(.is-done, .is-current) { background: var(--df-accent); }
.df2 .df-flowhead { display: none; }
@media (max-width: 860px) {
  .df2 .df-flowhead {
    position: sticky; top: 0; z-index: 40; box-sizing: border-box;
    display: flex; align-items: center; gap: var(--df-space-2); height: var(--df-flowhead-h); padding: 0 var(--df-col-inset);
    background: var(--df-canvas); border-bottom: 1px solid var(--df-hairline);
  }
  .df2 .df-flowhead__back { flex: none; display: inline-grid; place-items: center; width: 44px; height: 44px; margin-left: calc(-1 * var(--df-space-3)); border-radius: 50%; color: var(--df-ink); }
  .df2 .df-flowhead__x { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
  .df2 body:has(.df-flowhead) .df-sitebar { display: none; }   /* a flow screen: the flow header IS the bar */
  .df2 .df-flowhead__label { overflow: hidden; font-size: var(--df-text-sm); font-weight: 600; line-height: 20px; color: var(--df-muted); white-space: nowrap; text-overflow: ellipsis; }
}
@media (pointer: coarse) { .df2 .df-flowhead__back { width: var(--df-touch); height: var(--df-touch); } }

/* ── 20. round icon button + quantity stepper. The round button is ONE circular control (44;
   --sm 36 on fine pointers; 48 on touch); --danger = a destructive icon action (remove
   a line) — no ring, danger ink, danger tint on hover. The stepper is − figure + in a row. ── */
.df2 .df-roundbtn {
  display: grid; place-items: center; flex: none; width: var(--df-round-btn); height: var(--df-round-btn); padding: 0; cursor: pointer;
  border: 1px solid var(--df-ctl-line); border-radius: 50%; background: var(--df-surface); color: var(--df-accent-strong);
  transition: background-color var(--df-dur-1) var(--df-ease-out), border-color var(--df-dur-2) var(--df-ease-out), color var(--df-dur-2) var(--df-ease-out), scale var(--df-dur-0) var(--df-ease-out);
}
.df2 .df-roundbtn .df-ic { width: 18px; height: 18px; }
@media (hover: hover) { .df2 .df-roundbtn:not(:disabled):hover { border-color: var(--df-accent-strong); background: var(--df-accent-softer); color: var(--df-accent-strong); } }
.df2 .df-roundbtn:active:not(:disabled) { scale: var(--df-press-step); }
.df2 .df-roundbtn:disabled { color: var(--df-hairline-hover); border-color: var(--df-hairline); background: var(--df-surface); cursor: not-allowed; }
@media (pointer: fine) { .df2 .df-roundbtn--sm { width: 36px; height: 36px; } }
@media (pointer: coarse) { .df2 :is(.df-roundbtn, .df-roundbtn--sm) { width: var(--df-touch); height: var(--df-touch); } }
.df2 .df-roundbtn--danger { background: none; border-color: transparent; color: var(--df-danger); }
@media (hover: hover) { .df2 .df-roundbtn--danger:not(:disabled):hover { border-color: transparent; background: var(--df-danger-bg); color: var(--df-danger); } }
.df2 .df-stepper { display: inline-flex; align-items: center; gap: var(--df-space-1); }
.df2 .df-stepper__v { min-width: 36px; text-align: center; font-size: var(--df-text-md); font-weight: 700; }
.df2 .df-stepper__v:is(input) { width: 4ch; padding: 0; border: 0; background: none; appearance: textfield; -moz-appearance: textfield; }
.df2 .df-stepper__v::-webkit-inner-spin-button { appearance: none; }
/* --fill: the stepper stretched across a card, − and + at the ends in a tinted pill */
.df2 .df-stepper--fill { display: flex; justify-content: space-between; width: 100%; padding: var(--df-space-1); border-radius: var(--df-radius-pill); background: var(--df-accent-softer); box-shadow: inset 0 0 0 1px rgba(var(--df-accent-strong-rgb), .25); }
.df2 .df-stepper--fill .df-roundbtn { border-color: transparent; background: var(--df-surface); }
@media (hover: hover) { .df2 .df-stepper--fill .df-roundbtn:not(:disabled):hover { background: var(--df-accent); color: var(--df-on-accent); } }

/* ── 21. pill — ONE status/meta pill. Tones: (accent) · --ok in stock / confirmed · --warn low
   stock / attention · --neutral pending · --muted out of stock / cancelled. The dot is 8. ── */
.df2 .df-pill {
  display: inline-flex; align-items: center; gap: var(--df-space-1);
  min-height: 26px; padding: 0 10px; border: 0; border-radius: var(--df-radius-pill); width: fit-content;
  background: var(--df-accent-soft); color: var(--df-accent-strong);
  font-size: var(--df-text-xs); font-weight: 600; line-height: 1.3; white-space: nowrap; font-variant-numeric: tabular-nums;
}
.df2 .df-pill--ok { background: var(--df-ok-bg); color: var(--df-ok); }
.df2 .df-pill--warn { background: var(--df-warn-bg); color: var(--df-warn); }
.df2 .df-pill--neutral { background: var(--df-surface-alt); color: var(--df-text-2); box-shadow: inset 0 0 0 1px var(--df-hairline); }
.df2 .df-pill--muted { background: var(--df-surface-alt); color: var(--df-muted); }
.df2 .df-pills { display: flex; flex-wrap: wrap; gap: 6px; }
.df2 .df-dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: currentColor; }

/* ── 22. "go" affordance — the quiet accent "View →" line INSIDE a tappable card (a span; the
   card is the target) ── */
.df2 .df-go { display: inline-flex; align-items: center; gap: var(--df-space-2); font-size: 15px; font-weight: 600; color: var(--df-accent-strong); }
.df2 .df-go .df-ic { width: 16px; height: 16px; transition: translate var(--df-dur-2) var(--df-ease-out); }
@media (hover: hover) { .df2 :is(a, label):hover .df-go .df-ic { translate: 3px 0; } }

/* ── 24. note / callout — compact radius, 20 inset, 14 type, its icon first. Tones: (neutral) ·
   --accent · --ok · --warn · --danger (errors: always with role="alert" + its icon) ── */
.df2 .df-note {
  display: flex; align-items: flex-start; gap: 10px; margin-top: var(--df-space-5); padding: 14px var(--df-space-4);
  border: 0; border-radius: 12px; background: var(--df-surface-alt);
  font-size: var(--df-text-sm); line-height: 1.45; color: var(--df-text-2);
}
.df2 .df-note .df-ic { width: 18px; height: 18px; margin-top: 1px; }
.df2 .df-note :is(b, strong) { font-weight: 700; color: var(--df-ink); }
/* tones: the tint carries the hue, the text stays ink and the icon takes the tone (an error always has its icon) */
.df2 .df-note--accent { background: var(--df-accent-softer); color: var(--df-ink); }
.df2 .df-note--accent .df-ic { color: var(--df-accent-strong); }
.df2 .df-note--ok { background: var(--df-ok-bg); color: var(--df-ink); }
.df2 .df-note--ok .df-ic { color: var(--df-ok); }
.df2 .df-note--warn { background: var(--df-warn-bg); color: var(--df-ink); }
.df2 .df-note--warn .df-ic { color: var(--df-warn); }
.df2 .df-note--danger { background: var(--df-danger-bg); color: var(--df-ink); box-shadow: inset 0 0 0 1px rgba(var(--df-danger-rgb), .25); }
.df2 .df-note--danger .df-ic { color: var(--df-danger); }

/* ── 33. text link — THE text action (Edit, Change, See all): 14/600 accent-strong, no underline.
   --inline: a link inside running text takes the sentence's size and IS underlined (never
   colour alone, WCAG 1.4.1). ── */
.df2 .df-link { font-size: 15px; font-weight: 600; color: var(--df-accent-strong); text-decoration: none; text-underline-offset: 3px; }
.df2 .df-link--inline { font-size: inherit; text-decoration: underline; }
.df2 :where(button).df-link { padding: 0; border: 0; background: none; cursor: pointer; }
@media (hover: hover) { .df2 .df-link:hover { text-decoration: underline; } }
.df2 .df-foot { margin: var(--df-space-4) 0 0; text-align: center; }

/* ── 34. four-up card grid — the catalogue listing: 4 across, 2 on a tablet, and (below) 2 compact on a
   phone and 1 under 360. Equal rows, so the cards' feet line up across a row. ── */
.df2 .df-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); grid-auto-rows: 1fr; }
@media (max-width: 860px) { .df2 .df-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--df-space-3); } }

/* ── 35. breadcrumb — a quiet trail above a page head; the last crumb is the page. Phones drop
   it (the flow head and the browser carry "back"). ── */
.df2 .df-crumbs { margin-bottom: var(--df-space-4); font-size: var(--df-text-sm); line-height: 1.5; color: var(--df-muted); }
.df2 .df-col > .df-crumbs:first-child { margin-top: var(--df-space-6); }
.df2 .df-crumbs + .df-phead { margin-top: var(--df-space-5); }
.df2 .df-crumbs li + li::before { content: "/" / ""; }
.df2 .df-crumbs ol { display: flex; flex-wrap: wrap; align-items: center; gap: var(--df-space-1) var(--df-space-2); margin: 0; padding: 0; list-style: none; }
.df2 .df-crumbs li { display: inline-flex; align-items: center; gap: var(--df-space-2); min-width: 0; }
.df2 .df-crumbs a { color: var(--df-text-2); text-decoration: none; }
@media (hover: hover) { .df2 .df-crumbs a:hover { text-decoration: underline; text-underline-offset: 3px; } }
.df2 .df-crumbs [aria-current="page"] { color: var(--df-ink); font-weight: 600; }

/* ── 38. quote count — the number of lines in the quote, written by quote-count. [hidden] at zero
   (display must not override it).
   The base sets nothing the tab variant owns (position, line-height). --pill is accent-tinted, for a nav link.
   The tab-bar variant (df-tabbar__n) is styled with the tab bar. ── */
.df2 .df-qcount { font-variant-numeric: tabular-nums; }
.df2 .df-qcount[hidden] { display: none; }
.df2 .df-qcount--pill { display: inline-flex; align-items: center; justify-content: center; box-sizing: border-box; min-width: var(--df-space-5); height: var(--df-space-5); padding-inline: var(--df-space-2); border-radius: var(--df-radius-pill); font-size: var(--df-text-xs); font-weight: 700; line-height: 1; }
.df2 .df-qcount--pill { background: var(--df-accent-soft); color: var(--df-accent-strong); }

/* a text-entry control has focus on a phone: the on-screen keyboard owns the bottom edge, so the
   docks step aside (keyboard-dock sets the attribute on <html>) */
@media (max-width: 860px) { .df2[data-keyboard-open] :is(.df-actionbar, .df-tabbar) { display: none; } }

/* ── 39. site search — ONE search field for the site bar: a quiet pill, the magnifier at its start,
   Enter submits. The field turns white with an accent edge on focus. 48 (--df-touch) tall. ── */
.df2 .df-search {
  display: flex; align-items: center; flex: 1 1 auto; gap: var(--df-space-3); min-width: 0; max-width: 560px;
  box-sizing: border-box; min-height: var(--df-touch); padding: 0 var(--df-space-5);
  border: 1px solid transparent; border-radius: var(--df-radius-pill); background: var(--df-surface-alt);
  transition: background-color var(--df-dur-1) var(--df-ease-out), border-color var(--df-dur-1) var(--df-ease-out);
}
.df2 .df-search:focus-within { background: var(--df-surface); border-color: var(--df-accent); box-shadow: var(--df-focus-ring); }
.df2 .df-search input[type="search"] {
  flex: 1 1 auto; min-width: 0; margin: 0; padding: 0; border: 0; outline: 0; background: transparent;
  color: var(--df-ink); font-size: var(--df-text-md); line-height: 1.2; -webkit-appearance: none; appearance: none;
}
.df2 .df-search input[type="search"]::placeholder { color: var(--df-muted); opacity: 1; }
.df2 .df-search input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; }
.df2 .df-search .df-ic { color: var(--df-muted); }

/* ── 40. storefront top chrome — the logo link, the site bar's row and the skip link.
     .df-logo              the logo image as a link (44 tall target)
     .df-sitebar__in       §5's inner row on the store: logo, search, nav. On a phone the nav is gone
                           (the tab bar carries it) and the search wraps to its own full-width row.
     .df-skip              "skip to content": off-screen until it takes focus ── */
.df2 .df-logo { display: inline-flex; align-items: center; flex: none; min-height: 44px; }
.df2 .df-logo img { display: block; width: auto; height: 34px; }
@media (hover: hover) { .df2 .df-sitebar .df-logo:hover { opacity: .85; } }
.df2 .df-sitebar__nav a { white-space: nowrap; }
@media (max-width: 860px) {
  .df2 .df-sitebar { height: auto; }
  .df2 .df-sitebar__in { flex-wrap: wrap; gap: var(--df-space-3); padding-block: var(--df-space-3); }
  .df2 .df-sitebar__in .df-logo img { height: 28px; }
  .df2 .df-sitebar__in .df-search { order: 3; flex-basis: 100%; max-width: none; }
  /* a reading page (body.df-quietbar): no search row, and the bar scrolls away; the tab bar
     carries Catalogue, Categories and the quote count, so nothing is lost */
  .df2 .df-quietbar .df-search { display: none; }
  .df2 .df-quietbar .df-sitebar { position: static; }
}
.df2 .df-skip {
  position: absolute; left: var(--df-space-4); top: 0; z-index: 60;
  display: inline-flex; align-items: center; min-height: var(--df-touch); padding: 0 var(--df-space-5);
  border-radius: var(--df-radius-pill); background: var(--df-accent); color: var(--df-on-accent);
  font-size: var(--df-text-sm); font-weight: 600; text-decoration: none;
  translate: 0 -200%;
}
.df2 .df-skip:focus-visible { translate: 0 var(--df-space-2); }
.df2 main:focus { outline: none; }

/* ── 41. footer — four columns on the 1176 column (blurb · Catalogue · Ordering · Talk to us),
   then a legal row. Two columns on a tablet, one on a phone. The phone tab bar floats over the
   page bottom, so the body already reserves its height (§18). ── */
/* the footer sits at the foot of a short page (one quote line, Sent, an empty search) rather than
   floating partway up: the body is the column and main takes the slack. dvh, so a phone's collapsing
   address bar does not push it below the fold. */
.df2 body { display: flex; flex-direction: column; min-height: 100dvh; }
.df2 body > main { flex: 1 0 auto; }
.df2 body > .df-footer { flex: none; }
.df2 .df-footer {
  box-sizing: border-box; margin-top: var(--df-gap);
  padding: var(--df-space-12) max(var(--df-col-inset), calc((100% - var(--df-content)) / 2)) var(--df-space-6);
  background: var(--df-surface); border-top: 1px solid var(--df-hairline);
  font-size: var(--df-text-sm); color: var(--df-muted);
}
.df2 .df-footer__cols { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1fr; gap: var(--df-space-8); }
.df2 .df-footer__col { display: flex; flex-direction: column; align-items: flex-start; gap: var(--df-space-2); min-width: 0; }
.df2 .df-footer__col--brand { gap: var(--df-space-4); }
.df2 .df-footer .df-logo { min-height: 0; }
.df2 .df-footer .df-logo img { height: 26px; }
.df2 .df-footer__col--brand p { max-width: 36ch; line-height: 1.55; }
.df2 .df-footer__col p { line-height: 1.55; }
.df2 .df-footer__col .df-key { margin-bottom: var(--df-space-1); }
.df2 .df-footer a:not(.df-logo) { display: inline-flex; align-items: center; gap: var(--df-space-2); min-height: 32px; color: var(--df-text-2); text-decoration: none; }
@media (pointer: coarse) { .df2 .df-footer a:not(.df-logo) { min-height: var(--df-touch); } }
@media (hover: hover) { .df2 .df-footer a:not(.df-logo):hover { color: var(--df-accent-strong); text-decoration: underline; text-underline-offset: 3px; } }
.df2 .df-footer__legal {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--df-space-2) var(--df-space-6);
  margin-top: var(--df-space-10); padding-top: var(--df-space-5); border-top: 1px solid var(--df-hairline);
  font-size: var(--df-text-xs);
}
.df2 .df-footer .df-footer__legal p a:not(.df-logo) { display: inline; min-height: 0; }
.df2 .df-footer__legal nav { display: flex; flex-wrap: wrap; gap: 0 var(--df-space-5); }
@media (max-width: 860px) {
  .df2 .df-footer { padding-top: var(--df-space-10); }
  .df2 .df-footer__cols { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--df-space-8) var(--df-space-6); }
  .df2 .df-footer__col--brand { grid-column: 1 / -1; }
}

/* ── 42. toast region — #df-toast, a polite live region for short notices. Its notices stack
   above the tab bar on a phone, bottom centre on a desktop. The region takes no clicks; a notice does. ── */
.df2 .df-toast {
  position: fixed; z-index: 70; left: 50%; translate: -50% 0;
  bottom: var(--df-space-6);
  box-sizing: border-box; display: flex; flex-direction: column; gap: var(--df-space-2);
  width: min(calc(100% - 2 * var(--df-space-3)), 420px); pointer-events: none;
}
.df2 .df-toast > * {
  pointer-events: auto; box-sizing: border-box; padding: var(--df-space-3) var(--df-space-4);
  border: 1px solid var(--df-hairline); border-radius: var(--df-r-card-sm); background: var(--df-surface);
  box-shadow: var(--df-shadow-float); font-size: var(--df-text-sm); line-height: 1.45; color: var(--df-ink);
}
@supports (corner-shape: squircle) { .df2 .df-toast > * { corner-shape: squircle; } }
.df2 .df-toast__msg {
  margin: 0; opacity: 0; translate: 0 8px;
  transition: opacity calc(var(--df-dur-3) * .7) var(--df-ease-out), translate calc(var(--df-dur-3) * .7) var(--df-ease-out);
}
.df2 .df-toast__msg.is-in { opacity: 1; translate: 0 0; transition-duration: var(--df-dur-3); }
.df2 .df-toast__msg.is-out { opacity: 0; translate: 0 8px; }
@media (max-width: 860px) {
  .df2 .df-toast { bottom: calc(var(--df-tabbar-h) + env(safe-area-inset-bottom, 0px) + var(--df-space-3)); }
  /* a docked bar replaces the tab bar: the notices stack above the dock so Send / Keep browsing stay reachable */
  .df2 body:has(.df-actionbar:not(.df-actionbar--deferred, [hidden] *)) .df-toast { bottom: calc(var(--df-dock-h) + max(env(safe-area-inset-bottom, 0px), var(--df-space-3))); }
}

/* ── 43. cookie notice — a bar docked on the viewport foot (above the tab bar on a phone). cookie-consent
   toggles the literal class `hidden` on it. ── */
.df2 .df-cookie {
  position: fixed; z-index: 55; left: 0; right: 0; bottom: 0; box-sizing: border-box;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--df-space-4) var(--df-space-6);
  padding: var(--df-space-4) max(var(--df-col-inset), calc((100% - var(--df-content)) / 2)) max(env(safe-area-inset-bottom, 0px), var(--df-space-3));
  background: var(--df-surface); border-top: 1px solid var(--df-hairline); box-shadow: var(--df-shadow-bar);
}
.df2 .df-cookie.hidden { display: none; }
.df2 .df-cookie__text { flex: 1 1 360px; min-width: 0; max-width: 70ch; font-size: var(--df-text-sm); line-height: 1.5; color: var(--df-text-2); }
.df2 .df-cookie__text p + p { margin-top: var(--df-space-1); }
.df2 .df-cookie__text .df-title { margin-bottom: var(--df-space-1); }
.df2 .df-cookie__acts { display: flex; flex-wrap: wrap; gap: var(--df-space-2); }
.df2 .df-cookie .df-btn { min-height: var(--df-cta-h-sm); padding-inline: var(--df-space-5); font-size: var(--df-text-sm); }
@media (pointer: coarse) { .df2 .df-cookie .df-btn { min-height: var(--df-touch); } }
@media (max-width: 860px) {
  /* above the tab bar, which stays reachable; a docked bar replaces the tab bar, so the notice stacks above the dock */
  .df2 .df-cookie { bottom: calc(var(--df-tabbar-h) + env(safe-area-inset-bottom, 0px)); padding-bottom: var(--df-space-4); }
  .df2 body:has(.df-actionbar:not(.df-actionbar--deferred, [hidden] *)) .df-cookie { bottom: calc(var(--df-dock-h) + max(env(safe-area-inset-bottom, 0px), var(--df-space-3))); }
  .df2 .df-cookie__acts { flex: 1 1 100%; }
  .df2 .df-cookie__acts .df-btn { flex: 1 1 0; }
}

/* ── 45. page head — df_page_head: eyebrow, the display h1 and a lede in the title block (__x),
   with an optional action beside it. The head owns its vertical rhythm (40 above, 32 below);
   the action drops under the title block on a phone. ── */
.df2 .df-phead {
  display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: var(--df-space-4) var(--df-space-6);
  margin-block: var(--df-space-5) var(--df-space-6);
}
.df2 .df-phead__x { flex: 1 1 360px; min-width: 0; display: flex; flex-direction: column; gap: var(--df-space-3); }
.df2 .df-phead__x > * { margin: 0; }
.df2 .df-phead > :not(.df-phead__x) { flex: none; }
@media (max-width: 860px) {
  .df2 .df-phead { margin-block: var(--df-space-6) var(--df-space-6); }
}

/* ── 46. quote page — the page body under the head. The empty state, split and too-many note are
   toggled by quote with [hidden], which their own display would otherwise override. A line the
   server no longer returns is a muted df-item (section 69) without a thumb or stepper; its only
   control is Remove. ── */
.df2 .quote { padding-bottom: var(--df-space-12); }
.df2 :is(.df-split, .df-empty, .df-note)[hidden] { display: none; }

/* ── 47. product card — df-pcard (df-card--sm --flush): the photo well, then the tag, name, brand and ref,
   and a foot with the pack select and the quote controls (§60, §61). No price. The name clamps at three
   lines so a long one cannot stretch the grid. ── */
.df2 .df-pcard { display: flex; flex-direction: column; height: 100%; }
.df2 .df-pcard__body { display: flex; flex: 1 1 auto; flex-direction: column; gap: var(--df-space-2); padding: 14px var(--df-space-4) var(--df-space-4); }
@media (max-width: 860px) {
  .df2 .df-pcard__body { padding: var(--df-space-3) var(--df-space-4) var(--df-space-4); }
}

/* ── 48. product page — df-pdp: the gallery beside the buy box (the rail's width, 32 apart); one column on a
   phone. The buy box is a stack. storefront-pdp toggles [hidden] on its in-quote note, which the note's own
   display would otherwise override. The page opens 24 under the header, as every other page does. ── */
.df2 .df-pdp-page { padding-top: var(--df-space-6); padding-bottom: var(--df-space-12); }
.df2 .df-pdp { display: grid; grid-template-columns: minmax(0, 1fr) var(--df-rail-w); gap: var(--df-space-8); align-items: start; }
.df2 .df-pdp [hidden] { display: none; }
.df2 .df-pdp__info { display: flex; flex-direction: column; gap: var(--df-space-4); min-width: 0; }
.df2 .df-pdp__tags { display: flex; flex-wrap: wrap; gap: var(--df-space-2); }
.df2 .df-pdp__name { margin: 0; overflow-wrap: anywhere; }
.df2 .df-pdp + .df-related { margin-top: var(--df-gap); }
@media (max-width: 860px) {
  .df2 .df-pdp { grid-template-columns: minmax(0, 1fr); gap: var(--df-space-6); }
}

/* ── 49. gallery — df-gallery: a square well for the photo (a short one on phones) and a strip of
   thumbs. A product without a photo keeps the well, with a cube. gallery moves aria-current. ── */
.df2 .df-gallery { display: flex; flex-direction: column; gap: var(--df-space-4); min-width: 0; }
.df2 .df-gallery__well {
  display: grid; place-items: center; aspect-ratio: 1; overflow: hidden;
  border-radius: var(--df-r-card); background: var(--df-surface-alt); color: var(--df-muted);
}
.df2 .df-gallery__well > img { width: 100%; height: 100%; object-fit: contain; mix-blend-mode: multiply; }
.df2 .df-gallery__thumbs { display: flex; flex-wrap: wrap; gap: var(--df-space-3); margin: 0; padding: 0; list-style: none; }
.df2 .df-gallery__thumbs button {
  box-sizing: border-box; display: block; width: 72px; height: 72px; padding: 0; overflow: hidden; cursor: pointer;
  border: 1px solid var(--df-hairline); border-radius: calc(var(--df-r-card-sm) / 2); background: var(--df-surface-alt);
  transition: border-color var(--df-dur-2) var(--df-ease-out), box-shadow var(--df-dur-2) var(--df-ease-out);
}
.df2 .df-gallery__thumbs button > img { display: block; width: 100%; height: 100%; object-fit: contain; mix-blend-mode: multiply; }
.df2 .df-gallery__thumbs button[aria-current="true"] { border-color: var(--df-accent); box-shadow: 0 0 0 1px var(--df-accent); }
@media (hover: hover) { .df2 .df-gallery__thumbs button:hover { border-color: var(--df-accent-border); } }
.df2 .df-gallery__thumbs button:focus-visible { outline: none; box-shadow: var(--df-focus-ring); }
@supports (corner-shape: squircle) {
  .df2 :is(.df-gallery__well, .df-gallery__thumbs button) { corner-shape: squircle; }
}
@media (max-width: 860px) {
  .df2 .df-gallery__well { aspect-ratio: auto; height: 164px; border-radius: var(--df-r-card-sm); }
  .df2 .df-gallery__thumbs { display: none; }
}

/* ── 51. carousel — df-carousel: the admin banner carousel on /. A scroll-snap track of 3:1 slides
   (the image is contained, never cropped), prev/next round buttons over its edges and a row of
   dots over its foot. mobile-banner autoplays, pauses on hover and touch, and moves aria-current
   from the dot of one slide to the next as the track scrolls. scroll-behavior is left to JS, which
   jumps under reduced motion. ── */
.df2 .df-carousel { position: relative; }
/* the banner slot on Home: breathing room above, and below it before the page head */
.df2 .df-promoslot { margin-block: var(--df-space-4) var(--df-space-8); }
.df2 .df-carousel__track {
  display: flex; overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory; scrollbar-width: none;
}
.df2 .df-carousel__track::-webkit-scrollbar { display: none; }
.df2 .df-carousel__slide { flex: 0 0 100%; aspect-ratio: 3 / 1; scroll-snap-align: start; scroll-snap-stop: always; background: var(--df-surface-alt); }
.df2 .df-carousel__slide > a { display: block; height: 100%; }
.df2 .df-carousel__slide img { display: block; width: 100%; height: 100%; object-fit: contain; }
.df2 .df-carousel__prev, .df2 .df-carousel__next { position: absolute; top: 50%; translate: 0 -50%; }
.df2 .df-carousel__prev { inset-inline-start: var(--df-space-3); }
.df2 .df-carousel__next { inset-inline-end: var(--df-space-3); }
.df2 .df-carousel__dots {
  position: absolute; inset-inline: 0; bottom: var(--df-space-2); width: fit-content; margin-inline: auto;
  display: flex; align-items: center; padding: 0 var(--df-space-2); border-radius: var(--df-radius-pill);
  background: color-mix(in srgb, var(--df-surface) 80%, transparent);
}
.df2 .df-carousel__dot {
  box-sizing: border-box; display: grid; place-items: center; width: 24px; height: 24px; padding: 0; border: 0; background: none; cursor: pointer;
}
.df2 .df-carousel__dot::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--df-hairline-strong);
  transition: background-color var(--df-dur-1) var(--df-ease-out);
}
.df2 .df-carousel__dot[aria-current="true"]::before { background: var(--df-accent); }
.df2 .df-carousel__dot:focus-visible { outline: none; box-shadow: var(--df-focus-ring); border-radius: 50%; }
@media (pointer: coarse) { .df2 .df-carousel__dot { width: var(--df-touch); height: var(--df-touch); } }
@media (max-width: 860px) { .df2 .df-carousel__prev { inset-inline-start: var(--df-space-2); } .df2 .df-carousel__next { inset-inline-end: var(--df-space-2); } }

/* ── 52. chip bar spacing ── */
.df2 .df-col > .df-chipbar { margin-block: var(--df-space-6); }
/* Phone catalogue: two columns of compact cards (meta 12, title 15, pill 11 on 22). */
@media (max-width: 560px) {
  .df2 .df-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--df-space-3); }
  .df2 .df-grid--4 .df-pcard__body { padding: var(--df-space-3); }
  .df2 .df-grid--4 .df-pcard__body .df-meta { font-size: var(--df-text-xs); }
  .df2 .df-grid--4 .df-pcard__title { font-size: calc((var(--df-text-sm) + var(--df-text-md)) / 2); line-height: 1.3; }
  .df2 .df-grid--4 .df-pcard .df-pill { min-height: 22px; padding-block: 0; font-size: calc((var(--df-text-2xs) + var(--df-text-xs)) / 2); }
}
/* Under 360 nothing fits two-up: one column rather than controls that cannot show what they control. */
@media (max-width: 359px) { .df2 .df-grid--4 { grid-template-columns: minmax(0, 1fr); } }

/* ── 55. hero — df-hero: the Featured page's opening. The pitch (__main: eyebrow, display title,
   lede, buttons, help line) beside a "Today" card (__side: a df-kv of price list time, phone and
   hours; __range keeps one hours range on a line). Two columns above 860, stacked below. The card's links reach the touch height on coarse
   pointers. Nothing animates on load. ── */
.df2 .df-hero { display: grid; grid-template-columns: minmax(0, 1fr) var(--df-rail-w); gap: var(--df-space-10); align-items: start; margin-block: var(--df-space-10) var(--df-gap); }
.df2 .df-hero__main { min-width: 0; }
.df2 .df-hero__acts { display: flex; flex-wrap: wrap; gap: var(--df-space-3); margin-block: var(--df-space-6) var(--df-space-4); }
.df2 .df-hero__side { display: flex; flex-direction: column; gap: var(--df-space-5); }
.df2 .df-hero__side .df-kv { display: flex; flex-direction: column; gap: var(--df-space-4); }
.df2 .df-hero__range { white-space: nowrap; }
@media (pointer: coarse) { .df2 .df-hero__side .df-link { display: inline-flex; align-items: center; min-height: var(--df-touch); } }
@media (max-width: 860px) {
  .df2 .df-hero { grid-template-columns: minmax(0, 1fr); gap: var(--df-space-6); margin-block: var(--df-space-6) var(--df-gap); }
  .df2 .df-hero__acts .df-btn { flex: 1 1 100%; }
}

/* ── 56. brand tiles — df-brands: an auto-fill grid of df-brandtile links, each a square outline
   card holding one logo (object-fit: contain, so no logo is cropped or stretched). df-brands__all:
   the "All n brands" disclosure under it; its summary is a df-link and its list runs in columns
   above 860. A tile is at least 48px on every side. ── */
.df2 .df-brands { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 140px), 1fr)); gap: var(--df-grid); }
.df2 .df-brandtile {
  display: grid; place-items: center; box-sizing: border-box; aspect-ratio: 1; min-width: var(--df-touch); min-height: var(--df-touch);
  padding: var(--df-space-5); background: var(--df-surface); border: 1px solid var(--df-hairline); border-radius: var(--df-r-card-sm);
  box-shadow: var(--df-shadow-card); text-decoration: none;
  transition: border-color var(--df-dur-2) var(--df-ease-out), box-shadow var(--df-dur-2) var(--df-ease-out);
}
.df2 .df-brandtile img { display: block; max-width: 100%; max-height: 100%; object-fit: contain; }
@media (hover: hover) { .df2 .df-brandtile:hover { border-color: var(--df-accent-border); box-shadow: var(--df-shadow-card-hover); } }
.df2 .df-brandtile:focus-visible { outline: none; box-shadow: var(--df-focus-ring); }
@supports (corner-shape: squircle) { .df2 .df-brandtile { corner-shape: squircle; } }
.df2 .df-brands__all { margin-top: var(--df-space-5); }
.df2 .df-brands__all > summary { display: inline-flex; align-items: center; min-height: var(--df-touch); cursor: pointer; }
.df2 .df-brands__all ul { margin: var(--df-space-3) 0 0; padding: 0; list-style: none; }
.df2 .df-brands__all li a { display: inline-flex; align-items: center; min-height: var(--df-touch); }
@media (min-width: 861px) { .df2 .df-brands__all ul { columns: 4; column-gap: var(--df-space-8); } }

/* ── 57. steps — df-steps: an ol of numbered rows (the Sent page's "What happens next"). The number
   is a CSS counter in an accent-soft circle; the row's title and text sit beside it. ── */
.df2 .df-steps { display: flex; flex-direction: column; gap: var(--df-space-5); margin: var(--df-space-5) 0 0; padding: 0; list-style: none; counter-reset: df-step; }
.df2 .df-steps > li { display: grid; grid-template-columns: 32px minmax(0, 1fr); column-gap: var(--df-space-4); row-gap: var(--df-space-1); align-items: start; counter-increment: df-step; }
.df2 .df-steps > li::before {
  content: counter(df-step); grid-row: 1 / span 2; display: grid; place-items: center; width: 32px; height: 32px; border-radius: 50%;
  background: var(--df-accent-soft); color: var(--df-accent-strong); font-size: var(--df-text-sm); font-weight: 700; font-variant-numeric: tabular-nums;
}
.df2 .df-steps > li > * { grid-column: 2; margin: 0; }

/* ── 58. read-only items and the Sent column — df-qitem: one quote line with no controls (the
   Delivery page's items card): name and unit at the start (__main), quantity and total at the end
   (__end). Rows are split by a hairline. df-items: that card; phones drop it (the dock and the
   summary carry the total). df-sent: the Sent page's narrower column. ── */
.df2 .df-qitem { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--df-space-4); padding: var(--df-fc-y) var(--df-fc-x); }
.df2 .df-qitem + .df-qitem { border-top: 1px solid var(--df-hairline); }
.df2 .df-qitem__main { min-width: 0; display: flex; flex-direction: column; gap: var(--df-space-1); }
.df2 .df-qitem__main .df-title { overflow-wrap: anywhere; }
.df2 .df-qitem__end { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: var(--df-space-1); text-align: end; }
.df2 .df-qitem__end .df-amount { font-size: var(--df-text-lg); }
@media (max-width: 860px) { .df2 .df-items { display: none; } }
.df2 .df-sent { max-width: 980px; margin-inline: auto; padding-top: var(--df-space-10); }
.df2 .df-sent .df-kv { display: grid; gap: var(--df-space-3); }

/* ── 59. quote flow chrome — a hidden field or button stays hidden (.df-field sets display: block
   and .df-btn inline-flex, which beat the [hidden] default). df-noteacts: the failure note's small buttons, wrapping. df-qsend:
   the Delivery rail's send bar; its sum repeats the rail's total, so only the phone dock shows it.
   A phone flow screen hides the site bar (§5); the flow header is the bar, and
   the page scrolls a failure note or an invalid field clear of it (scroll-padding-top). ── */
.df2 .df-field[hidden], .df2 .df-btn[hidden] { display: none; }   /* .df-field / .df-btn set display, which beats the UA [hidden] */
.df2 .df-noteacts { display: flex; flex-wrap: wrap; align-items: center; gap: var(--df-space-2) var(--df-space-3); }
@media (min-width: 861px) { .df2 .df-qsend > .df-actionbar__sum { display: none; } }
@media (max-width: 860px) { .df2:has(.df-flowhead) { scroll-padding-top: calc(var(--df-flowhead-h) + var(--df-space-3)); } }

/* ============================================================================
   The test site's kit, folded in (storefront integration, Task 2). Per-board
   prefixes became df- names (a2 = category bar, al = facets, hs = how to order,
   ac = collections); B's ONE 900px breakpoint is this sheet's 860px.
   ============================================================================ */

/* ── 60. pack-size select — df-packselect: a compact select with a chevron, on a product card or in
   the filter row. 44 tall (48 on touch); it speaks the accent: ink and edge in the control line. ── */
.df2 .df-packselect { position: relative; display: block; }
.df2 .df-packselect select {
  appearance: none; -webkit-appearance: none; box-sizing: border-box; width: 100%; min-height: 44px; margin: 0;
  padding: 0 34px 0 12px; border: 1px solid var(--df-ctl-line); border-radius: 10px;
  background: var(--df-surface); color: var(--df-accent-strong);
  font-size: var(--df-text-sm); font-weight: 600; cursor: pointer;
  transition: border-color var(--df-dur-1) var(--df-ease-out), background-color var(--df-dur-1) var(--df-ease-out);
}
.df2 .df-packselect select option { color: var(--df-ink); }
@media (hover: hover) { .df2 .df-packselect select:hover { border-color: var(--df-accent-strong); background: var(--df-accent-softer); } }
.df2 .df-packselect select:focus-visible { outline: 2px solid var(--df-accent); outline-offset: 1px; border-color: var(--df-accent); }
.df2 .df-packselect .df-ic { position: absolute; right: 10px; top: 50%; translate: 0 -50%; pointer-events: none; color: var(--df-accent-strong); }
@media (pointer: coarse) { .df2 .df-packselect select { min-height: var(--df-touch); } }
@media (max-width: 860px) {
  .df2 .df-packselect select { padding: 0 26px 0 10px; }
  .df2 .df-packselect .df-ic { right: 7px; }
  .df2 .df-pcard__foot .df-btn--sm { padding-inline: 10px; }
}
/* a two-up card gives the select ~54px of text: the card shows the short pack label ("Ctn 48") and
   "Add" for "Add to quote" (the full wording stays in the button's aria-label) */
@media (max-width: 419px) {
  .df2 .df-pcard__body .df-btn__long { display: none; }
  .df2 .df-pcard__body .df-btn__short { display: inline; }
  .df2 .df-pcard__body .df-packselect select { font-size: 13px; }
}

/* ── 61. product card parts — the title link, the foot (select + button) and the photo well. The well
   is square; its photo is positioned, not sized by percentage, so a tall photo cannot stretch the card. ── */
.df2 .df-pcard__title { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; overflow-wrap: anywhere; color: var(--df-ink); text-decoration: none; font-size: calc((var(--df-text-sm) + var(--df-text-md)) / 2); font-weight: 700; line-height: 1.3; letter-spacing: -.01em; }
@media (hover: hover) { .df2 .df-pcard__title:hover { text-decoration: underline; } }
.df2 .df-pcard__foot { margin-top: auto; display: flex; flex-direction: column; gap: var(--df-space-2); padding-top: var(--df-space-1); }
/* a foot state: the add button, or the in-quote tag above the stepper; the card shows one,
   so [hidden] must beat the display below */
.df2 .df-pcard__state { display: flex; flex-direction: column; gap: var(--df-space-2); }
.df2 .df-pcard__state[hidden] { display: none; }
/* one surface behind a photo: the card's own white (the image multiplies its white away against it) */
.df2 .df-pcard__media { --df-pcard-pad: 18px; position: relative; display: block; overflow: hidden; aspect-ratio: 1; background: var(--df-surface); }
.df2 .df-pcard__media img {
  position: absolute; inset: var(--df-pcard-pad);
  width: calc(100% - 2 * var(--df-pcard-pad)); height: calc(100% - 2 * var(--df-pcard-pad));
  object-fit: contain; mix-blend-mode: multiply;
}

/* ── 62. pager — numbered pages in round targets; the current page is a solid accent disc. Wraps, so a
   Kaminari window cannot widen the page on a phone. ── */
.df2 .df-pager { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 6px; margin-top: var(--df-gap); }
.df2 .df-pager :is(a, span) {
  display: inline-grid; place-items: center; min-width: 44px; height: 44px; border-radius: 50%;
  font-size: 15px; font-weight: 600; color: var(--df-text-2); text-decoration: none; font-variant-numeric: tabular-nums;
}
.df2 .df-pager a { color: var(--df-accent-strong); }
@media (hover: hover) { .df2 .df-pager a:hover { background: var(--df-accent-softer); } }
.df2 .df-pager a:focus-visible { outline: 2px solid var(--df-accent); outline-offset: 2px; }
.df2 .df-pager [aria-current="page"] { background: var(--df-accent); color: var(--df-on-accent); }
@media (pointer: coarse) { .df2 .df-pager :is(a, span) { min-width: var(--df-touch); height: var(--df-touch); } }

/* ── 63. listing tabs — df-tabsbar over df-tabs: the sections of a category page, an accent rule under
   the current one; scrolls sideways and fades at the edge on a phone. ── */
.df2 .df-tabsbar { display: flex; align-items: center; gap: var(--df-space-2); border-bottom: 1px solid var(--df-hairline); }
.df2 .df-tabsbar .df-tabs { flex: 1 1 auto; min-width: 0; }
/* a mouse's way along the row (the track hides its scrollbar): the category track's arrows (§64) */
.df2 .df-tabsbar__arrows { flex: none; display: flex; gap: 6px; }
@media (max-width: 860px) { .df2 .df-tabsbar__arrows { display: none; } }
.df2 .df-tabs {
  display: flex; gap: 28px; overflow-x: auto; scrollbar-width: none; padding-right: 48px;
  -webkit-mask-image: linear-gradient(90deg, black calc(100% - 48px), transparent); mask-image: linear-gradient(90deg, black calc(100% - 48px), transparent);
}
.df2 .df-tabs::-webkit-scrollbar { display: none; }
/* the row scrolls smoothly when focus moves along it, like the category track (§64) */
.df2 .df-tabs { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { .df2 .df-tabs { scroll-behavior: auto; } }
.df2 .df-tab {
  flex: none; display: inline-flex; align-items: center; gap: 6px; min-height: 48px;
  border-bottom: 2px solid transparent; font-size: 15px; font-weight: 600; color: var(--df-accent-strong); text-decoration: none; white-space: nowrap;
  transition: color var(--df-dur-1) var(--df-ease-out), border-color var(--df-dur-1) var(--df-ease-out);
}
.df2 .df-tab:hover { border-bottom-color: var(--df-tint-4); }
.df2 .df-tab[aria-current="page"] { font-weight: 700; border-bottom-color: var(--df-accent); }
.df2 .df-tab small { font-size: var(--df-key-size); font-weight: 500; color: var(--df-muted); font-variant-numeric: tabular-nums; }

/* ── 64. category bar — df-catbar (Home, the category pages): a sideways track of df-catchip pills, each
   with its icon, and round arrows (hidden on a phone, where the track just scrolls). The track fades
   out at its end. ── */
.df2 .df-catbar { display: flex; align-items: center; gap: var(--df-space-3); padding: var(--df-space-5) 0 var(--df-space-1); }
.df2 .df-catbar__track {
  flex: 1; min-width: 0; display: flex; gap: 10px; overflow-x: auto; scrollbar-width: none; scroll-behavior: smooth; scroll-snap-type: x proximity;
  padding: 2px 48px 2px 2px;
  -webkit-mask-image: linear-gradient(90deg, black calc(100% - 48px), transparent); mask-image: linear-gradient(90deg, black calc(100% - 48px), transparent);
}
.df2 .df-catbar__track::-webkit-scrollbar { display: none; }
.df2 .df-catbar__arrows { display: flex; gap: var(--df-space-2); flex: none; }
.df2 .df-catchip {
  flex: none; scroll-snap-align: start; display: inline-flex; align-items: center; gap: 10px; min-height: 48px; padding: 0 18px 0 14px;
  border: 1px solid var(--df-ctl-line); border-radius: var(--df-radius-pill); background: var(--df-surface);
  color: var(--df-accent-strong); font-size: 15px; font-weight: 600; text-decoration: none; white-space: nowrap;
  transition: background-color var(--df-dur-1) var(--df-ease-out), border-color var(--df-dur-1) var(--df-ease-out), color var(--df-dur-1) var(--df-ease-out);
}
@media (hover: hover) { .df2 .df-catchip:hover { background: var(--df-accent-softer); border-color: var(--df-accent-strong); } }
.df2 .df-catchip[aria-current="page"] { background: var(--df-accent); border-color: var(--df-accent); color: var(--df-on-accent); }
.df2 .df-caticon { flex: none; width: 22px; height: 22px; background: currentColor; -webkit-mask: var(--df-cat-icon) center / contain no-repeat; mask: var(--df-cat-icon) center / contain no-repeat; }
@media (max-width: 860px) {
  .df2 .df-catbar__arrows, .df2 .df-catbar__all { display: none; }
  .df2 .df-catbar__track { margin-right: calc(-1 * var(--df-col-inset)); }
}
@media (prefers-reduced-motion: reduce) {
  .df2 .df-catbar__track { scroll-behavior: auto; }
  .df2 .df-catchip { transition: none; }
}

/* ── 65. facets — df-facets: the filter row (brand and sort selects beside the chips); df-active: the
   filters now on, each a removable df-active__x pill. ── */
.df2 .df-facets { display: flex; flex-wrap: wrap; align-items: center; gap: var(--df-space-3); }
.df2 .df-facets .df-packselect { width: 200px; }
.df2 .df-active { display: flex; flex-wrap: wrap; align-items: center; gap: var(--df-space-2); margin-bottom: var(--df-space-4); }
.df2 .df-active__x {
  display: inline-flex; align-items: center; gap: 6px; min-height: 36px; padding: 0 var(--df-space-2) 0 14px;
  border: 1px solid var(--df-ctl-line); border-radius: var(--df-radius-pill); background: var(--df-surface);
  font-size: var(--df-text-sm); font-weight: 600; color: var(--df-accent-strong); text-decoration: none; cursor: pointer;
}
@media (hover: hover) { .df2 .df-active__x:hover { border-color: var(--df-accent-strong); background: var(--df-accent-softer); } }
@media (pointer: coarse) { .df2 .df-active__x { min-height: var(--df-touch); } }
/* on a phone the selects share rows as halves that can shrink, so two facets take one row, not two */
@media (max-width: 860px) {
  .df2 .df-facets { flex: 1 1 100%; gap: var(--df-space-2); }
  .df2 .df-facets .df-packselect { flex: 1 1 140px; min-width: 0; width: auto; }
}

/* ── 66. how to order — df-howto: a tinted lead beside three numbered steps; the lead deepens and a step
   slides on hover (fine pointers only). One column on a phone. ── */
.df2 .df-howto { display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); overflow: hidden; border: 1px solid var(--df-hairline); border-radius: var(--df-r-card); background: var(--df-surface); }
.df2 .df-howto__lead {
  position: relative; isolation: isolate; overflow: hidden;
  display: flex; flex-direction: column; justify-content: space-between; gap: var(--df-space-6); padding: var(--df-space-8);
  background: var(--df-tint-1); border-right: 1px solid var(--df-tint-3); color: var(--df-ink);
  transition: background-color var(--df-dur-4) var(--df-ease-out);
}
.df2 .df-howto__lead > * { position: relative; z-index: 1; }
.df2 .df-howto__lead h2:not(.df-sans) { font-size: 28px; line-height: 32px; letter-spacing: -.02em; color: var(--df-ink); }
.df2 .df-howto__lead p { max-width: 320px; font-size: 15px; line-height: 22px; color: var(--df-muted); }
.df2 .df-howto__btn {
  align-self: flex-start; display: inline-flex; align-items: center; gap: var(--df-space-2); min-height: 48px; padding: 0 22px;
  border-radius: var(--df-radius-pill); background: var(--df-accent); color: var(--df-on-accent); font-size: 15px; font-weight: 600; text-decoration: none;
  transition: transform var(--df-dur-2) var(--df-ease-out), box-shadow var(--df-dur-2) var(--df-ease-out), background-color var(--df-dur-2) var(--df-ease-out);
}
.df2 .df-howto__btn svg { transition: transform var(--df-dur-3) var(--df-ease-out); }
.df2 .df-howto__steps { display: flex; flex-direction: column; margin: 0; padding: var(--df-space-2) var(--df-space-10); list-style: none; }
.df2 .df-howto__step { position: relative; display: flex; align-items: flex-start; gap: var(--df-space-5); padding: 22px 0; }
.df2 .df-howto__step + .df-howto__step { border-top: 1px solid var(--df-hairline); }
.df2 .df-howto__step::before {
  content: ""; position: absolute; left: -20px; top: 14px; bottom: 14px; width: 3px; border-radius: 0 3px 3px 0; background: var(--df-accent);
  transform: scaleY(0); transition: transform var(--df-dur-4) var(--df-ease);
}
.df2 .df-howto__n {
  flex: none; display: inline-block; width: 44px; font-size: 22px; line-height: 26px; font-weight: 700; color: var(--df-accent); font-variant-numeric: tabular-nums;
  transition: transform var(--df-dur-4) var(--df-ease-out), color var(--df-dur-2) var(--df-ease-out);
}
.df2 .df-howto__x { display: flex; flex-direction: column; gap: var(--df-space-1); transition: transform var(--df-dur-4) var(--df-ease); }
.df2 .df-howto__x b { font-size: 17px; line-height: 24px; font-weight: 700; color: var(--df-ink); transition: color var(--df-dur-2) var(--df-ease-out); }
.df2 .df-howto__x span { font-size: var(--df-text-sm); line-height: 20px; color: var(--df-muted); }
@media (hover: hover) {
  .df2 .df-howto:hover .df-howto__lead { background: var(--df-tint-2); }
  .df2 .df-howto__btn:hover { background: var(--df-accent-strong); transform: translateY(-2px); box-shadow: 0 8px 20px rgba(var(--df-accent-strong-rgb), .22); }
  .df2 .df-howto__btn:hover svg { transform: translateX(4px); }
  .df2 .df-howto__step:hover::before { transform: scaleY(1); }
  .df2 .df-howto__step:hover .df-howto__n { transform: translateX(4px) scale(1.12); color: var(--df-accent-strong); }
  .df2 .df-howto__step:hover .df-howto__x { transform: translateX(6px); }
  .df2 .df-howto__step:hover .df-howto__x b { color: var(--df-accent-strong); }
}
@media (max-width: 860px) {
  .df2 .df-howto { grid-template-columns: minmax(0, 1fr); }
  .df2 .df-howto__lead { padding: var(--df-space-6); border-right: 0; border-bottom: 1px solid var(--df-tint-3); }
  .df2 .df-howto__lead h2:not(.df-sans) { font-size: 24px; line-height: 28px; }
  .df2 .df-howto__steps { padding: var(--df-space-1) var(--df-space-6); }
  .df2 .df-howto__step::before { left: -12px; }
}
@media (prefers-reduced-motion: reduce) {
  .df2 .df-howto__lead, .df2 .df-howto__step::before, .df2 .df-howto__n, .df2 .df-howto__x, .df2 .df-howto__btn, .df2 .df-howto__btn svg { transition: none; }
}

/* ── 67. collections — df-collections: a four-up grid of df-collection links (logo + name) for the
   all-categories page; df-collage: a 2 x 2 mosaic of a category's photos on a card's media well. The
   collage sets min-height 0 so the 4/3 ratio wins over the flex item's content minimum. ── */
.df2 .df-collage {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: repeat(2, minmax(0, 1fr)); gap: 6px;
  min-height: 0; aspect-ratio: 4 / 3; padding: var(--df-space-3); background: var(--df-surface);
}
/* no grey well and no white tiles on it: the gaps read as spacing between products, not a second set of cards */
.df2 .df-collage span { display: block; min-height: 0; padding: 6px; overflow: hidden; border-radius: 10px; background: transparent; }
.df2 .df-collage span:only-child { grid-row: 1 / -1; grid-column: 1 / -1; }
.df2 .df-collage img { width: 100%; height: 100%; object-fit: contain; mix-blend-mode: multiply; }
.df2 .df-collections { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--df-space-4); }
.df2 .df-collection { display: flex; align-items: center; gap: var(--df-space-4); padding: var(--df-space-4) var(--df-space-5); text-decoration: none; }
.df2 .df-collection img { flex: none; width: 64px; height: 64px; object-fit: contain; mix-blend-mode: multiply; }
@media (max-width: 860px) { .df2 .df-collections { grid-template-columns: minmax(0, 1fr); } }

/* ── 68. pack-size choice cards (the product page) + the "in your quote" mark ── */
.df2 .df-choices { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--df-space-3); }
.df2 .df-card--choice { display: flex; flex-direction: column; gap: 2px; }
.df2 label.df-card:has(> input:checked) .df-title { color: var(--df-accent-strong); }
.df2 .df-inquote { display: inline-flex; align-items: center; gap: var(--df-space-1); font-size: var(--df-text-xs); font-weight: 600; color: var(--df-ok); }

/* ── 69. quote item — df-item: one editable line of the quote card (thumb, name, stepper, remove). On a
   phone the controls share a row of their own under the name, the remove button at the far end. ── */
.df2 .df-item { display: grid; grid-template-columns: 64px minmax(0, 1fr) auto auto; align-items: center; gap: var(--df-space-4); padding: var(--df-space-4) var(--df-space-6); border-top: 1px solid var(--df-hairline); }
.df2 .df-item__img { width: 64px; height: 64px; padding: 6px; border-radius: 12px; background: var(--df-surface-alt); }
.df2 .df-item__img img { width: 100%; height: 100%; object-fit: contain; mix-blend-mode: multiply; }
.df2 .df-item__x { display: flex; flex-direction: column; gap: var(--df-space-1); min-width: 0; }
.df2 .df-item__x .df-title { overflow-wrap: anywhere; color: var(--df-ink); text-decoration: none; }
.df2 .df-item__x a.df-title:is(:hover, :focus-visible) { color: var(--df-accent-strong); text-decoration: underline; }
@media (max-width: 860px) {
  .df2 .df-item { grid-template-columns: 56px minmax(0, 1fr) auto; padding: 14px var(--df-space-4); }
  .df2 .df-item__x { grid-column: 2 / -1; }
  .df2 .df-item > .df-stepper { grid-column: 2; }
  .df2 .df-item > .df-roundbtn--danger { grid-column: 3; }
  .df2 .df-item__img { width: 56px; height: 56px; }
}

.df2 .df-item--muted { grid-template-columns: minmax(0, 1fr) auto; background: var(--df-surface-alt); }
.df2 .df-item--muted .df-title { color: var(--df-text-2); }
@media (max-width: 860px) {
  .df2 .df-item--muted { grid-template-columns: minmax(0, 1fr) auto; }
  .df2 .df-item--muted > .df-item__x { grid-column: 1; }
  .df2 .df-item--muted > .df-roundbtn--danger { grid-column: 2; }
}

/* ── 70. summary lines, control rows and the page-top row ── */
.df2 .df-sum__lines { display: flex; flex-direction: column; gap: var(--df-space-2); }
.df2 .df-sum__line > :first-child { min-width: 0; }
/* the totals row: "N products" stays whole; the pack breakdown wraps as a whole under it when it
   does not fit beside it, and reads from the right */
.df2 .df-sum__total { flex-wrap: wrap; }
.df2 .df-sum__total > :first-child { flex: none; white-space: nowrap; }
.df2 .df-sum__total > :last-child { flex: 1 1 auto; min-width: 0; text-align: end; }
.df2 .df-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--df-space-4); }
.df2 .df-rowstack { display: flex; flex-direction: column; gap: 6px; }
/* a label stacked over a control, with a button beside it: the button sits on the control's baseline and fills the row */
.df2 .df-row:has(.df-rowstack) { align-items: flex-end; }
.df2 .df-row:has(.df-rowstack) > .df-btn { flex: 1; min-width: 220px; align-self: flex-end; }
/* a pair of actions that stays on one line; on a phone they share the row and their labels may wrap */
.df2 .df-row--pair { flex-wrap: nowrap; }
@media (max-width: 860px) {
  .df2 .df-row--pair { align-items: stretch; gap: 10px; }
  .df2 .df-row--pair > .df-btn { flex: 1 1 0; min-width: 0; padding-inline: var(--df-space-3); white-space: normal; line-height: 1.2; text-align: center; }
}
.df2 .df-pagetop { margin-bottom: var(--df-space-4); }
/* the trail sits on the back link's centreline, so it carries no margin of its own here */
.df2 .df-pagetop .df-crumbs { margin-bottom: 0; }
/* a fieldset's label sits clear of the controls under it */
.df2 fieldset > .df-key { display: block; margin-bottom: var(--df-space-3); }
/* a card's key/value list as label and value rows: the label left, the value right, a hairline between */
.df2 .df-title + .df-kv--rows { margin-top: var(--df-space-3); }
.df2 .df-kv--rows { display: grid; gap: var(--df-space-3); }
.df2 .df-kv--rows > div { display: flex; gap: var(--df-space-4); justify-content: space-between; padding-bottom: var(--df-space-3); border-bottom: 1px solid var(--df-hairline); }
.df2 .df-kv--rows > div:last-child { padding-bottom: 0; border-bottom: 0; }
.df2 .df-kv--rows dt { font-size: var(--df-text-sm); font-weight: 400; }
.df2 .df-kv--rows dd { margin-top: 0; font-size: var(--df-text-sm); text-align: right; }

/* ── 71. FAQ — df-faq: one question and answer per row on the card's text rail. The number is a fixed
   badge on the question's first line; the answer hangs under the question text. ── */
.df2 .df-faq { padding: var(--df-space-5) var(--df-space-6); border-top: 1px solid var(--df-hairline); }
.df2 .df-faq:first-child { border-top: 0; }
.df2 .df-faq__q { display: flex; align-items: flex-start; gap: 10px; font-size: 17px; font-weight: 700; letter-spacing: -.01em; line-height: 1.35; color: var(--df-ink); }
.df2 .df-faq__n { flex: none; display: grid; place-items: center; width: 24px; height: 24px; margin-top: 1px; border-radius: 50%; background: var(--df-accent-soft); color: var(--df-accent-strong); font-size: var(--df-key-size); font-weight: 700; }
.df2 .df-faq__a { margin-top: 6px; padding-inline-start: 34px; font-size: 15px; color: var(--df-text-2); }
@media (max-width: 860px) {
  .df2 .df-faq { padding: var(--df-space-4); }
  .df2 .df-faq__q { font-size: var(--df-text-md); }
}

/* ── 72. prose — df-prose: a readable column for long copy (the policy and about pages): headings,
   paragraphs and lists on the type tokens. ── */
.df2 .df-prose { max-width: 68ch; font-size: var(--df-text-md); line-height: 1.7; color: var(--df-text-2); }
.df2 .df-prose > * + * { margin-top: var(--df-space-4); }
.df2 .df-prose :is(h2, h3, h4):not(.df-sans) { margin-top: var(--df-space-8); font-weight: 700; line-height: 1.3; letter-spacing: -.01em; color: var(--df-ink); }
.df2 .df-prose h2:not(.df-sans) { font-size: var(--df-text-2xl); }
.df2 .df-prose h3:not(.df-sans) { font-size: var(--df-text-xl); }
.df2 .df-prose h4:not(.df-sans) { font-size: var(--df-text-lg); }
.df2 .df-prose :is(h2, h3, h4):not(.df-sans) + * { margin-top: var(--df-space-3); }
.df2 .df-prose :is(ul, ol) { padding-inline-start: var(--df-space-6); }
.df2 .df-prose ul { list-style: disc; }
.df2 .df-prose ol { list-style: decimal; }
.df2 .df-prose li + li { margin-top: var(--df-space-2); }
.df2 .df-prose :is(strong, b) { font-weight: 600; color: var(--df-ink); }
.df2 .df-prose a { color: var(--df-accent-strong); text-decoration: underline; text-underline-offset: 3px; }
.df2 .df-prose hr { height: 1px; margin-block: var(--df-space-8); border: 0; background: var(--df-hairline); }
.df2 .df-prose table { width: 100%; border-collapse: collapse; font-size: var(--df-text-sm); }
.df2 .df-prose :is(th, td) { padding: var(--df-space-2) var(--df-space-3); border-bottom: 1px solid var(--df-hairline); text-align: start; }

/* ── 72b. content pages — df-col--page: a narrower column for text pages; df-iconlist: icon then text rows
   (--row lets them run in a line); df-about__mark: the About illustration; df-switch: an on/off
   checkbox drawn as a track (the cookie policy's Necessary / All). ── */
.df2 .df-col--page { max-width: 920px; padding-bottom: var(--df-space-12); }
/* --wide: the full 1176 column (FAQ); --inset: its content one more inset in, crumbs stay on the
   column (About, Contact); df-phead--center: the centred title those two pages open with */
.df2 .df-col--wide { max-width: var(--df-col); }
.df2 .df-col--inset > :not(.df-crumbs) { margin-inline: var(--df-col-inset); }
.df2 .df-phead--center { text-align: center; }
.df2 .df-phead--center .df-phead__x { align-items: center; }
/* a short grid that fills its row: empty tracks collapse, so three cards share a wide card evenly */
.df2 .df-grid--fit { grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); }
/* a button pair sharing the row equally, stacked when they no longer fit */
.df2 .df-row--fill { flex-wrap: wrap; }
.df2 .df-row--fill > .df-btn { flex: 1 1 240px; }
/* the Contact page: locations beside the form, the form on the wider three fifths */
.df2 .df-contact { display: grid; gap: var(--df-space-6); align-items: start; }
@media (min-width: 1024px) {
  .df2 .df-contact { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .df2 .df-contact > :first-child { grid-column: span 2; }
  .df2 .df-contact > :last-child { grid-column: span 3; }
}
/* df-formcard--boxed: a label over a bordered 36px control, no row hairlines. For a short standalone
   form (Contact); the checkout forms keep the row-is-the-label fields of section 17. */
.df2 .df-formcard--boxed { display: flex; flex-direction: column; gap: var(--df-space-4); padding: var(--df-space-6) var(--df-fc-x); }
.df2 .df-formcard--boxed .df-formcard__head { padding: 0; }
.df2 .df-formcard--boxed .df-field { padding: 0; }
.df2 .df-formcard--boxed .df-field-row { gap: var(--df-space-4); }
.df2 .df-formcard--boxed .df-field-row > .df-field + .df-field { border-left: 0; }
.df2 .df-formcard--boxed > :is(.df-field, .df-field-row) + :is(.df-field, .df-field-row)::before,
.df2 .df-formcard--boxed .df-field-row > .df-field::before,
.df2 .df-formcard--boxed .df-field:focus-within::after { content: none; }
.df2 .df-formcard--boxed .df-field:focus-within { background: none; }
.df2 .df-formcard--boxed .df-field__label { margin-bottom: var(--df-space-1); font-size: var(--df-text-sm); font-weight: 500; color: var(--df-ink); }
.df2 .df-formcard--boxed .df-field :is(input, textarea) { height: 36px; min-height: 0; padding: var(--df-space-1) var(--df-space-3); border: 1px solid var(--df-hairline); border-radius: var(--df-radius); background: var(--df-surface); font-weight: 400; }
.df2 .df-formcard--boxed .df-field :is(input, textarea):focus { border-color: var(--df-accent); box-shadow: 0 0 0 1px var(--df-accent); }
.df2 .df-formcard--boxed .df-formcard__foot { padding: 0; border-top: 0; }
.df2 .df-formcard--boxed .df-formcard__foot > .df-btn { flex: 1 1 200px; }
.df2 .df-iconlist, .df2 .df-prose ul.df-iconlist { display: grid; gap: var(--df-space-3); margin: 0; padding: 0; list-style: none; }
.df2 .df-iconlist--row, .df2 .df-prose ul.df-iconlist--row { display: flex; flex-wrap: wrap; gap: var(--df-space-3) var(--df-space-6); }
.df2 .df-iconlist li, .df2 .df-prose .df-iconlist li + li { display: flex; align-items: flex-start; gap: var(--df-space-3); margin-top: 0; }
.df2 .df-iconlist .df-ic { flex: none; margin-top: .2em; color: var(--df-accent-strong); }
.df2 .df-about__mark { display: block; width: 100%; max-width: 240px; height: auto; margin-inline: auto; }
.df2 .df-switch { display: inline-flex; align-items: center; gap: var(--df-space-3); min-height: 44px; font-size: var(--df-text-sm); font-weight: 600; color: var(--df-ink); }
.df2 .df-switch__track { position: relative; flex: none; width: 44px; height: 24px; border-radius: var(--df-radius-pill); background: var(--df-hairline-strong); cursor: pointer; transition: background var(--df-dur-2) var(--df-ease-out); }
.df2 .df-switch__track::after { content: ""; position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; border-radius: 50%; background: var(--df-surface); box-shadow: var(--df-shadow-thumb); transition: translate var(--df-dur-2) var(--df-ease-out); }
.df2 .df-switch__track:has(input:checked) { background: var(--df-accent); }
.df2 .df-switch__track:has(input:checked)::after { translate: 20px 0; }
.df2 .df-switch__track:has(input:focus-visible) { outline: 2px solid var(--df-accent); outline-offset: 2px; }

/* ── 73. category icons — df-caticon--<category slug>: a mask image per category, so the glyph takes
   the chip's currentColor. Keyed by slug (not position): reordering Constants::PRODUCT_CATEGORIES
   cannot shuffle the artwork. --all is the "All products" chip. ── */
/* All products */
.df2 .df-caticon--all { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Crect%20x%3D%274%27%20y%3D%274%27%20width%3D%277%27%20height%3D%277%27%20rx%3D%271.5%27%2F%3E%3Crect%20x%3D%2713%27%20y%3D%274%27%20width%3D%277%27%20height%3D%277%27%20rx%3D%271.5%27%2F%3E%3Crect%20x%3D%274%27%20y%3D%2713%27%20width%3D%277%27%20height%3D%277%27%20rx%3D%271.5%27%2F%3E%3Crect%20x%3D%2713%27%20y%3D%2713%27%20width%3D%277%27%20height%3D%277%27%20rx%3D%271.5%27%2F%3E%3C%2Fsvg%3E"); }
/* Chips, Crackers & Savoury Snacks */
.df2 .df-caticon--chips-crackers-savoury-snacks { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Cpath%20d%3D%27M7%204h10l-1%2016H8z%27%2F%3E%3Cpath%20d%3D%27M7%204l1.7-1%201.6%201%201.7-1%201.6%201%201.7-1L17%204%27%2F%3E%3Cpath%20d%3D%27M10%2010h4%27%2F%3E%3C%2Fsvg%3E"); }
/* Biscuits, Cakes & Chocolates */
.df2 .df-caticon--biscuits-cakes-chocolates { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Ccircle%20cx%3D%2712%27%20cy%3D%2712%27%20r%3D%278%27%2F%3E%3Cpath%20d%3D%27M9%209h.01M14.5%208.5h.01M15%2014h.01M9.5%2015h.01M12%2012h.01%27%2F%3E%3C%2Fsvg%3E"); }
/* Candies */
.df2 .df-caticon--candies { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Ccircle%20cx%3D%2712%27%20cy%3D%2712%27%20r%3D%274%27%2F%3E%3Cpath%20d%3D%27M8%2012%203%208.5v7zM16%2012l5-3.5v7z%27%2F%3E%3C%2Fsvg%3E"); }
/* Beverages */
.df2 .df-caticon--beverages { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Cpath%20d%3D%27M6%208h12l-1.5%2012h-9z%27%2F%3E%3Cpath%20d%3D%27M9%208V5h6v3M7%2012h10%27%2F%3E%3C%2Fsvg%3E"); }
/* Soft Drinks */
.df2 .df-caticon--soft-drinks { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Cpath%20d%3D%27M10%203h4v3l2%203v12H8V9l2-3z%27%2F%3E%3Cpath%20d%3D%27M8%2013h8%27%2F%3E%3C%2Fsvg%3E"); }
/* Dairy */
.df2 .df-caticon--dairy { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Cpath%20d%3D%27M8%203h8v3l2%203v12H6V9l2-3z%27%2F%3E%3Cpath%20d%3D%27M6%209h12M10%2014h4%27%2F%3E%3C%2Fsvg%3E"); }
/* Tea, Coffee & Instants */
.df2 .df-caticon--tea-coffee-instants { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Cpath%20d%3D%27M5%2010h11v5a5%205%200%200%201-5%205h-1a5%205%200%200%201-5-5z%27%2F%3E%3Cpath%20d%3D%27M16%2012h1.5a2%202%200%200%201%200%204H16M9%203.5v3M12.5%203.5v3%27%2F%3E%3C%2Fsvg%3E"); }
/* Noodles & Pasta */
.df2 .df-caticon--noodles-pasta { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Cpath%20d%3D%27M4%2012h16a8%208%200%200%201-16%200z%27%2F%3E%3Cpath%20d%3D%27M9%2012%2013%203M12.5%2012%2018%204%27%2F%3E%3C%2Fsvg%3E"); }
/* Canned Foods */
.df2 .df-caticon--canned-foods { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Crect%20x%3D%276%27%20y%3D%274%27%20width%3D%2712%27%20height%3D%2716%27%20rx%3D%272%27%2F%3E%3Cpath%20d%3D%27M6%208h12M6%2016h12%27%2F%3E%3C%2Fsvg%3E"); }
/* Condiments & Sauces */
.df2 .df-caticon--condiments-sauces { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Cpath%20d%3D%27M11%203h2v4l2%202v12H9V9l2-2z%27%2F%3E%3Cpath%20d%3D%27M9%2013h6%27%2F%3E%3C%2Fsvg%3E"); }
/* Herbs & Spices */
.df2 .df-caticon--herbs-spices { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Cpath%20d%3D%27M5%2019C5%2010%2010%205%2019%205c0%209-5%2014-14%2014z%27%2F%3E%3Cpath%20d%3D%27M5%2019l8-8%27%2F%3E%3C%2Fsvg%3E"); }
/* Cooking & Baking */
.df2 .df-caticon--cooking-baking { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Cpath%20d%3D%27M7%208h10l1%2012H6z%27%2F%3E%3Cpath%20d%3D%27M9%208V5h6v3M10%2013h4%27%2F%3E%3C%2Fsvg%3E"); }
/* Grains & Staples */
.df2 .df-caticon--grains-staples { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Cpath%20d%3D%27M6%2010c0-3%203-6%206-6s6%203%206%206v10H6z%27%2F%3E%3Cpath%20d%3D%27M9%204.5l3%203%203-3M9%2014h6%27%2F%3E%3C%2Fsvg%3E"); }
/* Nuts & Dry Fruits */
.df2 .df-caticon--nuts-dry-fruits { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Cpath%20d%3D%27M12%203c4.5%203%206.5%207.5%204.5%2012.5S10%2021%208%2018s-1.5-10%204-15z%27%2F%3E%3Cpath%20d%3D%27M12%207c-1%203-1.5%206-1%209%27%2F%3E%3C%2Fsvg%3E"); }
/* Oils & Fats */
.df2 .df-caticon--oils-fats { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Cpath%20d%3D%27M10%203h4v3l1%202v13H9V8l1-2z%27%2F%3E%3Cpath%20d%3D%27M12%2011.5c-1%201.5-1.5%202.3-1.5%203a1.5%201.5%200%200%200%203%200c0-.7-.5-1.5-1.5-3z%27%2F%3E%3C%2Fsvg%3E"); }
/* Personal Care */
.df2 .df-caticon--personal-care { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Cpath%20d%3D%27M8%209h8v12H8z%27%2F%3E%3Cpath%20d%3D%27M12%209V5h3M10%205h2M10%2014h4%27%2F%3E%3C%2Fsvg%3E"); }
/* Household Care */
.df2 .df-caticon--household-care { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Cpath%20d%3D%27M8%2010h6v11H8z%27%2F%3E%3Cpath%20d%3D%27M9%2010V7h4l3%202M17%204.5h2M17%207.5h2%27%2F%3E%3C%2Fsvg%3E"); }
/* Baby Products */
.df2 .df-caticon--baby-products { --df-cat-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.8%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Cpath%20d%3D%27M9%208h6v11a2%202%200%200%201-2%202h-2a2%202%200%200%201-2-2z%27%2F%3E%3Cpath%20d%3D%27M10%208V6l2-3%202%203v2M9%2012h6M9%2016h6%27%2F%3E%3C%2Fsvg%3E"); }
