/* blackjack.global — site chrome.
   Every value comes from tokens.css. No raw hex, radius, duration or easing
   below this line. Component CSS for the game surface lives in game.css. */
@import url("/assets/css/tokens.css?v=68bdb6cf");

/* Satoshi (Fontshare) + JetBrains Mono. Both are loaded with display=swap so a
   slow font never blocks the deal. */
@import url("https://api.fontshare.com/v2/css?f[]=satoshi@400,500,700,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap");

/* Components that set an explicit display would otherwise outrank the user
   agent's [hidden] rule, which silently keeps hidden elements on screen. */
[hidden] { display: none !important; }

*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  background: var(--bg);
}

/* DE/TR/FI/PL run up to 40% longer; loosen the leading for those locales rather
   than shrinking the type. */
html[lang="de"],
html[lang="tr"],
html[lang="fi"],
html[lang="pl"] { --leading-body: var(--leading-loose); }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-body);
  letter-spacing: var(--track-normal);
  color: var(--text-1);
  background: var(--bg);
  /* faint matrix etch: the strategy grid behind the whole product */
  background-image:
    linear-gradient(var(--etch) 1px, transparent 1px),
    linear-gradient(90deg, var(--etch) 1px, transparent 1px);
  background-size: var(--space-9) var(--space-9);
}

h1, h2, h3, h4 {
  margin: 0 0 var(--space-3);
  line-height: var(--leading-tight);
  letter-spacing: var(--track-tight);
  font-weight: var(--weight-bold);
  text-wrap: balance;
  overflow-wrap: anywhere;
}
h1 { font-size: var(--text-3xl); }
h2 { font-size: var(--text-2xl); }
h3 { font-size: var(--text-xl); }
p { margin: 0 0 var(--space-4); }
a { color: var(--brand-text); }
:where(a):hover { color: var(--brand-hover); }

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}

.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip {
  position: absolute;
  left: -9999px;
}
.skip:focus {
  left: var(--space-4);
  top: var(--space-4);
  z-index: var(--z-toast);
  padding: var(--space-2) var(--space-3);
  min-height: var(--tap-min);
  display: inline-flex;
  align-items: center;
  background: var(--surface-1);
  color: var(--text-1);
  border: 1px solid var(--border-ui);
  border-radius: var(--radius-md);
}

main {
  flex: 1 0 auto;
  width: 100%;
  margin: 0 auto;
}

/* ------------------------------------------------------- container scale ---
   M17. Page width was declared in four places with four different answers, so
   the same paragraph measured 704px on one page type and 1183px on another and
   the policy pages had no cap at all. There is now one scale, the token scale in
   tokens.css, and exactly one step per page type:

     --container-sm  prose only surfaces: the error pages (base.css, below)
     --container-md  the homepage (base.css, .home, below)
     --container-lg  every content surface: rule variations, strategy charts,
                     the calculator, the comparison pages (rules.css) and the
                     policy pages (compliance/compliance.css)
     --container-xl  the game surface only (game.css), and the site footer,
                     which is the full page rule under everything

   The cap is always declared on the article that owns the page frame together
   with the gutter padding, never on a bare `main`, so the two can never stack
   and double the gutter. A new page type picks a step from this list; it does
   not invent a width.
   --------------------------------------------------------------------------- */

/* ------------------------------------------------------- reduced motion ---
   M12 and N11. The on page Reduced motion control writes data-motion="reduce"
   on <html>, and until now no rule anywhere matched it, so the control moved an
   attribute and nothing else. tokens.css collapses most duration tokens under
   the operating system preference; it misses --dur-instant and --dur-fast,
   which is why the action buttons kept a 0.09s and 0.14s transition under OS
   reduce.

   The collapsed values live once, in the --rm-* tokens below. The two triggers,
   the OS preference and the attribute, then map the animation tokens onto those
   values with the same list of declarations. Adding a duration token means
   adding one line to each of the two mappings; the values themselves stay in
   one place. CSS has no way to share one declaration block between a media
   query and a selector, so the mapping is written twice on purpose and the two
   copies must stay identical.
   --------------------------------------------------------------------------- */
:root {
  --rm-dur: 1ms;
  --rm-gap: 0ms;
  --rm-turn: 0deg;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-instant: var(--rm-dur);
    --dur-fast: var(--rm-dur);
    --dur-base: var(--rm-dur);
    --dur-slow: var(--rm-dur);
    --dur-slower: var(--rm-dur);
    --dur-deal: var(--rm-dur);
    --dur-deal-stagger: var(--rm-gap);
    --dur-flip: var(--rm-dur);
    --dur-settle: var(--rm-dur);
    --dur-chip-toss: var(--rm-dur);
    --dur-payout: var(--rm-dur);
    --dur-edge-tick: var(--rm-dur);
    --card-settle-rotate: var(--rm-turn);
  }
}

[data-motion="reduce"] {
  --dur-instant: var(--rm-dur);
  --dur-fast: var(--rm-dur);
  --dur-base: var(--rm-dur);
  --dur-slow: var(--rm-dur);
  --dur-slower: var(--rm-dur);
  --dur-deal: var(--rm-dur);
  --dur-deal-stagger: var(--rm-gap);
  --dur-flip: var(--rm-dur);
  --dur-settle: var(--rm-dur);
  --dur-chip-toss: var(--rm-dur);
  --dur-payout: var(--rm-dur);
  --dur-edge-tick: var(--rm-dur);
  --card-settle-rotate: var(--rm-turn);
}

/* A collapsed duration still leaves a keyframe animation running its course, so
   the attribute path switches those off the same way the media query in game.css
   does. */
[data-motion="reduce"] *,
[data-motion="reduce"] *::before,
[data-motion="reduce"] *::after {
  animation-duration: var(--rm-dur);
  animation-iteration-count: 1;
}

/* ---------------------------------------------------------------- brand mark */
.lockup {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}
.mark {
  width: 2rem;
  height: 2rem;
  flex: 0 0 auto;
  display: block;
  color: var(--text-2);
}
.wordmark {
  font-weight: var(--weight-black);
  letter-spacing: var(--track-tight);
  font-size: var(--text-lg);
  color: var(--text-1);
  overflow-wrap: anywhere;
}
.wordmark .tld {
  font-family: var(--font-mono);
  font-weight: var(--weight-medium);
  font-size: 0.72em;
  letter-spacing: var(--track-normal);
  color: var(--text-3);
}

/* ------------------------------------------------------------- primitives ---
   Lifted from the design-system gallery so the game surface and the content
   surface share one button, badge and field implementation. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--label-min-h);          /* min-height, never height */
  padding: var(--btn-pad-y) var(--btn-pad-x);
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  font-family: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  letter-spacing: var(--track-snug);
  line-height: var(--leading-snug);
  text-align: center;
  text-wrap: balance;
  overflow-wrap: anywhere;
  hyphens: auto;
  cursor: pointer;
  text-decoration: none;
  transition: background var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard),
              transform var(--dur-instant) var(--ease-standard);
}
.btn:active { transform: translateY(1px); }
.btn--money { background: var(--brand); color: var(--text-on-accent); border-color: var(--gold-600); }
.btn--money:hover { background: var(--brand-hover); }
.btn--primary { background: var(--surface-3); color: var(--text-1); border-color: var(--border-ui); }
.btn--primary:hover { background: var(--surface-hover); }
.btn--outline { background: transparent; color: var(--text-1); border-color: var(--border-ui); }
.btn--outline:hover { background: var(--surface-2); }
.btn--quiet { background: transparent; color: var(--text-2); border-color: transparent; font-weight: var(--weight-medium); }
.btn--quiet:hover { background: var(--surface-2); color: var(--text-1); }
/* N9. A control that explains itself uses aria-disabled and stays focusable, so
   the disabled look has to follow the ARIA state as well as the attribute. */
.btn[disabled],
.btn[aria-disabled="true"] { opacity: 0.42; cursor: not-allowed; }
.btn--block { width: 100%; }

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 1.5rem;
  padding: 2px var(--space-2);
  border-radius: var(--radius-cell);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  line-height: var(--leading-snug);
  border: 1px solid var(--border-subtle);
  background: var(--surface-2);
  color: var(--text-2);
  overflow-wrap: anywhere;
}
.badge--pos { background: var(--pos-quiet); border-color: transparent; color: var(--pos); }
.badge--neg { background: var(--neg-quiet); border-color: transparent; color: var(--neg); }
.badge--gold { background: var(--brand-quiet); border-color: var(--brand-line); color: var(--brand-text); }

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}
.field > label {
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--text-2);
  overflow-wrap: anywhere;
}
.input,
.select {
  min-height: var(--tap-min);
  padding: var(--space-2) var(--space-3);
  width: 100%;
  background: var(--surface-inset);
  color: var(--text-1);
  border: 1px solid var(--border-ui);
  border-radius: var(--radius-md);
  font: inherit;
  font-size: var(--text-sm);
}

.mono {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* -------------------------------------------------------------- error pages --- */
/* The holding page rules that used to share this block are gone with the holding
   page itself: the locale root is now a real homepage and carries `.home`. */
.error-page main {
  max-width: var(--container-sm);
  padding: var(--section-y) var(--gutter);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
}
.lede {
  font-size: var(--text-md);
  color: var(--text-2);
  max-width: var(--measure-narrow);
}
.engine {
  margin-top: var(--space-7);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

.error-links {
  list-style: none;
  padding: 0;
  margin: var(--space-5) 0 0;
  display: grid;
  gap: var(--space-2);
  justify-items: start;
}
/* M15. The recovery link is the only action on a 404, so it is a real tap
   target rather than a 21px line of text. */
.error-links a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  padding-inline: var(--space-1);
}

/* The chart-unavailable state. A variation page gets a real explanation here, not
   a dashed empty box: what is missing, why we refuse to substitute another
   game's chart, and that the table is still playable. */
.chartnote {
  display: grid;
  gap: var(--space-3);
  margin: 0;
  padding: var(--space-5);
  border: 1px solid var(--border-ui);
  border-left: 3px solid var(--brand-line, var(--border-ui));
  border-radius: var(--radius-md);
  background: var(--surface-1);
  max-width: 62ch;
}
.chartnote p {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--text-2);
  overflow-wrap: anywhere;
}
.chartnote__h {
  font-size: var(--text-base);
  font-weight: var(--weight-bold);
  color: var(--text-1);
}

/* ----------------------------------------------------------------- footer --- */
.site-footer {
  flex: 0 0 auto;
  width: 100%;
  max-width: var(--container-xl);
  margin: 0 auto;
  padding: var(--space-6) var(--gutter) var(--space-9);
  border-top: 1px solid var(--border-subtle);
  font-size: var(--text-sm);
  color: var(--text-3);
}
.site-footer .rg { margin: 0 0 var(--space-3); max-width: var(--measure-prose); }
.site-footer .rg strong { color: var(--text-2); }
.footer-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  margin: var(--space-3) 0;
}
.footer-nav a {
  min-height: var(--tap-min);
  min-width: var(--nav-item-min-w);
  display: inline-flex;
  align-items: center;
  color: var(--text-2);
  text-decoration: none;
  overflow-wrap: anywhere;
}
.footer-nav a:hover { color: var(--text-1); text-decoration: underline; }
.legal { margin: var(--space-3) 0 0; font-size: var(--text-xs); }

/* ----------------------------------------------------------------- header --- */
/* N8. Every page needs a way out that is not the page foot. The game surface had
   none: a keyboard player had to tab past the whole felt to reach the footer nav.
   Same tap floor and same wrapping rules as .footer-nav, because it is the same
   kind of object at the other end of the page. */
.site-header {
  flex: 0 0 auto;
  width: 100%;
  max-width: var(--container-xl);
  margin: 0 auto;
  padding: var(--space-4) var(--gutter) 0;
  font-size: var(--text-sm);
}
.site-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--border-subtle);
}
.site-nav a {
  min-height: var(--tap-min);
  min-width: var(--nav-item-min-w);
  display: inline-flex;
  align-items: center;
  color: var(--text-2);
  text-decoration: none;
  overflow-wrap: anywhere;
}
.site-nav a:hover { color: var(--text-1); text-decoration: underline; }

/* ------------------------------------------------------ modification stamp --- */
/* The visible date every content page carries under its H1. The date inside the
   <time> element is the machine-readable one and the two are the same string, so a
   translated locale cannot drift from the schema. */
.last-updated {
  margin: calc(var(--space-2) * -1) 0 var(--space-4);
  font-size: var(--text-sm);
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

/* -------------------------------------------------- prose page containers --- */
/* Blocker B12. A prose page carries <article class="policy"> or
   <article class="home">, and `main` has no padding of its own, so without a
   rule on the article itself the text sits against the viewport edge at every
   width. The gutter is the shared --gutter token, so a prose page indents by
   exactly the amount every other page does.

   The rule lives in base.css rather than in a bundle, because base.css is the one
   stylesheet every page loads: a new prose page cannot be born without a gutter.

   No max-width is declared for .policy here on purpose. compliance.css caps
   article.policy at --container-lg and wins on specificity, and one class with
   two competing caps in two files is how the four different page widths that
   M17 removed grew in the first place. This rule is the floor, not the cap. */
.policy,
.home {
  width: 100%;
  margin: 0 auto;
  padding: var(--section-y) var(--gutter) var(--space-9);
}
.home {
  max-width: var(--container-md);
}
.policy > p,
.policy li,
.home > p {
  max-width: var(--measure-prose);
}

/* ------------------------------------------------------------ home hub list -- */
.home-hubs {
  list-style: none;
  margin: var(--space-4) 0 0;
  padding: 0;
  display: grid;
  gap: var(--space-2);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
}
.home-hubs a {
  display: flex;
  align-items: center;
  min-height: var(--tap-min);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border-ui);
  border-radius: var(--radius-cell);
  color: var(--text-1);
  text-decoration: none;
  overflow-wrap: anywhere;
}
.home-hubs a:hover { border-color: var(--brand-line); text-decoration: underline; }
