/* ══════════════════════════════════════════════════════════
   SO DOPE — subpages (retailer / menu / investors)
   Cinematic chapters of the homepage: dark base, neon graffiti
   accents, layered motion.
   ══════════════════════════════════════════════════════════ */
.subpage { background: var(--bg); }
[hidden] { display: none !important; }  /* the hidden attribute must beat display:grid/flex */

/* ---------- Ambient atmosphere (shared with the homepage feel) ---------- */
.aurora {
  position: fixed;
  inset: -20% -10%;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(38% 32% at 18% 22%, rgba(198,242,78,0.13), transparent 62%),
    radial-gradient(34% 30% at 82% 30%, rgba(255,62,165,0.14), transparent 62%),
    radial-gradient(40% 34% at 55% 88%, rgba(46,230,255,0.11), transparent 62%);
  filter: blur(28px);
  animation: aurora-drift 26s ease-in-out infinite alternate;
}
@keyframes aurora-drift {
  0%   { transform: translate3d(-2%, -1%, 0) scale(1); }
  50%  { transform: translate3d(3%, 2%, 0) scale(1.08); }
  100% { transform: translate3d(-1%, 3%, 0) scale(1.03); }
}
.grain {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0.16;
  mix-blend-mode: overlay;
  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.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
  animation: grain-shift 0.7s steps(3) infinite;
}
@keyframes grain-shift {
  0%,100% { transform: translate(0, 0); }
  33%     { transform: translate(-3%, 2%); }
  66%     { transform: translate(2%, -3%); }
}
.subpage > nav, .subpage > header, .subpage > main,
.subpage > section, .subpage > footer { position: relative; z-index: 2; }

/* ---------- Page hero (cinematic, parallaxed) ---------- */
.page-hero {
  position: relative;
  min-height: 92vh;
  min-height: 92svh; /* stable on iOS while the toolbar collapses */
  display: grid;
  place-items: center;
  padding: 170px 32px 100px;
  overflow: hidden;
  text-align: center;
}
.page-hero.tall { min-height: 100vh; min-height: 100svh; }
.page-hero-media {
  position: absolute;
  inset: -12% 0 -12%;
  width: 100%;
  height: 124%;
  object-fit: cover;
  will-change: transform;
}
.page-hero-video { opacity: 0.5; filter: saturate(1.35) contrast(1.05); }
.page-hero-img   { opacity: 0.55; filter: saturate(1.3); }
.page-hero-scrim {
  position: absolute; inset: 0;
  background:
    radial-gradient(110% 80% at 50% 45%, transparent 38%, rgba(5,5,5,0.72) 100%),
    linear-gradient(180deg, rgba(5,5,5,0.8) 0%, rgba(5,5,5,0.28) 42%, var(--bg) 100%);
}
.page-hero-inner { position: relative; z-index: 3; max-width: 940px; margin: 0 auto; will-change: transform, opacity; }
.page-hero h1 {
  font-family: var(--display);
  font-size: clamp(2.8rem, 8.5vw, 7rem);
  line-height: 1.0;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  text-shadow: 0 6px 60px rgba(0,0,0,0.85);
}
.page-lede {
  margin: 26px auto 0;
  max-width: 640px;
  color: var(--dim);
  font-size: 1.12rem;
  line-height: 1.75;
}
.hero-scroll-cue {
  position: absolute;
  bottom: 34px; left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.4em;
  color: var(--dim);
  animation: bob 1.8s ease-in-out infinite;
}

/* headline words rise on load */
.rise > span {
  display: inline-block;
  animation: rise-in 1s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
.rise > span:nth-child(2) { animation-delay: 0.12s; }
.rise > span:nth-child(3) { animation-delay: 0.24s; }
@keyframes rise-in {
  from { opacity: 0; transform: translateY(90%) rotate(3deg); }
  to   { opacity: 1; transform: none; }
}

/* ---------- Section chrome ---------- */
.section-head { text-align: center; max-width: 760px; margin: 0 auto 60px; }
.section-head h2 {
  font-family: var(--display);
  font-size: clamp(2.2rem, 5.5vw, 4.2rem);
  text-transform: uppercase;
  line-height: 1.06;
  letter-spacing: 0.02em;
}
.section-head p { margin-top: 18px; color: var(--dim); line-height: 1.75; }

/* ---------- Retailer: perks strip ---------- */
.perks { max-width: 1150px; margin: 0 auto; padding: 110px 28px 0; }
.perk-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; }
.perk {
  position: relative;
  padding: 32px 26px;
  border-radius: 20px;
  background: rgba(255,255,255,0.035);
  border: 1px solid rgba(255,255,255,0.09);
  overflow: hidden;
  transition: border-color 0.35s, box-shadow 0.35s, transform 0.2s;
  transform-style: preserve-3d;
}
.perk::after {   /* cursor-following sheen */
  content: "";
  position: absolute; inset: 0;
  background: radial-gradient(50% 60% at var(--gx, 50%) var(--gy, 50%), rgba(198,242,78,0.14), transparent 70%);
  opacity: 0;
  transition: opacity 0.35s;
  pointer-events: none;
}
.perk:hover { border-color: rgba(198,242,78,0.5); box-shadow: 0 28px 60px rgba(0,0,0,0.55); }
.perk:hover::after { opacity: 1; }
.perk-icon { font-size: 1.9rem; }
.perk .card-num { font-family: var(--display); font-size: 2.4rem; opacity: 0.9; display: block; }
.perk h3 { font-family: var(--display); font-size: 1.25rem; letter-spacing: 0.05em; margin: 14px 0 10px; }
.perk p { color: var(--dim); font-size: 0.95rem; line-height: 1.65; }

/* ---------- Forms ---------- */
.form-wrap { max-width: 800px; margin: 0 auto; padding: 90px 24px 140px; }
.form-shell {
  padding: 46px 44px;
  border-radius: 26px;
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.1);
  backdrop-filter: blur(10px);
  box-shadow: 0 50px 110px rgba(0,0,0,0.55);
}
.neon-form { display: grid; gap: 18px; }
.form-section-title {
  position: relative;
  font-family: var(--display);
  font-size: 1.35rem;
  letter-spacing: 0.08em;
  margin-top: 30px;
  padding-left: 16px;
}
.form-section-title::before {
  content: "";
  position: absolute;
  left: 0; top: 12%;
  width: 4px; height: 76%;
  border-radius: 4px;
  background: currentColor;
  box-shadow: 0 0 14px currentColor;
}
.form-section-title:first-child { margin-top: 0; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.grid-3 { display: grid; grid-template-columns: 2fr 1fr 1.2fr; gap: 18px; }
.neon-form label {
  display: grid;
  gap: 8px;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  color: var(--dim);
  text-transform: uppercase;
  transition: color 0.25s;
}
.neon-form label:focus-within { color: var(--lime); }
.neon-form label.filled { color: rgba(245,244,239,0.8); }
.neon-form input {
  padding: 15px 16px;
  font: 500 1rem var(--body);
  color: var(--ink);
  background: rgba(255,255,255,0.045);
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 12px;
  outline: none;
  transition: border-color 0.25s, box-shadow 0.25s, background 0.25s;
}
.neon-form input::placeholder { color: rgba(245,244,239,0.5); letter-spacing: 0; }
.neon-form input:focus {
  border-color: var(--lime);
  background: rgba(198,242,78,0.05);
  box-shadow: 0 0 0 3px rgba(198,242,78,0.16), 0 0 26px rgba(198,242,78,0.14);
}
.neon-form input[type="file"] { padding: 12px; cursor: pointer; }
.neon-form input[type="file"]::file-selector-button {
  margin-right: 14px;
  padding: 8px 16px;
  border: 1px solid var(--cyan);
  border-radius: 999px;
  background: transparent;
  color: var(--cyan);
  font: 700 0.75rem var(--body);
  letter-spacing: 0.15em;
  cursor: pointer;
  transition: background 0.25s, color 0.25s;
}
.neon-form input[type="file"]::file-selector-button:hover { background: var(--cyan); color: #050505; }
.hint { font-weight: 400; letter-spacing: 0.02em; text-transform: none; color: rgba(245,244,239,0.42); font-size: 0.82rem; }
.neon-form .btn { margin-top: 26px; justify-self: start; border: none; cursor: pointer; }
.form-status { color: var(--magenta); font-weight: 700; min-height: 1.2em; }

.form-success { text-align: center; padding: 70px 0 40px; display: grid; gap: 22px; justify-items: center; }
.form-success h2 { font-family: var(--display); font-size: clamp(2rem, 5vw, 3.6rem); }
.form-success p { color: var(--dim); line-height: 1.7; }
.form-success a:not(.btn) { color: var(--cyan); }
.success-mark {
  width: 92px; height: 92px;
  border-radius: 50%;
  display: grid; place-items: center;
  font-size: 2.6rem;
  border: 2px solid var(--lime);
  color: var(--lime);
  box-shadow: 0 0 40px rgba(198,242,78,0.4), inset 0 0 30px rgba(198,242,78,0.12);
  animation: pop-in 0.6s cubic-bezier(0.2, 1.4, 0.4, 1) both;
}
@keyframes pop-in { from { opacity: 0; transform: scale(0.5) rotate(-12deg); } to { opacity: 1; transform: none; } }

/* ---------- Sign-in gate ---------- */
.gate {
  position: relative;
  min-height: 100vh;
  min-height: 100svh; /* stable on iOS while the toolbar collapses */
  display: grid;
  place-items: center;
  padding: 140px 24px 90px;
  overflow: hidden;
}
.gate-media {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0.4;
  filter: saturate(1.3);
  animation: ken-burns 26s ease-in-out infinite alternate;
}
@keyframes ken-burns {
  from { transform: scale(1) translate3d(0, 0, 0); }
  to   { transform: scale(1.14) translate3d(-1.5%, 1.5%, 0); }
}
.gate-scrim {
  position: absolute; inset: 0;
  background:
    radial-gradient(80% 70% at 50% 50%, rgba(5,5,5,0.55), rgba(5,5,5,0.92) 100%),
    linear-gradient(180deg, var(--bg), transparent 30%, transparent 72%, var(--bg));
}
.gate-card {
  position: relative;
  z-index: 3;
  width: min(450px, 100%);
  padding: 46px 40px;
  text-align: center;
  background: rgba(10,10,14,0.72);
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 26px;
  backdrop-filter: blur(16px);
  box-shadow: 0 50px 110px rgba(0,0,0,0.7), 0 0 60px rgba(198,242,78,0.06);
  display: grid;
  gap: 14px;
  justify-items: center;
  animation: card-in 0.9s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
@keyframes card-in { from { opacity: 0; transform: translateY(28px) scale(0.97); } to { opacity: 1; transform: none; } }

/* justify-items:center sizes every grid item to fit-content, so anything that
   isn't explicitly width:100% SHRINK-WRAPS to its own text while the form and
   the buttons run full width — which is what made this card look ragged. The
   panels, the feet and WordPress's login form all want the card's full width;
   the logo is the one child that genuinely wants centring at its own size, and
   it re-declares its width below (equal specificity, later source order). */
.gate-card > * { width: 100%; }
.gate-logo { width: 190px; justify-self: center; filter: drop-shadow(0 6px 26px rgba(0,0,0,0.8)); }

/* The three sign-in panels are single grid items, so the card's own 14px gap
   never reaches inside them — without this their contents sit flush against
   each other on the Node build while WordPress (whose equivalents ARE direct
   children of the card) gets the gap. Same rhythm on both targets. */
#signin-panel, #reset-request-panel, #reset-confirm-panel { display: grid; gap: 14px; }
/* .kicker carries an 18px bottom margin from the homepage, where it is not in
   a gapped grid. Here it double-spaces the first row. */
.gate-card .kicker { margin-bottom: 0; }
.gate-card h1 { font-family: var(--display); font-size: 2.1rem; letter-spacing: 0.04em; }
.gate-lede { color: var(--dim); font-size: 0.95rem; line-height: 1.65; }
.gate-card form { display: grid; gap: 14px; width: 100%; margin-top: 8px; }
.gate-card label { display: grid; gap: 6px; text-align: left; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.2em; color: var(--dim); }
.gate-card input {
  padding: 13px 14px;
  font: 500 1rem var(--body);
  color: var(--ink);
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 10px;
  outline: none;
  transition: border-color 0.25s, box-shadow 0.25s;
}
.gate-card input:focus { border-color: var(--lime); box-shadow: 0 0 0 3px rgba(198,242,78,0.15); }
/* One radius family and one vertical rhythm for the whole card. Site-wide .btn
   is a 999px pill with 18px/44px padding, which above a stack of 10px-radius
   inputs read as two different components bolted together. Scoped to
   .gate-card only — every other button on the site keeps the pill. */
.gate-card input,
.gate-card .btn { border-radius: 12px; }
.gate-card .btn {
  border: none;
  cursor: pointer;
  margin-top: 6px;
  width: 100%;
  padding: 15px 22px;
  text-align: center;
}
.gate-card .btn:focus-visible { outline: 2px solid var(--lime); outline-offset: 3px; }

.gate-foot { font-size: 0.85rem; color: var(--dim); text-align: center; }
.gate-foot a { color: var(--lime); }
.gate-foot a:focus-visible { outline: 2px solid var(--lime); outline-offset: 3px; border-radius: 3px; }
/* The way back into a locked-out account. It has to look like something you
   can click without looking like a second submit button. */
.gate-foot-reset a {
  font-weight: 700;
  font-size: 0.9rem;
  letter-spacing: 0.04em;
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 1px;
}
.gate-foot-reset a:hover { color: var(--magenta); }
/* Everything below the hairline is for people who do NOT have an account, and
   should not compete with the two things above it that are for people who do. */
.gate-foot-alt { padding-top: 14px; border-top: 1px solid rgba(255,255,255,0.1); }

/* ---------- WordPress: core wp_login_form() inside the gate card ----------
   The WP gate does not render the markup above. It renders CORE's login form —
   `<p class="login-username"><label>…</label><input class="input" size="20">`,
   a remember-me checkbox, and `#wp-submit` as an `<input type="submit">`. None
   of that matches `.gate-card form / label / input`, and that mismatch is the
   whole reason the live gate looked broken while menu.html looked fine:
     • the text inputs kept their `size="20"` width instead of filling the card;
     • `#wp-submit` is an <input>, so `.gate-card input` styled the SUBMIT BUTTON
       as a dark text field;
     • `#rememberme` is also an <input>, so the checkbox inherited 13px of
       padding and `.gate-card label`'s display:grid stacked it above its text;
     • core's <p> wrappers are grid items with no internal layout.

   We STYLE core's markup rather than replace it. Replacing wp_login_form()
   means owning the nonce, the redirect, the auth cookies and lost-password
   integration on a LIVE authentication surface, and re-owning them every time
   core changes. The structure below is stable core API; the wording comes from
   wp_login_form()'s own args (label_username / label_log_in) in backend.php, so
   nothing here reimplements a form. Everything is scoped under .gate-card, so
   wp-login.php and wp-admin are untouched. */
.gate-card #loginform { display: grid; gap: 14px; width: 100%; margin-top: 8px; }
.gate-card #loginform p { margin: 0; }
.gate-card #loginform p.login-username,
.gate-card #loginform p.login-password { display: grid; gap: 6px; text-align: left; }
/* display:block, not the grid `.gate-card label` uses: core puts the input
   NEXT TO the label, not inside it, so there is nothing here to stack. */
.gate-card #loginform label {
  display: block;
  text-align: left;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  color: var(--dim);
}
.gate-card #loginform input[type="text"],
.gate-card #loginform input[type="password"] {
  width: 100%;
  box-sizing: border-box;
}
.gate-card #loginform p.login-remember { justify-self: start; }
.gate-card #loginform p.login-remember label {
  display: flex;
  align-items: center;
  gap: 9px;
  letter-spacing: 0.14em;
  cursor: pointer;
}
.gate-card #loginform #rememberme {
  width: auto;
  padding: 0;
  margin: 0;
  flex: 0 0 auto;
  border-radius: 3px;
  accent-color: var(--lime);
}
/* `.login-submit` also carries the hidden redirect_to input, which the UA
   stylesheet keeps out of the layout. */
.gate-card #loginform p.login-submit { display: grid; }
/* #wp-submit has to escape `.gate-card input` entirely and become the same
   button menu.html's `.btn` renders. The id out-specifies the input rules, so
   this is a clean override rather than a pile of !important. */
.gate-card #loginform #wp-submit {
  display: block;
  width: 100%;
  margin-top: 6px;
  padding: 15px 22px;
  font-family: var(--display);
  font-size: 1.05rem;
  letter-spacing: 0.14em;
  text-align: center;
  color: #050505;
  background: var(--lime);
  border: none;
  border-radius: 12px;
  box-shadow: 0 0 34px rgba(198,242,78,0.4);
  cursor: pointer;
  transition: transform 0.3s, box-shadow 0.3s, background 0.3s;
}
.gate-card #loginform #wp-submit:hover {
  transform: translateY(-3px) scale(1.03);
  background: var(--magenta);
  color: var(--ink);
  box-shadow: 0 0 44px rgba(255,62,165,0.55);
}
.gate-card #loginform #wp-submit:focus-visible { outline: 2px solid var(--lime); outline-offset: 3px; }

/* ---------- Live menu ---------- */
.menu-wrap { max-width: 1220px; margin: 0 auto; padding: 150px 28px 120px; }
.menu-head {
  display: flex;
  justify-content: space-between;
  align-items: end;
  gap: 20px;
  flex-wrap: wrap;
  margin-bottom: 32px;
  padding-bottom: 26px;
  border-bottom: 1px solid rgba(255,255,255,0.1);
}
.menu-head h1 { font-family: var(--display); font-size: clamp(2.2rem, 5vw, 4rem); letter-spacing: 0.03em; }
.live-dot {
  display: inline-block;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--lime);
  box-shadow: 0 0 12px var(--lime);
  animation: live-pulse 1.6s ease-in-out infinite;
  vertical-align: middle;
}
@keyframes live-pulse { 0%,100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.35; transform: scale(0.85); } }
.menu-meta { color: var(--dim); font-size: 0.9rem; margin-top: 8px; }
.menu-user { display: flex; align-items: center; gap: 16px; color: var(--dim); font-weight: 700; letter-spacing: 0.06em; }
.btn-ghost {
  padding: 10px 20px;
  background: transparent;
  border: 1px solid rgba(255,255,255,0.25);
  border-radius: 999px;
  color: var(--ink);
  font: 700 0.75rem var(--body);
  letter-spacing: 0.2em;
  cursor: pointer;
  transition: border-color 0.25s, color 0.25s;
}
.btn-ghost:hover { border-color: var(--magenta); color: var(--magenta); }
.menu-filters { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 30px; }
.chip {
  padding: 9px 20px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.18);
  background: transparent;
  color: var(--dim);
  font: 700 0.8rem var(--body);
  letter-spacing: 0.12em;
  cursor: pointer;
  transition: all 0.25s;
}
.chip.on, .chip:hover { border-color: var(--lime); color: var(--lime); box-shadow: 0 0 16px rgba(198,242,78,0.2); }
.menu-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; }

/* ---------- Pre-Order Inventory ----------
   A second shelf, below the live one and visibly not it: these items are runs
   that haven't been received into inventory yet. Requesting one is still a
   request, but the stock behind it doesn't exist yet, so it must never read as
   "on the shelf". Hence the separate heading, the ember accent, and the pill. */
.menu-preorder { margin-top: 54px; }
.menu-subhead {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px 16px;
  margin: 0 0 18px; padding-top: 22px; border-top: 1px solid rgba(255,255,255,0.1);
}
.menu-subhead h2 {
  font-family: var(--display); font-size: clamp(1.4rem, 3vw, 2.1rem);
  letter-spacing: 0.03em; margin: 0; color: var(--ember);
}
.menu-subhead p { margin: 0; color: var(--dim); font-size: 0.85rem; }
.menu-card.pre-order { border-color: rgba(255,122,24,0.3); }
.preorder-pill {
  font-size: 0.65rem; font-weight: 700; letter-spacing: 0.18em; padding: 5px 12px;
  border-radius: 999px; color: var(--ember); border: 1px solid var(--ember);
}
.menu-card {
  position: relative;
  padding: 26px;
  background: rgba(255,255,255,0.035);
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 20px;
  display: grid;
  gap: 10px;
  align-content: start;
  overflow: hidden;
  transition: transform 0.35s, border-color 0.35s, box-shadow 0.35s;
  animation: card-in 0.6s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
.menu-card::before {   /* neon edge that lights on hover */
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 20px;
  padding: 1px;
  background: linear-gradient(135deg, var(--lime), var(--magenta), var(--cyan));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  opacity: 0;
  transition: opacity 0.35s;
  pointer-events: none;
}
.menu-card:hover { transform: translateY(-7px); box-shadow: 0 30px 60px rgba(0,0,0,0.6); }
.menu-card:hover::before { opacity: 1; }
.menu-card.sold-out { opacity: 0.42; }
.menu-card-top { display: flex; justify-content: space-between; align-items: center; }
.menu-cat { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.25em; color: var(--cyan); text-transform: uppercase; }
.stock-pill { font-size: 0.65rem; font-weight: 700; letter-spacing: 0.18em; padding: 5px 12px; border-radius: 999px; }
.stock-pill.in  { color: var(--lime); border: 1px solid var(--lime); box-shadow: 0 0 12px rgba(198,242,78,0.25); }
.stock-pill.low { color: var(--ember); border: 1px solid var(--ember); box-shadow: 0 0 12px rgba(255,122,24,0.25); }
.stock-pill.out { color: var(--magenta); border: 1px solid var(--magenta); }
.menu-card h3 { font-family: var(--display); font-size: 1.4rem; letter-spacing: 0.04em; }
.menu-specs { color: var(--ink); font-size: 0.85rem; font-weight: 700; letter-spacing: 0.08em; }
/* The expected-release line rides the spec line's size and rhythm but must not
   compete with it: the specs are what the product IS, this is a promise about
   when. Italic and dimmed, and the spec line's 700 weight is deliberately not
   inherited — bold italic reads louder than the thing it sits under, which is
   the opposite of the intent. Contract 8; rendered only on pre-order items,
   by menu-view.js's releaseLine(). */
.menu-release { color: var(--dim); font-style: italic; font-weight: 500; letter-spacing: 0.04em; }
.menu-desc { color: var(--dim); font-size: 0.9rem; line-height: 1.6; }
/* On a CARD the description is a teaser, not the copy. The grid is
   `auto-fill, minmax(300px, 1fr)`, so one product with four sentences used to
   set the row height for every card beside it and pushed their ADD buttons
   down the page. Three lines, then it stops — the full text (formatted, and
   with nothing clipped) is one click away in the dialog, which is where the
   long read belongs. Scoped to .menu-card so the dialog is untouched: the
   -webkit- prefixed line-clamp trio is the version every current browser
   implements, including Firefox since 68. */
.menu-card .menu-desc {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.menu-card-foot { display: flex; justify-content: space-between; align-items: baseline; margin-top: 8px; }
.menu-price { font-family: var(--display); font-size: 1.6rem; color: var(--lime); }
/* Cased items are picked by the case but priced per unit, and a price with no
   denominator beside a "2 cases" picker reads as the case price. */
.menu-per-unit { font-family: var(--body); font-size: 0.7rem; letter-spacing: 0.1em; color: rgba(245,244,239,0.45); }
.menu-sku { font-size: 0.7rem; color: rgba(245,244,239,0.35); letter-spacing: 0.12em; }
.menu-empty { color: var(--dim); padding: 40px 0; }

/* ---------- Request Order (the menu cart) ----------
   A REQUEST, not an order: nothing here reserves stock or fixes a price. The
   copy says so in the panel, and the totals are labelled indicative, because
   the team re-prices from the product catalogue when they draft the invoice. */
.menu-card-add { display: flex; gap: 8px; margin-top: 12px; }
.menu-card-add input {
  width: 74px; padding: 9px 10px; border-radius: 10px;
  background: rgba(255,255,255,0.05); color: var(--paper);
  border: 1px solid rgba(255,255,255,0.14); font: inherit; font-size: 0.9rem;
}
/* Cased items order by the case, so the control names the unit maths out loud
   ("2 cases — 80 units") rather than leaving the buyer to multiply. It needs
   the room a bare quantity box doesn't. */
.menu-card-add select {
  flex: 1; min-width: 0; padding: 9px 10px; border-radius: 10px;
  background: rgba(255,255,255,0.05); color: var(--paper);
  border: 1px solid rgba(255,255,255,0.14); font: inherit; font-size: 0.9rem;
}
.menu-card-add select option { background: #12121b; color: var(--paper); }
.menu-card-add .btn-add { flex: 0 0 auto; }
.btn-add {
  flex: 1; padding: 9px 14px; border-radius: 10px; cursor: pointer;
  background: transparent; color: var(--lime); border: 1px solid var(--lime);
  font-family: var(--display); letter-spacing: 0.1em; font-size: 0.85rem;
  transition: background 0.2s, color 0.2s;
}
.btn-add:hover { background: var(--lime); color: #0b0b12; }

/* Pinned to the viewport so a long menu never hides the request in progress.
   Uses svh, not vh, so phone browser chrome can't sit on top of the button. */
.cart-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  background: rgba(11,11,18,0.94); backdrop-filter: blur(14px);
  border-top: 1px solid rgba(255,255,255,0.12);
}
.cart-bar-inner {
  max-width: 1150px; margin: 0 auto; padding: 14px 28px;
  display: flex; gap: 14px; align-items: center; justify-content: space-between;
}
.btn-add-big {
  padding: 12px 26px; font-size: 0.9rem;
  background: var(--lime); color: #0b0b12; border: none; border-radius: 10px;
  font-family: var(--display); letter-spacing: 0.1em; cursor: pointer;
}
.btn-add-big:disabled { opacity: 0.55; cursor: default; }
.cart-panel {
  max-width: 1150px; margin: 0 auto; padding: 22px 28px 6px;
  max-height: 58svh; overflow-y: auto;
  border-bottom: 1px solid rgba(255,255,255,0.08);
}
.cart-panel h3 {
  font-family: var(--display); letter-spacing: 0.08em; color: var(--lime);
  margin: 0 0 14px; font-size: 1.05rem;
}
.cart-table { width: 100%; border-collapse: collapse; }
.cart-table td { padding: 9px 0; border-bottom: 1px solid rgba(255,255,255,0.07); font-size: 0.92rem; }
.cart-sku { display: block; font-size: 0.68rem; letter-spacing: 0.12em; color: rgba(245,244,239,0.35); }
.cart-qty input, .cart-qty select {
  width: 68px; padding: 6px 8px; border-radius: 8px; font: inherit; font-size: 0.85rem;
  background: rgba(255,255,255,0.05); color: var(--paper); border: 1px solid rgba(255,255,255,0.14);
}
.cart-qty select { width: auto; max-width: 150px; }
.cart-qty select option { background: #12121b; color: var(--paper); }
/* Units under the case count: the retailer picked cases, the invoice will be
   in units, and hiding that until the invoice arrives would be a surprise. */
.cart-units { display: block; font-size: 0.68rem; letter-spacing: 0.08em; color: rgba(245,244,239,0.4); margin-top: 3px; }
/* The menu moved under a cart that was already open. Amber rather than red:
   nothing is broken and nothing was lost, but this line needs a number before
   it can be sent. */
.cart-stale { color: var(--ember); }
.cart-line { text-align: right; color: var(--lime); white-space: nowrap; }
.cart-x {
  background: none; border: none; color: rgba(245,244,239,0.4);
  font-size: 1.3rem; line-height: 1; cursor: pointer; padding: 0 0 0 12px;
}
.cart-x:hover { color: var(--magenta); }
.cart-notes-label { display: block; margin: 16px 0 4px; color: var(--dim); font-size: 0.82rem; }
.cart-notes-label textarea {
  display: block; width: 100%; margin-top: 6px; padding: 10px 12px; border-radius: 10px;
  background: rgba(255,255,255,0.05); color: var(--paper);
  border: 1px solid rgba(255,255,255,0.14); font: inherit; font-size: 0.9rem; resize: vertical;
}
.cart-total-row { display: flex; justify-content: space-between; align-items: baseline; margin: 14px 0 4px; color: var(--dim); }
.cart-total-row strong { font-family: var(--display); font-size: 1.4rem; color: var(--paper); }
.cart-fineprint { color: rgba(245,244,239,0.45); font-size: 0.78rem; line-height: 1.5; margin: 0 0 10px; }
.cart-done {
  position: fixed; left: 50%; bottom: 96px; transform: translateX(-50%); z-index: 41;
  background: var(--lime); color: #0b0b12; padding: 13px 22px; border-radius: 12px;
  font-weight: 700; font-size: 0.9rem; max-width: min(92vw, 460px); text-align: center;
}
@media (max-width: 640px) {
  .cart-bar-inner { padding: 12px 18px; }
  .cart-panel { padding: 18px 18px 4px; max-height: 52svh; }
  .btn-add-big { padding: 12px 18px; }
}

/* ---------- Investors ---------- */
.invest-wrap { max-width: 1150px; margin: 0 auto; padding: 110px 28px 140px; }
.invest-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 22px; }
.invest-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 50px;
  justify-content: center;
  text-align: center;
  margin-top: 100px;
  padding: 60px 28px;
  border-radius: 26px;
  background: rgba(255,255,255,0.028);
  border: 1px solid rgba(255,255,255,0.09);
}
.invest-stats .stat-num { font-family: var(--display); font-size: clamp(2.8rem, 6vw, 5rem); display: block; }
.invest-stats .stat-label { letter-spacing: 0.28em; font-size: 0.76rem; font-weight: 700; color: var(--dim); }
.invest-cta { text-align: center; margin-top: 110px; display: grid; gap: 18px; justify-items: center; }
.invest-cta h2 { font-family: var(--display); font-size: clamp(2.4rem, 6vw, 4.5rem); letter-spacing: 0.03em; }

/* ---------- Contact: textarea, honeypot, channel links ---------- */
.neon-form textarea {
  padding: 15px 16px;
  font: 500 1rem var(--body);
  color: var(--ink);
  background: rgba(255,255,255,0.045);
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 12px;
  outline: none;
  resize: vertical;
  min-height: 150px;
  line-height: 1.6;
  transition: border-color 0.25s, box-shadow 0.25s, background 0.25s;
}
.neon-form textarea::placeholder { color: rgba(245,244,239,0.5); letter-spacing: 0; }
.neon-form textarea:focus {
  border-color: var(--lime);
  background: rgba(198,242,78,0.05);
  box-shadow: 0 0 0 3px rgba(198,242,78,0.16), 0 0 26px rgba(198,242,78,0.14);
}
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.contact-link {
  color: var(--cyan);
  text-decoration: none;
  font-weight: 700;
  border-bottom: 1px solid rgba(46,230,255,0.35);
  transition: color 0.25s, border-color 0.25s;
}
.contact-link:hover { color: var(--lime); border-color: var(--lime); }
.perk p + p { margin-top: 10px; }

/* ---------- Licensing ---------- */
.licensing { max-width: 1150px; margin: 0 auto; padding: 40px 28px 140px; }
.license-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); gap: 22px; }
.license-card {
  position: relative;
  padding: 32px 28px;
  border-radius: 20px;
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.1);
  transition: border-color 0.35s, box-shadow 0.35s;
}
.license-card:hover { border-color: rgba(46,230,255,0.4); box-shadow: 0 24px 55px rgba(0,0,0,0.5); }
.license-flag {
  display: inline-block;
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.22em;
  border: 1px solid currentColor;
  box-shadow: 0 0 14px currentColor;
}
.license-card h3 { font-family: var(--display); font-size: 1.3rem; letter-spacing: 0.05em; margin: 16px 0 18px; }
.license-card dl { display: grid; gap: 4px; margin: 0; }
.license-card dt {
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--dim);
  margin-top: 12px;
}
.license-card dt:first-child { margin-top: 0; }
.license-card dd { margin: 0; font-size: 1rem; line-height: 1.55; }
.license-card dd[data-fill] {           /* obvious placeholder until real data is filled in */
  color: var(--ember);
  font-size: 0.9rem;
  font-style: italic;
  opacity: 0.85;
}
.license-note {
  max-width: 720px;
  margin: 44px auto 0;
  text-align: center;
  color: var(--dim);
  font-size: 0.92rem;
  line-height: 1.7;
}

/* ══════════ Find SO DOPE — locator ══════════ */
.find-head {
  position: relative;
  padding: 150px 28px 40px;
  text-align: center;
}
.find-head-inner { max-width: 820px; margin: 0 auto; }
.find-head h1 {
  font-family: var(--display);
  font-size: clamp(2.6rem, 7.5vw, 5.5rem);
  line-height: 1.02;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.btn-locate {
  margin-top: 30px;
  border: none;
  cursor: pointer;
  font-family: var(--display);
}
.locate-note { margin-top: 14px; color: var(--dim); font-size: 0.9rem; min-height: 1.2em; }

/* WordPress renders Near Me inside [sodope_locator] rather than the page hero,
   because the hero there is the generic [sodope_page_hero] shared with four other
   pages. The button inherited the hero's centring on the static build and had
   none of its own, so outside it the button sat flush against the viewport edge.
   Matches .map-shell / .stores geometry so the three line up. */
.locate-section {
  max-width: 1220px;
  margin: 0 auto;
  padding: 28px 28px 0;
  text-align: center;
}
.locate-section .btn-locate { margin-top: 0; }

/* ---------- Map ---------- */
.map-section { padding: 20px 28px 0; }
.map-shell {
  position: relative;
  max-width: 1220px;
  margin: 0 auto;
  height: clamp(340px, 52vh, 560px);
  border-radius: 26px;
  overflow: hidden;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 40px 90px rgba(0,0,0,0.6), 0 0 60px rgba(46,230,255,0.06);
  background: #0d0d12;
}
.map-canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.map-fallback { position: absolute; inset: 0; display: grid; place-items: center; padding: 30px; text-align: center; }
.map-fallback-inner { max-width: 480px; display: grid; gap: 12px; justify-items: center; }
.map-fallback-icon { font-size: 2.6rem; }
.map-fallback h3 { font-family: var(--display); font-size: 1.2rem; letter-spacing: 0.08em; color: var(--ember); }
.map-fallback p { color: var(--dim); font-size: 0.95rem; line-height: 1.65; }
.map-fallback code {
  display: block;
  margin-top: 6px;
  padding: 10px 14px;
  border-radius: 10px;
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.1);
  font-size: 0.76rem;
  color: var(--cyan);
  word-break: break-all;
}

/* ---------- Search + filters ---------- */
.stores { max-width: 1220px; margin: 0 auto; padding: 54px 28px 120px; }
.stores-bar {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 22px;
}
.search-wrap { position: relative; flex: 1 1 320px; }
.search-icon { position: absolute; left: 18px; top: 50%; transform: translateY(-50%); opacity: 0.5; font-size: 0.95rem; }
#store-search {
  width: 100%;
  padding: 15px 18px 15px 48px;
  font: 500 1rem var(--body);
  color: var(--ink);
  background: rgba(255,255,255,0.045);
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 999px;
  outline: none;
  transition: border-color 0.25s, box-shadow 0.25s;
}
#store-search::placeholder { color: rgba(245,244,239,0.5); }
#store-search:focus { border-color: var(--cyan); box-shadow: 0 0 0 3px rgba(46,230,255,0.15), 0 0 26px rgba(46,230,255,0.12); }
.state-filters { display: flex; gap: 10px; flex-wrap: wrap; }
.demo-banner {
  margin-bottom: 18px;
  padding: 14px 18px;
  border-radius: 14px;
  background: rgba(255,122,24,0.1);
  border: 1px solid rgba(255,122,24,0.4);
  color: var(--ember);
  font-size: 0.9rem;
}
.stores-count { color: var(--dim); font-size: 0.88rem; letter-spacing: 0.14em; text-transform: uppercase; margin-bottom: 20px; }

/* ---------- Store cards ---------- */
.store-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; }
.store-card {
  position: relative;
  padding: 24px;
  border-radius: 20px;
  background: rgba(255,255,255,0.035);
  border: 1px solid rgba(255,255,255,0.1);
  display: grid;
  gap: 9px;
  align-content: start;
  cursor: pointer;
  transition: transform 0.3s, border-color 0.3s, box-shadow 0.3s;
  animation: card-in 0.55s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
.store-card:hover {
  transform: translateY(-6px);
  border-color: rgba(46,230,255,0.5);
  box-shadow: 0 26px 55px rgba(0,0,0,0.55), 0 0 32px rgba(46,230,255,0.1);
}
.store-card.featured { border-color: rgba(198,242,78,0.35); }
.store-card.featured:hover { border-color: var(--lime); box-shadow: 0 26px 55px rgba(0,0,0,0.55), 0 0 32px rgba(198,242,78,0.14); }
.store-top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.store-state { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.22em; color: var(--cyan); text-transform: uppercase; }
.store-badge {
  font-size: 0.62rem; font-weight: 700; letter-spacing: 0.16em;
  padding: 4px 10px; border-radius: 999px;
  color: var(--lime); border: 1px solid var(--lime);
  box-shadow: 0 0 12px rgba(198,242,78,0.25);
}
.store-dist { margin-left: auto; font-size: 0.78rem; font-weight: 700; color: var(--ember); }
.store-card h3 { font-family: var(--display); font-size: 1.3rem; letter-spacing: 0.04em; }
.store-addr { color: var(--dim); font-size: 0.92rem; line-height: 1.5; }
.store-hours { color: rgba(245,244,239,0.5); font-size: 0.85rem; }
.store-tags { display: flex; gap: 7px; flex-wrap: wrap; margin-top: 3px; }
.store-tag {
  font-size: 0.68rem; font-weight: 700; letter-spacing: 0.1em;
  padding: 4px 11px; border-radius: 999px;
  background: rgba(255,255,255,0.06); color: var(--dim);
}
.store-actions { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 10px; }
.store-link {
  font-size: 0.78rem; font-weight: 700; letter-spacing: 0.14em;
  color: var(--lime); text-decoration: none;
  transition: color 0.25s;
}
.store-link.ghost { color: var(--dim); }
.store-link:hover { color: var(--cyan); }
.stores-empty { color: var(--dim); padding: 50px 0; line-height: 1.7; grid-column: 1 / -1; }
.stores-empty a { color: var(--lime); }

.find-cta {
  text-align: center;
  padding: 0 28px 140px;
  display: grid;
  gap: 18px;
  justify-items: center;
}
.find-cta h2 { font-family: var(--display); font-size: clamp(2.2rem, 5.5vw, 4rem); letter-spacing: 0.03em; }

@media (max-width: 640px) {
  .find-head { padding-top: 120px; }
  .map-section { padding-left: 16px; padding-right: 16px; }
  .stores { padding-left: 18px; padding-right: 18px; }
}

/* ---------- Scroll reveals ---------- */
.reveal { opacity: 0; transform: translateY(40px); transition: opacity 0.95s cubic-bezier(0.2,0.6,0.2,1), transform 0.95s cubic-bezier(0.2,0.6,0.2,1); }
.reveal.in { opacity: 1; transform: none; }

/* ---------- Mobile ---------- */
@media (max-width: 640px) {
  .grid-2, .grid-3 { grid-template-columns: 1fr; }
  .menu-head { align-items: start; flex-direction: column; }
  .page-hero { padding-top: 130px; min-height: 84vh; }
  .form-shell { padding: 30px 22px; }
  .invest-stats { gap: 34px; padding: 40px 20px; }
}
@media (prefers-reduced-motion: reduce) {
  .aurora, .grain, .gate-media, .rise > span, .menu-card, .success-mark { animation: none !important; }
  .reveal { opacity: 1; transform: none; }
}

/* ---------- Request modals ---------- */
.modal {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgba(3,3,6,0.82);
  backdrop-filter: blur(8px);
  overflow-y: auto;
  /* The last leg of the scroll fix. menu-view.js and modal.js stop Lenis and
     lock <html>/<body> while a dialog is open, and data-lenis-prevent hands
     the wheel back to the browser inside it — this stops that native wheel
     CHAINING to the page once the dialog has hit its own end. */
  overscroll-behavior: contain;
  animation: modal-in 0.25s ease-out;
}
@keyframes modal-in { from { opacity: 0; } to { opacity: 1; } }
.modal-card {
  position: relative;
  width: min(560px, 100%);
  margin: auto;
  padding: 42px 38px;
  border-radius: 24px;
  overscroll-behavior: contain;
  background: rgba(11,11,18,0.96);
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 50px 120px rgba(0,0,0,0.75), 0 0 70px rgba(198,242,78,0.05);
  animation: modal-rise 0.35s cubic-bezier(0.2,0.7,0.2,1);
}
@keyframes modal-rise { from { transform: translateY(24px) scale(0.97); } to { transform: none; } }
.modal-close {
  position: absolute;
  top: 14px; right: 16px;
  width: 38px; height: 38px;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.16);
  background: transparent;
  color: var(--dim);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  transition: color 0.25s, border-color 0.25s;
}
.modal-close:hover { color: var(--magenta); border-color: var(--magenta); }
.modal-title {
  font-family: var(--display);
  font-size: clamp(1.8rem, 4.5vw, 2.6rem);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  line-height: 1.05;
}
.modal-lede { color: var(--dim); font-size: 0.94rem; line-height: 1.6; margin-bottom: 6px; }
.modal .neon-form { gap: 14px; }
.modal .neon-form .btn { justify-self: stretch; text-align: center; margin-top: 18px; }
.modal-success { padding: 30px 0 10px; }

.product-ctas { display: flex; gap: 16px; flex-wrap: wrap; justify-content: center; }
.product-ctas .btn { border: none; cursor: pointer; }
.product-ctas .btn-outline { border: 2px solid var(--lime); }

@media (max-width: 560px) {
  .modal-card { padding: 34px 22px; }
  /* Short phones: the tall request forms would exceed the screen — cap the
     card and let it scroll inside itself rather than relying on overlay
     scroll behind a sticky-feeling backdrop. */
  .modal-card { max-height: calc(100dvh - 32px); overflow-y: auto; -webkit-overflow-scrolling: touch; }
  .modal { padding: 16px; }
  /* Phone rhythm for subpages */
  .page-hero { padding: 130px 20px 70px; }
}

/* ---------- Storefront photo on a locator card ---------- */
.store-photo {
  margin: -24px -24px 4px;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 20px 20px 0 0;
  background: #101016;
}
.store-photo img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.6s;
}
.store-card:hover .store-photo img { transform: scale(1.06); }

/* ══════════════════════════════════════════════════════════
   LIVE MENU — card/list views, product detail, prior orders
   Everything menu-view.js renders (the shared renderer used by both
   menu.html and the WordPress [sodope_menu] shortcode).

   THIS BLOCK STAYS LAST IN THE FILE, AND WHOLE. Every rule below is one
   class deep against classes declared earlier (.menu-card, .modal,
   .stock-pill …), so it wins only on SOURCE ORDER — the exact trap that
   rendered every .btn-outline on the live site as a solid lime pill for
   months (PROJECT-STATE §"defects found already live"). Insert new menu
   rules at the END of this block; never move the block up, and never
   restyle .btn / .btn-ghost / .btn-outline from here.
   ══════════════════════════════════════════════════════════ */

/* ---------- View toggle + PRIOR ORDERS, in .menu-head ---------- */
/* .menu-head is `justify-content: space-between`, so four children would
   spread across the whole width and orphan the toggle mid-header. Pushing
   the toggle with `margin-left: auto` groups it with the actions and the
   user block on the right, leaving the title alone on the left. */
.menu-view-toggle { margin-left: auto; }
.menu-actions { display: flex; align-items: center; gap: 10px; }
.view-toggle {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 999px;
  background: rgba(255,255,255,0.04);
}
.view-toggle-btn {
  display: grid;
  place-items: center;
  width: 38px; height: 34px;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--dim);
  cursor: pointer;
  transition: color 0.25s, background 0.25s, box-shadow 0.25s;
}
.view-toggle-btn svg { width: 17px; height: 17px; display: block; pointer-events: none; }
/* The icon markup carries its own currentColor fill/stroke. A bare <svg>
   that declares neither would paint default black on a black header, so
   fill it — icons that state their own paint are left untouched. */
.view-toggle-btn svg:not([fill]):not([stroke]) { fill: currentColor; }
.view-toggle-btn:hover { color: var(--ink); background: rgba(255,255,255,0.07); }
/* The lit state is the .chip.on idiom — lime text plus the same soft glow —
   so "which view am I in" reads the same as "which category am I in". */
.view-toggle-btn[aria-pressed="true"] {
  color: var(--lime);
  background: rgba(198,242,78,0.13);
  box-shadow: 0 0 16px rgba(198,242,78,0.2);
}

/* ---------- Card view: the product image ---------- */
/* Bled to the card's edges with the card's own padding as a negative margin,
   the way .store-photo does it on a locator card. */
.menu-card-media {
  margin: -26px -26px 4px;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 20px 20px 0 0;
  background: #101016;
}
.menu-card-img {
  width: 100%;
  height: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  display: block;
  transition: transform 0.6s;
}
.menu-card:hover .menu-card-img { transform: scale(1.06); }
/* No image is a fact about the catalogue, not an error, so it gets the brand
   wordmark on a dark gradient rather than a browser broken-image glyph. */
.menu-card-placeholder {
  width: 100%; height: 100%;
  display: grid;
  place-items: center;
  font-family: var(--display);
  font-size: 1.35rem;
  letter-spacing: 0.3em;
  text-indent: 0.3em; /* letter-spacing pads the right of the last glyph */
  color: rgba(198,242,78,0.22);
  background:
    radial-gradient(70% 90% at 50% 30%, rgba(198,242,78,0.07), transparent 70%),
    linear-gradient(135deg, #0d0d14, #16161f 55%, #0a0a10);
}

/* Cards became clickable when the detail modal arrived, so they need a
   keyboard focus ring — the same cyan one the age gate uses. */
.menu-card:focus-visible,
.view-toggle-btn:focus-visible {
  outline: 3px solid var(--cyan);
  outline-offset: 3px;
}
/* These two live inside clipping boxes — .menu-row inside the list strip's
   overflow-x:auto, .order-row-head filling .order-row's border-radius clip —
   and ancestors DO clip a descendant's outline. An outset ring there renders
   as nothing at all, so the ring draws inside the edge instead. */
.menu-row:focus-visible,
.order-row-head:focus-visible {
  outline: 3px solid var(--cyan);
  outline-offset: -3px;
}

/* ---------- List view ---------- */
/* The row is a fixed strip of columns; below its min-width the STRIP scrolls
   inside this container rather than wrapping into soup. `position: relative`
   + `overflow-x: auto` is the house responsive pattern — the page body must
   never scroll horizontally. */
.menu-grid.menu-list {
  display: block;
  position: relative;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: thin;
  scrollbar-color: rgba(198,242,78,0.35) transparent;
}
.menu-grid.menu-list::-webkit-scrollbar { height: 8px; }
.menu-grid.menu-list::-webkit-scrollbar-thumb { background: rgba(198,242,78,0.3); border-radius: 999px; }
.menu-row {
  display: flex;
  align-items: center;
  gap: 16px;
  min-width: 720px;   /* narrower than this and the strip scrolls, by design */
  padding: 12px 16px;
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 16px;
  background: rgba(255,255,255,0.035);
  cursor: pointer;
  transition: border-color 0.3s, background 0.3s, box-shadow 0.3s;
}
.menu-row + .menu-row { margin-top: 10px; }
.menu-row:hover {
  border-color: rgba(198,242,78,0.45);
  background: rgba(255,255,255,0.055);
  box-shadow: 0 18px 40px rgba(0,0,0,0.45);
}
/* Same two states the card carries, so a view switch never changes meaning. */
.menu-row.pre-order { border-color: rgba(255,122,24,0.3); }
.menu-row.sold-out { opacity: 0.42; }
.menu-row-thumb {
  flex: 0 0 64px;
  width: 64px; height: 64px;
  border-radius: 12px;
  overflow: hidden;
  background: #101016;
}
.menu-row-thumb img, .menu-row-img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* The wordmark placeholder at thumbnail scale — same element, legible size. */
.menu-row-thumb .menu-card-placeholder { font-size: 0.42rem; letter-spacing: 0.16em; text-indent: 0.16em; }
/* Explicit placement rather than DOM order: name and SKU stack in column one,
   the specs sit beside them, and a missing SKU or missing specs just leaves
   its cell empty instead of reflowing the row. */
.menu-row-main {
  flex: 1 1 auto;
  min-width: 0;
  display: grid;
  grid-template-columns: minmax(0, auto) minmax(0, 1fr);
  column-gap: 16px;
  row-gap: 2px;
  align-items: baseline;
}
.menu-row-name {
  grid-area: 1 / 1;
  font-family: var(--display);
  font-size: 1.05rem;
  letter-spacing: 0.04em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.menu-row-sku { grid-area: 2 / 1; font-size: 0.68rem; color: rgba(245,244,239,0.35); letter-spacing: 0.12em; }
.menu-row-specs {
  grid-area: 1 / 2 / 3 / 3;
  align-self: center;
  color: var(--ink);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.08em;
}
.menu-row .stock-pill, .menu-row .preorder-pill { flex: 0 0 auto; white-space: nowrap; }
.menu-row-price {
  flex: 0 0 auto;
  min-width: 96px;
  text-align: right;
  font-family: var(--display);
  font-size: 1.2rem;
  color: var(--lime);
  white-space: nowrap;
}
.menu-row-add { flex: 0 0 auto; display: flex; align-items: center; gap: 8px; }

/* ---------- The add control, wherever it appears ----------
   .menu-card-add already owns the card's copy; the row and the detail modal
   repeat its geometry so ordering feels identical in all three places. */
.menu-row-add input, .menu-detail-add input {
  width: 74px; padding: 9px 10px; border-radius: 10px;
  background: rgba(255,255,255,0.05); color: var(--ink);
  border: 1px solid rgba(255,255,255,0.14); font: inherit; font-size: 0.9rem;
}
.menu-row-add select, .menu-detail-add select {
  min-width: 150px; padding: 9px 10px; border-radius: 10px;
  background: rgba(255,255,255,0.05); color: var(--ink);
  border: 1px solid rgba(255,255,255,0.14); font: inherit; font-size: 0.9rem;
}
/* The popup list is painted by the OS, which ignores the control's
   translucent background and renders white-on-white. Same opaque override
   the cart selects carry. */
.menu-row-add select option, .menu-detail-add select option { background: #12121b; color: var(--ink); }
/* .btn-add is `flex: 1` for the card, where it fills the row. Here it sits
   beside a price or a picker and must not stretch. */
.menu-row-add .btn-add, .menu-detail-add .btn-add { flex: 0 0 auto; }

/* ---------- Product detail modal ---------- */
/* .modal is z-index 200, already clear of the fixed .cart-bar (40), the
   cart toast (41) and the nav (90). Restated above it here because these
   two dialogs must NEVER open behind the request bar — a buyer who cannot
   reach the X is stuck. Equal specificity to .modal, so, again: source order. */
.menu-detail-modal, .prior-orders-modal { z-index: 210; }
.menu-detail-modal .modal-card {
  /* Wider than the 680px single column it replaced, because it now holds two.
     Still min(), so a phone gets the full width and the stack below. */
  width: min(920px, 100%);
  display: grid;
  gap: 12px;
  align-content: start;
  max-height: calc(100dvh - 64px);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
/* An item with NO description of either kind has nothing to put in the second
   column, so its card goes back to the width it had before contract 7. At
   920px the 16:9 photo alone is 465px tall and pushes the price and the ADD
   button below the fold — the extra width only earns its keep when there is a
   column of copy to fill it.
   The class is put on the card by menu-view.js's openDetail() rather than
   matched with `:has(.menu-detail-grid.is-solo)`, which is what this rule used
   to do: `:has()` is unsupported before Safari 15.4 / Firefox 121, and there
   the selector simply never matches — so the browsers least able to spare the
   vertical space would be the ones getting the tall card. A class the renderer
   sets is understood everywhere. */
.menu-detail-modal .modal-card.is-solo { width: min(680px, 100%); }
/* Source order IS the phone order — picture, what it is, what it costs, how to
   order it, then the long read — so the single-column stack needs no rules at
   all and the two-column desktop layout is the exception. */
.menu-detail-grid { display: grid; gap: 12px; align-content: start; }
.menu-detail-main { display: grid; gap: 12px; align-content: start; min-width: 0; }
.menu-detail-desc { min-width: 0; }
/* The only min-width query in this file, and deliberately: everything else
   here is a phone override on a desktop rule, but this one has to be, because
   the layout it turns on cannot be the fallback — a browser that does not
   match it must get the stack, not half a stack. 720px is where two ~400px
   columns stop being cramped inside a 920px card. */
@media (min-width: 720px) {
  /* align-items is left at its `stretch` default on purpose: it is what makes
     the description column — and the hairline down its left edge — run the
     full height of the card rather than stopping under its last line. */
  .menu-detail-grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 12px 34px;
  }
  /* No description to put beside it — one column, full width, rather than an
     empty half. */
  .menu-detail-grid.is-solo { grid-template-columns: minmax(0, 1fr); }
  /* The photo still bleeds to the card's top and left edges, but no longer to
     the right one: that edge is now the gutter between the columns. */
  .menu-detail-grid:not(.is-solo) .menu-detail-media {
    margin: -42px 0 10px -38px;
    border-radius: 24px 0 0 0;
  }
  .menu-detail-desc {
    padding-left: 26px;
    border-left: 1px solid rgba(255,255,255,0.1);
  }
  /* The close button sits over the card's top-right corner, which in THIS
     layout is the description's first line — on the single-column stack it is
     over the photo and this problem does not exist. A floated spacer makes the
     copy wrap around it for however many lines it needs, rather than padding
     the entire column away from an edge it only collides with once. */
  .menu-detail-desc > *::before {
    content: "";
    float: right;
    width: 46px;
    height: 30px;
  }
}
/* Over a photo the outline-only close button disappears, so it gets its own
   ground and sits above the media. */
.menu-detail-modal .modal-close {
  z-index: 2;
  background: rgba(5,5,8,0.62);
  backdrop-filter: blur(6px);
  color: var(--ink);
}
.menu-detail-media {
  margin: -42px -38px 10px;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 24px 24px 0 0;
  background: #101016;
}
.menu-detail-media img, .menu-detail-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.menu-detail-media .menu-card-placeholder { font-size: 2rem; }
.menu-detail-modal .menu-price { font-size: 2rem; }
.menu-detail-modal .menu-desc { font-size: 0.95rem; }
/* ---------- The formatted description (contract 7) ----------
   Nine tags and a link get through the allowlist on both targets, so nine tags
   and a link are styled here — anything else cannot arrive. The global reset
   (`* { margin: 0; padding: 0 }` in styles.css) strips list indents and every
   default margin site-wide, so a `<ul>` with no rules of its own renders its
   markers outside the card. Every rule below is restoring something that
   reset took away, in this dialog only. */
.menu-desc-rich > * { margin: 0; }
.menu-desc-rich > * + * { margin-top: 11px; }
.menu-desc-rich h3, .menu-desc-rich h4 {
  font-family: var(--display);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
  margin-top: 20px;
}
.menu-desc-rich h3 { font-size: 1.15rem; }
.menu-desc-rich h4 { font-size: 0.95rem; }
.menu-desc-rich > *:first-child { margin-top: 0; }
.menu-desc-rich ul, .menu-desc-rich ol { padding-left: 20px; }
.menu-desc-rich ul { list-style: disc; }
.menu-desc-rich ol { list-style: decimal; }
.menu-desc-rich li { margin-top: 5px; }
.menu-desc-rich li::marker { color: var(--lime); }
.menu-desc-rich strong { color: var(--ink); font-weight: 700; }
.menu-desc-rich em { font-style: italic; }
/* Cyan is the site's "this leaves the page" colour — the same one the COA
   button uses two rules down. */
.menu-desc-rich a {
  color: var(--cyan);
  text-decoration: underline;
  text-underline-offset: 3px;
  word-break: break-word;
}
.menu-desc-rich a:hover { color: var(--lime); }
/* Testing is a specification, so it reads as one: label column, value column,
   in the .license-card dl idiom. */
.menu-detail-testing {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 9px 20px;
  margin: 6px 0 0;
  padding-top: 16px;
  border-top: 1px solid rgba(255,255,255,0.1);
}
.menu-detail-testing dt {
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--dim);
}
.menu-detail-testing dd { margin: 0; font-size: 0.92rem; line-height: 1.4; }
/* The word itself carries the verdict — the colour only reinforces it, so
   this still reads correctly in monochrome or to a colour-blind buyer. */
.menu-detail-testing .pf-pass { color: var(--lime); font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; }
.menu-detail-testing .pf-fail { color: var(--magenta); font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; }
.menu-detail-coa {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
  padding: 9px 18px;
  border: 1px solid var(--cyan);
  border-radius: 999px;
  color: var(--cyan);
  text-decoration: none;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  transition: background 0.25s, color 0.25s;
}
.menu-detail-coa:hover { background: var(--cyan); color: #050505; }
.menu-detail-add {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 6px;
  padding-top: 18px;
  border-top: 1px solid rgba(255,255,255,0.1);
}

/* ---------- Prior orders modal ---------- */
.prior-orders-modal .modal-card {
  width: min(760px, 100%);
  max-height: calc(100dvh - 64px);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.prior-orders-modal .modal-title { margin-bottom: 6px; }
.order-row {
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 14px;
  background: rgba(255,255,255,0.03);
  overflow: hidden;
}
.order-row + .order-row { margin-top: 10px; }
.order-row:first-of-type { margin-top: 18px; }
.order-row-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 14px;
  width: 100%;
  padding: 14px 16px;
  border: none;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background 0.25s;
}
.order-row-head:hover { background: rgba(255,255,255,0.04); }
/* Positional, because §12 froze only .order-status and the renderer emits the
   rest as bare spans: number, date, [pill], total. The total takes the auto
   margin so the money column lines up down the list however wide the numbers
   before it run. */
.order-row-head > span:first-of-type { font-family: var(--display); letter-spacing: 0.06em; font-size: 1.05rem; }
.order-row-head > span:nth-of-type(2) { color: var(--dim); font-size: 0.85rem; }
.order-row-head > span:last-of-type {
  margin-left: auto;
  text-align: right;
  font-family: var(--display);
  font-size: 1.1rem;
  color: var(--lime);
  white-space: nowrap;
}
/* The disclosure arrow is CSS, not markup, so the renderer's button carries
   only the data. It flips with aria-expanded — the state the assistive tech
   already reads. */
.order-row-head::after {
  content: "▾";
  margin-left: 4px;
  flex: 0 0 auto;
  color: var(--dim);
  transition: transform 0.2s;
}
.order-row-head[aria-expanded="true"]::after { transform: rotate(180deg); }
.order-status {
  flex: 0 0 auto;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: 4px 11px;
  border-radius: 999px;
  border: 1px solid currentColor;
}
/* Pill palette by meaning, on the .stock-pill idiom: waiting on us (ember),
   out with the retailer (cyan, dimmed — it is not an alert), settled (lime),
   late (magenta). */
.order-status.pending  { color: var(--ember); }
.order-status.sent     { color: rgba(46,230,255,0.8); }
.order-status.paid     { color: var(--lime); box-shadow: 0 0 12px rgba(198,242,78,0.2); }
.order-status.overdue  { color: var(--magenta); box-shadow: 0 0 12px rgba(255,62,165,0.2); }
/* Same ledger look as the cart table, which is the other place on this site
   where a retailer reads lines and totals. Five columns with nowrap numbers
   outgrow a phone-width card, and .order-row's overflow:hidden would simply
   amputate the line-total column — so this wrapper scrolls sideways itself,
   the house responsive pattern, with the list strip's thin lime affordance. */
.order-lines {
  width: 100%;
  padding: 0 16px 14px;
  position: relative;
  overflow-x: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(198,242,78,0.35) transparent;
  font-size: 0.86rem;
}
.order-lines::-webkit-scrollbar { height: 8px; }
.order-lines::-webkit-scrollbar-thumb { background: rgba(198,242,78,0.3); border-radius: 999px; }
.order-lines table { width: 100%; border-collapse: collapse; }
.order-lines th, .order-lines td {
  padding: 8px 0;
  border-bottom: 1px solid rgba(255,255,255,0.07);
  text-align: left;
}
.order-lines th {
  font-size: 0.64rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--dim);
}
/* The gutter is padding, not table spacing, because once the table sits at
   min-content width (the phone, scrolling) zero horizontal padding welds the
   right-aligned columns into one run of words. */
.order-lines th:not(:first-child), .order-lines td:not(:first-child) { text-align: right; white-space: nowrap; padding-left: 16px; }
.order-lines tr:last-child th, .order-lines tr:last-child td { border-bottom: none; }
.orders-empty { color: var(--dim); font-size: 0.95rem; line-height: 1.7; padding: 26px 2px; }

/* ---------- No JavaScript ----------
   The cart has always required JS, so the menu going client-rendered costs a
   visitor without it nothing they had. Say so rather than showing a blank. */
.menu-noscript {
  margin-top: 18px;
  padding: 14px 18px;
  border-radius: 14px;
  background: rgba(255,122,24,0.1);
  border: 1px solid rgba(255,122,24,0.4);
  color: var(--ember);
  font-size: 0.9rem;
}

/* ---------- Menu views: phones ---------- */
@media (max-width: 640px) {
  /* .menu-head turns into a column here, and `margin-left: auto` in a column
     flex pushes the toggle to the right edge, away from everything it belongs
     with. Back to the flow, and let both wrappers wrap. */
  .menu-view-toggle { margin-left: 0; }
  .menu-actions { flex-wrap: wrap; }
  .menu-row-price { min-width: 84px; }
}
@media (max-width: 560px) {
  /* The generic `.modal-card` phone rules are one class deep and lose to the
     two-class rules above, so both dialogs restate the tighter cap here. */
  .menu-detail-modal .modal-card, .prior-orders-modal .modal-card { max-height: calc(100dvh - 32px); }
  /* Follows .modal-card's phone padding (34px 22px) so the media still bleeds
     exactly to the card edge. */
  .menu-detail-media { margin: -34px -22px 8px; }
  .order-row-head { padding: 12px 13px; }
  .order-lines { padding: 0 13px 12px; }
}

/* ══════════════════════════════════════════════════════════
   STRAIN LIBRARY — the public genetics index (strains.html)
   Everything strain-view.js renders that the Live Menu block above does
   not already dress.

   THIS BLOCK COMES AFTER THE LIVE MENU BLOCK, AND THAT IS THE WHOLE
   MECHANISM. strain-view.js carries the menu's structural classes
   (.menu-card, .menu-row, .menu-detail-*, .modal-*) on every element and
   adds a strain-* co-class beside them, so the two pages share a look
   through CSS rather than through code and a future menu restyle restyles
   this page with it. Which means almost nothing belongs down here: a rule
   is only justified when the strain page needs something the menu has no
   equivalent of (the gallery, the tag chips, the media badge) or when the
   menu's rule was written about money and this page has none.

   Several rules below are one class deep and beat a one-class menu rule on
   SOURCE ORDER alone — the same cascade trap the block above warns about.
   Do not move this block, and do not move the menu block above it. Append
   new strain rules at the END of this one.
   ══════════════════════════════════════════════════════════ */

/* ---------- Page chrome ---------- */
/* .menu-wrap's 150px of top padding clears a fixed nav on a page with no
   hero. This page has one, so it follows .invest-wrap's post-hero spacing
   instead. */
.strain-wrap { padding-top: 110px; }
/* The head's title is an h2 here, because the hero above owns the page's one
   h1 — .menu-head h1 is where the display font would otherwise come from. */
.strain-wrap .menu-head h2 {
  font-family: var(--display);
  font-size: clamp(1.6rem, 3.4vw, 2.4rem);
  letter-spacing: 0.03em;
}


/* ---------- Spec lines that are context, not headline ----------
   .menu-specs is 700-weight ink because on the menu it carries the one line
   that says what the product IS. In the strain dialog three of these stack —
   potency, lineage, pack sizes — and three consecutive bold lines read as
   three headlines. The potency line keeps the weight; the two that qualify
   it step back, the same way .menu-release does. */
.strain-lineage, .strain-sizes { color: var(--dim); font-weight: 500; letter-spacing: 0.04em; }

/* ---------- Tag chips: aroma, flavor, effects ---------- */
/* On a CARD these are unlabelled and capped at four by the renderer — a
   glance, not a table. */
.strain-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 2px; }
.strain-tag {
  padding: 4px 11px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.14);
  color: var(--dim);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  white-space: nowrap;
}
/* In the DIALOG the same chips come back in labelled groups, because "Citrus"
   and "Relaxed" are indistinguishable as bare chips. The label is a real
   element rather than an aria-label, so it reads to everybody. */
.strain-tag-group { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 4px; }
.strain-tag-label {
  flex: 0 0 auto;
  min-width: 72px;
  font-size: 0.64rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--dim);
}

/* ---------- The cultivator's notes ----------
   Last thing in the description column, in a different voice from the copy
   above it — so it gets a rule only when there IS copy above it to be
   separated from. */
.strain-grow-notes { font-style: italic; }
.strain-copy + .strain-grow-notes {
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid rgba(255,255,255,0.1);
}

/* The ≥720px close-button spacer in the menu block floats a 46x30 box out of
   `.menu-detail-desc > *::before` — every direct child, because the menu's
   description column only ever has one. This column has two (copy, then grow
   notes), and the second spacer would carve a notch out of the middle of the
   text. Only the first child collides with the close button, so only the
   first child keeps its spacer. `:not()` takes its argument's specificity, so
   this is two classes deep and wins outright rather than on source order. */
.strain-detail-copy > *:not(:first-child)::before { content: none; }

/* ---------- The gallery ----------
   Laid out as a one-column grid rather than with absolutely-positioned
   arrows, and that is load-bearing. The arrows are SIBLINGS of the viewport,
   not children of it, so `top: 50%` against the wrapper would centre them on
   the viewport PLUS the dot row and sit them low over the photo. Overlaying
   them in grid cell 1/1 pins them to the picture itself with no magic number
   to go stale when the dots wrap.

   The bleed to the card's edges moves here from .menu-detail-media, because
   the wrapper is now the thing that has to reach the edge. The viewport gives
   its own margin up in exchange — one class deep and later in the file than
   .menu-detail-media, so it wins on source order. */
.strain-gallery {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  margin: -42px -38px 10px;
}
.strain-gallery-viewport { grid-area: 1 / 1; margin: 0; }
/* A clip is not a photograph: `object-fit: cover` would crop a 4:5 vertical
   phone clip to a 16:9 letterbox and cut the plant out of the middle of it.
   pages.css styles `.menu-detail-media img` and `.menu-detail-img` — the
   video carries the latter, so it was being cropped rather than left
   unstyled. Contain it on black instead, and let the pillarbox show. */
.strain-slide-video {
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000;
  display: block;
}
.strain-gallery-nav {
  grid-area: 1 / 1;
  align-self: center;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 40px; height: 40px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.22);
  background: rgba(5,5,8,0.62);
  backdrop-filter: blur(6px);
  color: var(--ink);
  cursor: pointer;
  transition: background 0.25s, border-color 0.25s, color 0.25s;
}
.strain-gallery-prev { justify-self: start; margin-left: 12px; }
.strain-gallery-next { justify-self: end; margin-right: 12px; }
.strain-gallery-nav:hover { background: rgba(198,242,78,0.16); border-color: var(--lime); color: var(--lime); }
.strain-gallery-nav svg { display: block; pointer-events: none; }

/* Row two, under the picture. Only one of these two ever renders — dots up to
   ten slides, a counter above that — so they share the cell. */
.strain-gallery-dots {
  grid-area: 2 / 1;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 2px;
  padding-top: 6px;
}
.strain-gallery-count {
  grid-area: 2 / 1;
  padding-top: 12px;
  text-align: center;
  color: var(--dim);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.16em;
}
/* The button is a 22px touch target; the dot inside it is 9px. A 9px button
   is the right dot and the wrong tap. */
.strain-gallery-dot {
  width: 22px; height: 22px;
  padding: 0;
  border: none;
  background: transparent;
  display: grid;
  place-items: center;
  cursor: pointer;
}
.strain-gallery-dot::before {
  content: "";
  width: 9px; height: 9px;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.4);
  transition: background 0.25s, border-color 0.25s, box-shadow 0.25s;
}
.strain-gallery-dot:hover::before { border-color: var(--lime); }
/* The lit state is the .chip.on / view-toggle idiom, so "which slide am I on"
   reads the same as "which view am I in". */
.strain-gallery-dot[aria-current="true"]::before {
  background: var(--lime);
  border-color: var(--lime);
  box-shadow: 0 0 12px rgba(198,242,78,0.35);
}
/* The house focus ring: 3px cyan, outset. Neither control sits inside a
   clipping box — .strain-gallery has no overflow of its own, and the arrows
   are siblings of the viewport rather than children — so the ring is not
   swallowed the way .menu-row's would be. */
.strain-gallery-nav:focus-visible,
.strain-gallery-dot:focus-visible {
  outline: 3px solid var(--cyan);
  outline-offset: 3px;
}

/* Nothing positions .strain-gallery-status. It carries its own inline
   visually-hidden style, deliberately, so a stylesheet that has not caught up
   with strain-view.js cannot leave "Photo 2 of 5" printed under the dots. A
   rule here would be the second opinion that breaks it. */

/* ---------- "+2", on a card with more media behind it ---------- */
/* .menu-card-media has overflow:hidden but no positioning context of its own,
   so without this the badge would resolve against .menu-card and sit at the
   bottom of the whole card. Scoped to .strain-card: the menu has no badge and
   this must not silently change what a future menu rule can assume. */
.strain-card .menu-card-media { position: relative; }
.strain-media-badge {
  position: absolute;
  right: 10px; bottom: 10px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.18);
  background: rgba(5,5,8,0.66);
  backdrop-filter: blur(6px);
  color: var(--ink);
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.1em;
}
/* The list row's thumbnail is 64x64. A pill with an icon and a number in it is
   most of that square and legible at none of it, and the row is the SCANNING
   view — the affordance belongs on the card, which is the browsing one. */
.menu-row-thumb .strain-media-badge { display: none; }

/* ---------- Gallery bleed at the two layouts the dialog has ---------- */
@media (min-width: 720px) {
  /* Two columns: the picture still bleeds to the card's top and left edges,
     but the right edge is now the gutter. Mirrors the
     `.menu-detail-grid:not(.is-solo) .menu-detail-media` rule in the menu
     block — which is three classes deep and would otherwise beat the
     one-class `.strain-gallery-viewport { margin: 0 }` above. */
  .menu-detail-grid:not(.is-solo) .strain-gallery { margin: -42px 0 10px -38px; }
  .menu-detail-grid:not(.is-solo) .strain-gallery .strain-gallery-viewport {
    margin: 0;
    border-radius: 24px 0 0 0;
  }
}
@media (max-width: 560px) {
  /* Follows .modal-card's phone padding (34px 22px), same as the menu's own
     phone rule for .menu-detail-media. */
  .strain-gallery { margin: -34px -22px 8px; }
}

/* ---------- Reduced motion ---------- */
/* The cards' entrance animation is already handled: .strain-card carries
   .menu-card, which the block near the top of this file switches off. What is
   new here is hover and state TRANSITIONS on the gallery controls, and a
   visitor who asked for less motion should not get them either. */
@media (prefers-reduced-motion: reduce) {
  .strain-gallery-nav, .strain-gallery-dot::before { transition: none; }
}

/* ── the strain dialog's close button ──────────────────────────────────────
   The base .modal-close is a transparent circle with a 16%-white hairline and
   --dim glyph. That reads fine on the flat card the plain .modal shows, and
   vanishes completely here: this dialog's gallery bleeds to the top edge, so
   the button sits ON the photograph, and a grey X on a bud shot is invisible.
   The menu dialog already solved this for itself (.menu-detail-modal
   .modal-close, a dark ground + blur); the strain dialog never got the same
   treatment, which is the bug.

   Cyan rather than a scrim alone, because --cyan is already this page's
   "interactive" colour — it is the focus ring on the gallery arrows and dots
   sitting directly below it — so the control that closes the dialog now says
   the same thing they do. The dark blurred ground stays underneath it: a photo
   can be any colour, and cyan-on-white would be as unreadable as grey-on-green.
   Ground first, colour on top; neither alone is enough. */
.strain-detail-modal .modal-close {
  z-index: 3;
  width: 42px;
  height: 42px;
  background: rgba(5, 5, 8, 0.66);
  backdrop-filter: blur(6px);
  border: 2px solid var(--cyan);
  color: var(--cyan);
  font-size: 1.6rem;
  box-shadow: 0 2px 14px rgba(0, 0, 0, 0.45);
  transition: background 0.2s, color 0.2s, border-color 0.2s, box-shadow 0.2s;
}
/* Hover/focus INVERTS rather than tinting: over unpredictable photography a
   filled disc is the only state change guaranteed to be visible. */
.strain-detail-modal .modal-close:hover,
.strain-detail-modal .modal-close:focus-visible {
  background: var(--cyan);
  border-color: var(--cyan);
  color: #05050a;
  box-shadow: 0 2px 18px rgba(46, 230, 255, 0.55);
}
/* The one place on this page the focus ring is NOT cyan, on purpose: the
   button is cyan the moment it is focused, and a cyan ring on a cyan disc is
   the exact failure this rule exists to fix. White reads against both the
   filled disc and whatever photo is behind it. */
.strain-detail-modal .modal-close:focus-visible {
  outline: 3px solid var(--ink);
  outline-offset: 3px;
}
@media (prefers-reduced-motion: reduce) {
  .strain-detail-modal .modal-close { transition: none; }
}

/* ── Clickwrap consent ────────────────────────────────────────────────────
   Immediately above the submit button, unchecked, and the terms one link away.
   Wu v. Uber (N.Y. Ct. App., 2024) upheld a clickwrap built exactly this way and
   set out why: inquiry notice comes from the terms being AVAILABLE and the
   agreement being AFFIRMATIVE. A footer line saying "by using this site you
   agree" is the browsewrap courts decline to enforce, which is why this is a
   real checkbox on a real form and not a sentence in the footer. */
.consent {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  margin: 6px 0 18px;
  font-size: 0.86rem;
  line-height: 1.6;
  color: rgba(245,244,239,0.78);
  cursor: pointer;
}
.consent input[type="checkbox"] {
  flex: none;
  width: 20px;
  height: 20px;
  margin-top: 2px;
  accent-color: var(--lime);
  cursor: pointer;
}
.consent input[type="checkbox"]:focus-visible {
  outline: 3px solid var(--cyan);
  outline-offset: 3px;
}
.consent a { color: var(--lime); text-decoration: underline; text-underline-offset: 2px; }
.consent a:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
.consent strong { color: rgba(245,244,239,0.92); }
