375 lines
14 KiB
CSS
375 lines
14 KiB
CSS
/* ══════════════════════════════════════════════════════════════════════
|
|
Melange theme — a blend, which is all the name means now. It began as a
|
|
port of savq/melange-nvim and kept that scheme's idea rather than its
|
|
browns: a handful of hues that only make sense mixed. Here they are a
|
|
sorbet's (pink, coral, lilac, sky, mint), run together as one gradient
|
|
along the header, through the site's name and between a journal's blocks,
|
|
on grounds of berry at night and of blush paper by day.
|
|
|
|
The rest is a print of it: film grain over the whole page, pillowy
|
|
borderless cards that sit in a tinted shadow rather than inside a line,
|
|
a glow under whatever is active, and one quirky grotesque for all of it.
|
|
|
|
The two schemes are one print and its negative. They trade ink and paper:
|
|
the night's lilac-white type is the day's page, the night's plum ground
|
|
the day's type. What doesn't trade is the sorbet: the accent is the same
|
|
pink in both, steeped a little deeper by day so that it holds on paper,
|
|
and what is written on it is the same plum. A pill, a button, the stripe
|
|
under the header are the same objects in either.
|
|
|
|
Dark scheme → berry (plum grounds, lilac-white ink).
|
|
Light scheme → the same on paper (lilac-white grounds, plum ink).
|
|
══════════════════════════════════════════════════════════════════════ */
|
|
|
|
/* ── Palette (light-dark: see tokens.css) ─────────────────────────── */
|
|
:root[data-style="melange"] {
|
|
/* One family. fonts.css loads its weight axis alone, so it is the same
|
|
cut at every size. */
|
|
--font-body: "Bricolage Grotesque Variable", system-ui, sans-serif;
|
|
--font-display: var(--font-body);
|
|
|
|
/* Nothing here has a sharp corner. */
|
|
--radius-xs: 5px;
|
|
--radius-sm: 8px;
|
|
--radius-md: 12px;
|
|
--radius-lg: 16px;
|
|
--radius-xl: 22px;
|
|
|
|
/* Text — by day, the night's card colour. On the accent it is plum in
|
|
both schemes. */
|
|
--color-text: light-dark(#2b2338, #f1e8f3);
|
|
--color-text-secondary: light-dark(#564769, #c8b8d2);
|
|
--color-text-muted: light-dark(#746489, #a898b6);
|
|
--color-on-accent: #2a1830;
|
|
|
|
/* Surfaces — sunken < bg < surface < raised: the page is the tinted
|
|
ground in both schemes and a card the lighter sheet on it. By day the
|
|
page is the night's type colour. */
|
|
--color-bg: light-dark(#f1e8f3, #211a2b);
|
|
--color-surface: light-dark(#fbf7fc, #2b2338);
|
|
--color-surface-raised: light-dark(#fffcff, #372d47);
|
|
--color-surface-sunken: light-dark(#e3d6e7, #19131f);
|
|
|
|
/* Borders — mostly unused: this theme separates by tint and shadow, not
|
|
by line. */
|
|
--color-border: light-dark(rgb(117 98 131 / 0.34), rgb(168 152 182 / 0.36));
|
|
--color-border-subtle: light-dark(
|
|
rgb(117 98 131 / 0.16),
|
|
rgb(168 152 182 / 0.18)
|
|
);
|
|
|
|
/* Accent — one pink, deeper on paper than at night. Hovering walks it one
|
|
step along the blend, to the coral. */
|
|
--color-accent: light-dark(#e2568f, #f48fb1);
|
|
--color-accent-hover: light-dark(#ea6a45, #ff9e80);
|
|
--color-accent-soft: light-dark(
|
|
rgb(226 86 143 / 0.12),
|
|
rgb(244 143 177 / 0.14)
|
|
);
|
|
--color-focus-ring: light-dark(
|
|
rgb(226 86 143 / 0.4),
|
|
rgb(244 143 177 / 0.42)
|
|
);
|
|
|
|
/* Links — a line of text needs more ink than a pill: the pink again,
|
|
steeped until it reads at any size on paper. */
|
|
--color-link: light-dark(#b62d6b, #f48fb1);
|
|
--color-link-hover: light-dark(#c2452b, #ff9e80);
|
|
|
|
--color-danger: light-dark(#c0303a, #ff8a80);
|
|
--color-danger-bg: light-dark(#f8dde0, #4d2030);
|
|
--color-danger-hover: light-dark(#c0303a, #c9404f);
|
|
|
|
--color-success: light-dark(#1b7f66, #86d3b4);
|
|
--color-success-bg: light-dark(#d5efe6, #1d3a33);
|
|
--color-success-hover: light-dark(#17705a, #a3e0c8);
|
|
|
|
--color-warning: light-dark(#b5541f, #ffb38a);
|
|
|
|
/* Overlays */
|
|
--color-overlay: light-dark(rgb(54 38 63 / 0.3), rgb(15 10 20 / 0.72));
|
|
--color-header-user-bg: transparent;
|
|
--color-header-user-bg-hover: light-dark(
|
|
rgb(54 38 63 / 0.07),
|
|
rgb(241 232 243 / 0.08)
|
|
);
|
|
|
|
/* Misc */
|
|
--color-option-bg: light-dark(#eee3ef, #2b2338);
|
|
--color-option-border: light-dark(
|
|
rgb(117 98 131 / 0.16),
|
|
rgb(168 152 182 / 0.18)
|
|
);
|
|
|
|
/* The rest of the blend, beside the accent's pink: the theme's own
|
|
furniture colours. By day each is steeped as far as the accent is, a
|
|
sorbet still and not a flag's primary. */
|
|
--mel-coral: light-dark(#ea6a45, #ff9e80);
|
|
--mel-lilac: light-dark(#8262d8, #b9a2f2);
|
|
--mel-sky: light-dark(#3a8fd4, #86bdea);
|
|
--mel-mint: light-dark(#27a583, #86d3b4);
|
|
|
|
/* The mélange: every hue, blended once, left to right in the order of
|
|
the wheel so no two neighbours mix to mud. */
|
|
--mel-spice: linear-gradient(
|
|
90deg,
|
|
var(--mel-coral),
|
|
var(--color-accent) 26%,
|
|
var(--mel-lilac) 54%,
|
|
var(--mel-sky) 78%,
|
|
var(--mel-mint)
|
|
);
|
|
|
|
/* Shadows are tinted with the ground and wide. Light needs more of them
|
|
than dark: on paper, shadow is the only thing holding a card off the
|
|
page. */
|
|
--shadow-color: light-dark(rgb(96 52 118 / 0.2), rgb(8 4 12 / 0.5));
|
|
--shadow-color-soft: light-dark(rgb(96 52 118 / 0.13), rgb(8 4 12 / 0.32));
|
|
--shadow-color-strong: light-dark(rgb(96 52 118 / 0.32), rgb(8 4 12 / 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 fine tile for both schemes, laid differently (see
|
|
body::after). Defaults are the night's; the day 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 accent catches light where it's interactive. */
|
|
--mel-glow: 0 3px 16px -4px
|
|
light-dark(rgb(226 86 143 / 0.5), rgb(244 143 177 / 0.38));
|
|
|
|
/* Component skins — no lines anywhere; tint and shadow do the work. */
|
|
--border-width: 1px;
|
|
/* The header is a board laid over the page, lighter than it in both
|
|
schemes. */
|
|
--header-bg: light-dark(#fffcff, #2b2338);
|
|
--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(226 86 143 / 0.6), rgb(244 143 177 / 0.48));
|
|
}
|
|
|
|
/* ══════════════════════════════════════════════════════════════════════
|
|
Structural overrides
|
|
══════════════════════════════════════════════════════════════════════ */
|
|
|
|
/* ── The page is lit from above: the accent pools faintly at the top,
|
|
the ground below is flat. ────────────────────────────────────── */
|
|
[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.
|
|
|
|
It is the same fine tile in both schemes, and the blend is what
|
|
differs. On berry, `soft-light` grits the surface without lifting the
|
|
blacks. On paper that blend does nothing, pale grey noise on a pale
|
|
ground having nothing to work against, so the day multiplies it:
|
|
paper tooth, which is tiny shadows, kept faint enough that the page
|
|
stays the colour it is given. Neither blend nor opacity takes
|
|
light-dark(), so the two 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-blend: multiply;
|
|
--mel-grain-opacity: 0.4;
|
|
}
|
|
}
|
|
|
|
:root[data-style="melange"][data-color-scheme="light"] {
|
|
--mel-grain-blend: multiply;
|
|
--mel-grain-opacity: 0.4;
|
|
}
|
|
|
|
/* Forcing dark under a light OS would otherwise inherit the day's two from
|
|
the media query above. */
|
|
:root[data-style="melange"][data-color-scheme="dark"] {
|
|
--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 tinted shadow, and the blend laid along its bottom edge
|
|
as a single 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: 3px;
|
|
background: var(--mel-spice);
|
|
}
|
|
|
|
/* Brand — the site's name is cut out of the blend itself. The fill takes
|
|
the place of the text's colour, so the emoji beside it, which sits
|
|
outside the name's span, keeps its own. The blend is laid twice as wide
|
|
as the name and drifts under it, from its warm end to its cool one and
|
|
back, so the name is never the same two colours for long. Pointed at, the
|
|
name fills with the accent over the blend, as a card's title turns to it. */
|
|
[data-style="melange"] .app-header-brand {
|
|
font-weight: 800;
|
|
letter-spacing: -0.02em;
|
|
}
|
|
|
|
[data-style="melange"] .app-header-brand-name {
|
|
background: var(--mel-spice) 0 0 / 200% 100%;
|
|
-webkit-background-clip: text;
|
|
background-clip: text;
|
|
color: transparent;
|
|
transition: color var(--dur-base);
|
|
animation: mel-drift 7s ease-in-out infinite alternate;
|
|
}
|
|
|
|
[data-style="melange"] .app-header-brand:hover .app-header-brand-name {
|
|
color: var(--color-accent);
|
|
}
|
|
|
|
@keyframes mel-drift {
|
|
to {
|
|
background-position: 100% 0;
|
|
}
|
|
}
|
|
|
|
/* Held still, the name shows the whole blend. */
|
|
@media (prefers-reduced-motion: reduce) {
|
|
[data-style="melange"] .app-header-brand-name {
|
|
background-size: 100% 100%;
|
|
animation: none;
|
|
}
|
|
}
|
|
|
|
/* Headlines are heavy and set a little tight, as the face likes. */
|
|
[data-style="melange"] h1,
|
|
[data-style="melange"] .dump-title,
|
|
[data-style="melange"] .page-title,
|
|
[data-style="melange"] .form-page-title {
|
|
font-weight: 800;
|
|
letter-spacing: -0.02em;
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
}
|
|
|
|
/* A pointed-at headline over a photo sits on a pillow of the night ground
|
|
— the dark scheme's in either scheme, since the scrim under it is dark in
|
|
both — lit in the dark scheme's pink. */
|
|
[data-style="melange"] .journal-card--image .journal-card-title {
|
|
--journal-title-hover-bg: rgb(33 26 43 / 0.86);
|
|
--journal-title-hover-color: #f48fb1;
|
|
--journal-title-hover-radius: var(--radius-sm);
|
|
--journal-title-hover-shadow: 0 4px 14px -4px rgb(0 0 0 / 0.5);
|
|
}
|
|
|
|
/* ── A quote is a printed pull-quote: big mark, in the coral ─────── */
|
|
[data-style="melange"] .journal-card--quote {
|
|
background: var(--color-surface);
|
|
}
|
|
|
|
[data-style="melange"] .journal-card-quotemark {
|
|
color: var(--mel-coral);
|
|
opacity: 0.3;
|
|
}
|
|
|
|
[data-style="melange"] .journal-card-quote-body {
|
|
font-size: var(--text-lg);
|
|
line-height: 1.35;
|
|
}
|
|
|
|
/* The blend runs along the header's bottom edge; between sub-blocks it
|
|
returns as a softer band of the same — the page divided by its own
|
|
palette rather than by a line. A rule can't carry a gradient, so this one
|
|
is a filled bar and the base break's border stands down. */
|
|
[data-style="melange"] .journal-break {
|
|
--journal-break-space: 2rem;
|
|
--journal-break-rule: none;
|
|
height: 3px;
|
|
border-radius: 999px;
|
|
background: var(--mel-spice);
|
|
opacity: 0.6;
|
|
}
|
|
|
|
/* Vote tallies are the blend's lilac, apart from the accent's pink. */
|
|
[data-style="melange"] .vote-btn:not(.vote-btn--active) {
|
|
color: var(--mel-lilac);
|
|
}
|
|
|
|
/* A dump's note is read at length: full ink, where the base dims it. */
|
|
[data-style="melange"] .dump-comment {
|
|
opacity: 1;
|
|
}
|