/* ============================================================================
   FROOTCITY — COMPONENT LIBRARY
   Every component supports: default / hover / focus / active / selected /
   disabled / loading / error / success / empty / offline.
   ========================================================================= */

/* ------------------------------------------------------------------ BUTTON */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--fc-s-2); min-height: var(--fc-tap); padding: 0 var(--fc-s-5);
  border-radius: var(--fc-r-pill); font-weight: var(--fc-w-semi);
  font-size: var(--fc-t-md); letter-spacing: -.005em; position: relative;
  transition: transform var(--fc-m-fast) var(--fc-ease-out), background-color var(--fc-m-fast) var(--fc-ease-out), box-shadow var(--fc-m-fast) var(--fc-ease-out), opacity var(--fc-m-fast) var(--fc-ease-out);
  overflow: hidden; user-select: none; white-space: nowrap;
  border: 1px solid transparent;
  /* A button is sized by its label. Flex parents may not shrink it below
     that — clipped button text was the single most common overflow bug. */
  flex: none; max-width: 100%;
}
.btn > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* The corollary of `flex: none`, and the half that was missing.
   If a button may not be shrunk below its label, then the ROW has to give when
   the labels grow. Telugu and Hindi run 1.3-1.8x the width of English, so the
   order card's "Reorder / Report an issue" pair asks for 296px inside a 270px
   row: at 320px the second button and the rating stars were pushed clean out of
   the card. Measured on 35 order rows, in te and hi only, which is exactly why
   an English-only sweep never saw it.
   Wrapping is the right give: the label stays intact (the thing `flex: none`
   was protecting) and nothing leaves the card. */
.row:has(> .btn) { flex-wrap: wrap; }
/* Full-width buttons take the space they are given and wrap rather than clip. */
.btn--block { flex: 1 1 auto; min-width: 0; white-space: normal; height: auto; padding-top: 8px; padding-bottom: 8px; }
.btn--block > span { white-space: normal; overflow: visible; text-overflow: clip; }
/* --fc-press is the single press scale. Seven different values used to
   exist for one identical gesture; they are all this token now. */
.btn:active:not(:disabled):not(.is-loading) { transform: scale(var(--fc-press)); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .42; cursor: not-allowed; }
.btn svg { flex: none; }

.btn--primary {
  background: linear-gradient(178deg, var(--fc-green-500), var(--fc-green-700));
  color: var(--fc-ink-900);
  box-shadow: 0 1px 0 rgba(255,255,255,.28) inset, 0 6px 18px -6px rgba(94,158,30,.7);
}
.btn--primary:hover:not(:disabled) { box-shadow: 0 1px 0 rgba(255,255,255,.32) inset, 0 10px 26px -8px rgba(94,158,30,.85); }
.btn--danger {
  background: linear-gradient(178deg, var(--fc-red-400), var(--fc-red-600));
  color:#fff; box-shadow: 0 1px 0 rgba(255,255,255,.24) inset, 0 6px 18px -6px rgba(214,33,27,.6);
}
.btn--dark { background: var(--fc-ink-900); color: #fff; }
[data-surface="night"] .btn--dark { background: #fff; color: var(--fc-ink-900); }
.btn--glass {
  background: var(--glass-fill); border-color: var(--glass-stroke); color: var(--txt-1);
  -webkit-backdrop-filter: blur(14px) saturate(150%); backdrop-filter: blur(14px) saturate(150%);
}
.btn--ghost { background: transparent; color: var(--txt-1); border-color: var(--line); }
.btn--ghost:hover:not(:disabled) { background: var(--on-glass-chip); }
.btn--quiet { background: transparent; color: var(--txt-2); padding: 0 var(--fc-s-3); }
.btn--quiet:hover:not(:disabled) { color: var(--txt-1); background: var(--on-glass-chip); }
.btn--accent-soft { background: var(--fc-green-100); color: var(--fc-green-800); }
[data-surface="night"] .btn--accent-soft { background: rgba(140,198,63,.16); color: var(--fc-green-300); }

.btn--sm { min-height: 34px; padding: 0 var(--fc-s-4); font-size: var(--fc-t-sm); }
.btn--xs { min-height: 28px; padding: 0 var(--fc-s-3); font-size: var(--fc-t-xs); gap: 5px; }
.btn--lg { min-height: 54px; padding: 0 var(--fc-s-7); font-size: var(--fc-t-lg); }
.btn--block { display: flex; width: 100%; }
.btn--icon { padding: 0; width: var(--fc-tap); min-height: var(--fc-tap); border-radius: 50%; }
.btn--icon.btn--sm { width: 34px; min-height: 34px; }

.btn.is-loading { color: transparent !important; pointer-events: none; }
.btn.is-loading::after {
  content: ""; position: absolute; width: 17px; height: 17px; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent; opacity: .0;
  animation: spin calc(var(--fc-m-slow) * 1.1) linear infinite, fadeIn var(--fc-m-quick) forwards;
  color: #fff;
}
.btn--ghost.is-loading::after, .btn--glass.is-loading::after, .btn--quiet.is-loading::after { color: var(--txt-1); }
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes fadeIn { to { opacity: 1; } }

/* Ripple */
.ripple {
  position: absolute; border-radius: 50%; transform: scale(0);
  background: rgba(255,255,255,.42); pointer-events: none;
  animation: ripple var(--fc-m-slow) var(--fc-ease-out) forwards;
}
.btn--ghost .ripple, .btn--glass .ripple, .btn--quiet .ripple { background: rgba(120,140,110,.28); }
@keyframes ripple { to { transform: scale(2.6); opacity: 0; } }

/* --------------------------------------------------------------- SEGMENTED */
.seg { display: inline-flex; padding: 3px; gap: 2px; border-radius: var(--fc-r-pill); background: var(--on-glass-chip); }
.seg button {
  padding: 8px var(--fc-s-4); border-radius: var(--fc-r-pill); font-size: var(--fc-t-sm);
  font-weight: var(--fc-w-medium); color: var(--txt-2); white-space: nowrap;
  transition: color var(--fc-m-fast) var(--fc-ease-out), background var(--fc-m-fast) var(--fc-ease-out);
}
.seg button[aria-selected="true"] {
  background: var(--glass-fill-hard); color: var(--txt-1); font-weight: var(--fc-w-semi);
  box-shadow: 0 1px 3px rgba(0,0,0,.12);
}
[data-surface="night"] .seg button[aria-selected="true"] { background: rgba(255,255,255,.13); }

/* -------------------------------------------------------------------- CHIP */
.chip {
  display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 var(--fc-s-3);
  border-radius: var(--fc-r-pill); font-size: var(--fc-t-sm); font-weight: var(--fc-w-medium);
  background: var(--on-glass-chip); color: var(--txt-2); border: 1px solid transparent;
  transition-property: var(--fc-tx); transition-duration: var(--fc-m-fast); transition-timing-function: var(--fc-ease-out); white-space: nowrap;
}
.chip:hover { color: var(--txt-1); }
.chip[aria-pressed="true"], .chip.is-on {
  background: var(--fc-green-600); color: var(--accent-ink); border-color: transparent;
  box-shadow: 0 4px 12px -4px rgba(94,158,30,.6);
}
.chip--sm { height: 26px; font-size: var(--fc-t-xs); padding: 0 10px; }

/* ------------------------------------------------------------------- BADGE */
.badge {
  display: inline-flex; align-items: center; gap: 4px; padding: 3px 8px;
  border-radius: var(--fc-r-xs); font-size: var(--fc-t-2xs); font-weight: var(--fc-w-bold);
  letter-spacing: .05em; text-transform: uppercase; line-height: 1.35;
}
.badge--eat-today  { background: rgba(232,162,28,.16); color: var(--ink-on-warn); }
.badge--eat-soon   { background: rgba(140,198,63,.20); color: var(--ink-on-green); }
.badge--ripen-home { background: rgba(76,155,209,.16); color: var(--ink-on-blue); }
.badge--fresh      { background: rgba(31,168,91,.16); color: var(--ink-on-green); }
.badge--premium    { background: rgba(200,155,60,.18); color: var(--ink-on-gold); }
.badge--danger     { background: rgba(224,54,44,.14); color: var(--fc-red-700); }
.badge--info       { background: rgba(62,143,208,.15); color: var(--ink-on-info); }
.badge--neutral    { background: var(--on-glass-chip); color: var(--txt-2); }
.badge--solid      { background: var(--fc-ink-900); color: #fff; }
[data-surface="night"] .badge--eat-today  { background: rgba(232,162,28,.20); color: var(--ink-on-warn); }
[data-surface="night"] .badge--eat-soon   { background: rgba(140,198,63,.18); color: var(--fc-green-300); }
[data-surface="night"] .badge--ripen-home { background: rgba(76,155,209,.20); color: var(--ink-on-blue); }
[data-surface="night"] .badge--fresh      { background: rgba(31,168,91,.20); color: var(--ink-on-green); }
[data-surface="night"] .badge--premium    { background: rgba(200,155,60,.20); color: var(--ink-on-gold); }
[data-surface="night"] .badge--danger     { background: rgba(224,54,44,.20); color: var(--fc-red-400); }
[data-surface="night"] .badge--info       { background: rgba(62,143,208,.20); color: var(--ink-on-info); }
[data-surface="night"] .badge--solid      { background:#fff; color: var(--fc-ink-900); }

/* Ripeness dot — state must not rely on colour alone (a11y) */
.rip { display:inline-flex; align-items:center; gap: 5px; font-size:var(--fc-t-2xs); font-weight:var(--fc-w-bold); letter-spacing:.04em; text-transform:uppercase; }
.rip i { width:8px; height:8px; border-radius:50%; flex:none; position:relative; }
.rip i::after { content:""; position:absolute; inset:2px; border-radius:50%; background:rgba(255,255,255,.9); }
.rip--today i { background: var(--fc-eat-today); }
.rip--soon  i { background: var(--fc-eat-soon); }
.rip--soon  i::after { inset:0; background:none; }
.rip--home  i { background: var(--fc-ripen-home); }
.rip--home  i::after { inset:2.5px; }

/* Counter pill (cart badge, notifications) */
.count {
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: 99px;
  background: var(--fc-red-500); color: #fff; font-size: var(--fc-t-2xs);
  font-weight: var(--fc-w-bold); display: inline-grid; place-items: center;
  box-shadow: 0 0 0 2px var(--bg-base);
}
.count--pop { animation: countPop var(--fc-m-medium) var(--fc-ease-spring); }
@keyframes countPop { 0%{transform:scale(.4)} 60%{transform:scale(1.28)} 100%{transform:scale(1)} }

/* ------------------------------------------------------------------- INPUT */
.field { display: block; }
.field > label, .lbl {
  display: block; font-size: var(--fc-t-xs); font-weight: var(--fc-w-semi);
  color: var(--txt-2); margin-bottom: 6px; letter-spacing: .02em;
}
.input, .select, .textarea {
  width: 100%; min-height: var(--fc-tap); padding: 12px var(--fc-s-4);
  border-radius: var(--fc-r-md); border: 1px solid var(--line);
  background: var(--field); color: var(--txt-1); font-size: var(--fc-t-md);
  transition: border-color var(--fc-m-fast) var(--fc-ease-out), box-shadow var(--fc-m-fast) var(--fc-ease-out), background var(--fc-m-fast) var(--fc-ease-out);
  -webkit-appearance: none; appearance: none;
}
.textarea { min-height: 92px; resize: vertical; line-height: var(--fc-lh-base); }
.select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%237C8B71' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center; padding-right: 34px;
}
.input:focus, .select:focus, .textarea:focus {
  outline: none; border-color: var(--fc-green-500);
  box-shadow: 0 0 0 3px rgba(140,198,63,.22);
}
.input::placeholder, .textarea::placeholder { color: var(--txt-3); }
.input:disabled, .select:disabled, .textarea:disabled { opacity: .5; cursor: not-allowed; }
.field.is-error .input, .field.is-error .select, .field.is-error .textarea {
  border-color: var(--fc-danger); box-shadow: 0 0 0 3px rgba(224,54,44,.14);
}
.field .msg { font-size: var(--fc-t-xs); margin-top: 5px; color: var(--txt-3); }
.field.is-error .msg { color: var(--fc-danger); font-weight: var(--fc-w-medium); }
.field.is-ok .input { border-color: var(--fc-success); }
.input-group { position: relative; }
.input-group .input { padding-left: 42px; }
.input-group > .ig-icon {
  position: absolute; left: 14px; top: 50%; transform: translateY(-50%);
  color: var(--txt-3); pointer-events: none;
}
.input-group > .ig-end { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); }

/* Checkbox / radio / switch */
.check { display: flex; align-items: flex-start; gap: 10px; cursor: pointer; padding: 6px 0; }
/* Without min-width:0 a flex child refuses to shrink below its content, so a
   long identifier runs straight under the switch. */
.check > .grow { min-width: 0; overflow-wrap: anywhere; }
.check > .grow > * { overflow-wrap: anywhere; }
.check input { position: absolute; opacity: 0; width: 0; height: 0; }
.check .box {
  width: 21px; height: 21px; border-radius: 7px; border: 1.8px solid var(--line);
  background: var(--field); flex: none; display: grid; place-items: center;
  transition-property: var(--fc-tx); transition-duration: var(--fc-m-fast); transition-timing-function: var(--fc-ease-out); margin-top: 1px;
}
.check input:checked + .box { background: var(--fc-green-600); border-color: var(--fc-green-600); }
.check input:checked + .box::after {
  content: ""; width: 10px; height: 6px; border: 2px solid var(--accent-ink); border-top: 0; border-right: 0;
  transform: rotate(-45deg) translate(1px,-1px);
}
.check input:focus-visible + .box { outline: 2px solid var(--focus); outline-offset: 2px; }
.check--radio .box { border-radius: 50%; }
.check--radio input:checked + .box::after {
  content:""; width:9px; height:9px; border:0; border-radius:50%; background:var(--accent-ink); transform:none;
}
.switch { width: 46px; height: 27px; border-radius: 99px; background: var(--line); position: relative; flex: none; transition: background var(--fc-m-quick) var(--fc-ease-out); }
.switch::after {
  content:""; position:absolute; top:3px; left:3px; width:21px; height:21px; border-radius:50%;
  background:#fff; box-shadow: 0 1px 4px rgba(0,0,0,.28);
  transition: transform var(--fc-m-quick) var(--fc-ease-spring);
}
.check input:focus-visible ~ .switch { outline: 2px solid var(--focus); outline-offset: 2px; }
.check input:checked ~ .switch { background: var(--fc-green-600); }
.check input:checked ~ .switch::after { transform: translateX(19px); }

/* OTP input */
.otp { display: flex; gap: 10px; justify-content: center; }
.otp input {
  width: 48px; height: 58px; text-align: center; font-size: var(--fc-t-2xl);
  font-weight: var(--fc-w-bold); border-radius: var(--fc-r-md);
  border: 1.5px solid var(--line); background: var(--field); color: var(--txt-1);
  transition-property: var(--fc-tx); transition-duration: var(--fc-m-fast); transition-timing-function: var(--fc-ease-out); font-variant-numeric: tabular-nums;
}
.otp input:focus { outline:none; border-color: var(--fc-green-500); box-shadow: 0 0 0 4px rgba(140,198,63,.2); transform: translateY(-2px); }
.otp.is-error input { border-color: var(--fc-danger); animation: shake calc(var(--fc-m-medium) * 1.25); }
.otp.is-ok input { border-color: var(--fc-success); background: rgba(31,168,91,.08); }
@keyframes shake { 10%,90%{transform:translateX(-2px)} 20%,80%{transform:translateX(4px)} 30%,50%,70%{transform:translateX(-7px)} 40%,60%{transform:translateX(7px)} }

/* Search bar */
.searchbar {
  display: flex; align-items: center; gap: 10px; height: 46px; padding: 0 var(--fc-s-4);
  border-radius: var(--fc-r-md); background: var(--glass-fill-hard);
  border: 1px solid var(--glass-stroke); box-shadow: var(--glass-shadow);
  -webkit-backdrop-filter: blur(16px) saturate(160%); backdrop-filter: blur(16px) saturate(160%);
}
.searchbar input { flex: 1 1 auto; border: 0; background: none; outline: none; min-width: 0; font-size: var(--fc-t-md); }
/* the input drops its own outline, so the bar carries the ring instead */
.searchbar:focus-within { outline: 2px solid var(--focus); outline-offset: 2px; }
.searchbar input::placeholder { color: var(--txt-3); }

/* ------------------------------------------------------------------- CARD */
.card { border-radius: var(--fc-r-lg); padding: var(--fc-s-4); }
.card--tap { transition: transform var(--fc-m-fast) var(--fc-ease-out), box-shadow var(--fc-m-fast) var(--fc-ease-out); cursor: pointer; }
.card--tap:active { transform: scale(var(--fc-press)); }
.card--tap:hover { box-shadow: var(--glass-shadow-lg); }
.card-head { display:flex; align-items:center; justify-content:space-between; gap: var(--fc-s-3); margin-bottom: var(--fc-s-3); }
.card-title { font-size: var(--fc-t-md); font-weight: var(--fc-w-semi); letter-spacing:-.01em; }

/* Section header */
.sec-head { display:flex; align-items:flex-end; justify-content:space-between; gap: var(--fc-s-3); padding: var(--fc-s-6) 0 var(--fc-s-3); }
.sec-head h2 { font-size: var(--fc-t-xl); font-weight: var(--fc-w-bold); letter-spacing:-.02em; line-height:1.2; }
.sec-head .sub { font-size: var(--fc-t-sm); color: var(--txt-3); margin-top: 3px; }
.sec-head a, .sec-head button.link {
  font-size: var(--fc-t-sm); font-weight: var(--fc-w-semi); color: var(--accent);
  white-space: nowrap; position: relative; padding: var(--fc-s-2) 0 var(--fc-s-2) var(--fc-s-3);
}
.sec-head a::after, .sec-head button.link::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: max(100%, 44px); height: 44px; transform: translate(-50%, -50%);
}
/* Inline text buttons everywhere get the same treatment. */
button.link { position: relative; padding: var(--fc-s-2) 0; }
button.link::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: max(100%, 44px); height: 44px; transform: translate(-50%, -50%);
}
/* Icon buttons that sit inside a field or bar keep their small visual box
   but claim the full 44px band around it. */
.searchbar .btn--icon, .input-group .btn--icon { position: relative; }
.searchbar .btn--icon::after, .input-group .btn--icon::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 44px; height: 44px; transform: translate(-50%, -50%);
}

/* ----------------------------------------------------------- PRODUCT CARD */
.pcard {
  display: flex; flex-direction: column; text-align: left; position: relative;
  border-radius: var(--fc-r-lg); padding: var(--fc-s-2) var(--fc-s-2) var(--fc-s-3);
  transition: transform var(--fc-m-fast) var(--fc-ease-out), box-shadow var(--fc-m-quick) var(--fc-ease-out);
  cursor: pointer; overflow: hidden;
}
.pcard:active { transform: scale(var(--fc-press)); }
.pcard:hover { box-shadow: var(--glass-shadow-lg); }
.pcard-img {
  position: relative; border-radius: var(--fc-r-md); overflow: hidden;
  aspect-ratio: 1/1; background: #fff; margin-bottom: 10px;
}
[data-surface="night"] .pcard-img { background: rgba(255,255,255,.07); }
/* Photographs are shot on a plain ground, so they are contained rather than
   cropped — cropping a banana on white just shows the white. The card's own
   ground is white so a photo's backdrop blends into it and a generated
   illustration sits on exactly the same surface. */
.pcard-img img {
  width: 100%; height: 100%; object-fit: contain; padding: 8%;
  transition: transform var(--fc-m-medium) var(--fc-ease-out);
}
.pcard-img img.is-photo { padding: 4%; }
.pcard:hover .pcard-img img { transform: scale(1.06) rotate(-1.5deg); }
.pcard-flag { position: absolute; top: 6px; left: 6px; z-index: 2; }
.pcard-tags {
  position: absolute; left: 5px; right: 5px; bottom: 5px; z-index: 2;
  display: flex; flex-wrap: wrap-reverse; gap: 4px; justify-content: space-between;
}
.pcard-tags > * { max-width: 100%; }
.pcard-save { position: absolute; top: 5px; right: 5px; z-index: 2; width: 30px; height: 30px; border-radius: 50%;
  background: var(--glass-fill-hard); display: grid; place-items: center; color: var(--txt-3);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); transition-property: var(--fc-tx); transition-duration: var(--fc-m-fast); transition-timing-function: var(--fc-ease-out); }
.pcard-save.is-on { color: var(--fc-red-500); }
.pcard-save:hover { transform: scale(1.1); }
.pcard-name { font-size: var(--fc-t-sm); font-weight: var(--fc-w-semi); line-height: 1.28; letter-spacing: -.005em; }
/* The name is the card's control. The card itself is not a button, so the
   price, unit, discount and low-stock badge stay readable content instead
   of being swallowed by one widget's accessible name. */
button.pcard-name { text-align: left; width: 100%; position: relative; }
/* The name is the card's control (see productCard: a widget role on the whole
   card swallowed the price, the unit and the badges into one accessible name).
   One line of 12.5px type is a 16px-tall target, though, and on the home rails
   most names are one line. Claim the band around it the way every other inline
   text button here does — the visual box is unchanged, the thumb gets 44px. */
button.pcard-name::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 100%; height: 44px; transform: translate(-50%, -50%);
}
.pcard-meta { font-size: var(--fc-t-xs); color: var(--txt-3); margin-top: 2px; }
.pcard-foot { display: flex; align-items: flex-end; justify-content: space-between; gap: 6px; margin-top: 8px; }
/* A 2-up card at 360px gives the footer 140px, but the price (86px) plus the
   gap plus the ADD button (76px min) needs 168px. They cannot share a line, so
   the price is allowed to wrap and — on a genuinely narrow card — the control
   takes its own full-width row. The query is on the CARD, not the viewport,
   because the same card is narrow inside a rail at any screen size. */
.pcard { container-type: inline-size; }
.pcard-foot > .price { min-width: 0; flex: 1 1 auto; }
.pcard-foot > *:last-child { flex: 0 0 auto; }
@container (max-width: 178px) {
  .pcard-foot { flex-direction: column; align-items: stretch; gap: 8px; }
  .pcard-foot > .addbtn, .pcard-foot > .qty { width: 100%; }
}
.pcard-oos::after {
  content: ""; position: absolute; inset: 0; background: var(--glass-fill-hard); opacity: .55;
  border-radius: inherit; pointer-events: none;
}
.price { display: flex; align-items: baseline; gap: 5px; flex-wrap: wrap; min-width: 0; }
.price b { font-size: var(--fc-t-lg); font-weight: var(--fc-w-bold); letter-spacing: -.03em; }
.price s { font-size: var(--fc-t-xs); color: var(--txt-3); }
.price .off { font-size: var(--fc-t-2xs); font-weight: var(--fc-w-bold); color: var(--fc-green-700); }
[data-surface="night"] .price .off { color: var(--fc-green-400); }

/* Add button / quantity stepper (the money control) */
.addbtn {
  min-width: 68px; height: 34px; border-radius: var(--fc-r-sm); font-size: var(--fc-t-sm);
  font-weight: var(--fc-w-bold); letter-spacing: .02em; border: 1.4px solid var(--fc-green-600);
  color: var(--fc-green-700); background: var(--glass-fill-hard);
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  transition-property: var(--fc-tx); transition-duration: var(--fc-m-fast); transition-timing-function: var(--fc-ease-out); position: relative;
}
[data-surface="night"] .addbtn { color: var(--fc-green-300); border-color: var(--fc-green-600); background: rgba(140,198,63,.08); }
.addbtn:hover { background: var(--fc-green-600); color: var(--accent-ink); }
.addbtn:active { transform: scale(var(--fc-press)); }
/* overflow is visible, not hidden: the 44px hit expanders on the two buttons
   have to be able to reach outside the 34px band, or the stepper's real tap
   target is only as big as it looks. The rounded band is kept by rounding the
   end buttons instead of clipping the container. */
.qty {
  display: inline-flex; align-items: center; height: 34px; min-width: 96px;
  border-radius: var(--fc-r-sm); background: var(--fc-green-600); color: var(--accent-ink);
  font-weight: var(--fc-w-bold); box-shadow: 0 4px 12px -4px rgba(94,158,30,.6);
}
.qty button:first-child { border-radius: var(--fc-r-sm) 0 0 var(--fc-r-sm); }
.qty button:last-child  { border-radius: 0 var(--fc-r-sm) var(--fc-r-sm) 0; }
/* flex:0 0 auto — the buttons carry a declared width but were flex items with
   the default shrink factor, so a narrow stepper squeezed them under the
   32px target floor. The declared size is now the real size. */
.qty button { flex: 0 0 auto; width: 32px; height: 100%; display: grid; place-items: center; color: var(--accent-ink); font-size: 17px; transition: background var(--fc-m-fast) var(--fc-ease-out); }
.qty button:hover { background: rgba(0,0,0,.14); }
.qty button:active { background: rgba(0,0,0,.24); }
/* flex:1 is flex:1 1 0% — a zero basis, so the number was squeezed below its
   own width and clipped by the parent's overflow:hidden as soon as the label
   grew past "9" (HoReCa steppers read up to "255 kg"). An auto basis lets the
   control grow past its 90px minimum instead. */
.qty .n { flex: 1 0 auto; text-align: center; padding: 0 4px; font-size: var(--fc-t-sm); font-variant-numeric: tabular-nums; }
.qty--lg { height: 44px; min-width: 120px; }
.qty--lg button { width: 40px; font-size: 20px; }
/* An inset shadow rather than a border: a border is inside the 34px box, so it
   shrank the buttons to 31.2px — under the 32px target floor — on every
   ghost stepper in the wholesale board. A shadow costs no layout. */
.qty--ghost { background: transparent; color: var(--txt-1); box-shadow: inset 0 0 0 1.4px var(--line); }
.qty--ghost button { color: var(--txt-1); }

/* ADD ⇄ stepper share one .vfx-morph wrapper (spec §3.5, ui.qtyControl). A
   one-cell grid: the wrapper is sized by the face that is showing and, mid
   morph, by the larger of the two; a hidden face leaves the grid entirely, so
   the card foot never collapses under an absolutely placed stepper. The
   .vfx-morph.qtyc pair outranks vfx.css's generic placement on purpose. */
/* Both selectors carry the wrapper's two classes: vfx.css (loaded later) sets
   `.vfx-morph { display:inline-block }` at the same specificity as a bare
   `.qtyc`, which would win the cascade and blockify the wrapper inside the
   flex foot — stacking the two faces vertically for the whole morph. */
.qtyc, .vfx-morph.qtyc { display: inline-grid; justify-items: end; align-items: center; position: relative; }
.vfx-morph.qtyc > .addbtn, .vfx-morph.qtyc > .qty, .vfx-morph.qtyc > .badge { grid-area: 1 / 1; position: relative; right: auto; top: auto; }
.vfx-morph.is-stepper.qtyc > .qty { position: relative; }
.vfx-morph.qtyc > [hidden] { display: none !important; }

/* Fly-to-cart particle */
.fly {
  position: fixed; z-index: var(--fc-z-top); width: 44px; height: 44px; border-radius: 50%;
  pointer-events: none; overflow: hidden; background: var(--glass-fill-hard);
  box-shadow: var(--glass-shadow-lg); border: 1px solid var(--glass-stroke);
}
.fly img { width:100%; height:100%; object-fit: contain; padding: 4px; }

/* ------------------------------------------------------------ CATEGORY TILE */
.cat {
  display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center;
  padding: var(--fc-s-3) 4px; border-radius: var(--fc-r-md);
  transition: transform var(--fc-m-fast) var(--fc-ease-out), background var(--fc-m-fast) var(--fc-ease-out);
}
.cat:active { transform: scale(var(--fc-press)); }
.cat:hover { background: var(--on-glass-chip); }
.cat-orb {
  width: 56px; height: 56px; border-radius: 19px; display: grid; place-items: center;
  overflow: hidden; position: relative;
  box-shadow: 0 6px 16px -8px rgba(20,40,14,.4), inset 0 1px 0 rgba(255,255,255,.5);
}
.cat-orb img { width: 78%; height: 78%; object-fit: contain; }
.cat-orb img.is-photo { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
.cat-orb img.fc3d-still { width: 88%; height: 88%; object-fit: contain; }
.cat span { font-size: var(--fc-t-xs); font-weight: var(--fc-w-medium); line-height: 1.25; color: var(--txt-2); }

/* --------------------------------------------------------------- LIST ROW */
.lrow {
  display: flex; align-items: center; gap: var(--fc-s-3); padding: var(--fc-s-3) var(--fc-s-4);
  border-radius: var(--fc-r-md); transition: background var(--fc-m-fast) var(--fc-ease-out); width: 100%; text-align: left;
}
.lrow:hover { background: var(--on-glass-chip); }
.lrow + .lrow { box-shadow: 0 -1px 0 var(--line-soft); }
.lrow-ic { width: 38px; height: 38px; border-radius: 12px; display: grid; place-items: center; flex: none; background: var(--on-glass-chip); color: var(--txt-2); }
.lrow-tt { font-size: var(--fc-t-md); font-weight: var(--fc-w-medium); overflow-wrap: anywhere; }
.lrow-sb { font-size: var(--fc-t-xs); color: var(--txt-3); margin-top: 1px; }

/* ---------------------------------------------------------------- SHEET */
.scrim {
  position: fixed; inset: 0; background: var(--scrim); z-index: var(--fc-z-sheet);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  animation: scrimIn var(--fc-m-medium) var(--fc-ease-out);
}
.scrim.is-out { animation: scrimOut var(--fc-m-quick) var(--fc-ease-in) forwards; }
@keyframes scrimIn { from { opacity: 0 } }
@keyframes scrimOut { to { opacity: 0 } }

.sheet {
  position: fixed; left: 50%; bottom: 0; transform: translateX(-50%);
  width: 100%; max-width: var(--fc-shell-max); z-index: var(--fc-z-sheet);
  border-radius: var(--fc-r-2xl) var(--fc-r-2xl) 0 0;
  background: var(--glass-fill-hard); border: 1px solid var(--glass-stroke); border-bottom: 0;
  -webkit-backdrop-filter: blur(28px) saturate(180%); backdrop-filter: blur(28px) saturate(180%);
  box-shadow: var(--glass-shadow-lg);
  max-height: 92dvh; display: flex; flex-direction: column;
  animation: sheetIn var(--fc-m-medium) var(--fc-ease-out);
  padding-bottom: var(--fc-safe-bot);
}
body.framed .sheet { position: absolute; }
.sheet.is-out { animation: sheetOut var(--fc-m-quick) var(--fc-ease-in) forwards; }
@keyframes sheetIn { from { transform: translate(-50%, 100%); } }
@keyframes sheetOut { to { transform: translate(-50%, 100%); } }
.sheet-grip { width: 38px; height: 4px; border-radius: 99px; background: var(--line); margin: 10px auto 4px; flex: none; }
.sheet-head { padding: var(--fc-s-2) var(--fc-s-4) var(--fc-s-3); display: flex; align-items: center; justify-content: space-between; gap: var(--fc-s-3); flex: none; }
.sheet-head h3 { font-size: var(--fc-t-xl); font-weight: var(--fc-w-bold); letter-spacing: -.02em; }
.sheet-body { padding: 0 var(--fc-s-4) var(--fc-s-5); overflow-y: auto; flex: 1 1 auto; }
.sheet-foot { padding: var(--fc-s-3) var(--fc-s-4) var(--fc-s-5); border-top: 1px solid var(--line-soft); flex: none; }
.sheet--full { max-height: 100dvh; height: 100dvh; border-radius: 0; }

/* Modal (desktop-leaning surfaces) */
.modal {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%,-50%);
  z-index: var(--fc-z-modal); width: min(560px, calc(100vw - 32px)); max-height: 88dvh;
  border-radius: var(--fc-r-xl); background: var(--glass-fill-hard);
  border: 1px solid var(--glass-stroke); box-shadow: var(--glass-shadow-lg);
  -webkit-backdrop-filter: blur(28px) saturate(180%); backdrop-filter: blur(28px) saturate(180%);
  display: flex; flex-direction: column; animation: modalIn var(--fc-m-medium) var(--fc-ease-spring);
}
@keyframes modalIn { from { transform: translate(-50%,-46%) scale(.94); opacity: 0; } }
.modal.is-out { animation: modalOut var(--fc-m-quick) var(--fc-ease-in) forwards; }
@keyframes modalOut { to { transform: translate(-50%,-52%) scale(.96); opacity: 0; } }
.modal--wide { width: min(1000px, calc(100vw - 32px)); }

/* --------------------------------------------------------------- TOAST */
.toaster {
  position: fixed; left: 50%; transform: translateX(-50%); bottom: calc(84px + var(--fc-safe-bot));
  z-index: var(--fc-z-toast); display: flex; flex-direction: column-reverse; gap: 8px;
  width: min(calc(100% - 28px), 420px); pointer-events: none;
}
body.framed .toaster { position: absolute; }
.toast {
  display: flex; align-items: center; gap: 10px; padding: 12px var(--fc-s-4);
  border-radius: var(--fc-r-md); background: var(--glass-fill-hard);
  border: 1px solid var(--glass-stroke); box-shadow: var(--glass-shadow-lg);
  -webkit-backdrop-filter: blur(20px) saturate(170%); backdrop-filter: blur(20px) saturate(170%);
  font-size: var(--fc-t-sm); font-weight: var(--fc-w-medium); pointer-events: auto;
  animation: toastIn var(--fc-m-medium) var(--fc-ease-spring);
}
@keyframes toastIn { from { transform: translateY(16px) scale(.94); opacity: 0; } }
.toast.is-out { animation: toastOut var(--fc-m-quick) var(--fc-ease-in) forwards; }
@keyframes toastOut { to { transform: translateY(8px); opacity: 0; } }
.toast-ic { width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; flex: none; color: #fff; }
.toast--ok .toast-ic { background: var(--fc-success); }
.toast--err .toast-ic { background: var(--fc-danger); }
.toast--info .toast-ic { background: var(--fc-info); }
.toast--warn .toast-ic { background: var(--fc-warn); }
.toast button.act { margin-left: auto; color: var(--accent); font-weight: var(--fc-w-bold); font-size: var(--fc-t-sm); flex: none; }
/* "Can I undo?" — the undo action reads as a pill, not a link. */
.toast--undo button.act--undo { padding: var(--fc-s-2) var(--fc-s-3); border-radius: var(--fc-r-pill); background: var(--on-glass-chip); color: var(--txt-1); }
.toast--undo button.act--undo:active { transform: scale(var(--fc-press)); }
/* "How long is this here?" — a hairline drains left-to-right (scaleX, WAAPI). */
.toast { position: relative; overflow: hidden; z-index: 1; will-change: transform; }
.toast-bar { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--accent); opacity: .7; transform-origin: left center; }
.toast--err .toast-bar { background: var(--fc-danger); }
.toast--warn .toast-bar { background: var(--fc-warn); }
.toast.is-held { animation: none; transition: none; cursor: grabbing; }
/* The stack: newest in front at identity, the two behind tuck under it. */
.toast.is-behind { position: absolute; left: 0; right: 0; bottom: 0; z-index: 0; pointer-events: none;
  transform: translateY(calc(var(--toast-depth, 1) * -8px)) scale(calc(1 - var(--toast-depth, 1) * .04));
  opacity: calc(1 - var(--toast-depth, 1) * .3);
  transition: transform var(--fc-m-quick) var(--fc-ease-out), opacity var(--fc-m-quick) var(--fc-ease-out); }

/* ------------------------------------------------------------- SKELETON */
.sk { border-radius: var(--fc-r-sm); background: var(--on-glass-chip); position: relative; overflow: hidden; }
.sk::after {
  content: ""; position: absolute; inset: 0; transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.5), transparent);
  animation: shimmer calc(var(--fc-m-epic) * 1.25) infinite;
}
[data-surface="night"] .sk::after { background: linear-gradient(90deg, transparent, rgba(255,255,255,.08), transparent); }
@keyframes shimmer { 100% { transform: translateX(100%); } }
.sk-line { height: 11px; }
.sk-line.w-60 { width: 60%; } .sk-line.w-40 { width: 40%; } .sk-line.w-80 { width: 80%; }
.sk-sq { aspect-ratio: 1/1; border-radius: var(--fc-r-md); }
.sk-circle { border-radius: 50%; }

/* Loading with a reason — never a naked spinner */
.loading { display: flex; flex-direction: column; align-items: center; gap: var(--fc-s-4); padding: var(--fc-s-10) var(--fc-s-5); text-align: center; }
.loading-ring { width: 42px; height: 42px; border-radius: 50%; border: 2.5px solid var(--line); border-top-color: var(--accent); animation: spin calc(var(--fc-m-slow) * 1.4) linear infinite; }
.loading p { font-size: var(--fc-t-sm); color: var(--txt-2); font-weight: var(--fc-w-medium); }
.progress { height: 5px; border-radius: 99px; background: var(--on-glass-chip); overflow: hidden; }
.progress > i { display: block; height: 100%; border-radius: 99px; background: linear-gradient(90deg, var(--fc-green-500), var(--fc-green-700)); transition: width var(--fc-m-medium) var(--fc-ease-out); }
.progress--indet > i { width: 38%; animation: indet calc(var(--fc-m-epic) * 1.15) var(--fc-ease) infinite; }
@keyframes indet { 0%{margin-left:-40%} 100%{margin-left:100%} }

/* ------------------------------------------------------- EMPTY / ERROR */
.state { display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--fc-s-3); padding: var(--fc-s-9) var(--fc-s-6); }
.state-art { width: 108px; height: 108px; margin-bottom: 2px; opacity: .96; }
.state-art--ic { display: grid; place-items: center; border-radius: 50%; background: var(--on-glass-chip); color: var(--txt-3); }
.state h3 { font-size: var(--fc-t-lg); font-weight: var(--fc-w-bold); letter-spacing: -.01em; }
.state p { font-size: var(--fc-t-sm); color: var(--txt-2); max-width: 34ch; line-height: var(--fc-lh-loose); }
.state .btn { margin-top: var(--fc-s-2); }

/* --------------------------------------------------------------- TIMELINE */
.tl { position: relative; padding-left: 30px; }
.tl::before { content:""; position:absolute; left:10px; top:8px; bottom:12px; width:2px; background: var(--line); border-radius:2px; }
.tl-item { position: relative; padding-bottom: var(--fc-s-5); }
.tl-item:last-child { padding-bottom: 0; }
.tl-dot {
  position: absolute; left: -30px; top: 1px; width: 21px; height: 21px; border-radius: 50%;
  background: var(--bg-base); border: 2px solid var(--line); display: grid; place-items: center;
  color: var(--txt-3); z-index: 1;
}
.tl-item.is-done .tl-dot { background: var(--fc-green-600); border-color: var(--fc-green-600); color: #fff; }
.tl-item.is-now .tl-dot { background: var(--fc-green-600); border-color: var(--fc-green-600); color: #fff; box-shadow: 0 0 0 0 rgba(140,198,63,.6); animation: pulse calc(var(--fc-m-epic) * 1.7) infinite; }
.tl-item.is-fail .tl-dot { background: var(--fc-danger); border-color: var(--fc-danger); color:#fff; }
@keyframes pulse { 70% { box-shadow: 0 0 0 11px rgba(140,198,63,0); } 100% { box-shadow: 0 0 0 0 rgba(140,198,63,0); } }
.tl-item.is-done::before, .tl-item.is-now::before {
  content:""; position:absolute; left:-20.5px; top:8px; height:100%; width:2px; background: var(--fc-green-600); z-index:0;
}
.tl-item:last-child::before { display: none; }
.tl-t { font-size: var(--fc-t-md); font-weight: var(--fc-w-semi); line-height: 1.3; }
.tl-s { font-size: var(--fc-t-xs); color: var(--txt-3); margin-top: 2px; }
.tl-item:not(.is-done):not(.is-now) .tl-t { color: var(--txt-3); font-weight: var(--fc-w-regular); }

/* ---------------------------------------------------------------- TABLE */
.tbl-wrap { overflow-x: auto; border-radius: var(--fc-r-md); }
.tbl { font-size: var(--fc-t-sm); min-width: 100%; }
.tbl th {
  text-align: left; font-size: var(--fc-t-2xs); font-weight: var(--fc-w-bold);
  text-transform: uppercase; letter-spacing: .07em; color: var(--txt-3);
  padding: 10px var(--fc-s-3); white-space: nowrap; border-bottom: 1px solid var(--line);
  position: sticky; top: 0; background: var(--glass-fill-hard);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); z-index: 1;
}
.tbl td { padding: 12px var(--fc-s-3); border-bottom: 1px solid var(--line-soft); vertical-align: middle; }
.tbl tbody tr { transition: background var(--fc-m-fast) var(--fc-ease-out); }
.tbl tbody tr:hover { background: var(--on-glass-chip); }
.tbl tbody tr:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; background: var(--on-glass-chip); }
.tbl tbody tr.is-sel { background: rgba(140,198,63,.12); }
.tbl .num, .tbl .ta-r { text-align: right; font-variant-numeric: tabular-nums; }
.tbl-compact td, .tbl-compact th { padding: 8px 10px; }

/* ------------------------------------------------------------------ KPI */
.kpi { padding: var(--fc-s-4); border-radius: var(--fc-r-lg); }
.kpi .k-lbl { font-size: var(--fc-t-2xs); text-transform: uppercase; letter-spacing: .08em; color: var(--txt-3); font-weight: var(--fc-w-bold); }
.kpi .k-val { font-size: var(--fc-t-3xl); font-weight: var(--fc-w-bold); letter-spacing: -.035em; margin-top: 6px; line-height: 1; font-variant-numeric: tabular-nums; }
.kpi .k-delta { font-size: var(--fc-t-xs); font-weight: var(--fc-w-semi); margin-top: 8px; display: inline-flex; align-items: center; gap: 3px; }
.kpi .k-delta.up { color: var(--fc-success); }
.kpi .k-delta.down { color: var(--fc-danger); }
.kpi .k-spark { margin-top: 10px; height: 30px; }

/* --------------------------------------------------------------- NAV BAR */
.topbar {
  position: sticky; top: 0; z-index: var(--fc-z-nav); flex: none;
  padding: calc(var(--fc-safe-top) + 10px) var(--fc-s-4) 10px;
  background: var(--glass-fill); border-bottom: 1px solid var(--glass-stroke-lo);
  -webkit-backdrop-filter: blur(22px) saturate(170%); backdrop-filter: blur(22px) saturate(170%);
}
.topbar--plain { background: transparent; border-bottom: 0; -webkit-backdrop-filter: none; backdrop-filter: none; }
.topbar h1 { font-size: var(--fc-t-lg); font-weight: var(--fc-w-bold); letter-spacing: -.02em; }

.tabbar {
  position: sticky; bottom: 0; z-index: var(--fc-z-nav); flex: none;
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  padding: 8px 6px calc(8px + var(--fc-safe-bot));
  background: var(--glass-fill-hard); border-top: 1px solid var(--glass-stroke-lo);
  -webkit-backdrop-filter: blur(26px) saturate(180%); backdrop-filter: blur(26px) saturate(180%);
}
.tabbtn {
  display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 5px 2px;
  color: var(--txt-3); border-radius: var(--fc-r-sm); position: relative;
  transition: color var(--fc-m-fast) var(--fc-ease-out); min-height: 50px; justify-content: center;
}
.tabbtn span { font-size: var(--fc-t-2xs); font-weight: var(--fc-w-medium); letter-spacing: .01em; }
.tabbtn[aria-current="page"] { color: var(--accent); }
.tabbtn[aria-current="page"] span { font-weight: var(--fc-w-bold); }
/* "Which tab is active?" — each icon has its own gesture (Blinkit E30), on
   mount and again on every select (.is-hit, cleared on animationend). All
   settle at identity; colour and weight carry the state when nothing moves. */
.tabbtn[aria-current="page"] .ti, .tabbtn.is-hit .ti { animation: tabPop var(--fc-m-medium) var(--fc-ease-spring); }
.tabbtn[data-tab="home"][aria-current="page"] .ti, .tabbtn[data-tab="home"].is-hit .ti { animation-name: tabHome; animation-duration: var(--fc-m-slow); }
.tabbtn[data-tab="shop"][aria-current="page"] .ti, .tabbtn[data-tab="shop"].is-hit .ti,
.tabbtn[data-tab="categories"][aria-current="page"] .ti, .tabbtn[data-tab="categories"].is-hit .ti,
.tabbtn[data-tab="catalogue"][aria-current="page"] .ti, .tabbtn[data-tab="catalogue"].is-hit .ti { animation-name: tabTurn; }
.tabbtn[data-tab="cart"][aria-current="page"] .ti, .tabbtn[data-tab="cart"].is-hit .ti { animation-name: tabSquash; }
.tabbtn[data-tab="account"][aria-current="page"] .ti, .tabbtn[data-tab="account"].is-hit .ti { animation-name: tabPop; }
@keyframes tabPop    { 0%{transform:scale(.8) translateY(2px)} 55%{transform:scale(1.16)} 100%{transform:none} }
@keyframes tabHome   { 0%{transform:none} 35%{transform:translateY(-5px) scale(1.08)} 65%{transform:translateY(1px) scale(.98)} 100%{transform:none} }
@keyframes tabTurn   { 0%{transform:scale(.9)} 50%{transform:rotate(-16deg) scale(1.14)} 100%{transform:none} }
@keyframes tabSquash { 0%{transform:none} 35%{transform:scale(1.18, .84)} 65%{transform:scale(.94, 1.08)} 100%{transform:none} }
.tabbtn .badge-dot { position:absolute; top:4px; right: calc(50% - 17px); }

/* Sidebar (admin / command center) */
.sidebar {
  width: 236px; flex: none; padding: var(--fc-s-4) var(--fc-s-3);
  border-right: 1px solid var(--line-soft); overflow-y: auto;
  display: flex; flex-direction: column; gap: 2px;
}
.side-sec { font-size: var(--fc-t-2xs); text-transform: uppercase; letter-spacing: .1em; color: var(--txt-3); font-weight: var(--fc-w-bold); padding: var(--fc-s-4) var(--fc-s-3) 6px; }
.side-item {
  display: flex; align-items: center; gap: 10px; padding: 8px var(--fc-s-3); border-radius: var(--fc-r-sm);
  font-size: var(--fc-t-sm); font-weight: var(--fc-w-medium); color: var(--txt-2); width: 100%; text-align: left;
  transition: background var(--fc-m-fast) var(--fc-ease-out), color var(--fc-m-fast) var(--fc-ease-out);
}
.side-item:hover { background: var(--on-glass-chip); color: var(--txt-1); }
.side-item[aria-current="page"] { background: var(--fc-green-600); color: var(--accent-ink); font-weight: var(--fc-w-semi); box-shadow: 0 4px 14px -6px rgba(94,158,30,.8); }
.side-item .tail { margin-left: auto; font-size: var(--fc-t-2xs); opacity: .8; }
.side-item:disabled,
.side-item[aria-disabled="true"] { opacity: .34; cursor: not-allowed; }
.side-item[aria-disabled="true"]:hover { background: none; color: var(--txt-2); }

/* Sticky action bar (cart / checkout) */
.actionbar {
  position: sticky; bottom: 0; z-index: calc(var(--fc-z-nav) + 1); flex: none;
  padding: var(--fc-s-3) var(--fc-s-4) calc(var(--fc-s-3) + var(--fc-safe-bot));
  background: var(--glass-fill-hard); border-top: 1px solid var(--glass-stroke-lo);
  -webkit-backdrop-filter: blur(26px) saturate(180%); backdrop-filter: blur(26px) saturate(180%);
  animation: barIn var(--fc-m-medium) var(--fc-ease-out);
}
@keyframes barIn { from { transform: translateY(100%); } }
/* The inset is the home indicator's room, and only the bottom-most bar owes
   it. With a tab bar underneath, the action bar paying it too leaves an
   empty 34px band of glass between the two. */
.actionbar:has(+ .tabbar), :has(+ .tabbar) > .actionbar { padding-bottom: var(--fc-s-3); }

/* Floating cart bubble */
.cartbar {
  position: sticky; bottom: 10px; z-index: calc(var(--fc-z-nav) + 1); margin: 0 var(--fc-s-4) 10px;
  display: flex; align-items: center; gap: var(--fc-s-3); padding: 8px 10px 8px var(--fc-s-4);
  border-radius: var(--fc-r-pill); color: #fff;
  background: linear-gradient(150deg, var(--fc-green-600), var(--fc-green-800));
  box-shadow: 0 10px 30px -8px rgba(71,122,23,.7), inset 0 1px 0 rgba(255,255,255,.25);
  animation: barIn var(--fc-m-medium) var(--fc-ease-spring);
}
.cartbar.is-bump { animation: bump var(--fc-m-medium) var(--fc-ease-spring); }
@keyframes bump { 0%,100%{transform:scale(1)} 40%{transform:scale(1.035)} }

/* Cart bar anatomy (spec §3.5): anchor = thumb stack + count, then total, then
   the CTA. The anchor is the flight target for every ADD in the app. */
.cartbar-anchor { display: inline-flex; align-items: center; gap: var(--fc-s-2); min-height: 44px; padding: 0; color: inherit; position: relative; flex: none; }
.cartbar-thumbs { display: flex; align-items: center; flex: none; }
.cartbar-thumbs > * { width: 32px; height: 32px; border-radius: 50%; object-fit: cover; background: var(--pith-white);
  box-shadow: 0 0 0 2px var(--fc-green-700); margin-left: -10px; transition: transform var(--fc-m-quick) var(--fc-ease-spring); }
.cartbar-thumbs > *:first-child { margin-left: 0; }
.cartbar-thumbs > * img, .cartbar-thumbs > * canvas { width: 100%; height: 100%; object-fit: contain; border-radius: 50%; }
.cartbar-anchor .count { position: absolute; top: -4px; left: -4px; }
.cartbar-anchor .cartbar-n { font-size: var(--fc-t-xs); font-weight: var(--fc-w-semi); opacity: .9; }
.cartbar-total { font-size: var(--fc-t-md); font-weight: var(--fc-w-bold); font-variant-numeric: tabular-nums; flex: 1 1 auto; text-align: left; }
.cartbar-cta { display: inline-flex; align-items: center; gap: 4px; min-height: 44px; padding: 0 var(--fc-s-4); border-radius: var(--fc-r-pill);
  background: var(--glass-fill-hard); color: var(--fc-green-800); font-weight: var(--fc-w-bold); font-size: var(--fc-t-sm); flex: none; }
.cartbar-cta:active { transform: scale(var(--fc-press)); }
.cartbar.is-bump .cartbar-thumbs > *:last-child { animation: countPop var(--fc-m-medium) var(--fc-ease-spring); }

/* Sliding chip indicator (Blinkit A5). The rail gets .chip-rail; the
   indicator is translated to the active chip with --chip-x / --chip-w (px)
   set by the screen; only transform moves. */
.chip-rail { position: relative; }
.chip-ind { position: absolute; left: 0; bottom: 0; height: 2px; width: 1px; border-radius: var(--fc-r-pill); background: var(--accent);
  transform: translateX(var(--chip-x, 0px)) scaleX(var(--chip-w, 0)); transform-origin: left center;
  transition: transform var(--fc-m-medium) var(--fc-ease-out); pointer-events: none; }

/* Notification dot */
.badge-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--fc-red-500); box-shadow: 0 0 0 2px var(--glass-fill-hard); }

/* Offline / sync banner */
.netbar {
  display: flex; align-items: center; gap: 8px; padding: 8px var(--fc-s-4);
  font-size: var(--fc-t-xs); font-weight: var(--fc-w-semi); flex: none;
}
.netbar--off  { background: rgba(224,54,44,.16); color: var(--fc-red-600); }
.netbar--sync { background: rgba(62,143,208,.16); color: var(--ink-on-info); }
.netbar--ok   { background: rgba(31,168,91,.15); color: var(--ink-on-green); }
[data-surface="night"] .netbar--off { color:var(--fc-red-400) } [data-surface="night"] .netbar--sync { color:var(--ink-on-info) }
[data-surface="night"] .netbar--ok { color:var(--ink-on-green) }
.netbar { animation: netIn var(--fc-m-medium) var(--fc-ease-out); }
@keyframes netIn { from { transform: translateY(-100%); opacity: 0; } }
.netbar i { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; }
.netbar-pip { width: 24px; height: 24px; flex: none; display: block; }
.netbar-pip img { width: 100%; height: 100%; object-fit: contain; }
.netbar--sync i { animation: blink calc(var(--fc-m-epic) * .9) infinite; }
@keyframes blink { 50% { opacity: .3; } }

/* Stat pills / trust strip */
.trust { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 1px; border-radius: var(--fc-r-lg); overflow: hidden; }
.trust > div { padding: var(--fc-s-3) 8px; text-align: center; background: var(--glass-fill-soft); }
.trust b { display: block; font-size: var(--fc-t-sm); font-weight: var(--fc-w-bold); }
.trust span { display: block; font-size: var(--fc-t-2xs); color: var(--txt-3); margin-top: 2px; line-height: 1.3; }

/* Accordion */
.acc { border-bottom: 1px solid var(--line-soft); }
.acc > button { display: flex; align-items: center; justify-content: space-between; gap: var(--fc-s-3); width: 100%; padding: var(--fc-s-4) 0; text-align: left; font-weight: var(--fc-w-semi); font-size: var(--fc-t-md); }
.acc > button .chev { transition: transform var(--fc-m-quick) var(--fc-ease-out); color: var(--txt-3); flex: none; }
.acc[open] > button .chev, .acc.is-open > button .chev { transform: rotate(180deg); }
.acc-body { overflow: hidden; font-size: var(--fc-t-sm); color: var(--txt-2); line-height: var(--fc-lh-loose); }
.acc-body > div { padding-bottom: var(--fc-s-4); }

/* Stepper (checkout progress) */
.steps { display: flex; align-items: center; gap: 6px; }
.steps > div { flex: 1; height: 3px; border-radius: 99px; background: var(--line); overflow: hidden; }
.steps > div > i { display: block; height: 100%; width: 0; background: var(--fc-green-600); border-radius: 99px; transition: width var(--fc-m-medium) var(--fc-ease-out); }
.steps > div.is-done > i, .steps > div.is-now > i { width: 100%; }
.steps > div.is-now > i { animation: stepFill var(--fc-m-slow) var(--fc-ease-out); }
@keyframes stepFill { from { width: 0 } }

/* Success burst */
.burst { position: relative; width: 108px; height: 108px; margin: 0 auto; }
.burst svg { position: absolute; inset: 0; }
.burst-ring { stroke: var(--fc-green-600); stroke-width: 3.5; fill: none; stroke-linecap: round;
  stroke-dasharray: 314; stroke-dashoffset: 314; animation: drawRing calc(var(--fc-m-slow) * 1.25) var(--fc-ease-out) forwards; }
@keyframes drawRing { to { stroke-dashoffset: 0; } }
.burst-tick { stroke: var(--fc-green-600); stroke-width: 5; fill: none; stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 48; stroke-dashoffset: 48; animation: drawTick calc(var(--fc-m-medium) * 1.1) var(--fc-ease-out) calc(var(--fc-m-slow) * .85) forwards; }
@keyframes drawTick { to { stroke-dashoffset: 0; } }

/* Confetti */
.confetti { position: fixed; inset: 0; pointer-events: none; z-index: var(--fc-z-top); overflow: hidden; }
.confetti i { position: absolute; width: 8px; height: 12px; border-radius: 2px; animation: fall linear forwards; }
@keyframes fall { to { transform: translateY(105vh) rotate(720deg); opacity: 0; } }

/* Map canvas */
.mapbox { position: relative; border-radius: var(--fc-r-lg); overflow: hidden; background: var(--on-glass-chip); }
.mapbox svg { display: block; width: 100%; height: 100%; }
.map-pin { transition: transform var(--fc-m-epic) var(--fc-ease); }

/* Avatar */
.av { border-radius: 50%; display: grid; place-items: center; font-weight: var(--fc-w-bold); flex: none;
  background: linear-gradient(140deg, var(--fc-green-400), var(--fc-green-700)); color: #fff; letter-spacing: -.02em; }
.av--28 { width:28px; height:28px; font-size:11px } .av--36 { width:36px; height:36px; font-size:13px }
.av--34 { width:34px; height:34px; font-size:13px } .av--38 { width:38px; height:38px; font-size:14px }
.av--44 { width:44px; height:44px; font-size:15px } .av--60 { width:60px; height:60px; font-size:20px }
.av--red { background: linear-gradient(140deg, var(--fc-red-400), var(--fc-red-700)); }
.av--blue { background: linear-gradient(140deg, var(--fc-info), var(--ink-on-blue)); }
.av--gold { background: linear-gradient(140deg, var(--fc-premium), var(--ink-on-gold)); }
.av--slate { background: linear-gradient(140deg, var(--fc-ink-400), var(--fc-ink-600)); }

/* Tag / meta line */
.meta { display: flex; align-items: center; gap: 6px; font-size: var(--fc-t-xs); color: var(--txt-3); flex-wrap: wrap; }
.meta > * { display: inline-flex; align-items: center; gap: 4px; }

/* Callout */
.callout { display: flex; gap: 10px; padding: var(--fc-s-3) var(--fc-s-4); border-radius: var(--fc-r-md); font-size: var(--fc-t-sm); line-height: var(--fc-lh-base); }
.callout--info { background: rgba(62,143,208,.12); color: var(--txt-1); }
.callout--ok   { background: rgba(31,168,91,.12); }
.callout--warn { background: rgba(232,162,28,.14); }
.callout--err  { background: rgba(224,54,44,.12); }
.callout--green{ background: rgba(140,198,63,.15); }
.callout b { font-weight: var(--fc-w-bold); }
.callout .ci { flex: none; margin-top: 1px; }

/* Rating */
.stars { display: inline-flex; gap: 2px; color: var(--fc-warn); }
.stars svg { width: 13px; height: 13px; }

/* Data pair */
.pairs { display: grid; gap: 8px; }
.pair { display: flex; align-items: baseline; justify-content: space-between; gap: var(--fc-s-4); font-size: var(--fc-t-sm); }
.pair > dt { color: var(--txt-3); flex: none; }
.pair > dd { margin: 0; text-align: right; font-weight: var(--fc-w-medium); font-variant-numeric: tabular-nums; }
.pair--total { font-size: var(--fc-t-lg); font-weight: var(--fc-w-bold); padding-top: 10px; border-top: 1px dashed var(--line); }
.pair--total > dt { color: var(--txt-1); }

/* Page transition */
.route-in  { animation: routeIn var(--fc-m-medium) var(--fc-ease-out); }
@keyframes routeIn { from { opacity: 0; transform: translateY(9px); } }
.route-in-x { animation: routeInX var(--fc-m-medium) var(--fc-ease-out); }
@keyframes routeInX { from { opacity: 0; transform: translateX(20px); } }
/* The ladder is a slot index times a token-derived step (two sevenths of
   --fc-m-fast, offset by half a step), so it scales with the token and
   collapses with it under reduced motion instead of holding literal delays. */
.stagger > * {
  animation: routeIn var(--fc-m-medium) var(--fc-ease-out) backwards;
  animation-delay: calc(var(--fc-m-fast) * (2 * var(--fc-i, 0) + 1) / 7);
}
.stagger > *:nth-child(2){--fc-i:1} .stagger > *:nth-child(3){--fc-i:2} .stagger > *:nth-child(4){--fc-i:3}
.stagger > *:nth-child(5){--fc-i:4} .stagger > *:nth-child(6){--fc-i:5} .stagger > *:nth-child(7){--fc-i:6}
.stagger > *:nth-child(8){--fc-i:7} .stagger > *:nth-child(n+9){--fc-i:8}

/* ============================================================================
   PASS 1 — CANONICAL ROW + TOUCH TARGETS
   Audit finding: list rows were being written inline with six different
   paddings (7/0, 9/0, 10/14, 11/15, 11/16, 12/14), so the same component had
   four different left edges across screens. One class now owns that geometry.
   ========================================================================= */
.rowset { padding: var(--fc-s-2) 0; }
.row-item {
  display: flex; align-items: center; gap: var(--fc-s-3);
  padding: var(--fc-s-3) var(--fc-s-4);
  min-height: 56px;
}
.row-item + .row-item { box-shadow: 0 -1px 0 var(--line-soft); }
.row-item--top { align-items: flex-start; }
.row-item--tight { min-height: 44px; padding: var(--fc-s-2) var(--fc-s-4); }
.row-item--flush { padding-left: 0; padding-right: 0; }
.row-item .rt { margin-left: auto; text-align: right; flex: none; }
.row-item > *:last-child:not(:only-child) { margin-left: auto; }
.row-item > .grow ~ * { margin-left: 0; }

/* Minimum 44×44 hit area without inflating the visual control.
   The control keeps its density; the finger gets the target. */
.tap-safe { position: relative; }
.tap-safe::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: max(100%, 44px); height: max(100%, 44px);
  transform: translate(-50%, -50%);
}
/* These need a positioning context for the ::after hit expander below.
   .pcard-save is deliberately NOT in this list: it is already
   `position: absolute` (line ~305), and this rule — later in the file with
   equal specificity — silently reset it to relative, dropping the wishlist
   heart out of its overlay position and into normal flow on every card. */
.addbtn, .qty button, .chip--sm, .btn--xs, .tabbtn, .acct-go {
  position: relative;
}
/* A bare text button — "Remove", "Save for later" — carries no button chrome
   and so had no min-height: 64x15 targets against a declared 44px minimum.
   The expander gives it a real hit area without changing how it looks. */
.txtbtn { position: relative; }
.txtbtn::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: max(100%, 44px); height: 44px; transform: translate(-50%, -50%);
}
.addbtn::after, .pcard-save::after, .qty button::after, .chip--sm::after, .btn--xs::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: max(100%, 44px); height: max(100%, 44px);
  transform: translate(-50%, -50%);
}
/* ---- INPUT-MODALITY-AWARE TARGETS ----------------------------------------
   On a mouse, dense controls are correct — a 34px stepper on a product card
   keeps four cards per row on a 390px screen. On touch, density loses to the
   thumb, so every interactive control grows to the 44px minimum. This is why
   the numbers differ, and it is deliberate.                                 */
@media (pointer: coarse) {
  .addbtn { min-height: 40px; min-width: 76px; }
  .qty { height: 40px; }
  .qty button { width: 40px; }
  .qty--lg { height: 48px; }
  .qty--lg button { width: 48px; }
  .pcard-save { width: 36px; height: 36px; }
  .chip { height: 40px; }
  .chip--sm { height: 34px; }
  .btn--xs { min-height: 36px; }
  .btn--sm { min-height: 40px; }
  .seg button { min-height: 40px; }
  .tabbtn { min-height: 56px; }
  .check .box { width: 24px; height: 24px; }
  .switch { width: 52px; height: 30px; }
  .switch::after { width: 24px; height: 24px; }
  .check input:checked ~ .switch::after { transform: translateX(22px); }
}
/* The stepper is one control: the two halves share the band between them. */
.qty { min-height: 34px; }
.qty button::after { width: max(100%, 36px); height: max(100%, 44px); }
.pcard-save::after { width: 44px; height: 44px; }
