/* 18xx.guide — one stylesheet for screen and paper.
   The print rules own the page geometry; guides must not override them. */

/* Warm paper, a white card on top of it, and a green tint: the colors the
   sheets have always been printed in, now the site's everywhere rather than
   the guides' alone. A guide overrides the tint with a color from its own
   rulebook, and its sheet overrides the paper by painting itself --card. */
:root {
  --paper: #fbfaf7;
  --card: #ffffff;
  --ink: #16201c;
  --muted: #5d6a63;
  --rule: #d8d6cf;
  --tint: #0e5c40;
  /* The tile colors, the same in every guide. */
  --tile-yellow: #fee700;
  --tile-green: #70bf44;
  --tile-brown: #c97645;
  --tile-russet: #dd5028;
  --tile-gray: #c9c9c9;
  --tile-red: #dc3b30;
  --tile-blue: #2eb6e8;
  --tile-edge: #333333;
  --rail: #111111;
  --casing: #ffffff;
  --halt: #a8a8a8;
  color-scheme: light dark;
}

/* The tint is not restated here: it is light enough to survive, and `body`
   below lifts it the rest of the way for the dark card. */
@media (prefers-color-scheme: dark) {
  :root {
    --paper: #101512;
    --card: #171d19;
    --ink: #e6ece8;
    --muted: #94a29a;
    --rule: #2c3630;
    --tile-edge: #0d100e;
  }
}

/* The green is a guide's color—a sheet that has not said otherwise—and the
   listing is not a guide. It takes the near-black rail of tile 881, the tile
   the favicon is cut from, and in the dark that tile's gray hex instead,
   since the rail cannot lighten. Only the tint: the paper is the site's. */
body.listing { --tint: #110a0c; }

@media (prefers-color-scheme: dark) {
  body.listing { --tint: #a9afb2; }
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  --accent: var(--tint);
  --accent-soft: color-mix(in srgb, var(--tint) 11%, #fff);
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 16px/1.5 "IBM Plex Sans", ui-sans-serif, -apple-system,
    "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-variant-numeric: tabular-nums;
}

@media (prefers-color-scheme: dark) {
  body {
    --accent: color-mix(in oklab, var(--tint) 58%, white);
    --accent-soft: color-mix(in srgb, var(--tint) 34%, var(--card));
  }
}

a { color: var(--accent); }

/* ---------- site chrome (screen only) ---------- */

.chrome {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  align-items: baseline;
  padding: 0.7rem clamp(0.75rem, 4vw, 2rem);
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--rule);
}
/* Bebas carries no lowercase, so the logo sets as caps; it has one weight,
   and at this size it wants tracking rather than the tightening it gets on a
   sheet's number. */
.chrome a.home {
  font-family: "Bebas Neue", ui-sans-serif, sans-serif;
  font-size: 1.35rem;
  font-weight: 400;
  letter-spacing: 0.06em;
  text-decoration: none;
}
.chrome .spacer { flex: 1; }
.chrome button {
  font: inherit;
  font-size: 0.85rem;
  padding: 0.25rem 0.7rem;
  color: var(--ink);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 999px;
  cursor: pointer;
}
.chrome button:hover { border-color: var(--accent); color: var(--accent); }
.chrome .hint { font-size: 0.8rem; color: var(--muted); }
/* The PDF is the sheet as it was measured, so it is the one to print. */
.chrome a.pdf {
  font-size: 0.85rem;
  padding: 0.25rem 0.7rem;
  color: var(--paper);
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 999px;
  text-decoration: none;
  white-space: nowrap;
}
.chrome a.pdf:hover { background: var(--ink); border-color: var(--ink); }

/* ---------- the sheet ---------- */

.sheet {
  background: var(--card);
  color: var(--ink);
  max-width: 62rem;
  margin: clamp(0.75rem, 3vw, 2rem) auto;
  padding: clamp(1rem, 3vw, 1.6rem);
  border: 1px solid var(--rule);
  border-radius: 3px;
  font-size: 0.9rem;
  line-height: 1.38;
}

.sheet > header {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.6em;
  border-bottom: 2px solid var(--accent);
  padding-bottom: 0.35em;
}
/* Bebas has one weight and a tall cap-height, so it wants no synthetic bold,
   a touch of tracking rather than the tightening a grotesque wanted, and a
   size bump to hold its own against the subtitle beside it. */
.sheet > header h1 {
  font-family: "Bebas Neue", ui-sans-serif, sans-serif;
  font-size: 2.5em;
  font-weight: 400;
  letter-spacing: 0.01em;
  margin: 0;
}
/* The game's name and its designer are presented the same way on the listing
   as on a sheet: Newsreader, the name in ink, the designer muted beside it. */
.sheet > header .sub,
ul.guides .title {
  font-family: "Newsreader", ui-serif, Georgia, serif;
}
ul.guides .title { font-size: 1.1rem; }
.sheet > header .sub { font-size: 1.32em; }
.sheet > header .sub .by { font-size: 0.86em; }
.sheet > header .sub .name,
ul.guides .name { font-weight: 500; }
.sheet > header .sub .by,
ul.guides .by { color: var(--muted); }
.sheet > header .right { margin-left: auto; color: var(--muted); font-size: 0.9em; }

.strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5em 1.8em;
  margin: 0.55em 0;
  padding: 0.45em 0.7em;
  background: var(--accent-soft);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  font-size: 0.95em;
}
.strip p { margin: 0; flex: 1 1 16em; }
.strip b { color: var(--accent); }

.sprite { display: none; }
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}
/* Sized to sit beside a digit. Safari needs the explicit box, not just the
   viewBox, or it falls back to the default replaced-element size. */
.person {
  display: inline-block;
  width: 0.6em;
  height: 0.78em;
  margin-left: 0.14em;
  fill: currentColor;
  vertical-align: -0.03em;
}

table.setup { border-collapse: collapse; }
table.setup th,
table.setup td { padding: 0.02em 0 0.02em 1em; text-align: right; white-space: nowrap; }
table.setup tr:first-child th { color: var(--muted); font-weight: 400; }
table.setup th:first-child {
  padding-left: 0;
  font-weight: 700;
  color: var(--accent);
}

/* multi-column reference body */
.flow {
  columns: 18rem;
  column-gap: 1.4em;
  margin-top: 0.6em;
}
.block {
  break-inside: avoid;
  margin: 0 0 0.6em;
}
.block h2 {
  margin: 0 0 0.25em;
  font-size: 0.92em;
  font-weight: 400;
  text-transform: uppercase;
  color: var(--accent);
}
/* The label says which round the block belongs to, so it only has to read as
   a different word from the title beside it—weight does that, and the heading
   drops to regular so the weight has something to tell against. Nothing is
   drawn: a painted chip had to hang off the line box to cost the sheet no
   height, and ink outside the line box is clipped away on the one heading per
   column that sits flush with the top of its column box. */
.block h2 .tag {
  margin-right: 0.3em;
  font-weight: 700;
}
/* The marker is painted rather than set, because `list-style: square` hands
   the glyph's size and position to the engine and this sheet is measured to
   the pixel in two of them. A background square is the same everywhere, and
   it costs the item no width: the indent is the item's own padding. */
.block ul { margin: 0; padding-left: 0.1em; list-style: none; }
.block li {
  /* How far down the box the square starts. Measured, its centre sits 0.367em
     above the baseline in both media: a shade above the midline of the first
     line's capitals, and well above the x-height midline a bullet is usually
     hung from. Every item on these sheets opens with a capital, so a capital
     is what the square has to sit against. The offset is taken from the top
     of the box, so it carries the half-leading—the only part of this that
     differs between screen and paper, and the whole of what the print value
     below re-measures. */
  --dot: 0.5em;
  margin-bottom: 0.1em;
  padding-left: 0.75em;
  /* Lightened toward the page rather than toward white, so it fades the same
     amount on a dark card as on paper: the marker is a pointer, and at full
     accent it competed with the headings for the eye. */
  --marker: color-mix(in srgb, var(--accent) 60%, var(--card));
  background: linear-gradient(var(--marker), var(--marker)) no-repeat
    left var(--dot) / 0.35em 0.35em;
}

/* full-width tables */
table.wide {
  width: 100%;
  border-collapse: collapse;
  margin-top: 0.45em;
  font-size: 0.88em;
}
table.wide caption {
  text-align: left;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--accent);
  font-size: 0.92em;
  padding-bottom: 0.15em;
}
table.wide th {
  text-align: left;
  white-space: nowrap;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-size: 0.9em;
  border-bottom: 1px solid var(--ink);
  padding: 0.15em 0.5em 0.15em 0;
}
table.wide td {
  padding: 0.09em 0.5em 0.09em 0;
  border-bottom: 1px solid var(--rule);
  vertical-align: top;
}
/* A number and its unit never split across lines. */
table.wide td.n, table.wide th.n {
  text-align: right;
  padding-right: 0.9em;
  white-space: nowrap;
}
table.wide td.nw, table.wide th.nw { white-space: nowrap; }
.pair { display: flex; flex-wrap: wrap; gap: 0.4em 1.4em; align-items: start; }
.pair > * { flex: 1 1 14em; }
.pair > .grow { flex-grow: 2.2; }

/* A table has a width below which it cannot wrap. On a phone it scrolls
   inside itself rather than pushing the page sideways. */
@media screen and (max-width: 44rem) {
  table.wide { display: block; overflow-x: auto; }
}

.foot {
  margin-top: 0.5em;
  color: var(--muted);
  font-size: 0.85em;
}

/* ---------- tile manifest ---------- */

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4em 1.2em;
  align-items: center;
  margin: 0.5em 0 0.7em;
  font-size: 0.9em;
  color: var(--muted);
}
.legend .key { display: inline-flex; align-items: center; gap: 0.35em; color: var(--ink); }
/* Drawn with borders, not fills, so they survive a printer with background
   graphics turned off. */
.legend .dot {
  width: 0;
  height: 0;
  border: 0.36em solid var(--rail);
  border-radius: 50%;
}
.legend .dot.city {
  width: 0.46em;
  height: 0.46em;
  border: 1.5px solid var(--rail);
  background: var(--casing);
}
.legend .dot.halt { border-color: var(--halt); }
.legend .gauge { width: 1.5em; height: 0; border-top: 0.34em solid var(--rail); }
.legend .gauge.narrow { border-top-style: dashed; }
.legend .gauge.dual {
  height: 0.18em;
  background: var(--casing);
  border-top: 0.08em solid var(--rail);
  border-bottom: 0.08em solid var(--rail);
}

.group-head {
  display: flex;
  align-items: baseline;
  gap: 0.5em;
  margin: 0.6em 0 0.3em;
  font-size: 0.92em;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--accent);
}
.group-head .count { color: var(--muted); font-weight: 400; letter-spacing: 0.02em; }

/* Each color is a section, and the sections flow: one that does not fill a
   line leaves room for the next to start beside it rather than below. A
   group of one tile then costs a column, not a row. For that the cell has to
   be a fixed width—a section sized to its content cannot also size its
   content to itself—so `--cell` is set from the page geometry below, and the
   tracks are laid at that width rather than stretched to fill. */

/* On screen the manifest is a stack of sections, each as wide as the page and
   reflowing to whatever the window gives it. On paper the page is a fixed box
   and the sections flow instead—see the print rules. */
.grid {
  display: grid;
  --tile-gap: 0.4em;
  grid-template-columns: repeat(auto-fill, minmax(4.6rem, 1fr));
  gap: 0.35em var(--tile-gap);
}
.cell { margin: 0; text-align: center; }
/* A double tile covers two hexes, so its cell takes two columns. Two columns
   and the gap between them are wider than the drawing needs: it is 362 units
   across where a single tile is 212, so it wants 362/424 of the two columns
   alone. Size it from the cell and the gap goes into the hexes, which then
   come out half again too big beside everyone else's. */
.cell.double { grid-column: span 2; }
.cell.double svg {
  width: calc(0.8538 * (100% - var(--tile-gap)));
  margin: 0 auto;
}
/* A tile is looked up by its number, so the number wants to be findable at
   arm's length across a table—but 1849 caps how far this can go. Its manifest
   is the fullest in the set and its back sheet has 19px of slack at the old
   0.78em and 0.3em gap; this size and that gap spend 13 of them, and 0.86em
   or a 0.4em gap would spend the lot. */
.cell figcaption {
  margin-top: 0.1em;
  font-size: 0.84em;
  line-height: 1.2;
}
.cell figcaption i { color: var(--muted); font-style: normal; display: block; }

/* A tile is drawn by 18xx.games' own renderer, in a hex of radius 100, and
   every width and position in it is theirs — see tools/tiles.mjs. What is the
   site's is the ink: they draw a tile in two colors, the rail's and the
   paper's, and each element arrives carrying which of the two it asked for. */
svg.tile { display: block; width: 100%; height: auto; }
/* The ring around a city circle is inherited from the group, not set on the
   circle, so its width belongs here. Anything that sets its own width, which
   is every piece of track at the gauge it is drawn in, keeps it: an attribute
   on the element beats a value inherited from an ancestor. A revenue circle is
   a third of the size and takes a finer ring, and text is not outlined at all. */
svg.tile > g { stroke-width: 3; }
svg.tile .badge { stroke: var(--rail); stroke-width: 1.5; }
svg.tile text { stroke: none; }
svg.tile .fill-rail   { fill: var(--rail); }
svg.tile .fill-paper  { fill: var(--casing); }
svg.tile .fill-halt   { fill: var(--halt); }
svg.tile .stroke-rail { stroke: var(--rail); }
svg.tile .stroke-paper { stroke: var(--casing); }
/* An off-board prints a strip of what it pays, one cell per phase. */
svg.tile .fill-yellow { fill: var(--tile-yellow); }
svg.tile .fill-green  { fill: var(--tile-green); }
svg.tile .fill-russet { fill: var(--tile-russet); }
svg.tile .fill-brown  { fill: var(--tile-brown); }
svg.tile .fill-gray   { fill: var(--tile-gray); }
svg.tile .fill-red    { fill: var(--tile-red); }
svg.tile .fill-blue   { fill: var(--tile-blue); }
svg.tile .face { stroke: var(--tile-edge); stroke-width: 2.5; }
svg.tile.yellow .face { fill: var(--tile-yellow); }
svg.tile.green  .face { fill: var(--tile-green); }
svg.tile.russet .face { fill: var(--tile-russet); }
svg.tile.brown  .face { fill: var(--tile-brown); }
svg.tile.gray   .face { fill: var(--tile-gray); }
svg.tile.red    .face { fill: var(--tile-red); }
svg.tile.blue   .face { fill: var(--tile-blue); }
/* A tile's own text is set in the site's faces: the revenue in the sans, the
   hex letter in the serif. Newsreader is loaded to 600, so the letter takes
   its weight there rather than the 800 a variable sans would have given. */
svg.tile .value {
  fill: var(--rail);
  font-family: "IBM Plex Sans", ui-sans-serif, sans-serif;
  font-size: 22px;
  font-weight: 600;
  text-anchor: middle;
  dominant-baseline: central;
}
svg.tile .label {
  fill: var(--rail);
  font-family: "Newsreader", ui-serif, Georgia, serif;
  font-size: 14px;
  font-weight: 600;
  text-anchor: middle;
  dominant-baseline: central;
}

/* ---------- index ---------- */

.wrap { max-width: 46rem; margin: 0 auto; padding: 2rem clamp(1rem, 5vw, 2rem) 4rem; }
/* The page served for an address that misses. */
.gone {
  font-family: "Newsreader", ui-serif, Georgia, serif;
  font-size: 1.6rem;
  font-weight: 500;
  margin: 3rem 0 0.6rem;
}
.gone-sub { color: var(--muted); margin: 0; max-width: 32rem; }
/* One grid for the whole list, so the number column is as wide as the longest
   number in it and no wider, and every title lines up. Each row is a subgrid
   of that, so the link can still span both columns and carry the rule and the
   hover. A name far longer than a year—marked .wide, since nothing in CSS can
   count its letters—would push every title right to make room for it, so its
   row leaves the grid and sets its title just after it instead. */
ul.guides {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: 1.1rem;
}
ul.guides li { display: contents; }
ul.guides a {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
  align-items: center;
  padding: 0.9rem 0.2rem 0.9rem 0.6rem;
  border-top: 1px solid var(--rule);
  text-decoration: none;
  color: inherit;
}
ul.guides a:has(> .num.wide) {
  display: flex;
  gap: 1.1rem;
}
ul.guides li:last-child a { border-bottom: 1px solid var(--rule); }
ul.guides a:hover { background: var(--accent-soft); }
ul.guides .num {
  font-family: "Bebas Neue", ui-sans-serif, sans-serif;
  font-size: 2.2rem;
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--accent);
}
/* Title and designer are one block, so the year centers against both, and
   the designer always sits on a line of their own beneath the name. */
ul.guides .title {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  min-width: 0;
}
ul.guides .by { font-size: 0.86em; }

/* ---------- print ---------- */

/* Small, because Safari reserves room for its headers and footers inside the
   page box. At 0.4in a 9.8in sheet no longer fits an 11in page once Safari
   has taken its cut, and the sheet spills a sliver onto a page of its own—
   Chromium clips the same overflow instead, so its PDF never shows it. */
@page { margin: 0.2in; }

@media print {
  .chrome, .screen-only { display: none !important; }
  /* The markers are painted, so a printer's "no background graphics" would
     drop them and leave the items unmarked. */
  .block li {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  /* Paper's leading is tighter, so the whole line sits 0.13em nearer the top
     of the box and the square follows it up. */
  .block li { --dot: 0.37em; }
  body {
    background: #fff;
    color: #16201c;
    --paper: #fff;
    --card: #fff;
    --ink: #16201c;
    --muted: #5d6a63;
    --rule: #c9c7c0;
    --accent: var(--tint);
    --accent-soft: color-mix(in srgb, var(--tint) 11%, #fff);
    --tile-edge: #333;
  }
  .sheet {
    width: 7.3in;
    height: 9.5in;
    max-width: none;
    margin: 0.3in auto 0;
    padding: 0 0.06in;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    overflow: hidden;
    font-size: 7.4pt;
    line-height: 1.17;
  }
  .sheet + .sheet {
    break-before: page;
    page-break-before: always; /* Safari still wants the old name */
  }
  /* Longhand, and the column width explicitly cleared: the screen rule sets
     a width (18rem) rather than a count, and a browser that keeps it would
     fit two columns to a 7.3in sheet instead of three. */
  .flow {
    column-count: 3;
    column-width: auto;
    column-gap: 0.22in;
  }
  /* Each color is a section, and on paper the sections flow: one that does not
     fill a line leaves room for the next to start beside it rather than
     below, so a group of one tile costs a column and not a row.
     That needs a cell of fixed width—a section sized to its content cannot
     also size its content to itself—and the sheet is a known box, so the cell
     is arithmetic: 7.3in less its 0.06in of side padding, split into as many
     columns as the guide asks for, less the gaps between them. How many
     columns a section takes is written into its grid by the build; `auto-fill`
     cannot work it out, having no width to divide. */
  .manifest {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    column-gap: 1.2em;
  }
  /* The gap under the legend used to be its bottom margin collapsed with the
     first group heading's top margin—the larger of the two. A flex item's
     margins don't collapse, so the two would now stack; let the heading's
     margin stand for both. */
  .legend { margin-bottom: 0; }
  .group {
    flex: 0 0 auto;
    max-width: 100%;
  }
  .grid {
    --cell: calc(
      (7.18in - (var(--tile-columns, 8) - 1) * var(--tile-gap)) /
        var(--tile-columns, 8)
    );
    grid-template-columns: repeat(var(--cols, 8), var(--cell));
  }
}
