v3: tracked down many visual inconsistencies, added two new themes
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 43s

This commit is contained in:
khannurien
2026-06-27 14:28:33 +00:00
parent 01940e14be
commit 96c41f01da
11 changed files with 1299 additions and 359 deletions

576
src/themes/nyt.css Normal file
View File

@@ -0,0 +1,576 @@
/* ══════════════════════════════════════════════════════════════════════
"Old Grey Lady" theme — New York Times editorial styling.
Serif typography, paper-and-ink palette, hairline rules, sharp corners,
restrained NYT-blue links, inverted ink-on-paper primary buttons.
Light scheme → newsprint (white page, black ink).
Dark scheme → NYT night mode (near-black page, warm-grey ink).
══════════════════════════════════════════════════════════════════════ */
/* ── Dark variant (default for this theme) ────────────────────────── */
:root[data-style="nyt"] {
--color-text: #e6e6e6;
--color-text-secondary: #ababab;
--color-text-muted: #8a8a8a;
--color-on-accent: #121212;
--color-bg: #121212; /* NYT night */
--color-surface: #1e1e1e;
--color-border: #3a3a3a;
--color-border-subtle: rgba(255, 255, 255, 0.12);
--color-accent: #ececec; /* monochrome: interactive = paper-on-ink */
--color-accent-hover: #ffffff;
--color-link: #ececec;
--color-link-hover: #ffffff;
--color-danger: #ff6b6b;
--color-danger-bg: #2a1414;
--color-danger-hover: #ff9a9a;
--color-success: #6cc070;
--color-success-bg: #122a14;
--color-success-hover: #95d699;
--color-overlay: rgba(0, 0, 0, 0.6);
--color-header-user-bg: rgba(255, 255, 255, 0.06);
--color-header-user-bg-hover: rgba(255, 255, 255, 0.12);
--color-option-bg: #181818;
--color-option-border: #3a3a3a;
}
/* ── Light via system preference (auto color-scheme) ──────────────── */
@media (prefers-color-scheme: light) {
:root[data-style="nyt"]:not([data-color-scheme]) {
--color-text: #121212; /* ink */
--color-text-secondary: #5a5a5a;
--color-text-muted: #767676; /* NYT timestamp grey */
--color-on-accent: #ffffff;
--color-bg: #ffffff; /* white page — content sits directly on it */
--color-surface: #ffffff; /* paper */
--color-border: #e2e2e2; /* hairline rule */
--color-border-subtle: rgba(0, 0, 0, 0.08);
--color-accent: #121212; /* monochrome: interactive = ink-on-paper */
--color-accent-hover: #000000;
--color-link: #1a1a1a;
--color-link-hover: #000000;
--color-danger: #b10000;
--color-danger-bg: #fdecec;
--color-danger-hover: #8a0000;
--color-success: #1a7f37;
--color-success-bg: #e6f4ea;
--color-success-hover: #136a2c;
--color-overlay: rgba(0, 0, 0, 0.4);
--color-header-user-bg: rgba(0, 0, 0, 0.05);
--color-header-user-bg-hover: rgba(0, 0, 0, 0.09);
--color-option-bg: #f2f2f2;
--color-option-border: #e2e2e2;
}
}
/* ── Manual dark override ─────────────────────────────────────────── */
:root[data-style="nyt"][data-color-scheme="dark"] {
color-scheme: dark;
--color-text: #e6e6e6;
--color-text-secondary: #ababab;
--color-text-muted: #8a8a8a;
--color-on-accent: #121212;
--color-bg: #121212;
--color-surface: #1e1e1e;
--color-border: #3a3a3a;
--color-border-subtle: rgba(255, 255, 255, 0.12);
--color-accent: #ececec;
--color-accent-hover: #ffffff;
--color-link: #ececec;
--color-link-hover: #ffffff;
--color-danger: #ff6b6b;
--color-danger-bg: #2a1414;
--color-danger-hover: #ff9a9a;
--color-success: #6cc070;
--color-success-bg: #122a14;
--color-success-hover: #95d699;
--color-overlay: rgba(0, 0, 0, 0.6);
--color-header-user-bg: rgba(255, 255, 255, 0.06);
--color-header-user-bg-hover: rgba(255, 255, 255, 0.12);
--color-option-bg: #181818;
--color-option-border: #3a3a3a;
}
/* ── Manual light override ────────────────────────────────────────── */
:root[data-style="nyt"][data-color-scheme="light"] {
color-scheme: light;
--color-text: #121212;
--color-text-secondary: #5a5a5a;
--color-text-muted: #767676;
--color-on-accent: #ffffff;
--color-bg: #ffffff;
--color-surface: #ffffff;
--color-border: #e2e2e2;
--color-border-subtle: rgba(0, 0, 0, 0.08);
--color-accent: #121212;
--color-accent-hover: #000000;
--color-link: #1a1a1a;
--color-link-hover: #000000;
--color-danger: #b10000;
--color-danger-bg: #fdecec;
--color-danger-hover: #8a0000;
--color-success: #1a7f37;
--color-success-bg: #e6f4ea;
--color-success-hover: #136a2c;
--color-overlay: rgba(0, 0, 0, 0.4);
--color-header-user-bg: rgba(0, 0, 0, 0.05);
--color-header-user-bg-hover: rgba(0, 0, 0, 0.09);
--color-option-bg: #f2f2f2;
--color-option-border: #e2e2e2;
}
/* ══════════════════════════════════════════════════════════════════════
Structural overrides
══════════════════════════════════════════════════════════════════════ */
/* ── Typography — one serif everywhere ───────────────────────────── */
[data-style="nyt"] {
--font-body: "Instrument Serif", Georgia, "Times New Roman", serif;
--font-display: "Instrument Serif", Georgia, "Times New Roman", serif;
font-family: var(--font-body);
font-weight: 400;
line-height: 1.5;
}
/* Sharp, rectilinear corners throughout — newsprint has no rounding. */
[data-style="nyt"] button,
[data-style="nyt"] .dump-card,
[data-style="nyt"] .playlist-card,
[data-style="nyt"] .journal-card,
[data-style="nyt"] .dump-post-header,
[data-style="nyt"] .auth-card,
[data-style="nyt"] .notification-item,
[data-style="nyt"] .user-result-item,
[data-style="nyt"] .comment-node-inner,
[data-style="nyt"] .comment-top-form,
[data-style="nyt"] .rich-content-card,
[data-style="nyt"] .rich-content-badge,
[data-style="nyt"] .modal-card,
[data-style="nyt"] .confirm-modal,
[data-style="nyt"] .user-menu-dropdown,
[data-style="nyt"] .user-list-popover,
[data-style="nyt"] .global-player,
[data-style="nyt"] .global-player-media-wrap,
[data-style="nyt"] .global-player-iframe-wrap,
[data-style="nyt"] .fdz,
[data-style="nyt"] .visibility-toggle,
[data-style="nyt"] .feed-tab,
[data-style="nyt"] .md code,
[data-style="nyt"] .md pre,
[data-style="nyt"]
input:not([type="range"]):not([type="file"]):not([type="checkbox"]):not(
[type="radio"]
),
[data-style="nyt"] textarea {
border-radius: 0;
}
/* ── Headlines — display serif ───────────────────────────────────── */
[data-style="nyt"] h1,
[data-style="nyt"] .app-header-brand,
[data-style="nyt"] .dump-title,
[data-style="nyt"] .dump-card-title,
[data-style="nyt"] .playlist-card-title,
[data-style="nyt"] .journal-card-title,
[data-style="nyt"] .playlist-detail-title,
[data-style="nyt"] .form-page-title,
[data-style="nyt"] .auth-card-title,
[data-style="nyt"] .profile-subpage-title,
[data-style="nyt"] .notifications-title,
[data-style="nyt"] .dump-create-title {
font-family: var(--font-display);
font-weight: 400; /* Instrument Serif is single-weight; size carries it */
letter-spacing: 0;
line-height: 1.14;
}
/* A confident broadsheet type scale */
[data-style="nyt"] .app-header-brand {
font-size: 1.45rem;
letter-spacing: 0;
}
[data-style="nyt"] .dump-title {
font-size: 2.1rem;
}
[data-style="nyt"] .playlist-detail-title {
font-size: 1.9rem;
}
[data-style="nyt"] .dump-card-title,
[data-style="nyt"] .playlist-card-title {
font-size: 1.2rem;
line-height: 1.2;
}
[data-style="nyt"] .journal-card-title {
font-size: 1.15rem;
line-height: 1.18;
}
[data-style="nyt"] .journal-card--feature .journal-card-title {
font-size: 1.6rem;
}
/* Headline links underline on hover (ink stays ink). */
[data-style="nyt"] .dump-card-inner:hover .dump-card-title,
[data-style="nyt"] .playlist-card-inner:hover .playlist-card-title,
[data-style="nyt"] .journal-card-title:hover {
color: var(--color-text);
text-decoration: underline;
text-underline-offset: 2px;
}
/* ── Section labels — sentence case, no shouty caps ──────────────── */
[data-style="nyt"] .comment-section-title,
[data-style="nyt"] .related-section-title,
[data-style="nyt"] .form-page-eyebrow,
[data-style="nyt"] .feed-sort-btn,
[data-style="nyt"] .follow-btn,
[data-style="nyt"] .playlist-badge,
[data-style="nyt"] .dump-card-private-badge,
[data-style="nyt"] .notif-group-label,
[data-style="nyt"] .dump-card-date,
[data-style="nyt"] .journal-card-meta {
text-transform: none;
font-variant-caps: small-caps;
font-size: 90%;
letter-spacing: 0;
}
[data-style="nyt"] .comment-section-title,
[data-style="nyt"] .related-section-title,
[data-style="nyt"] .form-page-eyebrow {
font-weight: 700;
}
/* ── Lead note — a standfirst with an editorial drop cap ─────────── */
[data-style="nyt"] .dump-comment {
border-left: none;
padding: 0;
margin: 0.35rem 0 0;
opacity: 1;
color: var(--color-text-secondary);
font-size: 1.2rem;
line-height: 1.6;
}
[data-style="nyt"] .dump-comment p:first-of-type::first-letter {
float: left;
font-family: var(--font-display);
font-weight: 400;
font-size: 3.4rem;
line-height: 0.78;
padding: 0.12em 0.14em 0 0;
color: var(--color-text);
}
/* ── Generous editorial leading for the lead note; comments stay tight ── */
[data-style="nyt"] .dump-comment,
[data-style="nyt"] .dump-comment p {
line-height: 1.7;
}
/* Tight, ruled comment thread — small padding, snug leading, no extra gaps. */
[data-style="nyt"] .comment-body {
line-height: 1.45;
}
[data-style="nyt"] .comment-node-inner {
padding: 0.5rem 0;
gap: 0.6rem;
}
[data-style="nyt"] .comment-meta {
margin-bottom: 0.1rem;
}
[data-style="nyt"] .comment-list,
[data-style="nyt"] .comment-replies {
gap: 0;
}
/* ── Content isn't boxed — it sits on the page, divided by hairline
rules (à la nytimes.com). No surface fill, no card shadow. ─────────── */
[data-style="nyt"] .dump-card,
[data-style="nyt"] .playlist-card,
[data-style="nyt"] .user-result-item,
[data-style="nyt"] .comment-node-inner {
background: transparent;
border: none;
border-bottom: 1px solid var(--color-border);
border-radius: 0;
box-shadow: none;
}
/* The dump detail is a single article, not a list — no dividing rules. */
[data-style="nyt"] .dump-post-header,
[data-style="nyt"] .dump-rich-content {
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
}
/* Notifications keep their left bar (the unread indicator), lose the box. */
[data-style="nyt"] .notification-item {
border: none;
border-left: 3px solid transparent;
border-bottom: 1px solid var(--color-border);
border-radius: 0;
box-shadow: none;
}
/* No box-hover; the headline underline is the affordance. */
[data-style="nyt"] .dump-card:hover,
[data-style="nyt"] .playlist-card:hover,
[data-style="nyt"] .user-result-item:hover {
background: transparent;
border-color: var(--color-border);
}
/* Genuine containers (forms, embeds, the compose box) keep a hairline box. */
[data-style="nyt"] .auth-card,
[data-style="nyt"] .comment-top-form,
[data-style="nyt"] .rich-content-card {
background: transparent;
border: 1px solid var(--color-border);
box-shadow: none;
}
/* Journal view: a section-front grid of stories divided by hairline rules,
not boxed cards. Close the gaps and rule each cell on its top & left edge so
the rules read as continuous row + column delimiters (à la nytimes.com).
The left-most column's rule is masked off (below) so there's no outer frame
on the left — CSS grid can't target "first column", hence the mask. */
[data-style="nyt"] .journal-grid {
gap: 0;
position: relative;
}
[data-style="nyt"] .journal-card {
background: transparent;
border: none;
border-top: 1px solid var(--color-border);
border-left: 1px solid var(--color-border);
box-shadow: none;
}
/* Page-coloured strip over the grid's content-left edge, hiding the first
column's left rule (left value tracks the grid's padding-left). */
[data-style="nyt"] .journal-grid::before {
content: "";
position: absolute;
top: 0;
bottom: 0;
left: 1.25rem;
width: 1px;
background: var(--color-bg);
z-index: 1;
pointer-events: none;
}
@media (max-width: 460px) {
[data-style="nyt"] .journal-grid::before {
left: 1rem;
}
}
[data-style="nyt"] .journal-card:hover {
border-color: var(--color-border);
transform: none;
box-shadow: none;
}
/* Inset content from the rules so the grid breathes — photos get a margin
frame, text stories sit a little further off the lines. */
[data-style="nyt"] .journal-card--image {
padding: 0.55rem;
}
[data-style="nyt"] .journal-card--image .journal-card-image {
inset: 0.55rem;
}
[data-style="nyt"] .journal-card--quote,
[data-style="nyt"] .journal-card--text {
padding: 1.05rem;
}
/* ── App header — crisp masthead rule ────────────────────────────── */
[data-style="nyt"] .app-header {
border-bottom: 2px solid var(--color-text);
}
[data-style="nyt"] .header-search-below {
border-bottom: 1px solid var(--color-border);
}
[data-style="nyt"] .app-header-user {
border-radius: 0;
}
/* ── Primary button — inverted ink-on-paper (auto-flips per scheme) ─ */
[data-style="nyt"] .btn-primary {
background: var(--color-text);
color: var(--color-bg);
border: 1px solid var(--color-text);
box-shadow: none;
}
[data-style="nyt"] .btn-primary:hover:not(:disabled) {
background: color-mix(in srgb, var(--color-text) 82%, var(--color-bg));
box-shadow: none;
transform: none;
}
/* Secondary / outline buttons — plain hairline box */
[data-style="nyt"] .btn-secondary,
[data-style="nyt"] .btn-border,
[data-style="nyt"] .btn-add-playlist,
[data-style="nyt"] .vote-btn,
[data-style="nyt"] .feed-sort-btn,
[data-style="nyt"] .follow-btn {
border-radius: 0;
}
/* ── Inputs — clean field, ink focus ─────────────────────────────── */
[data-style="nyt"] .form input:focus,
[data-style="nyt"] .form textarea:focus,
[data-style="nyt"] .mention-textarea-wrap textarea:focus {
border-color: var(--color-accent);
box-shadow: none;
}
/* ── Modals — paper sheet with a soft editorial shadow ───────────── */
[data-style="nyt"] .modal-card,
[data-style="nyt"] .confirm-modal,
[data-style="nyt"] .user-menu-dropdown,
[data-style="nyt"] .user-list-popover {
border: 1px solid var(--color-border);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);
}
[data-style="nyt"] .modal-header {
border-bottom: 1px solid var(--color-border);
}
/* ── Rich content cards — keep brand cue, square it, drop the glow ── */
[data-style="nyt"] .rich-content-card {
box-shadow: none;
}
/* ── Global player — framed strip ────────────────────────────────── */
[data-style="nyt"] .global-player {
border: 1px solid var(--color-border);
box-shadow: 0 8px 28px rgba(0, 0, 0, 0.2);
}
/* ── Drop the reply "tree" rules; nesting reads from indentation alone ── */
[data-style="nyt"] .comment-replies {
border-left: none;
margin-top: 0;
}
/* ══════════════════════════════════════════════════════════════════════
Monochrome UI chrome — colour is reserved for meaning (danger, the
notification badge, brand-provider cues). Everything else is ink & paper.
══════════════════════════════════════════════════════════════════════ */
/* Feed sort — section-front tabs: an underline, not a filled chip. */
[data-style="nyt"] .feed-sort-btn {
border: none;
border-bottom: 2px solid transparent;
border-radius: 0;
background: none;
color: var(--color-text-muted);
padding: 0.2rem 0.15rem;
}
[data-style="nyt"] .feed-sort-btn:hover {
background: none;
color: var(--color-text);
}
[data-style="nyt"] .feed-sort-btn.active {
background: none;
color: var(--color-text);
border-bottom-color: var(--color-text);
}
/* Square off the remaining pills & chips. */
[data-style="nyt"] .playlist-badge,
[data-style="nyt"] .dump-card-private-badge,
[data-style="nyt"] .notifications-unread-pill,
[data-style="nyt"] .notification-badge,
[data-style="nyt"] .vote-btn,
[data-style="nyt"] .follow-btn,
[data-style="nyt"] .btn-add-playlist,
[data-style="nyt"] .invite-btn {
border-radius: 0;
border: none;
}
/* Links are now ink, so give the user-link classes a hover underline
to keep them findable without colour. */
[data-style="nyt"] .dump-op-link:hover,
[data-style="nyt"] .playlist-card-owner:hover,
[data-style="nyt"] .playlist-detail-owner:hover,
[data-style="nyt"] .comment-author:hover {
text-decoration: underline;
text-underline-offset: 2px;
}
/* Desaturate decorative UI emoji/icons (the header truck, notification
type icons, card glyphs…). Real content — avatars, uploaded thumbnails,
media — is left in colour. grayscale() also greys the notif icon tints. */
[data-style="nyt"] .app-header-brand,
[data-style="nyt"] .nav-search-btn,
[data-style="nyt"] .search-bar-btn,
[data-style="nyt"] .notification-bell-icon,
[data-style="nyt"] .notif-icon,
[data-style="nyt"] .notifications-empty-icon,
[data-style="nyt"] .notifications-title-bell,
[data-style="nyt"] .dump-card-preview-icon,
[data-style="nyt"] .playlist-card-icon,
[data-style="nyt"] .rich-content-compact-icon,
[data-style="nyt"] .journal-card-glyph,
[data-style="nyt"] .fdz__file-icon,
[data-style="nyt"] .empty-state {
filter: grayscale(1);
}
/* ── Tighter, continuous ruled feed (no inter-item gap; the hairline
bottom rules read as one column). Even vertical padding per item. ── */
[data-style="nyt"] .dump-feed {
gap: 0;
}
[data-style="nyt"] .dump-card-inner,
[data-style="nyt"] .playlist-card-inner {
padding-top: 0.9rem;
padding-bottom: 0.9rem;
}
/* ── Card thumbnail — square & flat box (no pop/shadow), but keep a
hover effect adapted to the theme: the image zooms gently inside its
fixed, clipped frame, the editorial way. ───────────────────────── */
[data-style="nyt"] .dump-card-preview,
[data-style="nyt"] .playlist-card-preview {
border-radius: 0;
transition: none;
}
[data-style="nyt"] .dump-card-inner:hover .dump-card-preview,
[data-style="nyt"] .playlist-card-inner:hover .playlist-card-preview {
transform: none;
box-shadow: none;
}
[data-style="nyt"] .dump-card-preview img,
[data-style="nyt"] .playlist-card-preview img {
transition: transform 0.3s ease;
}
[data-style="nyt"] .dump-card-inner:hover .dump-card-preview img,
[data-style="nyt"] .playlist-card-inner:hover .playlist-card-preview img {
transform: scale(1.09);
}