/* Outta This World Audio — design system
   Dark OLED ground with a warm accent. Inter throughout.
   Replaces the per-page inline styles that were on every page. */

:root{
  --bg:#0F0F23;
  --card:#1B1B30;
  --muted:#27273B;
  --ink:#F8FAFC;
  --dim:#94A3B8;
  --line:#2A2A45;
  --accent:#F97316;
  --accent-ink:#FDBA74;
  --on-accent:#0F172A;
  --ring:#F97316;

  --space-1:8px; --space-2:16px; --space-3:24px;
  --space-4:32px; --space-5:48px; --space-6:64px;

  --radius:12px;
  --maxw:1120px;
  color-scheme:dark;
}

*{box-sizing:border-box}

html{-webkit-text-size-adjust:100%}

body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font:400 16px/1.6 Inter,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  font-feature-settings:"cv02","cv03","cv04","calt";
  -webkit-font-smoothing:antialiased;
}

/* A soft glow behind the top of the page so the dark ground is not flat. */
body::before{
  content:"";
  position:fixed;
  inset:-20% -20% auto -20%;
  height:70vh;
  background:radial-gradient(60% 60% at 50% 0%,rgba(249,115,22,.10),transparent 70%);
  pointer-events:none;
  z-index:0;
}

a{color:var(--accent-ink);text-underline-offset:3px}
a:hover{color:var(--accent)}

:focus-visible{outline:2px solid var(--ring);outline-offset:3px;border-radius:4px}

.wrap{max-width:var(--maxw);margin:0 auto;padding:0 var(--space-3);position:relative;z-index:1}

/* ---------- header ---------- */
header{
  border-bottom:1px solid var(--line);
  background:rgba(15,15,35,.72);
  backdrop-filter:blur(12px);
  position:sticky;top:0;z-index:20;
}
nav{display:flex;align-items:center;justify-content:space-between;gap:var(--space-3);min-height:68px;flex-wrap:wrap}
.brand{
  font-weight:700;letter-spacing:-.01em;text-decoration:none;color:var(--ink);
  display:inline-flex;align-items:center;gap:10px;font-size:16px;
}
.brand::before{
  content:"";width:10px;height:10px;border-radius:2px;
  background:var(--accent);box-shadow:0 0 12px rgba(249,115,22,.7);
}
nav ul{list-style:none;display:flex;gap:var(--space-3);margin:0;padding:0;flex-wrap:wrap}
nav ul a{
  text-decoration:none;color:var(--dim);font-size:15px;
  padding:10px 2px;display:inline-block;min-height:44px;line-height:24px;
  transition:color .18s ease;
}
nav ul a:hover{color:var(--ink)}
/* Accent sweep under the nav links on hover. */
nav ul a{position:relative}
nav ul a::after{
  content:"";position:absolute;left:0;right:100%;bottom:8px;height:2px;
  background:var(--accent);border-radius:2px;
  transition:right .28s cubic-bezier(.22,1,.36,1);
}
nav ul a:hover::after{right:0}

/* ---------- hero ---------- */
.hero{padding:var(--space-6) 0 var(--space-4)}
.hero h1{
  font-size:clamp(30px,5vw,52px);
  line-height:1.08;letter-spacing:-.025em;font-weight:700;
  margin:0 0 var(--space-2);max-width:20ch;text-wrap:balance;
}
.hero p{max-width:64ch;color:var(--dim);font-size:clamp(16px,1.6vw,19px);margin:0 0 var(--space-2)}

.facts{
  display:flex;flex-wrap:wrap;gap:var(--space-1) var(--space-3);
  margin:var(--space-3) 0 0;padding:0;list-style:none;font-size:14px;color:var(--dim);
}
.facts li{
  display:inline-flex;align-items:center;gap:9px;
  background:var(--muted);border:1px solid var(--line);
  border-radius:999px;padding:7px 14px;
}
.facts li::before{
  content:"";width:6px;height:6px;border-radius:50%;
  background:var(--accent);flex:none;
}

/* ---------- hero waveform ----------
   Injected by site.js. Idles gently, then locks onto whichever preview is
   playing via the Web Audio analyser. Decorative, so it is aria-hidden. */
.wave{
  display:block;width:100%;height:104px;margin:var(--space-4) 0 0;
  transform-origin:bottom center;
  filter:drop-shadow(0 0 22px rgba(249,115,22,.18));
  transition:filter .4s ease;
}
.wave.is-live{filter:drop-shadow(0 0 30px rgba(249,115,22,.42))}
@media (max-width:640px){.wave{height:72px}}

/* ---------- headings & prose ---------- */
h2{font-size:clamp(20px,2.4vw,26px);letter-spacing:-.015em;margin:var(--space-6) 0 var(--space-2);text-wrap:balance}
h3{letter-spacing:-.01em}
.prose{max-width:70ch}
.prose p{margin:0 0 var(--space-2);color:var(--dim)}
.prose p strong{color:var(--ink)}

/* ---------- cards ---------- */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:var(--space-3)}
.card{
  background:var(--card);
  border:1px solid var(--line);
  border-radius:var(--radius);
  overflow:hidden;display:flex;flex-direction:column;
  transition:transform .22s ease,border-color .22s ease,box-shadow .22s ease;
}
.card:hover{
  transform:translateY(-3px);
  border-color:rgba(249,115,22,.45);
  box-shadow:0 12px 32px rgba(0,0,0,.45);
}
/* 63/50, not 16/10. The covers are authored at 630x500 (1.26:1); forcing them
   into 1.6:1 with object-fit:cover cropped 26% off the height and guillotined
   the pack name straight through the middle of the lettering. */
.card img{
  width:100%;display:block;aspect-ratio:63/50;object-fit:cover;
  background:var(--muted);
  transition:transform .5s cubic-bezier(.22,1,.36,1);
}
.card:hover img{transform:scale(1.045)}
.card .body{padding:var(--space-2) 18px 18px;display:flex;flex-direction:column;gap:10px;flex:1}
.card h3{margin:0;font-size:17px}
.card p{margin:0;font-size:15px;color:var(--dim)}
/* Sound count sits above the description on the pack cards. */
.card .count{
  display:inline-block;font-size:12px;letter-spacing:.06em;text-transform:uppercase;
  font-weight:600;color:var(--accent-ink);
}
.card p strong{color:var(--ink)}
/* The two flagship cards run the full grid width and put the artwork beside
   the copy rather than above it. Stacked, a 630x500 cover either stretches to
   ~800px tall (absurd) or gets cropped through its own lettering. Side by side
   it stays at its native ratio, uncropped, and the card stops being a banner
   with a caption. */
.card.wide{grid-column:1/-1}
@media (min-width:760px){
  .card.wide{display:grid;grid-template-columns:minmax(0,380px) minmax(0,1fr);align-items:stretch}
  .card.wide img{height:100%;max-height:none;aspect-ratio:auto;object-fit:cover;border-right:1px solid var(--line)}
  .card.wide .body{padding:var(--space-3)}
}
@media (max-width:759px){
  .card.wide img{aspect-ratio:63/50;object-fit:cover}
}

/* The named anti-pattern for this product type is a poor audio player, so the
   native control gets a real surface rather than sitting loose on the card. */
.card audio,audio{
  width:100%;margin-top:auto;height:40px;
  border-radius:8px;background:var(--muted);
  outline-offset:3px;
}
audio::-webkit-media-controls-panel{background:var(--muted)}

/* ---------- buttons ---------- */
.dl,.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:10px;
  background:var(--accent);color:var(--on-accent);
  text-decoration:none;font-weight:650;font-size:17px;
  padding:15px 26px;border-radius:10px;min-height:48px;cursor:pointer;
  border:1px solid transparent;
  transition:transform .16s ease,box-shadow .16s ease,background .16s ease;
  box-shadow:0 6px 20px rgba(249,115,22,.22);
}
.dl:hover,.btn:hover{background:#FB8B3C;color:var(--on-accent);transform:translateY(-2px);box-shadow:0 10px 26px rgba(249,115,22,.32)}
.dl:active,.btn:active{transform:translateY(0)}
.dlnote{font-size:14px;color:var(--dim);margin:0}

/* Hero call to action. Two buttons: buy the library, or hear it free first.
   The second is outlined rather than filled so the paid action stays the one
   the eye lands on. */
.cta-row{display:flex;flex-wrap:wrap;gap:12px;margin:var(--space-3) 0 var(--space-2)}
.btn.ghost{background:transparent;color:var(--ink);border-color:var(--line);box-shadow:none}
.btn.ghost:hover{background:transparent;color:var(--ink);border-color:var(--accent);box-shadow:none}

/* ---------- tables (store pages) ---------- */
table{
  width:100%;border-collapse:collapse;margin:var(--space-4) 0 var(--space-3);
  font-size:15px;
}
thead th{
  text-align:left;font-size:12px;letter-spacing:.07em;text-transform:uppercase;
  font-weight:600;color:var(--dim);
  padding:0 var(--space-2) 12px 0;border-bottom:1px solid var(--line);
  white-space:nowrap;
}
tbody td{
  padding:14px var(--space-2) 14px 0;
  border-bottom:1px solid var(--line);vertical-align:baseline;
}
tbody tr:hover td{background:rgba(255,255,255,.022)}
/* First column is the product name and carries the width. */
tbody td:first-child{color:var(--ink);font-weight:500;padding-right:var(--space-4);width:46%}
/* Store columns: keep each link on one line and give the em-dash a muted look
   so an unavailable store reads as absence rather than as content. */
tbody td:not(:first-child){white-space:nowrap;color:#7D8296}
.lead{color:var(--dim);max-width:70ch;font-size:17px}
.note{color:var(--dim);font-size:14px;max-width:70ch;margin-top:var(--space-3)}
.back{color:var(--dim);text-decoration:none;font-size:15px}
.back:hover{color:var(--ink)}
@media (max-width:720px){
  table{font-size:14px}
  tbody td:first-child{width:auto;padding-right:var(--space-2)}
  thead th,tbody td{padding-right:12px}
}

/* ---------- manifest (pack pages) ---------- */
.manifest{columns:2;column-gap:var(--space-4);list-style:none;padding:0;margin:0 0 18px;font-size:15px;color:var(--dim)}
.manifest li{break-inside:avoid;padding:6px 0;border-bottom:1px solid var(--line)}
@media (max-width:560px){.manifest{columns:1}}

/* ---------- footer ---------- */
footer{
  margin-top:var(--space-6);border-top:1px solid var(--line);
  padding:var(--space-4) 0 var(--space-5);color:var(--dim);font-size:14px;
}
footer .wrap{display:flex;flex-wrap:wrap;gap:var(--space-2) var(--space-4);justify-content:space-between}

/* ---------- motion ----------
   Elements start hidden ONLY once JS has confirmed it can animate them, so a
   script failure leaves the page fully readable instead of blank. */
/* Content is NEVER hidden waiting on JavaScript.
   This used to be `.js-motion [data-reveal]{opacity:0}`, on the reasoning that
   the class is only added once Motion has loaded, so a CDN failure would leave
   the page visible. The reasoning was wrong in a way that shipped: `animate()`
   rejects ASYNCHRONOUSLY, so a failure inside it never reaches the synchronous
   catch that removes `.js-motion` - and the hero on every page sat at opacity 0
   permanently. Headline, sub-heading, both calls to action and the spec list
   were invisible to every visitor, on every page, for as long as that rule
   existed. Scroll reveals still work; they animate from an inline 0 that Motion
   sets and clears itself. If motion is wanted on the hero again, it animates
   from a VISIBLE resting state, never toward one. */

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms !important;transition-duration:.001ms !important}
  .js-motion [data-reveal]{opacity:1 !important;transform:none !important}
  .card:hover{transform:none}
}

@media (max-width:640px){
  .hero{padding:var(--space-5) 0 var(--space-3)}
  nav{min-height:auto;padding:12px 0}
  .grid{grid-template-columns:1fr}
}

/* ==================================================================
   Homepage components (2026-09-12)
   Added rather than replacing the existing system: the tokens above
   already matched what the design pass recommended, so the problem was
   never the palette. It was an invisible hero, cropped covers, and a
   landing page that asked for money before it made a sound.
   ================================================================== */

:root{
  --font-mono:"JetBrains Mono",ui-monospace,"Cascadia Mono",Consolas,monospace;
}

/* Small uppercase label above a section heading. Also used by
   /fantasy-rpg-library/, where it was markup with no rule behind it. */
.eyebrow{
  font-family:var(--font-mono);
  font-size:12px;font-weight:500;letter-spacing:.09em;text-transform:uppercase;
  color:var(--accent-ink);margin:0 0 10px;display:block;
}
.lede{font-size:clamp(17px,1.8vw,20px);color:var(--dim);max-width:62ch;margin:0 0 var(--space-3)}

/* Figures read as data, not prose: counts, formats, prices, specs. */
.mono{font-family:var(--font-mono);font-variant-numeric:tabular-nums}

/* ---------- hero ----------
   Two columns on desktop: the argument on the left, something audible on
   the right. Collapses to one column early, because the player matters
   more than the layout. */
.hero-split{
  display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);
  gap:var(--space-5);align-items:start;
}
@media (max-width:900px){.hero-split{grid-template-columns:1fr;gap:var(--space-4)}}

.hero-listen{
  background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  padding:var(--space-3);display:flex;flex-direction:column;gap:14px;
}
.hero-listen h2{margin:0;font-size:17px;letter-spacing:-.01em}
.hero-listen p{margin:0;font-size:14px;color:var(--dim)}
/* height:auto is load-bearing. The <img> carries width/height attributes for
   layout stability, and in this flex column that fixed height wins over
   aspect-ratio - the box came out 386x500 instead of 63/50, so object-fit:cover
   cropped the sides and sliced the pack name in half. */
.hero-listen img{
  width:100%;height:auto;display:block;border-radius:8px;
  aspect-ratio:63/50;object-fit:cover;
  border:1px solid var(--line);
}

/* ---------- the free tier ----------
   A banded section so the free row reads as its own offer rather than as
   more products. This is the top of the funnel and the only thing a
   sceptical developer will act on before they trust the catalogue. */
.tier{
  border:1px solid var(--line);border-radius:var(--radius);
  background:linear-gradient(180deg,rgba(249,115,22,.07),transparent 60%),var(--card);
  padding:var(--space-4);margin:var(--space-4) 0 0;
}
.tier > h2{margin-top:0}
.tier .grid{grid-template-columns:repeat(auto-fill,minmax(215px,1fr))}
.tier .card{background:var(--bg)}

/* Compact card for the free mini-packs: cover, name, count, one link. */
.card.mini .body{padding:14px 14px 16px;gap:7px}
.card.mini h3{font-size:15px}
.card.mini .count{font-size:11px}

/* Format / licence line at the foot of a pack card. */
.card .meta{
  margin-top:auto;padding-top:12px;border-top:1px solid var(--line);
  font-family:var(--font-mono);font-size:11.5px;color:var(--dim);
  display:flex;flex-wrap:wrap;gap:4px 10px;
}

/* ---------- where to buy ---------- */
.stores{display:flex;flex-wrap:wrap;gap:10px;margin:var(--space-2) 0 0;padding:0;list-style:none}
.stores a{
  display:inline-flex;align-items:center;min-height:40px;padding:8px 15px;
  border:1px solid var(--line);border-radius:999px;background:var(--muted);
  color:var(--ink);text-decoration:none;font-size:14px;
  transition:border-color .18s ease,color .18s ease;
}
.stores a:hover{border-color:var(--accent);color:var(--accent-ink)}

/* Quiet divider between major bands. */
.rule{border:0;border-top:1px solid var(--line);margin:var(--space-6) 0 0}

/* ==================================================================
   Fantasy RPG library page (2026-09-12)
   This page's markup shipped with .player, .sections, .sec, .n, .rows,
   .total and .tablewrap and no rules behind any of them, so the whole
   section breakdown rendered as raw browser defaults on the flagship
   246-sound product. Scoped here so the /buy/ table rules stay intact.
   ================================================================== */

.player{
  background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  padding:var(--space-3);display:flex;flex-direction:column;gap:12px;
  margin:var(--space-3) 0 0;
}
.player .count{
  font-family:var(--font-mono);font-size:12px;font-weight:500;
  letter-spacing:.06em;text-transform:uppercase;color:var(--accent-ink);
}

.sections{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(330px,1fr));
  gap:var(--space-3);margin-top:var(--space-3);
}
.sec{
  background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  padding:var(--space-3);display:flex;flex-direction:column;gap:10px;
}
.sec h3{margin:0;font-size:17px}
.sec .sub{margin:0;font-size:14.5px;color:var(--dim)}

/* The per-section count, set as data rather than prose. */
.n{
  font-family:var(--font-mono);font-variant-numeric:tabular-nums;
  font-size:30px;font-weight:500;line-height:1;color:var(--accent);
  display:flex;align-items:baseline;gap:8px;
}
.n span{
  font-size:11px;font-weight:500;letter-spacing:.09em;
  text-transform:uppercase;color:var(--dim);
}

/* Label on the left, count hard right, so the numbers form a column the eye
   can run down instead of hiding at the end of each sentence. */
.rows{list-style:none;margin:6px 0 0;padding:0}
.rows li{
  display:flex;justify-content:space-between;align-items:baseline;gap:14px;
  padding:9px 0;border-top:1px solid var(--line);
  font-size:14px;color:var(--dim);
}
.rows li:first-child{border-top:0}
.rows b{
  font-family:var(--font-mono);font-variant-numeric:tabular-nums;
  color:var(--ink);font-weight:500;flex:none;
}

.total{
  display:flex;flex-wrap:wrap;justify-content:space-between;align-items:baseline;
  gap:10px;margin:var(--space-3) 0 0;padding:var(--space-3);
  background:var(--muted);border:1px solid var(--line);border-radius:var(--radius);
  color:var(--dim);font-size:15px;
}
.total b{font-family:var(--font-mono);color:var(--accent);font-size:20px;font-weight:500}

/* Spec table: label column against a value column, and it scrolls inside its
   own box rather than pushing the page sideways on a phone. */
.tablewrap{overflow-x:auto;margin:var(--space-3) 0 0}
.tablewrap table{margin:0}
.tablewrap th{
  text-align:left;vertical-align:top;white-space:nowrap;width:1%;
  font-weight:500;color:var(--dim);text-transform:none;letter-spacing:normal;
  font-size:15px;padding:12px var(--space-3) 12px 0;
  border-bottom:1px solid var(--line);
}
.tablewrap td{padding:12px 0;border-bottom:1px solid var(--line)}
.tablewrap tr:last-child th,.tablewrap tr:last-child td{border-bottom:0}

/* Cover on the flagship page. It existed on disk, unreferenced, while the
   page carried no imagery at all. */
.hero-art{
  width:100%;max-width:430px;display:block;height:auto;
  aspect-ratio:63/50;object-fit:cover;
  border:1px solid var(--line);border-radius:var(--radius);
  margin:var(--space-3) 0 0;
}
