/* The number games: Guess the Number and Code Breaker.
   ───────────────────────────────────────────────────────────────────────
   One board, two games. Guess the Number marks every digit; Code Breaker gives
   two totals and leaves the marking to the player. Everything below is
   shared, because the difference between them is what the feedback says
   and not what it looks like.

   Loaded after styles.css and games.css, which is where the palette, the
   faces and the shell come from.

   ══ ABOUT THE THREE STATES ══

   Not green and yellow. That pair belongs to a game somebody else owns,
   and borrowing it is the sort of resemblance that is expensive to argue
   about later. These are the site's own tokens, and they are told apart
   by weight before they are told apart by hue:

     exact     solid ink, the digit reversed out of it. The heaviest
               thing on the board, because it is the most certain.
     near      brass on brass, outlined. Present, unresolved.
     gone      sunk into the page, the digit greyed. Spent.

   A reader who cannot see colour at all still reads three states, which
   is the test a hue pair fails. Both themes get the same three, because
   both themes declare the same tokens. */

/* ══ THE BAR ══
   The streak, beside who is playing. docs/building-a-game.md says a game
   carries no streak, and it was right until a game could keep one: the
   number has to be where it is earned, or solving the daily pays
   something the player cannot see. */
.gm-streak{display:inline-flex;align-items:center;gap:5px;padding:4px 9px;
  border:1px solid var(--line-2);border-radius:999px;font-family:'JetBrains Mono',monospace;
  font-size:11px;color:var(--ink-3);white-space:nowrap;}
.gm-streak svg{fill:var(--ink-3);}
.gm-streak.lit{border-color:var(--brass);color:var(--brass);}
.gm-streak.lit svg{fill:var(--brass);}
.gm-streak[hidden]{display:none;}

/* ══ ONE SCREEN ══
   The board and the keys are the game. A title, a description, a how-to,
   a leaderboard and the other games underneath them are all things to
   scroll past on the way to playing, so none of them are on the page any
   more: they are behind the two buttons in the bar, which is where
   nytimes.com/games/wordle keeps them.

   Nothing scrolls. The shell is exactly the height of the screen, the bar
   and the keys hold their size, and the board takes whatever is left,
   which is the number js/games/numbers.js measures to size a tile. */
body[data-page="game"]{overflow:hidden;}
.gm-shell-game{height:100vh;height:100dvh;min-height:0;overflow:hidden;}
.gm-shell-game .gm-top{flex-shrink:0;}

.nb-main{flex:1;min-height:0;display:flex;}
.nb-game{flex:1;min-height:0;width:100%;max-width:1000px;margin:0 auto;
  padding:12px 16px 14px;display:flex;flex-direction:column;}

/* ══ THE BAR OVER THE BOARD ══
   Which game on the left, where it stands on the right, in one row rather
   than two, because every row above the tiles is a row of board somebody
   loses. */
.nb-bar{flex-shrink:0;display:flex;flex-wrap:wrap;align-items:center;
  justify-content:space-between;gap:8px 14px;margin-bottom:8px;}
.nb-figs{font-family:'JetBrains Mono',monospace;font-size:11px;letter-spacing:.05em;
  color:var(--ink-3);display:flex;flex-wrap:wrap;gap:12px;}

.nb-tabs{display:inline-flex;border:1px solid var(--line-2);border-radius:3px;
  overflow:hidden;}
.nb-tab{appearance:none;background:var(--surface);border:0;cursor:pointer;
  padding:7px 15px;font-family:'JetBrains Mono',monospace;font-size:10px;
  letter-spacing:.09em;text-transform:uppercase;color:var(--ink-3);
  transition:background .15s,color .15s;}
.nb-tab + .nb-tab{border-left:1px solid var(--line-2);}
.nb-tab:hover{color:var(--ink);}
.nb-tab[aria-selected="true"]{background:var(--accent);color:var(--paper);}

/* ══ THE STAGE ══
   No card around it any more. The board is the page. */
.nb-stage{flex:1;min-height:0;display:flex;flex-direction:column;
  align-items:center;gap:8px;}

/* One line, spoken once. aria-live, so a refused guess is heard and not
   only seen. */
.nb-msg{flex-shrink:0;min-height:18px;font-size:13px;color:var(--ink-2);
  text-align:center;}
.nb-msg.bad{color:var(--neg);}

/* Resign, or play again. Small, under the keys, where it is out of the way
   of a thumb that is typing. */
.nb-under{flex-shrink:0;margin-top:2px;}
.nb-under .btn{padding:6px 16px;font-size:11.5px;}

/* ══ THE BOARD ══
   --nb-cols is the digit count and --nb-rows the tries, both set from the
   script, because the board is a different shape in a three digit game
   and a six digit one.

   The split is for the twelve row games. Rows run down the first column
   and then down the second, which is grid-auto-flow:column with the row
   count pinned. Below 720px there is one column and the tiles shrink
   instead. */
/* overflow:auto is the safety valve. Twenty two pixels is as small as a
   tile goes, and on a window short enough that twelve rows of them still
   do not fit, something has to give: the page cannot scroll, so without
   this the keys would be clipped and unreachable. The board gives instead,
   and the keys stay where a thumb left them. */
.nb-board{flex:1;min-height:0;overflow:auto;display:grid;gap:6px;
  justify-content:center;align-content:center;}
@media (min-width:760px){
  .nb-board.split{grid-auto-flow:column;grid-template-rows:repeat(var(--nb-half),auto);
    column-gap:30px;}
}

.nb-row{display:flex;align-items:center;gap:6px;justify-content:center;}
.nb-tiles{display:grid;grid-template-columns:repeat(var(--nb-cols),var(--nb-size));gap:6px;}

/* The tile. --nb-size shrinks with the digit count so that six digits at
   375px still fit without the page scrolling sideways, which is what the
   prototype's zoom slider was standing in for. */
.nb-t{width:var(--nb-size);height:var(--nb-size);border:1.5px solid var(--line-2);
  border-radius:2px;display:flex;align-items:center;justify-content:center;
  font-family:'JetBrains Mono',monospace;font-size:calc(var(--nb-size) * .46);
  font-weight:600;color:var(--ink);background:transparent;
  transition:border-color .12s,background .12s,color .12s;}

/* Typed but not yet sent. */
.nb-t.set{border-color:var(--ink-3);}
/* Where the next digit lands. */
.nb-t.on{border-color:var(--brass);box-shadow:inset 0 0 0 1px var(--brass);}

.nb-t.exact{background:var(--accent);border-color:var(--accent);color:var(--paper);}
.nb-t.near{background:var(--brass-2);border-color:var(--brass);color:var(--brass);}
.nb-t.gone{background:var(--surface-2);border-color:var(--surface-2);color:var(--ink-3);}
/* Code Breaker's rows are not marked at all. The digits stay on the page
   as a record of what has been tried; the counters beside them are the
   only thing said about them. */
.nb-t.sent{background:var(--surface-2);border-color:var(--line-2);color:var(--ink);}

.nb-flip{animation:nb-flip .32s ease;}
@keyframes nb-flip{
  0%{transform:rotateX(0);}
  50%{transform:rotateX(90deg);}
  100%{transform:rotateX(0);}
}

/* The two totals, for Code Breaker. Fixed width on both sides of nothing,
   so the tiles stay centred whether a row has been answered or not. */
.nb-counts{display:flex;gap:10px;width:74px;flex-shrink:0;justify-content:flex-end;
  font-family:'JetBrains Mono',monospace;font-size:14px;font-weight:600;}
.nb-counts .ex{color:var(--ink);}
.nb-counts .ne{color:var(--brass);}
.nb-counts .z{color:var(--ink-3);font-weight:400;}

/* ══ THE KEYPAD ══
   On the page rather than left to the device's own, because a numeric
   field that summons a keyboard over the board is worse on a phone than
   ten buttons that do not move. The physical keyboard works as well. */
.nb-pad{flex-shrink:0;display:grid;grid-template-columns:repeat(7,1fr);gap:6px;
  width:100%;max-width:430px;}
.nb-k{appearance:none;cursor:pointer;border:1px solid var(--line-2);border-radius:3px;
  background:var(--surface-2);color:var(--ink);padding:14px 0;
  font-family:'JetBrains Mono',monospace;font-size:16px;font-weight:600;
  transition:background .12s,border-color .12s;touch-action:manipulation;}
.nb-k:hover:not(:disabled){border-color:var(--ink-3);}
.nb-k:active:not(:disabled){background:var(--accent-2);}
.nb-k:disabled{opacity:.4;cursor:not-allowed;}
.nb-k.wide{grid-column:span 2;font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;}
.nb-k.go{background:var(--accent);color:var(--paper);border-color:var(--accent);}
.nb-k.go:hover:not(:disabled){opacity:.88;}

/* Figures that appear inside the dialog rather than on the page. */
.nb-answer{font-family:'JetBrains Mono',monospace;font-size:19px;font-weight:600;
  letter-spacing:.14em;color:var(--ink);}
.nb-score{font-family:'JetBrains Mono',monospace;font-size:26px;font-weight:600;
  color:var(--brass);display:block;margin:4px 0 2px;}
.nb-acts{display:flex;flex-wrap:wrap;gap:9px;justify-content:center;margin-top:16px;}

/* ══ THE STREAK, WHERE IT WAS EARNED ══ */
.nb-streak{margin-top:16px;padding-top:16px;border-top:1px solid var(--line);}
.nb-streak-n{font-family:'Newsreader',serif;font-size:17px;color:var(--ink);}
.nb-week{display:flex;gap:6px;justify-content:center;margin:10px 0 8px;}
.nb-d{width:28px;display:flex;flex-direction:column;align-items:center;gap:3px;}
.nb-d i{font-family:'JetBrains Mono',monospace;font-size:9px;letter-spacing:.06em;
  color:var(--ink-3);font-style:normal;}
.nb-d b{width:22px;height:22px;border:1px solid var(--line-2);border-radius:2px;
  display:flex;align-items:center;justify-content:center;font-size:11px;
  color:var(--ink-3);font-weight:600;}
.nb-d.on b{background:var(--accent);border-color:var(--accent);color:var(--paper);}
.nb-d.now b{border-color:var(--brass);}

/* ══ THE SETTINGS FOR A FREE GAME ══ */
/* The two fields carry a label above them and the two buttons do not, so
   centring the row left the buttons floating halfway up the selects. They
   line up along the bottom instead, which is the edge they share, and the
   whole group is centred in the space by align-content. A fixed height on
   both keeps that edge honest when one of them wraps. */
.nb-setup{flex:1;min-height:0;width:100%;max-width:460px;display:flex;
  flex-wrap:wrap;gap:12px;align-items:flex-end;align-content:center;
  justify-content:center;}
.nb-setup .btn{height:38px;display:inline-flex;align-items:center;
  justify-content:center;padding:0 18px;}
.nb-field{display:flex;flex-direction:column;gap:5px;}
.nb-field select{height:38px;}
.nb-field label{font-family:'JetBrains Mono',monospace;font-size:9.5px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--ink-3);}
.nb-field select{appearance:none;background:var(--surface);border:1px solid var(--line-2);
  border-radius:3px;color:var(--ink);padding:9px 30px 9px 11px;font-family:inherit;
  font-size:14px;cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23696F77' stroke-width='1.4'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 11px center;}

/* ══ HOW THAT COMPARED ══
   Three bars to one scale, so the lengths can be read against each other
   rather than against their own numbers. Yours is the solid one. There was
   a distribution here, one bar per try count; it is gone, because a bar
   chart of seven people is noise and it never answered the question
   somebody has when they finish, which is whether they did well. */
.nb-cmp{display:grid;gap:22px;margin-top:16px;}
@media (min-width:720px){.nb-cmp{grid-template-columns:1fr 1fr;gap:34px;}}

.nb-cmp-set{display:flex;flex-direction:column;gap:7px;}
.nb-cmp-label{font-family:'JetBrains Mono',monospace;font-size:9.5px;
  letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3);margin-bottom:2px;}
.nb-cmp-bar{display:grid;grid-template-columns:58px 1fr auto;align-items:center;gap:10px;}
.nb-cmp-who{font-size:12.5px;color:var(--ink-3);}
.nb-cmp-track{display:block;height:16px;border-radius:2px;background:var(--surface-2);}
.nb-cmp-track i{display:block;height:100%;border-radius:2px;background:var(--line-2);}
.nb-cmp-n{font-family:'JetBrains Mono',monospace;font-size:12px;color:var(--ink-3);
  min-width:52px;text-align:right;}
.nb-cmp-bar.you .nb-cmp-who{color:var(--ink);font-weight:500;}
.nb-cmp-bar.you .nb-cmp-track i{background:var(--brass);}
.nb-cmp-bar.you .nb-cmp-n{color:var(--brass);font-weight:600;}
.nb-cmp-foot{font-size:12.5px;color:var(--ink-3);margin-top:16px;}

/* ══ THE CARD WHEN THE DAILY IS DONE ══
   A dialog, so Escape closes it, focus stays inside it and the board
   behind it is inert. Four things that would each have to be built and
   each be got wrong. */
/* margin:auto is what centres a modal dialog against its inset:0 box, and
   the global reset in styles.css sets every margin to zero, so it has to be
   said again here or the card opens in the top left corner. */
.nb-pop{border:1px solid var(--line);border-radius:6px;background:var(--surface);
  color:var(--ink);padding:0;margin:auto;max-width:400px;width:calc(100% - 32px);
  max-height:calc(100dvh - 48px);overflow:auto;
  box-shadow:0 20px 60px -24px var(--ink);}
.nb-pop::backdrop{background:rgba(0,0,0,.55);}
html[data-theme="dark"] .nb-pop::backdrop{background:rgba(0,0,0,.72);}
.nb-pop-in{padding:26px 24px 22px;text-align:center;}
.nb-pop h3{font-family:'Newsreader',serif;font-size:24px;font-weight:600;
  color:var(--ink);margin:0 0 4px;}
.nb-pop p{font-size:13.5px;line-height:1.6;color:var(--ink-2);margin:0 0 10px;}
.nb-pop-tally{font-family:'JetBrains Mono',monospace;font-size:13px;
  letter-spacing:.08em;color:var(--ink-3)!important;margin-bottom:16px!important;}
.nb-pop-note{font-size:12.5px;color:var(--ink-3);margin:14px 0 0!important;}

/* The grid the copy button copies, so the button is not a promise. */
/* A picture of what the share button sends, in the board's own colours.
   The text it copies uses three squares of one size; those are emoji, and
   a black one on a dark page cannot be seen, so the preview is drawn. */
.nb-pop-grid{display:flex;flex-direction:column;align-items:center;gap:3px;
  margin:18px 0;}
.nb-pop-grid div{display:flex;gap:3px;}
.nb-pop-grid i{width:13px;height:13px;border-radius:2px;display:block;}
.nb-pop-grid i.exact{background:var(--accent);}
.nb-pop-grid i.near{background:var(--brass);}
.nb-pop-grid i.gone{background:var(--surface-2);box-shadow:inset 0 0 0 1px var(--line);}

/* ══ THE LISTS IN THE DIALOG ══ */
.nb-list{display:flex;flex-direction:column;}
.nb-li{display:flex;align-items:center;gap:10px;padding:9px 2px;
  border-bottom:1px solid var(--line);text-align:left;}
.nb-li:last-child{border-bottom:0;}
.nb-rank{font-family:'JetBrains Mono',monospace;font-size:11px;color:var(--ink-3);
  width:18px;flex-shrink:0;}
.nb-li-who{flex:1;min-width:0;}
.nb-li-name{display:block;font-size:13.5px;color:var(--ink);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;}
.nb-li-sub{display:block;font-family:'JetBrains Mono',monospace;font-size:9.5px;
  letter-spacing:.04em;color:var(--ink-3);margin-top:2px;}
.nb-li-score{font-family:'JetBrains Mono',monospace;font-size:13.5px;font-weight:600;
  color:var(--brass);flex-shrink:0;}
.nb-none{font-size:13px;color:var(--ink-3);font-style:italic;padding:10px 0;}

/* ══ THE FIGURES, WHEN A DAILY IS DONE ══
   Four numbers across, the shape every daily game uses, because four
   numbers in a row are read at a glance and four numbers in a list are
   read one at a time. All time: how many of this game's dailies have been
   solved, how often a started one got finished, the longest run, and how
   long solving one usually takes. */
.nb-figs-head{font-family:'JetBrains Mono',monospace;font-size:9.5px;
  letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);
  text-align:left;margin:22px 0 10px;}
.nb-tiles-4{display:grid;grid-template-columns:repeat(4,1fr);gap:6px;}
.nb-stat{display:flex;flex-direction:column;align-items:center;gap:2px;}
.nb-stat b{font-family:'Newsreader',serif;font-size:24px;font-weight:600;
  line-height:1.1;color:var(--ink);}
.nb-stat i{font-family:'JetBrains Mono',monospace;font-size:8.5px;
  letter-spacing:.09em;text-transform:uppercase;color:var(--ink-3);
  font-style:normal;text-align:center;}

/* ══ WHAT THE CARD SAYS BACK ══
   Brass, which is the colour this site uses to mean look here, and heavy
   enough to be seen against the grey the rest of the card is written in.
   The height is held whether there is anything in it or not, so a
   confirmation appearing does not shove the buttons down. */
.nb-said{min-height:18px;margin:10px 0 0!important;font-size:13px;
  font-weight:500;color:var(--brass)!important;text-align:center;}
.nb-said.bad{color:var(--neg)!important;}

/* ══ NOTHING OF THAT WAS KEPT ══
   The one moment on the page that has earned the right to ask. */
.nb-signup{margin-top:20px;padding-top:18px;border-top:1px solid var(--line);}
.nb-signup p{margin:0 0 4px;font-size:15px;color:var(--ink);}
.nb-signup .nb-pop-note{margin:0 0 14px!important;}
.nb-signup .btn{display:inline-block;}

/* ══ MORE TO PLAY ══ */
.nb-else-head{margin-top:26px;}
.nb-pop-in .gm-list{max-width:none;margin-top:12px;grid-template-columns:1fr 1fr;}
.nb-pop-in .gm-card-face{padding:18px 10px 14px;gap:8px;}
.nb-pop-in .gm-card-mark svg{width:30px;height:30px;}
.nb-pop-in .gm-card-name{font-size:14.5px;}
.nb-pop-in .gm-card-foot{padding:8px;}
.nb-pop-in .gm-pill{padding:6px 10px;font-size:11.5px;}

/* ══ THE HOW-TO, INSIDE THE DIALOG ══
   Left aligned, because prose that is centred is prose nobody finishes:
   every line starts in a different place and the eye has to find it again.
   Short, for the same reason. Written as copy in each game's own page and
   lifted in here, so it stays where it can be edited as copy. */
.nb-pop-in h4{font-family:'Newsreader',serif;font-size:15.5px;font-weight:600;
  color:var(--ink);margin:20px 0 8px;text-align:left;}
.nb-pop-in ul{margin:0 0 10px;padding-left:18px;text-align:left;}
.nb-pop-in li{font-size:13px;line-height:1.6;color:var(--ink-2);margin-bottom:5px;}
.nb-pop-in b{color:var(--ink);font-weight:600;}

/* The how-to is the one card that is a column of text rather than a column
   of figures, so it is the one card that is read rather than scanned. */
.nb-pop-help{text-align:left;}
.nb-pop-help h3{text-align:left;}
.nb-pop-help p{text-align:left;}
.nb-pop-help .nb-acts{justify-content:flex-start;}

/* A swatch and what it means, on one line. */
.nb-key{display:flex;align-items:center;gap:12px;margin:0 0 9px;}
.nb-key .nb-eg{margin:0;flex-shrink:0;}
.nb-key p{margin:0;font-size:13px;line-height:1.5;}
.nb-help-foot{margin-top:14px!important;font-size:12.5px!important;
  color:var(--ink-3)!important;}

.nb-pop-in .nb-eg{display:flex;gap:5px;--nb-size:30px;}

@media (max-width:640px){
  .nb-game{padding:8px 10px 10px;}
  .nb-bar{margin-bottom:6px;}
  .nb-counts{width:58px;gap:7px;font-size:12.5px;}
  .nb-pad{gap:5px;}
  .nb-k{padding:12px 0;font-size:15px;}
  .nb-tab{padding:6px 12px;}
}

/* Buttons on this page are buttons rather than links, and a button does not
   inherit the page's face on its own. */
button.btn{font-family:inherit;}


/* ══ THE OTHER GAMES, AS A TAB ══
   Not a board, so it takes the space a board would and centres what it has.
   It scrolls inside itself on a short screen for the same reason the board
   does: the page cannot scroll, so something has to give and it must not be
   the bar the tab lives in. */
.nb-other{flex:1;min-height:0;overflow:auto;width:100%;max-width:720px;
  display:flex;flex-direction:column;justify-content:center;padding:4px 0;}
.nb-other .gm-list{max-width:none;margin:0;}
