/* ==========================================================================
   egg with wings — site stylesheet

   Load order in <head>:  fonts.css  ->  tokens.css  ->  site.css
   Every value comes from tokens.css. No !important anywhere. No framework.

   CONTENTS
     01  Reset / normalize
     02  Base elements
     03  Utilities
     04  Layout primitives  .wrap .section .grid .cluster .flow
     05  Focus & skip link
     06  Buttons
     07  Brand mark / wordmark
     08  Header, nav, language switch
     09  Hero
     10  Section head / eyebrow
     11  Game cards
     12  Pills & badges
     13  Feature list, contact cards, info rows
     14  Notice / callout
     15  Prose (legal & long-form) + TOC + last-updated
     16  Footer
     17  Reveal-on-scroll + motion preferences
     18  Print
   ========================================================================== */


/* ==========================================================================
   01  RESET / NORMALIZE
   ========================================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Anchors must not land underneath the sticky header. */
  scroll-padding-top: calc(var(--header-h) + var(--space-md));
}

body,
h1, h2, h3, h4, h5, h6,
p, figure, blockquote, dl, dd, ol, ul, pre {
  margin: 0;
}

ul[class], ol[class] {
  padding: 0;
  list-style: none;
}

img, svg, video, canvas, picture {
  display: block;
  max-width: 100%;
}

img, video { height: auto; }

input, button, textarea, select {
  font: inherit;
  color: inherit;
}

button {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

table {
  border-collapse: collapse;
  border-spacing: 0;
}

hr {
  border: 0;
  border-top: var(--border-w) solid var(--border);
  margin: var(--space-xl) 0;
}

[hidden] { display: none; }

:target { scroll-margin-top: calc(var(--header-h) + var(--space-md)); }


/* ==========================================================================
   02  BASE ELEMENTS
   ========================================================================== */

body {
  min-height: 100svh;
  background-color: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  letter-spacing: var(--ls-normal);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-feature-settings: 'kern' 1;
  /* Belt and braces against horizontal overflow at 320px. */
  overflow-x: hidden;
}

/* Korean: never break inside a word; Hangul lines want more air. */
:lang(ko) {
  word-break: keep-all;
  overflow-wrap: break-word;
  line-break: strict;
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  font-weight: var(--fw-display);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-tight);
  color: var(--text);
  text-wrap: balance;
  overflow-wrap: break-word;
}

h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); }
h4 { font-size: var(--fs-h4); }
h5, h6 {
  font-family: var(--font-body);
  font-size: var(--fs-sm);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-normal);
}

p { text-wrap: pretty; overflow-wrap: break-word; }

a {
  color: var(--link);
  text-decoration: underline;
  text-decoration-thickness: 0.06em;
  text-underline-offset: 0.18em;
  text-decoration-color: color-mix(in srgb, var(--link) 40%, transparent);
  transition: color var(--dur-fast) var(--ease-out),
              text-decoration-color var(--dur-fast) var(--ease-out);
}

a:hover {
  color: var(--link-hover);
  text-decoration-color: currentColor;
}

strong, b { font-weight: var(--fw-bold); }

small { font-size: var(--fs-sm); }

code, kbd, samp, pre {
  font-family: var(--font-mono);
  font-size: 0.9em;
}

code {
  background-color: var(--wash-ink);
  border-radius: var(--radius-xs);
  padding: 0.12em 0.38em;
  overflow-wrap: break-word;
}

::selection {
  background-color: var(--wash-yolk-2);
  color: var(--ink);
}


/* ==========================================================================
   03  UTILITIES
   ========================================================================== */

.visually-hidden:not(:focus):not(:active) {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.text-muted   { color: var(--text-muted); }
.text-center  { text-align: center; }
.measure      { max-width: var(--measure); }
.measure-short{ max-width: var(--measure-short); }
.center-x     { margin-inline: auto; }

.lead {
  font-size: var(--fs-lead);
  line-height: var(--lh-snug);
  color: var(--text-muted);
}

.no-wrap { white-space: nowrap; }


/* ==========================================================================
   04  LAYOUT PRIMITIVES
   ========================================================================== */

/* .wrap — the horizontal frame. Every full-bleed band puts a .wrap inside. */
.wrap {
  width: 100%;
  max-width: var(--w-page);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.wrap--wide   { max-width: var(--w-wide); }
.wrap--narrow { max-width: var(--w-narrow); }
.wrap--prose  { max-width: calc(var(--w-prose) + var(--gutter) * 2); }

/* .section — a full-bleed horizontal band. Alternate paper / shell. */
.section {
  padding-block: var(--section-y);
  background-color: var(--bg);
}

.section--shell { background-color: var(--bg-alt); }
.section--paper { background-color: var(--bg); }
.section--tight { padding-block: var(--section-y-sm); }
.section--flush-top    { padding-block-start: 0; }
.section--flush-bottom { padding-block-end: 0; }

/* A hairline between two same-coloured bands. */
.section--ruled { border-top: var(--border-w) solid var(--border); }

/* .flow — vertical rhythm for sibling blocks. Override with --flow-gap. */
.flow > * + * { margin-block-start: var(--flow-gap, var(--stack)); }
.flow--sm { --flow-gap: var(--space-sm); }
.flow--lg { --flow-gap: var(--space-lg); }
.flow--xl { --flow-gap: var(--space-xl); }

/* .cluster — inline group that wraps rather than overflowing. */
.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--cluster-gap, var(--space-sm));
}

.cluster--center { justify-content: center; }
.cluster--between { justify-content: space-between; }
.cluster--tight { --cluster-gap: var(--space-2xs); }

/* .grid — auto-responsive card grid: 1 col / 2 / 3.
   min-width: 0 on children is what actually prevents overflow when a card
   contains a long unbreakable string. */
.grid {
  display: grid;
  gap: var(--space-md);
  grid-template-columns: 1fr;
}

.grid > * { min-width: 0; }

@media (min-width: 40em) {           /* 640px  — tablet: 2 columns */
  .grid { gap: var(--space-lg); grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 62em) {           /* 992px  — desktop: 3 columns */
  .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.grid--2  { grid-template-columns: 1fr; }
@media (min-width: 40em) { .grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 62em) { .grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* Single-item grids should not stretch a lone card to full width on desktop —
   the site legitimately has one game. Cap the track so it reads as a card,
   not a banner. */
.grid--cap > * { max-width: 32rem; }
.grid--cap { justify-content: center; }

/* --- .split — heading rail + content column ------------------------------
   For interior bands whose whole content is one narrow text column. Left
   alone inside a .wrap--wide those bands occupy the left ~45% of a 1440px
   viewport and leave the rest blank, which reads as unfinished rather than
   airy. .split moves the section head into a left rail so the band becomes a
   two-column spread that fills the frame.

   Exactly two children: the .section-head first, the content second. Below
   64em it collapses to the single stacked column it always was, so nothing
   about the phone layout changes. */
.split { display: grid; gap: var(--space-md); }

/* Stacked, the second child is the whole band's body copy and would otherwise
   run the full width of a .wrap--wide. Keep the reading measure. */
.split > * + * { max-width: var(--measure); }

@media (min-width: 64em) {
  .split {
    /* Both tracks are capped rather than 1fr: at 1fr the body column would run
       past 100 characters on a wide screen, trading one legibility problem for
       another. 45rem is ~85 characters at --fs-body. */
    grid-template-columns: minmax(0, 22rem) minmax(0, 45rem);
    column-gap: var(--space-2xl);
    row-gap: var(--space-xl);
    align-items: start;
  }

  /* Each track already sets the width; the children's own measure caps would
     fight it and reintroduce the ragged right edge. */
  .split > * + * { max-width: none; }
  .split > .section-head { max-width: none; margin-block-end: 0; }
}


/* ==========================================================================
   05  FOCUS & SKIP LINK
   ========================================================================== */

/* One rule, everywhere. 3px solid --ink is 18.52:1 on paper and 10.12:1 on a
   yolk button, so it stays visible on every surface the site uses. The white
   halo keeps it legible where the ring sits directly on a dark fill. */
:focus-visible {
  outline: var(--focus-w) solid var(--focus-ring);
  outline-offset: var(--focus-offset);
}

/* Do NOT set border-radius here. Browsers already trace the element's own
   corner radius when drawing an outline, and setting one would square off
   pills and cards the moment they take focus. */

/* Suppress the UA ring for mouse users only — keyboard users keep it. */
:focus:not(:focus-visible) { outline: none; }

.skip-link {
  position: absolute;
  top: var(--space-2xs);
  left: var(--space-2xs);
  z-index: var(--z-skip);
  display: inline-block;
  padding: var(--space-xs) var(--space-md);
  background-color: var(--ink);
  color: var(--paper);
  font-family: var(--font-body);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  text-decoration: none;
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-lg);
  transform: translateY(-160%);
  transition: transform var(--dur-fast) var(--ease-out);
}

/* The ring must NOT be re-coloured here. `outline-offset` puts it 3px OUTSIDE
   the ink pill, so it is drawn on the white page on both sides — never on the
   dark fill. --yolk there measures 1.83:1 against #FFFFFF and fails WCAG
   1.4.11 (3:1). The inherited --focus-ring (--ink) is 18.52:1 on white. */
.skip-link:focus-visible {
  transform: translateY(0);
  color: var(--paper);
}


/* ==========================================================================
   06  BUTTONS
   ========================================================================== */

.btn {
  --btn-py: 0.8125rem;
  --btn-px: 1.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2xs);
  padding: var(--btn-py) var(--btn-px);
  min-height: 2.875rem;              /* 46px — comfortable tap target */
  font-family: var(--font-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: 1.2;
  letter-spacing: var(--ls-normal);
  text-align: center;
  text-decoration: none;
  border: var(--border-w-thick) solid transparent;
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-base) var(--ease-out),
              transform var(--dur-base) var(--ease-spring);
}

.btn--lg { --btn-py: 1rem; --btn-px: 2rem; font-size: var(--fs-lead); min-height: 3.375rem; }
.btn--sm { --btn-py: 0.5rem; --btn-px: 1rem; font-size: var(--fs-sm); min-height: 2.25rem; }
.btn--block { display: flex; width: 100%; }

/* Primary — yolk fill, INK text. White on yolk is 2.4:1 and is never used. */
.btn--primary {
  background-color: var(--accent);
  border-color: var(--accent);
  color: var(--text-on-accent);
  font-weight: var(--fw-bold);
  box-shadow: var(--shadow-sm);
}

.btn--primary:hover {
  background-color: var(--accent-hover);
  border-color: var(--accent-hover);
  color: var(--text-on-accent);
  box-shadow: var(--shadow-yolk);
  transform: translateY(-2px);
}

.btn--primary:active {
  transform: translateY(0);
  box-shadow: var(--shadow-xs);
}

/* Secondary — outlined on paper. */
.btn--secondary {
  background-color: var(--surface);
  border-color: var(--ink);
  color: var(--text);
}

.btn--secondary:hover {
  background-color: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

.btn--secondary:active { transform: translateY(0); }

/* Ghost — no chrome until hover. */
.btn--ghost {
  background-color: transparent;
  border-color: transparent;
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--ink) 28%, transparent);
  text-underline-offset: 0.24em;
}

.btn--ghost:hover {
  background-color: var(--wash-ink);
  color: var(--text);
  text-decoration-color: currentColor;
}

/* Trailing arrow that nudges on hover. */
.btn__arrow {
  display: inline-block;
  transition: transform var(--dur-base) var(--ease-out);
}

.btn:hover .btn__arrow { transform: translateX(3px); }

.btn[aria-disabled='true'],
.btn:disabled {
  cursor: not-allowed;
  opacity: 0.55;
  transform: none;
  box-shadow: none;
}


/* ==========================================================================
   07  BRAND MARK / WORDMARK
   ========================================================================== */

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  text-decoration: none;
  color: var(--text);
  line-height: 1;
}

.brand:hover { color: var(--text); }

/* The mark's artwork is landscape inside a square 64x64 viewBox, so a square
   box at the wordmark's cap height renders visually small. 2.375rem balances
   it against a 19px wordmark. */
.brand__mark {
  flex: none;
  width: 2.375rem;
  height: 2.375rem;
  transform-origin: 50% 60%;
  transition: transform var(--dur-slow) var(--ease-spring);
}

.brand__text {
  font-family: var(--font-display);
  font-weight: var(--fw-display);
  font-size: 1.1875rem;
  letter-spacing: -0.015em;
  text-transform: lowercase;
  white-space: nowrap;
}

/* The one signature motion moment the brief allows: a gentle wing flap. */
.brand:hover .brand__mark,
.brand:focus-visible .brand__mark {
  animation: wing-flap 900ms var(--ease-in-out);
}

@keyframes wing-flap {
  0%, 100% { transform: rotate(0deg)   translateY(0); }
  25%      { transform: rotate(-5deg)  translateY(-2px); }
  55%      { transform: rotate(4deg)   translateY(-1px); }
  80%      { transform: rotate(-2deg)  translateY(0); }
}

/* Hero-scale lockup. */
.brand--stacked {
  flex-direction: column;
  gap: var(--space-sm);
}

.brand--stacked .brand__mark {
  width: clamp(5rem, 3rem + 10vw, 8.5rem);
  height: clamp(5rem, 3rem + 10vw, 8.5rem);
}

.brand--stacked .brand__text { font-size: var(--fs-h3); }

/* --- Korean lockups ------------------------------------------------------

   The Hangul wordmark is drawn as paths inside logo-ko.svg and
   logo-stacked-ko.svg, so the Korean header, footer and hero use the whole
   lockup as one image instead of mark + live text. Two consequences:

     - the box is sized by HEIGHT with `width: auto`, so the lockup keeps its
       own aspect ratio. Never give it a width and a height at once —
       logo-lockup-guide.md §5 forbids stretching;
     - the wing-flap rotation is not used, because rotating the lockup would
       rotate the wordmark with it. The alternative motion sanctioned by
       logo-lockup-guide.md §9 — a 2px lift — is used instead.

   Sizes are set so the rendered width stays above the §4 minimums:
   logo-ko.svg 150px, and enough of logo-stacked-ko.svg for the Hangul
   counters to stay open.
   ------------------------------------------------------------------------ */

.brand__lockup {
  flex: none;
  width: auto;
  height: 2rem;             /* -> ~195px wide, above the 150px floor */
  transition: transform var(--dur-slow) var(--ease-spring);
}

.brand:hover .brand__lockup,
.brand:focus-visible .brand__lockup { transform: translateY(-2px); }

/* Hero. Sized so the whole lockup lands at roughly the same optical weight as
   the English hero's mark-plus-display-headline pair: ~170px wide at 375px,
   ~250px at 1440px. */
.hero__lockup {
  display: block;
  width: auto;
  height: clamp(8rem, 5.5rem + 12vw, 12rem);
  margin-inline: auto;
}

/* The lockup carries the wordmark, so the hero H1 is the image and needs
   none of the display type sizing. */
.hero__title--lockup {
  max-width: none;
  font-size: 0;
  line-height: 0;
}


/* ==========================================================================
   08  HEADER, NAV, LANGUAGE SWITCH
   ========================================================================== */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background-color: color-mix(in srgb, var(--paper) 88%, transparent);
  -webkit-backdrop-filter: saturate(1.6) blur(12px);
  backdrop-filter: saturate(1.6) blur(12px);
  border-bottom: var(--border-w) solid transparent;
  transition: box-shadow var(--dur-base) var(--ease-out),
              border-color var(--dur-base) var(--ease-out),
              background-color var(--dur-base) var(--ease-out);
}

/* JS adds .is-scrolled once the page has scrolled past ~8px. */
.site-header.is-scrolled {
  background-color: color-mix(in srgb, var(--paper) 94%, transparent);
  border-bottom-color: var(--border);
  box-shadow: var(--shadow-header);
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-header { background-color: var(--paper); }
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  min-height: var(--header-h);
}

.site-header__nav {
  display: flex;
  align-items: center;
  gap: var(--space-md);
}

/* --- primary nav (desktop) --------------------------------------------- */

.site-nav__list {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-nav__link {
  display: inline-block;
  padding: var(--space-2xs) var(--space-xs);
  border-radius: var(--radius-pill);
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out);
}

.site-nav__link:hover {
  color: var(--text);
  background-color: var(--wash-ink);
}

.site-nav__link[aria-current='page'] {
  color: var(--text);
  font-weight: var(--fw-bold);
  background-color: var(--wash-yolk);
}

/* --- language switch ---------------------------------------------------- */

.lang-switch {
  display: inline-flex;
  align-items: center;
  padding: 3px;
  gap: 2px;
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-pill);
  background-color: var(--surface);
}

.lang-switch__link {
  display: inline-block;
  padding: 0.3125rem 0.6875rem;
  border-radius: var(--radius-pill);
  color: var(--text-muted);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  letter-spacing: 0.02em;
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out);
}

.lang-switch__link:hover {
  color: var(--text);
  background-color: var(--wash-ink);
}

.lang-switch__link[aria-current='true'] {
  background-color: var(--ink);
  color: var(--paper);
  font-weight: var(--fw-bold);
}

.lang-switch__link[aria-current='true']:hover { color: var(--paper); }

/* --- hamburger ---------------------------------------------------------- */

.nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  flex: none;
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-md);
  background-color: var(--surface);
  color: var(--text);
  transition: background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}

.nav-toggle:hover { background-color: var(--wash-ink); border-color: var(--border-strong); }

.nav-toggle__box {
  position: relative;
  display: block;
  width: 1.125rem;
  height: 0.75rem;
}

.nav-toggle__bar {
  position: absolute;
  left: 0;
  width: 100%;
  height: 2px;
  border-radius: var(--radius-pill);
  background-color: currentColor;
  transition: transform var(--dur-base) var(--ease-out),
              opacity var(--dur-fast) var(--ease-out);
}

.nav-toggle__bar:nth-child(1) { top: 0; }
.nav-toggle__bar:nth-child(2) { top: calc(50% - 1px); }
.nav-toggle__bar:nth-child(3) { bottom: 0; }

.nav-toggle[aria-expanded='true'] .nav-toggle__bar:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.nav-toggle[aria-expanded='true'] .nav-toggle__bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded='true'] .nav-toggle__bar:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }

/* --- mobile panel ------------------------------------------------------- */

.nav-panel {
  position: fixed;
  inset: var(--header-h) 0 auto 0;
  z-index: var(--z-nav);
  max-height: calc(100svh - var(--header-h));
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-md) var(--gutter) var(--space-xl);
  background-color: var(--paper);
  border-bottom: var(--border-w) solid var(--border);
  box-shadow: var(--shadow-lg);
  /* Closed state. `visibility` is what removes it from the tab order. */
  visibility: hidden;
  opacity: 0;
  transform: translateY(-0.75rem);
  transition: opacity var(--dur-base) var(--ease-out),
              transform var(--dur-base) var(--ease-out),
              visibility 0s linear var(--dur-base);
}

.nav-panel.is-open {
  visibility: visible;
  opacity: 1;
  transform: translateY(0);
  transition: opacity var(--dur-base) var(--ease-out),
              transform var(--dur-base) var(--ease-out),
              visibility 0s;
}

.nav-panel__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.nav-panel__list li + li { border-top: var(--border-w) solid var(--border); }

.nav-panel__link {
  display: block;
  padding: var(--space-sm) var(--space-2xs);
  font-family: var(--font-display);
  font-size: var(--fs-h4);
  font-weight: var(--fw-display);
  color: var(--text);
  text-decoration: none;
  border-radius: var(--radius-sm);
}

.nav-panel__link:hover { color: var(--text); background-color: var(--wash-ink); }
.nav-panel__link[aria-current='page'] { color: var(--text); }
.nav-panel__link[aria-current='page']::after {
  content: '';
  display: inline-block;
  width: 0.4375rem;
  height: 0.4375rem;
  margin-inline-start: 0.5rem;
  vertical-align: 0.15em;
  border-radius: 50%;
  background-color: var(--yolk);
}

.nav-panel__foot {
  margin-block-start: var(--space-md);
  padding-block-start: var(--space-md);
  border-top: var(--border-w) solid var(--border);
}

/* Scrim behind the open panel. It sits BELOW the header on purpose: if it
   covers the header it swallows clicks on the close button, and the only way
   out becomes Escape or a scrim tap. */
.nav-scrim {
  position: fixed;
  inset: 0;
  z-index: var(--z-scrim);
  background-color: rgba(22, 19, 15, 0.28);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-base) var(--ease-out),
              visibility 0s linear var(--dur-base);
}

.nav-scrim.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--dur-base) var(--ease-out), visibility 0s;
}

/* Stop background scroll while the panel is open. */
body.nav-open { overflow: hidden; }

/* With the panel open the header sits above the scrim, and a backdrop-filter
   would sample the dimmed page through it and go grey. Make it opaque. */
body.nav-open .site-header {
  background-color: var(--paper);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* --- responsive switch: hamburger below 900px, full nav at and above ---- */

@media (max-width: 56.24em) {
  .site-header__nav .site-nav,
  .site-header__nav .lang-switch { display: none; }
}

@media (min-width: 56.25em) {
  .nav-toggle,
  .nav-panel,
  .nav-scrim { display: none; }
  .site-header__nav { gap: var(--space-lg); }
}


/* ==========================================================================
   09  HERO
   ========================================================================== */

.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding-block: clamp(3rem, 1.5rem + 8vw, 8rem) clamp(3.5rem, 2rem + 8vw, 8.5rem);
  background-color: var(--paper);
  text-align: center;
}

/* Soft radial yolk wash, centred on where the logo sits. Deliberately weak:
   at these alphas it reads as warm light falling on white paper. Push it and
   the band turns cream, which breaks the white-is-the-brand directive. */
.hero::before {
  content: '';
  position: absolute;
  z-index: var(--z-below);
  left: 50%;
  top: -14%;
  width: min(112vw, 54rem);
  aspect-ratio: 1;
  transform: translateX(-50%);
  background:
    radial-gradient(circle at 50% 40%,
      rgba(255, 176, 32, 0.15) 0%,
      rgba(255, 176, 32, 0.07) 22%,
      rgba(255, 176, 32, 0.02) 40%,
      rgba(255, 176, 32, 0) 58%);
  pointer-events: none;
}

/* Fine concentric arcs — the "ripple" around the yolk. Masked to a ring so it
   never runs under the headline and never reaches the edge of the band. */
.hero::after {
  content: '';
  position: absolute;
  z-index: var(--z-below);
  left: 50%;
  top: -14%;
  width: min(128vw, 72rem);
  aspect-ratio: 1;
  transform: translateX(-50%);
  background: repeating-radial-gradient(circle at 50% 40%,
    rgba(240, 138, 0, 0.09) 0 1px,
    rgba(240, 138, 0, 0) 1px 40px);
  -webkit-mask-image: radial-gradient(circle at 50% 40%,
    rgba(0, 0, 0, 0) 12%, rgba(0, 0, 0, 0.5) 26%,
    rgba(0, 0, 0, 0.22) 42%, rgba(0, 0, 0, 0) 56%);
  mask-image: radial-gradient(circle at 50% 40%,
    rgba(0, 0, 0, 0) 12%, rgba(0, 0, 0, 0.5) 26%,
    rgba(0, 0, 0, 0.22) 42%, rgba(0, 0, 0, 0) 56%);
  pointer-events: none;
}

.hero__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-md);
}

.hero__logo { margin-block-end: var(--space-2xs); }

.hero__title {
  font-size: var(--fs-display);
  font-weight: var(--fw-display-strong);
  line-height: var(--lh-display);
  letter-spacing: var(--ls-display);
  max-width: 18ch;
  text-wrap: balance;
}

:lang(ko) .hero__title,
.hero__title:lang(ko) { max-width: 16em; }

.hero__title em {
  font-style: normal;
  position: relative;
  white-space: nowrap;
}

/* Yolk stroke under the emphasised word. Sits clear of descenders — at
   bottom: 0 it cuts straight through the tail of a "g". */
.hero__title em::after {
  content: '';
  position: absolute;
  left: -0.05em;
  right: -0.05em;
  bottom: -0.09em;
  height: 0.13em;
  z-index: var(--z-below);
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, var(--yolk), var(--yolk-deep));
}

.hero__sub {
  max-width: var(--measure-short);
  font-size: var(--fs-lead);
  line-height: var(--lh-snug);
  color: var(--text-muted);
  text-wrap: pretty;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-xs);
  margin-block-start: var(--space-sm);
}

/* The status line — e.g. "nothing is released yet".

   This is the most concrete sentence in the hero and it used to be set at
   --fs-sm in muted grey directly under a --fs-lead paragraph, which inverted
   the hierarchy: the one falsifiable claim on the page read as a footnote.
   It is now body size in full-strength ink, and enclosed so it reads as a
   deliberate status chip rather than shrunken body copy. */
.hero__note {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-2xs);
  margin-inline: auto;
  padding: var(--space-2xs) var(--space-md);
  font-size: var(--fs-body);
  line-height: var(--lh-snug);
  color: var(--text);
  text-wrap: pretty;
  background-color: var(--surface);
  border: var(--border-w) solid var(--border-strong);
  border-radius: var(--radius-pill);
}

/* The marker. Same yolk dot as .eyebrow and .pill, so the chip is legibly part
   of the same family. `align-items: baseline` would drop a zero-height inline
   box onto the text baseline, so the dot is nudged up by hand. */
.hero__note::before {
  content: '';
  align-self: center;
  width: 0.5rem;
  height: 0.5rem;
  flex: none;
  border-radius: 50%;
  background-color: var(--yolk);
}

/* Below the pill radius the chip wraps to two lines and the pill shape stops
   reading as one; square it off and let it fill the column. */
@media (max-width: 30em) {
  .hero__note {
    display: flex;
    align-items: flex-start;
    padding: var(--space-xs) var(--space-sm);
    border-radius: var(--radius-md);
    text-align: start;
  }
  .hero__note::before { align-self: flex-start; margin-block-start: 0.45em; }
}

/* A short, page-level hero for interior pages. */
.page-hero {
  padding-block: clamp(2.5rem, 1.5rem + 5vw, 5rem) clamp(2rem, 1.2rem + 4vw, 4rem);
  background-color: var(--paper);
}

.page-hero__title { font-size: var(--fs-h1); font-weight: var(--fw-display-strong); }

.page-hero__sub {
  max-width: var(--measure);
  margin-block-start: var(--space-sm);
  font-size: var(--fs-lead);
  line-height: var(--lh-snug);
  color: var(--text-muted);
}


/* ==========================================================================
   10  SECTION HEAD / EYEBROW
   ========================================================================== */

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  font-family: var(--font-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
}

.eyebrow::before {
  content: '';
  width: 0.5rem;
  height: 0.5rem;
  flex: none;
  border-radius: 50%;
  background-color: var(--yolk);
}

:lang(ko) .eyebrow { letter-spacing: 0.06em; text-transform: none; }

.section-head {
  max-width: var(--measure);
  margin-block-end: var(--space-xl);
}

.section-head--center {
  margin-inline: auto;
  text-align: center;
}

.section-head--center .eyebrow { justify-content: center; }

.section-head__title {
  margin-block-start: var(--space-xs);
  font-size: var(--fs-h2);
  font-weight: var(--fw-display-strong);
}

.section-head__body {
  margin-block-start: var(--space-sm);
  font-size: var(--fs-lead);
  line-height: var(--lh-snug);
  color: var(--text-muted);
  text-wrap: pretty;
}


/* ==========================================================================
   11  GAME CARDS
   ========================================================================== */

.game-card {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background-color: var(--surface);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  transition: transform var(--dur-base) var(--ease-spring),
              box-shadow var(--dur-base) var(--ease-out),
              border-color var(--dur-base) var(--ease-out);
}

/* On the warm band the default hairline all but disappears against the card
   fill; step it up so the card still reads as an object. */
.section--shell .game-card,
.section--shell .card,
.section--shell .contact-card { border-color: var(--border-strong); }

/* Only lift cards that are actually navigable. */
.game-card:has(.game-card__link):hover,
.game-card:has(.game-card__link):focus-within {
  transform: translateY(-4px);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-md);
}

.game-card__media {
  position: relative;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background-color: var(--shell);
  border-bottom: var(--border-w) solid var(--border);
}

.game-card__cover {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease-out);
}

.game-card:has(.game-card__link):hover .game-card__cover { transform: scale(1.035); }

/* --- fallback cover ------------------------------------------------------
   We have no art yet. This must look deliberate, not broken: a warm shell
   field, soft concentric yolk arcs, and the title's initial set in the
   display face. Set data-initial="t" on the element.                       */
.game-card__fallback {
  position: relative;
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  background:
    radial-gradient(circle at 50% 46%,
      rgba(255, 176, 32, 0.34) 0%,
      rgba(255, 176, 32, 0.14) 36%,
      rgba(255, 176, 32, 0) 66%),
    linear-gradient(158deg, #FFFCF6 0%, #F7F1E5 55%, #EFE7D8 100%);
}

.game-card__fallback::before {
  content: '';
  position: absolute;
  inset: 0;
  background: repeating-radial-gradient(circle at 50% 46%,
    rgba(240, 138, 0, 0.20) 0 1px,
    rgba(240, 138, 0, 0) 1px 20px);
  -webkit-mask-image: radial-gradient(circle at 50% 46%,
    #000 0%, rgba(0, 0, 0, 0.45) 55%, rgba(0, 0, 0, 0) 82%);
  mask-image: radial-gradient(circle at 50% 46%,
    #000 0%, rgba(0, 0, 0, 0.45) 55%, rgba(0, 0, 0, 0) 82%);
}

.game-card__fallback::after {
  content: attr(data-initial);
  position: relative;
  font-family: var(--font-display);
  font-size: clamp(3.5rem, 8vw, 5.5rem);
  font-weight: var(--fw-display-strong);
  line-height: 1;
  /* Warm, not grey: --ink at low alpha over a warm ground reads as a smudge. */
  color: var(--ember);
  opacity: 0.20;
  text-transform: lowercase;
  letter-spacing: -0.03em;
}

.game-card__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: var(--space-2xs);
  padding: var(--space-md);
}

.game-card__eyebrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2xs);
  margin-block-end: var(--space-3xs);
}

.game-card__title {
  font-size: var(--fs-h3);
  font-weight: var(--fw-display-strong);
  letter-spacing: -0.015em;
}

.game-card__desc {
  color: var(--text-muted);
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
}

.game-card__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2xs);
  margin-block-start: auto;
  padding-block-start: var(--space-sm);
}

/* Whole-card link. The ::after stretches the hit area over the card while
   the visible text stays a normal, readable link label. */
.game-card__link {
  align-self: flex-start;
  margin-block-start: var(--space-2xs);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--link);
  text-decoration: none;
}

.game-card__link::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

.game-card__link:hover { color: var(--link-hover); text-decoration: underline; }

.game-card__link .btn__arrow { margin-inline-start: 0.25rem; }

/* Card variant with no cover at all — text only, shorter.

   align-self: start is load-bearing. A grid item stretches to the row height by
   default, so a three-line flat card sharing a row with a card that has a media
   panel grows to match it and leaves ~450px of empty fill underneath — which
   reads as a broken or half-loaded card, not as a short one. Sizing it to its
   content makes the difference deliberate. */
.game-card--flat { align-self: start; }
.game-card--flat .game-card__media { display: none; }

/* --- standalone illustration ---------------------------------------------
   The same panel treatment as a card cover, for pages that show art outside a
   card — /games/ describes trimweight in prose, not in a card, and still wants
   the board illustration. 16:10 like .game-card__media, so one asset serves
   both without a second crop. Needs real alt text: nothing else on the page
   describes the picture. */
.illus {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  background-color: var(--shell);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-lg);
}

.section--shell .illus { border-color: var(--border-strong); }


/* ==========================================================================
   12  PILLS & BADGES
   ========================================================================== */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.25rem 0.6875rem;
  border-radius: var(--radius-pill);
  background-color: var(--wash-ink);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  line-height: 1.4;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

.pill::before {
  content: '';
  width: 0.4375rem;
  height: 0.4375rem;
  flex: none;
  border-radius: 50%;
  background-color: var(--ink-60);
}

/* "In development" — the only status the site may currently claim. */
.pill--dev { background-color: var(--wash-yolk); }
.pill--dev::before { background-color: var(--yolk-deep); }

.pill--live { background-color: var(--wash-sky); }
.pill--live::before { background-color: var(--sky-deep); }

/* Neutral pill without a dot. */
.pill--plain::before { display: none; }

/* Platform badges — quieter than a pill, no dot. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3125rem;
  padding: 0.1875rem 0.5625rem;
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-sm);
  background-color: var(--surface);
  color: var(--text-muted);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  line-height: 1.45;
  white-space: nowrap;
}

.badge__icon { width: 0.875rem; height: 0.875rem; flex: none; }

/* On a --shell band the badge needs a paper fill to stay distinct. */
.section--shell .badge { background-color: var(--paper); }


/* ==========================================================================
   13  FEATURE LIST, CONTACT CARDS, INFO ROWS
   ========================================================================== */

/* Generic surface card used by the studio band and support page. */
.card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  padding: var(--space-lg);
  background-color: var(--surface);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs);
}

.card__title {
  font-size: var(--fs-h4);
  font-weight: var(--fw-display-strong);
}

.card__body { color: var(--text-muted); font-size: var(--fs-sm); }

.card__icon {
  width: 2.5rem;
  height: 2.5rem;
  display: grid;
  place-items: center;
  margin-block-end: var(--space-2xs);
  border-radius: var(--radius-md);
  background-color: var(--wash-yolk);
  color: var(--ink);
}

.card__icon svg { width: 1.25rem; height: 1.25rem; }

/* Contact card — the store-facing support surface. */
.contact-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  padding: var(--space-lg);
  background-color: var(--surface);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

.contact-card__label {
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
}

:lang(ko) .contact-card__label { letter-spacing: 0.06em; text-transform: none; }

.contact-card__value {
  font-family: var(--font-display);
  font-size: var(--fs-h4);
  font-weight: var(--fw-display);
  overflow-wrap: anywhere;   /* long email addresses must not overflow */
}

.contact-card__value a { text-decoration-color: color-mix(in srgb, var(--link) 45%, transparent); }

.contact-card__note { font-size: var(--fs-sm); color: var(--text-muted); }

/* Definition-list rows — business info, spec tables, "at a glance" blocks. */
.info-rows { margin: 0; }

.info-rows > div {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3xs);
  padding-block: var(--space-sm);
  border-top: var(--border-w) solid var(--border);
}

.info-rows > div:last-child { border-bottom: var(--border-w) solid var(--border); }

.info-rows dt {
  font-size: var(--fs-sm);
  font-weight: var(--fw-bold);
  color: var(--text-muted);
}

.info-rows dd {
  margin: 0;
  font-size: var(--fs-body);
  overflow-wrap: anywhere;
}

@media (min-width: 40em) {
  .info-rows > div {
    grid-template-columns: minmax(9rem, 15rem) 1fr;
    gap: var(--space-md);
    align-items: baseline;
  }
}

/* The two-column switch above keys off the viewport, but inside a game card the
   container is a fraction of it. Between 40em and 56em the 9rem label minimum
   starves the value track and `overflow-wrap: anywhere` then breaks the value
   one character per line. Keep card rows stacked until the card itself is wide. */
@media (max-width: 56em) {
  .game-card .info-rows > div {
    grid-template-columns: 1fr;
    gap: var(--space-3xs);
  }
}

/* A `[[PLACEHOLDER]]` token rendered so it is impossible to miss in review. */
.placeholder {
  display: inline-block;
  padding: 0.05em 0.4em;
  border: 1px dashed var(--ember);
  border-radius: var(--radius-xs);
  background-color: var(--wash-yolk);
  color: var(--ember);
  font-family: var(--font-mono);
  font-size: 0.85em;
  font-weight: var(--fw-bold);
  overflow-wrap: anywhere;
}


/* ==========================================================================
   14  NOTICE / CALLOUT
   ========================================================================== */

.notice {
  display: flex;
  gap: var(--space-sm);
  padding: var(--space-md) var(--space-md);
  border: var(--border-w) solid var(--border);
  border-inline-start: 4px solid var(--ink-60);
  border-radius: var(--radius-md);
  background-color: var(--wash-ink);
  color: var(--text);
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
}

.notice__icon { flex: none; width: 1.25rem; height: 1.25rem; margin-block-start: 0.15rem; }
.notice__body > * + * { margin-block-start: var(--space-2xs); }

.notice__title {
  font-family: var(--font-display);
  font-size: var(--fs-h4);
  font-weight: var(--fw-display);
  line-height: var(--lh-snug);
}

.notice--accent {
  background-color: var(--wash-yolk);
  border-color: color-mix(in srgb, var(--yolk) 40%, var(--line));
  border-inline-start-color: var(--yolk-deep);
}

.notice--info {
  background-color: var(--wash-sky);
  border-color: color-mix(in srgb, var(--sky) 30%, var(--line));
  border-inline-start-color: var(--sky-deep);
}


/* ==========================================================================
   15  PROSE (LEGAL & LONG-FORM)
   ========================================================================== */

.prose {
  max-width: var(--measure);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text);
}

.prose > * + * { margin-block-start: var(--space-md); }

.prose h2 {
  margin-block-start: var(--space-2xl);
  padding-block-start: var(--space-md);
  border-top: var(--border-w) solid var(--border);
  font-size: var(--fs-h2);
  font-weight: var(--fw-display-strong);
  scroll-margin-top: calc(var(--header-h) + var(--space-md));
}

.prose > h2:first-child { margin-block-start: 0; padding-block-start: 0; border-top: 0; }

.prose h3 {
  margin-block-start: var(--space-xl);
  font-size: var(--fs-h3);
  font-weight: var(--fw-display);
  scroll-margin-top: calc(var(--header-h) + var(--space-md));
}

.prose h4 {
  margin-block-start: var(--space-lg);
  font-family: var(--font-body);
  font-size: var(--fs-h4);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-normal);
  scroll-margin-top: calc(var(--header-h) + var(--space-md));
}

.prose p { color: var(--text); }

.prose a {
  color: var(--link);
  text-decoration-color: color-mix(in srgb, var(--link) 45%, transparent);
}

.prose ul,
.prose ol {
  padding-inline-start: 1.35em;
}

.prose ul { list-style: none; padding-inline-start: 1.25em; }

.prose ul > li { position: relative; }

.prose ul > li::before {
  content: '';
  position: absolute;
  left: -1em;
  top: 0.66em;
  width: 0.375rem;
  height: 0.375rem;
  border-radius: 50%;
  background-color: var(--yolk-deep);
}

.prose ol { list-style: decimal; }
.prose ol::marker,
.prose ol > li::marker { color: var(--text-muted); font-weight: var(--fw-bold); }

.prose li + li { margin-block-start: var(--space-2xs); }
.prose li > ul,
.prose li > ol { margin-block-start: var(--space-2xs); }

/* Nested list bullets step down in emphasis. */
.prose ul ul > li::before { background-color: var(--ink-60); width: 0.3125rem; height: 0.3125rem; }

.prose blockquote {
  padding: var(--space-sm) var(--space-md);
  border-inline-start: 3px solid var(--yolk);
  background-color: var(--shell);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
}

/* Tables in legal pages get wide — they must scroll, not push the page.

   Three things have to hold at once:

   1. A table that fits must not be made to scroll. A flat `min-width: 32rem`
      padded every table out to 512px, so a two-column table at 320px scrolled
      for no reason. `min(32rem, 100%)` resolves the percentage against the
      scrollport, so the floor never exceeds the space actually available and
      only a genuinely wider table overflows.
   2. A table that does not fit should get more room before it is asked to
      scroll. The prose column is capped at the reading measure (~687px), which
      no six-column table fits into at any viewport width. Above 64em the
      wrapper breaks out of the measure and centres itself on the column.
   3. When it still overflows, say so — see .table-frame below. */
.prose .table-scroll,
.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-md);
  background-color: var(--bg);
}

.prose table,
.table {
  width: 100%;
  min-width: min(30rem, 100%);
  font-size: var(--fs-sm);
  text-align: start;
}

.table-scroll > table { min-width: min(32rem, 100%); }

/* Break out of the reading measure on wide screens. The widths are fixed rem
   steps rather than viewport maths on purpose: 100vw includes the classic
   scrollbar, and a breakout sized from it can push the page sideways. Each
   step below is checked to stay inside the visual viewport at its own
   breakpoint, so no width introduces horizontal page scroll.

   Both selectors are listed because site.js wraps each .table-scroll in a
   .table-frame at runtime; without JS the .table-scroll is still the direct
   child and still widens. */
@media (min-width: 64em) {
  .prose > .table-scroll,
  .prose > .table-frame {
    position: relative;
    inset-inline-start: 50%;
    width: 54rem;
    transform: translateX(-50%);
  }
}

@media (min-width: 80em) {
  .prose > .table-scroll,
  .prose > .table-frame { width: 64rem; }
}

/* 80rem rather than --w-page (72rem): the widest table in the privacy policy
   needs 1216px to lay out without scrolling, and this is the step that finally
   gives it that. It is still inside --w-wide, the site's page frame. */
@media (min-width: 96em) {
  .prose > .table-scroll,
  .prose > .table-frame { width: 80rem; }
}

/* --- overflow affordance -------------------------------------------------

   site.js wraps every .table-scroll in a .table-frame and toggles the three
   classes below from the container's real scroll geometry, so the fade shows
   only when there is something past the edge to scroll to. The gradient is a
   shadow rather than a fade to the page colour: the rows are striped and the
   header row is filled, so a fade to --bg would band against them.

   The fade is a sibling overlay rather than a mask on the scroller itself,
   because a mask is clipped to the border box and would eat the focus ring on
   the tabindex="0" container. */
.table-frame { position: relative; }

.table-frame > .table-scroll { width: 100%; }

.table-frame__fade {
  position: absolute;
  inset-block: var(--border-w);
  width: var(--space-lg);
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-out);
}

.table-frame__fade--start {
  inset-inline-start: var(--border-w);
  border-start-start-radius: var(--radius-md);
  border-end-start-radius: var(--radius-md);
  background-image: linear-gradient(to right,
    color-mix(in srgb, var(--ink) 20%, transparent), transparent);
}

.table-frame__fade--end {
  inset-inline-end: var(--border-w);
  border-start-end-radius: var(--radius-md);
  border-end-end-radius: var(--radius-md);
  background-image: linear-gradient(to left,
    color-mix(in srgb, var(--ink) 20%, transparent), transparent);
}

.table-frame.has-overflow:not(.at-start) > .table-frame__fade--start,
.table-frame.has-overflow:not(.at-end)   > .table-frame__fade--end { opacity: 1; }

.prose thead th,
.table thead th {
  padding: var(--space-xs) var(--space-sm);
  background-color: var(--wash-ink);
  color: var(--text);
  font-weight: var(--fw-bold);
  text-align: start;
  vertical-align: bottom;
  border-bottom: var(--border-w) solid var(--border);
}

.prose tbody th,
.table tbody th { font-weight: var(--fw-bold); text-align: start; }

.prose tbody td,
.prose tbody th,
.table tbody td,
.table tbody th {
  padding: var(--space-xs) var(--space-sm);
  border-top: var(--border-w) solid var(--border);
  vertical-align: top;
  line-height: var(--lh-snug);
}

.prose tbody tr:nth-child(even),
.table tbody tr:nth-child(even) { background-color: color-mix(in srgb, var(--shell) 65%, var(--paper)); }

.prose caption,
.table caption {
  padding-block-end: var(--space-2xs);
  color: var(--text-muted);
  font-size: var(--fs-sm);
  text-align: start;
}

/* Definition lists inside prose — used heavily by privacy policies. */
.prose dl { margin-block-start: var(--space-md); }
.prose dt {
  margin-block-start: var(--space-sm);
  font-weight: var(--fw-bold);
}
.prose dt:first-child { margin-block-start: 0; }
.prose dd {
  margin: var(--space-3xs) 0 0;
  padding-inline-start: var(--space-md);
  border-inline-start: 2px solid var(--line);
  color: var(--text-muted);
}

.prose hr { margin-block: var(--space-xl); }

.prose img,
.prose figure { border-radius: var(--radius-md); }

.prose figcaption {
  margin-block-start: var(--space-2xs);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

.prose code { font-size: 0.88em; }

/* Korean legal text is dense. Give it more room than the Latin default. */
.prose:lang(ko) { line-height: var(--lh-body); }
.prose:lang(ko) li + li { margin-block-start: var(--space-xs); }

/* --- table of contents -------------------------------------------------- */

.toc {
  padding: var(--space-md) var(--space-lg);
  background-color: var(--shell);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-lg);
}

.toc__title {
  margin-block-end: var(--space-xs);
  font-family: var(--font-display);
  font-size: var(--fs-h4);
  font-weight: var(--fw-display-strong);
}

.toc__list {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: toc;
}

.toc__list > li { counter-increment: toc; }

.toc__list a {
  display: block;
  padding: 0.375rem 0;
  color: var(--text);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  text-decoration: none;
  border-bottom: var(--border-w) solid transparent;
}

.toc__list > li > a::before {
  content: counter(toc) '.';
  display: inline-block;
  /* Must clear a two-digit ordinal AND still leave a gap. At 1.6em (24px) the
     string "10." measured 20.7px, so items 10-18 rendered as "10.Behavioural
     advertising" with 3px of air. 2.25em (33.75px) leaves ~13px after the
     widest two-digit ordinal and puts one- and two-digit labels in the same
     column. `.toc--unnumbered` below resets this to 0, so the Korean legal
     pages — which number themselves 제1조, 제2조 … — are unaffected. */
  min-width: 2.25em;
  color: var(--text-muted);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
}

.toc__list a:hover { color: var(--link-hover); text-decoration: underline; }

/* The Korean legal pages number their own sections in the label itself
   (제1조, 제2조 …), and a generated ordinal beside them would run one ahead
   of the article number and read as a contradiction. This drops the ordinal
   and keeps the indent, so the two columns still line up. */
.toc--unnumbered .toc__list > li > a::before {
  content: '';
  min-width: 0;
}

.toc__list ol {
  margin: 0 0 var(--space-2xs) 1.6em;
  padding: 0;
  list-style: none;
}

.toc__list ol a { font-size: var(--fs-xs); color: var(--text-muted); padding-block: 0.25rem; }

@media (min-width: 48em) {
  .toc--cols .toc__list { columns: 2; column-gap: var(--space-lg); }
  .toc--cols .toc__list > li { break-inside: avoid; }
}

/* --- last-updated block -------------------------------------------------- */

.updated {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2xs) var(--space-md);
  padding: var(--space-sm) var(--space-md);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-md);
  background-color: var(--surface);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

.updated__label {
  font-weight: var(--fw-bold);
  color: var(--text);
}

.updated time { font-variant-numeric: tabular-nums; }

/* Page header for a legal document. */
.legal-head { margin-block-end: var(--space-xl); }
.legal-head__title { font-size: var(--fs-h1); font-weight: var(--fw-display-strong); }
.legal-head__sub {
  max-width: var(--measure);
  margin-block-start: var(--space-sm);
  font-size: var(--fs-lead);
  line-height: var(--lh-snug);
  color: var(--text-muted);
}


/* ==========================================================================
   16  FOOTER
   ========================================================================== */

.site-footer {
  padding-block: var(--section-y-sm) var(--space-xl);
  background-color: var(--shell);
  border-top: var(--border-w) solid var(--border);
  color: var(--text);
  font-size: var(--fs-sm);
}

.site-footer__top {
  display: grid;
  gap: var(--space-xl);
  grid-template-columns: 1fr;
}

@media (min-width: 40em) {
  .site-footer__top { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 62em) {
  .site-footer__top {
    grid-template-columns: minmax(14rem, 1.4fr) repeat(4, minmax(0, 1fr));
    gap: var(--space-lg);
  }
}

.site-footer__brand { display: flex; flex-direction: column; gap: var(--space-xs); }

.site-footer__blurb {
  max-width: var(--measure-short);
  color: var(--text-muted);
  font-size: var(--fs-sm);
}

.footer-col__title {
  margin-block-end: var(--space-xs);
  font-family: var(--font-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
}

:lang(ko) .footer-col__title { letter-spacing: 0.06em; text-transform: none; }

.footer-col__list { margin: 0; padding: 0; list-style: none; }
.footer-col__list li + li { margin-block-start: 0.4375rem; }

.footer-col__list a {
  color: var(--text);
  text-decoration: none;
  overflow-wrap: break-word;
}

.footer-col__list a:hover { color: var(--link-hover); text-decoration: underline; }

/* --- business-info block -------------------------------------------------
   Holds 4-6 short lines of statutory detail, most of them `[[PLACEHOLDER]]`
   tokens until the 개인사업자 is registered. Deliberately quiet: it is a legal
   obligation, not a design feature. Reads as a paragraph on mobile and as a
   dot-separated run of pairs from 640px up.                                */
.biz-info {
  margin-block-start: var(--space-xl);
  padding-block-start: var(--space-md);
  border-top: var(--border-w) solid var(--border);
}

.biz-info__title {
  margin-block-end: var(--space-xs);
  font-family: var(--font-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
}

:lang(ko) .biz-info__title { letter-spacing: 0.06em; text-transform: none; }

.biz-info__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
  margin: 0;
  font-size: var(--fs-xs);
  line-height: 1.7;
  color: var(--text-muted);
}

.biz-info__list > div { display: flex; flex-wrap: wrap; gap: 0.15rem 0.4rem; }

.biz-info__list dt { font-weight: var(--fw-bold); color: var(--text-muted); }
.biz-info__list dt::after { content: '\00a0'; }
.biz-info__list dd { margin: 0; color: var(--text); overflow-wrap: anywhere; }

@media (min-width: 40em) {
  .biz-info__list {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 0.25rem var(--space-md);
    max-width: var(--measure);
  }
  .biz-info__list > div { align-items: baseline; }
}

.site-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm) var(--space-md);
  margin-block-start: var(--space-lg);
  padding-block-start: var(--space-md);
  border-top: var(--border-w) solid var(--border);
  font-size: var(--fs-xs);
  color: var(--text-muted);
}

.site-footer__copyright { margin: 0; }

.site-footer__legal-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-sm);
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-footer__legal-links a { color: var(--text-muted); text-decoration: none; }
.site-footer__legal-links a:hover { color: var(--link-hover); text-decoration: underline; }

/* The footer language switch sits on --shell, so give it a paper fill; and
   inside the column flexbox it must shrink-wrap rather than stretch. */
.site-footer .lang-switch {
  align-self: flex-start;
  background-color: var(--paper);
}


/* ==========================================================================
   17  REVEAL-ON-SCROLL + MOTION PREFERENCES
   ========================================================================== */

/* .reveal is inert until site.js adds .js-reveal to <html>. If JS is blocked
   or fails, or the visitor prefers reduced motion, the content is simply
   visible — it never depends on script to be readable. */
.js-reveal .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity var(--dur-reveal) var(--ease-out),
              transform var(--dur-reveal) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}

.js-reveal .reveal.is-revealed {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* Stagger helper — set inline or via these classes. */
.reveal--d1 { --reveal-delay: 70ms; }
.reveal--d2 { --reveal-delay: 140ms; }
.reveal--d3 { --reveal-delay: 210ms; }
.reveal--d4 { --reveal-delay: 280ms; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  /* Backstop. tokens.css already zeroes the duration tokens; this catches
     anything with a hard-coded duration and any third-party-ish keyframes. */
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms;
    animation-iteration-count: 1;
    transition-duration: 0.01ms;
    scroll-behavior: auto;
  }

  /* Motion that is purely decorative is removed outright, not shortened. */
  .brand:hover .brand__mark,
  .brand:focus-visible .brand__mark { animation: none; }

  .brand:hover .brand__lockup,
  .brand:focus-visible .brand__lockup { transform: none; }

  .btn:hover,
  .game-card:hover,
  .game-card:focus-within { transform: none; }

  .js-reveal .reveal { opacity: 1; transform: none; transition: none; }
}


/* ==========================================================================
   18  PRINT
   Legal pages get printed and filed. Make that not embarrassing.
   ========================================================================== */

@media print {
  .site-header,
  .nav-panel,
  .nav-scrim,
  .skip-link,
  .lang-switch,
  .hero::before,
  .hero::after { display: none; }

  body { background: #fff; color: #000; font-size: 11pt; }
  .wrap { max-width: none; padding-inline: 0; }
  .prose { max-width: none; }
  .prose h2, .prose h3, .prose h4 { break-after: avoid; }
  .prose li, .prose tr, .toc { break-inside: avoid; }
  a { color: #000; text-decoration: underline; }
  .prose a[href^='http']::after { content: ' (' attr(href) ')'; font-size: 0.85em; word-break: break-all; }
  .site-footer { border-top: 1px solid #999; background: none; }
}
