/* THE DESIGN SYSTEM — one file, every page.
   Written from DESIGN.md and answerable to it. The site, the design page and
   anything added later load THIS first, so a colour or a component changed here
   changes everywhere at once. Page stylesheets add layout on top of this and
   never restate what is here.

   North star: noon light on a cream desk, a handheld console spilling little
   guys onto the page. Warm paper, hard black ink, hairlines, and colour only
   on the things that are alive. */

/* ---------------------------------------------------------------- tokens */
:root {
  /* the warm neutral ramp, paper to void */
  --paper: #fcfaf4;   /* the ground */
  --bone: #f5f1e7;    /* a panel with a border round it */
  --shell: #ede7d9;   /* a thing that reacts: hovered row, bar, tooltip */
  --mist: #dfd8c6;    /* every hairline in the chrome */
  --ash: #c6bda8;     /* a hovered or chosen border */
  --fog: #9a927f;     /* the smallest print */
  --smoke: #6e6858;   /* dim ink: labels, captions */
  --graphite: #46423a;/* body copy that is not a heading */
  --ink: #232019;     /* headings, values, the button fill */
  --void: #12100c;    /* the outline drawn around a render */

  /* colour belongs only to what is alive */
  --screen: #57c463;      /* generating · kept · rare */
  --bubblegum: #e85d9b;
  --cobalt: #2e5be0;
  --marigold: #f2b705;
  --tomato: #d94c3d;

  /* the faces: one sign, one voice */
  --display: "Pixelify Sans", ui-monospace, monospace;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;

  /* the four layout numbers, and the one base they are all multiples of */
  --gap: 8px;
  /* the height of the top bar, which three screens subtract from the viewport to
     work out how tall the stage is — so it is a token, not a number in two files */
  --bar: 55px;
  --pad: 14px;
  --section: 64px;
  --page: 1180px;

  /* three radii, and the third is zero */
  --r-tag: 3px;
  --r-pill: 9999px;

  /* the one shadow that exists in the chrome: an offset, never a blur */
  --sticker: 2px 2px 0 var(--ink);
  /* the scrim behind text laid over a render — the backdrop is a different
     colour for every guy, so a readout inside the viewport cannot rely on it */
  --scrim: rgba(18, 16, 12, .72);

  --text: 13px;
  --lh: 1.5;
  color-scheme: light;
}

/* ------------------------------------------------------------------ base */
* { box-sizing: border-box; }
html { background: var(--paper); -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--paper); color: var(--graphite);
  font: var(--text)/var(--lh) var(--mono);
  font-variant-numeric: tabular-nums;
}
a { color: var(--ink); text-underline-offset: 3px; }
a.out { color: var(--cobalt); }
button, input, select, textarea { font: inherit; border-radius: 0; color: inherit; }
button { cursor: pointer; }
/* never smooth-scale a render — a bilinear guy is a broken guy */
img, canvas { image-rendering: pixelated; image-rendering: crisp-edges; }
::selection { background: var(--ink); color: var(--paper); }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* ------------------------------------------------------------------ type */
/* THE PIXEL FACE CARRIES THE HIERARCHY. Five steps, and each one is obviously a
   different rank from a room away: 76 / 48 / 30 / 17 / 10. The old scale ran
   40 / 22 / 14 and the top two were near enough the same size that a screen had
   no shape to it. Weight does half the work — the display face is set at 700
   everywhere it is large, because a bulky letterform is the whole joke. */
.wordmark {
  font-family: var(--display); font-weight: 700; font-size: 30px; line-height: 1;
  letter-spacing: 1px; color: var(--ink); text-decoration: none; display: inline-block;
}
.hero {
  font-family: var(--display); font-weight: 700;
  font-size: clamp(46px, 7.4vw, 84px); line-height: 0.94; letter-spacing: -1px;
  color: var(--ink); margin: 0;
}
.guy-name {
  font-family: var(--display); font-weight: 700;
  font-size: clamp(34px, 4.4vw, 54px); line-height: 0.98; letter-spacing: -0.5px;
  color: var(--ink); margin: 0;
}

/* THE TITLE — the heading over a section. Pixel face too, so the hierarchy is
   one ladder rather than two competing ones. */
.title {
  font-family: var(--display); font-weight: 600; color: var(--ink);
  font-size: 17px; letter-spacing: 1px; text-transform: uppercase;
  line-height: 1.2; margin: 0;
}
/* THE KICKER — a quiet label over a thing */
.kicker {
  color: var(--smoke); font-size: 10px; font-weight: 400; letter-spacing: 3px;
  text-transform: uppercase; line-height: 1.4;
}
/* the one lowercase line under a control saying what it will do */
.hint { color: var(--smoke); margin: 0; }
.hint i { font-style: normal; color: var(--ink); }
.quiet { color: var(--smoke); }
.tiny { font-size: 11px; }
.micro { font-size: 10px; letter-spacing: 1px; color: var(--fog); }
.big-number { font-size: 30px; line-height: 1.1; letter-spacing: 1px; color: var(--ink); }

/* ------------------------------------------------------------------ motion */
/* EVERY EASING IN THIS FILE IS steps(). A smooth cubic curve is a different
   world from a grid of whole pixels — the guys are quantised, the shadows are
   quantised, and an interface that glides while they step reads as two products
   bolted together. Two to four frames is enough to feel like motion and short
   enough that nobody is ever waiting for it. */
@keyframes rise-in { from { opacity: 0; transform: translateY(10px) } to { opacity: 1; transform: none } }
@keyframes drop-in { from { opacity: 0; transform: translateY(-8px) } to { opacity: 1; transform: none } }
@keyframes pop { 0% { transform: scale(1) } 40% { transform: scale(1.22) } 100% { transform: scale(1) } }
@keyframes flash-in { from { opacity: 0 } to { opacity: 1 } }

/* --------------------------------------------------------------- buttons */
/* THE BUTTON — ink on paper, one per view, always a verb */
.btn {
  padding: 13px 22px; background: var(--ink); color: var(--paper);
  border: 1px solid var(--ink); box-shadow: var(--sticker);
  font-size: 13px; letter-spacing: 3px; text-transform: uppercase;
  transition: transform .08s steps(2), box-shadow .08s steps(2), background .08s steps(2);
}
/* It lifts OFF the page under the cursor and is pressed back INTO it — the
   shadow grows and shrinks with the lift, so the two read as one movement. */
.btn:hover { background: var(--void); transform: translate(-1px, -1px); box-shadow: 3px 3px 0 var(--ink); }
.btn:active { transform: translate(2px, 2px); box-shadow: 0 0 0 var(--ink); }
.btn.quiet:hover { transform: translate(-1px, -1px); box-shadow: 2px 2px 0 var(--ash); }
.btn.quiet:active { transform: translate(1px, 1px); box-shadow: 0 0 0 var(--ash); }
/* the little grey key printed on a button that also has a shortcut */
.btn kbd {
  display: inline-block; margin-left: 10px; padding: 0 5px; font: inherit; font-size: 10px;
  border: 1px solid currentColor; opacity: .55; letter-spacing: 1px; vertical-align: 1px;
}
.star { font-size: 13px; display: inline-block; }
.pop .star { animation: pop .28s steps(4); }
.btn[disabled] { background: var(--ash); border-color: var(--ash); box-shadow: none; cursor: default; }
/* ...and its quiet kin, which may repeat */
.btn.quiet {
  background: transparent; color: var(--smoke); border-color: var(--ash); box-shadow: none;
}
.btn.quiet:hover { color: var(--ink); border-color: var(--ink); }
.btn.small { padding: 9px 14px; font-size: 11px; letter-spacing: 2px; }
/* A button never wraps its own label: two words on two lines in a bordered box
   reads as a broken layout, and the row it sits in can wrap instead. */
.btn { white-space: nowrap; }
/* Sometimes the one action is a DESTINATION rather than a verb the page runs
   itself, and then it has to be a real link so it can be opened in a tab. An
   inline anchor ignores the vertical padding and draws its own underline
   through the label, so it is made a box first. */
a.btn { display: inline-block; text-decoration: none; }

/* PLAY — the way into the game, and the loudest button in the product. It is
   set in the pixel face rather than the mono one: it is the one button that is
   also a headline. */
.btn.play, .btn.play-big { font-family: var(--display); font-weight: 700; letter-spacing: 2px; text-align: center; }
.btn.play { font-size: 18px; line-height: 1; padding: 8px 16px 9px; }
.btn.play-big { display: block; width: 100%; font-size: 34px; line-height: 1; padding: 16px 20px 18px; box-shadow: 3px 3px 0 var(--void); }
.btn.play-big:hover { box-shadow: 4px 4px 0 var(--void); }

/* THE PILL — a small choice among a few */
.pill {
  padding: 6px 10px; background: var(--paper); color: var(--smoke); border: 1px solid var(--mist);
  font-size: 10px; letter-spacing: 2px; text-transform: uppercase;
}
.pill { transition: transform .08s steps(2), border-color .08s steps(2), color .08s steps(2); }
.pill:hover { border-color: var(--ash); color: var(--graphite); transform: translateY(-1px); }
.pill.on { color: var(--ink); border-color: var(--ink); background: var(--shell); }

/* THE LINK-BUTTON — the smallest choice */
.link-quiet {
  padding: 6px 0; background: none; border: 0; color: var(--fog); font-size: 11px;
  text-decoration: underline; text-underline-offset: 3px;
}
.link-quiet:hover { color: var(--smoke); }

/* ---------------------------------------------------------------- fields */
.field {
  padding: 13px 15px; background: var(--paper); color: var(--ink); border: 1px solid var(--ash);
  font-size: 16px; letter-spacing: 2px;    /* 16px or iOS zooms the page on focus */
}
.field::placeholder { color: var(--fog); letter-spacing: 1px; }
.field:focus { outline: none; border-color: var(--ink); box-shadow: var(--sticker); }
.field.small { padding: 7px 10px; font-size: var(--text); letter-spacing: 0; background: var(--bone); border-color: var(--mist); }

/* ------------------------------------------------------------------ tags */
/* THE TAG — one word in a thin frame. The only round corner in the system. */
.tag {
  display: inline-block; border: 1px solid var(--mist); border-radius: var(--r-tag);
  padding: 1px 7px; margin: 1px 4px 1px 0; color: var(--graphite); text-decoration: none;
  font-size: 11px; white-space: nowrap;
}
/* the chips arrive one after another, which is what makes a list of facts read
   as something being told to you rather than as something that was always there */
.stagger > * { animation: flash-in .16s steps(2) both; }
.stagger > *:nth-child(1) { animation-delay: .02s }
.stagger > *:nth-child(2) { animation-delay: .05s }
.stagger > *:nth-child(3) { animation-delay: .08s }
.stagger > *:nth-child(4) { animation-delay: .11s }
.stagger > *:nth-child(5) { animation-delay: .14s }
.stagger > *:nth-child(6) { animation-delay: .17s }
.stagger > *:nth-child(7) { animation-delay: .20s }
.stagger > *:nth-child(8) { animation-delay: .23s }
.stagger > *:nth-child(9) { animation-delay: .26s }
.stagger > *:nth-child(10) { animation-delay: .29s }
.tag.dim { color: var(--smoke); }
.tag.seed { color: var(--ink); border-color: var(--ash); }
.tag.live { color: #2f7a3c; border-color: #a9dcb2; }
.tag.rare { color: #8a6600; border-color: #e8cf8a; }
a.tag:hover { border-color: var(--ink); }

/* the status dot: the pill radius exists for this and nothing else */
.dot { display: inline-block; width: 7px; height: 7px; border-radius: var(--r-pill); background: var(--screen); vertical-align: 1px; margin-right: 6px; }
.dot.idle { background: var(--ash); }

/* ----------------------------------------------------------------- cards */
.card { border: 1px solid var(--mist); background: var(--bone); padding: 12px var(--pad); }
.card b { display: block; font-size: 24px; letter-spacing: 1px; font-weight: 400; line-height: 1.2; color: var(--ink); }
.card b small { font-size: 11px; color: var(--smoke); letter-spacing: 0; margin-left: 4px; }
.card span { display: block; color: var(--smoke); font-size: 10px; letter-spacing: 2px; text-transform: uppercase; margin-top: 5px; }
.card i { display: block; font-style: normal; font-size: 10px; margin-top: 6px; color: var(--fog); }

/* ---------------------------------------------------------------- tables */
/* THE TRAIT TABLE — the code this one is made of */
table.traits { width: 100%; border-collapse: collapse; }
table.traits td, table.traits th { text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--mist); font-weight: 400; vertical-align: top; }
table.traits th { color: var(--smoke); font-size: 10px; letter-spacing: 2px; text-transform: uppercase; white-space: nowrap; }
table.traits td.k { color: var(--smoke); width: 34%; white-space: nowrap; }
table.traits td.v { color: var(--ink); text-align: right; }
table.traits tr:hover td { background: var(--shell); }
table.traits tr:last-child td { border-bottom: 0; }

/* ---------------------------------------------------------------- screen */
/* THE VIEWPORT — every render on every page lives inside one of these */
.screen {
  position: relative; background: var(--ink); border: 1px solid var(--void);
  display: block; overflow: hidden; line-height: 0;
}
.screen > canvas, .screen > img, .screen > .still { display: block; width: 100%; height: 100%; }
/* THE READOUT — the small print laid over a render, wherever that render is:
   inside a framed .screen, or across a full-bleed .stage. */
.screen .legend, .stage-over .legend,
.screen .corner, .stage-over .corner {
  position: absolute; z-index: 2; padding: 3px 7px; background: var(--scrim);
  font-size: 10px; letter-spacing: 2px; text-transform: uppercase; color: #a49b88;
  line-height: 1.5; pointer-events: none;
}
.screen .legend, .stage-over .legend { left: 0; bottom: 0; }
.screen .corner, .stage-over .corner { right: 0; top: 0; }
.screen .legend b, .stage-over .legend b { color: #8f8778; font-weight: 400; } /* the LABEL is quiet */
.screen .legend, .stage-over .legend { color: #efe9dc; }                        /* the number is loud */
.stage-over .corner { top: auto; bottom: 0; }

/* --------------------------------------------------------------- details */
details.fold { border: 1px solid var(--mist); background: var(--bone); padding: 8px var(--pad); }
details.fold summary { cursor: pointer; color: var(--smoke); font-size: 10px; letter-spacing: 3px; text-transform: uppercase; list-style: none; }
details.fold summary::-webkit-details-marker { display: none; }
details.fold summary::before { content: "+ "; }
details.fold[open] summary::before { content: "- "; }
details.fold[open] summary { margin-bottom: 10px; }

/* --------------------------------------------------------------- tooltip */
.q {
  display: inline-block; width: 14px; height: 14px; line-height: 12px; text-align: center;
  border: 1px solid var(--ash); border-radius: var(--r-pill); color: var(--smoke); font-size: 9px;
  margin-left: 7px; vertical-align: 1px; cursor: help; position: relative;
  letter-spacing: 0; text-transform: none; font-weight: 400;
}
.q:hover { color: var(--ink); border-color: var(--ink); }
.q::after {
  content: attr(data-tip); position: absolute; left: 0; top: 20px; z-index: 8;
  width: 340px; max-width: 78vw; white-space: normal; background: var(--shell);
  border: 1px solid var(--ash); color: var(--graphite); padding: 8px 10px;
  font-size: 11px; line-height: 1.5; letter-spacing: 0; text-transform: none; text-align: left;
  opacity: 0; pointer-events: none; transition: opacity .1s;
}
.q:hover::after { opacity: 1; }

/* ------------------------------------------------------------------ page */
.wrap { max-width: var(--page); margin: 0 auto; padding: 0 20px; }
.bar {
  border-bottom: 1px solid var(--mist); background: var(--paper);
  position: sticky; top: 0; z-index: 20;
}
.bar .wrap { display: flex; align-items: center; gap: 18px; height: calc(var(--bar) - 1px); flex-wrap: nowrap; }
.bar nav { margin-left: auto; display: flex; gap: 16px; flex-wrap: wrap; }
.bar nav a {
  color: var(--smoke); text-decoration: none; font-size: 10px; letter-spacing: 3px; text-transform: uppercase;
  padding: 4px 0; border-bottom: 1px solid transparent;
}
.bar nav a { transition: color .08s steps(2); }
.bar nav a:hover { color: var(--ink); border-bottom-color: var(--mist); }
.bar nav a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--ink); }
.stack { display: flex; flex-direction: column; gap: var(--gap); }
.row { display: flex; gap: var(--gap); align-items: center; flex-wrap: wrap; }
section + section { margin-top: var(--section); }
.rule { height: 1px; background: var(--mist); border: 0; margin: 0; }

@media (max-width: 640px) {
  :root { --section: 44px; }
  .hero { font-size: 28px; }
  .wrap { padding: 0 14px; }
  /* THE BAR IS ONE ROW ON A PHONE TOO. `nav { width: 100% }` used to hand the
     nav the whole line, which pushed DESIGN onto a second row inside a box
     whose height is fixed at --bar: the four destinations stopped being a row
     of capitals to the right of the wordmark and became a left-aligned block
     with two pixels of clearance under it, and the three stages went on
     subtracting 55px from a bar that no longer measured 55.
     The links keep their 3px of tracking — below that small capitals turn to
     mush — so the width has to come from the wordmark, which is the one thing
     in the bar still legible at two thirds the size. 20px against the phone
     hero's 28px keeps the ranks in the order the ladder puts them. */
  .bar .wrap { gap: 8px; }
  .bar .wordmark { font-size: 20px; }
  .bar nav { flex-wrap: nowrap; gap: 8px; }
  /* A link is one destination, not two words: without this the flex row runs
     out of width and breaks MAKE ONE over two lines instead, which is the same
     second row by another route. */
  .bar nav a { white-space: nowrap; }
}

/* Below about 390px the four destinations genuinely do not fit beside a
   wordmark anyone can read — 26 tracked capitals want 240px of the 347 a
   375px phone has. So the bar gives up and becomes two rows on purpose, and
   --bar grows to say so, which is the part the old rule never did.
   Since PLAY joined the bar (2026-10-09) one row needs about 490px, so the
   two rows start at 560 now, with PLAY beside SOUND on the wordmark's line. */
@media (max-width: 560px) {
  :root { --bar: 74px; }
  .bar .wrap { flex-wrap: wrap; align-content: center; gap: 6px 8px; }
  .bar .wordmark { font-size: 26px; }
  /* TWO ROWS MEANS TWO, and there are three things in this bar. The rule above
     was written when the bar held a wordmark and a nav; the sound toggle
     arrived later, found the nav already holding the whole second line, and
     wrapped onto a third one inside a box still fixed at 74px. The overflow
     was centred, so a 390px phone — which is most phones — opened the product
     with its wordmark sliced in half along the top of the window and the
     toggle sitting out on the render below.
     The toggle belongs on the wordmark's line: it is the one control in the
     bar, the wordmark is the one thing that is not a destination, and a pill
     pushed to the right of a 26px logotype is the same shape the bar has at
     every width above this one. */
  .bar .wrap > .pill { margin-left: auto; }
  .bar nav { order: 1; margin-left: 0; width: 100%; gap: 14px; }
  .btn.play { font-size: 16px; padding: 6px 14px 7px; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}
