/* NoPlanB. One accent, two typefaces, no gradients, no shadows. The only
   pictures on the page are the founders' own: a profile picture beside a name
   and a favicon beside a product link, both cached by src/images.js. The only
   glyphs are the sort arrow in the table head and the two theme icons in the
   footer. Mobile first; the breakpoints are 480px (the hero input row stacks),
   520px (the stats pill softens its corner), 600px (the real four column table
   starts) and 900px (that table takes its full width). */

/* The two typefaces, served from this box. They used to come from Google
   Fonts, which meant two extra connections before a single word could be
   painted and a third party seeing every reader's address. These are the same
   files satori draws the share cards with, converted to woff2.

   The content hash is in the FILE NAME, not a query string: a stylesheet
   cannot append ?v= to its own url(), and without a version in the address the
   year of immutable caching these are served with would strand a changed font
   forever. A new file is a new name.

   font-display: swap, so the text is readable in the fallback while the woff2
   arrives rather than invisible. The fallback stack in --sans and --mono is
   what it falls back to, and it is unchanged. */

@font-face {
  font-family: "DM Sans";
  src: url("/fonts/DMSans-Regular.f3f6e717.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "DM Sans";
  src: url("/fonts/DMSans-Bold.c2befb59.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("/fonts/JetBrainsMono-Regular.c409a138.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("/fonts/JetBrainsMono-Bold.be192b33.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --ground: #FAF7F2;
  --white: #FFFFFF;
  --ink: #111111;
  --ink-2: #3D3A35;
  --muted: #6B665F;
  --hairline: #E6E0D6;
  --row-hover: #F3EEE6;
  --underline: #C9C2B6;
  /* One accent, in two jobs. --accent fills a surface (the button) and
     --accent-text writes on the ground. On the light ground the same blue does
     both; on the dark ground a filled blue has to stay dark enough for white
     text while text on the ground has to be light enough to read, so the two
     values part company in the dark blocks below. --on-accent is the text that
     sits ON the filled blue, and it is white in every theme. */
  --accent: #3048C8;
  --accent-text: var(--accent);
  --on-accent: #FFFFFF;
  /* The two twin colours. Either site has to be able to paint the OTHER's
     segment in the header switch, so both are written down in both
     stylesheets. This site's own accent is above. */
  --twin-blue: #3048C8;
  --twin-gold: #EC9A13;
  --error: #B42318;
  --sans: "DM Sans", system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --pad: 20px;
  color-scheme: light;
}

/* Dark mode. These tokens are the whole switch: nothing below this point names
   a colour of its own, so every rule follows without being repeated.

   Two selectors, because there are three states. The media query is the
   default, "follow the system", and it must not fire for a reader who has
   asked for light. The attribute rule is the explicit choice and comes last,
   so the toggle wins in both directions. */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --ground: #141311;
    --white: #1C1A17;
    --ink: #F2EEE8;
    --ink-2: #CFC9C0;
    --muted: #9A948B;
    --hairline: #2C2925;
    --row-hover: #221F1B;
    --underline: #4A453E;
    --accent: #3048C8;
    --accent-text: #6B82F5;
    --on-accent: #FFFFFF;
    --twin-blue: #6B82F5;
    --twin-gold: #FEAF2D;
    --error: #F97066;
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --ground: #141311;
  --white: #1C1A17;
  --ink: #F2EEE8;
  --ink-2: #CFC9C0;
  --muted: #9A948B;
  --hairline: #2C2925;
  --row-hover: #221F1B;
  --underline: #4A453E;
  --accent: #3048C8;
  --accent-text: #6B82F5;
  --on-accent: #FFFFFF;
  --twin-blue: #6B82F5;
  --twin-gold: #FEAF2D;
  --error: #F97066;
}

* { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.5;
}

a { color: var(--ink); text-decoration: none; }
a:hover { color: var(--accent-text); }

input::placeholder { color: var(--muted); opacity: 1; }

.mono {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

.muted { color: var(--muted); }

/* Buttons */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  border: 0;
  cursor: pointer;
  white-space: nowrap;
  font-family: inherit;
}

.btn-dark { background: var(--ink); color: var(--white); }
.btn-accent { background: var(--accent); color: var(--on-accent); }
.btn-dark:hover { color: var(--white); opacity: 0.88; }
.btn-accent:hover { color: var(--on-accent); opacity: 0.88; }

.btn-sm { height: 40px; padding: 0 18px; border-radius: 10px; font-size: 14px; }
.btn-lg { height: 56px; padding: 0 26px; border-radius: 12px; font-size: 18px; }

/* Header bar */

.bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
  padding: 16px var(--pad);
  border-bottom: 1px solid var(--hairline);
}

/* The icon and the name read as one mark, so the link is a centred row rather
   than a line of text with a picture hung off its baseline. 20px at every
   width: the header is the same height on a phone and on a desktop.

   The link has exactly TWO flex items: the picture and one span holding the
   whole name. That is load bearing. A flex container makes an anonymous item
   out of every run of text, so with the name written straight into the link
   the dot span was a third item and the 10px gap opened up on both sides of
   it: "noplanb . lol". The gap belongs between the picture and the name and
   nowhere else, so the name is one element and the dot is nested inside it,
   where normal inline flow applies. */
.wordmark { display: inline-flex; align-items: center; gap: 10px; font-weight: 700; font-size: 16px; letter-spacing: -0.01em; }
.wm { white-space: nowrap; }
.wordmark:hover { color: var(--ink); }
/* The 32px PNG, not the SVG: one rasteriser, so the mark looks the same in
   every browser. display:block keeps it off the text baseline, and flex:none
   stops it being squeezed on a narrow header. */
.wordmark-pic { display: block; width: 20px; height: 20px; flex: none; border-radius: 5px; }
/* The dot is the blue the favicon and the button are, in both themes. It uses
   --accent rather than --accent-text on purpose: this is the brand mark, not
   a link colour, so it stays the same blue on the dark ground. */
.dot { color: var(--accent); }

/* The sprite holds the two theme icons and paints nothing itself. */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

/* The twin switch, right of the wordmark. A real switch: the two names with a
   track between them, and the knob sitting under the site you are on. NotYet
   is the left end and the amber track, NoPlanB the right end and the blue one,
   which is why both twin colours are tokens in both stylesheets.

   data-here is written by the server from app.locals, so one set of rules
   paints both sites and neither stylesheet has to know which one it is.

   It is one ordinary link. The script in the layout only holds the navigation
   back for the length of the slide; with no script at all the control still
   works, and so does the About and Rules pair beside it. */
.twin { display: flex; align-items: center; gap: 14px; }

.twin-link { font-size: 13px; line-height: 1.25; color: var(--muted); white-space: nowrap; }
.twin-link:hover { color: var(--ink); }

/* inline-flex, not flex: this is a link standing in a row of links. */
.twin-switch {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 3px 4px;
  border-radius: 999px;
  white-space: nowrap;
}
.twin-switch:hover { color: inherit; }
.twin-switch:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; }

/* The name of the site you are on is ink, the other is muted. Both are read
   out by the control's aria-label, so neither has to say "current" itself. */
.twin-label { font-size: 13px; font-weight: 700; line-height: 1.25; transition: color 180ms ease; color: var(--muted); }
.twin-switch[data-here="notyet"] .twin-label-ny,
.twin-switch[data-here="noplanb"] .twin-label-npb { color: var(--ink); }

/* Each name carries its own site's dot, and it keeps that colour on both
   sites: the amber one belongs to notyet.lol and the blue one to noplanb.lol
   whichever end you are standing at. The rule sits on the dot itself, so the
   ink or muted colour set on the label around it is never inherited, and the
   hover and flip rules, which also address the label, leave it alone too.

   It comes after .dot on purpose. The two carry the same weight, so source
   order is what lets the twin colour win over this site's own accent. */
.dot-ny { color: var(--twin-gold); }
.dot-npb { color: var(--twin-blue); }

/* 38 by 22 with a 2px inset all round, which is exactly what leaves an 18px
   knob room to sit at either end and nowhere in between. */
.twin-track {
  position: relative;
  flex: none;
  width: 38px;
  height: 22px;
  border-radius: 999px;
  background: var(--twin-gold);
  transition: background-color 180ms ease;
}
.twin-switch[data-here="noplanb"] .twin-track { background: var(--twin-blue); }

.twin-knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--ground);
  transition: transform 180ms ease;
}
.twin-switch[data-here="noplanb"] .twin-knob { transform: translateX(16px); }

/* Hover says where the click lands before it is clicked: the far name takes
   its own site's colour and the knob leans 3px that way. */
.twin-switch[data-here="notyet"]:hover .twin-label-npb { color: var(--twin-blue); }
.twin-switch[data-here="noplanb"]:hover .twin-label-ny { color: var(--twin-gold); }
.twin-switch[data-here="notyet"]:hover .twin-knob { transform: translateX(3px); }
.twin-switch[data-here="noplanb"]:hover .twin-knob { transform: translateX(13px); }

/* The flip, for the 190ms the script holds the navigation back. These come
   after the hover rules on purpose: they carry the same specificity, so source
   order is what lets them win while the pointer is still on the control. */
.twin-switch[data-here="notyet"].is-flipping .twin-knob { transform: translateX(16px); }
.twin-switch[data-here="noplanb"].is-flipping .twin-knob { transform: translateX(0); }
.twin-switch[data-here="notyet"].is-flipping .twin-track { background: var(--twin-blue); }
.twin-switch[data-here="noplanb"].is-flipping .twin-track { background: var(--twin-gold); }
.twin-switch[data-here="notyet"].is-flipping .twin-label-npb { color: var(--ink); }
.twin-switch[data-here="noplanb"].is-flipping .twin-label-ny { color: var(--ink); }

/* Less motion: the same states, arrived at without the travel. The script
   reads the same query and navigates straight away, so nothing is held back
   waiting for an animation that is not running. */
@media (prefers-reduced-motion: reduce) {
  .twin-label, .twin-track, .twin-knob { transition: none; }
}

/* A phone. Both names stay: the two names ARE the control, and an icon would
   say neither. They shrink and the gaps close instead. */
@media (max-width: 420px) {
  .twin { gap: 6px; }
  .twin-switch { gap: 6px; }
  .twin-link, .twin-label { font-size: 12px; }
}

.wrap { padding: 0 var(--pad); }

/* Hero. One centred column the width of a paragraph, read top to bottom: how
   big the list is, what the list is, the one input, and what it costs. */

.hero {
  max-width: 720px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 18px;
  padding: 40px 0 36px;
}

.statpill {
  margin: 0;
  padding: 7px 16px;
  max-width: 100%;
  font-size: 12px;
  color: var(--muted);
  border: 1px solid var(--hairline);
  border-radius: 999px;
  text-align: center;
}

h1 {
  margin: 0;
  font-size: 36px;
  line-height: 1.05;
  font-weight: 700;
  letter-spacing: -0.03em;
}

/* The sub-header under the headline: what the list is, in one sentence. */
/* 640px is one line of this sentence at the desktop size, so the last word is
   not left alone on a line of its own. Where it does wrap, balance splits it
   into two lines of similar length rather than a long one and a short one. */
.sub { margin: 0; max-width: 640px; font-size: 18px; line-height: 1.45; color: var(--ink-2); text-wrap: balance; }
/* The second half of the sub-header. Inline on a phone, where the sentence
   wraps wherever it has to, and a block from 600px up, where the break belongs
   after the comma and nowhere else. See the 600px block below. */
.sub-b { display: inline; }
.fine { margin: 0; font-size: 14px; color: var(--muted); }

/* The price and the rule that moves it, one small grey line under the input.
   The mechanism is not the pitch, so it is the quietest thing in the hero. */
.rule {
  margin: 0;
  font-family: var(--mono);
  font-size: 13px;
  color: var(--muted);
}

.empty { color: var(--muted); padding-bottom: 40px; }

.table { display: flex; flex-direction: column; padding-bottom: 8px; }

/* The list. Mobile is two columns with the building links tucked under the
   name and the joined date at the end of that second line; from 600px it is
   the real five column table. */

.thead, .row {
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr) auto;
  grid-template-areas:
    "rank who days"
    "pad building joined";
  gap: 2px 12px;
  align-items: baseline;
  padding: 8px 8px;
  border-bottom: 1px solid var(--hairline);
}

/* The head is words on one line, so its baseline is the right thing to line
   up. A row is not: the founder cell is a 32px picture next to two lines of
   text, and a baseline would drop the rank and the day count level with the
   SECOND line, at a different height for a row with a picture than for one
   with a letter circle. Centred, every row reads the same. */
.row { align-items: center; }

.thead {
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  padding-bottom: 10px;
}

.thead .col-building { display: none; }

.row { position: relative; border-radius: 8px; }
.row:hover { background: var(--row-hover); }

/* The stretched link: one empty anchor covering the whole row, so clicking
   anywhere that is not already a link opens the founder's page. It sits at
   z-index 0 and every inline link in the row is lifted to 1, which is what
   keeps the name pointing at X and the product links pointing at their own
   hosts without one anchor ever being nested inside another.

   Only filled in listings have one. A pending row's /@handle is a 404 until
   the details form is done, so it has no row link and no pointer cursor.

   The trade: text inside a row can no longer be selected by dragging, because
   the anchor is over it. That is the known cost of this pattern and it is
   worth it here, where a row is a link to one page and nothing in it is text
   somebody copies. */
.row-link {
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  cursor: pointer;
}

/* The focus ring is drawn on the anchor, not on the row through :focus-within.
   The row holds up to five other links, and :focus-within would throw a full
   row outline around every one of them as it took focus, on top of that link's
   own ring. The anchor is inset 0 of the row, so its outline IS a row outline,
   and it is drawn only when the row link itself has focus. */
.row-link:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: -2px;
}

/* Everything clickable in a row rides above the stretched link. Without this
   the anchor would swallow them and every row would go to the same place. */
.row .name,
.row .yt,
.row .quit a,
.row .blink {
  position: relative;
  z-index: 1;
}

.thead > :nth-child(1), .rank { grid-area: rank; }
.thead > :nth-child(2), .who { grid-area: who; }
.col-building { grid-area: building; }
.col-joined { grid-area: joined; text-align: right; }
.col-days { grid-area: days; text-align: right; }

/* The day the row landed on the list, and the second sort. Small and quiet:
   the rank and the day count are the numbers that matter, this one is context.
   Below 600px it rides on the second line beside the building links, so the
   sort is still reachable on a phone. */
.joined { font-size: 12px; color: var(--muted); white-space: nowrap; }

.rank { font-size: 22px; font-weight: 500; }

/* The founder cell: a 32px picture, then two lines. The name, then what they
   quit and the proof for it. align-items keeps each line as wide as its own
   text, so the hover target is the words and not the whole column. */
.who { display: flex; align-items: center; gap: 10px; min-width: 0; }
.who-lines { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; min-width: 0; }

/* The X profile picture, cached by src/images.js. The fallback is the same
   circle with the founder's initial in it, so a missing picture costs the row
   nothing in height and the column never moves. */
.avatar {
  width: 32px;
  height: 32px;
  flex: none;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--hairline);
  background: var(--row-hover);
}

.avatar-letter {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  user-select: none;
}

/* The name and, when there is one, the YouTube icon beside it. A row of its
   own because .who-lines is a column: an anchor after the name would otherwise
   drop onto the next line. */
.namerow { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; min-width: 0; }

.name { display: flex; align-items: center; gap: 6px; font-size: 16px; font-weight: 600; }

/* One icon, no counts and no thumbnails. Muted until it is hovered, so it sits
   beside the name without competing with it. */
.yt {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex: none;
  color: var(--muted);
  font-size: 13px;
}
.yt:hover { color: var(--accent-text); }
.yt span { text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--underline); }

.quit { font-size: 13px; color: var(--muted); }
.quit a { color: var(--muted); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--underline); }
.quit a:hover { color: var(--accent-text); }

/* Links wrap as whole words: each pair is nowrap and the row wraps between
   pairs, so a favicon never ends a line with its host on the next one.

   The favicon is a sibling of the link, not a child of it, so the underline
   runs under the host and not under the picture. .blink keeps the pair
   together as one item. There is no separator glyph between links: the 10px
   gap is the separator, which keeps more of them on one row. */
.building { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; font-size: 15px; }
.blink { display: inline-flex; align-items: center; gap: 6px; min-width: 0; white-space: nowrap; }
.favicon { width: 16px; height: 16px; flex: none; vertical-align: middle; border-radius: 3px; }
.building a { white-space: nowrap; text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--underline); }

.days { font-size: 22px; font-weight: 500; letter-spacing: -0.03em; color: var(--ink); }

/* The made up row the table shows while nobody has paid yet. Held back from
   the real rows it is standing in for: nothing in it is a link, and the whole
   row is dimmed so it reads as an illustration rather than as a listing. */
.row-example { opacity: 0.6; }

/* The label that says the row is not real. Same shape the table head has, in a
   hairline outline so it reads as a marker and not as a word in the name. */
.tag {
  flex: none;
  padding: 1px 6px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

/* The hero input row. One long thin 48px line: the field takes what is left
   after the button, which is only as wide as its label. It stops at 640px so
   it stays a control and does not stretch into a banner on a wide screen.

   The "@" is fixed furniture, not something to type. The wrapper carries the
   border and the focus ring, so the prefix and the field read as one control. */

.add-form { display: flex; gap: 8px; width: 100%; max-width: 640px; }

.field {
  display: flex;
  align-items: center;
  flex: 1;
  min-width: 0;
  height: 48px;
  border: 1px solid var(--hairline);
  border-radius: 8px;
  background: var(--white);
}

.field:focus-within { outline: 2px solid var(--ink); outline-offset: -2px; }
.field-at { padding-left: 16px; font-family: var(--mono); color: var(--muted); }

.add-form input {
  font: inherit;
  flex: 1;
  min-width: 0;
  height: 100%;
  padding: 0 16px 0 6px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--ink);
}

.add-form input:focus { outline: 0; }
.add-form .btn { height: 48px; padding: 0 20px; border-radius: 8px; font-size: 15px; }
.add-error { color: var(--error); font-size: 14px; margin: 0; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* The row holds its one line down to a small phone. Below 480px there is not
   enough width left for a field, so the button takes its own line, full width,
   which is the only place it looks deliberate rather than cramped. */
@media (max-width: 480px) {
  .add-form { flex-direction: column; }
  .add-form .btn { width: 100%; }
}

/* On a phone the column is narrower than the sentence however it is measured,
   so balancing it only makes the lines shorter than they need to be. Let it
   fill the width it has. */
@media (max-width: 600px) {
  .sub { text-wrap: normal; }
}

/* From 600px the break is written into the markup rather than left to the
   browser: line one ends at the comma, line two is "and what they are
   building". The span becomes a block, which also trims the space it starts
   with. No cap and no balancing, because both exist to make a browser choose
   a break and there is nothing left to choose. */
@media (min-width: 600px) {
  .sub { text-wrap: normal; max-width: none; }
  .sub-b { display: block; }
}

@media (max-width: 520px) {
  /* Two lines inside a 999px radius reads as a lozenge. A softer corner is
     what a wrapped pill wants. */
  .statpill { border-radius: 16px; }
}

/* Details page. One 520px column, labels 13px above 44px inputs, 16px of air
   between one field and the next. */

.narrow { max-width: 520px; margin: 0 auto; }

.back { font-size: 14px; margin: 24px 0 0; }

/* The headline on the token pages. One short line, so it is read rather than
   scanned, with the fact under it in the secondary ink. */
.lead { font-size: 34px; line-height: 1.1; margin: 16px 0 0; }
.lead-sub { margin: 8px 0 0; font-size: 18px; line-height: 1.45; color: var(--ink-2); }

/* Everything on a token page sits in one of these: the form, the share block,
   the edit-later block. A surface with a hairline around it, so a page with
   three jobs on it reads as three things and not as one long column. */
.card {
  margin-top: 20px;
  padding: 24px;
  border: 1px solid var(--hairline);
  border-radius: 12px;
  background: var(--white);
}

.card > :first-child { margin-top: 0; }
.card p:last-child { margin-bottom: 0; }
.card-copy { margin: 0 0 14px; font-size: 15px; line-height: 1.5; color: var(--ink-2); }

/* The heading over a group of fields, and over each block on the saved page.
   Same shape as the table head, which is where the eye has already met it. */
.group-head {
  margin: 0 0 14px;
  font-size: 13px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

/* 28px between one group of fields and the next, measured from the field
   above rather than added to it, so the first group still starts at the top
   of the card. */
.group-head-2 { margin-top: 28px; }

.form { display: flex; flex-direction: column; }
/* .label is the same thing for a value that is text rather than a control, so
   a <label> never has to point at nothing. */
.form label, .form .label { font-size: 13px; color: var(--ink-2); margin: 14px 0 6px; }
.form > label:first-of-type { margin-top: 0; }

/* The line under a field that explains it. It belongs to the field above, so
   it sits tight under it and the next label keeps the full 14px gap. */
.helper { margin: 6px 0 0; font-size: 13px; color: var(--muted); }

/* A label with a mark before its words. The icon takes the label's own ink
   through currentColor, so there is no colour written here. */
.form label.label-icon { display: flex; align-items: center; gap: 6px; }
.form label.label-icon svg { flex: none; }

.form input {
  font: inherit;
  width: 100%;
  height: 44px;
  padding: 0 14px;
  border: 1px solid var(--hairline);
  border-radius: 10px;
  background: var(--ground);
  color: var(--ink);
}

.form input:focus { outline: 2px solid var(--ink); outline-offset: -2px; }

/* The day they quit: three controls on one line, because a native date picker
   opens on this month and a founder who quit in 2019 would have to scroll back
   through thirty of them. Two digits, a month, four digits.

   The select is styled to match the inputs rather than left to the browser, so
   the row reads as one field. Its own arrow is kept: replacing it would mean
   drawing one, and it is the only thing that says the middle control opens. */
.datefields { display: flex; gap: 8px; }

.datefields input, .datefields select {
  font: inherit;
  height: 44px;
  padding: 0 12px;
  border: 1px solid var(--hairline);
  border-radius: 10px;
  background: var(--ground);
  color: var(--ink);
}

.datefields input:focus, .datefields select:focus { outline: 2px solid var(--ink); outline-offset: -2px; }

.date-day { width: 72px; }
.date-month { width: 140px; }
.date-year { width: 96px; }

/* Below 420px the three do not fit on one line. Day and year share the first,
   month takes the second whole. The month is ordered last so the two typed
   fields stay together; tab order still follows the markup, day then month
   then year. */
@media (max-width: 420px) {
  .datefields { flex-wrap: wrap; }
  .date-day, .date-year { width: calc(50% - 4px); }
  .date-month { order: 3; width: 100%; }
}
/* Full width and the same height as the fields it submits. It is the only
   thing to do on the page, so it is not hiding in a corner of it. */
.btn-full { width: 100%; height: 48px; border-radius: 10px; font-size: 16px; }
.form .btn-full { margin-top: 28px; }

/* The prepared post, shown as something to read before it is sent, not as
   something to edit. */
.quote {
  margin: 0 0 16px;
  padding: 12px 14px;
  border: 1px solid var(--hairline);
  border-radius: 10px;
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink-2);
}

/* The private link and its copy button on one line. The input is readonly and
   is there to be selected, not typed into. */
.copyrow { display: flex; align-items: center; gap: 8px; }
.copyrow input {
  font: inherit;
  flex: 1;
  min-width: 0;
  height: 44px;
  padding: 0 12px;
  border: 1px solid var(--hairline);
  border-radius: 10px;
  background: var(--ground);
  color: var(--ink-2);
  font-size: 13px;
}
.copyrow input:focus { outline: 2px solid var(--ink); outline-offset: -2px; }
.copyrow .btn { flex: none; }

/* The line under the Post on X button, and the one under the copy row. Both
   belong to the thing above them, so they carry their own top margin rather
   than relying on a browser default. */
.share-page { margin: 14px 0 0; }
.lost { margin-top: 12px; }
.lost a { color: var(--muted); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--underline); }
.lost a:hover { color: var(--ink); }

/* Text that is shown but never typed into: the permanent link back to this
   page, and the handle they paid with. The handle is fixed because checkout
   refuses a handle already on the list, so editing it here would walk straight
   around that check. */
.fixed-value { margin: 0; font-size: 14px; color: var(--ink-2); overflow-wrap: anywhere; }

/* A button that reads as a link. It reveals the two extra product fields and
   then takes itself out of the flow. */
.linkish {
  align-self: flex-start;
  margin-top: 14px;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: 14px;
  color: var(--ink-2);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--underline);
}

.linkish:hover { color: var(--accent-text); }

.more-fields { display: flex; flex-direction: column; }
/* display:flex would beat the hidden attribute, so say it again here. */
.more-fields[hidden] { display: none; }

.errors {
  margin: 20px 0 0;
  padding: 14px 16px;
  border: 1px solid var(--error);
  border-radius: 10px;
  color: var(--error);
  font-size: 15px;
}

/* Terms and privacy. One 680px column of plain prose: an H1, a date, then
   numbered sections. Nothing here is decorated; it exists to be read. */

/* One page per founder, at /@handle. It is the row as a card: the same
   pieces, the same tokens, nothing new to learn. No bio, no extra fields. */

.fpage { max-width: 680px; margin: 0 auto; padding-bottom: 56px; }

.fcard {
  display: flex;
  flex-direction: column;
  gap: 20px;
  margin-top: 24px;
  padding: 24px;
  border: 1px solid var(--hairline);
  border-radius: 14px;
}

/* The picture, the words, and the day count. It wraps on a narrow screen, so
   the number drops under the name rather than squeezing it. */
.fcard-main { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.fcard-lines { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; min-width: 0; flex: 1; }

.favatar {
  width: 64px;
  height: 64px;
  flex: none;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--hairline);
  background: var(--row-hover);
  font-size: 24px;
}

.fname { margin: 0; font-size: 26px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.15; }
.fhandle { margin: 0; font-size: 14px; color: var(--muted); }
.fhandle a { color: var(--muted); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--underline); }
.fhandle a:hover { color: var(--accent-text); }
.fquit { margin: 4px 0 0; font-size: 14px; color: var(--ink-2); }
.fquit a { color: var(--ink-2); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--underline); }
.fquit a:hover { color: var(--accent-text); }

/* The one big number on the page, in the accent, the same figure the list
   prints in that founder's row. */
.fdays { display: flex; flex-direction: column; align-items: flex-end; flex: none; }
.fdays-n { font-size: 44px; font-weight: 700; line-height: 1; letter-spacing: -0.03em; color: var(--accent-text); }
.fdays-label { font-size: 12px; color: var(--muted); }

.fbuilding { display: flex; flex-direction: column; gap: 6px; padding-top: 20px; border-top: 1px solid var(--hairline); }
.flabel { font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }

.fspot { margin: 0; font-size: 12px; color: var(--muted); }

.fadd { margin: 24px 0 0; }

.legal { max-width: 680px; margin: 0 auto; padding: 40px 0 56px; }
.legal h1 { font-size: 32px; margin: 0 0 8px; }
.legal h2 { font-size: 18px; font-weight: 600; letter-spacing: -0.01em; margin: 32px 0 8px; }
.legal p, .legal li { font-size: 16px; line-height: 1.6; color: var(--ink-2); }
.legal p { margin: 0 0 12px; }
.legal ul { margin: 0 0 12px; padding-left: 20px; }
.legal ol { margin: 0 0 12px; padding-left: 22px; }
.legal li { margin: 0 0 8px; }
.legal a { text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--underline); }
.legal .updated { margin: 0 0 28px; font-size: 14px; color: var(--muted); }

/* Footer */

.foot {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding: 32px var(--pad) 48px;
  margin-top: 24px;
  border-top: 1px solid var(--hairline);
  font-size: 13px;
  /* One line-height for every piece of footer text, so the words beside the
     picture sit at the same height as the words after it. */
  line-height: 1.4;
  color: var(--muted);
}

/* The left group is a row of small things, not a paragraph: "Built by", the
   byline with its picture, and the two legal links. As a flex row every one of
   them is centred on the same line rather than hung off a text baseline, which
   is what left the picture sitting low. */
.foot p {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.foot a { color: var(--muted); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--underline); }
.foot a:hover { color: var(--ink); }

/* The owner's own picture, a 20px circle sitting on the handle it belongs to.
   One static file in public/, never hotlinked from X. */
.byline { display: inline-flex; align-items: center; gap: 6px; vertical-align: middle; text-decoration: none; }
/* The rule belongs to the text, not to the picture: an underline drawn across
   the whole link would run under the circle too. */
.byline span { text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--underline); }
.byline:hover { color: var(--ink); }
/* display:block takes the picture off the text baseline, where the descender
   space under it pushed the circle below the words it sits with. */
.byline-pic { display: block; width: 20px; height: 20px; border-radius: 50%; object-fit: cover; border: 1px solid var(--hairline); }

/* The theme switch. An icon and nothing else: the moon while the light theme
   is on, the sun while the dark one is, set by the script under the footer. */
.theme-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  /* An 18px icon is an 18px tap target, which is half of what a thumb needs.
     The padding makes it 30px and the equal negative margin takes that space
     back out of the layout, so the footer line does not move. */
  padding: 6px;
  margin: -6px;
  border: 0;
  background: none;
  color: var(--muted);
  cursor: pointer;
}

.theme-btn:hover { color: var(--ink); }

/* From 600px the table is the real five column one: the building links move
   out from under the founder's name and into their own column, and the joined
   date moves up onto the same line. The columns are tight here and open up at
   900px. */
@media (min-width: 600px) {
  .thead, .row {
    grid-template-columns: 48px minmax(0, 1fr) 240px 82px 110px;
    grid-template-areas: "rank who building joined days";
    gap: 12px;
    align-items: center;
    padding: 9px 12px;
  }

  .thead { display: grid; align-items: baseline; }
  .thead .col-building { display: block; }
}

@media (min-width: 720px) {
  :root { --pad: 32px; }
}

@media (min-width: 900px) {
  :root { --pad: 56px; }
  .wrap, .bar, .foot { max-width: 1200px; margin-left: auto; margin-right: auto; }

  .hero { padding: 64px 0 44px; }
  h1 { font-size: 52px; line-height: 1.02; }
  .sub { font-size: 20px; }
  .statpill { font-size: 13px; }

  /* 340px is two of the longer hosts side by side, which is what keeps a
     founder's links on one row. The day count needs no more than 120px: it is
     four digits and a comma in a tabular font. */
  .thead, .row {
    grid-template-columns: 64px minmax(0, 1fr) 340px 92px 120px;
    padding: 9px 16px;
  }
}
