/* Bottega Sudiro — storefront.
   The four packaging colours are authoritative and come from css/styles.css.
   The layout below is lifted from index-mockup.html, the approved home-page
   design, and extended to cover the shop, cart, checkout, account and admin.
   Nothing here invents a colour. */

:root{
  /* Packaging palette — authoritative, per README.md */
  --birch:#332F21;
  --cream:#EFDBB2;
  --ginger:#E0C09F;
  --paper:#D9D9D6;
  --birch-lift:#3E3928;
  --birch-deep:#272419;

  --sans:"Inter", system-ui, sans-serif;

  /* How far the packs stand across the bottom edge of the band */
  --overlap:clamp(110px, 17vw, 215px);
  --gutter:clamp(1.25rem, 5vw, 4rem);
  --measure:1180px;
}

*{margin:0;padding:0;box-sizing:border-box}

/* The board: flat cream, monogram lattice at half strength, film grain. Same
   recipe as css/styles.css, painted on the root so overscroll is covered. */
html{
  height:100%;
  background-color:var(--cream);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.0225'/%3E%3C/svg%3E"),
    linear-gradient(rgba(239,219,178,0.5), rgba(239,219,178,0.5)),
    url("/img/monogram-tile.png");
  background-repeat:repeat,repeat,repeat;
  /* Third layer is the monogram tile; the first is film grain. A smaller tile
     reads as texture rather than as wallpaper with a repeating logo. */
  background-size:160px 160px, auto, 72px 72px;
  background-blend-mode:multiply,normal,normal;
  overscroll-behavior-x:none;
  scroll-behavior:smooth;
}
body{
  min-height:100dvh;
  color:var(--birch);
  font-family:var(--sans);
  font-weight:300;
  line-height:1.65;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
@media (prefers-reduced-motion:reduce){ html{scroll-behavior:auto} }

img{max-width:100%;display:block}
a{color:inherit}

.wrap{width:100%;max-width:var(--measure);margin-inline:auto;padding-inline:var(--gutter)}

/* The pack's own voice: spaced caps. Used only where the printed bag uses it —
   the descriptor lines and the footer meta. Never as a heading label. */
.pack-voice{
  font-size:clamp(0.56rem,1.5vw,0.64rem);
  font-weight:400;
  letter-spacing:0.26em;
  text-indent:0.26em;
  text-transform:uppercase;
}

:where(a,button,summary):focus-visible{
  outline:2px solid var(--ginger);
  outline-offset:3px;
}

.skip{
  position:absolute;left:-9999px;top:0;z-index:99;
  background:var(--birch-deep);color:var(--paper);
  padding:.75rem 1.25rem;font-size:.8rem;
}
.skip:focus{left:0}

/* ---------- Top bar — the head of the band, and it stays there ---------- */
.bar{
  position:sticky;top:0;z-index:30;
  background:var(--birch-lift);
  transition:box-shadow .3s ease;
}
.bar.is-stuck{box-shadow:0 10px 26px -14px rgba(39,36,25,.65)}
.bar-inner{
  display:flex;align-items:center;justify-content:space-between;gap:1.25rem;
  min-height:62px;
  /* The wordmark is 878x478 and sets the bar's height on its own. The padding
     is deliberately uneven: the logo's lowest element is the thin olive
     branch, so the eye reads the baseline of SUDIRO as the bottom edge.
     Equal padding therefore looks bottom-heavy. */
  padding-block:.7rem .5rem;
}
.bar-mark img{
  width:106px;
  /* The mockup faded this in only once the band had scrolled away, to avoid
     repeating the wordmark that sits right below it on the home page. That
     reasoning only ever held on the home page: every interior page has no band,
     so the bar sat with no mark on it at all. It is always visible now, and
     slightly held back while the band is still behind it. */
  opacity:.92;
  transition:opacity .3s ease;
}
.bar.is-stuck .bar-mark img{opacity:1}
.nav{display:flex;align-items:center;gap:clamp(.9rem,2.6vw,2rem)}
.nav a{
  font-size:.8rem;font-weight:300;letter-spacing:.06em;
  color:var(--paper);text-decoration:none;opacity:.82;
  padding-block:.4rem;
  border-bottom:1px solid transparent;
  transition:opacity .2s ease,border-color .2s ease;
}
.nav a:hover,.nav a:focus-visible{opacity:1;border-bottom-color:var(--ginger)}
.nav .cart{color:var(--ginger);opacity:.9}
/* Both an empty value and "0" suppress the count. Empty matters: the error page
   renders the layout without a cart count on purpose — an error page must not
   depend on the database — and without this it showed "Cart ()". */
.nav .cart[data-count]:not([data-count="0"]):not([data-count=""])::after{
  content:" (" attr(data-count) ")";
  font-variant-numeric:tabular-nums;
}

/* ---------- The band ---------- */
.band{
  position:relative;
  background:linear-gradient(178deg,
    rgba(62,57,40,.975) 0%,
    rgba(51,47,33,.97) 46%,
    rgba(39,36,25,.975) 100%);
  padding-top:clamp(2.75rem,7vh,5rem);
  padding-bottom:calc(var(--overlap) + clamp(2.5rem,7vh,4.5rem));
  text-align:center;
  color:var(--paper);
}
.band-wordmark{
  width:min(300px,58vw);margin-inline:auto;
  animation:fade 1s cubic-bezier(.22,1,.36,1) both;
}
.rule{
  width:64px;height:1px;margin:clamp(1.6rem,4vh,2.4rem) auto;
  background:linear-gradient(90deg,transparent,var(--ginger),transparent);
}
.band h1{
  font-size:clamp(2rem,5.4vw,3.9rem);
  font-weight:200;
  letter-spacing:-.022em;
  line-height:1.12;
  text-wrap:balance;
  animation:fade 1s cubic-bezier(.22,1,.36,1) .1s both;
}
.band h1 .br{display:block}
/* .lede is ginger ONLY inside the band, where it sits on birch at 7.26:1.
   Ginger on the cream board is 1.36:1 — a hard WCAG failure and, in practice,
   text you cannot read at all. The default below is birch at 78%, which is
   5.47:1 on the cream board and 6.46:1 on a paper card. */
.lede{
  max-width:44ch;margin:clamp(1rem,2.5vh,1.5rem) auto 0;
  font-size:clamp(.92rem,2.3vw,1.02rem);
  font-weight:300;
  color:rgba(51,47,33,.78);
  text-wrap:pretty;
}
.band .lede{
  color:var(--ginger);
  animation:fade 1s cubic-bezier(.22,1,.36,1) .18s both;
}

/* ---------- The shelf — packs standing across the band's bottom edge ------- */
.shelf{
  position:relative;z-index:5;
  margin-top:calc(-1 * var(--overlap));
  display:grid;
  grid-template-columns:repeat(2,minmax(0,380px));
  justify-content:center;
  gap:clamp(1.5rem,6vw,5.5rem);
  padding-bottom:clamp(2.75rem,7vh,4.5rem);
}
.piece{display:flex;flex-direction:column;animation:stand 1.05s cubic-bezier(.22,1,.36,1) both}
.piece:nth-child(1){animation-delay:.26s}
.piece:nth-child(2){animation-delay:.36s}

.piece-photo{
  position:relative;display:block;
  padding:clamp(10px,1.6vw,16px);
  background:var(--paper);
  border:1px solid rgba(51,47,33,.22);
  box-shadow:0 34px 52px -32px rgba(39,36,25,.62);
}
.piece-photo img{width:100%;height:auto}
/* One warm grade across both photographs. The marble reads cool next to the
   kraft otherwise, and the two packs stop looking like one shelf. */
.piece-photo::after{
  content:"";position:absolute;inset:clamp(10px,1.6vw,16px);
  background:var(--cream);opacity:.14;mix-blend-mode:multiply;
  pointer-events:none;
}

.piece-body{display:flex;flex-direction:column;flex:1;padding-top:clamp(1.1rem,2.5vh,1.5rem)}

/* Menu leader: name on the left, price on the right, dotted rule between —
   the way a shop card sets a price, not the way a product card does. */
.piece-line{display:flex;align-items:baseline;gap:.6rem}
.piece-name{
  font-size:clamp(1.15rem,2.9vw,1.42rem);
  font-weight:300;letter-spacing:-.012em;
  text-decoration:none;
  border-bottom:1px solid transparent;
  transition:border-color .2s ease;
}
.piece-name:hover,.piece-name:focus-visible{border-bottom-color:var(--ginger)}
.piece-leader{
  flex:1;height:0;
  border-bottom:1px dotted rgba(51,47,33,.4);
  transform:translateY(-.28em);
}
.piece-price{
  font-size:clamp(1rem,2.6vw,1.15rem);font-weight:400;
  font-variant-numeric:tabular-nums;letter-spacing:.01em;
}
.piece-meta{
  margin-top:.7rem;color:rgba(51,47,33,.78);
}
.piece-note{
  margin-top:.55rem;font-size:.86rem;line-height:1.55;
  color:rgba(51,47,33,.78);max-width:34ch;
}
.piece-break{
  margin-top:.5rem;margin-bottom:auto;font-size:.8rem;
  color:rgba(51,47,33,.78);
  font-variant-numeric:tabular-nums;
}

.buy{
  align-self:flex-start;
  margin-top:clamp(1rem,2.4vh,1.4rem);
  display:inline-flex;align-items:center;justify-content:center;
  min-height:44px;padding:.65rem 1.5rem;
  background:var(--birch);color:var(--paper);
  border:1px solid var(--birch);border-radius:0;
  font-family:var(--sans);font-size:.82rem;font-weight:400;letter-spacing:.09em;
  cursor:pointer;
  transition:background .2s ease,color .2s ease;
}
.buy:hover,.buy:focus-visible{background:transparent;color:var(--birch)}
.buy.is-added{background:var(--birch-deep);border-color:var(--birch-deep);color:var(--ginger)}

/* ---------- Board sections ---------- */
.board{padding-block:clamp(3rem,9vh,5.5rem)}
.board + .board{border-top:1px solid rgba(51,47,33,.16)}
/* The manifesto ends by leading into the Shop button: no divider, no gap. */
.manifesto + #shop-cta{border-top:0;padding-top:0}
.board h2{
  font-size:clamp(1.4rem,3.4vw,2rem);
  font-weight:200;letter-spacing:-.018em;line-height:1.2;
}
.board p{max-width:62ch;text-wrap:pretty}
.intro{margin-top:.85rem;color:rgba(51,47,33,.8)}


.ship-grid{
  margin-top:clamp(1.75rem,4vh,2.5rem);
  display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
  gap:clamp(1.5rem,4vw,3rem);
}
.ship-grid h3{
  font-size:1rem;font-weight:400;margin-bottom:.45rem;
}
.ship-grid p{font-size:.92rem;color:rgba(51,47,33,.8);max-width:34ch}
.ship-grid h3 a{color:inherit;text-decoration:none}
.ship-grid h3 a:hover,.ship-grid h3 a:focus-visible{text-decoration:underline}

/* ---------- Wholesale — the second band ---------- */
.trade{
  background:linear-gradient(178deg,
    rgba(62,57,40,.975) 0%,
    rgba(39,36,25,.975) 100%);
  color:var(--paper);
  padding-block:clamp(3rem,9vh,5rem);
}
.trade-inner{
  display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);
  gap:clamp(1.75rem,5vw,4rem);align-items:start;
}
.trade h2{font-size:clamp(1.4rem,3.4vw,2rem);font-weight:200;letter-spacing:-.018em}
.trade p{margin-top:.9rem;color:var(--ginger);max-width:48ch;text-wrap:pretty}
.terms{display:grid;gap:.85rem}
.term{
  display:flex;justify-content:space-between;gap:1.25rem;
  padding-bottom:.7rem;border-bottom:1px solid rgba(224,192,159,.28);
  font-size:.92rem;
}
.term dt{color:rgba(217,217,214,.7)}
.term dd{color:var(--paper);font-variant-numeric:tabular-nums;text-align:right}
.trade-actions{margin-top:clamp(1.5rem,3.5vh,2rem);display:flex;flex-wrap:wrap;gap:1.5rem;align-items:center}
.btn-light{
  display:inline-flex;align-items:center;min-height:44px;padding:.65rem 1.5rem;
  background:var(--paper);color:var(--birch);border:1px solid var(--paper);
  font-size:.82rem;font-weight:400;letter-spacing:.09em;text-decoration:none;
  transition:background .2s ease,color .2s ease;
}
.btn-light:hover,.btn-light:focus-visible{background:transparent;color:var(--paper)}
.quiet-link{
  font-size:.86rem;color:var(--ginger);text-decoration:none;
  border-bottom:1px solid rgba(224,192,159,.4);padding-bottom:.15rem;
  transition:color .2s ease,border-color .2s ease;
}
.quiet-link:hover,.quiet-link:focus-visible{color:var(--paper);border-bottom-color:var(--paper)}

/* ---------- Footer band ---------- */
.foot{
  background:var(--birch-deep);color:var(--ginger);
  padding-block:clamp(2.5rem,7vh,4rem);
}
.foot-top{
  display:flex;flex-wrap:wrap;justify-content:space-between;gap:2rem;
  padding-bottom:2rem;border-bottom:1px solid rgba(224,192,159,.2);
}
.foot-mark img{width:170px;opacity:.95}
.foot-mail{margin-top:1rem;display:block}
.foot-mail a{
  color:var(--paper);font-size:.9rem;text-decoration:none;
  border-bottom:1px solid rgba(224,192,159,.45);padding-bottom:.2rem;
}
.foot-mail a:hover{color:var(--ginger);border-bottom-color:var(--ginger)}
.foot-links{display:flex;flex-wrap:wrap;gap:.55rem 1.75rem;align-items:flex-start}
.foot-links a{
  font-size:.85rem;color:var(--ginger);opacity:.85;text-decoration:none;
  border-bottom:1px solid transparent;padding-bottom:.15rem;
}
.foot-links a:hover,.foot-links a:focus-visible{opacity:1;border-bottom-color:var(--ginger)}
.foot-bottom{
  padding-top:1.5rem;display:flex;flex-wrap:wrap;gap:1rem;
  justify-content:space-between;align-items:center;
}
.social{display:flex;gap:.25rem;margin-left:-.6rem}
.social a{
  display:flex;align-items:center;justify-content:center;
  width:2.75rem;height:2.75rem;color:var(--ginger);opacity:.75;
  transition:opacity .25s ease,transform .25s ease;
}
.social a:hover,.social a:focus-visible{opacity:1;transform:translateY(-2px)}
.social svg{width:1.1rem;height:1.1rem;fill:currentColor}
.copy{opacity:.85;font-size:.65rem;line-height:1.8}

/* ---------- Motion — one orchestrated load, nothing on scroll ---------- */
@keyframes fade{from{opacity:0}to{opacity:1}}
@keyframes stand{
  from{opacity:0;transform:translateY(20px)}
  to{opacity:1;transform:none}
}
@media (prefers-reduced-motion:reduce){
  .band-wordmark,.band h1,.lede,.piece{animation:none}
  .social a:hover,.social a:focus-visible{transform:none}
}

/* ---------- Narrow ---------- */
@media (max-width:760px){
  :root{--overlap:clamp(80px,20vw,130px)}
  .shelf{grid-template-columns:minmax(0,340px);gap:clamp(2.5rem,8vh,3.5rem)}
  .trade-inner{grid-template-columns:minmax(0,1fr)}
  .bar-mark img{width:88px}
  .nav{gap:.85rem}
  .nav a{font-size:.75rem}

  /* Once the footer's two columns stack, a left-aligned stack under a centred
     page reads as a mistake. Centre the whole band. The wordmark needs
     margin-inline:auto of its own: text-align does not move an image that the
     flex column has already stretched to full width. */
  .foot{text-align:center}
  .foot-top{flex-direction:column;align-items:center;justify-content:center;gap:1.75rem}
  .foot-mark{display:flex;flex-direction:column;align-items:center}
  .foot-mark img{margin-inline:auto}
  .foot-links{justify-content:center;gap:.55rem 1.25rem}
  .foot-bottom{flex-direction:column;justify-content:center;align-items:center;gap:.75rem}
  .social{margin-left:0;justify-content:center}
  .copy{text-align:center}
}
@media (max-width:430px){
  .band h1 .br{display:inline}
  .nav .label-hide{display:none}
}

/* ═══════════════════════════════════════════════════════════════════════════
   Everything below extends the mockup's design to the pages it didn't cover:
   the product list and detail, cart, checkout, sign-in, order status, account
   and admin. It reuses the mockup's tokens and voice and adds no new colours.
   ═══════════════════════════════════════════════════════════════════════════ */

:root{
  --rule-line:rgba(51,47,33,.18);
  --rule-soft:rgba(51,47,33,.10);
  --shadow:0 1px 2px rgba(39,36,25,.06), 0 8px 24px rgba(39,36,25,.07);
  --radius:4px;
}

/* The cart pill carries its count the way the mockup's bar does. */
.nav .cart[data-count="0"]::after,
.nav .cart[data-count=""]::after{content:none}

/* ---------- Interior page shell ---------- */
main.page{padding:clamp(2rem,6vw,4rem) 0 4rem}
.page-head{margin-bottom:clamp(1.5rem,4vw,2.5rem)}
.page-head h1{
  font-size:clamp(1.9rem,4.5vw,2.8rem);
  font-weight:300;letter-spacing:-.015em;line-height:1.15;
}
.eyebrow{
  font-size:clamp(.56rem,1.5vw,.64rem);font-weight:400;
  letter-spacing:.26em;text-indent:.26em;text-transform:uppercase;
  opacity:.6;margin-bottom:.7rem;
}
h2{font-size:clamp(1.3rem,3vw,1.7rem);font-weight:300;letter-spacing:-.01em}
h3{font-size:1.02rem;font-weight:500}

.card{
  background:var(--paper);
  border:1px solid var(--rule-soft);
  border-radius:var(--radius);
  box-shadow:var(--shadow);
}
.pad{padding:clamp(1.1rem,3vw,1.75rem)}
.stack>*+*{margin-top:1rem}
.muted{opacity:.65}
.tiny{font-size:.82rem}
.center{text-align:center}

/* ---------- Product grid (/products) ---------- */
.grid{
  display:grid;
  grid-template-columns:repeat(auto-fill,minmax(min(100%,17rem),1fr));
  gap:clamp(1rem,2.5vw,1.75rem);
}
.product-card{
  background:var(--paper);border:1px solid var(--rule-soft);
  border-radius:var(--radius);overflow:hidden;text-decoration:none;
  display:flex;flex-direction:column;box-shadow:var(--shadow);
  transition:transform .18s ease,box-shadow .18s ease;
}
.product-card:hover,.product-card:focus-visible{
  transform:translateY(-2px);
  box-shadow:0 2px 4px rgba(39,36,25,.08),0 14px 32px rgba(39,36,25,.11);
}
.product-card .shot{aspect-ratio:4/5;background:var(--cream);overflow:hidden}
.product-card .shot img{width:100%;height:100%;object-fit:cover}
.product-card .shot.empty{
  display:grid;place-items:center;color:rgba(51,47,33,.35);
  font-size:.62rem;letter-spacing:.26em;text-transform:uppercase;
}
.product-card .body{padding:1rem 1.15rem 1.25rem;display:flex;flex-direction:column;gap:.35rem;flex:1}
.product-card .price{margin-top:auto;padding-top:.6rem;font-size:.95rem;opacity:.8}

/* ---------- Product detail ---------- */
.detail{display:grid;grid-template-columns:1fr;gap:clamp(1.5rem,4vw,3rem)}
@media (min-width:60rem){.detail{grid-template-columns:1.05fr 1fr;align-items:start}}
.gallery img{border-radius:var(--radius);border:1px solid var(--rule-soft)}
.gallery .empty{
  aspect-ratio:4/3;background:var(--paper);border:1px solid var(--rule-soft);
  border-radius:var(--radius);display:grid;place-items:center;
  color:rgba(51,47,33,.35);text-transform:uppercase;letter-spacing:.26em;font-size:.62rem;
}
.spec{border-top:1px solid var(--rule-line);margin-top:1.75rem;padding-top:1.5rem}
.spec h3{margin-bottom:.6rem}

/* Ingredients print in stored order — descending by weight. That order is a
   labelling requirement, so nothing here may re-sort the list. */
.ingredients{font-size:.93rem;line-height:1.7;opacity:.88}
.ingredients .sub{opacity:.7}

.allergens{display:flex;flex-wrap:wrap;gap:.45rem;margin-top:.6rem}
.allergen-tag{
  font-size:.72rem;letter-spacing:.06em;padding:.25rem .65rem;
  border-radius:999px;border:1px solid var(--rule-line);
}
.allergen-tag.contains{background:var(--birch);color:var(--paper);border-color:var(--birch)}
.allergen-tag.may_contain,.allergen-tag.shared_equipment{background:var(--ginger);color:var(--birch-deep)}
.diet-tag{
  font-size:.72rem;letter-spacing:.06em;padding:.25rem .65rem;border-radius:999px;
  border:1px solid rgba(51,47,33,.22);background:transparent;
}

.form-legend{
  font-size:.68rem;letter-spacing:.16em;text-transform:uppercase;
  color:rgba(51,47,33,.75);font-weight:400;
  margin:1.5rem 0 .75rem;padding-top:1rem;border-top:1px solid var(--rule-soft);
}
.form-legend:first-of-type{margin-top:.5rem;padding-top:0;border-top:0}
.weight-input{display:flex;gap:.5rem}
.weight-input input{flex:1;min-width:0}
.contact-only{font-size:.88rem;line-height:1.5;color:rgba(51,47,33,.8)}
.contact-only a{color:inherit}
.allergen-lines{display:grid;gap:.5rem;font-size:.93rem}
.allergen-lines div{display:grid;grid-template-columns:9.5rem 1fr;gap:1rem;align-items:baseline}
.allergen-lines dt{
  font-size:.68rem;letter-spacing:.16em;text-transform:uppercase;color:rgba(51,47,33,.75);
}
.allergen-lines dd{margin:0;line-height:1.6}
@media (max-width:30rem){.allergen-lines div{grid-template-columns:1fr;gap:.1rem}}

.variant-row{
  display:flex;flex-wrap:wrap;align-items:center;gap:.85rem;
  padding:.85rem 0;border-bottom:1px solid var(--rule-soft);
}
.variant-row:last-of-type{border-bottom:0}
.variant-row .meta{flex:1 1 11rem;min-width:0}
.variant-row .meta small{display:block;opacity:.62;font-size:.8rem}
.variant-row .amt{font-variant-numeric:tabular-nums;white-space:nowrap}
.tiers{font-size:.8rem;opacity:.7;margin-top:.2rem}
.tiers span+span::before{content:" · "}

/* ---------- Forms ---------- */
label{
  display:block;font-size:.72rem;letter-spacing:.14em;text-transform:uppercase;
  opacity:.7;margin-bottom:.35rem;
}
input[type=text],input[type=email],input[type=number],input[type=tel],
input[type=url],input[type=date],input[type=password],select,textarea{
  width:100%;font:inherit;font-weight:300;color:var(--birch);
  background:var(--paper);border:1px solid var(--rule-line);
  border-radius:var(--radius);padding:.6rem .7rem;
}
input:focus-visible,select:focus-visible,textarea:focus-visible{
  outline:2px solid var(--ginger);outline-offset:2px;
}
.qty{width:4.5rem;text-align:center}
.field{margin-bottom:1rem}
.field-row{display:grid;gap:1rem;grid-template-columns:1fr}
@media (min-width:40rem){.field-row.two{grid-template-columns:1fr 1fr}}
.check{
  display:flex;gap:.45rem;align-items:center;text-transform:none;
  letter-spacing:0;opacity:1;font-size:.92rem;margin-bottom:0;
}
.check input{width:auto}

/* The mockup's .buy is the primary button; .btn matches it for links and forms
   elsewhere so there is one button voice across the site. */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:.5rem;
  font:inherit;font-weight:400;font-size:.72rem;
  letter-spacing:.14em;text-transform:uppercase;
  padding:.8rem 1.4rem;border:1px solid var(--birch);border-radius:2px;
  background:var(--birch);color:var(--paper);text-decoration:none;cursor:pointer;
  transition:background .15s ease,color .15s ease;
}
.btn:hover,.btn:focus-visible{background:var(--birch-deep)}
.btn.ghost{background:transparent;color:var(--birch)}
.btn.ghost:hover,.btn.ghost:focus-visible{background:rgba(51,47,33,.07)}
.btn.small{padding:.5rem .9rem;font-size:.66rem}
/* A button whose form is on its way: a spinner, and no second tap. */
.btn.is-loading{pointer-events:none;cursor:progress;opacity:.9}
.btn.is-loading::before{
  content:"";display:inline-block;width:.9em;height:.9em;margin-right:.6em;vertical-align:-.12em;
  border:2px solid currentColor;border-right-color:transparent;border-radius:50%;
  animation:btn-spin .7s linear infinite;
}
@keyframes btn-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.btn.is-loading::before{animation-duration:2s}}
.btn.wide{width:100%}
.btn[disabled]{opacity:.45;cursor:not-allowed}

/* ---------- Tables ---------- */
.table-scroll{overflow-x:auto}
table.data{width:100%;border-collapse:collapse;font-size:.9rem}
table.data th,table.data td{text-align:left;padding:.65rem .7rem;border-bottom:1px solid var(--rule-soft)}
table.data th{
  font-size:.64rem;text-transform:uppercase;letter-spacing:.16em;
  opacity:.6;font-weight:400;
}
table.data td.num,table.data th.num{text-align:right;font-variant-numeric:tabular-nums}
table.data tr:last-child td{border-bottom:0}

/* ---------- Totals ---------- */
.totals{list-style:none;font-variant-numeric:tabular-nums}
.totals li{display:flex;justify-content:space-between;gap:1rem;padding:.4rem 0}
.totals li.grand{border-top:1px solid var(--rule-line);margin-top:.4rem;padding-top:.7rem;font-size:1.1rem}
.totals .discount{color:#5d6b3a}

.two-col{display:grid;gap:clamp(1.5rem,4vw,2.5rem);grid-template-columns:1fr;align-items:start}
@media (min-width:58rem){.two-col{grid-template-columns:1.6fr 1fr}}

/* ---------- Notices ---------- */
.notice{border-radius:var(--radius);padding:.85rem 1rem;font-size:.92rem;border:1px solid var(--rule-line);background:var(--paper)}
.notice.error{border-color:#a4462f;background:#f7e7e1;color:#6d2b1b}
.notice.ok{border-color:#5d6b3a;background:#eef0e2;color:#3f4a25}

/* ---------- Order status track ---------- */
.track{display:flex;flex-wrap:wrap;gap:0;margin:1.5rem 0;list-style:none}
.track li{flex:1 1 8rem;position:relative;padding-top:1.9rem;font-size:.86rem}
.track li::before{
  content:"";position:absolute;top:.35rem;left:0;width:.85rem;height:.85rem;
  border-radius:999px;background:var(--paper);border:2px solid var(--rule-line);
}
.track li::after{content:"";position:absolute;top:.72rem;left:.85rem;right:0;height:2px;background:var(--rule-soft)}
.track li:last-child::after{display:none}
.track li.done::before{background:var(--birch);border-color:var(--birch)}
.track li.done::after{background:var(--birch)}
.track li .at{display:block;font-size:.76rem;opacity:.6}
/* The admin's order path: where it is now, what was skipped, where it stopped. */
.admin-track{margin:.25rem 0 1.25rem}
.admin-track li.current{font-weight:600}
.admin-track li.current::before{box-shadow:0 0 0 4px rgba(51,47,33,.16)}
.admin-track li.current .at{opacity:.85;font-weight:400}
.admin-track li.skipped::before{background:var(--paper);border-style:dashed;border-color:var(--birch)}
.admin-track li.stopped::before{background:var(--ginger);border-color:var(--birch)}

/* ---------- Admin ---------- */
.admin-bar{background:var(--birch-deep);color:var(--paper)}
.admin-bar .wrap{display:flex;flex-wrap:wrap;gap:1rem;padding-block:.6rem;align-items:center}
.admin-bar a{
  color:var(--paper);text-decoration:none;opacity:.78;
  letter-spacing:.16em;text-transform:uppercase;font-size:.62rem;
}
.admin-bar a:hover,.admin-bar a:focus-visible{opacity:1}
.admin-bar .sp{margin-left:auto;opacity:.55;font-size:.7rem}

.status-tag{
  font-size:.62rem;letter-spacing:.14em;text-transform:uppercase;
  padding:.22rem .6rem;border-radius:999px;border:1px solid var(--rule-line);white-space:nowrap;
}
.status-tag.paid,.status-tag.delivered,.status-tag.picked_up,.status-tag.active,.status-tag.approved{
  background:var(--birch);color:var(--paper);border-color:var(--birch);
}
.status-tag.pending_payment,.status-tag.payment_failed,.status-tag.pending{background:#f7e7e1;border-color:#c8907c}
.status-tag.packed,.status-tag.shipped,.status-tag.ready_for_pickup,.status-tag.out_for_delivery{background:var(--ginger)}
.status-tag.refunded,.status-tag.cancelled,.status-tag.draft,.status-tag.archived{opacity:.6}

details>summary{cursor:pointer}

/* A product with no photography yet must not collapse the shelf. The pieces are
   pulled up into the band by --overlap, and that overlap is measured from the
   photo's height: with an empty photo box the pack's name and price end up
   inside the birch, unreadable. Photography is the item most often deferred, so
   the empty state has to hold its own shape. */
.piece-photo.empty{
  aspect-ratio:4/5;
  display:grid;place-items:center;
  background:var(--cream);
}
.piece-photo.empty::before{
  content:"Photograph to come";
  font-size:.56rem;letter-spacing:.26em;text-transform:uppercase;
  color:rgba(51,47,33,.38);
}

/* Cloudflare Turnstile. The widget is a fixed-size iframe Cloudflare controls,
   so it is given room rather than styled — and centred so it does not sit
   awkwardly against a full-width button. */
.cf-turnstile{
  margin:0 0 1rem;
  min-height:65px;
  display:flex;
  justify-content:center;
}

/* Interior pages set their own measure: the band centres its lede under a
   centred headline, but a page head is left-aligned and the auto margins would
   push it away from the heading it belongs to. */
.page-head .lede{margin-left:0;margin-right:0;max-width:52ch}

/* A disabled field must look disabled. The wholesale form renders its inputs
   disabled until you sign in, and an input that accepts no typing while looking
   exactly like one that does reads as a broken page rather than a locked one. */
input:disabled, select:disabled, textarea:disabled{
  background:rgba(51,47,33,.05);
  color:rgba(51,47,33,.45);
  border-color:rgba(51,47,33,.12);
  cursor:not-allowed;
}
label:has(+ input:disabled), label:has(+ textarea:disabled){opacity:.45}
.field:has(input:disabled) .tiny, .field:has(textarea:disabled) .tiny{opacity:.55}

/* The file input's helper text was flowing alongside the button. */
input[type=file]{
  width:100%;
  padding:.5rem;
  background:var(--paper);
  border:1px dashed var(--rule-line);
  border-radius:var(--radius);
  font-size:.88rem;
}
.field input[type=file] + .tiny{display:block;margin-top:.4rem}

/* KPI tiles. An inline grid-template-columns can't be overridden by a media
   query, which is why these are a class: at 11rem minimum two tiles need ~380px
   and a 390px phone has ~358px of content box, so they dropped to one per row
   and pushed the table below the fold. 8rem fits two. */
.kpis{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,8rem),1fr));
  gap:clamp(.7rem,2vw,1.75rem);
}
.kpis .card{padding:clamp(.9rem,2.5vw,1.75rem)}
.kpis p:last-child{font-size:clamp(1.35rem,5vw,2rem);line-height:1.2}
@media (min-width:48rem){
  .kpis{grid-template-columns:repeat(auto-fit,minmax(11rem,1fr))}
}
/* A tile is a link to the list it counts. */
.kpis a.kpi-link{text-decoration:none;display:block;transition:box-shadow .15s,transform .15s}
.kpis a.kpi-link:hover,.kpis a.kpi-link:focus-visible{transform:translateY(-1px);box-shadow:0 2px 10px rgba(51,47,33,.14)}

/* The cart pill wrapped onto two lines in the bar once the count appeared. */
.nav .cart{white-space:nowrap}

/* The band's bottom padding reserves room for the packs that overlap into it.
   With an empty catalogue there are no packs, and that reserved space becomes a
   quarter-screen of dead birch. A new store launches empty, so this is the
   first state anyone sees. */
.band.bare{padding-bottom:clamp(2.5rem,7vh,4.5rem)}

/* Hero calls to action, sitting under the band's lede. Light on birch, so they
   read as the band's own buttons rather than borrowed from the board. */
.band-actions{
  display:flex;flex-wrap:wrap;gap:.75rem;justify-content:center;
  margin-top:clamp(1.5rem,3.5vh,2.25rem);
}
.band-actions .btn-light{margin:0}

/* Closing call to action — centred, with room above so it reads as the end of
   the page rather than part of the shipping grid.
   max-width:none overrides `.board p{max-width:62ch}`, which otherwise centres
   the button inside a 62-character column starting at the left margin, leaving
   it visibly off-centre on a wide screen. Scoped under .board so it outranks
   `.board p` (0,1,1) — a bare .closing-cta (0,1,0) loses and the cap stays. */
.board .closing-cta{
  margin-top:clamp(2rem,5vh,3rem);
  max-width:none;
  text-align:center;
}

/* ---------- The manifesto ----------
   Set as verse, not prose: the lines are short declarations and they read as
   one flat paragraph when they are run together. Everything here is centred on
   its own measure, so a line break lands where the sentence ends rather than
   wherever the column happens to run out. */
.manifesto-ask{
  margin-top:.9rem;font-size:clamp(1.02rem,2.4vw,1.2rem);line-height:1.7;
  color:rgba(51,47,33,.72);max-width:40ch;margin-inline:auto;
}
.manifesto-line{
  margin-top:clamp(1.5rem,3.5vh,2.25rem);
  font-size:clamp(1rem,2.2vw,1.1rem);line-height:1.75;
  max-width:38ch;margin-inline:auto;text-wrap:balance;
}
.manifesto-things{
  list-style:none;padding:0;
  margin:clamp(1.5rem,3.5vh,2.25rem) auto 0;
  display:grid;gap:.5rem;justify-items:center;
  font-size:clamp(1rem,2.2vw,1.12rem);line-height:1.6;
}
.manifesto-things li:last-child{
  margin-top:.55rem;max-width:30ch;color:rgba(51,47,33,.8);
  text-wrap:balance;
}

/* The manifesto's closing line is set as a mark rather than a sentence: wider
   letter-spacing, its own rule above it, and it breaks in two at phone width
   the way the band's headline does. */
.manifesto-sign{
  margin-top:clamp(1.75rem,4vh,2.5rem);
  padding-top:clamp(1.5rem,3.5vh,2rem);
  border-top:1px solid rgba(51,47,33,.18);
  font-size:.78rem;letter-spacing:.2em;text-transform:uppercase;
  color:rgba(51,47,33,.78);
}
.manifesto-sign .br{display:block}
@media (min-width:46rem){.manifesto-sign .br{display:inline}}

/* ---------- Centred sections ----------
   .board p carries max-width:62ch so a paragraph never runs to an
   uncomfortable measure. Centring the text alone would leave that column
   pinned to the left, so the measure has to be centred too — margin-inline:auto
   on the paragraphs, not just text-align on the parent. */
.centered{text-align:center}
/* The plain-words section on the home page: centred like the manifesto, with
   air between its paragraphs. */
.about h2{margin-bottom:1rem}
.about p + p{margin-top:.9rem}
.centered p,
.centered .intro{margin-inline:auto}
.centered .trade-actions{justify-content:center}
.centered dl.terms{margin-inline:auto}

/* The trade block is a two-column grid when the terms table is present. With
   the table moved to /wholesale it is a single column, so it should sit in the
   middle of the band rather than hugging the left edge. */
.trade-inner.centered{
  grid-template-columns:minmax(0,1fr);
  justify-items:center;
}
.trade-inner.centered > div{max-width:46rem}

/* ---------- Policy pages ---------- */
.policy-section + .policy-section{
  margin-top:1.75rem;
  padding-top:1.5rem;
  border-top:1px solid var(--rule-soft);
}
.policy-section h2{
  font-size:1.02rem;
  font-weight:500;
  letter-spacing:0;
  margin-bottom:.6rem;
}
.policy-section p{margin-bottom:.7rem;max-width:60ch}
.policy-section p:last-child{margin-bottom:0}
.policy-identity p{font-size:.93rem}
