/* patchwork.css — shared shell for the Patchwork project page and dashboard.
   Hand-written replacement for Bootstrap 4.5.2 + Font Awesome. No JS required.
   Keep this file out of the dashboard's regeneration path so the two pages
   cannot drift apart. */

:root {
  --band:    #ffc107;   /* the site's existing yellow, kept as the identity colour */
  --ink:     #1a1a1a;
  --ink-mid: #55524c;
  --link:    #0a5aa8;
  --link-hi: #7a2f00;
  --rule:    #d8d4cc;
  --paper:   #ffffff;
  --wash:    #f4f2ee;
  --nav-h:   2.9rem;

  /* run outcomes */
  --ok:    #2f7d32;
  --bad:   #b3261e;
  --warn:  #b26a00;
  --idle:  #9a958c;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  padding-top: var(--nav-h);            /* clears the fixed band */
  background: var(--paper);
  color: var(--ink);
  font: 400 1rem/1.6 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Helvetica Neue", Arial, sans-serif;
}

.wrap { max-width: 66rem; margin: 0 auto; padding: 0 1.25rem; }
/* Prose in the wide container had no measure and could run to ~151 characters.
   Headings, tables and figures are exempt: they want the full width. */
.wrap--wide > p, main > .wrap--wide > p { max-width: 74ch; }
.wrap--wide { max-width: 78rem; }

a { color: var(--link); }
a:hover, a:focus { color: var(--link-hi); }
:focus-visible { outline: 3px solid var(--link-hi); outline-offset: 2px; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--ink); color: #fff; padding: .6rem 1rem;
}
.skip:focus { left: 0; color: #fff; }

/* ---- Masthead -------------------------------------------------------- */
.masthead {
  position: fixed; inset: 0 0 auto 0; z-index: 50;
  height: var(--nav-h); background: var(--band);
  box-shadow: 0 1px 0 rgba(0,0,0,.18);
}
.masthead .wrap { display: flex; align-items: center; height: 100%; }
.masthead a { color: var(--ink); font-weight: 600; }   /* 11:1 on the yellow */
.masthead .sep { padding: 0 .6rem; }

.people > summary {
  list-style: none; cursor: pointer; font-weight: 600; color: var(--ink);
  padding: .3rem .5rem; border-radius: 3px;
}
.people > summary::-webkit-details-marker { display: none; }
.people > summary::after { content: " \25BE"; }
.people[open] > summary { background: rgba(0,0,0,.12); }
.people ul {
  position: absolute; margin: .35rem 0 0; padding: .4rem 0; list-style: none;
  min-width: 16rem; background: var(--paper); border: 1px solid var(--rule);
  box-shadow: 0 4px 14px rgba(0,0,0,.15);
}
.people li { padding: .3rem 1rem; }
.people a { text-decoration: none; font-weight: 400; }
.people a:hover { text-decoration: underline; }

/* ---- Hero ------------------------------------------------------------ */
.hero { background: var(--wash); border-bottom: 1px solid var(--rule); padding: 2.5rem 0; }
.hero h1 {
  display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
  margin: 0 0 1rem; font-size: clamp(2.2rem, 6vw, 3.2rem);
  font-weight: 300; letter-spacing: -.02em;
}
.hero h1 img { height: 1.2em; width: auto; }
.hero h1 .beta {
  font-size: .3em; font-weight: 600; letter-spacing: .02em;
  color: var(--bad); align-self: flex-start; padding-top: .6em;
}
.hero p, .hero ul { max-width: 62ch; text-wrap: pretty; }
.hero > .wrap > p:first-of-type { font-size: 1.08rem; }

.note { display: flex; gap: .55rem; align-items: baseline; margin: 1.4rem 0 .4rem; }
.note svg, .note img { flex: none; width: 30px; height: 30px; }
/* Inline SVG icons: no external file, so nothing can 404 and leave a hole. */
.note svg { color: var(--link); }
/* Icon inside a run of text. The margin replaces a literal space, which
   otherwise stacks with the space before the icon and reads as a gap. */
.icon-inline { width: 14px; height: 14px; margin-right: .3em;
               vertical-align: -.15em; }
h2.note { font-size: 1.35rem; }

/* ---- News grid (project page) ---------------------------------------- */
.news {
  display: grid; gap: 2rem 2.5rem;
  grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
  padding: 2.5rem 0 1rem;
}
.entry h2 { margin: 0 0 .5rem; font-size: 1.35rem; font-weight: 600; line-height: 1.25; }
.entry p { margin: 0; }
.entry time { font-weight: 700; font-style: italic; }
.thumbs { margin: 0 0 .85rem; display: flex; gap: .6rem; flex-wrap: wrap; justify-content: center; }
.thumbs img { border: 1px solid #000; height: auto; max-width: 100%; background: var(--paper); }

/* ---- Data table (dashboard) ------------------------------------------ */
.tablewrap { overflow-x: auto; }          /* keyboard-scrollable, see tabindex="0" */
.runs { border-collapse: collapse; width: 100%; margin: 0 0 2rem; }
/* No max-width: the caption sits above a full-width table, and a 62ch cap
   made a one-sentence caption wrap on desktop for no reason. */
.runs caption { text-align: left; padding: 0 0 .75rem; color: var(--ink-mid); }
.runs th, .runs td { padding: .55rem .75rem; text-align: left; vertical-align: middle; }
.runs thead th {
  border-bottom: 2px solid var(--ink); font-size: .82rem; letter-spacing: .04em;
  text-transform: none; white-space: nowrap;
}
.runs tbody tr { border-bottom: 1px solid var(--rule); }
.runs tbody tr:nth-child(even) { background: rgba(128,128,128,.07); }
.runs tbody th { font-weight: 600; white-space: nowrap; }
.runs .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.runs .chart { width: 200px; }
.runs .chart img { display: block; border: 1px solid var(--rule); height: auto; max-width: 100%; }

/* Outcome bar. Percentages arrive as three unitless custom properties;
   the fourth segment (in progress) is whatever remains. */
.bar {
  display: block; height: .5rem; width: 11rem; max-width: 100%; margin-bottom: .3rem;
  border: 1px solid var(--rule);
  background: linear-gradient(to right,
    var(--ok)   0 calc(var(--s) * 1%),
    var(--bad)  0 calc((var(--s) + var(--f)) * 1%),
    var(--warn) 0 calc((var(--s) + var(--f) + var(--d)) * 1%),
    var(--idle) 0 100%);
}
.vals { font-size: .84rem; color: var(--ink-mid); }

.note-link {
  display: inline-block; margin-left: .35rem; padding: 0 .35rem;
  font-size: .78rem; border: 1px solid currentColor; border-radius: 3px;
  text-decoration: none; color: var(--bad);
}
.note-link:hover, .note-link:focus { color: var(--bad); text-decoration: underline; }

.legend { display: flex; flex-wrap: wrap; gap: 1rem; padding: 0; margin: 0 0 1.5rem; list-style: none;
          font-size: .86rem; color: var(--ink-mid); }
.legend li { display: flex; align-items: center; gap: .4rem; }
.legend .swatch { width: .8rem; height: .8rem; border: 1px solid var(--rule); }

/* ---- Footer ---------------------------------------------------------- */
footer { border-top: 1px solid var(--rule); margin-top: 2.5rem; padding: 1.5rem 0 3rem; }
/* No measure cap here: the footer is a one-line credit, not reading matter,
   and a 66ch cap forced the 139-character sentence onto three lines. It now
   fits one line at desktop widths and wraps only when the viewport demands
   it. text-wrap: pretty improves the rag where it does wrap. */
footer p { margin: 0 0 .8rem; color: var(--ink-mid); text-wrap: pretty; }
footer .updated { font-size: .9rem; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ---- Single-run page --------------------------------------------------- */
.runnav { display: flex; gap: 1.25rem; flex-wrap: wrap; font-size: .9rem;
          padding: 1rem 0 0; margin: 0; list-style: none; }
.runnav li { margin: 0; }
.runnav .spacer { flex: 1 1 auto; }

.facts { margin: 0 0 2rem; }
.facts > div { padding: .9rem 0; border-bottom: 1px solid var(--rule); }
.facts dt { font-weight: 600; margin: 0 0 .25rem; }
.facts dd { margin: 0; }
.facts .value { font-size: 1.15rem; font-variant-numeric: tabular-nums; }
/* 68ch is a deliberate reading measure for these multi-sentence caveats, not
   an accident: uncapped they would run to ~151 characters. text-wrap: pretty
   improves where the unavoidable wraps fall. */
.facts .caveat { display: block; margin-top: .4rem; font-size: .88rem;
                 color: var(--ink-mid); max-width: 68ch; text-wrap: pretty; }

.chartfig { margin: 0 0 3rem; }
.chartfig h3 { margin: 0 0 .35rem; font-size: 1.2rem; }
.chartfig .lede { margin: 0 0 .9rem; color: var(--ink-mid); max-width: 68ch;
                  text-wrap: pretty; }
.chartfig img { display: block; max-width: 100%; height: auto;
                border: 1px solid var(--rule); background: var(--paper); }
.chartfig details { margin-top: .75rem; max-width: 68ch; }
.chartfig summary { cursor: pointer; font-size: .9rem; }
.chartfig table { border-collapse: collapse; margin-top: .75rem; font-size: .9rem; }
.chartfig th, .chartfig td { border: 1px solid var(--rule); padding: .3rem .6rem; text-align: left; }
.chartfig .num { text-align: right; font-variant-numeric: tabular-nums; }

/* Run notes. Sits at the top of the hero because it is the only content on
   the page specific to this run. Two kinds, distinguished by icon and fill as
   well as hue -- red and amber are the pair red-green colour blindness
   confuses -- with "alert" carrying more weight than "notice". */
.runnote {
  margin: 0 0 1.5rem; padding: 1rem 1.25rem; max-width: 68ch;
  border: 1px solid; border-left-width: 6px; border-radius: 4px;
}
.runnote h2 {
  display: flex; align-items: center; gap: .5rem;
  margin: 0 0 .4rem; font-size: 1.1rem; font-weight: 700;
}
.runnote h2 svg { flex: none; width: 1.3em; height: 1.3em; }
.runnote p { margin: 0; text-wrap: pretty; color: var(--ink); }

.runnote--alert  { border-color: #b3261e; background: #fdecea; }
.runnote--alert h2 { color: #8c1d16; }          /* 8.0:1 on the tint */
.runnote--notice { border-color: #8a5a00; background: #fff8e1; }
.runnote--notice h2 { color: #6b4600; }         /* 8.6:1 on the tint */

@media print {                                  /* notes must survive printing */
  .runnote { border: 2px solid #000; background: #fff; }
}

.beta-notice { font-size: .9rem; color: var(--ink-mid); max-width: 68ch;
               text-wrap: pretty; }

/* Keep a label and its value on one line: "in progress 0.00%" must not split.
   The renderers also put a non-breaking space inside each pair, so this holds
   even if the stylesheet fails to load. */
.pair { white-space: nowrap; }

/* Note chips. The original used red vs #f5d327 yellow, which are 4.0:1 and
   1.5:1 against white and are also the hue pair that red-green colour
   blindness confuses. The distinction is preserved, but each kind differs by
   FILL as well as hue: "alert" is solid, "notice" is outlined. */
.note-link--alert  { background: #b3261e; border-color: #b3261e; color: #fff; }
.note-link--alert:hover, .note-link--alert:focus  { color: #fff; }
.note-link--notice { background: var(--paper); border-color: #8a5a00; color: #8a5a00; }
.note-link--notice:hover, .note-link--notice:focus { color: #6b4600; }
