/* ============================================================
   styles.css — PaliaMarket shared stylesheet
   Loaded by: index.html, rewards.html, votes.html
   ============================================================ */

/* ── GOOGLE FONTS ─────────────────────────────────────────── */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&family=DM+Serif+Display:ital@0;1&family=Fredoka:wght@400;600;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@300;400;500;600;700&display=swap');

/* ── DESIGN TOKENS ────────────────────────────────────────── */
:root {
  /* ── Primary accent — warm gold ── */
  --accent:       var(--pp-green-600);
  --accent-deep:  var(--pp-green-700);
  --accent-light: #FEF5E0;

  /* ── Market design tokens ── */
  --bg:           #FAFAFA;
  --surface:      #FFFFFF;
  --ink:          #1A1A1A;
  --muted:        #8A8A8A;
  --line:         #ECECEC;
  --chip:         #F5F2F0;
  --sidebar-w:    320px;

  /* ── Legacy aliases → gold (keeps all var() usages working) ── */
  --sun:          var(--pp-green-500);
  --sun-deep:     var(--pp-green-600);
  --sun-light:    #FEF5E0;
  --mint:         #FEF5E0;
  --mint-deep:    var(--pp-green-600);
  --lilac:        #FEF5E0;
  --lilac-deep:   var(--pp-green-600);

  /* ── Semantic colors ── */
  --coral:        #EF4444;
  --coral-light:  #FEE2E2;
  --sky:          #EFF6FF;
  --sky-deep:     #3B82F6;

  /* ── Neutrals ── */
  --cream:        #F5F2F0;
  --peach:        #F2F2F6;
  --peach-deep:   #9090A8;
  --text:         #1A1A1A;
  --text-soft:    #6B6B7B;
  /* ── --text-muted is the one token that has to clear WCAG AA on its own ──
     It is the ink for counts, section labels, footer links, timestamps and
     legal lines — small text, and the last thing anyone thinks to check.
     #8A8A8A came out at 3.5:1 on --surface, under the 4.5:1 small-text floor;
     index.css and builder.css each shadowed it with an even lighter #AFAFAF
     (2.1:1), which is what the browse page and the Pack Builder actually
     painted. #6E6E78 measures 5.0:1 on white and 4.8:1 on --bg.
     All three files must carry the SAME value — see the note in index.css. */
  --text-muted:   #6E6E78;
  --white:        #FFFFFF;
  --card-bg:      #FFFFFF;
  --border:       #ECECEC;
  --shadow:       0 1px 3px rgba(0,0,0,0.04), 0 4px 16px rgba(0,0,0,0.04);
  --shadow-hover: 0 4px 12px rgba(0,0,0,0.08), 0 16px 40px rgba(0,0,0,0.08);
  --radius:       16px;
  --radius-sm:    12px;

  /* Shared screen-level title rhythm. Entity names, auth headings and modal
     titles intentionally do not use these tokens. */
  --page-title-size: 34px;
  --page-title-weight: 800;
  --page-title-line-height: 1.1;
  --page-title-letter-spacing: -0.02em;
  --page-header-margin-top: 6px;
  --page-header-margin-bottom: 12px;
}

/* ── RESET ────────────────────────────────────────────────── */
* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; }

/* Form controls do not inherit font-family from their parent — the UA sheet
   gives them its own default — so any button or input that never set one drew
   in Arial next to the Geist/Inter text around it. The upload picker on the
   listing modal was the visible case; most of the rest are icon-only buttons
   where it only showed in the glyph metrics. Controls that set their own font
   still win: this only supplies the value where nothing else does. */
button, input, select, textarea { font-family: inherit; }

/* Instant dark/light mode — no fade */
.sh-no-transition *,
.sh-no-transition *::before,
.sh-no-transition *::after {
  transition: none !important;
  animation-duration: 0s !important;
}

/* ── BASE ─────────────────────────────────────────────────── */
body {
  font-family: 'Geist', 'Inter', 'DM Sans', ui-sans-serif, system-ui, sans-serif;
  font-feature-settings: "ss01","cv11";
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
  overflow-x: hidden;
  position: relative;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  letter-spacing: -0.005em;
}
body::before { display: none; }

/* ── Override header.js #FFFFFF !important — restore the subtle grey bg ── */
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  background: var(--bg) !important;
  font-family: 'Inter', 'Geist', sans-serif !important;
}
body.dark { background: var(--bg) !important; }

/* ── Page wrap + inner page padding (shared by all pages) ── */
.page-wrap { position: relative; z-index: 1; flex: 1 0 auto; min-height: 0; }
body > .page-wrap { margin-left: var(--sidebar-w); }
.page-wrap > .page {
  padding: 24px 20px 24px;
  position: relative;
  z-index: 1;
}
@media (max-width: 600px) {
  .page-wrap > .page { padding: 20px 16px; }
}
.page-title {
  font-family: 'Inter', 'Geist', sans-serif;
  font-size: var(--page-title-size);
  font-weight: var(--page-title-weight);
  color: var(--text);
  letter-spacing: var(--page-title-letter-spacing);
  line-height: var(--page-title-line-height);
  margin: 0;
}
.votes-page-header {
  width: 85%;
  max-width: 1400px;
  margin: var(--page-header-margin-top) auto var(--page-header-margin-bottom);
  box-sizing: border-box;
}
@media (max-width: 1024px) {
  .votes-page-header {
    width: 100% !important;
    padding: 0 16px;
  }
}
.page-content-width {
  width: 85%;
  max-width: 1400px;
  margin: 0 auto;
}
.deco { display: none; }

/* ── ANIMATIONS ───────────────────────────────────────────── */
@keyframes float      { 0%,100% { transform: translateY(0); }   50% { transform: translateY(-20px); } }
@keyframes bounce     { 0%,100% { transform: translateY(0); }   50% { transform: translateY(-4px); } }
@keyframes fadeInDown { from { opacity: 0; transform: translateY(-16px); } to { opacity: 1; transform: translateY(0); } }
@keyframes fadeInUp   { from { opacity: 0; transform: translateY(16px);  } to { opacity: 1; transform: translateY(0); } }
@keyframes popIn      { from { opacity: 0; transform: scale(0.7); }        to { opacity: 1; transform: scale(1); } }
@keyframes slideInRight { from { opacity: 0; transform: translateX(100%); } to { opacity: 1; transform: translateX(0); } }
@keyframes fadeOut    { from { opacity: 1; } to { opacity: 0; } }
@keyframes spin       { to { transform: rotate(360deg); } }
@keyframes confettiFall { 0% { opacity:1; transform: translateY(0) rotate(0deg); } 100% { opacity:0; transform: translateY(100vh) rotate(720deg); } }

/* ── PAGE HERO (shared base for all sub-pages) ────────────── */
.page-hero {
  max-width: 1200px;
  margin: 0 auto;
  padding: 40px 28px 28px;
  text-align: left;
  border-bottom: 1px solid var(--border, #ECECEC);
  margin-bottom: 32px;
}
.page-hero-badge {
  display: inline-flex; align-items: center; gap: 6px;
  background: transparent; border: 1px solid var(--border, #ECECEC);
  border-radius: 50px; padding: 5px 14px;
  font-size: 12px; font-weight: 500; color: var(--text-muted, #8A8A8A);
  margin-bottom: 16px; animation: fadeInDown 0.6s ease;
  font-family: 'Geist', 'DM Sans', sans-serif; letter-spacing: 0.02em;
}
.page-hero h1 {
  font-family: 'Instrument Serif', 'DM Serif Display', serif;
  font-size: clamp(32px, 5vw, 54px); font-weight: 400;
  color: var(--text); line-height: 1.05;
  margin-bottom: 12px; animation: fadeInUp 0.7s ease;
  letter-spacing: -0.025em;
}
.page-hero h1 span { color: var(--sun-deep); font-style: italic; }
.page-hero p {
  font-size: 15px; color: var(--text-muted, #8A8A8A);
  max-width: 540px;
  line-height: 1.6; white-space: normal;
  animation: fadeInUp 0.8s ease;
}

/* ── BUTTONS — canonical system ───────────────────────────────
   One consistent look for every button, themed for light + dark.
   Semantic variants:
     .btn-primary    → GREEN  — main / confirm action
     .btn-danger     → RED    — destructive / cancel   (.btn-coral is an alias)
     .btn-secondary  → GREY   — neutral / secondary action
     .btn-outline    → quiet outline (tertiary)
     .btn-sky        → BLUE   — informational (kept)
   Modifiers: .btn-sm · .btn-lg · .btn-block · :disabled
   Aliases (.btn-coral / .btn-mint) are kept so existing markup stays consistent.
   All variants keep a 2px border (transparent when unused) so heights never jump. */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: 7px; padding: 10px 20px; border-radius: 12px;
  font-family: 'DM Sans', sans-serif; font-size: 14px; font-weight: 700;
  line-height: 1; white-space: nowrap; cursor: pointer; text-decoration: none;
  border: 2px solid transparent;
  transition: background .18s, border-color .18s, color .18s, box-shadow .18s, transform .12s;
  -webkit-tap-highlight-color: transparent;
}
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn:active { transform: translateY(0) scale(0.98); }
.btn:disabled, .btn.is-disabled { opacity: 0.5; cursor: not-allowed; transform: none !important; box-shadow: none !important; }

/* GREEN — primary */
/* GREEN — primary.
   Deliberately --accent-deep (#15803D) and not --accent (#16A34A): the label is
   white, and white on --accent measures 3.3:1, under the 4.5:1 floor for a 14px
   button label. #15803D is 5.0:1 and is the same green the hover state already
   used, so this is a shade of the existing palette rather than a new colour.
   Dark mode inverts instead — see the body.dark block further down. */
.btn-primary, .btn-mint   { background: var(--accent-deep); color: #fff; border-color: var(--accent-deep); }
.btn-primary:hover, .btn-mint:hover { background: var(--pp-green-800); border-color: var(--pp-green-800); transform: translateY(-1px); box-shadow: 0 4px 16px rgba(var(--pp-green-500-rgb), 0.35); }

/* RED — danger */
.btn-danger, .btn-coral   { background: var(--coral); color: #fff; border-color: var(--coral); }
.btn-danger:hover, .btn-coral:hover { background: #DC2626; border-color: #DC2626; transform: translateY(-1px); box-shadow: 0 4px 16px rgba(239,68,68,0.35); }

/* GREY — secondary / neutral */
.btn-secondary { background: var(--chip); color: var(--text); border-color: var(--border); }
.btn-secondary:hover { background: var(--border); border-color: var(--text-muted); transform: translateY(-1px); }

/* Quiet outline — tertiary */
.btn-outline   { background: transparent; color: var(--text-soft); border-color: var(--border); }
.btn-outline:hover { border-color: var(--accent); color: var(--accent); transform: translateY(-1px); }

/* BLUE — informational */
.btn-sky       { background: var(--sky); color: var(--sky-deep); border-color: var(--sky-deep); }
.btn-sky:hover { background: var(--sky-deep); color: #fff; transform: translateY(-1px); box-shadow: 0 4px 16px rgba(59,130,246,0.35); }

/* Sizes / width */
.btn-sm    { padding: 7px 14px; font-size: 13px; }
.btn-lg    { padding: 13px 26px; font-size: 15px; }
.btn-block { width: 100%; }

/* ── On-image buttons (glass) ─────────────────────────────────
   Add .btn-on-image to ANY variant to make it glassy for use over photos /
   busy backgrounds. Each keeps its colour identity but frosted, with white
   text + blur + subtle shadow so it reads on light OR dark images:
     class="btn btn-primary   btn-on-image"  → glassy green
     class="btn btn-danger    btn-on-image"  → glassy red
     class="btn btn-secondary btn-on-image"  → glassy neutral (dark scrim)
     class="btn btn-sky       btn-on-image"  → glassy blue
     class="btn btn-on-image"                → neutral glass (no colour)
   .btn-white is a solid high-emphasis alternative. No dark-theme override is
   needed — these sit on the image, not the page. */
.btn-on-image {
  color: #fff !important;
  /* Hairline edge + faint sheen = a crafted glass pill, not a flat fill */
  border: 1.5px solid rgba(255,255,255,0.28);
  background: rgba(17,18,24,0.34);          /* mostly-transparent dark interior */
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  text-shadow: 0 1px 2px rgba(0,0,0,0.5);
  box-shadow: 0 6px 22px rgba(0,0,0,0.26), inset 0 1px 0 rgba(255,255,255,0.18) !important;
}
.btn-on-image:hover { transform: translateY(-1px); background: rgba(17,18,24,0.46); border-color: rgba(255,255,255,0.5); }

/* Colour = dark glass tinted toward the hue + a matching soft edge, so the
   interior stays see-through and elegant rather than a solid colour block. */
.btn-primary.btn-on-image, .btn-mint.btn-on-image             { background: rgba(var(--pp-green-900-rgb), 0.42); border-color: rgba(var(--pp-green-300-rgb), 0.45); }
.btn-primary.btn-on-image:hover, .btn-mint.btn-on-image:hover { background: rgba(var(--pp-green-900-rgb), 0.58); border-color: rgba(var(--pp-green-300-rgb), 0.7); }
.btn-danger.btn-on-image, .btn-coral.btn-on-image             { background: rgba(96,26,26,0.44); border-color: rgba(252,165,165,0.45); }
.btn-danger.btn-on-image:hover, .btn-coral.btn-on-image:hover { background: rgba(96,26,26,0.6); border-color: rgba(252,165,165,0.7); }
.btn-secondary.btn-on-image                                   { background: rgba(17,18,24,0.34); }
.btn-secondary.btn-on-image:hover                             { background: rgba(17,18,24,0.5); }
.btn-sky.btn-on-image                                         { background: rgba(23,52,102,0.44); border-color: rgba(147,197,253,0.45); }
.btn-sky.btn-on-image:hover                                   { background: rgba(23,52,102,0.6); border-color: rgba(147,197,253,0.7); }

.btn-white { background: #fff; color: #14141A; border-color: #fff; box-shadow: 0 4px 14px rgba(0,0,0,0.18); }
.btn-white:hover { background: #F0F0F0; border-color: #F0F0F0; transform: translateY(-1px); }

/* ── DROPDOWNS ────────────────────────────────────────────────
   One consistent look, matching the header menus. Two parts:
   1. Native <select> — styled globally so every select box matches
      (chevron, radius, border, focus ring), light + dark via tokens.
      NB: the OPEN option list is drawn by the OS and can't be themed;
      to fully match, a select must be rebuilt as a .dropdown-menu.
   2. .dropdown-menu / .dropdown-item / .dropdown-divider — the custom
      panel, mirroring the header dropdown (white/#16161A, 12px radius,
      soft shadow, 8px-radius items, hover fill, bounce-in). Opt-in. */

/* 1 — native selects */
select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  font-family: 'Geist', 'Inter', sans-serif; font-size: 14px; font-weight: 500;
  color: var(--text); background-color: var(--card-bg);
  border: 1px solid var(--border); border-radius: 10px;
  padding: 9px 34px 9px 13px; cursor: pointer; outline: none; line-height: 1.2;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%238A8A8A' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center; background-size: 13px;
  transition: border-color .15s, box-shadow .15s;
}
select:hover  { border-color: var(--text-muted); }
select:focus  { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(var(--pp-green-500-rgb), 0.16); }
select:disabled { opacity: 0.5; cursor: not-allowed; }
/* Explicit dark values — native form controls can resolve var() inconsistently,
   so pin the surfaces to guarantee the select box matches the panel in dark. */
body.dark select { background-color: #16161A; border-color: #26262B; color: #F2F2F0; }
body.dark select:hover { border-color: #45454F; }

/* 2 — custom dropdown panel (matches the header menu) */
.dropdown-menu {
  background: var(--card-bg); border: 1px solid var(--border); border-radius: 12px;
  padding: 5px; box-shadow: 0 8px 24px rgba(0,0,0,.1); z-index: 9000; min-width: 200px;
  opacity: 0; pointer-events: none; transform: translateY(-8px) scale(0.97);
  transform-origin: top; transition: opacity .18s ease, transform .18s cubic-bezier(0.34,1.2,0.64,1);
}
.dropdown-menu.open { opacity: 1; pointer-events: all; transform: translateY(0) scale(1); }
body.dark .dropdown-menu { box-shadow: 0 8px 24px rgba(0,0,0,.35); }
.dropdown-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 12px; border-radius: 8px; border: none; background: transparent;
  font-family: 'Geist', sans-serif; font-size: 13px; font-weight: 400; color: var(--text);
  text-align: left; cursor: pointer; text-decoration: none; transition: background .1s;
}
.dropdown-item:hover { background: var(--chip); }
.dropdown-item svg { flex-shrink: 0; opacity: 0.5; }
.dropdown-item.is-active { font-weight: 600; color: var(--accent); }
.dropdown-item.is-danger { color: var(--coral); }
.dropdown-divider { height: 1px; background: var(--border); margin: 4px 0; }

/* ── GOOGLE SIGN-IN BUTTON ────────────────────────────────── */
.google-btn {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 11px 16px; border: 2px solid var(--border); border-radius: 12px;
  background: var(--white); font-family: 'DM Sans', sans-serif;
  font-size: 14px; font-weight: 700; color: var(--text);
  cursor: pointer; justify-content: center; margin-bottom: 12px; transition: all 0.2s;
}
.google-btn:hover { border-color: #4285F4; background: #f0f6ff; transform: translateY(-1px); }

/* ── SECTION LAYOUT ───────────────────────────────────────── */
.section        { max-width: 1200px; margin: 0 auto; padding: 0 24px 60px; position: relative; z-index: 1; }
.section-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 28px; flex-wrap: wrap; gap: 12px; }
.section-title  { font-family: 'Instrument Serif', 'DM Serif Display', serif; font-size: 30px; font-weight: 400; color: var(--text); display: flex; align-items: center; gap: 10px; letter-spacing: -0.02em; }

/* ── TABS ─────────────────────────────────────────────────── */
.tabs    { display: flex; gap: 6px; background: var(--cream); border: 2px solid var(--border); border-radius: 50px; padding: 4px; margin-bottom: 28px; flex-wrap: wrap; }
.tab-btn { padding: 8px 18px; border-radius: 50px; border: none; background: transparent; font-family: 'DM Sans', sans-serif; font-size: 14px; font-weight: 700; color: var(--text-muted); cursor: pointer; transition: all 0.2s; }
.tab-btn.active { background: var(--sun); color: var(--text); box-shadow: 0 2px 8px rgba(var(--pp-green-400-rgb), 0.3); }

/* ── FORMS ────────────────────────────────────────────────── */
.form-group  { margin-bottom: 16px; }
.form-label  { display: block; font-size: 13px; font-weight: 700; color: var(--text-soft); margin-bottom: 6px; }
.form-input  { width: 100%; padding: 12px 16px; border: 2px solid var(--border); border-radius: var(--radius-sm); font-family: 'DM Sans', sans-serif; font-size: 15px; color: var(--text); background: var(--cream); transition: all 0.2s; outline: none; }
.form-input:focus { border-color: var(--sun-deep); background: var(--white); }
.form-divider { display: flex; align-items: center; gap: 12px; margin: 20px 0; font-size: 13px; color: var(--text-muted); }
.form-divider::before, .form-divider::after { content: ''; flex: 1; height: 1px; background: var(--border); }
.form-error  { background: #FFE4DA; border: 2px solid var(--coral); border-radius: var(--radius-sm); padding: 10px 14px; font-size: 13px; font-weight: 700; color: #C0391B; margin-bottom: 14px; display: none; }
.form-error.show { display: block; }

/* ── MODAL ────────────────────────────────────────────────── */
/* `visibility` alongside `opacity`, and it is not cosmetic: opacity:0 alone
   leaves a closed modal fully present in the accessibility tree and in the tab
   order. On the public Browse page that meant a screen-reader user was read the
   entire admin-only "Admin listing / New Etsy custom listing / Create ghost
   listing" form — invisible to sighted visitors, announced to everyone else —
   and could Tab into its fields. Every modal on the site uses this one class,
   so this closes it everywhere at once.
   visibility is transitioned too, with the same 0.3s duration: as a discrete
   property it flips at the END of a transition to `hidden` and at the START
   when going to `visible`, so the fade-out still plays in full and the fade-in
   is not delayed. */
.modal-overlay { position: fixed; inset: 0; background: rgba(45,32,20,0.6); backdrop-filter: blur(4px); z-index: 1000; display: flex; align-items: center; justify-content: center; padding: 20px; opacity: 0; visibility: hidden; pointer-events: none; transition: opacity 0.3s, visibility 0.3s; }
.modal-overlay.open { opacity: 1; visibility: visible; pointer-events: all; }
.modal { background: var(--white); border-radius: 16px; padding: 32px; width: 100%; max-width: 480px; max-height: 90vh; overflow-y: auto; transform: scale(0.92) translateY(20px); transition: all 0.3s; border: 3px solid var(--sun); position: relative; }
.modal-overlay.open .modal { transform: scale(1) translateY(0); }
.modal-close { position: absolute; top: 16px; right: 16px; background: var(--sun-light); border: none; width: 36px; height: 36px; border-radius: 50%; font-size: 18px; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.2s; color: var(--text); }
.modal-close:hover { background: var(--sun); transform: rotate(90deg); }
.modal-title { font-family: 'DM Serif Display', serif; font-size: 26px; font-weight: 400; color: var(--text); margin-bottom: 4px; }
.modal-sub   { font-size: 14px; color: var(--text-muted); margin-bottom: 24px; }

/* ── AUTH MODAL ───────────────────────────────────────────── */
.auth-tabs { display: flex; background: var(--cream); border-radius: 50px; padding: 4px; margin-bottom: 24px; border: 2px solid var(--border); }
.auth-tab  { flex: 1; padding: 10px; text-align: center; border-radius: 50px; font-size: 14px; font-weight: 700; cursor: pointer; transition: all 0.2s; color: var(--text-muted); border: none; background: transparent; font-family: 'DM Sans', sans-serif; }
.auth-tab.active { background: var(--sun); color: var(--text); }
.guest-notice    { background: var(--sky); border: 2px dashed var(--sky-deep); border-radius: var(--radius-sm); padding: 12px 16px; font-size: 13px; font-weight: 600; color: var(--sky-deep); display: flex; align-items: center; gap: 8px; margin-bottom: 16px; }

/* ── PANEL (slide-out) ────────────────────────────────────── */
.panel-overlay { position: fixed; inset: 0; overflow: hidden; background: rgba(20,10,5,0.7); backdrop-filter: blur(6px); z-index: 2000; display: flex; align-items: stretch; justify-content: flex-end; opacity: 0; pointer-events: none; transition: opacity 0.3s; }
.panel-overlay.open { opacity: 1; pointer-events: all; }
.panel { width: 100%; max-width: 780px; height: 100vh; background: var(--white); display: flex; flex-direction: column; transform: translateX(100%); transition: transform 0.35s cubic-bezier(0.34,1.1,0.64,1); border-left: 3px solid var(--sun); overflow: hidden; }
.panel-overlay.open .panel { transform: translateX(0); }
.panel-header { padding: 20px 24px; border-bottom: 2px solid var(--border); display: flex; align-items: center; justify-content: space-between; background: var(--cream); }
.panel-title  { font-family: 'DM Serif Display', serif; font-size: 22px; font-weight: 400; color: var(--text); display: flex; align-items: center; gap: 10px; }
.panel-tabs   { display: flex; gap: 4px; padding: 12px 16px; background: var(--card-bg); border-bottom: 2px solid var(--border); flex-wrap: wrap; }
.panel-tab    { padding: 8px 16px; border-radius: 50px; border: none; background: transparent; font-family: 'DM Sans', sans-serif; font-size: 13px; font-weight: 700; color: var(--text-muted); cursor: pointer; transition: all 0.2s; }
.panel-tab.active { background: var(--sun); color: var(--text); }
.panel-body   { flex: 1; overflow-y: auto; padding: 24px; }
.panel-section { display: none; }
.panel-section.active { display: block; }


.cart-btn     { position: relative; background: var(--peach); border: 2px solid var(--peach-deep); border-radius: 12px; padding: 8px 16px; cursor: pointer; transition: all 0.2s; display: flex; align-items: center; gap: 6px; font-family: 'DM Sans', sans-serif; font-weight: 700; font-size: 14px; color: var(--text); }
.cart-btn:hover { background: var(--peach-deep); transform: scale(1.05); }
.cart-count   { position: absolute; top: -6px; right: -6px; background: var(--coral); color: var(--white); width: 20px; height: 20px; border-radius: 50%; font-size: 11px; font-weight: 800; display: flex; align-items: center; justify-content: center; border: 2px solid var(--white); }


/* ── PROGRESS BAR ─────────────────────────────────────────── */
.progress-bar-wrap { background: var(--border); border-radius: 50px; height: 10px; margin: 12px 0; overflow: hidden; }
.progress-bar-fill { height: 100%; background: linear-gradient(90deg, var(--sun) 0%, var(--sun-deep) 100%); border-radius: 50px; transition: width 0.4s ease; }

/* Toasts: laid out and styled in ONE place, header.js (window.ppToast). */

/* ── REWARDS / TIER CARDS ─────────────────────────────────── */
.rewards-section { background: var(--card-bg); border: 2px solid var(--border); border-radius: 28px; padding: 36px; margin-bottom: 32px; }
.rewards-tiers   { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 16px; margin-top: 24px; }
.tier-card       { background: var(--cream); border: 2px solid var(--border); border-radius: var(--radius-sm); padding: 20px 16px; text-align: center; transition: all 0.2s; position: relative; }
.tier-card.active { border-color: var(--sun-deep); background: var(--sun-light); transform: scale(1.03); }
.tier-icon       { font-size: 36px; margin-bottom: 8px; }
.tier-name       { font-family: 'DM Serif Display', serif; font-size: 18px; font-weight: 400; color: var(--text); margin-bottom: 4px; }
.tier-req        { font-size: 12px; color: var(--text-muted); font-weight: 600; margin-bottom: 8px; }
.tier-perks      { font-size: 12px; color: var(--text-soft); line-height: 1.5; }
.tier-active-badge { position: absolute; top: -10px; right: -10px; background: var(--sun-deep); color: var(--white); font-size: 10px; font-weight: 800; padding: 3px 8px; border-radius: 50px; }

/* ── SPIN WHEEL ───────────────────────────────────────────── */
.spin-section  { background: linear-gradient(135deg, var(--pp-green-50) 0%, #F2E9E0 50%, #E8DFF5 100%); border: 3px dashed var(--sun-deep); border-radius: 28px; padding: 32px; text-align: center; margin-bottom: 32px; position: relative; overflow: hidden; }
.spin-title    { font-family: 'DM Serif Display', serif; font-size: 34px; font-weight: 400; color: var(--text); margin-bottom: 8px; }
.spin-subtitle { font-size: 16px; color: var(--text-soft); margin-bottom: 28px; }
.wheel-wrap      { display: flex; flex-direction: column; align-items: center; gap: 24px; }
.wheel-container { position: relative; width: 280px; height: 280px; }
.wheel-pointer   { position: absolute; top: -18px; left: 50%; transform: translateX(-50%); width: 0; height: 0; border-left: 14px solid transparent; border-right: 14px solid transparent; border-top: 28px solid var(--coral); z-index: 10; filter: drop-shadow(0 2px 4px rgba(0,0,0,0.2)); }
.wheel-center    { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); width: 50px; height: 50px; background: var(--white); border-radius: 50%; border: 4px solid var(--sun-deep); z-index: 5; display: flex; align-items: center; justify-content: center; font-size: 20px; }
.spin-result     { background: var(--sun-light); border: 3px solid var(--sun-deep); border-radius: var(--radius); padding: 24px; text-align: center; margin-top: 20px; display: none; }
.spin-result.show { display: block; animation: popIn 0.5s cubic-bezier(0.34,1.56,0.64,1); }
.spin-result-emoji { font-size: 48px; margin-bottom: 8px; }
.spin-result-title { font-family: 'DM Serif Display', serif; font-size: 24px; font-weight: 400; color: var(--text); }
.spin-result-sub   { font-size: 14px; color: var(--text-soft); margin-top: 4px; }

/* ── ADMIN BADGE ──────────────────────────────────────────── */
.admin-badge { background: var(--coral); color: var(--white); font-size: 10px; font-weight: 800; padding: 3px 8px; border-radius: 50px; letter-spacing: 0.5px; }

/* ── EMPTY STATE ──────────────────────────────────────────── */
.empty-state      { text-align: center; padding: 60px 20px; color: var(--text-muted); }
.empty-state-icon { font-size: 48px; margin-bottom: 16px; }
.empty-state-text { font-size: 16px; font-weight: 600; }

/* ── SPINNER ──────────────────────────────────────────────── */
.spinner { width: 20px; height: 20px; border: 3px solid rgba(255,255,255,0.3); border-top-color: #fff; border-radius: 50%; animation: spin 0.7s linear infinite; display: inline-block; }

/* ── CONFETTI ─────────────────────────────────────────────── */
.confetti-piece { position: fixed; width: 10px; height: 10px; border-radius: 2px; pointer-events: none; z-index: 9999; animation: confettiFall 3s ease-in forwards; }

/* ══════════════════════════════════════════════════════════
   SCROLLBARS
   ══════════════════════════════════════════════════════════ */
html.dark, body.dark, html.dark * , body.dark * {
  scrollbar-color: #4A4A52 #1A1A1E;
}
html.dark ::-webkit-scrollbar, body.dark ::-webkit-scrollbar {
  width: 10px; height: 10px;
}
html.dark ::-webkit-scrollbar-track, body.dark ::-webkit-scrollbar-track {
  background: #1A1A1E;
}
html.dark ::-webkit-scrollbar-thumb, body.dark ::-webkit-scrollbar-thumb {
  background: #4A4A52;
  border-radius: 8px;
}
html.dark ::-webkit-scrollbar-thumb:hover, body.dark ::-webkit-scrollbar-thumb:hover {
  background: #5C5C66;
}

/* ══════════════════════════════════════════════════════════
   DARK MODE
   ══════════════════════════════════════════════════════════ */
html.dark, body.dark {
  background: #0E0E10;
  color: #F2F2F0;
  /* Override all design tokens for dark mode */
  --bg:           #0E0E10;
  --surface:      #16161A;
  --ink:          #F2F2F0;
  --muted:        #9A9A95;
  --line:         #26262B;
  --chip:         #1E1E22;
  --accent:       var(--pp-green-500);
  --accent-deep:  var(--pp-green-600);
  --accent-light: #2C1F00;
  --sun:          var(--pp-green-500);
  --sun-deep:     var(--pp-green-500);
  --sun-light:    #2C1F00;
  --mint:         #2C1F00;
  --mint-deep:    var(--pp-green-500);
  --lilac:        #2C1F00;
  --lilac-deep:   var(--pp-green-500);
  --coral:        #F87171;
  --coral-light:  #2A1A1A;
  --sky:          #1A1F2E;
  --sky-deep:     #60A5FA;
  --cream:        #1E1E22;
  --peach:        #16161A;
  --peach-deep:   #7070A0;
  --text:         #F2F2F0;
  --text-soft:    #9A9A95;
  /* Dark counterpart of the note above. #6A6A65 was 3.6:1 on --surface and the
     shadowing copies used #555560 (2.6:1) — the footer, the sidebar counts and
     the copyright line were all painted with it. #8A8A94 is 5.3:1 on
     --surface and 5.6:1 on --bg. */
  --text-muted:   #8A8A94;
  --white:        #16161A;
  --card-bg:      #16161A;
  --border:       #26262B;
  --shadow:       0 1px 3px rgba(0,0,0,0.3), 0 4px 16px rgba(0,0,0,0.25);
  --shadow-hover: 0 4px 12px rgba(0,0,0,0.4), 0 16px 40px rgba(0,0,0,0.35);
}

/* Component-specific dark mode overrides */
body.dark .modal         { background: #16161F; border-color: rgba(233,168,37,0.4); }
body.dark .modal-close   { background: #2C1F00; color: #F0F0F8; }
body.dark .modal-title   { color: #F0F0F8; }
body.dark .modal-sub     { color: #6060A0; }
body.dark .form-input    { background: #111119; border-color: rgba(255,255,255,0.1); color: #F0F0F8; }
body.dark .form-input:focus { background: #2C1F00; border-color: var(--pp-green-500); }
body.dark .form-label    { color: #9090A8; }
body.dark .form-error    { background: #2A1A1A; border-color: #F87171; color: #F87171; }
body.dark .tabs          { background: #111119; border-color: rgba(255,255,255,0.07); }
body.dark .tab-btn       { color: #4A4A60; }
body.dark .tab-btn.active { background: #2C1F00; color: #F0F0F8; box-shadow: none; }
body.dark .auth-tabs     { background: #111119; border-color: rgba(255,255,255,0.07); }
body.dark .auth-tab      { color: #4A4A60; }
body.dark .auth-tab.active { background: #2C1F00; color: #F0F0F8; }
body.dark .google-btn    { background: #16161F; border-color: rgba(255,255,255,0.1); color: #F0F0F8; }
body.dark .google-btn:hover { background: #1E1E2C; border-color: rgba(255,255,255,0.2); }
body.dark .guest-notice  { background: #1A1F2E; border-color: rgba(96,165,250,0.3); color: #60A5FA; }
body.dark .panel         { background: #16161F; border-left-color: rgba(233,168,37,0.5); }
body.dark .panel-header  { background: #111119; border-bottom-color: rgba(255,255,255,0.06); }
body.dark .panel-title   { color: #F0F0F8; }
body.dark .panel-tabs    { background: #16161F; border-bottom-color: rgba(255,255,255,0.06); }
body.dark .panel-tab     { color: #4A4A60; }
body.dark .panel-tab.active { background: #2C1F00; color: #F0F0F8; }

body.dark .cart-btn      { background: #1E1E2C; border-color: rgba(255,255,255,0.1); color: #9090A8; }
body.dark .cart-btn:hover { background: #252538; border-color: rgba(255,255,255,0.18); color: #F0F0F8; }

body.dark .section-title { color: #F0F0F8; }
body.dark .tier-card     { background: #111119; border-color: rgba(255,255,255,0.07); }
body.dark .tier-card.active { background: #2C1F00; border-color: var(--pp-green-500); }
body.dark .tier-name     { color: #F0F0F8; }
body.dark .rewards-section  { background: #111119; border-color: rgba(255,255,255,0.07); }
body.dark .spin-section  { background: linear-gradient(135deg, #2C1F00 0%, #1A1A2E 50%, #1A1830 100%); }
body.dark .page-hero-badge  { background: transparent; border-color: #26262B; color:var(--text-muted); }
body.dark .page-hero { border-bottom-color: #26262B; }
body.dark .page-hero h1  { color: #F0F0F8; }
body.dark .page-hero p   { color: #666670; }
/* Buttons — dark theme. Blue keeps its vars (already dark-aware).
   Red is forced to a strong shade (the dark --coral token is a light red that fails
   against white text), and grey gets explicit dark surfaces. */

/* Green primary — one identity in both themes.
   This used to invert in dark mode (dark ink #062B16 on bright #4ADE80, 8.8:1),
   because white on the dark --accent #22C55E is only 2.3:1. That solved the
   contrast but made the site's most important control read as a different
   button per theme, which is the thing this block set out to prevent.
   Darkening the FILL instead of flipping the ink gets both: white on var(--pp-green-700) is
   5.0:1 (AA), and the button SHAPE still separates from the #0E0E10 page at
   3.8:1 — comfortably over the 3:1 floor for non-text — so it does not vanish
   the way a mid-green fill would. var(--pp-green-700) is already the light-mode value, so
   the themes now differ only in hover.
   The literal is deliberate: --accent-deep resolves to var(--pp-green-600) under dark, and
   white on that is 3.3:1, so reading the token here would reintroduce the very
   failure this note is about.
   NB this also RE-matches checkout's `body.dark .co-pay-btn`, which has been
   var(--pp-green-700) on white all along — the inversion had drifted away from it. */
body.dark .btn-primary, body.dark .btn-mint { background: var(--pp-green-700); border-color: var(--pp-green-700); color: #fff; }
body.dark .btn-primary:hover, body.dark .btn-mint:hover { background: var(--pp-green-800); border-color: var(--pp-green-800); box-shadow: 0 4px 16px rgba(var(--pp-green-500-rgb), 0.35); }
/* …but NOT the glassy on-image variant, which keeps a dark translucent fill in
   both themes (see .btn-on-image below) and so still needs white text.
   The background/border have to be restated, not just the colour: the rule above
   is `body.dark .btn-primary` (0,0,2,1) and out-specifies `.btn-primary.btn-on-image`
   (0,0,2,0), so without this the glassy fill is replaced by solid bright green and
   the white label lands at 2.3:1 — worse than what this whole block set out to fix. */
body.dark .btn-primary.btn-on-image, body.dark .btn-mint.btn-on-image {
  background: rgba(var(--pp-green-900-rgb), 0.42); border-color: rgba(var(--pp-green-300-rgb), 0.45); color: #fff;
}
body.dark .btn-primary.btn-on-image:hover, body.dark .btn-mint.btn-on-image:hover {
  background: rgba(var(--pp-green-900-rgb), 0.58); border-color: rgba(var(--pp-green-300-rgb), 0.7);
}

body.dark .btn-danger, body.dark .btn-coral { background: #EF4444; border-color: #EF4444; color: #fff; }
body.dark .btn-danger:hover, body.dark .btn-coral:hover { background: #DC2626; border-color: #DC2626; box-shadow: 0 4px 16px rgba(0,0,0,0.45); }
body.dark .btn-secondary { background: #24242A; color: #F2F2F0; border-color: #33333A; }
body.dark .btn-secondary:hover { background: #2C2C34; border-color: #4A4A55; }
body.dark .btn-outline   { background: transparent; color: #9090A8; border-color: rgba(255,255,255,0.12); }
body.dark .btn-outline:hover { border-color: rgba(255,255,255,0.25); color: #F0F0F8; }
body.dark footer         { background: #07070E; }

/* ── RESPONSIVE ───────────────────────────────────────────── */
@media (max-width: 600px) {
  .page-hero p { white-space: normal; }
  .panel { max-width: 100%; }

}

/* Better mobile touch targets */
@media (max-width: 480px) {
  .btn { padding: 10px 18px; font-size: 13px; }
  .btn-sm { padding: 8px 14px; font-size: 12px; }
  .modal { padding: 24px 20px; border-radius: 16px; }
  .section { padding-left: 16px; padding-right: 16px; }

  .cart-footer { padding: 16px; }
  .cart-header { padding: 18px 16px; }
}

/* ── PAGE TAB NAVIGATION (Shop / Votes / Referral Redeemer) ──────────── */
.page-tab-nav {
  max-width: 1240px;
  margin: 0 auto;
  padding: 0 24px;
}
.page-tab-nav-inner {
  display: flex;
  align-items: center;
  gap: 0;
  border-bottom: 1.5px solid rgba(0,0,0,0.08);
  position: relative;
}
.page-tab-link {
  font-family: 'DM Sans', sans-serif;
  font-size: 15px;
  font-weight: 600;
  color: #9aada3;
  text-decoration: none;
  padding: 12px 0;
  margin-right: 28px;
  display: flex;
  align-items: center;
  white-space: nowrap;
  transition: color 0.22s ease;
  position: relative;
  letter-spacing: 0.1px;
  background: none;
  border: none;
  cursor: pointer;
}
.page-tab-link:first-child { padding-left: 0; }
.page-tab-link:last-child  { margin-right: 0; }
.page-tab-link:hover { color: var(--pp-green-600); }
.page-tab-link.active { color: #1a1a1a; font-weight: 700; }
.page-tab-indicator {
  position: absolute;
  bottom: -1px;
  height: 2.5px;
  background: linear-gradient(90deg, var(--pp-green-400), var(--pp-green-600));
  border-radius: 2px 2px 0 0;
  transition: left 0.3s cubic-bezier(0.45,0,0.25,1), width 0.3s cubic-bezier(0.45,0,0.25,1);
  pointer-events: none;
  will-change: left, width;
}
body.dark .page-tab-nav-inner { border-color: rgba(255,255,255,0.1); }
body.dark .page-tab-link { color: var(--pp-green-ink-soft); }
body.dark .page-tab-link:hover { color: var(--pp-green-400); }
body.dark .page-tab-link.active { color: #e8f4ee; }
body.dark .page-tab-indicator { background: linear-gradient(90deg, var(--pp-green-600), var(--pp-green-400)); }
@media (max-width: 600px) {
  .page-tab-nav { padding: 0 14px; }
  .page-tab-link { font-size: 14px; margin-right: 18px; }
}

/* ── MARKET DESIGN: Sidebar layout ───────────────────────────────────────── */
@media (max-width: 799.98px) {
  body > .page-wrap { margin-left: 0; }
}
/* ── IGN underline input — dark mode transparency ────────────────────────── */
body.dark .ign-underline-wrap,
body.dark .ign-underline-wrap > div {
  background: transparent !important;
  box-shadow: none !important;
  border: none !important;
}
body.dark .ign-underline-input,
body.dark input[type="text"].ign-underline-input,
body.dark input[type="number"].ign-underline-input {
  background: transparent !important;
  box-shadow: none !important;
  border: none !important;
  -webkit-box-shadow: none !important;
}
body.dark .ign-underline-input:-webkit-autofill,
body.dark .ign-underline-input:-webkit-autofill:hover,
body.dark .ign-underline-input:-webkit-autofill:focus {
  -webkit-box-shadow: 0 0 0px 1000px transparent inset !important;
  transition: background-color 5000s ease-in-out 0s;
}

/* ══════════════════════════════════════════════════════════
   STARRED VARIANT INDICATOR
   `starred` marks the special variant of an item — it pairs with a standard
   one sharing the same inventory_tag. These two classes are the single visual
   language for that flag everywhere it surfaces (builder cards and pack
   summary, checkout, dashboard orders, order and pack pages), replacing the
   old Star.png overlay that sat on the item thumbnail and was easy to miss.
   ══════════════════════════════════════════════════════════ */

/* Inline glyph that sits directly before an item name.
   These were declared unconditionally (no light/dark split), always at the
   dark-mode-appropriate values — so light mode got the same moody navy/amber/
   purple badge as dark mode instead of its own look. Split below; dark values
   are unchanged from before. */
:root {
  --pp-star-bg: rgba(254,243,199,.82);
  --pp-star-border: rgba(245,158,11,.85);
  --pp-star-icon: #92400E;
  --pp-star-shadow: 0 0 0 2px rgba(0,0,0,.04), 0 2px 8px rgba(0,0,0,.10);
  --pp-recipe-bg: rgba(219,234,254,.82);
  --pp-recipe-border: rgba(59,130,246,.85);
  --pp-recipe-icon: #1D4ED8;
  --pp-recipe-shadow: 0 0 0 2px rgba(0,0,0,.04), 0 2px 8px rgba(0,0,0,.10);
  --pp-style-bg: rgba(250,232,255,.82);
  --pp-style-border: rgba(217,70,239,.85);
  --pp-style-icon: #A21CAF;
  --pp-style-shadow: 0 0 0 2px rgba(0,0,0,.04), 0 2px 8px rgba(0,0,0,.10);
  --pp-grown-bg: rgba(var(--pp-green-100-rgb), .82);
  --pp-grown-border: rgba(var(--pp-green-500-rgb), .85);
  --pp-grown-icon: var(--pp-green-700);
  --pp-grown-shadow: 0 0 0 2px rgba(0,0,0,.04), 0 2px 8px rgba(0,0,0,.10);
  /* Unselected ("off") state — a light neutral chip, NOT a dark one. */
  --pp-off-bg: rgba(255,255,255,.82);
  --pp-off-border: rgba(0,0,0,.18);
  --pp-off-icon: #8A8A94;
  --pp-off-shadow: 0 0 0 2px rgba(0,0,0,.04), 0 2px 8px rgba(0,0,0,.10);
}
body.dark {
  --pp-star-bg: rgba(77,59,5,.82);
  --pp-star-border: rgba(245,179,1,.85);
  --pp-star-icon: #F5B301;
  --pp-star-shadow: 0 0 0 2px rgba(15,15,17,.62), 0 4px 12px rgba(0,0,0,.5);
  --pp-recipe-bg: rgba(16,42,79,.82);
  --pp-recipe-border: rgba(59,130,246,.85);
  --pp-recipe-icon: #60A5FA;
  --pp-recipe-shadow: 0 0 0 2px rgba(15,15,17,.62), 0 4px 12px rgba(0,0,0,.5);
  --pp-style-bg: rgba(59,23,79,.82);
  --pp-style-border: rgba(217,70,239,.85);
  --pp-style-icon: #F0ABFC;
  --pp-style-shadow: 0 0 0 2px rgba(15,15,17,.62), 0 4px 12px rgba(0,0,0,.5);
  --pp-grown-bg: rgba(var(--pp-green-950-rgb), .82);
  --pp-grown-border: rgba(var(--pp-green-500-rgb), .85);
  --pp-grown-icon: var(--pp-green-400);
  --pp-grown-shadow: 0 0 0 2px rgba(15,15,17,.62), 0 4px 12px rgba(0,0,0,.5);
  --pp-off-bg: rgba(20,20,22,.82);
  --pp-off-border: rgba(255,255,255,.28);
  --pp-off-icon: #9A9AA4;
  --pp-off-shadow: 0 0 0 2px rgba(15,15,17,.62), 0 4px 12px rgba(0,0,0,.5);
}
.pp-star-ico {
  flex-shrink: 0;
  vertical-align: -2px;
  margin-right: 4px;
  color: var(--pp-star-icon);
}

/* Icon-only badge — no label, just the star in a rounded square. Gold when
   the starred variant is active, grey when it isn't — the grey state is what
   makes it read as a control rather than a badge, so only render it for
   items that can actually be toggled. Padding-based (not a fixed box) so it
   hugs whatever icon size a given call site passes to _ppStarIcoHTML/
   PP_STAR_ICO — dense list rows and a modal title don't use the same size. */
.pp-starred-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  padding: 4px;
  box-sizing: border-box;
  border-radius: 8px;
  border: 2px solid var(--pp-star-border);
  background: var(--pp-star-bg);
  color: var(--pp-star-icon);
  box-shadow: var(--pp-star-shadow);
  vertical-align: -4px;
  line-height: 0;
}
/* The tokens are already theme-aware, so the on/off states need no
   body.dark twins — one rule each drives both modes. */
.pp-starred-pill.is-off {
  border: 2px solid var(--pp-off-border);
  background: var(--pp-off-bg);
  color: var(--pp-off-icon);
  box-shadow: var(--pp-off-shadow);
  backdrop-filter: blur(4px);
}
/* The off state's star is drawn with currentColor so it greys out with the
   pill; the on state's is hard-coded gold in the markup. The icon carries its
   own margin/vertical-align for its old inline (no-pill) uses — inside the
   pill it's centered by flex instead, so both get zeroed here. */
.pp-starred-pill.is-off .pp-star-ico { color: inherit; }
.pp-starred-pill .pp-star-ico {
  display: block;
  margin: 0 !important;
  vertical-align: 0 !important;
}

/* Deliberately no hover colour. These pills are toggles whose COLOUR is their
   state — gold/green means "on", grey means "off". Tinting the grey pill on
   hover made a pill the pointer merely passed over read as switched on, which
   is exactly the question the pill is there to answer. The cursor carries the
   affordance instead; colour only ever changes on a real click. */
button.pp-starred-pill {
  cursor: pointer;
}

/* Display-only Recipe marker. It shares the same compact rounded-square
   language as Starred, but blue distinguishes metadata from quality. */
.pp-blueprint-ico {
  flex-shrink: 0;
  display: block;
  margin: 0 !important;
  vertical-align: 0 !important;
}
.pp-recipe-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  padding: 4px;
  box-sizing: border-box;
  border-radius: 8px;
  border: 2px solid var(--pp-recipe-border);
  background: var(--pp-recipe-bg);
  color: var(--pp-recipe-icon);
  box-shadow: var(--pp-recipe-shadow);
  vertical-align: -4px;
  line-height: 0;
}
body.dark .pp-recipe-pill {
  border-color: var(--pp-recipe-border);
  background: var(--pp-recipe-bg);
  color: var(--pp-recipe-icon);
}

/* Reusable Housing Style unlock (wallpaper, flooring, roofing). Geometry is
   intentionally identical to the Blueprint / Recipe pill. */
.pp-paintbrush-ico {
  flex-shrink: 0;
  display: block;
  margin: 0 !important;
  vertical-align: 0 !important;
}
.pp-style-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  padding: 4px;
  box-sizing: border-box;
  border-radius: 8px;
  border: 2px solid var(--pp-style-border);
  background: var(--pp-style-bg);
  color: var(--pp-style-icon);
  box-shadow: var(--pp-style-shadow);
  vertical-align: -4px;
  line-height: 0;
}
body.dark .pp-style-pill {
  border-color: var(--pp-style-border);
  background: var(--pp-style-bg);
  color: var(--pp-style-icon);
}

/* ── Fully Grown ─────────────────────────────────────────────────────────────
   "Deliver this plant at its full-grown stage" — a per-line CHOICE, like the
   star, not a fixed property like Recipe/Housing Style. So it borrows the
   star's on/off grammar exactly: green when the line is being bought fully
   grown, the shared grey --pp-off-* chip when it isn't, and the pill stays on
   screen in both states so it can be toggled back.
   Only rendered on products whose own `fully_grown` flag is set — everything
   else has no such stage to deliver, and the backend refuses the uplift there
   anyway (see grownMult in backend/routes/orders.ts). */
.pp-grown-ico {
  flex-shrink: 0;
  display: block;
  margin: 0 !important;
  vertical-align: 0 !important;
}
.pp-grown-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  padding: 4px;
  box-sizing: border-box;
  border-radius: 8px;
  border: 2px solid var(--pp-grown-border);
  background: var(--pp-grown-bg);
  color: var(--pp-grown-icon);
  box-shadow: var(--pp-grown-shadow);
  vertical-align: -4px;
  line-height: 0;
}
.pp-grown-pill.is-off {
  border: 2px solid var(--pp-off-border);
  background: var(--pp-off-bg);
  color: var(--pp-off-icon);
  box-shadow: var(--pp-off-shadow);
  backdrop-filter: blur(4px);
}
/* No hover colour — same reason as button.pp-starred-pill above. */
button.pp-grown-pill {
  cursor: pointer;
}

/* ── Item-card marker strip ──────────────────────────────────────────────────
   One placement for every item grid on the site: the pills above sit on the
   thumbnail's bottom-left corner, not in front of the name, where they used to
   push the name around and read as part of the text. Drop this container inside
   the (position:relative) image wrapper and put the pills in it — pack.html
   overrides the sizes for its larger cards. */
.pack-fs-img-badges {
  position: absolute;
  left: 6px;
  bottom: 6px;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 4px;
  pointer-events: none;
}
.pack-fs-img-badges > * {
  width: 24px;
  min-width: 24px;
  height: 24px;
  margin: 0 !important;
  padding: 0 !important;
  border-radius: 7px;
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: 0 !important;
  line-height: 0;
  font-size: 0;
}
.pack-fs-img-badges svg {
  width: 13px !important;
  height: 13px !important;
  display: block;
  margin: 0 !important;
  vertical-align: 0 !important;
}
/* Same corner on the small row thumbnails (cart lines, order rows, ~44–60px)
   where a full-size badge would swallow the artwork. */
.pack-fs-img-badges.compact {
  left: 3px;
  bottom: 3px;
  gap: 3px;
}
.pack-fs-img-badges.compact > * {
  width: 18px;
  min-width: 18px;
  height: 18px;
  border-radius: 6px;
  border-width: 1.5px;
}
.pack-fs-img-badges.compact svg { width: 10px !important; height: 10px !important; }

/* ── Browse-only mode (the admin safety switch) ──────────────────────────────
   header.js puts .pp-no-purchase on <html> when /api/settings says the switch
   applies to this viewer — never for an admin. The site becomes an item browser
   and pack tracker: packs still build and save, there is just nothing to pay
   with and no price to pay.

   This is presentation only. index.ts refuses the same requests server-side, so
   nothing here is what actually stops a purchase — it stops us ADVERTISING one,
   which is the point: no prices, no checkout, no payment hints.

   Prices carry a per-page class rather than one shared hook, so this is an
   explicit list. Anything missed shows a price on a site that cannot sell — ugly
   but not dangerous. Add new price classes here as they appear. */
html.pp-no-purchase .ci-price,
html.pp-no-purchase .tier-price,
html.pp-no-purchase .qs-price,
html.pp-no-purchase .qa-price,
html.pp-no-purchase .amt-price,
html.pp-no-purchase .pack-card-price,
html.pp-no-purchase .pack-fs-ghost-price-row,
html.pp-no-purchase .hp-card-price,
html.pp-no-purchase .bb-item-price-pill,
html.pp-no-purchase .bb-ic-amount-price,
html.pp-no-purchase .rf-item-price,
html.pp-no-purchase .rf-foot-total,
html.pp-no-purchase .pd-hero-price,
html.pp-no-purchase .pd-buy-price,
html.pp-no-purchase .total-cost-val,
html.pp-no-purchase .total-cost-label,
html.pp-no-purchase .save-badge-pill,
/* Checkout and payment affordances — the safety-critical half of this list. */
html.pp-no-purchase .pd-buy,
html.pp-no-purchase .mcard-buy-btn,
/* Pack Builder card redesign (2026-09-22): price + "+ Add" live in the card
   foot; every Add to Basket button (phone bar, pack panel, pack page). */
html.pp-no-purchase .mcard-foot-bar,
html.pp-no-purchase .mcard-media-action,
html.pp-no-purchase .bb-pack-fab-atc,
html.pp-no-purchase #bbAtcBtn,
html.pp-no-purchase .pack-fs-atc,
html.pp-no-purchase .pack-fs-outline-atc,
html.pp-no-purchase .co-basket-block,
html.pp-no-purchase #sh-basket-btn,
html.pp-no-purchase .sh-cart-btn-clean,
html.pp-no-purchase [data-purchase-only] {
  display: none !important;
}

/* Tint a housing line was bought in (3D preview) — rendered by
   window.ppTintMarkHTML (header.js) on every page: the original pill, a dot of
   the tint's three colours plus the name, inline beside the price/name with
   the .pp-mark chips below. */
.pp-tint-mark {
  display: inline-flex; align-items: center; gap: 5px; max-width: 100%;
  padding: 2px 8px 2px 3px; border-radius: 20px; box-sizing: border-box;
  background: rgba(127, 127, 127, .14); color: var(--text);
  font-size: 10.5px; font-weight: 800; line-height: 1.4;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 0 1 auto;
}
.pp-tint-name { overflow: hidden; text-overflow: ellipsis; }
/* Star Quality / Fully Grown / Recipe / Housing Style — window.ppItemMarksHTML
   (header.js). The tint pill's shape, the icon carrying the colour; sits
   inline beside the price/name; order-item cards put Star/Grown on the thumbnail. */
.pp-mark {
  display: inline-flex; align-items: center; gap: 4px; max-width: 100%;
  padding: 2px 8px 2px 5px; border-radius: 20px; box-sizing: border-box;
  background: rgba(127, 127, 127, .14); color: var(--text);
  font-size: 10.5px; font-weight: 800; line-height: 1.4;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  /* Wrap to its own line before truncating (narrow pack rows on phones). */
  flex: 0 0 auto; vertical-align: middle;
}
.pp-mark-ico { display: inline-flex; flex: 0 0 auto; }
.pp-mark-ico svg { display: block; width: 12px; height: 12px; }
.pp-mark-name { overflow: hidden; text-overflow: ellipsis; }
.pp-mark--recipe .pp-mark-ico { color: #3B82F6; }
.pp-mark--style .pp-mark-ico { color: #C026D3; }
body.dark .pp-mark--recipe .pp-mark-ico { color: #60A5FA; }
body.dark .pp-mark--style .pp-mark-ico { color: #E879F9; }
/* A row of marks under a name, for surfaces with no price row to share. */
.pp-marks { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; margin-top: 7px; min-width: 0; }
.pp-marks:empty { display: none; }
.pp-tint-dot {
  display: inline-flex; flex: 0 0 auto; width: 13px; height: 13px; border-radius: 50%; overflow: hidden;
  box-shadow: 0 0 0 1px rgba(127, 127, 127, .4); transform: rotate(-20deg); background: #6b6b75;
}
.pp-tint-dot i { flex: 1 1 0; }
/* In the thumbnail's marker row: undo the row's 24px-square icon sizing and
   sit on a dark backing so the name reads over any artwork. */
.pack-fs-img-badges > .pp-tint-mark {
  width: auto; min-width: 0; height: 22px; padding: 0 8px 0 4px !important; border-radius: 20px;
  font-size: 10px; line-height: 1; justify-content: flex-start;
  background: rgba(15, 15, 17, .78); color: #fff; backdrop-filter: blur(4px);
}
/* Star Quality / Fully Grown on a card thumbnail (order.js itemImgBadges):
   the icon alone, on the same dark backing as the tint mark. */
.pack-fs-img-badges > .pp-mark { background: rgba(15, 15, 17, .78); color: #fff; backdrop-filter: blur(4px); border-radius: 7px; }
.pack-fs-img-badges > .pp-mark .pp-mark-name { display: none; }
/* Small row thumbnails (basket lines): the dot alone — a name won't fit. */
.pack-fs-img-badges.compact > .pp-tint-mark { height: 18px; width: 18px; min-width: 18px; padding: 0 !important; justify-content: center; }
.pack-fs-img-badges.compact > .pp-tint-mark .pp-tint-name { display: none; }
.pack-fs-img-badges.compact > .pp-tint-mark .pp-tint-dot { width: 12px; height: 12px; }

/* ── No recipe markers anywhere (owner, 2026-10-01) ───────────────────────────
   The recipe tag/badge/pill is removed site-wide: cards, pack + basket lines,
   orders, rewards/path/wheel, admin. Items keep item_type 'recipe' and price
   the same; only the marker is gone. Same rule in styles.css, rewards.css and
   admin.css because rewards.html / admin.html don't load styles.css. */
.bb-card-recipe-badge,
.bb-item-recipe-badge,
.path-reward-recipe-badge,
.path-reward-recipe-svg,
.pp-recipe-pill,
.wheel-recipe-badge,
.reward-recipe-badge,
.pp-mark--recipe,
.bb-ov-note--recipe {
  display: none !important;
}
