|
|
|
|
@@ -0,0 +1,337 @@
|
|
|
|
|
/* ══════════════════════════════════════════════════════════════════════
|
|
|
|
|
Melange theme — after savq/melange-nvim, whose palette is pure 1970s
|
|
|
|
|
desert: toasted amber, terracotta, olive, dusty rose, laid on roasted
|
|
|
|
|
coffee (dark) or warm plaster (light).
|
|
|
|
|
|
|
|
|
|
So this is not an editor skin — it's a warm print. The scheme's own
|
|
|
|
|
colours are kept exactly; what's built on them is analog: a soft
|
|
|
|
|
Windsor-ish serif, film grain over the whole page, pillowy borderless
|
|
|
|
|
cards that sit in warm shadow rather than inside a line, and a spice
|
|
|
|
|
gradient — the mélange itself, every hue blended — along the header.
|
|
|
|
|
|
|
|
|
|
Dark scheme → melange dark (#292522 grounds, cream ink).
|
|
|
|
|
Light scheme → melange light (plaster, and every ink is a brown).
|
|
|
|
|
══════════════════════════════════════════════════════════════════════ */
|
|
|
|
|
|
|
|
|
|
/* ── Palette (light-dark: see tokens.css) ─────────────────────────── */
|
|
|
|
|
:root[data-style="melange"] {
|
|
|
|
|
/* One family, soft-serif: Fraunces sits at the Souvenir/Cooper end of
|
|
|
|
|
the 70s, which is exactly where this palette lives.
|
|
|
|
|
|
|
|
|
|
Its optical-size axis is the catch — left on `auto`, a headline is
|
|
|
|
|
cut as a high-contrast Didone while the caption under it is a sturdy
|
|
|
|
|
slab, and one family starts reading as three. So opsz is pinned low
|
|
|
|
|
and everywhere: sturdy, low-contrast, warm at every size. Any rule
|
|
|
|
|
that touches SOFT or WONK repeats opsz, since font-variation-settings
|
|
|
|
|
replaces the whole list rather than merging into it. */
|
|
|
|
|
--font-body: "Fraunces", Georgia, serif;
|
|
|
|
|
--font-display: "Fraunces", Georgia, serif;
|
|
|
|
|
--mel-opsz: 14;
|
|
|
|
|
|
|
|
|
|
/* Nothing here has a sharp corner. */
|
|
|
|
|
--radius-xs: 5px;
|
|
|
|
|
--radius-sm: 8px;
|
|
|
|
|
--radius-md: 12px;
|
|
|
|
|
--radius-lg: 16px;
|
|
|
|
|
--radius-xl: 22px;
|
|
|
|
|
|
|
|
|
|
/* Text — a.fg / a.com / a.ui */
|
|
|
|
|
--color-text: light-dark(#54433a, #ece1d7);
|
|
|
|
|
--color-text-secondary: light-dark(#7d6658, #c1a78e);
|
|
|
|
|
--color-text-muted: light-dark(#a98a78, #867462);
|
|
|
|
|
--color-on-accent: light-dark(#f7f4f1, #292522);
|
|
|
|
|
|
|
|
|
|
/* Surfaces — sunken < bg < surface < raised.
|
|
|
|
|
Dark: below a.bg · a.bg · a.float · a.sel.
|
|
|
|
|
Light: a.sel is the well, a.float is the *page* — melange's light
|
|
|
|
|
side keeps its warmth in the floats, so on a page made of
|
|
|
|
|
cards the plaster belongs underneath and the cards are the
|
|
|
|
|
bleached tints above it. Reversing those two tiers is what
|
|
|
|
|
keeps the light scheme from reading as grey. */
|
|
|
|
|
--color-bg: light-dark(#e9e1db, #292522);
|
|
|
|
|
--color-surface: light-dark(#f6f2ef, #34302c);
|
|
|
|
|
--color-surface-raised: light-dark(#fdfbf9, #403a36);
|
|
|
|
|
--color-surface-sunken: light-dark(#d9d3ce, #201d1b);
|
|
|
|
|
|
|
|
|
|
/* Borders — a.ui, but mostly unused: this theme separates by warmth
|
|
|
|
|
and shadow, not by line. */
|
|
|
|
|
--color-border: light-dark(rgb(169 138 120 / 0.38), rgb(134 116 98 / 0.45));
|
|
|
|
|
--color-border-subtle: light-dark(
|
|
|
|
|
rgb(169 138 120 / 0.18),
|
|
|
|
|
rgb(134 116 98 / 0.22)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/* Accent — b.yellow, the spice. Hover walks it toward c.yellow's burn. */
|
|
|
|
|
--color-accent: light-dark(#a06d00, #ebc06d);
|
|
|
|
|
--color-accent-hover: light-dark(#bc5c00, #e49b5d);
|
|
|
|
|
--color-accent-soft: light-dark(
|
|
|
|
|
rgb(160 109 0 / 0.13),
|
|
|
|
|
rgb(235 192 109 / 0.15)
|
|
|
|
|
);
|
|
|
|
|
--color-focus-ring: light-dark(
|
|
|
|
|
rgb(160 109 0 / 0.35),
|
|
|
|
|
rgb(235 192 109 / 0.4)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/* Links */
|
|
|
|
|
--color-link: light-dark(#a06d00, #ebc06d);
|
|
|
|
|
--color-link-hover: light-dark(#bc5c00, #e49b5d);
|
|
|
|
|
|
|
|
|
|
/* Danger — b.red on d.red */
|
|
|
|
|
--color-danger: light-dark(#bf0021, #d47766);
|
|
|
|
|
--color-danger-bg: light-dark(#f1dedf, #7d2a2f);
|
|
|
|
|
--color-danger-hover: light-dark(#c77b8b, #bd8183);
|
|
|
|
|
|
|
|
|
|
/* Success — b.green on d.green */
|
|
|
|
|
--color-success: light-dark(#3a684a, #85b695);
|
|
|
|
|
--color-success-bg: light-dark(#d0e9d1, #233524);
|
|
|
|
|
--color-success-hover: light-dark(#6e9b72, #78997a);
|
|
|
|
|
|
|
|
|
|
/* Warning — c.yellow */
|
|
|
|
|
--color-warning: light-dark(#bc5c00, #e49b5d);
|
|
|
|
|
|
|
|
|
|
/* Overlays */
|
|
|
|
|
--color-overlay: light-dark(rgb(84 67 58 / 0.3), rgb(32 29 27 / 0.72));
|
|
|
|
|
--color-header-user-bg: transparent;
|
|
|
|
|
--color-header-user-bg-hover: light-dark(
|
|
|
|
|
rgb(84 67 58 / 0.07),
|
|
|
|
|
rgb(236 225 215 / 0.07)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/* Misc */
|
|
|
|
|
--color-option-bg: light-dark(#e9e1db, #34302c);
|
|
|
|
|
--color-option-border: light-dark(
|
|
|
|
|
rgb(169 138 120 / 0.18),
|
|
|
|
|
rgb(134 116 98 / 0.22)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/* The rest of the desert — melange's c.* row, dusty rather than bright.
|
|
|
|
|
These are the theme's own furniture colours. */
|
|
|
|
|
--mel-terracotta: light-dark(#bc5c00, #e49b5d);
|
|
|
|
|
--mel-olive: light-dark(#6e9b72, #78997a);
|
|
|
|
|
--mel-rose: light-dark(#be79bb, #b380b0);
|
|
|
|
|
--mel-clay: light-dark(#c77b8b, #bd8183);
|
|
|
|
|
--mel-dust: light-dark(#a98a78, #867462);
|
|
|
|
|
|
|
|
|
|
/* The mélange: every hue of the desert, blended once, left to right. */
|
|
|
|
|
--mel-spice: linear-gradient(
|
|
|
|
|
90deg,
|
|
|
|
|
var(--color-accent),
|
|
|
|
|
var(--mel-terracotta) 32%,
|
|
|
|
|
var(--mel-clay) 58%,
|
|
|
|
|
var(--mel-rose) 78%,
|
|
|
|
|
var(--mel-olive)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/* Shadows are warm and wide — sunlight, not a drop shadow. Light needs
|
|
|
|
|
more of them than dark: on plaster, shadow is the only thing holding
|
|
|
|
|
a card off the page. */
|
|
|
|
|
--shadow-color: light-dark(rgb(122 84 46 / 0.26), rgb(12 9 8 / 0.5));
|
|
|
|
|
--shadow-color-soft: light-dark(rgb(122 84 46 / 0.16), rgb(12 9 8 / 0.32));
|
|
|
|
|
--shadow-color-strong: light-dark(rgb(122 84 46 / 0.36), rgb(12 9 8 / 0.7));
|
|
|
|
|
--shadow-1: 0 2px 10px -2px var(--shadow-color-soft);
|
|
|
|
|
--shadow-2: 0 14px 34px -10px var(--shadow-color),
|
|
|
|
|
0 2px 6px var(--shadow-color-soft);
|
|
|
|
|
--shadow-3: 0 32px 70px -16px var(--shadow-color-strong),
|
|
|
|
|
0 3px 10px var(--shadow-color-soft);
|
|
|
|
|
|
|
|
|
|
/* Grain — one tile, two treatments (see body::after). Defaults are the
|
|
|
|
|
dark ones; the light scheme overrides them by selector. */
|
|
|
|
|
--mel-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)' opacity='0.22'/%3E%3C/svg%3E");
|
|
|
|
|
--mel-grain-blend: soft-light;
|
|
|
|
|
--mel-grain-opacity: 0.55;
|
|
|
|
|
|
|
|
|
|
/* Glow: the spice catches light where it's interactive. */
|
|
|
|
|
--mel-glow: 0 3px 16px -4px
|
|
|
|
|
light-dark(rgb(160 109 0 / 0.45), rgb(235 192 109 / 0.35));
|
|
|
|
|
|
|
|
|
|
/* Component skins — no lines anywhere; warmth and shadow do the work. */
|
|
|
|
|
--border-width: 1px;
|
|
|
|
|
/* The header is a board laid over the page, lighter than it in both
|
|
|
|
|
schemes: a.float on coffee, the bleached tint on plaster. */
|
|
|
|
|
--header-bg: light-dark(#fdfbf9, #34302c);
|
|
|
|
|
--input-focus-bg: var(--color-surface-raised);
|
|
|
|
|
--overlay-filter: blur(6px);
|
|
|
|
|
--modal-border: transparent;
|
|
|
|
|
--card-border: transparent;
|
|
|
|
|
--card-border-width: 1px;
|
|
|
|
|
--card-shadow: var(--shadow-1);
|
|
|
|
|
--card-hover-border: transparent;
|
|
|
|
|
--panel-ring: var(--shadow-1);
|
|
|
|
|
--tab-border: transparent;
|
|
|
|
|
--btn-primary-shadow: var(--mel-glow);
|
|
|
|
|
--btn-primary-shadow-hover: 0 5px 22px -4px
|
|
|
|
|
light-dark(rgb(160 109 0 / 0.55), rgb(235 192 109 / 0.45));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ══════════════════════════════════════════════════════════════════════
|
|
|
|
|
Structural overrides
|
|
|
|
|
══════════════════════════════════════════════════════════════════════ */
|
|
|
|
|
|
|
|
|
|
/* ── One cut of Fraunces, at one optical size, for every size of text ── */
|
|
|
|
|
:root[data-style="melange"],
|
|
|
|
|
[data-style="melange"] body {
|
|
|
|
|
font-optical-sizing: none;
|
|
|
|
|
font-variation-settings: "opsz" var(--mel-opsz), "SOFT" 40, "WONK" 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── The page is sunlit: warm light pools at the top, the ground below
|
|
|
|
|
is flat desert. ───────────────────────────────────────────────── */
|
|
|
|
|
[data-style="melange"] body {
|
|
|
|
|
background-image: radial-gradient(
|
|
|
|
|
120% 55% at 50% -12%,
|
|
|
|
|
var(--color-accent-soft),
|
|
|
|
|
transparent 70%
|
|
|
|
|
);
|
|
|
|
|
background-repeat: no-repeat;
|
|
|
|
|
background-attachment: fixed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── Film grain over everything, so no surface reads as flat pixels.
|
|
|
|
|
Sits above the page, below modals and toasts.
|
|
|
|
|
|
|
|
|
|
The two schemes need opposite grain. On coffee, `soft-light` grits
|
|
|
|
|
the surface without lifting the blacks. On plaster that same blend
|
|
|
|
|
is invisible — pale grey noise on a pale ground has nothing to
|
|
|
|
|
work against — so light multiplies instead, which is what paper
|
|
|
|
|
tooth actually is: tiny shadows. Neither blend nor opacity takes
|
|
|
|
|
light-dark(), so the two parameters are custom properties and the
|
|
|
|
|
scheme is picked by selector below. ───────────────────────────── */
|
|
|
|
|
[data-style="melange"] body::after {
|
|
|
|
|
content: "";
|
|
|
|
|
position: fixed;
|
|
|
|
|
inset: 0;
|
|
|
|
|
z-index: calc(var(--z-modal) - 1);
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
opacity: var(--mel-grain-opacity);
|
|
|
|
|
mix-blend-mode: var(--mel-grain-blend);
|
|
|
|
|
background-image: var(--mel-grain);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Auto (no forced scheme) follows the OS; the attribute forms win over
|
|
|
|
|
it because they come later and are more specific. */
|
|
|
|
|
@media (prefers-color-scheme: light) {
|
|
|
|
|
:root[data-style="melange"] {
|
|
|
|
|
--mel-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.55' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23g)' opacity='0.42'/%3E%3C/svg%3E");
|
|
|
|
|
--mel-grain-blend: multiply;
|
|
|
|
|
--mel-grain-opacity: 0.85;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:root[data-style="melange"][data-color-scheme="light"] {
|
|
|
|
|
--mel-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.55' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23g)' opacity='0.42'/%3E%3C/svg%3E");
|
|
|
|
|
--mel-grain-blend: multiply;
|
|
|
|
|
--mel-grain-opacity: 0.85;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Repeats the fine tile too: forcing dark under a light OS would
|
|
|
|
|
otherwise inherit the coarse one from the media query above. */
|
|
|
|
|
:root[data-style="melange"][data-color-scheme="dark"] {
|
|
|
|
|
--mel-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)' opacity='0.22'/%3E%3C/svg%3E");
|
|
|
|
|
--mel-grain-blend: soft-light;
|
|
|
|
|
--mel-grain-opacity: 0.55;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (prefers-reduced-transparency: reduce) {
|
|
|
|
|
[data-style="melange"] body::after {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── Header — a board over the page: no rule under it, just its own
|
|
|
|
|
shade, a warm shadow, and the spice laid along its bottom edge as
|
|
|
|
|
a single blended stripe. ──────────────────────────────────────── */
|
|
|
|
|
[data-style="melange"] .app-header {
|
|
|
|
|
border-bottom: none;
|
|
|
|
|
box-shadow: var(--shadow-1);
|
|
|
|
|
z-index: var(--z-raised);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-style="melange"] .app-header::after {
|
|
|
|
|
content: "";
|
|
|
|
|
position: absolute;
|
|
|
|
|
inset: auto 0 0 0;
|
|
|
|
|
height: 2px;
|
|
|
|
|
background: var(--mel-spice);
|
|
|
|
|
opacity: 0.7;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Brand — soft and a little wonky, the way 70s display type was cut. */
|
|
|
|
|
[data-style="melange"] .app-header-brand {
|
|
|
|
|
color: var(--mel-terracotta);
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
font-variation-settings: "opsz" var(--mel-opsz), "SOFT" 100, "WONK" 1;
|
|
|
|
|
letter-spacing: -0.01em;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-style="melange"] .form-page-title,
|
|
|
|
|
[data-style="melange"] .profile-subpage-title,
|
|
|
|
|
[data-style="melange"] .profile-section-title,
|
|
|
|
|
[data-style="melange"] .comment-section-title,
|
|
|
|
|
[data-style="melange"] .related-section-title {
|
|
|
|
|
font-variation-settings: "opsz" var(--mel-opsz), "SOFT" 80, "WONK" 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Tabs keep the shared uppercase cut, but the active one glows. */
|
|
|
|
|
[data-style="melange"] .feed-sort-btn.active {
|
|
|
|
|
box-shadow: var(--mel-glow);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-style="melange"] .feed-sort-btn:hover:not(.active) {
|
|
|
|
|
background: var(--color-accent-soft);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── Cards sit in the light rather than inside a line; they rise a
|
|
|
|
|
little when pointed at. ───────────────────────────────────────── */
|
|
|
|
|
[data-style="melange"] .dump-card,
|
|
|
|
|
[data-style="melange"] .journal-card,
|
|
|
|
|
[data-style="melange"] .playlist-card {
|
|
|
|
|
transition:
|
|
|
|
|
box-shadow var(--dur-slow) var(--ease-out),
|
|
|
|
|
transform var(--dur-slow) var(--ease-out);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-style="melange"] .dump-card:hover,
|
|
|
|
|
[data-style="melange"] .journal-card:hover,
|
|
|
|
|
[data-style="melange"] .playlist-card:hover {
|
|
|
|
|
box-shadow: var(--shadow-2);
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
|
|
|
[data-style="melange"] .dump-card:hover,
|
|
|
|
|
[data-style="melange"] .journal-card:hover,
|
|
|
|
|
[data-style="melange"] .playlist-card:hover {
|
|
|
|
|
transform: none;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── Metadata is dust: quiet, warm, never black ──────────────────── */
|
|
|
|
|
[data-style="melange"] .journal-card:not(.journal-card--image) .journal-card-meta,
|
|
|
|
|
[data-style="melange"] .dump-card-date,
|
|
|
|
|
[data-style="melange"] .comment-time,
|
|
|
|
|
[data-style="melange"] .notification-time {
|
|
|
|
|
color: var(--mel-dust);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── A quote is a printed pull-quote: big soft mark, terracotta ──── */
|
|
|
|
|
[data-style="melange"] .journal-card--quote {
|
|
|
|
|
background: var(--color-surface);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-style="melange"] .journal-card-quotemark {
|
|
|
|
|
color: var(--mel-terracotta);
|
|
|
|
|
opacity: 0.28;
|
|
|
|
|
font-variation-settings: "opsz" var(--mel-opsz), "SOFT" 100, "WONK" 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-style="melange"] .journal-card-quote-body {
|
|
|
|
|
font-size: var(--text-lg);
|
|
|
|
|
line-height: 1.35;
|
|
|
|
|
font-variation-settings: "opsz" var(--mel-opsz), "SOFT" 70, "WONK" 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Vote tallies wear the dusty rose of the palette's far end */
|
|
|
|
|
[data-style="melange"] .vote-btn:not(.vote-btn--active) {
|
|
|
|
|
color: var(--mel-rose);
|
|
|
|
|
}
|