/* The site's shared stylesheet. One file, seven pages: the type system and palette first, then
 * the page shell, the data tables and the one phone breakpoint.
 *
 * Every page links this before its own <style>, so anything here can still be overridden by a
 * page that has a reason to — but nothing about the faces or the headings should be. Change a
 * font here and the whole site follows; change it in a page and that page drifts.
 *
 * Three faces, one job each:
 *
 *   --display   opens a section: the masthead and every section heading
 *   --sans      anything meant to be READ: descriptions, blurbs, bullets, prose in boxes
 *   --mono      anything meant to be SCANNED: labels, dates, counts, tags, tables, chips
 *
 * The rule that keeps it from turning into noise: at most two of the three inside any one
 * component. A five-line box carrying all three reads as decoration rather than hierarchy.
 *
 * Trying a new face means editing ONE line below. Keep a real fallback stack on each, because
 * the webfont is a network request that can fail.
 */

@import url("https://fonts.googleapis.com/css2?family=Fragment+Mono&family=Archivo:wght@700&display=swap");

:root{
  /* The page's colours, shared by all seven pages. --accent is the one that carries meaning:
     on this site it means "this responds to you" and nothing else may use it, which is why a
     data colour (the RV green on the challenges page, the club colours, the wheels' blue and
     red) is always declared separately. */
  --bg:#ffffff;
  --text:#1a1a1a;
  --muted:#5a5a5a;
  --accent:#ff6a00;
  --rule:#e2e2e2;
  --panel:#fafafa;

  --mono:"Fragment Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
  --sans:"Helvetica Neue", Helvetica, Arial, sans-serif;
  --display:"Archivo", "Helvetica Neue", Helvetica, Arial, sans-serif;
}

/* The page's default is the monospace: most of what is on these pages is data, and the two
   other faces are opted into by the rules below. */
body{
  font-family:var(--mono);
  font-size:13px;
  line-height:1.45;
  letter-spacing:0.1px;
}

/* The masthead. Archivo has real weights, so this is a true 700 rather than the single-weight
   400 the serif needed. A bold grotesque carries more ink than a display serif at the same
   size, so it comes back down a few px and takes its tracking in. Margins stay with the
   page. */
.title{
  font-family:var(--display);
  font-weight:700; font-size:34px; letter-spacing:-.018em; line-height:1.08;
}

/* Every section heading. Table headings are NOT these — they label data rather than open a
   section, so they take --sans, under DATA TABLES below. Margins stay with the page, which is
   the only thing that legitimately differs between them. */
h2{
  font-family:var(--display);
  font-weight:700; font-size:19px; letter-spacing:-.008em;
  /* Headings set their own leading. Inheriting the body's 1.45 hung about 4px of half-leading
     under the cap, which read as a gap below every heading that no margin could close. */
  line-height:1.2;
}

/* The description under the masthead, and prose generally. The measure is capped in ch, so it
   tracks whatever face --sans is set to rather than a pixel width tuned for one of them. */
.blurb{
  font-family:var(--sans);
  font-size:13.5px; line-height:1.55; letter-spacing:0;
  color:var(--text);
  max-width:74ch;
}

/* ---- tags ----------------------------------------------------------------
 *
 * Words, not chips: no border, no fill, no padding. A tag names what a thing is about, which
 * is a quieter job than anything the accent marks, so it sits in one dark grey and stays out
 * of the way of the work it describes.
 *
 * With the box gone, selection needs its own mark — there is no border left to colour — so a
 * selected tag takes the accent AND an underline, the same pair every link on this site uses.
 */
:root{ --tag-ink:#878787; }

.t[data-tag]{
  background:transparent;
  border:0;
  color:var(--tag-ink);
  padding:0;
  line-height:1.2;
}
.t[data-tag]:hover{ color:var(--accent); }
.t[data-tag][aria-pressed="true"]{
  color:var(--accent);
  text-decoration:underline; text-underline-offset:2px;
}
/* The hash is the same grey as the word it belongs to, and turns with it. */
.t[data-tag] .n{ color:inherit; }

/* ==========================================================================================
 * THE PAGE SHELL
 *
 * Everything below was copy-pasted into all seven pages' own <style> blocks until it lived
 * here. There is no build step, so a shared rule has exactly one home: this file, linked by
 * every page BEFORE its own <style>. That ordering is the whole contract — a page can still
 * override anything here, and several deliberately do, but nothing that is the same on every
 * page belongs in a page any more.
 *
 * What stays in a page: its own --max, the margins on .title/h2/.blurb (the one thing that
 * legitimately differs between them), and whatever that page's content actually is.
 * ========================================================================================== */

:root{
  /* The project pages' measure. The homepage narrows it to 720 and the wheels grid opens it
     to 1080; both say so in their own :root, which is the only place a width should differ. */
  --max:800px;
}

*{ box-sizing:border-box; }
html,body{ height:100%; }
body{
  margin:0;
  background:var(--bg);
  color:var(--text);
}

.wrap{ max-width:var(--max); margin:0 auto; padding:28px 18px 64px; }

/* Underlined, and the accent on hover: the site has one link treatment and this is it. */
a{ color:var(--text); text-decoration:underline; text-underline-offset:2px; }
a:hover{ color:var(--accent); }

/* Every off-site link states where it actually goes, on hover. Pure CSS via attr(href) — no
   script, and no per-link markup that could drift from the href it describes. Opens down and
   to the right; a page whose links sit against its right edge flips this to `right:0`. */
a[href^="http"]{ position:relative; }
a[href^="http"]:hover::after{
  content:attr(href);
  position:absolute; left:0; top:calc(100% + 3px);
  font-size:11px; color:var(--muted); background:var(--bg);
  border:1px solid var(--rule); padding:2px 6px;
  white-space:nowrap; max-width:min(84vw,560px);
  overflow:hidden; text-overflow:ellipsis;
  z-index:20; pointer-events:none;
}

/* The furniture every project page carries: the date it was published, the way back to the
   index, the ~~~ dividers, and the small uppercase labels above a control or a list. */
.pubdate{ color:var(--muted); font-size:11px; margin:0 0 4px; }
.back{ color:var(--muted); font-size:12px; }
.rule{ color:var(--muted); margin:14px 0; user-select:none; }
.label{ color:var(--muted); text-transform:uppercase; letter-spacing:.06em; font-size:11px; }
.loading{ color:var(--muted); padding:24px 0; }

footer{ margin-top:28px; color:var(--muted); font-size:11.5px; }
footer p{ margin:6px 0; }

/* ==========================================================================================
 * DATA TABLES
 *
 * Six pages put numbers in a table and all six drew the same table. The shape: hairline rules,
 * right-aligned tabular figures, nothing wraps, and a frozen first column so a row three
 * columns in is still attached to whoever it belongs to.
 *
 * A page states only what is genuinely its own — how wide the frozen column has to be for the
 * names it holds, and any column it needs to treat specially.
 * ========================================================================================== */

.tablewrap{ overflow-x:auto; border:1px solid var(--rule); background:var(--panel); }
table{ border-collapse:collapse; width:100%; font-size:12px; }
th,td{ padding:5px 8px; text-align:right; white-space:nowrap; }

/* Table headings are Helvetica, not the display face: they label data rather than open a
   section. See the note on --display at the top of this file. */
th{
  font-family:var(--sans); color:var(--muted); font-weight:700; font-size:10.5px;
  letter-spacing:.03em; text-transform:uppercase; border-bottom:1px solid var(--rule);
}
td{ border-bottom:1px solid var(--rule); font-variant-numeric:tabular-nums; }

/* The identity column stays put while the numbers scroll under it. It needs an opaque
   background of its own, because a sticky cell is painted over by whatever scrolls beneath
   it. Each page sets its own min-width — that depends on what the column holds. */
th:first-child, td:first-child{
  text-align:left; position:sticky; left:0; z-index:1;
  background:var(--panel); border-right:1px solid var(--rule);
}
/* Breathing room against the frozen column: mid-scroll the first number would otherwise sit
   flush against the name it belongs to and read as one string. */
th:nth-child(2), td:nth-child(2){ padding-left:12px; }

/* The container's border closes the bottom edge, so the last row does not draw its own. */
tbody tr:last-child td{ border-bottom:0; }
/* The row under the cursor lifts off the panel. The first cell has to be named too — it has
   its own background, so it would otherwise stay --panel while the rest of the row turned. */
tbody tr:hover td, tbody tr:hover td:first-child{ background:var(--bg); }

/* ==========================================================================================
 * PHONE
 *
 * One breakpoint, shared. A page adds its own @media for a layout that has to change shape —
 * a grid dropping to one column, a four-column card stacking — but the shell's margins and
 * the tables' type size are the same everywhere and step down here.
 * ========================================================================================== */

@media (max-width:620px){
  .wrap{ padding:22px 12px 56px; }
  body{ font-size:12.5px; }
  table{ font-size:11.5px; }
  th,td{ padding:5px 6px; }
}
