/* ============================================================
   FIELD SUPPLY — shared theme. ONE source of truth for color.
   Change a variable here and the whole store (storefront + every
   product page) re-skins. Runtime: window.setTheme({ '--brand': '...' }).
   RGB-channel vars are space-separated (for Tailwind alpha);
   gradient stops take any CSS color.
   ============================================================ */
:root {
  --brand: 245 110 36;       /* #f56e24 — ember orange (site accent) */
  --brand-700: 209 86 22;    /* darker ember for hover */
  --ink: 26 23 20;           /* near-black warm ink for headings */
  --ink-soft: 74 68 62;      /* body text */
  --muted: 124 116 107;      /* captions */
  --line: 233 229 223;       /* hairlines */
  --soft: 250 248 245;       /* section wash (warm off-white) */
  --ok: 36 150 90;           /* success green */

  /* Hero gradient stops — warm ember sweep */
  --g1: #ffe7a8;
  --g2: #ffb24d;
  --g3: #ff7a3c;
  --g4: #ff5470;
  --g5: #ffd36b;
  --hero-angle: 110deg;
  --hero-cut: 5vw;
}

html { font-family: 'Inter', system-ui, sans-serif; color: rgb(var(--ink-soft)); -webkit-font-smoothing: antialiased; }
body { background: #fff; }
.font-mono { font-family: 'JetBrains Mono', monospace; }

.hero-grad {
  background:
    radial-gradient(60% 70% at 78% 8%, rgba(255,255,255,.55), transparent 60%),
    radial-gradient(50% 60% at 8% 0%, rgba(255,255,255,.35), transparent 55%),
    linear-gradient(var(--hero-angle), var(--g1), var(--g2) 26%, var(--g3) 50%, var(--g4) 76%, var(--g5));
}
.hero-cut { clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--hero-cut)), 0 100%); }
.grad-band { background: linear-gradient(var(--hero-angle), var(--g2), var(--g3) 45%, var(--g4) 100%); }
.brand-grad-text { background: linear-gradient(100deg, rgb(var(--brand)), var(--g3) 55%, var(--g4)); -webkit-background-clip: text; background-clip: text; color: transparent; }

.no-bar::-webkit-scrollbar { display: none; }
.no-bar { -ms-overflow-style: none; scrollbar-width: none; }

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .reveal { animation: rise linear both; animation-timeline: view(); animation-range: entry 0% entry 100%; }
  }
  @keyframes rise { from { opacity: 0; transform: translateY(22px); } to { opacity: 1; transform: none; } }
}
@media (prefers-reduced-motion: reduce) { * { animation: none !important; transition-duration: .01ms !important; } }

.head-scrolled { box-shadow: 0 1px 0 rgb(var(--line)), 0 8px 30px -16px rgba(26,23,20,.22); background: rgba(255,255,255,.92); backdrop-filter: blur(12px); }

/* skeleton / shimmer loaders — shown while product data loads from Gumroad */
.sk { position: relative; overflow: hidden; background: rgba(26,23,20,.08); border-radius: 7px; }

/* Concrete layout classes for JS-INJECTED content. The Tailwind Play CDN does
   not reliably generate arbitrary classes (aspect-[..], lg:grid-cols-[..]) that
   only appear in content injected after load, so we own these as real CSS. */
.ar-16x10 { aspect-ratio: 16 / 10; }
.ar-4x3 { aspect-ratio: 4 / 3; }
.rel-grid { display: grid; grid-template-columns: repeat(1, minmax(0,1fr)); gap: 1.5rem; }
/* align-items:start is what makes the sticky columns work: grid's default stretch would give every
   column the full row height, leaving position:sticky nothing to travel within. With natural heights,
   the SHORTER column (gallery vs buy box; spec rail vs the info copy) pins to the viewport top until
   its section scrolls past. */
.pdp-hero, .pdp-body { display: grid; align-items: start; }
.pdp-hero { grid-template-columns: 1fr; gap: 2.5rem; }
.pdp-body { grid-template-columns: 1fr; column-gap: 3.5rem; row-gap: 4rem; }
@media (min-width: 640px) { .rel-grid { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (min-width: 1024px) {
  .rel-grid { grid-template-columns: repeat(4, minmax(0,1fr)); }
  .pdp-hero { grid-template-columns: 1.05fr .95fr; gap: 3.5rem; }
  /* 420px: the rail carries BOTH the At-a-glance and Additional-details tables now — narrower
     widths made their label/value pairs wrap uncomfortably. */
  .pdp-body { grid-template-columns: 1fr 420px; }
}
.sk::after { content: ""; position: absolute; inset: 0; transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.7), transparent); animation: sk-shimmer 1.4s ease-in-out infinite; }
@keyframes sk-shimmer { 100% { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) { .sk::after { animation: none; } }

/* ── Mobile hardening ─────────────────────────────────────────────────────────
   overflow-x: clip (NOT hidden) — kills any residual horizontal scroll without
   creating a scroll container, so position:sticky keeps working. */
html, body { overflow-x: clip; }

@media (max-width: 640px) {
  /* iOS Safari zooms the page on focusing any input under 16px — the single most
     disorienting thing on the checkout. Promote every field to 16px on phones. */
  input, select, textarea { font-size: 16px !important; }

  /* The two-column layouts breathe a bit less on phones. */
  .pdp-hero { gap: 1.75rem; }
  .pdp-body { row-gap: 2.5rem; }

  /* Comfortable minimum touch targets for the primary commerce actions. */
  .buy-button, .chip { min-height: 44px; }
}

/* in-flight htmx states (classes toggled by shop.js "loading states") —
   the grid dims under a spinner while /shop/grid re-filters; the checkout
   summary + promo box dim while /shop/checkout/live re-prices. */
#gridRegion { position: relative; }
#gridRegion.is-loading #shopGrid, #gridRegion.is-loading #shopEmpty { opacity: .4; filter: saturate(.6); pointer-events: none; transition: opacity .2s; }
#gridRegion.is-loading::after { content: ""; position: absolute; top: 56px; left: 50%; margin-left: -14px;
  width: 28px; height: 28px; border-radius: 50%; z-index: 5;
  border: 3px solid rgba(26,23,20,.14); border-top-color: rgb(var(--brand)); animation: fs-spin .7s linear infinite; }
@keyframes fs-spin { to { transform: rotate(360deg); } }
#checkoutSummaryHost.is-updating, #promoHost.is-updating { opacity: .55; pointer-events: none; transition: opacity .15s; }
@media (prefers-reduced-motion: reduce) { #gridRegion.is-loading::after { animation-duration: 1.6s; } }

/* lazy-image placeholder: a soft tint behind cover images so slow loads read
   as "arriving", not broken. The painted image fully covers it. */
.ar-4x3, .ar-16x10 { background: rgba(26,23,20,.055); }

/* ── the purchased-content reader (/shop/items/{id}) ───────────────────────
   Document typography for operator-authored delivery pages. Covers both the
   generic elements rich-text blocks produce AND the block renderer's
   .shop-content-* classes, so every block type reads like a polished doc. */
.shop-doc { color: rgb(var(--ink-soft)); font-size: 15.5px; line-height: 1.75; }
.shop-doc h2 { color: rgb(var(--ink)); font-weight: 800; letter-spacing: -.01em; font-size: 1.3rem; margin: 1.8em 0 .55em; }
.shop-doc h3 { color: rgb(var(--ink)); font-weight: 700; font-size: 1.1rem; margin: 1.6em 0 .5em; }
.shop-doc h4 { color: rgb(var(--ink)); font-weight: 650; font-size: 1rem; margin: 1.4em 0 .4em; }
.shop-doc > :first-child, .shop-doc .shop-content-text > :first-child { margin-top: 0; }
.shop-doc p { margin: 0 0 1em; }
.shop-doc a { color: rgb(var(--brand)); text-decoration: underline; text-underline-offset: 2px; }
.shop-doc a:hover { color: rgb(var(--brand-700)); }
.shop-doc ul, .shop-doc ol { margin: 0 0 1.1em; padding-left: 1.35em; }
.shop-doc ul { list-style: disc; }
.shop-doc ol { list-style: decimal; }
.shop-doc li { margin: 0 0 .35em; }
.shop-doc blockquote { border-left: 3px solid rgb(var(--line)); padding-left: 1em; color: rgb(var(--muted)); margin: 0 0 1.1em; }
.shop-doc code { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: .88em; background: rgb(var(--soft)); border: 1px solid rgb(var(--line)); border-radius: 6px; padding: .1em .35em; }
.shop-doc pre { background: rgb(var(--soft)); border: 1px solid rgb(var(--line)); border-radius: 12px; padding: 1em 1.2em; overflow-x: auto; margin: 0 0 1.2em; }
.shop-doc pre code { background: none; border: 0; padding: 0; }
.shop-doc img { max-width: 100%; border-radius: 14px; margin: .2em 0; }
.shop-doc figure.shop-content-image { margin: 1.4em 0; }
.shop-doc figure.shop-content-image figcaption { font-size: 12.5px; color: rgb(var(--muted)); margin-top: .5em; font-family: 'JetBrains Mono', ui-monospace, monospace; }
.shop-doc hr, .shop-doc .shop-content-divider { border: 0; border-top: 1px solid rgb(var(--line)); margin: 1.8em 0; }
/* file blocks read as attachment chips */
.shop-doc .shop-content-file { margin: .9em 0; }
.shop-doc .shop-content-file a {
  display: inline-flex; align-items: center; gap: .55rem;
  background: rgb(var(--soft)); border: 1px solid rgb(var(--line)); border-radius: 12px;
  padding: .65rem 1rem; color: rgb(var(--ink)); font-weight: 600; font-size: 14px; text-decoration: none;
  transition: background .15s, border-color .15s;
}
.shop-doc .shop-content-file a::before { content: "⬇"; color: rgb(var(--brand)); }
.shop-doc .shop-content-file a:hover { background: #fff; border-color: rgba(26,23,20,.25); }
.shop-doc .shop-content-file__size { color: rgb(var(--muted)); font-size: 12px; font-family: 'JetBrains Mono', ui-monospace, monospace; }
.shop-doc .shop-content-button {
  display: inline-flex; align-items: center; gap: .5rem;
  background: rgb(var(--ink)); color: #fff !important; text-decoration: none !important;
  border-radius: 9999px; padding: .7rem 1.4rem; font-weight: 700; font-size: 14px;
}
.shop-doc .shop-content-button:hover { opacity: .92; }
.shop-doc .shop-content-embed a { word-break: break-all; }
.shop-doc .shop-content-faq { background: rgb(var(--soft)); border: 1px solid rgb(var(--line)); border-radius: 14px; padding: 1rem 1.2rem; margin: 0 0 1em; }
.shop-doc .shop-content-faq h4 { margin: 0 0 .35em; }
.shop-doc .shop-content-faq p { margin: 0; }
/* contents-rail active state (toggled by the reader's hash nav) */
.shop-doc-navlink.is-active { background: rgb(var(--ink)); color: #fff; }
.shop-doc-navlink.is-active .text-muted, .shop-doc-navlink.is-active span { color: rgba(255,255,255,.65); }

/* the chrome host wrappers must not box-trap the sticky header —
   collapse them so the header sticks against the page, not the wrapper. */
#fs-head, #fs-announce { display: contents; }

/* The pill button (formerly the Gumroad overlay button) — kept for its look + hover.
   Applies to BOTH <a> and <button> now that checkout is our own Stripe flow. */
.buy-button {
  display: inline-flex !important; align-items: center !important; justify-content: center !important;
  gap: .5rem !important;
  background-image: none !important; border: 0 !important; outline: 0 !important;
  border-radius: 9999px !important;
  color: #fff !important; cursor: pointer !important;
  font-family: 'Inter', system-ui, sans-serif !important; font-weight: 600 !important;
  text-decoration: none !important; letter-spacing: normal !important;
  white-space: nowrap !important; line-height: 1.2 !important;
  padding: .8rem 1.4rem !important;
  transition: background-color .2s ease, transform .12s ease, box-shadow .2s ease !important;
}
.buy-button.bg-brand { background-color: rgb(var(--brand)) !important; }
.buy-button.bg-brand:hover { background-color: rgb(var(--brand-700)) !important; transform: translateY(-1px); box-shadow: 0 10px 24px -12px rgba(var(--brand) / .7); }
.buy-button.bg-ink { background-color: rgb(var(--ink)) !important; }
.buy-button.bg-ink:hover { background-color: rgba(var(--ink) / .9) !important; transform: translateY(-1px); }
.buy-button:active { transform: translateY(0); }
.buy-button .logo-full,
.buy-button img { display: none !important; }

/* Stripe wordmark treatment for "Purchase with Stripe" — echoes the logo's tight, confident set. */
.stripe-wordmark {
  font-weight: 800 !important; letter-spacing: -.03em;
  font-feature-settings: "ss01";
}

/* accordion */
details.acc > summary { list-style: none; cursor: pointer; }
details.acc > summary::-webkit-details-marker { display: none; }
details.acc > summary .chev { transition: transform .2s ease; }
details.acc[open] > summary .chev { transform: rotate(180deg); }
