The web uses ink with a few print colours: oxblood keywords, bottle-green strings, umber literals, slate types, muted italic comments. Each is defined as an --hl-* token, and all reach at least 4.5:1 on paper-2 in both themes. The EPUBs rely on weight and slant (bold keywords, grey italic comments), using flat selectors for the X4. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
423 lines
28 KiB
CSS
423 lines
28 KiB
CSS
@import "tailwindcss" source(none);
|
|
@source "../web/templates";
|
|
@source "./static/app.js";
|
|
|
|
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
|
|
|
|
@font-face {
|
|
font-family: "Newsreader";
|
|
font-style: normal;
|
|
font-weight: 200 800;
|
|
font-stretch: normal;
|
|
font-display: swap;
|
|
src: url("/static/Newsreader.woff2") format("woff2");
|
|
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+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
}
|
|
|
|
@font-face {
|
|
font-family: "Newsreader";
|
|
font-style: italic;
|
|
font-weight: 200 800;
|
|
font-stretch: normal;
|
|
font-display: swap;
|
|
src: url("/static/Newsreader-italic.woff2") format("woff2");
|
|
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+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
}
|
|
|
|
/* Metric-matched local fallbacks for Newsreader.
|
|
`font-display: swap` paints text immediately in whichever of these the
|
|
platform has; the overrides make that first paint occupy the same box as
|
|
Newsreader, so the swap changes glyph shapes and nothing else (CLS 0).
|
|
|
|
size-adjust = (Newsreader xWidthAvg/upm) / (fallback xWidthAvg/upm)
|
|
ascent/descent-override = (Newsreader ascent|descent / upm) / size-adjust
|
|
|
|
Newsreader (src/web/static/fonts/Newsreader.woff2, wght 400 at opsz 17, the
|
|
body size): upm 2000, ascent 1470, descent -530, lineGap 0, and a
|
|
frequency-weighted average character width of 837 (0.4185 em). Fallback
|
|
widths are @capsizecss/metrics v4.2.0 `xWidthAvg`, which uses the same
|
|
weighting, except DejaVu Serif which is measured the same way from
|
|
/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf. */
|
|
|
|
@font-face {
|
|
font-family: "Newsreader Fallback Georgia";
|
|
src: local("Georgia");
|
|
/* xWidthAvg 913 / upm 2048 */
|
|
size-adjust: 93.88%;
|
|
ascent-override: 78.29%;
|
|
descent-override: 28.23%;
|
|
line-gap-override: 0%;
|
|
}
|
|
|
|
@font-face {
|
|
font-family: "Newsreader Fallback Times";
|
|
src: local("Times New Roman"), local("Liberation Serif"), local("Tinos");
|
|
/* xWidthAvg 832 / upm 2048 */
|
|
size-adjust: 103.02%;
|
|
ascent-override: 71.35%;
|
|
descent-override: 25.72%;
|
|
line-gap-override: 0%;
|
|
}
|
|
|
|
@font-face {
|
|
font-family: "Newsreader Fallback Noto Serif";
|
|
src: local("Noto Serif");
|
|
/* xWidthAvg 481 / upm 1000 */
|
|
size-adjust: 87.01%;
|
|
ascent-override: 84.48%;
|
|
descent-override: 30.46%;
|
|
line-gap-override: 0%;
|
|
}
|
|
|
|
@font-face {
|
|
font-family: "Newsreader Fallback DejaVu Serif";
|
|
src: local("DejaVu Serif");
|
|
/* xWidthAvg 1058 / upm 2048 */
|
|
size-adjust: 81.01%;
|
|
ascent-override: 90.73%;
|
|
descent-override: 32.71%;
|
|
line-gap-override: 0%;
|
|
}
|
|
|
|
:root {
|
|
--paper:#f6f3ec; --paper-2:#ece7db; --ink:#1c1b18; --ink-2:#4f4b43; --muted:#6b665a;
|
|
--rule:#d8d2c4; --rule-strong:#1c1b18; --accent:#a3231f; --accent-hover:#7c1a16;
|
|
--loved:#2f6f46; --good:#2f6a8f; --down:#9c3f36; --warn:#7d631c; color-scheme:light;
|
|
--hl-keyword:#8c2a22; --hl-string:#3b6246; --hl-number:#7a4f16; --hl-type:#2c5572;
|
|
}
|
|
|
|
@media (prefers-color-scheme: dark) {
|
|
:root:not([data-theme="light"]) {
|
|
--paper:#151513; --paper-2:#1e1d1a; --ink:#ebe6da; --ink-2:#bfb9aa; --muted:#8f8a7d;
|
|
--rule:#3a3833; --rule-strong:#ebe6da; --accent:#ef8c82; --accent-hover:#f7aaa2;
|
|
--loved:#7fcb92; --good:#7fb8d8; --down:#ea8f84; --warn:#d9b45a; color-scheme:dark;
|
|
--hl-keyword:#e3a197; --hl-string:#a3c9a9; --hl-number:#d8b77a; --hl-type:#9dbdd3;
|
|
}
|
|
}
|
|
|
|
:root[data-theme="dark"] {
|
|
--paper:#151513; --paper-2:#1e1d1a; --ink:#ebe6da; --ink-2:#bfb9aa; --muted:#8f8a7d;
|
|
--rule:#3a3833; --rule-strong:#ebe6da; --accent:#ef8c82; --accent-hover:#f7aaa2;
|
|
--loved:#7fcb92; --good:#7fb8d8; --down:#ea8f84; --warn:#d9b45a; color-scheme:dark;
|
|
--hl-keyword:#e3a197; --hl-string:#a3c9a9; --hl-number:#d8b77a; --hl-type:#9dbdd3;
|
|
}
|
|
|
|
@theme inline {
|
|
--color-paper:var(--paper); --color-paper-2:var(--paper-2); --color-ink:var(--ink);
|
|
--color-ink-2:var(--ink-2); --color-muted:var(--muted); --color-rule:var(--rule);
|
|
--color-rule-strong:var(--rule-strong); --color-accent:var(--accent);
|
|
--color-accent-hover:var(--accent-hover); --color-loved:var(--loved); --color-good:var(--good);
|
|
--color-down:var(--down); --color-warn:var(--warn);
|
|
--font-serif:"Newsreader", "Newsreader Fallback Georgia", "Newsreader Fallback Times",
|
|
"Newsreader Fallback Noto Serif", "Newsreader Fallback DejaVu Serif",
|
|
"Iowan Old Style", "Palatino Linotype", Georgia, serif;
|
|
--font-sans:ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
--font-mono:ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
}
|
|
|
|
@layer base {
|
|
[hidden] { display:none !important; }
|
|
/* Match the site's preferred 110% browser-zoom reading scale by default. */
|
|
html { font-size:110%; @apply bg-paper text-ink antialiased; }
|
|
body { @apply m-0 min-h-screen bg-paper font-serif text-[1.0625rem] leading-[1.65] text-ink; font-optical-sizing:auto; }
|
|
::selection { background:color-mix(in oklab, var(--accent) 24%, transparent); }
|
|
a { @apply text-accent decoration-rule underline-offset-4 transition-colors duration-150 hover:text-accent-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-paper; }
|
|
h1, h2, h3 { @apply text-ink; font-optical-sizing:auto; }
|
|
button, input, select, textarea { font:inherit; @apply rounded-sm border border-rule bg-paper px-2.5 py-1.5 text-ink transition-colors duration-150 placeholder:text-muted focus:border-ink focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-paper; }
|
|
button { @apply cursor-pointer; }
|
|
button:disabled, input:disabled, select:disabled, textarea:disabled { @apply cursor-not-allowed border-rule bg-paper-2 text-muted; }
|
|
textarea { @apply min-h-28; }
|
|
summary { @apply cursor-pointer; }
|
|
table { @apply w-full border-collapse font-sans text-sm leading-snug; font-variant-numeric:tabular-nums; }
|
|
thead { @apply sticky top-0 z-10 bg-paper; }
|
|
th, td { @apply border-b border-rule px-2 py-2 text-left align-top; }
|
|
th { @apply text-[0.72rem] font-semibold uppercase tracking-[0.1em] text-muted; }
|
|
tbody tr { @apply transition-colors duration-150 hover:bg-paper-2; }
|
|
code, pre { @apply font-mono; }
|
|
meter { @apply block h-2 w-full rounded-sm; -webkit-appearance:none; appearance:none; background:var(--rule); }
|
|
meter::-webkit-meter-bar { background:var(--rule); border:0; border-radius:2px; height:0.5rem; }
|
|
meter::-webkit-meter-optimum-value, meter::-webkit-meter-suboptimum-value, meter::-webkit-meter-even-less-good-value { background:var(--good); border-radius:2px; }
|
|
meter.over::-webkit-meter-optimum-value, meter.over::-webkit-meter-suboptimum-value, meter.over::-webkit-meter-even-less-good-value { background:var(--down); }
|
|
meter::-moz-meter-bar { background:var(--good); border-radius:2px; }
|
|
meter.over::-moz-meter-bar { background:var(--down); }
|
|
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { scroll-behavior:auto !important; transition-duration:0.01ms !important; } }
|
|
}
|
|
|
|
@layer components {
|
|
/* ---------- shared controls ---------- */
|
|
.btn, .button { @apply inline-flex min-h-10 items-center justify-center rounded-sm border border-rule-strong bg-transparent px-3 py-1.5 font-sans text-sm font-medium text-ink no-underline duration-150 hover:bg-ink hover:text-paper focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-paper; transition-property:transform, background-color, color, border-color; }
|
|
.btn-primary { @apply inline-flex min-h-10 items-center justify-center rounded-sm border border-ink bg-ink px-3 py-1.5 font-sans text-sm font-medium text-paper no-underline duration-150 hover:border-accent hover:bg-accent hover:text-paper focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-paper; transition-property:transform, background-color, color, border-color; }
|
|
.btn-quiet { @apply inline-flex min-h-9 items-center gap-1 rounded-sm border-0 bg-transparent px-2 py-1 font-sans text-sm text-muted underline decoration-rule underline-offset-4 hover:text-ink hover:decoration-accent; }
|
|
.btn:disabled, .btn-primary:disabled, .btn-danger:disabled { @apply cursor-not-allowed border-rule bg-paper-2 text-muted hover:bg-paper-2 hover:text-muted; }
|
|
.btn-danger, button.danger { @apply inline-flex min-h-9 items-center justify-center rounded-sm border border-down bg-transparent px-2.5 py-1 font-sans text-sm font-medium text-down duration-150 hover:bg-down hover:text-paper; transition-property:transform, background-color, color, border-color; }
|
|
.btn:active, .button:active, .btn-primary:active, .btn-danger:active, button.danger:active { transform:scale(0.96); }
|
|
|
|
.badge { @apply inline-flex items-center whitespace-nowrap rounded-full px-2 py-0.5 font-sans text-xs font-medium leading-5 tabular-nums; color:var(--ink-2); background:color-mix(in oklab, var(--ink) 8%, transparent); }
|
|
.badge.selected, .badge.loved, .badge.ok { color:var(--loved); background:color-mix(in oklab, var(--loved) 14%, transparent); }
|
|
.badge.good, .badge.assessed, .badge.triaged, .badge.degraded { color:var(--good); background:color-mix(in oklab, var(--good) 14%, transparent); }
|
|
.badge.down, .badge.slop, .badge.excluded, .badge.failed, .badge.dry_run { color:var(--down); background:color-mix(in oklab, var(--down) 14%, transparent); }
|
|
.badge.shortlisted, .badge.admitted, .badge.eligible, .badge.cleared, .badge.reason, .badge.running, .badge.requested { color:var(--muted); background:color-mix(in oklab, var(--muted) 14%, transparent); }
|
|
.badge.restart, .badge.warn { color:var(--warn); background:color-mix(in oklab, var(--warn) 16%, transparent); }
|
|
|
|
.kv { @apply grid grid-cols-[minmax(9rem,1fr)_2fr] gap-x-5 gap-y-1.5; }
|
|
.kv dt { @apply text-sm text-muted; }
|
|
.kv dd { @apply m-0 min-w-0 text-sm; overflow-wrap:anywhere; }
|
|
/* Dashboard table layout contract: docs/dashboard-tables.md. */
|
|
.scroll-x { @apply max-w-full overflow-x-auto; overscroll-behavior-inline:contain; }
|
|
.scroll-x.tall { @apply max-h-[70vh] overflow-y-auto; overscroll-behavior-block:contain; }
|
|
|
|
.reader-page { @apply min-w-0; overflow-wrap:anywhere; }
|
|
.prose-body { @apply text-[1.0625rem] leading-[1.72] text-ink; }
|
|
.prose-body > * + * { @apply mt-5; }
|
|
.prose-body p, .index-summary { text-wrap:pretty; }
|
|
.prose-body h2 { @apply mt-10 border-t border-rule pt-4 text-2xl font-semibold leading-[1.1] tracking-[-0.01em]; }
|
|
.prose-body h3 { @apply mt-8 text-xl font-semibold leading-[1.15] tracking-[-0.01em]; }
|
|
.prose-body a { @apply text-ink underline decoration-rule underline-offset-4 hover:text-ink hover:decoration-accent; }
|
|
.prose-body img { @apply mx-auto my-7 block h-auto max-w-full rounded-sm text-center font-sans text-xs italic text-muted; outline:1px solid oklch(0 0 0 / 0.1); outline-offset:-1px; }
|
|
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .prose-body img { outline-color:oklch(1 0 0 / 0.1); } }
|
|
:root[data-theme="dark"] .prose-body img { outline-color:oklch(1 0 0 / 0.1); }
|
|
.prose-body table { @apply block max-w-full overflow-x-auto; overscroll-behavior-inline:contain; }
|
|
/* Cells keep whole words and let the table scroll instead of squeezing. */
|
|
.prose-body th, .prose-body td { overflow-wrap:normal; }
|
|
.prose-body pre { @apply max-w-full overflow-x-auto rounded-sm bg-paper-2 p-4 text-sm leading-relaxed; }
|
|
.prose-body :not(pre) > code { @apply rounded-sm bg-paper-2 px-1 py-0.5 text-[0.9em]; }
|
|
/* Syntax tokens (src/highlight.rs): ink-first, with a few print colours —
|
|
oxblood keywords, bottle-green strings, umber literals, slate types. All at
|
|
least 4.5:1 on paper-2 in both themes. Names and variables stay ink. */
|
|
.hl-keyword, .hl-tag, .hl-diff-delete { color:var(--hl-keyword); }
|
|
.hl-string, .hl-diff-add { color:var(--hl-string); }
|
|
.hl-number, .hl-constant, .hl-macro, .hl-attribute, .hl-label { color:var(--hl-number); }
|
|
.hl-type, .hl-namespace, .hl-constructor { color:var(--hl-type); }
|
|
.hl-comment { color:var(--muted); font-style:italic; }
|
|
.hl-punctuation, .hl-operator { color:var(--ink-2); }
|
|
.hl-title, .hl-strong { font-weight:600; }
|
|
.hl-emphasis { font-style:italic; }
|
|
.prose-body blockquote { @apply my-7 border-l-2 border-rule-strong pl-5 text-ink-2; }
|
|
.prose-body ul { @apply list-disc pl-6; }
|
|
.prose-body ol { @apply list-decimal pl-6; }
|
|
.prose-body li::marker { color:var(--muted); }
|
|
.prose-body li + li { @apply mt-2; }
|
|
|
|
.reader-page :where(h1, h2, h3, h4), .reader-section-heading { text-wrap:balance; }
|
|
.reader-section-heading { @apply border-t-[3px] border-double border-rule-strong pt-3 font-serif text-[1.05rem] font-semibold uppercase leading-[1.2] tracking-[0.15em] text-ink; }
|
|
/* Matched-interest tags: a hairline in the divider colour with squared
|
|
corners, so the row reads as small print, not as buttons. */
|
|
.interest-chip { @apply inline-block rounded-xs border border-rule px-2 py-px text-xs leading-5 text-ink-2 no-underline; }
|
|
a.interest-chip { @apply relative; }
|
|
a.interest-chip::after { content:""; @apply absolute -inset-y-1.5 inset-x-0; }
|
|
a.interest-chip:hover { @apply border-accent text-accent; }
|
|
|
|
.rating { @apply my-5 flex flex-wrap items-center gap-x-3 font-sans text-xs; }
|
|
.rating-prompt { @apply font-serif text-[0.8rem] italic text-muted; }
|
|
.rating-actions { @apply flex min-h-10 items-center whitespace-nowrap; }
|
|
.rating button[data-label] { @apply relative h-8 text-xs duration-150; transition-property:transform, background-color, color, border-color; }
|
|
.rating button[data-label]::after { content:""; @apply absolute -inset-y-1.5 inset-x-0; }
|
|
.rating button[data-label]:active { transform:scale(0.96); }
|
|
.rating button[data-label]:focus-visible { @apply z-20 ring-offset-0; }
|
|
.rating button[data-label]:not(.clear) { @apply -ml-px rounded-none border-rule bg-transparent px-2 py-1 text-ink-2 first:ml-0 first:rounded-l-sm last:rounded-r-sm hover:z-10 hover:border-ink hover:bg-paper-2 hover:text-ink; }
|
|
.rating button.active[data-label="loved"] { @apply z-10 border-loved text-loved; background:color-mix(in oklab, var(--loved) 14%, transparent); }
|
|
.rating button.active[data-label="good"] { @apply z-10 border-good text-good; background:color-mix(in oklab, var(--good) 14%, transparent); }
|
|
.rating button.active[data-label="down"], .rating button.active[data-label="slop"] { @apply z-10 border-down text-down; background:color-mix(in oklab, var(--down) 14%, transparent); }
|
|
.rating button.clear { @apply invisible ml-1.5 border-0 bg-transparent px-1 text-muted underline decoration-rule underline-offset-4 hover:text-ink; }
|
|
.rating:has(button[data-label]:not(.clear).active) button.clear, .rating button.clear.active { @apply visible; }
|
|
.rating button.clear.active { @apply no-underline; }
|
|
.rating-cleared-label { @apply hidden; }
|
|
.rating button.clear.active .rating-clear-label { @apply hidden; }
|
|
.rating button.clear.active .rating-cleared-label { @apply inline; }
|
|
.rating-note { @apply mt-2 flex w-full max-w-md basis-full items-center gap-2 text-[0.72rem] text-muted; }
|
|
.rating-note input { @apply min-w-0 flex-1 rounded-none border-x-0 border-t-0 border-b border-rule bg-transparent px-0 py-1 shadow-none focus:border-ink; }
|
|
|
|
.flash { @apply my-4 border-l-4 border-accent bg-paper-2 px-4 py-3 font-sans text-sm; }
|
|
.error { @apply border-l-4 border-down bg-paper-2 px-4 py-3 font-sans text-sm text-down; }
|
|
.notice { @apply border-l-4 border-warn bg-paper-2 px-4 py-3 font-sans text-sm text-ink-2; }
|
|
ul.error, ul.notice { @apply list-disc pl-8; }
|
|
|
|
/* ---------- dashboard shell ---------- */
|
|
.dashboard {
|
|
--gutter:1rem;
|
|
@apply my-8 grid pb-6 font-sans text-base leading-normal;
|
|
grid-template-columns:
|
|
[full-start] var(--gutter)
|
|
[wide-start] 1fr
|
|
[content-start] minmax(0, calc(80rem - 2 * var(--gutter)))
|
|
[content-end] 1fr
|
|
[wide-end] var(--gutter)
|
|
[full-end];
|
|
}
|
|
@media (width >= 40rem) { .dashboard { --gutter:1.5rem; } }
|
|
/* Grid items never collapse margins, so a child's bottom margin (`.table-filter`, `.rating`) would add to
|
|
the next child's `mt-4`; the rhythm comes from top margins only. `!important` beats those utilities. */
|
|
.dashboard > * { grid-column:content; min-width:0; margin-bottom:0 !important; }
|
|
/* The wrapper shrinks to its table (a centred grid item is sized fit-content), so the
|
|
flanks beside a narrow table stay page, not scroll container: wheeling there scrolls the page. */
|
|
.dashboard > .scroll-x {
|
|
grid-column:wide;
|
|
justify-self:center;
|
|
min-width:min(100%, calc(80rem - 2 * var(--gutter)));
|
|
max-width:100%;
|
|
}
|
|
.dashboard > .scroll-x > table { width:auto; min-width:100%; }
|
|
.dashboard > * + * { @apply mt-4; }
|
|
.dashboard h1 { @apply text-2xl font-semibold leading-tight tracking-[-0.01em]; }
|
|
.dashboard h2 { @apply text-lg font-semibold; }
|
|
.dashboard h3 { @apply text-sm font-semibold; }
|
|
.dashboard > h2 { @apply mt-9 border-t border-rule pt-3 text-[0.78rem] font-semibold uppercase tracking-[0.14em] text-muted; }
|
|
.dashboard > p, .dashboard > ul, .dashboard > ol { @apply text-sm; }
|
|
.dashboard code { @apply rounded-sm bg-paper-2 px-1 py-0.5 text-[0.85em]; }
|
|
.dashboard pre code { @apply bg-transparent p-0; }
|
|
.dashboard table a { @apply text-ink underline decoration-rule underline-offset-2 hover:text-ink hover:decoration-accent; }
|
|
|
|
.page-head { @apply flex flex-wrap items-end justify-between gap-x-6 gap-y-3 border-b border-rule pb-4; }
|
|
.page-head > div:first-child { @apply min-w-0; }
|
|
.dashboard > .page-head + * { @apply mt-6; }
|
|
.page-desc { @apply mt-1.5 max-w-[74ch] text-sm text-muted; }
|
|
.page-desc a { @apply text-accent; }
|
|
.page-actions { @apply flex flex-wrap items-center gap-2 font-sans text-sm; }
|
|
.page-eyebrow { @apply text-[0.7rem] uppercase tracking-[0.14em] text-muted; }
|
|
|
|
.tiles { @apply grid gap-3; grid-template-columns:repeat(auto-fit,minmax(min(10.5rem,100%),1fr)); }
|
|
.tile { @apply min-w-0 border border-rule px-3.5 py-3; }
|
|
.tile-label { @apply block text-[0.68rem] font-medium uppercase tracking-[0.12em] text-muted; }
|
|
.tile-num { @apply mt-1 block text-[1.55rem] font-semibold leading-tight tracking-[-0.01em]; font-variant-numeric:tabular-nums; overflow-wrap:anywhere; }
|
|
.tile-delta { @apply mt-1 block text-xs text-muted; overflow-wrap:anywhere; }
|
|
|
|
.cards { @apply grid gap-4; grid-template-columns:repeat(auto-fit,minmax(min(20rem,100%),1fr)); }
|
|
.card { @apply min-w-0 border border-rule p-4; }
|
|
.card > * + * { @apply mt-3; }
|
|
.card h2 { @apply text-base font-semibold; }
|
|
.card h3 { @apply text-base font-semibold; }
|
|
.card > h2:first-child, .card > h3:first-child { @apply mt-0; }
|
|
.card p, .card li { @apply text-sm; }
|
|
|
|
.muted, .meta { @apply text-muted; }
|
|
.jobs a, .picks > li > a:first-child { @apply text-ink no-underline hover:text-accent; }
|
|
.num { @apply text-right tabular-nums; }
|
|
td.num { @apply whitespace-nowrap; }
|
|
.cell-wrap { @apply min-w-[10rem] max-w-[32rem] whitespace-normal; overflow-wrap:anywhere; }
|
|
.cell-tight { @apply whitespace-nowrap; }
|
|
|
|
.filters { @apply flex flex-wrap items-end gap-x-4 gap-y-3 border-y border-rule py-3 font-sans text-sm; }
|
|
.filters label { @apply grid gap-1 text-[0.66rem] font-medium uppercase tracking-[0.1em] text-muted; }
|
|
.filters input, .filters select, .filters textarea { @apply text-sm normal-case tracking-normal text-ink; }
|
|
.filters select, .filters input[type="date"] { @apply min-w-32; }
|
|
.filters .filter-actions { @apply flex items-center gap-3; }
|
|
.form-inline { @apply flex flex-wrap items-center gap-3 font-sans text-sm; }
|
|
.form-inline label { @apply flex items-center gap-2 text-sm; }
|
|
/* Rendered by the templates but only useful with the script; `has-js` is set pre-paint. */
|
|
.table-filter { @apply my-2 hidden w-80 max-w-full font-sans text-sm; }
|
|
.has-js .table-filter { @apply block; }
|
|
/* Theme toggle: the current theme's icon and label, chosen without script. */
|
|
[data-theme-icon], [data-theme-label] { display:none; }
|
|
html:not([data-theme]) [data-theme-icon="system"], html[data-theme="light"] [data-theme-icon="light"], html[data-theme="dark"] [data-theme-icon="dark"] { display:block; }
|
|
html:not([data-theme]) [data-theme-label="system"], html[data-theme="light"] [data-theme-label="light"], html[data-theme="dark"] [data-theme-label="dark"] { display:inline; }
|
|
|
|
.pager { @apply flex flex-wrap items-center justify-between gap-x-6 gap-y-2 py-1 font-sans text-sm tabular-nums text-muted; }
|
|
.pager a { @apply text-ink no-underline hover:text-accent; }
|
|
.run-nav { @apply flex flex-wrap items-center justify-between gap-x-6 gap-y-2 font-sans text-sm; }
|
|
.run-nav a { @apply text-ink no-underline hover:text-accent; }
|
|
.tabs { @apply flex flex-wrap items-center gap-x-6 border-b border-rule font-sans text-[0.72rem] font-medium uppercase tracking-[0.12em]; }
|
|
.tabs a { @apply -mb-px flex min-h-10 items-center border-b-2 border-transparent text-muted no-underline hover:text-ink; }
|
|
.tabs a.active { @apply border-accent text-ink; }
|
|
.pagination { @apply font-sans text-sm tabular-nums text-muted; }
|
|
|
|
tr.superseded > td { @apply text-muted; }
|
|
tr.superseded a { @apply text-muted; }
|
|
|
|
/* the rating widget has to fit inside a table cell or a dense list */
|
|
td .rating, .picks .rating { @apply my-0 max-w-none gap-y-1 text-xs; }
|
|
.picks .rating { @apply mt-2; }
|
|
td .rating-prompt, .picks .rating-prompt { @apply hidden; }
|
|
td .rating button[data-label]:not(.clear), .picks .rating button[data-label]:not(.clear) { @apply px-1.5 py-1 text-xs; }
|
|
td .rating button.clear, .picks .rating button.clear { @apply ml-1.5 px-0 text-xs; }
|
|
td .rating-note { @apply mt-0 max-w-none gap-1.5 text-[0.7rem]; }
|
|
td .rating-note-label { @apply sr-only; }
|
|
td .rating-note input { @apply text-xs; }
|
|
/* the ratings table's verdict cell: one column, buttons then note, nothing wraps */
|
|
.rating-cell .rating { @apply grid w-[18rem] grid-cols-1 gap-y-1.5; }
|
|
.rating-cell .rating-actions { @apply flex w-full min-h-0 items-center; }
|
|
.rating-cell .rating button.clear { @apply ml-auto; }
|
|
|
|
pre.block, pre.preview, pre.journal { @apply overflow-auto whitespace-pre-wrap rounded-sm bg-paper-2 p-3 font-mono text-[0.8125rem] leading-relaxed; overflow-wrap:anywhere; }
|
|
pre.block { @apply max-h-64; }
|
|
pre.preview { @apply max-h-56; }
|
|
pre.journal { @apply max-h-[34rem] p-4; }
|
|
pre.prompt, pre.learned { @apply max-h-[32rem]; }
|
|
td > pre.preview { @apply max-h-24 max-w-md bg-transparent p-0 text-xs text-muted; }
|
|
|
|
details.disclosure { @apply border border-rule; }
|
|
details.disclosure > summary { @apply px-4 py-3 font-sans text-sm font-medium; }
|
|
details.disclosure[open] > summary { @apply border-b border-rule; }
|
|
details.disclosure > .disclosure-body { @apply px-4 py-3 text-sm; }
|
|
details.disclosure > .disclosure-body > * + * { @apply mt-3; }
|
|
details.signals > summary { @apply min-w-0; }
|
|
.signals-body { @apply mt-2 max-w-2xl border-l-2 border-rule pl-3 text-xs; }
|
|
.signals-body > * + * { @apply mt-2; }
|
|
.signals-body ul { @apply list-disc pl-5; }
|
|
|
|
.funnel { @apply w-full min-w-[6rem] rounded-sm bg-paper-2; }
|
|
.funnel > * { @apply block min-w-px rounded-sm bg-good; }
|
|
.funnel-cell { @apply w-[14rem] min-w-[8rem] align-middle; }
|
|
|
|
.sparklines { @apply grid gap-4; grid-template-columns:repeat(auto-fit,minmax(min(18rem,100%),1fr)); }
|
|
.spark-figure { @apply m-0 min-w-0 border border-rule p-3; }
|
|
.spark-figure figcaption { @apply mb-2 text-[0.7rem] font-semibold uppercase tracking-[0.1em] text-ink; }
|
|
.spark-figure figcaption .muted { @apply font-normal normal-case tracking-normal; }
|
|
.spark { @apply h-auto w-full max-w-full; }
|
|
.spark .s0 { fill:var(--good); } .spark .s1 { fill:var(--loved); } .spark .s2 { fill:var(--down); } .spark .s3 { fill:var(--accent); } .spark .s4 { fill:var(--muted); } .spark .s5 { fill:var(--ink); } .spark .line { stroke:var(--accent); }
|
|
.spark-axis { @apply mt-1 flex justify-between text-[0.66rem] uppercase tracking-[0.08em]; }
|
|
.spark-legend { @apply mt-2 flex flex-wrap gap-x-3 gap-y-1 text-xs text-muted; }
|
|
.spark-legend li { @apply flex items-center gap-1.5; }
|
|
|
|
/* ---------- settings ---------- */
|
|
.settings-form > * + * { @apply mt-5; }
|
|
.setting { @apply grid gap-2 border-t border-rule py-3 md:grid-cols-[minmax(0,19rem)_minmax(0,1fr)] md:gap-6; }
|
|
.setting:first-of-type { @apply border-t-0 pt-1; }
|
|
.setting-label { @apply min-w-0; }
|
|
.setting-label label { @apply inline-block; }
|
|
.setting-label code { @apply bg-transparent p-0 text-[0.85rem] font-medium text-ink; overflow-wrap:anywhere; }
|
|
.setting-input { @apply min-w-0; }
|
|
.setting-input > input, .setting-input > select, .setting-input > textarea { @apply w-full max-w-lg; }
|
|
.help, .default { @apply mt-1 text-xs text-muted; overflow-wrap:anywhere; }
|
|
.setting-label .help { @apply max-w-[42ch]; }
|
|
.secret { @apply text-sm text-ink-2; }
|
|
code.lines { @apply mt-1 block whitespace-pre-wrap; }
|
|
button.reset { @apply ml-1 inline min-h-0 rounded-none border-0 bg-transparent p-0 text-xs text-muted underline decoration-rule underline-offset-2 hover:text-ink; }
|
|
.save-bar { @apply sticky bottom-0 z-20 -mx-4 mt-6 flex flex-wrap items-center justify-end gap-x-4 gap-y-2 border-t border-rule bg-paper px-4 py-3 sm:-mx-6 sm:px-6; box-shadow:0 -10px 18px -14px color-mix(in oklab, var(--ink) 55%, transparent); }
|
|
.save-bar .meta { @apply mr-auto text-xs; }
|
|
|
|
/* step 4: table-of-contents sidebar */
|
|
.toc-progress { @apply block h-0.5 w-full appearance-none border-0 p-0 align-middle; background:var(--rule); }
|
|
.toc-progress::-webkit-progress-bar { background:var(--rule); }
|
|
.toc-progress::-webkit-progress-value { background:var(--accent); transition:width 150ms linear; }
|
|
.toc-progress::-moz-progress-bar { background:var(--accent); }
|
|
/* While JS drives the bar from scroll position it must track the finger exactly. */
|
|
.toc-progress[data-live]::-webkit-progress-value { transition:none; }
|
|
@media (prefers-reduced-motion: reduce) { .toc-progress::-webkit-progress-value { transition:none; } }
|
|
[data-toc-panel] { scrollbar-width:thin; scrollbar-color:var(--rule) transparent; scrollbar-gutter:stable; }
|
|
[data-toc-panel]::-webkit-scrollbar { width:0.5rem; }
|
|
[data-toc-panel]::-webkit-scrollbar-thumb { border:2px solid transparent; background:var(--rule); background-clip:padding-box; }
|
|
.toc-link { @apply flex min-h-11 items-baseline gap-2 border-l-2 border-transparent py-2.5 pl-3 text-ink-2 no-underline transition-colors duration-150 hover:border-rule-strong hover:text-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-paper lg:min-h-10 lg:py-1.5; }
|
|
.toc-link[data-passed] { @apply text-ink; }
|
|
.toc-link[data-passed] > span:first-child { @apply text-ink; }
|
|
.toc-link[aria-current] { @apply border-accent font-semibold text-ink; }
|
|
.toc-toggle-icon { opacity:1; scale:1; filter:blur(0); transition-property:opacity, scale, filter; transition-duration:150ms; transition-timing-function:cubic-bezier(0.2, 0, 0, 1); }
|
|
.toc-toggle-icon-close { opacity:0; scale:0.25; filter:blur(4px); }
|
|
[data-toc-toggle][aria-expanded="true"] .toc-toggle-icon-menu { opacity:0; scale:0.25; filter:blur(4px); }
|
|
[data-toc-toggle][aria-expanded="true"] .toc-toggle-icon-close { opacity:1; scale:1; filter:blur(0); }
|
|
/* Without JS the panel is simply visible under the bar; `has-js` is set in the head. */
|
|
@media (width < 64rem) {
|
|
/* Lock only the root: locking body as well makes body its own scroll container and un-sticks the bar. */
|
|
html.toc-panel-open { overflow:hidden; scrollbar-gutter:stable; }
|
|
.has-js [data-toc-panel][data-open="true"] { height:calc(100dvh - var(--toc-panel-top, 3rem)); max-height:calc(100dvh - var(--toc-panel-top, 3rem)); }
|
|
.has-js [data-toc-panel]:not([data-open="true"]) { display:none; }
|
|
}
|
|
@media (max-width:40rem) {
|
|
.kv { @apply block; } .kv dt { @apply mt-2; }
|
|
.rating { @apply items-stretch; } .rating-prompt, .rating-note { @apply basis-full; } .rating-prompt { @apply mb-1; }
|
|
.rating-actions { @apply min-h-11; }
|
|
.rating button[data-label]::after { @apply -inset-y-2; }
|
|
.filters label { @apply w-full; }
|
|
.filters input, .filters select { @apply w-full; }
|
|
}
|
|
}
|