
/* The site and the PDF are one product, so they share a typeface and a palette.
   Same bundled faces the renderer uses — no webfont fetch here either. */
@font-face { font-family: 'Playfair Display'; font-weight: 700; font-style: normal;
             src: url('/static/fonts/PlayfairDisplay-700.ttf') format('truetype'); font-display: swap; }
@font-face { font-family: 'Playfair Display'; font-weight: 700; font-style: italic;
             src: url('/static/fonts/PlayfairDisplay-700Italic.ttf') format('truetype'); font-display: swap; }
@font-face { font-family: 'Source Sans 3'; font-weight: 400; font-style: normal;
             src: url('/static/fonts/SourceSans3-400.ttf') format('truetype'); font-display: swap; }
@font-face { font-family: 'Source Sans 3'; font-weight: 600; font-style: normal;
             src: url('/static/fonts/SourceSans3-600.ttf') format('truetype'); font-display: swap; }
@font-face { font-family: 'Source Sans 3'; font-weight: 400; font-style: italic;
             src: url('/static/fonts/SourceSans3-400Italic.ttf') format('truetype'); font-display: swap; }

:root {
    /* Two blues, and the split is the point. The brand blue is an *accent* —
       the stripe, the step marks, the load bars, the rules. Anything carrying
       text is the deep blue, because white on #0091d9 measures 3.47:1 and the
       PDF settled this exact question the same way
       (/.wiki/decisions/0033-the-recipe-page-is-a-two-column-grid.md). */
    --blue: #0091d9;
    --blue-deep: #0a3d62;
    --blue-lift: #0d4d7a;
    /* The PDF’s accent, darkened. Every orange on this site is small text —
       the eyebrow is 12.5px semibold with 0.34em tracking, the thinnest thing
       here — so there is no place for the brand #c1632c, which measures
       3.87:1 on the wash. One orange, and it is the one that can be read. */
    --accent: #a94f1a;

    --ink: #1d1d1d;
    --muted: #5a5a5a;
    /* Placeholder text. It has to read as "nothing typed here yet" without
       being text nobody can read: #9aa4a9 was 2.54:1, and 3.5:1 is the
       non-text threshold, which a placeholder is not. 4.59:1. */
    --faint: #6b7780;
    /* Hairlines that separate content, and edges that define a control. The
       second is not decoration — a border at 1.56:1 was the only thing making
       "Save the PDF" look like a button at all. */
    --rule: #e3e6e8;
    /* 3.45:1 on paper, 3.24 on the wash, 3.09 on --sink. All three, because a
       quiet button sits on all three across the flow and the first two passes
       each checked only the ground in front of them. */
    --edge: #7f8c95;
    --paper: #ffffff;
    --wash: #f6f8f9;
    /* The blue at a tint the page can carry behind text, and the one a home
       screen still shows. Used for the active step and the hardest day. */
    --tint: #eaf4fb;
    /* The one off-white that is not the page: a quiet button's hover, a code
       chip's ground. There were two of these, six hundredths apart. */
    --sink: #eef3f6;

    /* One scale, because there were four sizes between 14 and 16px doing
       subtly different jobs and nobody could tell them apart. */
    --t-hero: 2.6rem;
    --t-h2: 1.35rem;
    --t-lede: 1.06rem;
    --t-body: 1rem;
    --t-small: 0.9rem;
    --t-micro: 0.78rem;

    --s2: 0.7rem;
    --s3: 1.1rem;
    --s4: 1.7rem;
    --s5: 2.6rem;
    --radius: 10px;
}

* { box-sizing: border-box; }

/* On <html> as well as <body>: a meta-refresh repaints between documents, and
   the colour it repaints is the root’s. White there is a flash every five
   seconds on the one page an athlete watches for a quarter of an hour. */
html { background: var(--wash); }

body {
    margin: 0;
    font-family: 'Source Sans 3', -apple-system, 'Segoe UI', sans-serif;
    font-size: 17px;
    line-height: 1.55;
    color: var(--ink);
    background: var(--wash);
}

.stripe { height: 6px; background: var(--blue); }

/* The mark, on every page. The site had no identity of its own — the product
   name appeared once, in 12.5px grey, in the footer — while the PDF opens on a
   full-bleed cover with a roundel. It doubles as the way home from the pages
   that had none: the finished plan, and the wall. */
.brand {
    display: inline-flex; align-items: center; gap: 0.5rem;
    margin: 1.1rem 0 0; padding: 0.2rem 0; text-decoration: none;
    font-family: 'Playfair Display', Georgia, serif; font-weight: 700;
    font-size: 1.05rem; color: var(--blue-deep);
}
.brand .mark { width: 22px; height: 22px; border-radius: 5px; background-size: cover; }

/* Said to a screen reader, drawn for nobody. The rail’s states live in class
   names, which are not information. */
.vh {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap;
}
.wrap { max-width: 40rem; margin: 0 auto; padding: 0 1.25rem 4rem; }

.masthead { text-align: center; padding: var(--s5) 0 var(--s4); }
.eyebrow {
    /* 0.78rem, not 0.7: on the preview and the status page this line is the
       date range, which is the answer to the only question the athlete has at
       that moment — did you understand which week I meant? */
    text-transform: uppercase; letter-spacing: 0.34em; font-size: var(--t-micro);
    font-weight: 600; color: var(--accent);
}
h1 {
    font-family: 'Playfair Display', Georgia, serif;
    font-weight: 700; font-size: var(--t-hero); line-height: 1.1;
    margin: 0.6rem 0 0.4rem;
}
h2 {
    font-family: 'Playfair Display', Georgia, serif;
    font-weight: 700; font-size: var(--t-h2); margin: 0 0 var(--s2);
}
.lede { color: var(--muted); font-size: var(--t-lede); margin: 0 auto; max-width: 30rem; }

.card {
    background: var(--paper); border: 1px solid var(--rule); border-radius: var(--radius);
    padding: var(--s4); margin-bottom: var(--s3);
}

label { display: block; font-weight: 600; font-size: var(--t-small); margin-bottom: 0.25rem; }
/* Inside a <label> it trails the label on the same line — the em dash joining
   them is punctuation, and only works if they are one sentence. As a <p> under
   the field it is a line of its own. */
.hint { font-weight: 400; color: var(--muted); font-size: var(--t-small); }
p.hint { margin: 0.35rem 0 0; }
.field { margin-bottom: var(--s3); }
input, textarea, select {
    width: 100%; padding: 0.6rem 0.7rem; font: inherit; font-size: var(--t-small);
    border: 1px solid var(--edge); border-radius: 6px; background: #fff; color: var(--ink);
}
/* A country is picked from a list of 251, and it looked exactly like the URL
   field above it — while the weight unit two screens later is a <select> with
   a chevron. Two "choose one" controls with opposite affordances. A datalist
   cannot have a native arrow, so it gets a drawn one. */
input[list] {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235a5a5a' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 0.75rem center;
    background-size: 12px 8px; padding-right: 2.2rem;
}
/* Offset and deep, not a 2px brand-blue hairline. The old ring was #0091d9 on
   the wash — 3.26:1 — drawn hard against a #c8d0d4 border, so on the field it
   marked it was barely a change of colour. Keyboard focus has to be the most
   obvious thing on the page or it is not doing its job. */
input:focus-visible, textarea:focus-visible, select:focus-visible,
button:focus-visible, a:focus-visible {
    outline: 3px solid var(--blue-deep); outline-offset: 2px; border-color: var(--blue-deep);
}

/* Placeholders are examples, never values. Three rules keep that readable:
   a muted grey that still clears 3:1, because #9aa4a9 measured 2.54:1 and is
   not text anybody should have to squint at; and clearing it on focus, so the
   example cannot be mistaken for something already filled in. Every field
   has a real <label>, so nothing is lost when the placeholder goes. */
::placeholder { color: var(--faint); opacity: 1; }
:focus::placeholder { color: transparent; }
textarea { min-height: 4.5rem; resize: vertical; }
.narrow { max-width: 9rem; }
/* Two short controls side by side — unlike .row, which stretches its children. */
.pair { display: flex; gap: 0.6rem; }
.pair > select { flex: 0 0 5.5rem; }

/* One button, three weights, and an <a> can wear any of them — the download
   used to be a <button> nested inside an <a>, which is invalid and is announced
   inconsistently by screen readers. */
.btn {
    display: block; width: 100%; padding: 0.8rem 1rem; font: inherit;
    font-weight: 600; font-size: var(--t-body); line-height: 1.3; text-align: center;
    text-decoration: none; border: 0; border-radius: 6px; cursor: pointer;
    color: #fff; background: var(--blue-deep);
}
.btn:hover { background: var(--blue-lift); }
button { font: inherit; }
/* Secondary actions are not the same size as the thing they are beside. "Back"
   was a full-width block in a box of its own, identical in footprint to
   "Generate my plan" — the page offered two equal choices where one is the
   whole point of being on it. */
.btn.quiet {
    display: inline-block; width: auto; padding: 0.45rem 0.9rem;
    font-size: var(--t-small); font-weight: 600;
    color: var(--blue-deep); background: transparent; border: 1px solid var(--edge);
}
.btn.quiet:hover { background: var(--sink); }
.actions { display: flex; gap: 0.7rem; align-items: center; flex-wrap: wrap; margin-top: var(--s3); }
.actions.mid { justify-content: center; }
.actions form { margin: 0; }

/* A grid, not wrapping flex. Three boxes that wrap put the third alone on a
   row at double width, so on a phone "Hardest day" — the longest label of the
   three — got emphasis nobody gave it. Equal columns shrink together instead,
   and at 288px each still holds its label on one line. */
.stats {
    display: grid; gap: 0.7rem; margin: 0 0 var(--s3);
    /* minmax(0, 1fr), not 1fr: a bare 1fr floors at min-content, so on the
       delivery page "Hardest day" took 2.1x the width of "Est. load" below
       440px — the same orphaning, in a different shape. */
    grid-template-columns: repeat(3, minmax(0, 1fr));
}
/* The row was the card's first child until the delivery page put the button
   above it, and a 6px navy block flush against an 8px card row reads as one
   fused control — the focus ring overlapped it too. */
.btn + .stats { margin-top: var(--s3); }
.stat {
    text-align: center; padding: 0.7rem 0.4rem;
    background: var(--wash); border: 1px solid var(--rule); border-radius: 8px;
}
.stat .k {
    display: block; text-transform: uppercase; letter-spacing: 0.1em;
    font-size: var(--t-micro); font-weight: 600; color: var(--accent);
}
.stat .v { font-family: 'Playfair Display', Georgia, serif; font-weight: 700; font-size: 1.35rem; }

/* line-height is stated, not inherited: inside a table it computes to "normal"
   whatever the body says, and the load marks are centred against a line box
   whose height has to be a number this stylesheet knows. */
table.week { width: 100%; border-collapse: collapse; font-size: var(--t-small); line-height: 1.5; }
table.week td { padding: 0.4rem 0; border-bottom: 1px solid var(--rule); vertical-align: top; }
/* Every day cell carries the indent, not just the marked one: putting it on
   the peak row alone shifted that one day half a rem out of the column. */
table.week td.day { font-weight: 600; width: 6rem; padding-left: 0.5rem; }
table.week td.load { text-align: right; color: var(--muted); white-space: nowrap; width: 5.2rem; }
table.week tr.rest td { color: var(--muted); }
table.week tr.unplanned td { color: var(--accent); font-style: italic; }
/* The hardest day, marked in the table as well as named in the sentence under
   it. The product’s whole claim is that the food follows this column; showing
   the column as seven numbers and then asserting a winner in prose asks the
   reader to do the comparison we already did. */
table.week tr:last-child td { border-bottom: 0; }
table.week tr.peak td { background: var(--tint); }
table.week tr.peak td.day { box-shadow: inset 3px 0 0 var(--blue); }

/* The week’s shape, drawn. Same numbers as the load column, as a bar per day,
   so an athlete can see at a glance which day the plan is built around.

   The selector is qualified with the table, because the cell rule above it —
   "table.week td" — is the more specific one, so every padding this column
   declared was silently discarded. That is why the mark sat hard against the
   top of the row and hard against the session text beside it.

   Top, not middle: middle would centre the mark in the whole row, and on a day
   whose session runs to two lines that slides it half a line down. The cell
   aligns to the first line; the mark is centred inside a box exactly one line
   tall, which is arithmetic rather than a nudge and survives a change of type. */
table.week td.shape {
    width: 4rem; padding: 0.4rem 0.7rem 0.4rem 0; vertical-align: top;
}
.shape .rule { display: flex; align-items: center; height: 1.5em; }
/* 3px of radius, not a pill. At 9px tall a fully rounded end turns the
   shortest bar — an easy day against a five-hour Saturday — into a dot, which
   reads as a marker rather than as a quantity. */
.shape .bar {
    height: 9px; border-radius: 3px; background: var(--blue); min-width: 6px;
}
/* A rest day is not a full-width dash. It was drawn at the column’s full
   width, which made Friday’s nothing exactly as long as Saturday’s 268 — in
   the one column whose whole job is showing which day is biggest. It is the
   same geometry as a bar, so the two sit on one line: a short stub, thinner
   and grey, which reads as "nothing here" rather than "a very small day". */
.shape .none { width: 10px; height: 3px; border-radius: 2px; background: var(--edge); }

/* The preview’s conclusion, given the weight of one. It is the sentence that
   proves we read the calendar, and it used to be the smallest grey line on the
   page, under the table, indistinguishable from a footnote. */
.verdict {
    margin: var(--s3) 0 0; padding-top: var(--s3); border-top: 1px solid var(--rule);
    font-family: 'Playfair Display', Georgia, serif; font-size: 1.2rem; line-height: 1.35;
}
.verdict strong { color: var(--blue-deep); }
.verdict .why { display: block; font-size: var(--t-small);
    font-family: 'Source Sans 3', -apple-system, sans-serif; color: var(--muted); margin-top: 0.3rem; }

.note { padding: 0.9rem 1rem; border-radius: 8px; font-size: var(--t-small); margin-bottom: var(--s3); }
.note.warn { background: #fdf3ea; border: 1px solid #f0d3b8; color: #8a4a17; }
.note.stop { background: #fdecec; border: 1px solid #f2c4c4; color: #8f2b2b; }

/* ------------------------------------------------------------- the wait ---
   The page an athlete has open for a quarter of an hour. Three things had to change:
   the live message was the smallest text on it while being the only thing that
   moved; the step list drew a *filled* mark below the current one, because the
   furthest step legitimately runs ahead of the current one, and as a bulleted
   list that reads as a rendering fault; and nothing at all moved between the
   five-second refreshes, which is what a hang looks like. */
/* Outlined, not just tinted. The track’s job is to show what is *left*, and
   #e6ecef on white is 1.19:1 — at 96% the bar looked full. The outline is the
   boundary that carries the shape; the interior stays light so the fill reads
   against it. */
.meter {
    height: 10px; border-radius: 5px; background: #dde5ea; overflow: hidden;
    border: 1px solid var(--edge); margin: 0 0 0.5rem;
}
.meter i {
    display: block; height: 100%; border-radius: 4px; position: relative;
    overflow: hidden;
    background: linear-gradient(90deg, var(--blue), var(--blue-deep));
}
/* A highlight running along the filled part. This is the one thing on the page
   that moves *between* refreshes, and it has to be the honest kind of movement:
   the bar’s length is measured, and only the sheen is decorative. A bar that
   crept forward on its own would be inventing progress. */
.meter i::after {
    content: ''; position: absolute; inset: 0;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.45), transparent);
    transform: translateX(-100%); animation: sweep 2.5s ease-in-out infinite;
}
@keyframes sweep { to { transform: translateX(100%) } }
/* Not uppercase and not tracked. The right-hand slot is a clock, and
   "28M 52S SO FAR" at 0.12em is a puzzle rather than a reading. */
.meter-label {
    display: flex; justify-content: space-between; gap: 1rem;
    font-size: var(--t-micro); font-weight: 600; color: var(--muted);
    margin: 0 0 var(--s3);
}
.meter-label span:last-child { font-weight: 400; }

.track { list-style: none; padding: 0; margin: 0; }
.track li {
    position: relative; padding: 0 0 var(--s3) 1.75rem; color: var(--muted);
    font-size: var(--t-small);
}
.track li:last-child { padding-bottom: 0; }
/* The dot and the rail are placed in pixels, not ems: the current row is set a
   step larger than the rest, so an em offset would put its dot on a different
   line from everybody else’s and leave a kink in the rail. */
.track li::before {
    content: ''; position: absolute; left: 0; top: 6px;
    width: 12px; height: 12px; border-radius: 50%;
    background: var(--paper); border: 2px solid var(--edge); box-sizing: border-box;
}
/* The rail between this dot and the next one. Drawn per item rather than as one
   bar behind the list, so the filled length is exact whatever the rows measure —
   and so a filled rail can run *past* the current ring, which is the honest
   picture: the ring is where the work is, the fill is how far it has been.
   The negative bottom carries it into the next row, where that row’s dot is
   drawn over it. */
.track li::after {
    content: ''; position: absolute; left: 5px; top: 20px; bottom: -6px;
    /* 1.48:1 was a track you could not see, so "reached" and "not reached"
       rested on a distinction one of whose states was invisible. */
    width: 2px; background: var(--edge);
}
.track li:last-child::after { display: none; }
.track li.done::before { background: var(--blue); border-color: var(--blue); }
.track li.linked::after { background: var(--blue); }
.track li.now { color: var(--ink); font-weight: 600; font-size: var(--t-body); }
/* The heaviest mark on the page, not the lightest. As a white ring it shared
   its *shape* with the steps that have not happened, so on a job that has
   doubled back — filled, filled, ring, filled — it read as a hole punched in
   the rail rather than as the head of it. A filled disc inside a white gap
   inside a blue ring cannot be mistaken for an empty one. */
.track li.now::before {
    background: var(--blue); border: 3px solid var(--paper);
    box-shadow: 0 0 0 2px var(--blue);
}

/* What the model is doing, right now, in the athlete’s words — the only thing
   on this page that changes between refreshes, so it gets the room. */
/* Body size and full ink. At 14.4px grey it was pixel-identical to the four
   inert rows around it — the one line that changes every few seconds looked
   exactly like the ones that never do. */
.live {
    display: block; font-weight: 400; font-size: var(--t-body); color: var(--ink);
    margin-top: 0.2rem;
}
/* Every keyframe restates the 2px ring, because the animation owns the whole
   box-shadow property and would otherwise drop it for the length of the run. */
@keyframes halo {
    0%   { box-shadow: 0 0 0 2px var(--blue), 0 0 0 2px rgba(0, 145, 217, 0.45) }
    70%  { box-shadow: 0 0 0 2px var(--blue), 0 0 0 9px rgba(0, 145, 217, 0) }
    100% { box-shadow: 0 0 0 2px var(--blue), 0 0 0 2px rgba(0, 145, 217, 0) }
}
/* 2.5s, not 2.4s: the document reloads every 5 seconds and restarts both
   animations wherever they happen to be. 5 ÷ 2.4 lands mid-sweep, so the one
   element on the page whose job is to prove it is alive visibly snapped back
   twelve times a minute. 5 ÷ 2.5 and 60 ÷ 2.5 are both whole. */
.track li.now::before { animation: halo 2.5s ease-out infinite; }
@media (prefers-reduced-motion: reduce) {
    .track li.now::before { animation: none }
    .meter i::after { animation: none; display: none }
}

/* Three lines under the landing form. Not a feature list — the athlete cannot
   evaluate features before seeing the artifact — but the *shape of the next few
   minutes*, which they can. Pasting a calendar credential into a stranger’s
   form is easier when the next screen is known to be a read-only preview, and a
   twenty-minute wait is a different experience when it was announced. */
.steps { counter-reset: step; list-style: none; margin: 0; padding: 0; }
.steps li {
    position: relative; padding: 0 0 var(--s2) 2.1rem;
    font-size: var(--t-small); color: var(--muted);
}
.steps li:last-child { padding-bottom: 0; }
.steps li::before {
    counter-increment: step; content: counter(step);
    position: absolute; left: 0; top: 1px;
    width: 1.45rem; height: 1.45rem; border-radius: 50%;
    background: var(--tint); color: var(--blue-deep);
    font-size: var(--t-micro); font-weight: 600; line-height: 1.45rem; text-align: center;
}
.steps strong { color: var(--ink); font-weight: 600; }

.centred { margin: var(--s3) 0 0; text-align: center; color: var(--muted); font-size: var(--t-small); }
.centred.micro { margin-top: 0.3rem; }
.quiet { color: var(--muted); font-size: var(--t-small); }
.micro { color: var(--muted); font-size: var(--t-micro); }
footer { text-align: center; color: var(--muted); font-size: var(--t-micro); padding: var(--s3) 0 0; }
/* Not a bare ".wrap a": that rule is more specific than ".btn", so an <a>
   styled as the primary button had navy text on a navy ground — the label was
   there, and the button read as an empty box. */
footer a, .wrap a:not(.btn) { color: var(--blue-deep); }
/* The wash on paper is 1.05:1, so inside a card the chip was invisible and
   "webcal://" — the one string the athlete has to recognise literally — had
   no chip at all. */
code { background: var(--sink); border: 1px solid var(--edge); padding: 0.05em 0.3em;
    border-radius: 4px; font-size: 0.85em; }

/* 36rem, not 30rem. The table’s fixed columns are 96 + 64 + 83px, so between
   480 and 576px the session description was down to 160px and Sunday ran to
   four lines. The shape is the garnish; the session is the content. */
@media (max-width: 36rem) {
    td.shape { display: none; }
    /* 5rem leaves "Wednesday" 0.6px clear of the session text, so the padding
       is what actually keeps them apart. */
    table.week td.day { width: 5rem; padding-right: 0.6rem; }
}
@media (max-width: 30rem) {
    :root { --t-hero: 2.1rem; --s4: 1.25rem; --s5: 2rem; }
    .wrap { padding: 0 1rem 3rem; }
}

/* ---- the dashboard ----
   Only the owner sees this, so it is the one screen in the product that may be
   dense. A table you can read row by row is worth more here than anything
   aggregated: at this scale the rows *are* the finding. */
.admin { font-size: var(--t-small); }
.admin h2 { margin: var(--s4) 0 var(--s2); font-size: 1rem; letter-spacing: 0.02em; }
.admin .big { display: flex; flex-wrap: wrap; gap: var(--s3); margin-bottom: var(--s3); }
.admin .big div { min-width: 8rem; }
.admin .big .v {
  font-family: 'Playfair Display', Georgia, serif; font-weight: 700; font-size: 1.6rem;
  line-height: 1.1;
}
.admin .big .k { color: var(--muted); font-size: var(--t-small); }
.admin .rows { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.admin .rows th {
  text-align: left; font-weight: 600; color: var(--muted); font-size: var(--t-small);
  padding: 0.3rem 0.5rem 0.3rem 0; border-bottom: 1px solid var(--rule); white-space: nowrap;
}
.admin .rows td {
  padding: 0.3rem 0.5rem 0.3rem 0; border-bottom: 1px solid var(--rule); vertical-align: top;
}
.admin .rows td.n, .admin .rows th.n { text-align: right; padding-right: 0.9rem; }
/* The base rule for a code element gives it a background and a border, which
   is right for a token quoted inside a sentence and wrong for a whole column
   of them — forty bordered boxes read as forty input fields. Note: no
   backticks in here, they would close the template literal. */
.admin .rows code {
  font-size: 0.82em; color: var(--muted);
  background: none; border: 0; padding: 0;
}
.admin .bar { display: inline-block; height: 0.55rem; background: var(--blue); border-radius: 2px; }
/* A destructive control on a row of forty. Small enough not to dominate the
   table, large enough to still be a 32px tap target on a phone. */
.btn.small { padding: 0.3rem 0.7rem; font-size: var(--t-small); min-height: 2rem; }
.admin .note-text { color: var(--muted); font-style: italic; }
/* ---- text somebody else wrote ----
   Anything an athlete typed can be one unbroken token: a pasted URL, or a fist
   on the keyboard. The CSS default refuses to break inside a word, so such a
   token does not overflow its own box quietly — it widens every ancestor, and
   the WHOLE PAGE gains a horizontal scrollbar. Measured on the panel before
   this rule: one 2000-character message made the document 13,475px wide in a
   1,512px viewport.

   anywhere, not break-word: it also lets the box shrink below the longest word
   when the layout is measuring min-content, which is what a table cell does and
   what a flex item does, and both hold this text.
   No backticks in here — they would close the template literal. */
.said li, .verbatim li, .note-text { overflow-wrap: anywhere; }
/* Wide on a phone is the normal case for a table like this; it scrolls itself
   rather than making the page scroll. */
.admin .scroll { overflow-x: auto; }
/* The band, above everything, answering only what is true right now. It sits
   before the masthead because the operator opening this page at eleven at night
   is asking whether something is stuck, not what the cohort did. */
.band {
  display: flex; flex-wrap: wrap; gap: 0 var(--s3);
  padding: 0.55rem 0.8rem; margin-bottom: var(--s3);
  border: 1px solid var(--rule); border-radius: 6px;
  font-size: var(--t-small); font-variant-numeric: tabular-nums;
}
.band b { font-weight: 600; }
.band .ok { color: var(--muted); }
.band .bad { color: var(--accent); font-weight: 600; }
/* Which window a heading is measured over, said on the heading rather than at
   the foot of the page. Two sections here are lifetime facts and two are not,
   and a control a screen away from both cannot say which it governs. */
.admin h2 .stamp {
  font-family: 'Source Sans 3', -apple-system, 'Segoe UI', sans-serif;
  font-weight: 400; font-size: var(--t-small); color: var(--muted); letter-spacing: 0;
}
.admin h2 .stamp a { color: var(--muted); }
.admin .verbatim { margin: 0 0 var(--s2); padding-left: 0.9rem; border-left: 2px solid var(--rule); }
.admin .verbatim li { color: var(--ink); margin-bottom: 0.35rem; }
/* Words somebody wrote, given room to be read rather than scanned. A
   comfortable measure even though the panel is otherwise dense — this is the
   one part of the page that is prose. max-width bounds the line; the
   overflow-wrap rule above is what bounds a word. */
.admin .said li { margin-bottom: 0.8rem; max-width: 46rem; }
.admin .said .k { white-space: nowrap; }
/* A select and a submit on one row of forty. Inline so the column stays a
   column; the button is the same small destructive-scale control Remove uses,
   which is small enough not to dominate and still a 32px tap target. */
.admin .tag { display: flex; gap: 0.3rem; margin: 0; }
/* Two small controls side by side in one cell. The actions class on its own
   stacks them full-width, which is right under a card and wrong inside a table
   row. No backticks in here — they would close the template literal. */
.admin .actions.row { display: flex; gap: 0.3rem; margin: 0; flex-wrap: nowrap; }
.admin .actions.row .btn { width: auto; white-space: nowrap; }
/* The hash lookup, sitting on the same line as the view links rather than
   above or below them: it is one more way of asking the same question. */
.admin .find { display: inline-flex; gap: 0.3rem; align-items: center; margin: 0 0 0 0.4rem; }
.admin .find label { color: var(--muted); }
.admin .find input {
  font: inherit; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  padding: 0.15rem 0.35rem; border: 1px solid var(--edge); border-radius: 4px;
  background: var(--paper); color: var(--ink); width: 7rem;
}
.admin .tag select {
  font: inherit; padding: 0.15rem 0.3rem; border: 1px solid var(--edge);
  border-radius: 4px; background: var(--paper); color: var(--ink);
  /* Wide enough for the longest value. Sized to its content, a select whose
     current option is an em-dash collapses to a bare chevron — the column then
     shows a control with no visible state, which is worse than no column. */
  min-width: 6.5rem;
}
/* Tabular data that must not wrap: a timestamp broken over two lines makes
   every row in the table twice as tall for no gain. */
.admin .rows td.when { white-space: nowrap; }
