/* Musketeers — one stylesheet, no build, no JavaScript.
 *
 * Dark mode is prefers-color-scheme rather than a class a script toggles,
 * which is what lets this site run with script-src 'none'. The Nuxt version
 * needed @nuxtjs/color-mode for the same effect and paid for it by needing
 * script everywhere it was served. */

:root {
  --white: #ffffff;
  --cool-grey: #f4f4f5;
  --border: #e4e4e7;
  --mid-grey: #71717a;
  --charcoal: #0b0b0c;
  --cornflower: #748cc0;
  --navy: #071d4b;
  --light-blue: #bacae8;

  --bg: var(--white);
  --fg: var(--charcoal);
  --muted: var(--mid-grey);
  --rule: var(--border);
  --tag-bg: rgba(186, 202, 232, 0.4);
  --tag-fg: var(--navy);
}

/* Dark, three times over, because the viewer has three states and not two.
 *
 * No stamp on <html> is the DEFAULT — nobody has chosen, so the system
 * decides. The :not([data-theme="light"]) guard is what makes an explicit
 * light choice beat a dark OS; without it the media query wins and the toggle
 * only appears to work in one direction. The third block is the explicit dark
 * choice on a light system. Every token is defined in :root above, so a
 * colour is never only defined inside one of these. */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #1a1a1c;
    --fg: var(--white);
    --muted: #a1a1aa;
    --rule: #2e2e32;
    --tag-bg: var(--navy);
    --tag-fg: var(--light-blue);
  }
}

:root[data-theme="dark"] {
  --bg: #1a1a1c;
  --fg: var(--white);
  --muted: #a1a1aa;
  --rule: #2e2e32;
  --tag-bg: var(--navy);
  --tag-fg: var(--light-blue);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: Inter, system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

.container {
  max-width: 64rem;
  margin: 0 auto;
  padding: 0 1.5rem;
}

/* ── header ─────────────────────────────────────────────────────────────── */

header .container {
  display: flex;
  height: 5rem;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
}

.logo { display: inline-flex; align-items: center; transition: opacity .15s; }
.logo:hover { opacity: .7; }
.logo img { height: 1.75rem; width: auto; display: block; }

nav { display: flex; align-items: center; gap: 1.5rem; }
nav a {
  font-size: .875rem;
  color: var(--muted);
  text-decoration: none;
  transition: color .15s;
}
nav a:hover, nav a[aria-current="page"] { color: var(--fg); }

/* The toggle ships hidden and JavaScript reveals it. Where script does not
 * run — /t/musketeers/ serves these same bytes under script-src 'none' — a
 * button that cannot do anything is worse than no button, and the site still
 * follows the system there. */
.theme {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: 9999px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  transition: color .15s, border-color .15s;
}
.theme:hover { color: var(--fg); border-color: var(--muted); }
.theme svg { width: 1rem; height: 1rem; display: block; }

/* ── the page ───────────────────────────────────────────────────────────── */

main { padding: 5rem 0 8rem; }
@media (min-width: 768px) { main { padding: 8rem 0 12rem; } }

h1 {
  font-size: clamp(2rem, 5vw, 3rem);
  line-height: 1.1;
  letter-spacing: -0.03em;
  font-weight: 600;
  margin: 0;
  max-width: 36rem;
  text-wrap: balance;
}

h2 { font-size: 1.125rem; font-weight: 600; margin: 0; letter-spacing: -0.01em; }

p { max-width: 28rem; }
.lede { margin-top: 2.5rem; color: var(--muted); }
.after { margin-top: 4rem; color: var(--muted); }

a.quiet {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--rule);
  padding-bottom: 1px;
  transition: border-color .15s;
}
a.quiet:hover { border-color: currentColor; }

:focus-visible { outline: 2px solid var(--cornflower); outline-offset: 3px; }

/* ── lists ──────────────────────────────────────────────────────────────── */

.rows { list-style: none; margin: 3rem 0 0; padding: 0; }
.rows li {
  padding: 1rem 0;
  font-size: 1.125rem;
  border-top: 1px solid var(--rule);
}
.rows li:last-child { border-bottom: 1px solid var(--rule); }

.products { list-style: none; margin: 4rem 0 0; padding: 0; display: grid; gap: 3rem; }
.products li { display: flex; align-items: flex-start; gap: 1.25rem; }
.products img {
  height: 3.5rem;
  width: 3.5rem;
  flex: none;
  border-radius: 1rem;
  object-fit: cover;
}
.product-head { display: flex; flex-wrap: wrap; align-items: center; gap: .75rem; }
.tag {
  display: inline-flex;
  align-items: center;
  border-radius: 9999px;
  background: var(--tag-bg);
  color: var(--tag-fg);
  padding: .125rem .625rem;
  font-size: .75rem;
  font-weight: 500;
}
.products p { margin: .5rem 0 0; color: var(--muted); }

/* ── footer ─────────────────────────────────────────────────────────────── */

footer { border-top: 1px solid var(--rule); }
footer .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-top: 2.5rem;
  padding-bottom: 2.5rem;
  font-size: .875rem;
  color: var(--muted);
}
footer a { color: inherit; text-decoration: none; }
footer a:hover { color: var(--fg); }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }

/* ── the legal pages ───────────────────────────────────────────────────────
 *
 * Terms, privacy and refunds are one shape, so they are one block here rather
 * than three <style> elements that drift. They are long documents on a narrow
 * measure: 38rem is about 75 characters at this size, which is where prose
 * stops being tiring to read.
 *
 * Every heading carries an id and the document opens with a linked contents,
 * because the thing anyone actually does with a refund policy is look for the
 * one clause that applies to them — and because Paddle's reviewer wants to
 * land on a named section from a link. */


.legal h1 { font-size: 2rem; letter-spacing: -.03em; margin: 0 0 .75rem; }
.legal .stamp { font-size: .875rem; color: var(--muted); margin: 0 0 2rem; }
.legal h2 {
  font-size: 1.125rem;
  margin: 2.75rem 0 .75rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule);
  scroll-margin-top: 1.5rem;
}
.legal h3 { font-size: 1rem; margin: 1.75rem 0 .5rem; }
.legal p, .legal li { line-height: 1.65; }
.legal ul, .legal ol { padding-left: 1.25rem; }
.legal li { margin: .5rem 0; }
.legal .lead { font-size: 1.0625rem; color: var(--muted); }

/* The contents. A plain list of links, set quietly so it reads as apparatus
 * rather than as the first section of the document. */
.toc { margin: 0 0 1rem; padding: 1.25rem 0; border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }
.toc ol { margin: 0; padding-left: 1.25rem; columns: 2; column-gap: 2rem; }
.toc li { margin: .25rem 0; font-size: .9375rem; }
@media (max-width: 34rem) { .toc ol { columns: 1; } }

/* A pulled-out paragraph for the thing a reader most needs to see — the
 * refund window, who the merchant of record is. Tinted, not boxed in a
 * border, so it stays quiet in both themes. */
.note {
  background: var(--tag-bg);
  color: var(--fg);
  padding: 1rem 1.125rem;
  border-radius: .5rem;
  margin: 1.5rem 0;
  font-size: .9375rem;
  line-height: 1.6;
}
.note p { margin: 0; }
.note p + p { margin-top: .75rem; }

/* The catalogue on /products: what each product sells and on what terms.
 * A definition-style row rather than a card, because the page's job is to
 * let somebody find the product their statement was for. */
.catalogue { list-style: none; margin: 2.5rem 0 0; padding: 0; display: grid; gap: 2.5rem; }
.catalogue > li { padding-top: 2rem; border-top: 1px solid var(--rule); }
.catalogue h2 { font-size: 1.25rem; margin: 0 0 .5rem; }
.catalogue p { margin: 0 0 1rem; color: var(--muted); }
.catalogue dl { margin: 0; display: grid; grid-template-columns: 8.5rem 1fr; gap: .5rem 1rem; font-size: .9375rem; }
.catalogue dt { color: var(--muted); }
.catalogue dd { margin: 0; }
@media (max-width: 30rem) {
  .catalogue dl { grid-template-columns: 1fr; gap: .125rem; }
  .catalogue dd { margin-bottom: .75rem; }
}

/* The legal links in the footer, on every page including checkout — Paddle
 * expects them reachable from where the money is taken, not only from home. */
footer nav { display: flex; flex-wrap: wrap; gap: 1rem; }

/* ── the public pay surface ────────────────────────────────────────────────
 *
 * WHO ACTUALLY ARRIVES HERE. Mostly one person: somebody looking at a bank
 * statement with a line on it they do not recognise, who searched the word.
 * Behind them, a payments reviewer checking the seller is real. Both want the
 * same three things and want them immediately — this is legitimate, this is
 * what it was for, here is a human — so the page answers in that order and
 * sells nothing.
 *
 * WHICH MAKES RESTRAINT THE DESIGN RATHER THAN THE ABSENCE OF IT. A billing
 * page that looks marketed reads as a scam. This one is set like a bank's own
 * correspondence: quiet, exact, monospaced where money is involved, and
 * nothing on it moves.
 *
 * THE REPEATED OBJECT IS A LEDGER ROW — label left, value right, figures
 * tabular. The statement excerpt is one, each product is one, each document
 * is one. It is the shape the subject already comes in.
 *
 * Tokens are musketeers.io's, unchanged: this host is the site's sibling and
 * a second identity on the same brand would be its own kind of alarm. The one
 * addition is a muted green, kept away from the navy accent, for the three
 * facts about where card data goes. /hq's classes are untouched. */

:root { --safe: #3f6b4d; --safe-tint: rgba(63, 107, 77, .09); --link: #2f5597; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --safe: #82b795; --safe-tint: rgba(130, 183, 149, .12); --link: #9db4dd; }
}
:root[data-theme="dark"] { --safe: #82b795; --safe-tint: rgba(130, 183, 149, .12); --link: #9db4dd; }

a { color: var(--link); text-underline-offset: .17em; text-decoration-thickness: 1px; }
a:hover { text-decoration-thickness: 2px; }
/* The three that deliberately take the surrounding colour instead. */
a.quiet, footer a, .ledger .k a, .logo { color: inherit; }

/* Less air above the fold than the marketing site takes. The visitor came
   here mid-worry with a charge to identify; a tall opening is a page making
   them scroll before it answers. */
/* ONE COLUMN ACROSS THE PUBLIC HOST. The masthead sat in a 64rem container
   while every page's content sat in a narrower one centred inside it, so the
   logo and the headline below it did not share a left edge — on this page, on
   the checkout, and on all three legal documents. Nobody can name what is
   wrong with that, and everybody can see it. /hq keeps the wide container:
   it is a table, and a table wants the room. */
.pay-page .container { max-width: 40rem; }
.pay-page header .container,
.pay-page footer .container { max-width: 40rem; }

main.tight { padding: 3.5rem 0 6rem; }
@media (min-width: 768px) { main.tight { padding: 4.5rem 0 8rem; } }

.hub h1, .hub .lead { max-width: 24ch; }
.hub .lead { max-width: 34rem; }
.hub h1 { font-size: clamp(1.875rem, 1.4rem + 2vw, 2.5rem); letter-spacing: -.032em; margin: 0 0 .875rem; max-width: 22ch; }
.hub .lead { font-size: 1.0625rem; color: var(--muted); line-height: 1.6; margin: 0; max-width: 34rem; }

.mono, .amt, .desc-row b, .ledger .v {
  font-family: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-variant-numeric: tabular-nums;
}

/* The statement excerpt. What the visitor is holding, set the way their bank
   sets it, so the match is made for them instead of described to them. */
.statement {
  margin: 2.5rem 0 0;
  border: 1px solid var(--rule);
  border-radius: .5rem;
  overflow: hidden;
  background: var(--bg);
}
.statement-head {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: .6875rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
  padding: .75rem 1.125rem;
  border-bottom: 1px solid var(--rule);
  background: var(--rule);
}
.desc-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: .5rem 1rem;
  align-items: baseline;
  padding: .875rem 1.125rem;
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: .9375rem;
}
.desc-row + .desc-row { border-top: 1px dashed var(--rule); }
.desc-row b { font-weight: 500; overflow-wrap: anywhere; }
.desc-row .amt { color: var(--muted); white-space: nowrap; }
.statement figcaption {
  padding: .75rem 1.125rem;
  border-top: 1px solid var(--rule);
  font-size: .8125rem;
  color: var(--muted);
}

/* A ledger row: what it is on the left, what it is for on the right. Used for
   the products and for the documents, because they are the same shape. */
.ledger { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--rule); }
.ledger li {
  display: grid;
  grid-template-columns: minmax(9rem, 14rem) 1fr;
  gap: .25rem 1.5rem;
  align-items: baseline;
  padding: 1rem 0;
  border-bottom: 1px solid var(--rule);
}
.ledger .k { font-weight: 500; }
.ledger .k a { color: inherit; text-decoration-color: var(--muted); text-underline-offset: .2em; }
.ledger .k a:hover { text-decoration-color: currentColor; text-decoration-thickness: 2px; }
.ledger .v { font-size: .9375rem; color: var(--muted); font-family: inherit; }
@media (max-width: 34rem) { .ledger li { grid-template-columns: 1fr; } }

/* The three facts about card data. Ticks, not cards — this is reassurance in
   passing, not a feature grid, and boxing it would oversell it. */
.facts { list-style: none; margin: 0; padding: 0; display: grid; gap: .875rem; }
.facts li { display: grid; grid-template-columns: 1.1rem 1fr; gap: .75rem; align-items: start; font-size: .9375rem; line-height: 1.6; }
.facts svg { width: 1.1rem; height: 1.1rem; margin-top: .22rem; color: var(--safe); flex: none; }
.facts b { font-weight: 500; color: var(--fg); }
.facts span { color: var(--muted); }

.section { margin-top: 4rem; }
.section > h2 {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: .6875rem; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 1.25rem;
}

/* The one thing on the page anybody needs to do. A rule above it and room
   around it, rather than a button that would look like a purchase. */
.reach {
  margin-top: 4rem;
  padding-top: 2rem;
  border-top: 2px solid var(--fg);
}
.reach p { max-width: 34rem; color: var(--muted); font-size: .9375rem; }
.reach .addr {
  font-size: 1.125rem;
  font-weight: 500;
  display: inline-block;
  margin-bottom: .5rem;
}

/* ── the checkout ─────────────────────────────────────────────────────────
 * A waiting room, open for about two seconds while Paddle's own frame loads
 * over it. Its whole job is to look like nothing has gone wrong. */


.checkout h1 { font-size: 1.5rem; letter-spacing: -.02em; margin: 0 0 .5rem; }
.state {
  margin: 0 0 2rem;
  color: var(--muted);
  font-size: .9375rem;
  min-height: 1.5rem;
}
.state b { color: var(--fg); font-weight: 500; }
.checkout .statement { margin-top: 0; }
.checkout .facts { margin-top: 2rem; }

/* ── the shop ──────────────────────────────────────────────────────────────
 *
 * A PRICE LIST, NOT A CART. The hub cannot sell to a stranger and should not
 * pretend to: the handoff into /pay/start is HMAC-signed with HUB_SECRET, and
 * what a purchase grants attaches to a WORKSPACE — so the buyer has to be
 * somebody the product already knows. That is a security property, not a gap
 * to paper over with a basket. The shop therefore does what a good shop
 * window does: shows what there is, what it costs, and which door to go in.
 *
 * It reuses the ledger row from /charge deliberately. The same object says
 * "what it was for" on the explainer and "what it costs" here, which is the
 * whole of this host in one shape. */

.shop-item { border-top: 1px solid var(--rule); padding: 1.75rem 0; }
.shop-item:last-of-type { border-bottom: 1px solid var(--rule); }
.shop-head {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: .5rem 1rem;
}
.shop-head h3 { font-size: 1.125rem; font-weight: 600; letter-spacing: -.012em; margin: 0; }
.shop-item > p { color: var(--muted); font-size: .9375rem; margin: .5rem 0 1rem; max-width: 32rem; }

/* Prices arrive from /catalog after paint. Until they do — and where script
   does not run at all, which is this same build served at /t/musketeers-pay/
   under script-src 'none' — the row says where the price is instead of
   showing a stale one. Nothing here is ever a hardcoded amount. */
.prices { list-style: none; margin: 0; padding: 0; display: grid; gap: .4rem; }
.prices li {
  display: grid; grid-template-columns: 1fr auto; gap: 1rem;
  align-items: baseline;
  font-size: .9375rem;
  padding: .35rem 0;
}
.prices .what { color: var(--muted); }
.prices .amt { font-weight: 500; white-space: nowrap; }
.prices .per { color: var(--muted); font-weight: 400; }

.shop-note { font-size: .875rem; color: var(--muted); margin: .75rem 0 0; }

.go {
  display: inline-flex; align-items: center; gap: .4rem;
  margin-top: 1.25rem;
  font-size: .9375rem; font-weight: 500;
  color: var(--fg);
  text-decoration: none;
  border-bottom: 2px solid var(--fg);
  padding-bottom: .1rem;
}
.go:hover { color: var(--link); border-color: var(--link); }
.go .soon { font-weight: 400; color: var(--muted); }

/* The one line on the shop for the other visitor entirely. Quiet, above the
   footer, and unmissable if that is what you came for. */
.worried {
  margin-top: 3.5rem;
  padding: 1rem 1.15rem;
  background: var(--rule);
  border-radius: .35rem;
  font-size: .9375rem;
}
.worried a { font-weight: 500; }
