/* ------------------------------------------------------------------
   Frontier lab revenue forecasts

   Palette carries meaning rather than decoration:
     crimson = you, teal = the crowd, amber = the resolved outcome,
     ink = the recorded past.
   Type is the IBM Plex superfamily — Condensed for headings, Sans for
   prose, Mono for every figure, because the figures are the content.
   ------------------------------------------------------------------ */

@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans+Condensed:wght@600;700&family=IBM+Plex+Sans:ital,wght@0,400;0,500;0,600;1,400&display=swap');

:root {
  --ground: #eaeef4;
  --surface: #ffffff;
  --surface-sunk: #f4f6fa;
  --ink: #0f1528;
  --ink-soft: #5a6480;
  --ink-faint: #8b93a8;
  --rule: #d2d8e4;
  --rule-soft: #e4e8f0;

  --you: #cf1259;
  --you-wash: rgba(207, 18, 89, 0.12);
  --crowd: #0d7a84;
  --crowd-wash: rgba(13, 122, 132, 0.14);
  --actual: #b57608;
  --warn: #9a4a00;
  --warn-bg: #fdf3e4;

  --display: 'IBM Plex Sans Condensed', 'Helvetica Neue', sans-serif;
  --body: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  --gap: 1.5rem;
  --radius: 3px;
  --measure: 68ch;
}

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

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

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font: 400 16px/1.6 var(--body);
  /* The faintest decade rules, echoing a log-paper grid. */
  background-image: repeating-linear-gradient(
    to bottom, transparent 0 63px, rgba(15, 21, 40, 0.035) 63px 64px);
}

.wrap {
  max-width: 980px;
  margin: 0 auto;
  padding: 0 1.25rem 6rem;
}

/* ------------------------------------------------------------ masthead */

.masthead {
  padding: 3rem 0 1.5rem;
  border-bottom: 2px solid var(--ink);
  margin-bottom: 2rem;
}

.eyebrow {
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 1rem;
}

/* One line, at every width.
 *
 * There is no max-width; a measure of 18ch was what broke the title across
 * two lines. The size is capped for looks and otherwise tracks the viewport,
 * because the title has to fit the column rather than the screen. Measured in
 * the condensed face, the title sets about 12.5x its font-size wide, and the
 * column is the viewport less 2.5rem of gutter — so 7.4vw less a few pixels
 * clears it with roughly 6% to spare at every width, scrollbar included.
 *
 * Deliberately no `white-space: nowrap`: if the webfont fails to load, the
 * fallback is not condensed and sets much wider, and wrapping is a far better
 * failure than shoving the whole page sideways.
 */
.masthead h1 {
  font: 700 min(4.25rem, 7.4vw - 3px)/0.98 var(--display);
  letter-spacing: -0.015em;
  margin: 0 0 0.6rem;
}

.masthead .standfirst {
  font-size: 1.125rem;
  color: var(--ink-soft);
  max-width: var(--measure);
  margin: 0;
}

/* -------------------------------------------------------------- blocks */

section { margin-bottom: 3rem; }

h2 {
  font: 700 1.55rem/1.15 var(--display);
  letter-spacing: -0.01em;
  margin: 0 0 0.75rem;
}

h3 {
  font: 600 1.1rem/1.25 var(--display);
  margin: 0 0 0.5rem;
}

p { max-width: var(--measure); }

a { color: var(--crowd); text-decoration-thickness: 1px; text-underline-offset: 2px; }

.card {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 1.5rem;
  margin-bottom: 1.25rem;
}

.card--flush { padding: 1.25rem 1.5rem; }

.note {
  font-size: 0.875rem;
  color: var(--ink-soft);
  max-width: var(--measure);
}

.tag {
  display: inline-block;
  font: 500 10px/1 var(--mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 4px 7px;
  border: 1px solid currentColor;
  border-radius: 2px;
  vertical-align: 2px;
}

.tag--optional { color: var(--ink-faint); }
.tag--resolved { color: var(--actual); }

/* Definition strip used to explain the two revenue series. */
.defs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
}

.defs > div { background: var(--surface); padding: 1.1rem 1.25rem; }
.defs dt { font: 600 0.95rem/1.3 var(--body); margin-bottom: 0.35rem; }
.defs dd { margin: 0; font-size: 0.875rem; color: var(--ink-soft); }
.defs .figure { font: 600 1.6rem/1 var(--mono); display: block; margin-bottom: 0.5rem; }

/* --------------------------------------------------------------- forms */

.field { margin-bottom: 1.25rem; }

label {
  display: block;
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 0.4rem;
}

input[type="text"], textarea {
  width: 100%;
  font: 400 1rem/1.4 var(--body);
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 0.6rem 0.7rem;
}

input[type="number"] {
  width: 100%;
  font: 500 1.05rem/1.3 var(--mono);
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 0.55rem 0.6rem;
  text-align: right;
  -moz-appearance: textfield;
}

input:focus-visible, textarea:focus-visible, button:focus-visible {
  outline: 2px solid var(--you);
  outline-offset: 1px;
}

.honey { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* Three percentile inputs in a row. */
.triple {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.75rem;
  margin: 1rem 0 0.5rem;
}

.triple .cell label { margin-bottom: 0.35rem; }
.triple .cell .hint { font: 400 0.75rem/1.3 var(--body); color: var(--ink-faint); margin-top: 0.3rem; }

.unit-prefix { position: relative; }
.unit-prefix::before {
  content: '$';
  position: absolute;
  left: 0.6rem;
  top: 50%;
  transform: translateY(-50%);
  font: 500 0.95rem var(--mono);
  color: var(--ink-faint);
  pointer-events: none;
}
.unit-prefix input { padding-left: 1.4rem; }

button {
  font: 600 0.95rem/1 var(--body);
  border-radius: var(--radius);
  border: 1px solid var(--ink);
  background: var(--ink);
  color: #fff;
  padding: 0.75rem 1.4rem;
  cursor: pointer;
}

button:hover { background: #1d2743; }

button.ghost {
  background: transparent;
  color: var(--ink);
  border-color: var(--rule);
}
button.ghost:hover { background: var(--surface-sunk); }

button.small { padding: 0.45rem 0.8rem; font-size: 0.85rem; }

button:disabled { opacity: 0.45; cursor: not-allowed; }

.actions {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 1.5rem;
}

.error {
  color: var(--you);
  font-size: 0.875rem;
  margin-top: 0.5rem;
}

.callout {
  background: var(--warn-bg);
  border-left: 3px solid var(--warn);
  color: var(--warn);
  padding: 0.8rem 1rem;
  font-size: 0.875rem;
  border-radius: 0 var(--radius) var(--radius) 0;
  margin-top: 1rem;
}

/* ---------------------------------------------------------- questions */

/* All the questions live in one card, divided by rules rather than by gaps
   between separate boxes. */
.questions .question + .question {
  border-top: 1px solid var(--rule);
  margin-top: 1.5rem;
  padding-top: 1.5rem;
}

.q-legend { display: none; }
.col-label {
  display: block;
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* Given the width, a question is one row: its title beside its three boxes.
   Below this the boxes stack, and a title sitting alongside a column of three
   inputs reads as a heading for the first one. */
@media (min-width: 760px) {
  .questions .question,
  .q-legend {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.45fr);
    column-gap: 1.75rem;
    align-items: center;
  }

  .q-legend { display: grid; align-items: end; margin-bottom: 0.75rem; }
  .q-legend .hint { margin: 0.3rem 0 0; }

  .questions .q-head {
    border-bottom: 0;
    padding-bottom: 0;
    margin-bottom: 0;
    align-items: baseline;
  }
  .questions .q-head h3 { margin: 0; }
  .questions .triple { margin: 0; }

  /* Stated once in the column headings above. Kept in the markup, and kept
     reachable, for anyone not reading by eye. */
  .questions .question .cell label,
  .questions .question .cell .hint {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* Anything a question says after the fact lines up under its boxes. */
  .questions .question > .nudge,
  .questions .question > .error,
  .questions .question > .resolution {
    grid-column: 2;
  }
  .questions .question > .resolution { margin-top: 0.6rem; }
}

.q-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  border-bottom: 1px solid var(--rule-soft);
  padding-bottom: 0.6rem;
  margin-bottom: 0.9rem;
}

.q-index {
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.1em;
  color: var(--ink-faint);
  white-space: nowrap;
}

.anchor {
  font-size: 0.875rem;
  color: var(--ink-soft);
  border-left: 2px solid var(--rule);
  padding-left: 0.8rem;
  margin: 0.75rem 0 0;
  max-width: var(--measure);
}

details.resolution { margin-top: 0.9rem; }
details.resolution summary {
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  cursor: pointer;
}
details.resolution p { font-size: 0.875rem; color: var(--ink-soft); margin-top: 0.6rem; }

/* ------------------------------------------------------------- charts */

.chart { width: 100%; height: auto; display: block; overflow: visible; }

/* Six forecast columns plus the recorded years need real width. Below that,
   scroll it sideways rather than shrinking the labels into illegibility —
   the same bargain the wide tables make. */
.chart-scroll { overflow-x: auto; }
@media (max-width: 700px) {
  .chart-scroll { margin: 0 -1.1rem; padding: 0 1.1rem; }
  .chart { min-width: 620px; }
}
.chart text { font-family: var(--mono); }
.axis-label { font-size: 10px; fill: var(--ink-faint); letter-spacing: 0.06em; }
.decade-line { stroke: var(--rule); stroke-width: 1; }
.decade-line--major { stroke: var(--rule); stroke-dasharray: none; }
.hist-line { fill: none; stroke: var(--ink); stroke-width: 1.75; }
.hist-line--rr { stroke: var(--ink-faint); stroke-dasharray: 4 3; stroke-width: 1.5; }
.hist-dot { fill: var(--ink); }
.hist-dot--rr { fill: var(--ink-faint); }

/* Labels sitting above each forecast interval. Small, because the intervals
   are the message. */
.point-label { font-size: 10px; fill: var(--ink-soft); letter-spacing: 0.03em; }
.point-label--empty { fill: var(--ink-faint); opacity: 0.6; }

/* One column per forecast year. The boundaries are the reminder that the
   spacing is per question, not per elapsed year. */
.slot-line { stroke: var(--rule-soft); stroke-width: 1; }
.axis-label--slot { fill: var(--ink-soft); }

/* The chart scrolls with everything else. It was sticky once; holding a third
   of the viewport hostage cost more than the live feedback was worth. */
.chart-card { margin-bottom: 1.25rem; }

.nudge {
  font: 400 0.8rem/1.4 var(--body);
  color: var(--warn);
  margin: 0.5rem 0 0;
}

/* ------------------------------------------------------------- legend */

.legend {
  display: flex;
  gap: 1.25rem;
  flex-wrap: wrap;
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 0.9rem;
}

.legend span { display: inline-flex; align-items: center; gap: 0.4rem; }
/* Wide enough that a dash pattern reads as a pattern, since the recorded
   series are told apart by nothing else. */
.swatch { width: 22px; height: 3px; border-radius: 2px; display: inline-block; flex: none; }
.swatch--you { background: var(--you); }
.swatch--crowd { background: var(--crowd); }
.swatch--hist { background: var(--ink); }
.swatch--actual { background: var(--actual); }

/* --------------------------------------------------------- comparison */

.compare {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1px;
  background: var(--rule-soft);
  border: 1px solid var(--rule-soft);
  border-radius: var(--radius);
  margin-top: 1.25rem;
  overflow: hidden;
}

.compare > div { background: var(--surface); padding: 0.9rem 1rem; }
.compare .who {
  font: 500 10px/1 var(--mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-bottom: 0.5rem;
}
.compare .who--you { color: var(--you); }
.compare .who--crowd { color: var(--crowd); }
.compare .who--actual { color: var(--actual); }
.compare .range { font: 500 0.95rem/1.5 var(--mono); }
.compare .range b { font-weight: 600; font-size: 1.2rem; }

/* ---------------------------------------------------------- leaderboard */

.table-scroll { overflow-x: auto; margin: 0 -1.5rem; padding: 0 1.5rem; }

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}

th {
  font: 500 10px/1.3 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-align: left;
  padding: 0 0.7rem 0.6rem 0;
  border-bottom: 1px solid var(--ink);
  white-space: nowrap;
  vertical-align: bottom;
}

td {
  padding: 0.6rem 0.7rem 0.6rem 0;
  border-bottom: 1px solid var(--rule-soft);
  vertical-align: middle;
}

td.num, th.num { text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums; }
tr.is-you td { background: var(--you-wash); }
tr.is-crowd td { background: var(--crowd-wash); font-weight: 600; }
.rank { font: 600 0.95rem var(--mono); color: var(--ink-faint); }
.who-name { font-weight: 500; }

.strip { display: block; width: 160px; height: 16px; }
.strip-band { stroke: var(--ink-soft); stroke-width: 1.5; }
.strip-dot { fill: var(--ink); }
.strip-band--you { stroke: var(--you); }
.strip-dot--you { fill: var(--you); }

.skill-pos { color: var(--crowd); font-weight: 600; }
.skill-neg { color: var(--ink-soft); }

/* -------------------------------------------------------------- misc */

.count-line {
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.sources { font-size: 0.8rem; color: var(--ink-faint); }
.sources li { margin-bottom: 0.3rem; }

.hidden { display: none !important; }

.spinner { color: var(--ink-faint); font-family: var(--mono); font-size: 0.85rem; }

footer {
  border-top: 1px solid var(--rule);
  padding-top: 1.5rem;
  margin-top: 3rem;
  font-size: 0.8rem;
  color: var(--ink-faint);
}

@media (max-width: 620px) {
  .triple { grid-template-columns: 1fr; gap: 0.6rem; }
  .card { padding: 1.1rem; }
  .table-scroll { margin: 0 -1.1rem; padding: 0 1.1rem; }
}

@media (prefers-reduced-motion: no-preference) {
  .fade-in { animation: fade 0.4s ease both; }
  @keyframes fade { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
}

/* Whisker colours for the outlook chart. These carry the whole legend:
   crimson is the reader, teal is everyone pooled. */
.crowd-band { stroke: var(--crowd); }
.crowd-dot { fill: var(--crowd); }
.you-band { stroke: var(--you); }
.you-dot { fill: var(--you); }
.swatch--rr { background: var(--ink-faint); height: 2px; }
