source: Klonkt/src/assets/css/style.css@ d8f8f07

main
Last change on this file since d8f8f07 was d8f8f07, checked in by Robin <roboburr@…>, 3 weeks ago

Lezen: het snappunt op een anker van nul hoog, niet op het bericht zelf

Robins melding (20-8): "wanneer we aan de onderkant vlakbij de zone komen
begint het te verspringen; het lijkt alsof de bovenkant van de volgende
post aan de onderkant van de viewport snapt." En de goede vraag erbij: ligt
het aan de browser?

Ja, en volgens de spec -- dus geen bug maar een regel die ik niet kende.

Een snapgebied dat GROTER is dan het scherm mag op elke positie blijven
staan waar het het scherm nog vult. Onze berichten waren zelf het
snapgebied, en twee ervan zijn hoger dan de viewport (812 op dev):

bericht 2 1009px geldig van 700 tot 897
bericht 3 839px geldig van 1709 tot 1736

De bovenste stand van zo'n bereik is de onderkant van dat bericht op de
onderrand -- oftewel de bovenkant van het VOLGENDE bericht op de onderrand.
Precies wat Robin zag. En het "verspringen" volgt eruit: net binnen dat
bereik gebeurt er niets, net erbuiten wel, en die grens ligt midden in je
leesgebied. Onze CSS zei gewoon start; de browser mocht het ruimer nemen.

Gemeten voordat ik iets veranderde: landen op 867 (binnen het bereik van
bericht 2) gaf geen snap, landen op 1706 sprong naar 1709.

De reparatie: het snappunt verhuist naar een leeg <span> van NUL HOOG
bovenin elk bericht. Nul is nooit groter dan het scherm, dus er is precies
een geldige positie -- die bovenrand aan de bovenrand.

Na afloop gemeten:

grens naar bericht 2 -> 701 (doel 700)
grens naar bericht 3 -> 1710 (doel 1709)
oude "onderin"-stand 867 -> 701, geen vangst onderin meer
oude "onderin"-stand 1706 -> 1710

Onderweg een eigen fout gevangen: het anker staat BINNEN de padding van het
artikel, dus het snappunt lag 33px te laag en de scheidingslijn viel net
boven beeld (733 waar 700 hoort). scroll-margin-top: 2rem zet dat recht --
die verschuift alleen het snappunt en niet de opmaak, en blijft in de pas
met de padding-top van .read-post.

De regel voor het laatste bericht blijft staan; dat is een ander geval. Zijn
snappunt is onbereikbaar (2548 tegen een maximum van 2356), en dan snapt de
browser naar de bodem.

style.css naar v81.

Suite 1169/1169.

Co-Authored-By: Claude Opus 5 <noreply@…>

  • Property mode set to 100644
File size: 162.9 KB
RevLine 
[7bc636b]1/* ============================================================
2 LOKALE FONTS — SIL OFL 1.1 licensed, self-hosted
3 Geen third-party requests, geen privacy-leak naar Google.
4 Variable WOFF2 bestanden onder /assets/fonts/
5 Licenses in /assets/fonts/licenses/
6 ============================================================ */
7@font-face {
8 font-family: 'Fraunces';
9 font-style: normal;
10 font-display: swap;
11 font-weight: 100 900;
12 src: url('/assets/fonts/fraunces-latin-full-normal.woff2') format('woff2-variations');
13 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;
14}
15@font-face {
16 font-family: 'Fraunces';
17 font-style: italic;
18 font-display: swap;
19 font-weight: 100 900;
20 src: url('/assets/fonts/fraunces-latin-full-italic.woff2') format('woff2-variations');
21 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;
22}
23@font-face {
24 font-family: 'Literata';
25 font-style: normal;
26 font-display: swap;
27 font-weight: 400 700;
28 src: url('/assets/fonts/literata-latin-opsz-normal.woff2') format('woff2-variations');
29 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;
30}
31@font-face {
32 font-family: 'Literata';
33 font-style: italic;
34 font-display: swap;
35 font-weight: 400 700;
36 src: url('/assets/fonts/literata-latin-opsz-italic.woff2') format('woff2-variations');
37 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;
38}
39@font-face {
40 font-family: 'Plus Jakarta Sans';
41 font-style: normal;
42 font-display: swap;
43 font-weight: 400 700;
44 src: url('/assets/fonts/plus-jakarta-sans-latin-wght-normal.woff2') format('woff2-variations');
45 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;
46}
47@font-face {
48 font-family: 'Plus Jakarta Sans';
49 font-style: italic;
50 font-display: swap;
51 font-weight: 400 700;
52 src: url('/assets/fonts/plus-jakarta-sans-latin-wght-italic.woff2') format('woff2-variations');
53 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;
54}
55
[d2b7247]56/* Klonkt publieke stijl — editorial-ish, geen emoji-UI */
[7bc636b]57
58:root {
59 --font-display: 'Fraunces', Georgia, serif;
60 --font-body: 'Literata', Georgia, serif;
61 --font-ui: 'Plus Jakarta Sans', system-ui, sans-serif;
62 --font-mono: ui-monospace, Menlo, Consolas, monospace;
63 --radius: 8px; --transition: 180ms cubic-bezier(.4,0,.2,1);
64 --safe-top: env(safe-area-inset-top, 0); --safe-bot: env(safe-area-inset-bottom, 0);
[a036251]65 /* iOS top inset: starts from env(), but a tiny boot script overrides it with a
66 real/measured value (env() resolves to 0 in some iOS standalone states). */
67 --ios-safe-top: env(safe-area-inset-top, 0px);
[7bc636b]68 color-scheme: light dark;
69}
70
[977f65d]71/* Native controls (datum/tijd-picker, scrollbars) het SITE-thema laten volgen i.p.v.
72 de OS-voorkeur, en de datum/tijd-velden de site-accentkleur geven. Zo staat de
73 ingebouwde kalender-popup in dark + accent (de popup zelf is een browser-widget,
74 dus fonts/randen blijven van de browser). */
75[data-theme="dark"] { color-scheme: dark; }
76[data-theme="light"] { color-scheme: light; }
77input[type="date"], input[type="time"], input[type="datetime-local"] { accent-color: var(--accent, #6b8f71); }
78input[type="date"]::-webkit-calendar-picker-indicator,
79input[type="time"]::-webkit-calendar-picker-indicator,
80input[type="datetime-local"]::-webkit-calendar-picker-indicator { cursor: pointer; opacity: .7; }
81input[type="date"]:hover::-webkit-calendar-picker-indicator,
82input[type="time"]:hover::-webkit-calendar-picker-indicator,
83input[type="datetime-local"]:hover::-webkit-calendar-picker-indicator { opacity: 1; }
84
[7bc636b]85/* ============================================================
86 PALETTES — elk palette definieert alleen bg/tekst/rand shades.
87 --accent wordt LOS ingesteld via de accent-kleur config (inline in template).
88 Palette-selector: <html data-palette="forest"> en optioneel data-theme="dark"|"light".
89 Als geen data-palette = Sage default.
90 ============================================================ */
91
92/* ── SAGE (default) ── warme crème ── */
93:root,
94[data-palette="sage"] {
95 --paper: #faf8f3; --paper-2: #f2ede0;
96 --ink: #1a1a1a; --ink-soft: #3d3833; --ink-muted: #6b6560; --ink-faint: #a8a29e;
97 --rule: #e8e2d5; --rule-2: #d4ccb8;
98}
99@media (prefers-color-scheme: dark) {
100 :root:not([data-theme="light"]):not([data-palette]),
101 [data-palette="sage"]:not([data-theme="light"]) {
102 --paper: #1c1a17; --paper-2: #252220;
103 --ink: #f4ede0; --ink-soft: #d4ccb8; --ink-muted: #a8a29e; --ink-faint: #6b6560;
104 --rule: #3d3833; --rule-2: #4d4740;
105 }
106}
107[data-theme="dark"]:not([data-palette]),
108[data-theme="dark"][data-palette="sage"] {
109 --paper: #1c1a17; --paper-2: #252220;
110 --ink: #f4ede0; --ink-soft: #d4ccb8; --ink-muted: #a8a29e; --ink-faint: #6b6560;
111 --rule: #3d3833; --rule-2: #4d4740;
112}
113
[c9c70cc]114/* ── KLONKT ── merk-standaard: clean wit → bijna-zwart (neutraal, gouden accent) ── */
[dd7e2a2]115[data-palette="klonkt"] {
[c9c70cc]116 --paper: #ffffff; --paper-2: #f4f4f5;
117 --ink: #09090b; --ink-soft: #27272a; --ink-muted: #52525b; --ink-faint: #a1a1aa;
118 --rule: #e4e4e7; --rule-2: #d4d4d8;
[dd7e2a2]119}
120@media (prefers-color-scheme: dark) {
121 [data-palette="klonkt"]:not([data-theme="light"]) {
[c9c70cc]122 --paper: #0a0a0a; --paper-2: #18181b;
123 --ink: #fafafa; --ink-soft: #d4d4d8; --ink-muted: #a1a1aa; --ink-faint: #71717a;
124 --rule: #27272a; --rule-2: #3f3f46;
[dd7e2a2]125 }
126}
127[data-theme="dark"][data-palette="klonkt"] {
[c9c70cc]128 --paper: #0a0a0a; --paper-2: #18181b;
129 --ink: #fafafa; --ink-soft: #d4d4d8; --ink-muted: #a1a1aa; --ink-faint: #71717a;
130 --rule: #27272a; --rule-2: #3f3f46;
[dd7e2a2]131}
132
[7bc636b]133/* ── PAPER ── minimalistisch wit → zwart ── */
134[data-palette="paper"] {
135 --paper: #ffffff; --paper-2: #f4f4f5;
136 --ink: #09090b; --ink-soft: #27272a; --ink-muted: #52525b; --ink-faint: #a1a1aa;
137 --rule: #e4e4e7; --rule-2: #d4d4d8;
138}
139@media (prefers-color-scheme: dark) {
140 [data-palette="paper"]:not([data-theme="light"]) {
141 --paper: #0a0a0a; --paper-2: #18181b;
142 --ink: #fafafa; --ink-soft: #d4d4d8; --ink-muted: #a1a1aa; --ink-faint: #71717a;
143 --rule: #27272a; --rule-2: #3f3f46;
144 }
145}
146[data-theme="dark"][data-palette="paper"] {
147 --paper: #0a0a0a; --paper-2: #18181b;
148 --ink: #fafafa; --ink-soft: #d4d4d8; --ink-muted: #a1a1aa; --ink-faint: #71717a;
149 --rule: #27272a; --rule-2: #3f3f46;
150}
151
152
153/* ── FOREST ── olijfgroen → donker bos ── */
154[data-palette="forest"] {
155 --paper: #f2f6ed; --paper-2: #e1ead6;
156 --ink: #1a2e15; --ink-soft: #2d4a26; --ink-muted: #5a6f52; --ink-faint: #8aa080;
157 --rule: #ccddbd; --rule-2: #adc396;
158}
159@media (prefers-color-scheme: dark) {
160 [data-palette="forest"]:not([data-theme="light"]) {
161 --paper: #0d1f12; --paper-2: #1a331e;
162 --ink: #dcf2d0; --ink-soft: #b8d8a8; --ink-muted: #8aad7c; --ink-faint: #5a7a50;
163 --rule: #2d4a30; --rule-2: #3d5e42;
164 }
165}
166[data-theme="dark"][data-palette="forest"] {
167 --paper: #0d1f12; --paper-2: #1a331e;
168 --ink: #dcf2d0; --ink-soft: #b8d8a8; --ink-muted: #8aad7c; --ink-faint: #5a7a50;
169 --rule: #2d4a30; --rule-2: #3d5e42;
170}
171
172/* ── STONE ── beige bruin → koffie ── */
173[data-palette="stone"] {
174 --paper: #f5f0e8; --paper-2: #e7ddce;
175 --ink: #2b2218; --ink-soft: #4a3a2a; --ink-muted: #78614a; --ink-faint: #a8927b;
176 --rule: #d6c6ac; --rule-2: #bda98a;
177}
178@media (prefers-color-scheme: dark) {
179 [data-palette="stone"]:not([data-theme="light"]) {
180 --paper: #1a130b; --paper-2: #2d2416;
181 --ink: #f5e9d5; --ink-soft: #d4c0a3; --ink-muted: #a8927b; --ink-faint: #786452;
182 --rule: #3d2f1e; --rule-2: #534029;
183 }
184}
185[data-theme="dark"][data-palette="stone"] {
186 --paper: #1a130b; --paper-2: #2d2416;
187 --ink: #f5e9d5; --ink-soft: #d4c0a3; --ink-muted: #a8927b; --ink-faint: #786452;
188 --rule: #3d2f1e; --rule-2: #534029;
189}
190
191/* ── MIDNIGHT ── lavendel → donker paars ── */
192[data-palette="midnight"] {
193 --paper: #f3f1f8; --paper-2: #e3ddf0;
194 --ink: #1e1a2e; --ink-soft: #332c4d; --ink-muted: #5e5478; --ink-faint: #9288a8;
195 --rule: #d4cae3; --rule-2: #b8a9cc;
196}
197@media (prefers-color-scheme: dark) {
198 [data-palette="midnight"]:not([data-theme="light"]) {
199 --paper: #0f0a1f; --paper-2: #1c1432;
200 --ink: #e9def7; --ink-soft: #c4b5d9; --ink-muted: #9d88b8; --ink-faint: #6b5a85;
201 --rule: #2d1f4a; --rule-2: #3d2b5e;
202 }
203}
204[data-theme="dark"][data-palette="midnight"] {
205 --paper: #0f0a1f; --paper-2: #1c1432;
206 --ink: #e9def7; --ink-soft: #c4b5d9; --ink-muted: #9d88b8; --ink-faint: #6b5a85;
207 --rule: #2d1f4a; --rule-2: #3d2b5e;
208}
209
210/* ── SUNSET ── roze crème → diep paars-roze ── */
211[data-palette="sunset"] {
212 --paper: #fdf4f3; --paper-2: #f7e1dc;
213 --ink: #2e1618; --ink-soft: #4d282b; --ink-muted: #7a4a4e; --ink-faint: #b08589;
214 --rule: #ebcac3; --rule-2: #d9a8a0;
215}
216@media (prefers-color-scheme: dark) {
217 [data-palette="sunset"]:not([data-theme="light"]) {
218 --paper: #1f0a14; --paper-2: #321525;
219 --ink: #fce7f3; --ink-soft: #f0c5d3; --ink-muted: #c896a8; --ink-faint: #8a6878;
220 --rule: #4a1f35; --rule-2: #5e2d43;
221 }
222}
223[data-theme="dark"][data-palette="sunset"] {
224 --paper: #1f0a14; --paper-2: #321525;
225 --ink: #fce7f3; --ink-soft: #f0c5d3; --ink-muted: #c896a8; --ink-faint: #8a6878;
226 --rule: #4a1f35; --rule-2: #5e2d43;
227}
228
[19fbe03]229/* ── SAND ── warm papier (subtiel, niet fel geel) → warm donker ── (key blijft 'cream') */
[7bc636b]230[data-palette="cream"] {
[19fbe03]231 --paper: #f7f3ec; --paper-2: #ece5d8;
232 --ink: #232019; --ink-soft: #43392c; --ink-muted: #6f6149; --ink-faint: #a3957c;
233 --rule: #ddd3c0; --rule-2: #c9bca3;
[7bc636b]234}
235@media (prefers-color-scheme: dark) {
236 [data-palette="cream"]:not([data-theme="light"]) {
[19fbe03]237 --paper: #14120d; --paper-2: #221e15;
238 --ink: #efe9dd; --ink-soft: #d0c6b2; --ink-muted: #a3957c; --ink-faint: #6f6149;
239 --rule: #322c20; --rule-2: #463d2c;
[7bc636b]240 }
241}
242[data-theme="dark"][data-palette="cream"] {
[19fbe03]243 --paper: #14120d; --paper-2: #221e15;
244 --ink: #efe9dd; --ink-soft: #d0c6b2; --ink-muted: #a3957c; --ink-faint: #6f6149;
245 --rule: #322c20; --rule-2: #463d2c;
246}
247
[c9c70cc]248/* ── OCEAN ── helder blauw → diep oceaanblauw ── */
[19fbe03]249[data-palette="ocean"] {
[c9c70cc]250 --paper: #eef4fb; --paper-2: #d8e6f7;
251 --ink: #0f2942; --ink-soft: #1d4368; --ink-muted: #4a6e90; --ink-faint: #87a3c0;
252 --rule: #c2d8ee; --rule-2: #a3c2e0;
[19fbe03]253}
254@media (prefers-color-scheme: dark) {
255 [data-palette="ocean"]:not([data-theme="light"]) {
[c9c70cc]256 --paper: #081726; --paper-2: #102a42;
257 --ink: #d6e8fb; --ink-soft: #aecbe8; --ink-muted: #7e9fc0; --ink-faint: #547390;
258 --rule: #1d3a56; --rule-2: #2a4d6e;
[19fbe03]259 }
260}
261[data-theme="dark"][data-palette="ocean"] {
[c9c70cc]262 --paper: #081726; --paper-2: #102a42;
263 --ink: #d6e8fb; --ink-soft: #aecbe8; --ink-muted: #7e9fc0; --ink-faint: #547390;
264 --rule: #1d3a56; --rule-2: #2a4d6e;
[19fbe03]265}
266
[c9c70cc]267/* ── TEAL ── mint-turquoise → diep teal ── */
268[data-palette="teal"] {
269 --paper: #ecf7f5; --paper-2: #cfe9e4;
270 --ink: #0c2e2a; --ink-soft: #194a44; --ink-muted: #467168; --ink-faint: #84aaa2;
271 --rule: #bce0d9; --rule-2: #9bcbc1;
272}
273@media (prefers-color-scheme: dark) {
274 [data-palette="teal"]:not([data-theme="light"]) {
275 --paper: #06201d; --paper-2: #0e332e;
276 --ink: #d4f2ec; --ink-soft: #aad9d0; --ink-muted: #7aaaa0; --ink-faint: #517a72;
277 --rule: #1a4a42; --rule-2: #275e54;
278 }
279}
280[data-theme="dark"][data-palette="teal"] {
281 --paper: #06201d; --paper-2: #0e332e;
282 --ink: #d4f2ec; --ink-soft: #aad9d0; --ink-muted: #7aaaa0; --ink-faint: #517a72;
283 --rule: #1a4a42; --rule-2: #275e54;
284}
285
286/* ── CANDY ── zacht roze-rood → diep kersenrood ── */
[19fbe03]287[data-palette="candy"] {
[c9c70cc]288 --paper: #fdf1f3; --paper-2: #f8d8de;
289 --ink: #3a1018; --ink-soft: #5e1f2a; --ink-muted: #8e4450; --ink-faint: #c2868f;
290 --rule: #f0c5cd; --rule-2: #e3a0ab;
[19fbe03]291}
292@media (prefers-color-scheme: dark) {
293 [data-palette="candy"]:not([data-theme="light"]) {
[c9c70cc]294 --paper: #220810; --paper-2: #3a121d;
295 --ink: #fde0e6; --ink-soft: #f5b8c4; --ink-muted: #cd8b98; --ink-faint: #8e5f6a;
296 --rule: #4d1a28; --rule-2: #632536;
[19fbe03]297 }
298}
299[data-theme="dark"][data-palette="candy"] {
[c9c70cc]300 --paper: #220810; --paper-2: #3a121d;
301 --ink: #fde0e6; --ink-soft: #f5b8c4; --ink-muted: #cd8b98; --ink-faint: #8e5f6a;
302 --rule: #4d1a28; --rule-2: #632536;
303}
304
305/* ── AMBER ── warm honing → diep amber ── */
306[data-palette="amber"] {
307 --paper: #fdf6e9; --paper-2: #f7e6c2;
308 --ink: #3a2a0c; --ink-soft: #5e451a; --ink-muted: #8e7340; --ink-faint: #c2a877;
309 --rule: #f0dca8; --rule-2: #e3c581;
310}
311@media (prefers-color-scheme: dark) {
312 [data-palette="amber"]:not([data-theme="light"]) {
313 --paper: #221a08; --paper-2: #3a2c12;
314 --ink: #fdeecb; --ink-soft: #f0d49a; --ink-muted: #c2a877; --ink-faint: #8e7340;
315 --rule: #4d3a16; --rule-2: #634d20;
316 }
317}
318[data-theme="dark"][data-palette="amber"] {
319 --paper: #221a08; --paper-2: #3a2c12;
320 --ink: #fdeecb; --ink-soft: #f0d49a; --ink-muted: #c2a877; --ink-faint: #8e7340;
321 --rule: #4d3a16; --rule-2: #634d20;
[7bc636b]322}
323
[999aad2]324/* ── ROSE ── zacht roze → wijnrood ── */
325[data-palette="rose"] {
326 --paper: #fdf2f4; --paper-2: #f8dde3;
327 --ink: #2e1419; --ink-soft: #4d242c; --ink-muted: #7a4651; --ink-faint: #b3838d;
328 --rule: #f0c9d1; --rule-2: #e0a3af;
329}
330@media (prefers-color-scheme: dark) {
331 [data-palette="rose"]:not([data-theme="light"]) {
332 --paper: #1f0a0f; --paper-2: #33141c;
333 --ink: #fce4ea; --ink-soft: #f0bcc8; --ink-muted: #c98f9d; --ink-faint: #8a6470;
334 --rule: #4a1f2c; --rule-2: #5e2d3a;
335 }
336}
337[data-theme="dark"][data-palette="rose"] {
338 --paper: #1f0a0f; --paper-2: #33141c;
339 --ink: #fce4ea; --ink-soft: #f0bcc8; --ink-muted: #c98f9d; --ink-faint: #8a6470;
340 --rule: #4a1f2c; --rule-2: #5e2d3a;
341}
342
343
[0251bae]344/* ── TERRACOTTA ── warme klei → diep brick ── (key blijft 'mint' voor DB-compat) */
[999aad2]345[data-palette="mint"] {
[0251bae]346 --paper: #faf2ee; --paper-2: #f2ddd0;
347 --ink: #2e1a12; --ink-soft: #4a2c1e; --ink-muted: #7a5544; --ink-faint: #b3917e;
348 --rule: #eccdbb; --rule-2: #ddb49d;
[999aad2]349}
350@media (prefers-color-scheme: dark) {
351 [data-palette="mint"]:not([data-theme="light"]) {
[0251bae]352 --paper: #1f120c; --paper-2: #2e1c13;
353 --ink: #f7e6da; --ink-soft: #e0c3b0; --ink-muted: #b3917c; --ink-faint: #7a5544;
354 --rule: #4a2c1e; --rule-2: #5e3a28;
[999aad2]355 }
356}
357[data-theme="dark"][data-palette="mint"] {
[0251bae]358 --paper: #1f120c; --paper-2: #2e1c13;
359 --ink: #f7e6da; --ink-soft: #e0c3b0; --ink-muted: #b3917c; --ink-faint: #7a5544;
360 --rule: #4a2c1e; --rule-2: #5e3a28;
[999aad2]361}
362
363/* ── LILAC ── zacht lila → donker violet ── */
364[data-palette="lilac"] {
365 --paper: #faf4fb; --paper-2: #f0e0f3;
366 --ink: #2a1830; --ink-soft: #46294f; --ink-muted: #7a5685; --ink-faint: #b393bd;
367 --rule: #e6cdec; --rule-2: #d4abdd;
368}
369@media (prefers-color-scheme: dark) {
370 [data-palette="lilac"]:not([data-theme="light"]) {
371 --paper: #170a1c; --paper-2: #281433;
372 --ink: #f3e2f7; --ink-soft: #dabce4; --ink-muted: #b088c0; --ink-faint: #7a5a88;
373 --rule: #3d1f4a; --rule-2: #4f2b5e;
374 }
375}
376[data-theme="dark"][data-palette="lilac"] {
377 --paper: #170a1c; --paper-2: #281433;
378 --ink: #f3e2f7; --ink-soft: #dabce4; --ink-muted: #b088c0; --ink-faint: #7a5a88;
379 --rule: #3d1f4a; --rule-2: #4f2b5e;
380}
381
[7bc636b]382/* Accent-tint wordt berekend uit --accent, zodat hij meegaat bij elke accent-keuze.
383 Wordt in template inline gezet; hier alleen een fallback. */
384:root { --accent: #c2410c; --accent-soft: #ea580c; --accent-tint: #fef2e8; }
385
386* { box-sizing: border-box; }
[c3ad46d]387html {
388 -webkit-text-size-adjust: 100%; -webkit-tap-highlight-color: transparent;
389 overscroll-behavior-y: none;
390 /* Horizontaal clippen op ROOT-niveau: dit propageert naar de viewport (geen
391 horizontale scroll) ZONDER position:fixed te breken — html is sowieso de
392 document-scroller. De body mag GEEN overflow-x krijgen, want dan zou die een
393 tweede scroll-container worden en zou de fixed bottom-tab meeschuiven. */
394 overflow-x: hidden;
395}
[7bc636b]396body {
397 margin: 0;
398}
[93d6345]399
400/* ── Thema-scrollbar: slank, afgerond, subtiel — vervangt de standaard chunky
401 browser-scrollbar (met pijltjes) die niet bij het donkere thema past.
402 Werkt op de pagina én op interne scrollers (queue, chat-thread, dropdowns). ── */
403* {
404 scrollbar-width: thin;
405 scrollbar-color: color-mix(in srgb, var(--ink) 28%, transparent) transparent;
406}
407::-webkit-scrollbar { width: 10px; height: 10px; }
408::-webkit-scrollbar-track { background: transparent; }
409::-webkit-scrollbar-thumb {
410 background-color: color-mix(in srgb, var(--ink) 24%, transparent);
411 border-radius: 999px;
412 border: 2px solid transparent; /* transparante rand → optisch slanker (≈6px) */
413 background-clip: content-box;
414}
415::-webkit-scrollbar-thumb:hover {
416 background-color: color-mix(in srgb, var(--accent) 60%, var(--ink));
417}
418::-webkit-scrollbar-corner { background: transparent; }
[441f5d6]419
420/* Login/auth = focus-scherm. Bij htmx-navigatie naar login blijft de bottom-tab
421 uit de vorige pagina in de DOM staan → hier verbergen zodat het login-scherm
422 net zo "kaal" is als bij een full-load (waar de tab niet eens gerenderd wordt). */
423body.on-auth .bottom-tab { display: none; }
[7bc636b]424body:not(.admin) {
425 min-height: 100dvh;
426 background: var(--paper); color: var(--ink);
427 font-family: var(--font-body); font-size: 1.0625rem; line-height: 1.65;
428 font-feature-settings: "liga" 1, "kern" 1, "onum" 1;
429 -webkit-font-smoothing: antialiased;
430 /* v9.4 — Sticky footer: body als flex-kolom, main groeit, footer onderaan */
431 display: flex;
432 flex-direction: column;
433}
434body:not(.admin) #pcms-main { flex: 1 0 auto; }
435body:not(.admin) .site-footer { flex-shrink: 0; }
436body:not(.admin)::before {
437 content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
[5eef817]438 /* Per-palette achtergrond-gradient: opgebouwd uit de palette's EIGEN --paper/--paper-2
439 (diagonale verloop) + een zachte accent-glow erbovenop. Werkt automatisch voor elk
440 palet, light én dark — geen per-palette regels nodig. */
441 background: radial-gradient(ellipse at top, color-mix(in srgb, var(--accent) 6%, transparent), transparent 60%),
442 radial-gradient(ellipse at bottom right, color-mix(in srgb, var(--accent) 7%, transparent), transparent 55%),
443 linear-gradient(160deg, var(--paper) 0%, var(--paper-2) 100%);
[7bc636b]444}
[aadb11e]445/* Klonkt-palet gebruikt nu (net als de andere paletten) de generieke accent-glow
446 hierboven → de achtergrond-gradient volgt de gekozen accentkleur. */
[7bc636b]447::selection { background: var(--accent-tint); color: var(--accent); }
448
449h1, h2, h3, h4 { font-family: var(--font-display); font-weight: 450; line-height: 1.15; letter-spacing: -0.015em; margin: 0; text-wrap: balance; font-variation-settings: "opsz" 144, "SOFT" 50; }
450h1 { font-size: clamp(2rem, 4vw + 1rem, 3.5rem); letter-spacing: -0.022em; }
451h2 { font-size: clamp(1.5rem, 2vw + 1rem, 2.25rem); margin: 1.5rem 0 .4rem; }
452h3 { font-size: 1.375rem; margin: 1.25rem 0 .3rem; }
453p { margin: 0 0 .85em; text-wrap: pretty; hyphens: auto; }
454a { color: var(--ink); text-decoration: underline; text-decoration-color: var(--rule-2); text-underline-offset: 3px; transition: color var(--transition), text-decoration-color var(--transition); }
455a:hover { color: var(--accent); text-decoration-color: var(--accent); }
[2900f1d]456/* Knop-ankers houden hun eigen tekstkleur bij hover. Zonder dit overschrijft de
457 globale a:hover{color:accent} de knop-tekst → die wordt dezelfde kleur als de
458 accent-achtergrond en valt weg (vooral op sites met een felle accent). */
459a.btn:hover, a.epk-btn:hover { color: var(--ink); }
460a.btn-primary:hover, a.btn-danger:hover, a.btn-success:hover, a.button:hover,
461a.epk-btn-primary:hover, a.dls-btn:hover, a.sh-tix:hover, a.dl-go:hover { color: #fff; text-decoration-color: currentColor; }
[7bc636b]462a:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; text-decoration: none; }
463blockquote { margin: 2em 0; padding: .25em 0 .25em 1.25em; border-left: 2px solid var(--accent); font-family: var(--font-display); font-style: italic; font-size: 1.15em; color: var(--ink-soft); }
464code { font-family: var(--font-mono); font-size: .9em; padding: .15em .4em; background: var(--paper-2); border: 1px solid var(--rule); border-radius: 4px; }
465pre { font-family: var(--font-mono); font-size: .85rem; padding: 1.25em 1.5em; background: var(--paper-2); border: 1px solid var(--rule); border-radius: var(--radius); overflow-x: auto; line-height: 1.5; }
466pre code { padding: 0; background: none; border: none; }
467hr { border: 0; border-top: 1px solid var(--rule); margin: 3em auto; max-width: 4rem; }
468
469/* Container — schaalt mee met schermgrootte.
470 42rem default (optimale leesbreedte voor tekst),
471 breder op HD/2.5K/4K waar je meer ademruimte hebt.
472 Grid-view heeft z'n eigen bredere variant (zie .feed-grid). */
473/* Container max-width schaalt per schermformaat.
474 42rem is optimale leesbreedte voor tekst. Op grotere schermen
475 ademruimte geven zonder uitwaaieren. Grid apart geregeld. */
476.container { max-width: 42rem; margin-inline: auto; padding-inline: clamp(1.25rem, 4vw, 2rem); }
477
[703ead3]478/* Post-/leesbreedte. Globaal + hogere specificity (.container.post-page) zodat 'ie
479 de responsive .container-breakpoints (56/72rem) overal overrult — posts én de
480 downloads-pagina krijgen zo exact dezelfde 720px-breedte. */
481.container.post-page { max-width: 720px; margin: 0.5rem auto 2rem; padding: 0 1rem; }
[210a9cb]482
[7bc636b]483/* Laptop / Full HD — 1440px viewport of groter */
484@media (min-width: 1440px) {
485 .container { max-width: 56rem; }
486}
487/* Desktop / QHD 2.5K — 1920px viewport of groter */
488@media (min-width: 1920px) {
489 .container { max-width: 72rem; }
490}
491/* 4K UHD — 2560px viewport of groter */
492@media (min-width: 2560px) {
493 .container { max-width: 88rem; }
494}
495
496/* Grid-view tiles: Instagram-feel. Max-width schaalt met gekozen kolommen zodat
497 tegels niet te groot of te klein worden. */
498@media (min-width: 1200px) {
499 body[data-grid-cols="4"] .feed-grid.container { max-width: 80rem; }
500 body[data-grid-cols="3"] .feed-grid.container { max-width: 64rem; }
501 body[data-grid-cols="2"] .feed-grid.container { max-width: 48rem; }
502}
503@media (min-width: 1920px) {
504 body[data-grid-cols="4"] .feed-grid.container { max-width: 96rem; }
505}
506
507.icon { width: 1.125em; height: 1.125em; flex-shrink: 0; vertical-align: -0.15em; stroke: currentColor; fill: none; display: inline-block; }
508
509/* Masthead */
510.masthead {
511 border-bottom: 1px solid var(--rule);
[a036251]512 padding: calc(1rem + var(--ios-safe-top, 0px)) 0 1rem;
[c2a9522]513 /* GEEN backdrop-filter hier: een voorouder met backdrop-filter blokkeert de
514 frosted blur van het user-menu-dropdown eronder. Masthead is toch bijna
515 dekkend, dus solide bg i.p.v. blur. */
516 background: color-mix(in srgb, var(--paper) 94%, transparent);
[7bc636b]517 position: sticky; top: 0; z-index: 20;
518}
519.masthead-inner { display: flex; align-items: center; justify-content: flex-end; gap: 1.5rem; }
520.masthead-brand { min-width: 0; flex: 1 1 auto; overflow: hidden; }
521.site-title { font-family: var(--font-display); font-size: 1.5rem; font-weight: 500; font-variation-settings: "opsz" 72, "SOFT" 100; letter-spacing: -0.015em; text-decoration: none; color: var(--ink); line-height: 1; display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
522.site-title:hover { color: var(--accent); }
523/* v9.0 — nav-home icon (replaces site-title text in nav) */
524.nav-home {
525 display: inline-flex; align-items: center; justify-content: center;
526 width: 2.25rem; height: 2.25rem;
527 color: var(--ink-soft); text-decoration: none;
528 border-radius: 6px; border: 1px solid transparent;
529 transition: all var(--transition);
530}
531.nav-home:hover { color: var(--ink); background: var(--paper-2); border-color: var(--rule); }
532.nav-home .icon { width: 1.15rem; height: 1.15rem; }
533.top-nav { display: flex; align-items: center; gap: .25rem; flex-shrink: 0; }
534.nav-link, .nav-btn {
535 font-family: var(--font-ui); font-size: .875rem; font-weight: 500;
536 color: var(--ink-soft); text-decoration: none;
537 padding: .5rem .85rem; border-radius: 6px;
538 background: transparent; border: 1px solid transparent;
539 cursor: pointer;
540 display: inline-flex; align-items: center; gap: .4rem;
541 min-height: 2.25rem;
542 transition: all var(--transition);
543}
544.nav-link:hover, .nav-btn:hover { color: var(--ink); background: var(--paper-2); border-color: var(--rule); }
545.nav-link-muted { color: var(--ink-muted); }
546.nav-label { display: none; }
547@media (min-width: 560px) { .nav-label { display: inline; } }
548
549/* Article */
550main { padding-top: 2rem; }
551.page { padding-block: 2rem 3rem; }
552page-container { display: block; font-size: 1.125rem; line-height: 1.75; }
553page-container h1 { font-size: clamp(2rem, 5vw + 1rem, 3.75rem); margin-bottom: 1rem; letter-spacing: -0.025em; }
554page-container img, page-container iframe, page-container video { max-width: 100%; height: auto; display: block; margin: 2rem auto; border-radius: var(--radius); }
555page-container audio { width: 100%; margin: 1.5rem 0; }
556page-container figure { margin: 2rem 0; }
557page-container figcaption { font-family: var(--font-ui); font-size: .85rem; color: var(--ink-muted); text-align: center; margin-top: .5rem; }
558page-container[contenteditable="true"] { outline: 2px dashed var(--accent); outline-offset: .5rem; border-radius: var(--radius); }
559
560.empty { text-align: center; padding: 4rem 1rem; }
[bfa6fa1]561/* Moved account (FEP-7628 slice 3): the signpost above the feed. Loud on
562 purpose — a visitor must not read a stale timeline thinking it is current. */
563.moved-banner {
564 text-align: center;
565 margin: 1.5rem 0 2rem;
566 padding: 1.75rem 1.25rem;
567 border: 2px solid var(--accent, #e8b04b);
568 border-radius: var(--radius, 10px);
569 background: color-mix(in srgb, var(--accent, #e8b04b) 10%, var(--paper-2, var(--paper)));
570}
571.moved-banner-lead { margin: 0 0 .5rem; font-size: 1rem; opacity: .85; }
572.moved-banner-link {
573 display: inline-block;
574 font-family: var(--font-display);
575 font-size: clamp(1.5rem, 5vw, 2.4rem);
576 font-weight: 700;
577 line-height: 1.15;
578 overflow-wrap: anywhere;
579}
580.moved-banner-hint { margin: .75rem 0 0; font-size: .85rem; color: var(--ink-soft); }
[7bc636b]581.empty h1 { font-size: 2rem; }
582.empty p { color: var(--ink-muted); }
583
584/* Embeds */
585.pcms-embed, .folio-embed { margin: 2rem 0; }
[9dbb175]586.pcms-embed iframe, .pcms-embed video, .pcms-embed audio,
587.folio-embed iframe, .folio-embed video, .folio-embed audio { width: 100%; display: block; border: 0; border-radius: var(--radius); }
[7bc636b]588
589/* Article footer */
590.article-footer { display: flex; justify-content: center; padding-top: 2rem; margin-top: 2rem; border-top: 1px solid var(--rule); }
591
592/* Buttons */
593.button {
594 font-family: var(--font-ui); font-size: .875rem; font-weight: 500;
595 padding: .6rem 1.1rem; min-height: 2.5rem;
596 display: inline-flex; align-items: center; gap: .5rem;
597 background: var(--ink); color: var(--paper);
598 border: 1px solid var(--ink);
599 border-radius: 6px;
600 text-decoration: none; cursor: pointer;
601 transition: all var(--transition);
602}
603.button:hover { background: var(--accent); border-color: var(--accent); color: #fff; }
604.button-ghost { background: transparent; color: var(--ink); border-color: var(--rule-2); }
605.button-ghost:hover { background: var(--paper-2); border-color: var(--accent); color: var(--accent); }
606
607/* Pagination */
608.pagination {
609 display: grid;
610 grid-template-columns: 1fr 1fr;
611 gap: 1rem;
612 padding-block: 2rem 4rem;
613 margin-top: 2rem;
614 border-top: 1px solid var(--rule);
615}
616a.pagination-item {
617 display: flex; align-items: center; gap: 1rem; padding: 1rem 1.25rem;
618 border: 2px solid var(--rule-2, var(--rule));
619 border-radius: var(--radius);
620 text-decoration: none; transition: all .15s ease; font-size: .9rem;
621 background: var(--paper-2);
622 min-height: 5rem;
623 min-width: 0;
624 overflow: hidden;
625 cursor: pointer;
626 box-shadow: 0 1px 0 rgba(0,0,0,.02);
627 -webkit-tap-highlight-color: color-mix(in srgb, var(--accent) 30%, transparent);
628 position: relative;
629}
630.pagination-item:not(a) {
631 display: flex; align-items: center; gap: 1rem; padding: 1rem 1.25rem;
632 border: 1px dashed var(--rule); border-radius: var(--radius);
633 font-size: .9rem; background: transparent; min-height: 5rem;
634 min-width: 0; overflow: hidden;
635}
636.pagination-next { flex-direction: row-reverse; text-align: right; }
637a.pagination-item:hover {
638 border-color: var(--accent);
639 background: color-mix(in srgb, var(--accent) 5%, var(--paper-2));
640 transform: translateY(-2px);
641 box-shadow: 0 4px 12px rgba(0,0,0,.08);
642}
643a.pagination-item:active {
644 transform: translateY(0);
645 transition-duration: .05s;
646}
647.pagination-disabled { opacity: .5; cursor: default; font-style: italic; }
648.pagination-body { display: flex; flex-direction: column; gap: .15rem; min-width: 0; flex: 1; }
649.pagination-label {
650 display: block; font-family: var(--font-ui); font-size: .7rem; font-weight: 700;
651 letter-spacing: .08em; text-transform: uppercase; color: var(--accent);
652 margin-bottom: .15rem;
653}
654.pagination-slug {
655 display: block; font-size: .72rem; color: var(--ink-muted);
656 opacity: .75; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
657 font-style: italic;
658}
659.pagination-title {
660 display: block; font-family: var(--font-display); font-weight: 600; color: var(--ink);
661 font-variation-settings: "opsz" 72; font-style: normal;
662 line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
663 font-size: 1.05rem;
664 text-decoration: underline;
665 text-decoration-color: var(--rule-2, var(--rule));
666 text-decoration-thickness: 1px;
667 text-underline-offset: 3px;
668 transition: text-decoration-color .15s;
669}
670a.pagination-item:hover .pagination-title {
671 text-decoration-color: var(--accent);
672}
673.pagination .icon {
674 width: 1.75em; height: 1.75em; flex-shrink: 0;
675 color: var(--accent);
676 transition: transform .15s;
677}
678a.pagination-prev:hover .icon { transform: translateX(-4px); }
679a.pagination-next:hover .icon { transform: translateX(4px); }
680
681/* Pinned-targets → accent-tint en dikkere rand voor duidelijkheid */
682.pagination-item.is-pinned {
683 background: color-mix(in srgb, var(--accent) 8%, var(--paper-2));
684 border-color: color-mix(in srgb, var(--accent) 45%, var(--rule));
685}
686a.pagination-item.is-pinned:hover {
687 background: color-mix(in srgb, var(--accent) 15%, var(--paper-2));
688 border-color: var(--accent);
689}
690
691@media (max-width: 800px) { .pagination { grid-template-columns: 1fr; } }
692
693/* Footer */
[7ca3ffc]694.site-footer { padding: 2rem 0 calc(2rem + env(safe-area-inset-bottom, 0px)); border-top: 1px solid var(--rule); margin-top: 4rem; font-family: var(--font-ui); font-size: .85rem; color: var(--ink-muted); }
[7bc636b]695.site-footer-inner { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 1rem; align-items: center; }
696.site-footer a { color: var(--ink-muted); text-decoration-color: var(--rule); }
697.site-footer a:hover { color: var(--accent); }
698.site-footer-links { display: flex; gap: 1rem; }
699.sep { color: var(--ink-faint); margin: 0 .5rem; }
700.footer-tagline { font-style: italic; opacity: .8; }
701
702@media print {
703 .masthead, .pagination, .site-footer, .article-footer, .top-nav { display: none; }
704 body { background: #fff; color: #000; }
705}
706@media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition: none !important; animation: none !important; } }
707
708/* ============================================================
709 V7 ADDITIONS — post metadata UI + audio player + post-images
710 ============================================================ */
711
712/* Post header */
713.post-header { margin: 0 0 2rem; }
714.post-cover {
715 margin: 0 0 1.5rem;
716 border-radius: 8px;
717 overflow: hidden;
718 background: color-mix(in srgb, var(--fg) 4%, transparent);
719}
720.post-cover img {
721 display: block;
722 width: 100%;
[45d22b1]723 height: auto; /* volledige (niet-bijgesneden) hoogte */
724 /* geen max-height/object-fit: cover meer → de hele afbeelding toont,
725 volle containerbreedte, zijkanten gerespecteerd. */
[7bc636b]726}
727.post-title { font-size: clamp(1.6rem, 4vw, 2.6rem); line-height: 1.15; margin: 0 0 .5rem; letter-spacing: -.02em; }
728
729/* Pin banner — duidelijk zichtbaar dat een post gepind is */
730.post-pin-banner {
731 display: inline-flex;
732 align-items: center;
733 gap: .5rem;
734 background: color-mix(in srgb, var(--accent) 14%, transparent);
735 border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
736 color: var(--accent);
737 padding: .4rem .8rem;
738 border-radius: 999px;
739 font-size: .75rem;
740 font-weight: 600;
741 text-transform: uppercase;
742 letter-spacing: .08em;
743 margin: 0 0 .85rem;
744 line-height: 1;
745}
746.post-pin-banner-icon { font-size: 1rem; line-height: 1; }
747.post-pin-banner-sep { opacity: .5; }
748.post-pin-banner-pos { opacity: .85; }
749.post-date {
750 color: var(--fg-muted, #888);
751 font-size: .85rem;
752 letter-spacing: .05em;
753 text-transform: uppercase;
754 margin: 0 0 1.5rem;
755}
756
757/* Post-images in content (resize + align) */
758.post-image {
759 margin: 1.5rem 0;
760}
761.post-image img {
762 display: block;
763 height: auto;
764 border-radius: 6px;
765 max-width: 100%;
766}
767.post-image figcaption {
768 font-size: .85rem;
769 color: var(--fg-muted, #888);
770 margin-top: .5rem;
771 font-style: italic;
772 text-align: center;
773}
774.post-image--small img { max-width: 240px; }
775.post-image--medium img { max-width: 440px; }
776.post-image--large img { max-width: 720px; }
777.post-image--full img { width: 100%; max-width: 100%; }
778.post-image--left { text-align: left; }
779.post-image--left img { margin-left: 0; margin-right: auto; }
780.post-image--center { text-align: center; }
781.post-image--center img { margin-left: auto; margin-right: auto; }
782.post-image--right { text-align: right; }
783.post-image--right img { margin-left: auto; margin-right: 0; }
784
[d8c6a83]785/* Afbeeldingen in de post-tekst vullen ALTIJD de containerbreedte en houden hun
786 natuurlijke (niet-bijgesneden) hoogte — geen vaste hoogte / geen crop. */
787.post-content img {
788 display: block;
789 width: 100%;
790 max-width: 100%;
791 height: auto;
792 border-radius: 6px;
793 margin: 1.4em auto;
794}
795
[97bcf7e]796/* Video in de post-tekst (C2S-uploads uit Shaer): dezelfde maatvoering als
797 afbeeldingen, plus een plafond. Zonder deze regel rendert een <video> op
798 zijn natuurlijke maat en duwt een portret-video de hele kolom vol; met
799 object-fit blijft het beeld heel binnen het kader. Geldt ook voor de
800 Krant/Berichten (tl-content), waar dezelfde content langskomt. */
801.post-content video, .tl-content video {
802 display: block;
803 width: 100%;
804 max-width: 100%;
805 max-height: min(70vh, 540px);
806 height: auto;
807 object-fit: contain;
808 background: #000;
809 border-radius: 6px;
810 margin: 1.4em auto;
811}
812.post-content audio, .tl-content audio { width: 100%; display: block; margin: 1em auto; }
813
[7bc636b]814/* Mini-player + bottom-tab clearance: applied to .pcms-main so the footer
815 is NOT pushed below the viewport bottom. The bars are position:fixed so
816 they overlap whatever they sit on top of; the padding ensures the last
817 content row isn't covered. Footer naturally follows main and now sits
818 exactly at viewport-bottom on short pages (sticky footer flex). */
819.pcms-main { padding-bottom: 5.5rem; }
820body.has-audio-player .pcms-main { padding-bottom: 5.5rem; }
821
[9ef3c56]822/* Mobiel toetsenbord open (body.kb-open, gezet via visualViewport in shell.ejs):
823 verberg de vaste onderbalken — anders zweven de bottom-tab + mini-speler boven
824 het toetsenbord of overlappen ze het invoerveld. Ze komen terug zodra het
825 toetsenbord sluit. De extra clearance onderaan is dan ook niet meer nodig. */
826body.kb-open .bottom-tab,
827body.kb-open .audio-player { display: none !important; }
828body.kb-open .pcms-main { padding-bottom: 1rem; }
829
[5d68686]830/* Mobiel & tablet (touch): scrollbalken verbergen — scrollen blijft werken, alleen
831 de balk-UI is weg (geen verwarrende/dubbele balken). */
832@media (pointer: coarse) {
833 * { scrollbar-width: none; -ms-overflow-style: none; }
834 *::-webkit-scrollbar { width: 0; height: 0; display: none; }
835}
836
[d188736]837/* Afbeeldingen lastiger op te slaan (frictie, geen echte beveiliging): geen
838 sleep-naar-bureaublad, geen iOS long-press-bewaarmenu. Rechtsklik wordt in JS
839 geblokkeerd (zie shell.ejs). Covers/hero zijn al CSS-achtergronden = niet via
840 "afbeelding opslaan" te pakken. */
841img { -webkit-user-drag: none; -khtml-user-drag: none; -moz-user-drag: none; user-drag: none; -webkit-touch-callout: none; }
842
[7bc636b]843/* ============================================================
844 AUDIO PLAYER v7.1 — SVG iconen, thema-aware, geen emoji
845 ============================================================ */
846.audio-player {
847 position: fixed;
848 left: 0; right: 0; bottom: 0;
849 background: color-mix(in srgb, var(--paper, #fff) 96%, var(--ink, #000));
850 border-top: 1px solid var(--rule, rgba(0,0,0,.1));
851 color: var(--ink, #222);
852 z-index: 1000;
853 backdrop-filter: blur(12px);
854 -webkit-backdrop-filter: blur(12px);
855 box-shadow: 0 -4px 20px rgba(0,0,0,.04);
856}
857[data-theme="dark"] .audio-player {
858 background: color-mix(in srgb, var(--paper, #1a1a1a) 92%, #fff);
859 box-shadow: 0 -4px 20px rgba(0,0,0,.3);
860}
861.audio-player-inner {
862 display: grid;
863 grid-template-columns: minmax(0, 1.6fr) auto minmax(180px, 2fr) auto;
864 gap: 1rem;
865 align-items: center;
866 padding: .65rem 1.25rem;
867 max-width: 1400px;
868 margin: 0 auto;
869}
870
871/* v9.0 — Clickable trigger dat cover + meta combineert zodat klikken erop sheet opent */
872.audio-player-expand-trigger {
873 display: flex;
874 align-items: center;
875 gap: .65rem;
876 min-width: 0;
877 background: none;
878 border: none;
879 padding: 0;
880 margin: 0;
881 cursor: pointer;
882 color: inherit;
883 text-align: left;
884 font: inherit;
885 border-radius: 6px;
886 transition: background .15s;
887}
888.audio-player-expand-trigger:hover {
889 background: color-mix(in srgb, var(--ink, #000) 6%, transparent);
890}
891
892/* Cover art */
893.audio-player-cover {
894 width: 48px; height: 48px;
895 border-radius: 4px;
896 background: linear-gradient(135deg,
897 var(--accent, #c2410c),
898 color-mix(in srgb, var(--accent, #c2410c) 55%, #000));
899 background-size: cover;
900 background-position: center;
901 flex-shrink: 0;
902 position: relative;
903}
904.audio-player-cover.has-image {
905 background-blend-mode: normal;
906}
907
908/* Meta — titel + artiest */
909.audio-player-meta {
910 min-width: 0;
911 display: flex;
912 flex-direction: column;
913 gap: 2px;
914}
915.audio-player-title-wrap {
916 overflow: hidden;
917 white-space: nowrap;
918 position: relative;
919}
920.audio-player-title {
921 display: inline-block;
922 font-family: var(--font-ui, inherit);
923 font-weight: 600;
924 font-size: .9rem;
925 line-height: 1.3;
926 letter-spacing: -.01em;
927 color: var(--ink, inherit);
928 white-space: nowrap;
929}
930.audio-player-title.is-overflowing {
931 animation: audio-title-marquee 6s ease-in-out infinite alternate;
932}
933@keyframes audio-title-marquee {
934 0%, 8% { transform: translateX(0); }
935 92%, 100% { transform: translateX(calc(-1 * var(--audio-shift, 0px))); }
936}
937.audio-player-artist {
938 font-family: var(--font-ui, inherit);
939 font-size: .74rem;
940 line-height: 1.3;
941 color: var(--ink-muted, rgba(0,0,0,.55));
942 white-space: nowrap;
943 overflow: hidden;
944 text-overflow: ellipsis;
945}
946
947/* Controls — prev / play / next */
948.audio-player-controls {
949 display: flex;
950 gap: .1rem;
951 align-items: center;
952}
953.audio-btn {
954 background: transparent;
955 border: none;
956 color: inherit;
957 cursor: pointer;
958 padding: .5rem;
959 border-radius: 50%;
960 transition: background .15s, color .15s, transform .08s;
961 display: inline-flex;
962 align-items: center;
963 justify-content: center;
964 position: relative;
965}
966.audio-btn svg {
967 width: 18px; height: 18px;
968 display: block;
969}
970.audio-btn:hover { background: color-mix(in srgb, var(--ink, #000) 8%, transparent); }
971.audio-btn:active { transform: scale(.94); }
972.audio-btn-play {
973 background: var(--accent, #c2410c);
974 color: #fff;
975 width: 38px; height: 38px;
976 padding: 0;
977}
978.audio-btn-play:hover {
979 background: color-mix(in srgb, var(--accent, #c2410c) 85%, #fff);
980}
981[data-theme="dark"] .audio-btn-play:hover {
982 background: color-mix(in srgb, var(--accent, #c2410c) 85%, #000);
983}
984.audio-btn-play svg { width: 16px; height: 16px; }
985.audio-btn-play .icon-pause { display: none; }
986.audio-player.is-playing .audio-btn-play .icon-play { display: none; }
987.audio-player.is-playing .audio-btn-play .icon-pause { display: block; }
988
989/* Progress bar */
990.audio-player-progress {
991 display: flex;
992 gap: .75rem;
993 align-items: center;
994 min-width: 0;
995}
996.audio-time {
997 font-size: .7rem;
998 color: var(--ink-muted, rgba(0,0,0,.55));
999 font-variant-numeric: tabular-nums;
1000 min-width: 2.7em;
1001 text-align: center;
1002}
1003.audio-seek {
1004 flex: 1;
1005 min-width: 0;
1006 cursor: pointer;
1007 padding: .5rem 0;
1008 position: relative;
1009}
1010.audio-seek-bar {
1011 height: 3px;
1012 background: color-mix(in srgb, var(--ink, #000) 12%, transparent);
1013 border-radius: 2px;
1014 overflow: hidden;
1015 transition: height .15s;
1016}
1017.audio-seek:hover .audio-seek-bar { height: 5px; }
1018.audio-seek-fill {
1019 height: 100%;
1020 background: var(--accent, #c2410c);
1021 width: 0%;
1022 transition: width .1s linear;
1023}
1024
1025/* Volume — popup on hover */
1026.audio-player-volume {
1027 position: relative;
1028 display: flex;
1029 align-items: center;
1030}
1031.audio-btn .icon-mute { display: none; }
1032.audio-player.is-muted .audio-btn .icon-vol { display: none; }
1033.audio-player.is-muted .audio-btn .icon-mute { display: block; }
1034.audio-volume-popup {
1035 position: absolute;
1036 bottom: calc(100% + 8px);
1037 left: 50%;
1038 transform: translateX(-50%) scale(.95);
1039 transform-origin: bottom center;
1040 background: var(--paper, #fff);
1041 border: 1px solid var(--rule, rgba(0,0,0,.1));
1042 border-radius: 8px;
1043 padding: .75rem .5rem;
1044 box-shadow: 0 4px 16px rgba(0,0,0,.15);
1045 opacity: 0;
1046 pointer-events: none;
1047 transition: opacity .15s, transform .15s, visibility .15s;
1048 height: 110px;
1049 visibility: hidden;
1050}
1051/* Invisible bridge tussen knop en popup zodat hover niet breekt */
1052.audio-volume-popup::after {
1053 content: '';
1054 position: absolute;
1055 bottom: -12px;
1056 left: -10px;
1057 right: -10px;
1058 height: 16px;
1059}
1060[data-theme="dark"] .audio-volume-popup {
1061 background: color-mix(in srgb, var(--paper, #111) 92%, #fff);
1062}
1063.audio-player-volume:hover .audio-volume-popup,
1064.audio-player-volume:focus-within .audio-volume-popup,
1065.audio-player-volume.is-open .audio-volume-popup {
1066 opacity: 1;
1067 visibility: visible;
1068 transform: translateX(-50%) scale(1);
1069 pointer-events: auto;
1070}
1071.audio-volume-popup input[type=range] {
1072 /* Standard vertical slider — replaces deprecated -webkit-appearance: slider-vertical. */
1073 writing-mode: vertical-lr;
1074 direction: rtl;
1075 width: 6px;
1076 height: 90px;
1077 accent-color: var(--accent, #c2410c);
1078 /* Grotere hit-area via pseudo-touch padding */
1079 padding: 0 12px;
1080 box-sizing: content-box;
1081 cursor: pointer;
1082}
1083
1084/* Mobile */
1085@media (max-width: 720px) {
1086 .audio-player-inner {
1087 /* v9.0 — 3 cols: expand-trigger (cover+meta) | controls | volume */
1088 grid-template-columns: minmax(0, 1fr) auto auto;
1089 gap: .5rem;
1090 padding: .5rem .8rem;
1091 }
1092 .audio-player-progress {
1093 display: none;
1094 }
1095 .audio-player-cover { width: 40px; height: 40px; }
1096 .audio-btn-play { width: 34px; height: 34px; }
1097 body.has-audio-player .pcms-main { padding-bottom: 4.2rem; }
1098 /* Verberg titel-artiest op bijzonder smal, verstop volume op mobile */
1099 .audio-player-volume { display: none; }
1100}
1101
1102/* Ultra-small schermen (iPhone 4 = 320px; iPhone SE 1st gen = 320px;
1103 iPhone mini ~360px). v9.3 — alles vanaf 320px moet werken; daaronder
1104 accepteren we wel/niet. */
1105@media (max-width: 380px) {
1106 .audio-player-inner {
1107 gap: .35rem;
1108 padding: .4rem .6rem;
1109 }
1110 .audio-player-expand-trigger {
1111 gap: .45rem;
1112 }
1113 .audio-player-cover { width: 36px; height: 36px; }
1114 .audio-player-title { font-size: .88rem; }
1115 .audio-player-artist { font-size: .72rem; }
1116 .audio-player-controls { gap: .15rem; }
1117 .audio-btn { width: 30px; height: 30px; }
1118 .audio-btn svg { width: 16px; height: 16px; }
1119 .audio-btn-play { width: 32px; height: 32px; }
1120 .audio-btn-play svg { width: 18px; height: 18px; }
1121
1122 /* v9.3 — Tracklist compact op smalle telefoons.
1123 Leader 28×28, kleinere gap, padding strakker. Tijd in monoscript blijft
1124 leesbaar; titel krijgt 5-10px meer ruimte. */
1125 .pat-row {
1126 grid-template-columns: 28px 1fr auto;
1127 gap: .5rem;
1128 padding: .45rem .65rem;
1129 }
1130 .pat-row .pat-num,
1131 .pat-row .pat-cover {
1132 width: 28px;
1133 height: 28px;
1134 }
1135 .pat-row::before {
1136 left: .65rem;
1137 width: 28px; height: 28px;
1138 -webkit-mask-size: 22px 22px;
1139 mask-size: 22px 22px;
1140 }
1141 .pat-row .pat-title { font-size: .92rem; }
1142 .pat-row .pat-artist { font-size: .74rem; }
1143 .pat-row .pat-duration { font-size: .74rem; }
1144
1145 /* v9.3 — Album binnen post: cover + tracks compacter */
1146 .post-album-cover {
1147 width: 90px;
1148 height: 90px;
1149 }
1150 .post-album-header {
1151 gap: .65rem;
1152 padding: .65rem;
1153 }
1154 .post-album-title { font-size: 1rem; }
1155
1156 /* v9.3 — Profile-header bovenin compacter */
1157 .profile-photo {
1158 width: 48px !important;
1159 height: 48px !important;
1160 }
1161 .profile-content {
1162 gap: .65rem;
1163 }
1164
1165 /* v9.3 — Install-app modal: minder padding, kleinere knoppen */
1166 .install-modal-inner {
1167 padding: 1rem;
1168 }
1169 .install-app-btn {
1170 padding: .55rem 1rem;
1171 font-size: .9rem;
1172 }
1173
[c3ad46d]1174 /* v9.3 — horizontaal clippen gebeurt nu globaal op html (zie de html-regel
1175 bovenaan). Hier bewust NIETS op body zetten: body als scroll-container zou
1176 de fixed bottom-tab op mobiel laten meeschuiven. */
[7bc636b]1177}
1178
1179/* iPhone 4 / iPhone SE 1st gen / iPhone 5/5s (320px) — strakste niveau */
1180@media (max-width: 340px) {
1181 .audio-player-inner {
1182 padding: .35rem .5rem;
1183 }
1184 .audio-player-artist { display: none; }
1185 .audio-player-cover { width: 32px; height: 32px; }
1186 body.has-audio-player .pcms-main { padding-bottom: 3.6rem; }
1187 /* Expand-sheet wat strakker */
1188 .audio-sheet-panel {
1189 padding: .5rem 1rem 1.5rem;
1190 }
1191 .audio-sheet-title { font-size: 1.2rem; }
1192 .audio-sheet-artist { font-size: .9rem; }
1193 .audio-sheet-play { width: 60px; height: 60px; }
1194 .audio-sheet-play svg { width: 26px; height: 26px; }
1195 .audio-sheet-btn { width: 42px; height: 42px; }
1196 .audio-sheet-btn svg { width: 24px; height: 24px; }
1197 .audio-sheet-controls { gap: 1rem; }
1198
1199 /* v9.3 — Op iPhone 4 (320px): tracklist nog strakker */
1200 .pat-row {
1201 grid-template-columns: 26px 1fr auto;
1202 gap: .4rem;
1203 padding: .4rem .55rem;
1204 }
1205 .pat-row .pat-num,
1206 .pat-row .pat-cover {
1207 width: 26px;
1208 height: 26px;
1209 }
1210 .pat-row::before {
1211 left: .55rem;
1212 width: 26px; height: 26px;
1213 -webkit-mask-size: 20px 20px;
1214 mask-size: 20px 20px;
1215 }
1216 .pat-row .pat-artist {
1217 display: none; /* op extreem smal weglaten ten gunste van titel */
1218 }
1219 .pat-row .pat-title { font-size: .9rem; }
1220 .pat-row .pat-duration { font-size: .72rem; }
1221
1222 /* Container padding reduceren voor max content-breedte */
1223 .container {
1224 padding-inline: 1rem !important;
1225 }
1226
1227 /* Post-cover (de grote bovenste) krimpen */
1228 .post-cover {
1229 max-height: 200px;
1230 }
1231}
1232
1233/* ============================================================
1234 v9.0 — Audio player expand-sheet (Spotify-style "now playing")
1235 Slide-up half-screen met grote cover, track info, big controls
1236 ============================================================ */
1237.audio-sheet {
1238 position: fixed;
1239 inset: 0;
1240 z-index: 1100;
1241 pointer-events: none;
1242 opacity: 0;
1243 transition: opacity .25s ease;
1244}
1245.audio-sheet.is-open {
1246 pointer-events: auto;
1247 opacity: 1;
1248}
1249.audio-sheet-backdrop {
1250 position: absolute;
1251 inset: 0;
1252 /* v9.3 — Blur en overlay-dim allebei via CSS-variabele --pcms-sheet-progress
1253 (1 = volledig, 0 = weg). JS update tijdens drag; CSS-transition pakt
1254 open/close af. Sterke blur (24px) zodat 't effect goed zichtbaar is. */
1255 background: rgb(0 0 0 / calc(.4 * var(--pcms-sheet-progress, 1)));
1256 backdrop-filter: blur(calc(24px * var(--pcms-sheet-progress, 1)));
1257 -webkit-backdrop-filter: blur(calc(24px * var(--pcms-sheet-progress, 1)));
1258 transition: background .25s ease,
1259 backdrop-filter .25s ease,
1260 -webkit-backdrop-filter .25s ease;
1261 will-change: backdrop-filter, background;
1262}
1263/* Tijdens drag: instant updates vanuit JS, geen transition */
1264.audio-sheet-panel.is-dragging ~ .audio-sheet-backdrop,
1265.audio-sheet-backdrop.is-dragging {
1266 transition: none;
1267}
1268.audio-sheet-panel {
1269 position: absolute;
1270 left: 0; right: 0; bottom: 0;
1271 background: var(--paper, #fff);
1272 border-top-left-radius: 20px;
1273 border-top-right-radius: 20px;
1274 box-shadow: 0 -20px 60px rgba(0, 0, 0, .25);
1275 padding: .75rem 1.5rem 2rem;
1276 max-height: 85vh;
1277 overflow-y: auto;
1278 /* v9.2.1 — scroll blijft binnen panel, geen chaining naar body (iOS-proof) */
1279 overscroll-behavior: contain;
1280 touch-action: pan-y;
1281 /* Hide scrollbar but keep scrollable */
1282 scrollbar-width: none; /* Firefox */
1283 -ms-overflow-style: none; /* IE/Edge */
1284 transform: translateY(100%);
1285 transition: transform .3s cubic-bezier(.22, .9, .3, 1),
1286 opacity .3s cubic-bezier(.22, .9, .3, 1);
1287 display: flex;
1288 flex-direction: column;
1289 gap: 1rem;
1290 color: var(--ink);
1291}
1292.audio-sheet-panel::-webkit-scrollbar {
1293 display: none; /* Chrome/Safari */
1294}
1295/* Body scroll lock wanneer sheet open is */
1296body.audio-sheet-locked {
1297 overflow: hidden;
1298}
1299.audio-sheet.is-open .audio-sheet-panel {
1300 transform: translateY(0);
1301}
1302
1303/* v9.3 — Drag-zone: pill bovenaan + cover. Hele strook is touch-target voor
1304 swipe-down-to-close. Pull-to-refresh is uitgeschakeld op html-niveau dus
1305 geen interferentie. Onder de cover (info/progress/controls/queue) werkt
1306 normale touch — knoppen, scroll in queue, etc. */
1307.audio-sheet-drag-zone {
1308 flex-shrink: 0;
1309 display: flex;
1310 flex-direction: column;
1311 align-items: stretch;
1312 gap: 1rem;
1313 /* v9.3 — touch-action: pan-y staat verticale scroll toe (zodat queue
1314 eronder scrollt als gebruiker omhoog veegt over cover). Onze JS
1315 detecteert intent: alleen omlaag-swipe vanaf de top sluit de sheet,
1316 omhoog-swipe = scroll. */
1317 touch-action: pan-y;
1318 user-select: none;
1319 -webkit-user-select: none;
1320 cursor: grab;
1321 margin: -.75rem -1.5rem 0;
1322 padding: .75rem 1.5rem 0;
1323}
1324.audio-sheet-drag-zone:active { cursor: grabbing; }
1325
1326/* v9.4 — Drag alleen actief op touch-only apparaten (telefoons).
1327 Desktop met muis + tablets met muis-cursor → geen drag-grip,
1328 gebruiker sluit via × pill-knop bovenin of klik op backdrop. */
1329@media (hover: hover) and (pointer: fine) {
1330 .audio-sheet-drag-zone {
1331 touch-action: auto;
1332 cursor: default;
1333 pointer-events: none;
1334 }
1335 /* Pill blijft klikbaar als sluit-knop */
1336 .audio-sheet-drag-zone .audio-sheet-handle {
1337 pointer-events: auto;
1338 cursor: pointer;
1339 }
1340}
1341
1342/* Pill (handle) gecentreerd boven de cover */
1343.audio-sheet-drag-zone .audio-sheet-handle {
1344 margin: 0 auto .25rem;
1345}
1346
1347/* Tijdens dragging: panel volgt vinger realtime; geen transition */
1348.audio-sheet-panel.is-dragging {
1349 transition: none;
1350 will-change: transform;
1351}
1352[data-theme="dark"] .audio-sheet-panel {
1353 background: var(--paper, #1a1a1a);
1354 box-shadow: 0 -20px 60px rgba(0, 0, 0, .5);
1355}
1356/* Drag-handle + close button in één */
1357.audio-sheet-handle {
1358 display: block;
1359 width: 48px;
1360 height: 4px;
1361 border-radius: 2px;
1362 background: color-mix(in srgb, var(--ink, #000) 25%, transparent);
1363 border: none;
1364 margin: 0 auto .5rem;
1365 padding: 0;
1366 cursor: pointer;
1367 flex-shrink: 0;
1368 position: relative;
1369}
1370.audio-sheet-handle::before {
1371 content: "";
1372 position: absolute;
1373 /* v9.3 — Drag-strip wrapper neemt nu de hit-area-rol over. ::before
1374 blijft als kleine extra padding voor click-comfort. */
1375 inset: -10px -20px;
1376}
1377.audio-sheet-handle:hover {
1378 background: color-mix(in srgb, var(--ink, #000) 45%, transparent);
1379}
1380/* Grote cover */
1381.audio-sheet-cover {
1382 width: 100%;
1383 max-width: 360px;
1384 aspect-ratio: 1/1;
1385 margin: 0 auto;
1386 border-radius: 12px;
1387 background: linear-gradient(135deg,
1388 var(--accent, #c2410c),
1389 color-mix(in srgb, var(--accent, #c2410c) 55%, #000));
1390 background-size: cover;
1391 background-position: center;
1392 box-shadow: 0 20px 40px rgba(0, 0, 0, .15);
1393 flex-shrink: 0;
1394}
1395[data-theme="dark"] .audio-sheet-cover {
1396 box-shadow: 0 20px 40px rgba(0, 0, 0, .4);
1397}
1398.audio-sheet-info {
1399 text-align: center;
1400 padding: 0 1rem;
1401}
1402.audio-sheet-title {
1403 font-family: var(--font-display, inherit);
1404 font-size: 1.5rem;
1405 font-weight: 600;
1406 line-height: 1.2;
1407 margin: 0 0 .25rem;
1408 letter-spacing: -0.01em;
1409 color: var(--ink);
1410}
1411.audio-sheet-artist {
1412 font-size: 1rem;
1413 color: var(--ink-muted, var(--ink));
1414 opacity: .7;
1415}
1416.audio-sheet-album {
1417 margin-top: .35rem;
1418 font-size: .82rem;
1419 opacity: .5;
1420 text-transform: uppercase;
1421 letter-spacing: .05em;
1422}
1423.audio-sheet-album:empty { display: none; }
1424/* Progress + time */
1425.audio-sheet-progress {
1426 display: grid;
1427 grid-template-columns: auto 1fr auto;
1428 gap: .6rem;
1429 align-items: center;
1430 padding: 0 .5rem;
1431}
1432.audio-sheet-progress .audio-seek { width: 100%; }
1433.audio-sheet-progress .audio-time {
1434 font-size: .78rem;
1435 opacity: .55;
1436}
1437/* Grote controls */
1438.audio-sheet-controls {
1439 display: flex;
1440 align-items: center;
1441 justify-content: center;
1442 gap: 1.75rem;
1443}
1444.audio-sheet-btn {
1445 width: 48px;
1446 height: 48px;
1447 padding: 0;
1448}
1449.audio-sheet-btn svg { width: 28px; height: 28px; }
1450.audio-sheet-play {
1451 width: 72px;
1452 height: 72px;
1453 border-radius: 50%;
1454 background: var(--accent, #c2410c);
1455 color: var(--paper, #fff);
1456 border: none;
1457 cursor: pointer;
1458 display: inline-flex;
1459 align-items: center;
1460 justify-content: center;
1461 transition: transform .1s;
1462}
1463.audio-sheet-play:hover { transform: scale(1.05); }
1464.audio-sheet-play:active { transform: scale(.95); }
1465.audio-sheet-play svg { width: 30px; height: 30px; }
1466.audio-sheet-play .icon-pause { display: none; }
1467/* v9.2.1 — sheet staat nu als sibling van .audio-player buiten de balk,
1468 dus ancestor-selector .audio-player.is-playing werkt niet meer voor de
1469 sheet. JS zet is-playing ook rechtstreeks op sheet.play (regel 551 app.js). */
1470.audio-sheet-play.is-playing .icon-play { display: none; }
1471.audio-sheet-play.is-playing .icon-pause { display: block; }
1472/* v9.2.1 — fallback: als sheet buiten alle ancestors zit, tag body */
1473body.audio-is-playing .audio-sheet-play .icon-play { display: none; }
1474body.audio-is-playing .audio-sheet-play .icon-pause { display: block; }
1475
1476/* v9.3 — Loading state: roterende spiraal (het roboburr logo).
1477 Button-achtergrond wordt transparant, play/pause svgs verbergen, en de
1478 spiraal verschijnt als roterende background via ::after pseudo-element.
1479 Cool-effect: zachte hue-drift geeft de kleur een levend gevoel. */
1480.audio-player.is-loading .audio-btn-play,
1481.audio-player.is-loading .audio-sheet-play,
1482body.audio-is-loading .audio-sheet-play,
1483.pat-row.is-loading {
1484 pointer-events: none;
1485}
1486.audio-player.is-loading .audio-btn-play,
1487.audio-player.is-loading .audio-sheet-play,
1488body.audio-is-loading .audio-sheet-play {
1489 background: transparent;
1490 box-shadow: none;
1491}
1492
1493/* v9.3 — Play/pause-icons in de player-knoppen faden smooth uit/in tijdens
1494 loading. Pseudo-spiraal faded tegelijkertijd in (geen instant pop). */
1495.audio-btn-play > svg,
1496.audio-sheet-play > svg {
1497 transition: opacity .35s cubic-bezier(.4, 0, .2, 1),
1498 transform .35s cubic-bezier(.4, 0, .2, 1);
1499}
1500.audio-player.is-loading .audio-btn-play > svg,
1501.audio-player.is-loading .audio-sheet-play > svg,
1502body.audio-is-loading .audio-sheet-play > svg {
1503 opacity: 0;
1504 transform: scale(.7);
1505}
1506.pat-row.is-loading .pat-play-icon > svg,
1507.pat-row.is-loading .pat-num,
1508.pat-row.is-loading .pat-cover {
1509 opacity: 0;
1510}
1511
1512/* v9.3 — Spiraal als pseudo-element, ALTIJD aanwezig met opacity 0 default.
1513 Bij is-loading faden 'ie smooth in (opacity + scale-bounce), bij klaar
1514 faden 'ie weer uit. Pure accent-kleur, geen hue-drift. */
1515.audio-player .audio-btn-play,
1516.audio-player .audio-sheet-play,
1517.pat-row .pat-play-icon {
1518 position: relative;
1519}
1520.audio-btn-play::after,
1521.audio-sheet-play::after {
1522 content: "";
1523 position: absolute;
1524 inset: 0;
1525 background-color: var(--accent, #c2410c);
1526 -webkit-mask: url('/assets/spinner.svg') center/contain no-repeat;
1527 mask: url('/assets/spinner.svg') center/contain no-repeat;
1528 opacity: 0;
1529 transform: scale(.6);
1530 transition: opacity .4s cubic-bezier(.4, 0, .2, 1),
1531 transform .4s cubic-bezier(.34, 1.56, .64, 1);
1532 pointer-events: none;
1533 animation: pcms-spiral-spin 1.2s linear infinite paused;
1534 will-change: opacity, transform;
1535}
1536.audio-player.is-loading .audio-btn-play::after,
1537.audio-player.is-loading .audio-sheet-play::after,
1538body.audio-is-loading .audio-sheet-play::after {
1539 opacity: 1;
1540 transform: scale(1);
1541 animation-play-state: running;
1542}
1543/* Pat-row keeps its existing ::before spinner from earlier change.
1544 Voor backward-compat als oude HTML nog .pat-play-icon::after spinner had */
1545.pat-row.is-loading .pat-play-icon::after {
1546 content: "";
1547 position: absolute;
1548 inset: 0;
1549 background-color: var(--accent, #c2410c);
1550 -webkit-mask: url('/assets/spinner.svg') center/contain no-repeat;
1551 mask: url('/assets/spinner.svg') center/contain no-repeat;
1552 opacity: 1;
1553 animation: pcms-spiral-spin 1.2s linear infinite;
1554 pointer-events: none;
1555}
1556@keyframes pcms-spiral-spin {
1557 to { transform: scale(1) rotate(-360deg); }
1558}
1559/* Queue list */
1560.audio-sheet-queue {
1561 margin-top: .5rem;
1562 padding-top: 1rem;
1563 border-top: 1px solid var(--rule);
1564}
1565.audio-sheet-queue-label {
1566 font-size: .75rem;
1567 text-transform: uppercase;
1568 letter-spacing: .08em;
1569 opacity: .5;
1570 font-weight: 600;
1571 margin-bottom: .5rem;
1572 padding: 0 .5rem;
1573}
1574.audio-sheet-queue-list {
1575 list-style: none;
1576 padding: 0;
1577 margin: 0;
1578 display: flex;
1579 flex-direction: column;
1580 gap: 2px;
1581}
1582.audio-sheet-queue-item {
1583 display: flex;
1584 align-items: center;
1585 gap: .75rem;
1586 padding: .5rem .6rem;
1587 border-radius: 6px;
1588 cursor: pointer;
1589 transition: background .15s;
1590 background: none;
1591 border: none;
1592 width: 100%;
1593 color: inherit;
1594 font: inherit;
1595 text-align: left;
1596}
1597.audio-sheet-queue-item:hover {
1598 background: color-mix(in srgb, var(--ink, #000) 6%, transparent);
1599}
1600.audio-sheet-queue-item.is-current {
1601 background: color-mix(in srgb, var(--accent, #c2410c) 14%, transparent);
1602 color: var(--accent, #c2410c);
1603}
1604.audio-sheet-queue-cover {
1605 width: 36px;
1606 height: 36px;
1607 border-radius: 4px;
1608 background-size: cover;
1609 background-position: center;
1610 background-color: var(--rule);
1611 flex-shrink: 0;
1612}
1613.audio-sheet-queue-meta {
1614 flex: 1;
1615 min-width: 0;
1616 display: flex;
1617 flex-direction: column;
1618}
1619.audio-sheet-queue-title {
1620 font-size: .9rem;
1621 font-weight: 500;
1622 overflow: hidden;
1623 text-overflow: ellipsis;
1624 white-space: nowrap;
1625}
1626.audio-sheet-queue-artist {
1627 font-size: .75rem;
1628 opacity: .55;
1629 overflow: hidden;
1630 text-overflow: ellipsis;
1631 white-space: nowrap;
1632}
1633.audio-sheet-queue-duration {
1634 font-family: ui-monospace, monospace;
1635 font-size: .72rem;
1636 opacity: .5;
1637 flex-shrink: 0;
1638}
1639
1640/* Desktop: sheet is max 480px wide and centered for bigger screens */
1641@media (min-width: 720px) {
1642 .audio-sheet-panel {
1643 left: 50%;
1644 right: auto;
1645 width: 480px;
1646 transform: translate(-50%, 100%);
1647 border-top-left-radius: 20px;
1648 border-top-right-radius: 20px;
1649 }
1650 .audio-sheet.is-open .audio-sheet-panel {
1651 transform: translate(-50%, 0);
1652 }
1653}
1654
1655/* v9.2.1 — Mobiel: sheet is fullscreen, alleen te sluiten via handle-knop bovenin.
1656 Geen rounded corners, volledige viewport, safe-area voor notches/status bar. */
1657@media (max-width: 719.98px) {
1658 .audio-sheet-panel {
1659 inset: 0;
1660 max-height: none;
1661 border-top-left-radius: 0;
1662 border-top-right-radius: 0;
1663 box-shadow: none;
[a036251]1664 padding-top: calc(.75rem + var(--ios-safe-top, 0px));
[7bc636b]1665 padding-bottom: calc(2rem + env(safe-area-inset-bottom, 0px));
1666 }
1667 /* v9.3 — Backdrop blijft visible op mobile zodat drag-gesture de blur
1668 laat doorschemeren naar helder. */
1669}
1670
1671/* ============================================================
1672 Mobile masthead + pagination
1673 ============================================================ */
1674@media (max-width: 600px) {
1675 .masthead-inner { gap: .35rem; }
1676 .site-title { font-size: 1.2rem; }
1677 .site-subtitle { display: none; }
1678 .top-nav { gap: .1rem; }
1679 .nav-label { display: none; }
1680 .nav-btn, .nav-link {
1681 padding: .4rem .45rem;
1682 min-width: 38px;
1683 justify-content: center;
1684 }
1685 .pagination { flex-direction: column; gap: .5rem; }
1686 .pagination-item { width: 100%; }
1687}
[2149f5a]1688
[83b8b8f]1689/* Taal-keuze in de header-nav (NL/EN/DE) — eigen gestylede dropdown. */
1690.lang-menu { position: relative; }
1691.lang-menu > summary {
1692 list-style: none; cursor: pointer;
1693 display: inline-flex; align-items: center; gap: .3rem;
1694 padding: .35rem .55rem; border-radius: 999px;
1695 border: 1px solid var(--rule); background: transparent; color: var(--ink);
1696}
1697.lang-menu > summary::-webkit-details-marker { display: none; }
1698.lang-menu > summary:hover { border-color: var(--accent); }
1699.lang-toggle .lang-code { font-size: .8rem; font-weight: 700; letter-spacing: .02em; }
1700.lang-toggle .icon { width: 16px; height: 16px; opacity: .8; }
1701.lang-caret { width: 12px; height: 12px; opacity: .7; transition: transform .15s; }
1702.lang-menu[open] .lang-caret { transform: rotate(180deg); }
1703.lang-dropdown {
1704 position: absolute; top: calc(100% + 8px); right: 0;
1705 min-width: 170px; z-index: 60;
1706 background: var(--paper); border: 1px solid var(--rule);
1707 border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,.22);
1708 padding: .35rem; display: flex; flex-direction: column;
1709}
1710.lang-item {
1711 display: flex; align-items: center; gap: .6rem;
1712 padding: .5rem .65rem; border-radius: 8px;
1713 color: var(--ink); text-decoration: none; font-size: .9rem;
1714}
1715.lang-item:hover { background: var(--paper-2); }
1716.lang-item.is-active { color: var(--accent); font-weight: 600; }
1717.lang-item-code {
1718 font-size: .7rem; font-weight: 700; opacity: .6;
1719 min-width: 1.6em;
1720}
[7bc636b]1721@media (max-width: 400px) {
[a036251]1722 .masthead { padding: calc(.5rem + var(--ios-safe-top, 0px)) 0 .5rem; }
[7bc636b]1723 .masthead-inner { gap: .25rem; }
1724 .site-title { font-size: 1.05rem; }
1725 .nav-btn, .nav-link {
1726 padding: .35rem .3rem;
1727 min-width: 34px;
1728 }
1729 .nav-btn .icon, .nav-link .icon { width: 1rem; height: 1rem; }
1730 /* PWA-install knop verbergen op klein scherm — kan ook via menu */
1731 .nav-install-btn { display: none !important; }
1732}
1733@media (max-width: 340px) {
1734 .site-title { font-size: .95rem; }
1735 .nav-btn, .nav-link { padding: .3rem .25rem; min-width: 30px; }
1736 /* Theme-toggle verbergen op ultra-klein — kan via user-menu */
1737 [data-pcms-theme-toggle] { display: none; }
1738}
1739
1740.post-date-ago {
1741 margin-left: .5em;
1742 opacity: .6;
1743 font-size: .9em;
1744 font-style: italic;
1745 text-transform: none;
1746 letter-spacing: 0;
1747}
1748
1749/* HTMX loading indicator — subtle progress-bar aan de top van de content */
1750.pcms-loading {
1751 position: fixed;
1752 top: 0; left: 0;
1753 height: 2px;
1754 width: 0%;
1755 background: var(--accent, #c2410c);
1756 z-index: 9999;
1757 transition: width .3s ease, opacity .2s;
1758 opacity: 0;
1759 pointer-events: none;
1760}
1761.pcms-loading.htmx-request {
1762 opacity: 1;
1763 width: 80%;
1764 transition: width 6s cubic-bezier(.1,.9,.2,1), opacity .2s;
1765}
1766/* subtile fade wanneer content gewisseld wordt */
1767#pcms-main.htmx-swapping {
1768 opacity: .5;
1769 transition: opacity .15s;
1770}
1771
1772/* Masthead brand group (site-title + optional tagline) */
1773.masthead-brand { display: flex; flex-direction: column; gap: 2px; }
1774.site-subtitle {
1775 font-family: var(--font-ui, inherit);
1776 font-size: .75rem;
1777 color: var(--ink-muted, rgba(0,0,0,.55));
1778 letter-spacing: 0;
1779 line-height: 1.3;
1780}
1781
1782/* ============================================================
1783 v7.3 — TAGS, TYPE, ARCHIEF, ZOEK, RELATED, SPECIAL VIEWS
1784 ============================================================ */
1785
1786/* Post-meta row — datum + type-chip + tags samen onder de titel */
1787.post-meta {
1788 display: flex;
1789 flex-wrap: wrap;
1790 align-items: center;
1791 gap: .5rem .85rem;
1792 margin-top: .5rem;
1793}
1794.post-meta .post-date { margin: 0; }
1795
1796/* Type-chip (groter, als een label) */
1797.post-type-chip {
1798 display: inline-flex;
1799 align-items: center;
1800 padding: .2rem .6rem;
1801 background: color-mix(in srgb, var(--accent) 10%, transparent);
1802 color: var(--accent);
1803 border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
1804 border-radius: 999px;
1805 font-family: var(--font-ui);
1806 font-size: .72rem;
1807 font-weight: 600;
1808 text-decoration: none;
1809 letter-spacing: .04em;
1810 text-transform: uppercase;
1811 transition: background .15s;
1812}
1813.post-type-chip:hover { background: color-mix(in srgb, var(--accent) 20%, transparent); }
1814
1815/* Tag-chips — klein, subtiel, gelinkt */
1816.post-tags, .post-list-tags {
1817 display: inline-flex;
1818 flex-wrap: wrap;
1819 gap: .3rem;
1820}
1821.tag-chip {
1822 display: inline-block;
1823 padding: .15rem .55rem;
1824 background: color-mix(in srgb, var(--ink) 5%, transparent);
1825 color: var(--ink-muted);
1826 border-radius: 999px;
1827 font-family: var(--font-ui);
1828 font-size: .72rem;
1829 font-weight: 500;
1830 text-decoration: none;
1831 transition: background .15s, color .15s;
1832}
1833.tag-chip:hover {
1834 background: color-mix(in srgb, var(--accent) 12%, transparent);
1835 color: var(--accent);
1836}
1837
1838/* ============================================================
1839 SPECIAL PAGES (archief, tag, type, zoek)
1840 ============================================================ */
1841.special-page .post-header { margin-bottom: 2rem; }
1842.special-eyebrow {
1843 font-size: .72rem;
1844 color: var(--ink-muted);
1845 text-transform: uppercase;
1846 letter-spacing: .12em;
1847 margin: 0 0 .25rem;
1848}
1849
1850/* Archief: jaar-overzicht */
1851.archive-years {
1852 display: flex;
1853 flex-direction: column;
1854 gap: 2rem;
1855}
1856.archive-year h2 {
1857 font-family: var(--font-display);
1858 font-size: 1.75rem;
1859 margin: 0 0 .75rem;
1860}
1861.archive-year h2 a {
1862 color: var(--ink);
1863 text-decoration: none;
1864}
1865.archive-year h2 a:hover { color: var(--accent); }
1866.archive-year h2 .admin-muted { font-size: .9rem; font-weight: normal; color: var(--ink-muted); }
1867.archive-months {
1868 list-style: none;
1869 padding: 0; margin: 0;
1870 display: grid;
1871 grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
1872 gap: .5rem;
1873}
1874.archive-months li {
1875 display: flex;
1876 align-items: center;
1877 gap: .4rem;
1878 padding: .55rem .75rem;
1879 background: color-mix(in srgb, var(--ink) 3%, transparent);
1880 border-radius: var(--radius);
1881 transition: background .15s;
1882}
1883.archive-months li:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); }
1884.archive-months a {
1885 color: var(--ink);
1886 text-decoration: none;
1887 font-weight: 500;
1888 font-size: .95rem;
1889}
1890.archive-months .admin-muted { font-size: .75rem; color: var(--ink-muted); margin-left: auto; }
1891
1892/* Archief: jaar drill-down */
1893.archive-month-list {
1894 display: flex;
1895 flex-direction: column;
1896 gap: 2rem;
1897}
1898.archive-month h2 {
1899 font-family: var(--font-display);
1900 font-size: 1.35rem;
1901 margin: 0 0 .5rem;
1902 padding-bottom: .35rem;
1903 border-bottom: 1px solid var(--rule);
1904}
1905.archive-month h2 a {
1906 color: var(--ink);
1907 text-decoration: none;
1908}
1909.archive-month h2 a:hover { color: var(--accent); }
1910
1911/* Compact post-list (gebruikt in archief drill-down per maand) */
1912.post-compact-list {
1913 list-style: none;
1914 padding: 0; margin: 0;
1915 display: flex;
1916 flex-direction: column;
1917}
1918.post-compact-list li {
1919 border-bottom: 1px solid var(--rule);
1920}
1921.post-compact-list li:last-child { border-bottom: none; }
1922.post-compact-list a {
1923 display: grid;
1924 grid-template-columns: 3em 1fr;
1925 gap: .75rem;
1926 padding: .6rem .2rem;
1927 text-decoration: none;
1928 color: var(--ink);
1929 transition: background .12s;
1930 border-radius: 4px;
1931}
1932.post-compact-list a:hover {
1933 background: color-mix(in srgb, var(--accent) 6%, transparent);
1934}
1935.post-compact-date {
1936 color: var(--ink-muted);
1937 font-size: .8rem;
1938 align-self: center;
1939}
1940.post-compact-title { font-weight: 500; font-size: 1rem; align-self: center; }
1941.post-compact-list.large a { grid-template-columns: 4em 1fr; padding: .8rem .3rem; }
1942.post-compact-list.large .post-compact-title { font-family: var(--font-display); font-size: 1.15rem; }
1943.post-compact-excerpt {
1944 grid-column: 2;
1945 color: var(--ink-muted);
1946 font-size: .88rem;
1947 line-height: 1.5;
1948}
1949
1950/* Post-list (gebruikt in tag / type / zoek pagina's) */
1951.post-list {
1952 list-style: none;
1953 padding: 0; margin: 0;
1954 display: flex;
1955 flex-direction: column;
1956 gap: 1.5rem;
1957}
1958.post-list-item {
1959 display: grid;
1960 grid-template-columns: 120px 1fr;
1961 gap: 1.25rem;
1962 padding-bottom: 1.5rem;
1963 border-bottom: 1px solid var(--rule);
1964}
1965.post-list-item:last-child { border-bottom: none; }
1966.post-list-item:has(> .post-list-cover + .post-list-body) { grid-template-columns: 120px 1fr; }
1967.post-list-item:not(:has(.post-list-cover)) { grid-template-columns: 1fr; }
1968.post-list-cover {
1969 display: block;
1970 aspect-ratio: 1;
1971 overflow: hidden;
1972 border-radius: var(--radius);
[3038fc9]1973 /* Accent-gradient placeholder while the cover image loads (image fades in over it). */
1974 background-image: linear-gradient(135deg,
1975 color-mix(in srgb, var(--accent, #888) 22%, var(--paper-2, var(--paper))) 0%,
1976 color-mix(in srgb, var(--accent, #888) 6%, var(--paper-2, var(--paper))) 100%);
[7bc636b]1977}
[38120c7]1978.post-list-cover img, .post-list-cover video {
[7bc636b]1979 width: 100%; height: 100%;
[38120c7]1980 object-fit: cover; /* fill the square, keep aspect, crop the overflow, centered */
1981 object-position: center;
[7bc636b]1982 display: block;
[3038fc9]1983 background-color: #fff; /* transparent logos sit on white once loaded */
1984 transition: opacity .4s ease;
[7bc636b]1985}
[3038fc9]1986.post-list-cover img.is-loading { opacity: 0; }
[7bc636b]1987.post-list-body { display: flex; flex-direction: column; gap: .35rem; }
1988.post-list-meta {
1989 color: var(--ink-muted);
1990 font-size: .75rem;
1991 display: flex; gap: .35rem; align-items: center;
1992}
1993.post-list-title {
1994 font-family: var(--font-display);
1995 font-size: 1.3rem;
1996 font-weight: 450;
1997 margin: 0;
1998 line-height: 1.2;
1999}
2000.post-list-title a {
2001 color: var(--ink);
2002 text-decoration: none;
2003}
2004.post-list-title a:hover { color: var(--accent); }
2005.post-list-excerpt {
2006 color: var(--ink-muted);
2007 font-size: .95rem;
2008 margin: 0;
2009 line-height: 1.5;
2010}
2011
2012/* Zoek-formulier binnen special view */
2013.search-form {
2014 display: flex;
2015 gap: .5rem;
2016 margin-bottom: 2rem;
2017}
2018.search-form input[type=search] {
2019 flex: 1;
2020 padding: .75rem 1rem;
2021 background: var(--paper-2);
2022 border: 1px solid var(--rule);
2023 border-radius: var(--radius);
2024 font: inherit;
2025 color: var(--ink);
2026}
2027.search-form input[type=search]:focus {
2028 outline: none;
2029 border-color: var(--accent);
2030 box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 20%, transparent);
2031}
2032
2033/* ============================================================
2034 SEARCH OVERLAY (masthead → full-screen zoekbalk)
2035 ============================================================ */
2036.search-overlay {
2037 position: fixed;
2038 inset: 0;
2039 background: color-mix(in srgb, var(--ink) 50%, transparent);
2040 z-index: 1500;
2041 display: flex;
2042 justify-content: center;
2043 align-items: flex-start;
2044 padding-top: 10vh;
2045 backdrop-filter: blur(6px);
2046 -webkit-backdrop-filter: blur(6px);
2047}
2048.search-overlay[hidden] { display: none; }
2049.search-overlay-form {
2050 width: min(90vw, 600px);
2051 background: var(--paper);
2052 border-radius: calc(var(--radius) * 1.5);
2053 padding: .75rem 1rem;
2054 display: flex;
2055 align-items: center;
2056 gap: .6rem;
2057 box-shadow: 0 20px 60px rgba(0,0,0,.3);
2058 border: 1px solid var(--rule);
2059}
2060.search-overlay-form .icon {
2061 width: 1.2rem; height: 1.2rem;
2062 color: var(--ink-muted);
2063 flex-shrink: 0;
2064}
2065.search-overlay-form input[type=search] {
2066 flex: 1;
2067 background: transparent;
2068 border: none;
2069 font-family: var(--font-body);
2070 font-size: 1.1rem;
2071 color: var(--ink);
2072 padding: .5rem 0;
2073}
2074.search-overlay-form input[type=search]:focus { outline: none; }
2075.search-overlay-form .nav-btn {
2076 background: transparent;
2077 border: none;
2078 color: var(--ink-muted);
2079 cursor: pointer;
2080 font-size: 1.25rem;
2081 line-height: 1;
2082 padding: .3rem .5rem;
2083}
2084.search-overlay-form .nav-btn:hover { color: var(--ink); }
2085body.search-open { overflow: hidden; }
2086
2087/* ============================================================
2088 RELATED POSTS (onder elke post-view)
2089 ============================================================ */
2090.related-posts {
2091 margin-top: 2.5rem;
2092 padding-top: 2rem;
2093 border-top: 1px solid var(--rule);
2094}
2095.related-title {
2096 font-family: var(--font-mono);
2097 font-size: .7rem;
2098 color: var(--ink-muted);
2099 text-transform: uppercase;
2100 letter-spacing: .12em;
2101 margin: 0 0 1rem;
2102}
2103.related-grid {
2104 list-style: none;
2105 padding: 0; margin: 0;
2106 display: grid;
2107 grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
2108 gap: 1rem;
2109}
2110.related-grid a {
2111 display: flex;
2112 flex-direction: column;
2113 gap: .5rem;
2114 text-decoration: none;
2115 color: var(--ink);
2116 border: 1px solid var(--rule);
2117 border-radius: var(--radius);
2118 overflow: hidden;
2119 transition: border-color .15s, transform .15s;
2120 height: 100%;
2121}
2122.related-grid a:hover {
2123 border-color: color-mix(in srgb, var(--accent) 50%, var(--rule));
2124 transform: translateY(-2px);
2125}
2126.related-cover {
2127 display: block;
2128 aspect-ratio: 16/10;
2129 background-size: cover;
2130 background-position: center;
2131 background-color: var(--paper-2);
2132}
2133
2134/* v9.4 — Wanneer related-cover ook .grid-tile-gradient class heeft (lege cover
2135 fallback), erft 'ie automatisch de hue/gradient/title styling van grid-tiles.
2136 Geen aparte related-cover-gradient meer nodig. */
2137.related-body {
2138 display: flex;
2139 flex-direction: column;
2140 gap: .25rem;
2141 padding: .6rem .75rem .9rem;
2142}
2143.related-meta { color: var(--ink-muted); font-size: .7rem; }
2144.related-name {
2145 font-family: var(--font-display);
2146 font-weight: 450;
2147 font-size: 1rem;
2148 line-height: 1.25;
2149}
2150
2151/* ============================================================
2152 MOBILE TWEAKS voor v7.3
2153 ============================================================ */
2154@media (max-width: 600px) {
2155 .post-list-item { grid-template-columns: 1fr; }
2156 .post-list-cover { aspect-ratio: 16/9; }
2157 .archive-months { grid-template-columns: repeat(2, 1fr); }
2158 .related-grid { grid-template-columns: 1fr; }
2159 .search-overlay { padding-top: 4vh; }
2160}
2161
2162/* ============================================================
2163 v7.4 — PROFILE HEADER + VIEW SWITCHER + GRID + POST-TYPE LAYOUTS
2164 MOBILE-FIRST — belangrijkste eis
2165 ============================================================ */
2166
2167/* -------- PROFILE HEADER (Optie C: full op home, compact op post/special) -------- */
2168
2169.profile-header {
2170 background: var(--paper-2, var(--paper));
2171 border-bottom: 1px solid var(--rule);
2172 transition: padding .25s ease, background .2s;
2173}
2174/* Mobiel default = full-mode padding */
2175.profile-header { padding: 1.25rem 0; }
2176.profile-header-inner {
2177 display: flex;
2178 gap: .9rem;
2179 align-items: flex-start;
2180}
2181
2182.profile-photo {
2183 flex-shrink: 0;
2184 width: 80px;
2185 height: 80px;
2186 border-radius: 50%;
2187 overflow: hidden;
2188 display: block;
2189 background: var(--paper);
2190 border: 2px solid var(--rule);
2191 transition: width .25s ease, height .25s ease, border-color .2s;
2192 text-decoration: none;
2193}
2194.profile-photo:hover { border-color: var(--accent); }
2195.profile-photo img {
2196 width: 100%; height: 100%;
2197 object-fit: cover;
2198 display: block;
2199}
2200.profile-photo-fallback {
2201 display: flex;
2202 align-items: center;
2203 justify-content: center;
2204 width: 100%; height: 100%;
2205 background: var(--accent);
2206 color: var(--paper);
2207 font-family: var(--font-display);
2208 font-weight: 700;
2209 font-size: 2.2rem;
2210 text-transform: uppercase;
2211 line-height: 1;
2212 transition: font-size .25s ease;
2213}
2214
2215.profile-info {
2216 flex: 1;
2217 min-width: 0;
2218 display: flex;
2219 flex-direction: column;
2220 gap: .3rem;
2221}
2222.profile-name {
2223 margin: 0;
2224 font-family: var(--font-display);
2225 font-size: 1.2rem;
2226 font-weight: 500;
2227 line-height: 1.15;
2228 transition: font-size .25s ease;
2229}
2230.profile-name a {
2231 color: var(--ink);
2232 text-decoration: none;
2233}
2234.profile-name a:hover { color: var(--accent); }
2235.profile-bio {
2236 margin: 0;
2237 color: var(--ink-muted);
2238 font-size: .92rem;
2239 line-height: 1.45;
2240 max-height: 200px;
2241 overflow: hidden;
2242 transition: max-height .25s ease, margin .25s ease, opacity .2s;
2243}
2244.profile-links {
2245 list-style: none;
2246 padding: 0;
2247 margin: .15rem 0 0;
2248 display: flex;
2249 flex-wrap: wrap;
2250 gap: .4rem;
2251 max-height: 50px;
2252 overflow: hidden;
2253 transition: max-height .25s ease, margin .25s ease, opacity .2s;
2254}
2255.profile-links li { margin: 0; }
[3507b0b]2256.profile-links a,
2257.profile-links .profile-fedi-link {
[7bc636b]2258 display: inline-flex;
2259 align-items: center;
2260 justify-content: center;
2261 width: 40px;
2262 height: 40px;
2263 border-radius: 50%;
2264 background: color-mix(in srgb, var(--ink) 5%, transparent);
2265 color: var(--ink-muted);
2266 text-decoration: none;
2267 transition: background .15s, color .15s;
2268}
[3507b0b]2269.profile-links a:hover,
2270.profile-links .profile-fedi-link:hover {
[7bc636b]2271 background: color-mix(in srgb, var(--accent) 15%, transparent);
2272 color: var(--accent);
2273}
2274.profile-links .icon { width: 1.1rem; height: 1.1rem; }
2275
2276/* -------- COMPACT MODE: op post + special pages -------- */
2277
2278.on-post .profile-header,
2279.on-special .profile-header {
2280 padding: .5rem 0;
2281}
2282.on-post .profile-photo,
2283.on-special .profile-photo {
2284 width: 36px;
2285 height: 36px;
2286 border-width: 1px;
2287}
2288.on-post .profile-photo-fallback,
2289.on-special .profile-photo-fallback {
2290 font-size: 1rem;
2291}
2292.on-post .profile-name,
2293.on-special .profile-name {
2294 font-size: 1rem;
2295 align-self: center;
2296}
2297.on-post .profile-bio,
2298.on-special .profile-bio,
2299.on-post .profile-links,
2300.on-special .profile-links {
2301 display: none;
2302}
2303.on-post .profile-header-inner,
2304.on-special .profile-header-inner {
2305 align-items: center;
2306 justify-content: flex-start;
2307 gap: .6rem;
2308}
2309.on-post .profile-info,
2310.on-special .profile-info {
2311 flex: 0 1 auto;
2312 min-width: 0;
2313}
2314.on-post .profile-name,
2315.on-special .profile-name {
2316 text-align: left;
2317}
2318
2319/* -------- DESKTOP: meer ruimte, grotere foto -------- */
2320@media (min-width: 768px) {
2321 .profile-header { padding: 2rem 0; }
2322 .profile-photo { width: 120px; height: 120px; }
2323 .profile-photo-fallback { font-size: 3.2rem; }
2324 .profile-name { font-size: 1.5rem; }
2325 .profile-bio { font-size: 1rem; }
2326 .profile-header-inner { gap: 1.5rem; }
2327 .on-post .profile-header,
2328 .on-special .profile-header { padding: .6rem 0; }
2329 .on-post .profile-photo,
2330 .on-special .profile-photo { width: 42px; height: 42px; }
2331 /* Compact mode: gap blijft klein, ook op desktop */
2332 .on-post .profile-header-inner,
2333 .on-special .profile-header-inner { gap: .75rem; }
2334 .on-post .profile-name,
2335 .on-special .profile-name { font-size: 1.1rem; }
2336}
2337
2338/* -------- VIEW SWITCHER -------- */
2339.view-switcher-wrap {
2340 border-bottom: 1px solid var(--rule);
2341 background: var(--paper);
[ee25d45]2342 /* Bottom margin gives breathing room between the switcher bar and the
2343 first post. margin-top staat in shared-styles.ejs (de winnende inline
2344 <style>) — symmetrisch op 1.5rem. */
[7bc636b]2345 margin-bottom: 1.5rem;
2346}
2347.view-switcher {
2348 display: flex;
2349 justify-content: center;
2350 gap: .35rem;
2351 /* Slimmer bar — was .6rem, now .35rem so the bar reads as a divider
2352 rather than a row of weight equal to the header. */
2353 padding: .35rem 0;
2354}
[7cf8144]2355.view-switch-btn {
[7bc636b]2356 display: inline-flex;
2357 align-items: center;
2358 gap: .4rem;
2359 padding: .35rem .85rem; /* was .55rem 1rem */
2360 min-height: 32px; /* was 44px */
2361 background: transparent;
2362 border: 1px solid var(--rule);
2363 border-radius: 999px;
2364 color: var(--ink-muted);
2365 font-family: var(--font-ui);
2366 font-size: .82rem; /* was .85rem */
2367 cursor: pointer;
2368 transition: all .15s;
2369}
[7cf8144]2370.view-switch-btn:hover {
[7bc636b]2371 color: var(--ink);
2372 border-color: var(--ink-muted);
2373}
[3a3a882]2374/* Uitgeschakeld (Lezen in de cirkel) wint van :hover -- anders licht een knop
2375 op die je niet kunt indrukken, en dat is precies de verkeerde belofte. */
2376.view-switch-btn[disabled],
2377.view-switch-btn[disabled]:hover {
2378 opacity: .38;
2379 cursor: not-allowed;
2380 color: var(--ink-muted);
2381 border-color: var(--rule);
2382}
[d15b27f]2383/* Actieve state: puur afgeleid van body[data-feed-view]. Geen .is-active class meer.
2384 Niet op de Archive-pagina: daar is geen "huidige" timeline/grid-keuze, dus beide
2385 knoppen blijven neutraal (grijs). */
[1c6d61c]2386/* Actieve Tijdlijn/Grid-state wordt nu gestuurd via [aria-selected="true"] (gezet
2387 door syncAria, die óók op htmx:afterSettle draait) i.p.v. body[data-feed-view].
2388 Reden: body-class/attribuut-CSS pakte niet betrouwbaar na een htmx-OOB-swap;
2389 een element-attribuut wel. De witte active-regel staat in shared-styles. */
[7bc636b]2390.view-switch-btn .icon { width: 1rem; height: 1rem; }
2391
2392/* -------- FEED TOGGLE VIA BODY --------
[c974223]2393 Grid-modus werkt op de feed (home, cirkel). Het ARCHIEF negeert de grid-keuze
2394 bewust: dat is altijd de chronologische jaar/maand-lijst (de switcher is daar
2395 grijs en springt bij klik terug naar de feed). Post-pagina's tonen de
2396 feed-timeline article sowieso altijd. Alle andere body-classes negeren
[7bc636b]2397 data-feed-view en houden timeline visible. */
2398body.on-home[data-feed-view="grid"] .feed-timeline,
2399body.on-home[data-feed-view="grid"] .pagination,
2400body.on-home[data-feed-view="grid"] .related-posts,
2401body.on-home[data-feed-view="grid"] .article-footer,
[9f81a09]2402body.on-cirkel[data-feed-view="grid"] .feed-timeline {
[7bc636b]2403 display: none !important;
2404}
[c974223]2405/* Grid-sectie alleen zichtbaar op de feed in grid-mode (NIET op archief) */
[7bc636b]2406.feed-grid { display: none; }
2407body.on-home[data-feed-view="grid"] .feed-grid,
[9f81a09]2408body.on-cirkel[data-feed-view="grid"] .feed-grid { display: block; }
[7bc636b]2409
[7cf8144]2410/* -------- LEESWEERGAVE (data-feed-view="reader") --------
2411 Dezelfde berichten als de tijdlijn, maar heel: één per scherm, grenzen door
2412 scroll-snapping. GEEN eigen route en geen eigen shell -- de balken blijven
2413 staan, want je bent nog op de feed en moet terug kunnen schakelen.
2414 Pagina's zonder .feed-reader (cirkel, archief, post) negeren de keuze en
2415 houden hun tijdlijn: er is hieronder simpelweg geen regel die die daar
2416 verbergt. Zo is Lezen nooit een leeg scherm. */
2417.feed-reader { display: none; }
2418body.on-home[data-feed-view="reader"] .feed-reader { display: block; }
2419/* :has(.feed-reader) is hier de LEGE STAAT, niet een truc. Zonder berichten
2420 rendert de leessectie niet, en dan mag de tijdlijn niet verborgen worden --
2421 want dáár staat "nog niets geschreven" met de knop om te beginnen. Zonder deze
2422 voorwaarde is Lezen op een verse site een wit scherm. Hetzelfde geldt voor
2423 feeds die (nog) geen leessectie hebben. */
2424body.on-home[data-feed-view="reader"]:has(.feed-reader) .feed-timeline,
2425body.on-home[data-feed-view="reader"]:has(.feed-reader) .feed-grid,
2426body.on-home[data-feed-view="reader"]:has(.feed-reader) .pagination,
2427body.on-home[data-feed-view="reader"]:has(.feed-reader) .related-posts,
2428body.on-home[data-feed-view="reader"]:has(.feed-reader) .article-footer {
2429 display: none !important;
2430}
2431
[e46ebaa]2432/* -------- AUTO (data-feed-view="auto") --------
2433 Lezen op mobiel, Tijdlijn op desktop. GEEN JavaScript: de CSS kiest, dus geen
2434 resize-afhandeling en geen flikkering waarin je eerst de verkeerde weergave
2435 ziet. De tijdlijn is de terugval, dus boven de grens hoeft hier niets te
2436 staan -- die is vanzelf al zichtbaar.
2437 De :has(.feed-reader)-voorwaarde staat er om dezelfde reden als hierboven:
2438 zonder berichten is er geen leessectie, en dan moet de tijdlijn blijven staan
2439 met "nog niets geschreven" erin. */
2440@media (max-width: 767px) {
2441 body.on-home[data-feed-view="auto"] .feed-reader { display: block; }
2442 body.on-home[data-feed-view="auto"]:has(.feed-reader) .feed-timeline,
2443 body.on-home[data-feed-view="auto"]:has(.feed-reader) .feed-grid,
2444 body.on-home[data-feed-view="auto"]:has(.feed-reader) .pagination,
2445 body.on-home[data-feed-view="auto"]:has(.feed-reader) .related-posts,
2446 body.on-home[data-feed-view="auto"]:has(.feed-reader) .article-footer {
2447 display: none !important;
2448 }
2449}
2450/* In de auto-stand staan BEIDE knoppen in de HTML en laat de mediaquery er een
2451 zien. Zo verspringt de naam van de knop niet terwijl je ernaar kijkt, en is er
2452 geen JavaScript nodig dat op resize moet luisteren. */
2453.view-switch-btn.vs-alleen-mobiel { display: none; }
2454@media (max-width: 767px) {
2455 .view-switch-btn.vs-alleen-mobiel { display: inline-flex; }
2456 .view-switch-btn.vs-alleen-desktop { display: none; }
2457}
2458
[7cf8144]2459/* Snappen doet de SCROLLCONTAINER, en dat is het document -- niet .read-stream,
2460 die heeft overflow: visible en scrollt zelf niet. Proximity en geen mandatory:
2461 in een bericht dat langer is dan het scherm moet je rustig door kunnen lezen. */
[e46ebaa]2462html:has(body.on-home[data-feed-view="reader"]) {
2463 scroll-snap-type: y proximity;
[4989294]2464 /* GEEN scroll-behavior:smooth hier. Dat maakte elke beweging op deze
2465 scroller traag, ook het snappen zelf -- en een snap moet vlot zijn
2466 (Robin, 20-8: "vlot maar geanimeerd, mag niet te lang duren"). De browser
2467 animeert een snap uit zichzelf al, en korter dan zijn smooth-scroll.
2468 De terug-naar-boven-knop vraagt zijn animatie expliciet aan in
2469 mod/read.js, dus die blijft vloeiend. */
[e46ebaa]2470}
[7cf8144]2471/* En de browser niet óók laten compenseren als Load more er berichten bij zet:
2472 Chrome en Firefox schuiven bij invoegen zelf mee (scroll anchoring), en dat
2473 vecht met het snappen. */
2474html:has(body.on-home[data-feed-view="reader"]),
2475.feed-reader .read-stream { overflow-anchor: none; }
2476
2477.feed-reader .read-post {
[e46ebaa]2478 /* Snap naar de BOVENkant van een bericht, zacht (proximity op html) en nooit
2479 dwingend (stop: normal). Een korte post vult het scherm, zodat hij niet als
2480 snipper tussen twee lijnen hangt.
2481 De uitzondering staat NIET hier maar in mod/read.js: een bericht dat langer
2482 is dan het scherm krijgt scroll-snap-align:none, anders trekt de browser je
2483 tijdens het lezen terug naar zijn bovenrand en lijkt het of het scrollen
2484 stopt. "Past het op het scherm?" is een vraag over gemeten hoogte, en die
2485 kan CSS niet stellen. */
2486 /* Je LANDT op de bovenkant van een bericht -- dat is wat "snap to post"
2487 hoort te betekenen. (align:end probeerde ik ook; dan land je op de
2488 ONDERKANT van het vorige bericht, en bij een lang bericht zie je dus zijn
2489 laatste schermvol in plaats van de kop van het volgende.)
2490 Wanneer die bovenkant een snappunt IS, staat in mod/read.js: alleen zolang
2491 je er nog niet voorbij bent. Eenmaal in een bericht snapt er niets meer,
2492 ook niet naar zijn eigen bovenrand -- anders trekt proximity je terug
2493 zodra je een paar regels verder leest. */
[d8f8f07]2494 /* Het snappunt zit op .read-anker hierna, niet hier. Zie de toelichting
2495 daar: een snapgebied groter dan het scherm heeft een BEREIK aan geldige
2496 posities, en de bovenste daarvan zet het volgende bericht op de onderrand. */
2497 scroll-snap-align: none;
[7cf8144]2498 scroll-snap-stop: normal;
[e46ebaa]2499 /* GEEN min-height meer. Die rekte elk bericht tot een vol scherm, en bij een
2500 kort bericht leverde dat een halve pagina leegte op onder "Replies and
2501 reactions" -- je zat naar niets te kijken en moest verder scrollen om te
2502 ontdekken dat er nog iets kwam. Robins vondst (20-8), met een
2503 schermafbeelding erbij.
2504 Zonder die hoogte is de stroom gewoon bericht na bericht: je ziet het
2505 volgende meteen onder het vorige beginnen. Het snappen doet nog steeds
2506 zijn werk aan de grens -- dat hangt aan scroll-snap-align en niet aan de
2507 hoogte -- dus de streep lijnt nog altijd uit met de bovenkant van het
2508 volgende bericht. */
[7cf8144]2509 max-width: 46rem;
2510 margin: 0 auto;
2511 /* De onderrand loopt achter de vaste tabbalk door; deze padding houdt de
2512 TEKST erboven. */
2513 padding: 2rem 1.2rem 4rem;
2514 box-sizing: border-box;
2515}
[d8f8f07]2516/* ONDERIN GEBEURT ER NIETS (Robin, 20-8: "enkel de bovenkant mag snappen, niet
2517 de onderkant; onderin mag er niks met de zone gebeuren").
2518 Het laatste bericht heeft een snappunt dat de browser NIET KAN BEREIKEN: er
2519 zit niet genoeg pagina onder om zijn bovenkant naar de bovenrand te brengen.
2520 Gemeten op dev: snappunt 2548, maar de scroll gaat maar tot 2356. De spec
2521 laat de browser dan naar de dichtstbijzijnde BEREIKBARE positie snappen, en
2522 dat is de bodem -- waardoor het laatste bericht ergens middenin het scherm
2523 blijft hangen en het lijkt of er aan de onderkant wordt uitgelijnd.
2524 Zonder snappunt scrolt dat laatste stuk gewoon vrij uit tot het einde. */
2525/* HET SNAPPUNT. Nul hoog, dus precies EEN geldige positie: deze bovenrand aan de
2526 bovenrand van het scherm. Zat de uitlijning op het artikel zelf, dan gold voor
2527 elk bericht dat hoger is dan het scherm een heel BEREIK aan geldige posities
2528 (spec: een snapgebied groter dan de snapport mag overal staan waar het de
2529 snapport nog vult). Gemeten op dev: bericht van 1009px op een scherm van 812
2530 -> geldig van 700 tot 897, en op 867 bleef hij dus gewoon staan. Die bovenste
2531 stand, 897, is de onderkant van dat bericht op de onderrand -- oftewel de
2532 bovenkant van het VOLGENDE bericht op de onderrand. Dat is wat er onderin
2533 leek te snappen, en het kwam van de browser en niet uit onze code. */
2534.feed-reader .read-anker {
2535 display: block;
2536 height: 0;
2537 scroll-snap-align: start;
2538 /* Het anker staat BINNEN de padding van het artikel, dus 2rem onder de
2539 streep. Zonder deze correctie landt de snap 32px te laag en staat de
2540 scheidingslijn net boven beeld -- gemeten: 733 waar 700 hoort.
2541 scroll-margin verschuift alleen het SNAPPUNT en niet de opmaak, dus het
2542 anker blijft waar het staat en de uitlijning klopt met de lijn.
2543 Blijft in de pas met de padding-top van .read-post hierboven. */
2544 scroll-margin-top: 2rem;
2545}
2546/* Het laatste bericht krijgt geen snappunt: zijn bovenkant is niet te bereiken
2547 (er zit te weinig pagina onder), en de browser snapt dan naar de dichtstbij-
2548 zijnde bereikbare positie -- de bodem. Gemeten: snappunt 2548, maxScroll 2356. */
2549.feed-reader .read-post:last-child .read-anker { scroll-snap-align: none; }
2550
[7cf8144]2551/* Een lijn tussen twee berichten: zonder grens is een stroom een lange brij. */
2552.feed-reader .read-post + .read-post { border-top: 1px solid color-mix(in srgb, currentColor 12%, transparent); }
2553
[8c91ed3]2554/* De cover vult de leeskolom. Eigen regel, niet .post-cover hergebruikt: die
2555 heeft een marge van 2rem die hier tegen de scroll-snap aan duwt.
2556 De hoogtebegrenzing is er met opzet. Een paneel is min-height:100svh en snapt,
2557 dus een staande foto op volle breedte zou de titel en de eerste alinea onder
2558 de vouw duwen -- dan begint elk bericht met een plaat waar je langs moet
2559 scrollen om te zien wat het IS. */
2560.feed-reader .read-cover {
[e46ebaa]2561 /* Volle kolombreedte: de afbeelding erin neemt die breedte, dus de figure
2562 hoeft niet meer om het beeld te krimpen. */
2563 width: 100%;
2564 margin: 0 0 1.2rem;
[8c91ed3]2565 border-radius: 10px;
2566 overflow: hidden;
2567}
2568.feed-reader .read-cover img,
2569.feed-reader .read-cover video {
2570 display: block;
[e46ebaa]2571 /* Neemt de VOLLE kolombreedte, met de verhouding intact (object-fit
2572 weggelaten, dus geen bijsnijden). Een cover die van zichzelf kleiner is
2573 wordt netjes tot de kolom opgeschaald in plaats van als postzegeltje te
2574 blijven staan -- dat was te klein. De hoogtegrens houdt een staande foto
2575 nog binnen de perken zodat titel + eerste alinea boven de vouw blijven;
2576 hij krimpt dan mee in plaats van bijgesneden te worden. */
2577 display: block;
2578 width: 100%;
[8c91ed3]2579 height: auto;
[e46ebaa]2580 max-height: 70svh;
2581 object-fit: contain;
[598f090]2582 /* Een logo met doorzichtige achtergrond zweeft anders op de paginakleur;
2583 dezelfde keuze als bij .post-list-cover in de tijdlijn. */
2584 background-color: #fff;
[8c91ed3]2585}
2586
[7cf8144]2587.feed-reader .read-head { padding-bottom: .5rem; }
2588.feed-reader .read-title { font-size: clamp(1.6rem, 4vw, 2.4rem); line-height: 1.15; margin: 0 0 .3rem; }
2589/* De titel is een link, maar mag er niet als een link uitzien: dit is een
2590 leesscherm, geen index. */
2591.feed-reader .read-title a { color: inherit; text-decoration: none; }
2592.feed-reader .read-title a:hover,
2593.feed-reader .read-title a:focus-visible { text-decoration: underline; }
2594.feed-reader .read-when { font-size: .85rem; opacity: .6; margin: 0; }
2595
2596.feed-reader .read-foot { margin-top: 2rem; }
2597.feed-reader .read-open {
2598 display: inline-block; font-size: .9rem; opacity: .75;
2599 text-decoration: none; border-bottom: 1px solid currentColor; padding-bottom: 1px;
2600}
2601.feed-reader .read-open:hover,
2602.feed-reader .read-open:focus-visible { opacity: 1; }
2603
[e46ebaa]2604/* Terug naar boven. Rechtsonder, want daar zit de duim -- en boven de tabbalk,
2605 die op mobiel 1050 is en anders overheen zou vallen. Onzichtbaar tot je ver
2606 genoeg bent, zodat hij niet meteen in de weg staat bij het eerste bericht. */
2607.read-top {
2608 position: fixed;
2609 right: max(1rem, env(safe-area-inset-right, 0));
2610 bottom: calc(env(safe-area-inset-bottom, 0) + 4.75rem);
2611 z-index: 1040;
2612 display: grid;
2613 place-items: center;
2614 width: 44px;
2615 height: 44px; /* 44px = de kleinste maat die een duim betrouwbaar raakt */
2616 border-radius: 999px;
2617 border: 1px solid var(--rule);
2618 background: color-mix(in srgb, var(--paper) 88%, transparent);
2619 backdrop-filter: blur(14px) saturate(140%);
2620 -webkit-backdrop-filter: blur(14px) saturate(140%);
2621 color: var(--ink);
2622 box-shadow: 0 2px 12px color-mix(in srgb, var(--ink) 12%, transparent);
2623 cursor: pointer;
2624 opacity: 0;
2625 pointer-events: none;
2626 transition: opacity .18s ease, transform .18s ease;
2627 transform: translateY(6px);
2628}
2629.read-top.is-zichtbaar { opacity: 1; pointer-events: auto; transform: none; }
2630/* Buiten de leesweergave bestaat hij niet -- home.ejs rendert alle drie de
2631 secties, dus zonder deze regel zweeft hij ook boven Tijdlijn en Grid. */
2632body:not([data-feed-view="reader"]) .read-top,
2633body:not(.on-home) .read-top { display: none; }
2634/* Op desktop is er geen tabbalk, dus mag hij lager staan. */
2635@media (min-width: 768px) {
2636 .read-top { bottom: 1.5rem; right: 1.5rem; }
2637}
2638@media (prefers-reduced-motion: reduce) {
2639 .read-top { transition: none; transform: none; }
2640}
2641
[7cf8144]2642@media (prefers-reduced-motion: reduce) {
[e46ebaa]2643 html:has(body.on-home[data-feed-view="reader"]) {
2644 scroll-snap-type: none;
2645 scroll-behavior: auto;
2646 }
[7cf8144]2647}
2648
[7bc636b]2649/* -------- GRID VIEW TILES (Instagram-stijl) -------- */
2650.feed-grid {
2651 padding: 1rem 0 2rem;
2652}
2653.grid-tiles {
2654 display: grid;
2655 gap: 4px;
2656 grid-template-columns: repeat(2, 1fr);
2657}
2658.grid-tile {
2659 position: relative;
2660 display: block;
2661 aspect-ratio: 1;
2662 background-size: cover;
2663 background-position: center;
2664 background-color: var(--paper-2);
2665 overflow: hidden;
2666 text-decoration: none;
2667 color: var(--ink);
2668 transition: transform .2s;
2669 cursor: pointer;
2670 -webkit-tap-highlight-color: rgba(0,0,0,.1);
2671}
[cbe4f4e]2672
[a64d705]2673/* Transparent covers (PNG logos etc.) sit on white so they don't blend into a dark
2674 theme. The white is on the IMG, so the tile's accent-gradient placeholder shows
2675 while the image is still loading. */
[cbe4f4e]2676.post-cover img,
2677.post-list-cover img,
[a64d705]2678.grid-tile-img { background-color: #fff; }
2679/* Accent-gradient placeholder shown while the cover image loads (the image fades in
2680 over it), instead of a white flash on cover tiles. */
2681.grid-tile:not(.grid-tile-gradient) {
2682 background-image: linear-gradient(135deg,
2683 color-mix(in srgb, var(--accent, #888) 22%, var(--paper-2, var(--paper))) 0%,
2684 color-mix(in srgb, var(--accent, #888) 6%, var(--paper-2, var(--paper))) 100%);
2685}
[2eca083]2686/* Cover as a real <img> (not background-image): browsers downsample <img> with the
[a64d705]2687 high-quality image pipeline, so high-res line-art covers don't go jagged when shrunk.
2688 Fades in on load (.is-loading removed) so the placeholder shows meanwhile. */
[7475ff3]2689.grid-tile-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; transition: opacity .4s ease; }
[a64d705]2690.grid-tile-img.is-loading { opacity: 0; }
[6dd26e5]2691/* Audio tile (Shaer, Robins vraag 30-7): the waveform PNG is white on
2692 transparent and floats OVER the tile's own hue gradient, so every audio
[1f640ff]2693 post keeps its color and gets its shape. Wave and title each get their
2694 own band (wave upper, title lower): centering both stacked them right
2695 through each other (Robins schermafdruk). */
[6dd26e5]2696.grid-tile-img.grid-tile-wave {
2697 background-color: transparent;
2698 object-fit: contain;
[1f640ff]2699 /* explicit box, not auto: an absolutely positioned img falls back to its
2700 intrinsic size when width/height are auto, collapsing the band */
2701 top: 8%; left: 8%; right: auto; bottom: auto;
2702 width: 84%; height: 46%;
[6dd26e5]2703 opacity: .85;
2704}
[1f640ff]2705.grid-tile-audio .grid-tile-title { position: absolute; left: 10%; right: 10%; top: 60%; }
2706.grid-tile-audio .grid-tile-gradient-src { position: absolute; left: 10%; right: 10%; top: 76%; }
[b31c119]2707/* Cover videos are decorative, not players: let clicks + right-click pass through to the
2708 tile link so you get the normal link menu (not the browser's <video> menu/controls).
2709 Autoplay is independent of pointer-events, so the video still plays. */
2710video.grid-tile-img,
2711.post-list-cover video,
2712.post-cover video { pointer-events: none; }
[7bc636b]2713.grid-tile:hover { transform: scale(0.98); }
2714.grid-tile-overlay {
2715 position: absolute;
2716 inset: 0;
2717 padding: .6rem;
2718 display: flex;
[1f0c85b]2719 flex-direction: column;
2720 justify-content: flex-end;
2721 align-items: flex-start;
[7bc636b]2722 background: linear-gradient(to top, rgba(0,0,0,.65) 0%, rgba(0,0,0,0) 50%);
2723 opacity: 0;
2724 transition: opacity .2s;
2725 pointer-events: none; /* klik moet naar de <a> eronder gaan, niet naar de overlay */
2726}
[1f0c85b]2727/* Bron-site (cirkel-feed): toont bij hover "van <site>" onder de titel. */
[a78e051]2728/* Source label: small text that wraps to 2 lines if needed, with a big chain icon
2729 beside it (the text was 1.44rem — bigger than the title — and overflowed on mobile). */
[1f0c85b]2730.grid-tile-overlay-src {
2731 color: #fff; opacity: .85;
[a78e051]2732 font-size: .72rem; line-height: 1.2; margin-top: .25rem;
2733 display: flex; align-items: center; gap: .3rem; width: 100%;
[1f0c85b]2734}
[a78e051]2735.grid-tile-overlay-src::before { content: "⛓"; font-size: 1.3rem; line-height: 1; flex: 0 0 auto; }
[1f0c85b]2736.grid-tile-gradient-src {
[a78e051]2737 margin-top: .35rem; font-size: .72rem; line-height: 1.2; opacity: .85;
[6cabd18]2738 color: var(--ink-soft);
[a78e051]2739 display: flex; align-items: center; gap: .3rem; width: 100%;
[1f0c85b]2740}
[a78e051]2741.grid-tile-gradient-src::before { content: "⛓"; font-size: 1.3rem; line-height: 1; flex: 0 0 auto; }
[7bc636b]2742.grid-tile-overlay strong {
2743 color: #fff;
2744 font-family: var(--font-display);
2745 font-size: .9rem;
2746 font-weight: 500;
2747 line-height: 1.15;
2748 display: -webkit-box;
2749 -webkit-line-clamp: 3;
2750 -webkit-box-orient: vertical;
2751 overflow: hidden;
2752}
2753@media (hover: hover) {
2754 .grid-tile:hover .grid-tile-overlay { opacity: 1; }
2755}
2756@media (hover: none) {
2757 /* Op touch-devices altijd overlay tonen zodat titels zichtbaar zijn */
2758 .grid-tile-overlay { opacity: 1; background: linear-gradient(to top, rgba(0,0,0,.7) 0%, rgba(0,0,0,0) 70%); }
2759}
2760
2761.grid-tile-gradient {
2762 background-image: none;
2763 background-color: hsl(var(--tile-hue, 30), 40%, 85%);
2764 background-image: linear-gradient(135deg, hsl(var(--tile-hue, 30), 45%, 88%), hsl(calc(var(--tile-hue, 30) + 30), 35%, 75%));
2765 display: flex;
[6cabd18]2766 flex-direction: column;
[7bc636b]2767 align-items: center;
2768 justify-content: center;
2769 padding: 1rem;
2770 text-align: center;
2771}
2772[data-theme="dark"] .grid-tile-gradient,
2773.grid-tile-gradient[data-theme="dark"] {
2774 background-image: linear-gradient(135deg, hsl(var(--tile-hue, 30), 30%, 18%), hsl(calc(var(--tile-hue, 30) + 30), 25%, 12%));
2775}
2776.grid-tile-title {
2777 font-family: var(--font-display);
2778 font-size: 1rem;
2779 font-weight: 500;
2780 color: var(--ink);
2781 line-height: 1.2;
2782 display: -webkit-box;
2783 -webkit-line-clamp: 4;
2784 -webkit-box-orient: vertical;
2785 overflow: hidden;
2786 z-index: 1;
[b607d4d]2787 /* Federated link posts can have a long bare URL as their title — break it so it wraps
2788 inside the tile and clamps cleanly instead of overflowing past both edges. */
2789 max-width: 100%;
2790 overflow-wrap: anywhere;
2791 word-break: break-word;
2792 hyphens: auto;
[7bc636b]2793}
2794
2795.grid-tile-pin {
2796 position: absolute;
2797 top: .5rem;
2798 right: .5rem;
2799 display: inline-flex;
2800 align-items: center;
2801 gap: .25rem;
2802 padding: .2rem .55rem;
2803 background: var(--accent);
2804 color: #fff;
2805 border-radius: 999px;
2806 font-family: var(--font-ui);
2807 font-size: .65rem;
2808 font-weight: 700;
2809 text-transform: uppercase;
2810 letter-spacing: .06em;
2811 z-index: 3;
2812 box-shadow: 0 2px 6px rgba(0,0,0,.3);
2813 pointer-events: none;
2814}
[6bee3ec]2815.grid-tile-pin svg {
2816 width: .95em;
2817 height: .95em;
2818 margin-top: -1px;
[7bc636b]2819}
[2f919c0]2820/* Pinned/boosted tile: accent ring. An outline on the tile is painted UNDER the absolute
2821 cover <img>, so draw the ring as a pseudo-element overlay ABOVE the image (z-index above
2822 the img, below the corner badges + nsfw veil). */
2823.grid-tile.is-pinned { position: relative; z-index: 1; }
2824.grid-tile.is-pinned::after {
2825 content: '';
2826 position: absolute;
2827 inset: 0;
2828 border: 3px solid var(--accent);
2829 border-radius: inherit;
2830 pointer-events: none;
[7bc636b]2831 z-index: 1;
2832}
2833.grid-tile-type {
2834 position: absolute;
2835 top: .4rem;
2836 left: .4rem;
2837 padding: .15rem .5rem;
2838 background: rgba(0,0,0,.55);
2839 color: #fff;
2840 border-radius: 999px;
2841 font-family: var(--font-ui);
2842 font-size: .6rem;
2843 font-weight: 600;
2844 text-transform: uppercase;
2845 letter-spacing: .05em;
2846 z-index: 2;
2847}
2848
2849@media (min-width: 600px) {
2850 .grid-tiles { grid-template-columns: repeat(3, 1fr); }
2851}
2852@media (min-width: 900px) {
2853 .grid-tiles { grid-template-columns: repeat(3, 1fr); gap: 8px; }
2854}
2855
2856/* -------- POST-TYPE SPECIFIEKE LAYOUTS -------- */
2857
2858/* Foto-post: beeld prominent, geen titel bovenaan, caption onder */
2859.feed-timeline[data-post-type="foto"] .post-title {
2860 font-size: 1.1rem;
2861 color: var(--ink-muted);
2862 font-weight: 400;
2863}
2864.feed-timeline[data-post-type="foto"] .post-cover {
2865 margin: 0 -1rem 1rem;
2866 border-radius: 0;
2867}
2868.feed-timeline[data-post-type="foto"] .post-cover img {
2869 width: 100%;
2870 border-radius: 0;
2871}
2872
2873/* Post-caption onder de cover */
2874.post-caption {
2875 font-family: var(--font-body);
2876 font-size: 1rem;
2877 color: var(--ink);
2878 line-height: 1.5;
2879 margin: 0 0 1.25rem;
2880 padding: 0 0 1rem;
2881 border-bottom: 1px solid var(--rule);
2882 white-space: pre-wrap;
2883}
2884.feed-timeline[data-post-type="foto"] .post-caption {
2885 font-size: 1.05rem;
2886 margin-top: -.5rem;
2887 padding-bottom: 1.25rem;
2888}
2889
2890/* Audio/video posts — type-chip helder, content eronder zoals normaal */
2891.feed-timeline[data-post-type="audio"] .post-title,
2892.feed-timeline[data-post-type="video"] .post-title {
2893 font-size: 1.5rem;
2894}
2895
2896@media (min-width: 768px) {
2897 .feed-timeline[data-post-type="foto"] .post-cover {
2898 margin: 0 0 1.5rem;
2899 border-radius: var(--radius);
2900 }
2901}
2902
2903/* -------- ADMIN EDIT-BUTTON op post-view (alleen zichtbaar voor ingelogde admin) -------- */
2904.post-edit-btn {
2905 position: absolute;
2906 top: 1rem;
2907 right: 1rem;
2908 display: inline-flex;
2909 align-items: center;
2910 justify-content: center;
2911 width: 44px;
2912 height: 44px;
2913 background: var(--paper);
2914 border: 1px solid var(--rule);
2915 border-radius: 50%;
2916 color: var(--ink-muted);
2917 text-decoration: none;
2918 box-shadow: 0 2px 8px rgba(0,0,0,.08);
2919 transition: background .15s, color .15s, transform .15s, border-color .15s;
2920 z-index: 10;
2921}
2922.post-edit-btn:hover {
2923 background: var(--accent);
2924 border-color: var(--accent);
2925 color: var(--paper);
2926 transform: scale(1.05);
2927}
2928.post-edit-btn .icon {
2929 width: 1.1rem;
2930 height: 1.1rem;
2931}
2932/* Zorg dat de article relative is zodat absolute positionering werkt */
2933.feed-timeline { position: relative; }
2934
2935@media (min-width: 768px) {
2936 .post-edit-btn {
2937 top: 1.5rem;
2938 right: 1.5rem;
2939 }
2940}
2941
2942/* ============================================================
2943 v8.0 — ACCENT SPAN + POST-TABLE (published posts)
2944 ============================================================ */
2945.post span.accent,
2946.post-content span.accent,
2947article span.accent,
2948page-container span.accent {
2949 color: var(--accent);
2950 font-weight: 500;
2951}
2952
2953.post-table,
2954article table.post-table {
2955 width: 100%;
2956 max-width: 100%;
2957 border-collapse: collapse;
2958 margin: 1.25rem 0;
2959 font-size: .95rem;
2960 display: block;
2961 overflow-x: auto;
2962 -webkit-overflow-scrolling: touch;
2963}
2964.post-table thead { background: color-mix(in srgb, var(--accent) 10%, transparent); }
2965.post-table th,
2966.post-table td {
2967 padding: .6rem .8rem;
2968 text-align: left;
2969 border: 1px solid var(--rule);
2970 vertical-align: top;
2971}
2972.post-table th {
2973 font-family: var(--font-ui);
2974 font-weight: 600;
2975 font-size: .88rem;
2976 color: var(--ink);
2977 letter-spacing: .02em;
2978}
2979.post-table tbody tr:nth-child(even) {
2980 background: color-mix(in srgb, var(--ink) 3%, transparent);
2981}
2982@media (min-width: 700px) {
2983 .post-table { display: table; overflow: visible; }
2984}
2985
2986/* ============================================================
2987 v8.0 fix — grid-cols picker (desktop only) + grid col overrides
2988 ============================================================ */
2989
2990/* Switcher-wrap bevat nu ook de cols-picker; layout side-by-side */
2991.view-switcher-wrap .container {
2992 display: flex;
2993 align-items: center;
2994 justify-content: center;
2995 gap: 1rem;
2996 flex-wrap: wrap;
2997}
2998
[64b90c0]2999/* Solo / Cirkel scope-switcher (alleen in circle-modus) — segmented toggle, centraal.
3000 Hoge specificiteit (+ !important op tekst) zodat 'ie globale link-stijlen wint. */
3001.view-switcher-wrap .feed-scope {
3002 display: inline-flex;
3003 background: var(--paper-2);
3004 border: 1px solid var(--rule);
3005 border-radius: 999px;
3006 padding: 3px;
3007}
3008.view-switcher-wrap .feed-scope-btn {
3009 display: inline-flex;
3010 align-items: center;
3011 padding: .32rem .95rem;
3012 min-height: 30px;
3013 border: none !important;
3014 border-radius: 999px !important;
3015 background: transparent !important;
3016 color: var(--ink-muted) !important;
3017 font-family: var(--font-ui);
3018 font-size: .82rem;
3019 font-weight: 500 !important;
3020 text-decoration: none !important;
3021 cursor: pointer;
3022 transition: all .15s;
3023}
3024.view-switcher-wrap .feed-scope-btn:hover { color: var(--ink) !important; }
3025.view-switcher-wrap .feed-scope-btn.is-active {
3026 background: var(--ink) !important;
3027 color: var(--paper) !important;
3028}
[9f81a09]3029
[7bc636b]3030.grid-cols-picker {
3031 display: none; /* default hidden — desktop + grid-active maakt 'm zichtbaar */
3032 gap: 2px;
3033 padding: 0;
3034}
3035.grid-cols-btn {
3036 display: inline-flex;
3037 align-items: center;
3038 justify-content: center;
3039 min-width: 36px;
3040 height: 32px;
3041 padding: 0 .6rem;
3042 background: transparent;
3043 border: 1px solid var(--rule);
3044 color: var(--ink-muted);
3045 font-family: var(--font-ui);
3046 font-size: .85rem;
3047 font-weight: 500;
3048 cursor: pointer;
3049 transition: all .12s;
3050}
3051.grid-cols-btn:first-child { border-radius: 999px 0 0 999px; }
3052.grid-cols-btn:last-child { border-radius: 0 999px 999px 0; }
3053.grid-cols-btn:not(:first-child):not(:last-child) { border-left: none; border-right: none; }
3054.grid-cols-btn:hover { color: var(--ink); }
3055/* Active state puur via body[data-grid-cols] — geen is-active-class meer. */
3056body[data-grid-cols="2"] .grid-cols-btn[data-cols="2"],
3057body[data-grid-cols="3"] .grid-cols-btn[data-cols="3"],
3058body[data-grid-cols="4"] .grid-cols-btn[data-cols="4"] {
3059 background: var(--ink);
3060 color: var(--paper);
3061 border-color: var(--ink);
3062}
3063
[1578f5d]3064/* Desktop + grid-view → toon cols-picker (op de home-feed; niet op archief) */
[7bc636b]3065@media (min-width: 600px) {
[1578f5d]3066 body.on-home[data-feed-view="grid"] .grid-cols-picker {
[7bc636b]3067 display: inline-flex;
3068 }
3069}
3070
[66cfbaa]3071/* Kolom-overrides op desktop. Mobiel negeert dit (staat vast op 2). Geldt op ELKE
3072 feed met grid (home én cirkel/tag/type/user) — scope op .feed-grid .grid-tiles. */
[7bc636b]3073@media (min-width: 600px) {
[66cfbaa]3074 body[data-grid-cols="2"] .feed-grid .grid-tiles { grid-template-columns: repeat(2, 1fr); }
3075 body[data-grid-cols="3"] .feed-grid .grid-tiles { grid-template-columns: repeat(3, 1fr); }
3076 body[data-grid-cols="4"] .feed-grid .grid-tiles { grid-template-columns: repeat(4, 1fr); }
[7bc636b]3077}
3078
3079/* Gradient-tile: iets meer contrast voor light + dark mode zodat titel altijd leesbaar is */
3080.grid-tile-gradient {
3081 background-image: linear-gradient(135deg,
3082 hsl(var(--tile-hue, 30), 55%, 72%),
3083 hsl(calc(var(--tile-hue, 30) + 40), 45%, 60%));
3084}
3085[data-theme="dark"] .grid-tile-gradient {
3086 background-image: linear-gradient(135deg,
3087 hsl(var(--tile-hue, 30), 40%, 30%),
3088 hsl(calc(var(--tile-hue, 30) + 40), 30%, 18%));
3089}
3090.grid-tile-gradient .grid-tile-title {
3091 color: #fff;
3092 text-shadow: 0 1px 3px rgba(0,0,0,.25);
3093}
3094[data-theme="dark"] .grid-tile-gradient .grid-tile-title {
3095 color: #fff;
3096 text-shadow: 0 1px 2px rgba(0,0,0,.5);
3097}
3098
3099/* ============================================================
3100 v8.0.2 — COMPACT DESIGN OVERRIDES
3101 Tighter masthead, padding, margins overall. Profiel-header
3102 collapse/expand blijft zoals 'ie was.
3103 ============================================================ */
3104
3105/* Masthead: compacter */
[a036251]3106.masthead { padding: calc(.55rem + var(--ios-safe-top, 0px)) 0 .55rem; }
[7bc636b]3107.masthead-inner { gap: 1rem; }
3108.site-title { font-size: 1.25rem; }
3109.nav-link, .nav-btn { padding: .4rem .7rem; min-height: 2rem; font-size: .82rem; }
3110
3111/* Main content padding */
3112main { padding-top: 1rem; }
3113.page { padding-block: 1rem 1.75rem; }
3114
3115/* View switcher-bar strakker */
3116.view-switcher { padding: .4rem 0; gap: .3rem; }
3117.view-switch-btn { padding: .4rem .85rem; min-height: 38px; font-size: .8rem; }
3118.grid-cols-btn { min-width: 32px; height: 28px; padding: 0 .5rem; font-size: .8rem; }
3119
3120/* Post header spacing terug */
3121.post-header { margin: 0 0 1.25rem; }
3122.post-title { margin-bottom: .35rem; }
3123.post-meta { font-size: .78rem; }
3124.post-tags { margin-top: .6rem; gap: .3rem; }
3125.post-tag { font-size: .7rem; padding: .15rem .55rem; }
3126
3127/* Article footer + pagination compacter */
3128.article-footer { padding-top: 1.25rem; margin-top: 1.5rem; }
3129.pagination { padding-block: 1.25rem 2rem; margin-top: 1.5rem; }
3130.pagination-item { padding: .75rem .95rem; min-height: 4rem; }
3131.pagination-title { font-size: .95rem; }
3132
3133/* Site footer compacter */
[7ca3ffc]3134.site-footer { padding: 1.25rem 0 calc(1.25rem + env(safe-area-inset-bottom, 0px)); margin-top: 2rem; font-size: .78rem; }
[7bc636b]3135.site-footer-inner { gap: .75rem; }
3136
3137/* Profiel-header: full mode iets minder riant (compact mode blijft hetzelfde) */
3138.profile-header { padding: 1rem 0; }
3139.profile-photo { width: 72px; height: 72px; }
3140.profile-photo-fallback { font-size: 1.8rem; }
3141.profile-name { font-size: 1.2rem; }
3142.profile-bio { font-size: .85rem; margin-top: .15rem; }
3143.profile-links { margin-top: .5rem; gap: .4rem; }
[3507b0b]3144.profile-links a,
3145.profile-links .profile-fedi-link { width: 32px; height: 32px; }
[7bc636b]3146
3147@media (min-width: 768px) {
3148 .profile-header { padding: 1.35rem 0; }
3149 .profile-photo { width: 92px; height: 92px; }
3150 .profile-photo-fallback { font-size: 2.4rem; }
3151 .profile-name { font-size: 1.4rem; }
3152 .profile-bio { font-size: .95rem; }
3153 .profile-header-inner { gap: 1.1rem; }
3154 /* Compact-mode op desktop blijft klein zoals we hadden afgesproken */
3155 .on-post .profile-photo,
3156 .on-special .profile-photo { width: 42px; height: 42px; }
3157}
3158
3159/* Grid-tegels iets strakker gaten */
3160.grid-tiles { gap: 3px; }
3161
3162/* Post-cover margin */
3163.post-cover { margin: 0 0 1rem; }
3164
3165/* Audio player wat lichter */
3166#pcms-audio-bar { padding: .55rem 1rem; }
3167
3168/* v8.1 — pagination CTA + mobile tap target */
3169.pagination-cta {
3170 display: inline-block;
3171 font-family: var(--font-ui);
3172 font-size: .72rem;
3173 font-weight: 600;
3174 color: var(--accent);
3175 margin-top: .35rem;
3176 letter-spacing: .02em;
3177 opacity: .9;
3178}
3179a.pagination-item:hover .pagination-cta { opacity: 1; }
3180
3181/* Mobiel: nog meer tap-feedback + iets prominenter */
3182@media (max-width: 640px) {
3183 a.pagination-item {
3184 padding: 1.1rem 1rem;
3185 min-height: 5.5rem;
3186 border-width: 2px;
3187 }
3188 a.pagination-item:active {
3189 background: color-mix(in srgb, var(--accent) 10%, var(--paper-2));
3190 transform: scale(.98);
3191 }
3192 .pagination-title { font-size: 1rem; }
3193 .pagination-cta { font-size: .75rem; }
3194 .pagination .icon { width: 1.5em; height: 1.5em; }
3195}
3196
3197
3198
3199/* v8.3 / v9.4 — PWA install button (alleen zichtbaar als browser install ondersteunt) */
3200.nav-install-btn[hidden] { display: none; }
3201.nav-install-btn {
3202 position: relative;
3203 display: inline-flex;
3204 align-items: center;
3205 justify-content: center;
3206 gap: .35rem;
3207 background: linear-gradient(135deg,
3208 var(--accent),
3209 color-mix(in srgb, var(--accent) 80%, #000));
3210 color: #fff;
3211 border: none;
3212 border-radius: .65rem;
3213 padding: .45rem .85rem;
3214 font-size: .8rem;
3215 font-weight: 600;
3216 line-height: 1;
3217 cursor: pointer;
3218 overflow: hidden;
3219 isolation: isolate;
3220 box-shadow:
3221 0 1px 0 rgba(255,255,255,.15) inset,
3222 0 2px 6px color-mix(in srgb, var(--accent) 35%, transparent);
3223 transition:
3224 transform .15s cubic-bezier(.4, 0, .2, 1),
3225 box-shadow .2s ease,
3226 filter .15s ease;
3227}
3228.nav-install-btn::before {
3229 content: "";
3230 position: absolute;
3231 top: 0;
3232 left: -100%;
3233 width: 60%;
3234 height: 100%;
3235 background: linear-gradient(110deg,
3236 transparent 30%,
3237 rgba(255,255,255,.22) 50%,
3238 transparent 70%);
3239 z-index: -1;
3240 animation: pcmsInstallShimmer 4s ease-in-out infinite;
3241 pointer-events: none;
3242}
3243.nav-install-btn:hover {
3244 transform: translateY(-1px);
3245 filter: brightness(1.08);
3246 box-shadow:
3247 0 1px 0 rgba(255,255,255,.2) inset,
3248 0 4px 10px color-mix(in srgb, var(--accent) 50%, transparent);
3249}
3250.nav-install-btn:active { transform: translateY(0); }
3251.nav-install-btn .icon {
3252 flex-shrink: 0;
3253 transition: transform .25s cubic-bezier(.34, 1.56, .64, 1);
3254}
3255.nav-install-btn:hover .icon { transform: translateY(-1px); }
3256@media (prefers-reduced-motion: reduce) {
3257 .nav-install-btn::before { animation: none; left: -100%; }
3258 .nav-install-btn:hover { transform: none; }
3259 .nav-install-btn:hover .icon { transform: none; }
3260}
3261/* Als PWA al draait (standalone mode) — verberg install-prompt knop volledig */
3262@media all and (display-mode: standalone) {
3263 #pwa-install-btn { display: none !important; }
3264}
3265
3266/* ========== v8.9.9 — Privé-post indicators ========== */
3267.post-private-banner {
3268 display: flex;
3269 align-items: center;
3270 gap: .6rem;
3271 padding: .75rem 1rem;
3272 background: color-mix(in srgb, #eab308 12%, var(--paper, #fff));
3273 border: 1px solid color-mix(in srgb, #eab308 40%, transparent);
3274 border-radius: 8px;
3275 margin: 0 0 1rem;
3276 font-size: .88rem;
3277 color: var(--ink, #1a1a1a);
3278}
3279.post-private-banner strong {
3280 color: #b45309;
3281}
3282
3283.grid-tile-private {
3284 position: absolute;
3285 top: 8px;
3286 left: 8px;
3287 padding: 3px 8px;
3288 background: rgba(0,0,0,0.7);
3289 color: #fde68a;
3290 font-size: .7rem;
3291 font-weight: 700;
3292 border-radius: 999px;
3293 z-index: 3;
3294 backdrop-filter: blur(4px);
3295 -webkit-backdrop-filter: blur(4px);
3296}
3297
3298/* ========== v8.9.10 — Social chip (inline in post-body) ========== */
3299.social-chip {
3300 display: inline-flex;
3301 align-items: center;
3302 gap: .45rem;
3303 padding: .35rem .75rem;
3304 background: color-mix(in srgb, var(--accent) 10%, transparent);
3305 border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
3306 border-radius: 999px;
3307 color: var(--ink, #1a1a1a);
3308 text-decoration: none;
3309 font-family: var(--font-ui, system-ui);
3310 font-size: .85rem;
3311 font-weight: 600;
3312 line-height: 1.2;
3313 transition: all .15s;
3314 vertical-align: middle;
3315 margin: 0 .1rem;
3316}
3317.social-chip:hover {
3318 background: var(--accent);
3319 color: #fff;
3320 border-color: var(--accent);
3321 text-decoration: none;
3322 transform: translateY(-1px);
3323 box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 40%, transparent);
3324}
3325.social-chip .icon {
3326 width: 16px;
3327 height: 16px;
3328 flex-shrink: 0;
3329}
3330.social-chip-icon-only {
3331 width: 36px;
3332 height: 36px;
3333 padding: 0;
3334 justify-content: center;
3335 border-radius: 50%;
3336}
3337.social-chip-icon-only .icon {
3338 width: 18px;
3339 height: 18px;
3340}
3341
3342/* v8.9.34 — player hidden state + post audio blocks
3343 v9.3 — Hide-rules uitgeschakeld: mini-player blijft permanent zichtbaar
3344 zodat 'ie niet meer verdwijnt bij browser-back of navigatie. */
3345.audio-player.is-hidden {
3346 /* display: none !important; */
3347}
3348body:not(.has-audio-player) #pcms-audio-player.is-hidden {
3349 /* display: none !important; */
3350}
3351
3352/* Post audio track — single track row in een post */
3353/* Lokale audio-track — visueel consistent met .post-audio-external */
3354.post-audio-track {
3355 display: flex;
3356 align-items: center;
3357 gap: .75rem;
3358 padding: .65rem .85rem;
3359 background: var(--paper-2, color-mix(in srgb, var(--ink) 4%, transparent));
3360 border: 1px solid var(--rule, rgba(0,0,0,.08));
3361 border-radius: 10px;
3362 margin: .75rem 0;
3363 transition: background .15s, border-color .15s;
3364}
3365.post-audio-track:hover {
3366 border-color: var(--accent, #c2410c);
3367 background: color-mix(in srgb, var(--accent, #c2410c) 5%, var(--paper-2, transparent));
3368}
[230e446]3369/* Korte highlight wanneer je via de mini-speler naar deze track springt. */
[359b9ae]3370.post-audio-track.pat-flash,
3371.post-album-track-compact.pat-flash {
[230e446]3372 animation: patFlash 1.6s ease-out;
[359b9ae]3373 border-radius: 8px;
[5258945]3374}
3375/* Blijvende highlight op de track die NU actief is in de speler. */
3376.post-audio-track.pat-playing,
3377.post-album-track-compact.pat-playing {
3378 background: color-mix(in srgb, var(--accent, #c2410c) 12%, var(--paper-2, transparent));
3379 box-shadow: inset 3px 0 0 0 var(--accent, #c2410c);
3380 border-radius: 8px;
[230e446]3381}
3382@keyframes patFlash {
3383 0%, 30% { border-color: var(--accent, #c2410c); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent, #c2410c) 35%, transparent); }
3384 100% { box-shadow: 0 0 0 0 transparent; }
3385}
[7bc636b]3386.post-audio-track .pat-play {
3387 flex-shrink: 0;
3388 width: 42px;
3389 height: 42px;
3390 border-radius: 8px; /* zelfde rounded-square als pae-icon */
3391 border: none;
3392 background: var(--accent, #c2410c);
3393 color: var(--paper, #fff);
3394 cursor: pointer;
3395 display: inline-flex;
3396 align-items: center;
3397 justify-content: center;
3398 transition: transform .1s, background .15s;
3399 padding: 0;
3400 position: relative;
3401 overflow: hidden;
3402}
3403.post-audio-track .pat-play:hover { transform: scale(1.04); }
3404.post-audio-track .pat-play:active { transform: scale(.96); }
3405.post-audio-track .pat-play svg,
3406.post-audio-track .pat-play .pat-sitelogo {
3407 width: 100%; height: 100%;
3408 position: absolute;
3409 top: 0; left: 0;
3410 transition: opacity .15s;
3411}
3412.post-audio-track .pat-play .icon-play,
3413.post-audio-track .pat-play .icon-pause {
3414 width: 18px; height: 18px;
3415 position: absolute;
3416 top: 50%; left: 50%;
3417 transform: translate(-50%, -50%);
3418 fill: currentColor;
3419 opacity: 0; /* verborgen tot hover of is-current */
3420}
3421/* Site logo: object-cover binnen 42x42 box */
3422.post-audio-track .pat-play .pat-sitelogo {
3423 object-fit: cover;
3424 opacity: 1;
3425}
3426.post-audio-track .pat-play .pat-sitelogo-fallback {
3427 padding: 11px; /* SVG music-note iets kleiner in box */
3428 opacity: 1;
3429}
3430/* Bij hover: site logo faded, play-icoon verschijnt */
3431.post-audio-track:hover .pat-play .pat-sitelogo { opacity: 0.25; }
3432.post-audio-track:hover .pat-play .icon-play { opacity: 1; }
3433/* Bij current + playing: toon pause-icon */
3434.post-audio-track.is-current .pat-play .pat-sitelogo { opacity: 0.25; }
3435.post-audio-track.is-current .pat-play .icon-play { opacity: 1; }
3436.post-audio-track.is-current.is-playing .pat-play .icon-play { opacity: 0; }
3437.post-audio-track.is-current.is-playing .pat-play .icon-pause { opacity: 1; }
3438.post-audio-track.is-current {
3439 border-color: var(--accent, #c2410c);
3440 background: color-mix(in srgb, var(--accent, #c2410c) 10%, transparent);
3441}
3442.post-audio-track .pat-meta {
3443 flex: 1;
3444 min-width: 0;
3445 display: flex;
3446 flex-direction: column;
3447 gap: 2px;
3448}
3449.post-audio-track .pat-title {
3450 display: block;
3451 font-weight: 600;
3452 color: var(--ink);
3453 font-size: .95rem;
3454 overflow: hidden;
3455 text-overflow: ellipsis;
3456 white-space: nowrap;
3457}
3458.post-audio-track .pat-artist {
3459 display: block;
3460 font-size: .78rem;
3461 color: var(--ink-muted, var(--ink));
3462 opacity: .65;
3463 overflow: hidden;
3464 text-overflow: ellipsis;
3465 white-space: nowrap;
3466}
3467.post-audio-track .pat-duration {
3468 flex-shrink: 0;
3469 font-family: ui-monospace, monospace;
3470 font-size: .8rem;
3471 opacity: .55;
3472}
3473
3474/* Album block in een post */
3475.post-album {
3476 position: relative;
3477 border: 1px solid var(--rule, rgba(0,0,0,.1));
3478 border-radius: 14px;
3479 overflow: hidden;
3480 margin: 1.25rem 0;
3481 background: var(--paper-2, color-mix(in srgb, var(--ink) 3%, transparent));
3482}
3483.post-album-header {
3484 display: flex;
3485 gap: .75rem;
3486 padding: .55rem .7rem;
3487 align-items: center;
3488}
3489.post-album-cover {
3490 width: 120px;
3491 height: 120px;
3492 border-radius: 8px;
3493 background-size: cover;
3494 background-position: center;
3495 background-color: var(--rule);
3496 flex-shrink: 0;
3497}
3498/* v9.0 — Collage van track-covers als album-cover leeg is */
3499.post-album-cover-collage {
3500 display: grid;
3501 grid-template-columns: 1fr 1fr;
3502 grid-template-rows: 1fr 1fr;
3503 gap: 0;
3504 overflow: hidden;
3505 background: transparent;
3506}
3507.post-album-cover-collage .post-album-cover-tile {
3508 background-size: cover;
3509 background-position: center;
3510 width: 100%;
3511 height: 100%;
3512}
3513/* Empty state: gradient met muziek-noot */
3514.post-album-cover-empty {
3515 display: flex;
3516 align-items: center;
3517 justify-content: center;
3518 background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 25%, var(--paper-2)), color-mix(in srgb, var(--accent) 10%, var(--paper)));
3519 color: var(--accent, #c2410c);
3520}
3521.post-album-cover-empty svg {
3522 width: 42%;
3523 height: 42%;
3524 opacity: .55;
3525}
3526.post-album-info {
3527 flex: 1;
3528 min-width: 0;
3529}
3530.post-album-label {
3531 text-transform: uppercase;
3532 font-size: .68rem;
3533 letter-spacing: .1em;
3534 opacity: .55;
3535 margin: 0 0 .15rem;
3536 font-weight: 700;
3537}
3538.post-album-title {
3539 font-family: var(--font-display);
3540 font-size: 1.1rem;
3541 font-weight: 600;
3542 margin: 0 0 .1rem;
3543 line-height: 1.15;
3544 letter-spacing: -0.01em;
3545}
3546.post-album-artist {
3547 font-size: .88rem;
3548 opacity: .8;
3549 margin: 0 0 .12rem;
3550 line-height: 1.25;
3551}
3552.post-album-meta {
3553 font-size: .74rem;
3554 opacity: .55;
3555 margin: 0;
3556 line-height: 1.2;
3557}
3558.post-album-playall {
3559 margin-top: .75rem;
3560 padding: .45rem .9rem;
3561 background: var(--accent, #c2410c);
3562 color: var(--paper, #fff);
3563 border: none;
3564 border-radius: 6px;
3565 font-weight: 600;
3566 cursor: pointer;
3567 font-size: .88rem;
3568 display: inline-flex;
3569 align-items: center;
3570 gap: .35rem;
3571}
3572.post-album-playall:hover { filter: brightness(1.08); }
3573
3574/* ============================================================
3575 v9.0 — Album cover clickable button
3576 ============================================================ */
3577.post-album-cover-btn {
3578 position: relative;
3579 background: none;
3580 border: none;
3581 padding: 0;
3582 margin: 0;
3583 cursor: pointer;
3584 flex-shrink: 0;
3585 border-radius: 8px;
3586 overflow: hidden;
3587 display: block;
3588 width: auto;
3589 /* v9.1 — voorkom mobile 300ms double-tap zoom delay, anders zou 2× snel klikken
3590 een zoom triggeren i.p.v. 2× click-events */
3591 touch-action: manipulation;
3592 -webkit-tap-highlight-color: transparent;
3593}
3594.post-album-cover-btn .post-album-cover {
3595 display: block;
3596 width: 76px;
3597 height: 76px;
3598 border-radius: 7px;
3599 background-size: cover;
3600 background-position: center;
3601 background-color: var(--rule);
3602 transition: transform .25s ease;
3603}
3604.post-album-cover-btn:hover .post-album-cover {
3605 transform: scale(1.04);
3606}
3607.post-album-cover-btn .post-album-cover-empty {
3608 background: linear-gradient(135deg,
3609 color-mix(in srgb, var(--accent, #c2410c) 35%, var(--paper)),
3610 color-mix(in srgb, var(--accent, #c2410c) 10%, var(--paper-2)));
3611 display: flex;
3612 align-items: center;
3613 justify-content: center;
3614}
3615.post-album-cover-btn .post-album-cover-empty svg {
3616 width: 28px;
3617 height: 28px;
3618 color: color-mix(in srgb, var(--accent, #c2410c) 60%, transparent);
3619}
3620/* Play overlay op hover */
3621.post-album-cover-play {
3622 position: absolute;
3623 inset: 0;
3624 display: flex;
3625 align-items: center;
3626 justify-content: center;
3627 background: rgba(0, 0, 0, .35);
3628 opacity: 0;
3629 transition: opacity .2s ease;
3630 border-radius: 8px;
3631 pointer-events: none;
3632}
3633.post-album-cover-play svg {
3634 width: 48px;
3635 height: 48px;
3636 color: #fff;
3637 filter: drop-shadow(0 2px 8px rgba(0,0,0,.4));
3638}
3639.post-album-cover-btn:hover .post-album-cover-play,
3640.post-album-cover-btn:focus-visible .post-album-cover-play {
3641 opacity: 1;
3642}
3643
3644/* ============================================================
3645 v1 P52 — Admin actions overlay (edit / delete)
3646 Only rendered when the viewer has god role. Sits top-right
3647 of the card so it doesn't compete with the cover play affordance.
3648 ============================================================ */
3649.post-album-actions {
3650 position: absolute;
3651 top: .4rem;
3652 right: .4rem;
3653 display: flex;
3654 gap: .25rem;
3655 z-index: 2;
3656}
3657.post-album-action {
3658 width: 28px;
3659 height: 28px;
3660 border-radius: 6px;
3661 border: 1px solid var(--rule);
3662 background: color-mix(in srgb, var(--paper) 78%, transparent);
3663 backdrop-filter: blur(8px);
3664 -webkit-backdrop-filter: blur(8px);
3665 color: var(--ink);
3666 display: inline-flex;
3667 align-items: center;
3668 justify-content: center;
3669 cursor: pointer;
3670 text-decoration: none;
3671 opacity: .65;
3672 padding: 0;
3673 transition: opacity .15s ease, transform .15s ease, background .15s ease, color .15s ease, border-color .15s ease;
3674 -webkit-tap-highlight-color: transparent;
3675}
3676.post-album-action:hover,
3677.post-album-action:focus-visible {
3678 opacity: 1;
3679 transform: translateY(-1px);
3680 outline: none;
3681}
3682.post-album-action.is-danger:hover,
3683.post-album-action.is-danger:focus-visible {
3684 background: color-mix(in srgb, #c2410c 18%, var(--paper));
3685 border-color: color-mix(in srgb, #c2410c 45%, var(--rule));
3686 color: #c2410c;
3687}
3688.post-album-action svg {
3689 width: 15px;
3690 height: 15px;
3691 display: block;
3692}
3693
3694/* ============================================================
3695 v9.0 — Compacte tracklist (informatief, niet-klikbaar)
3696 ============================================================ */
3697.post-album-tracks {
3698 list-style: none;
3699 padding: 0;
3700 margin: 0;
3701 border-top: 1px solid var(--rule);
3702}
3703/* v9.4 — Playlist insert modal rows */
3704.pli-row {
3705 display: flex;
3706 align-items: center;
3707 gap: .75rem;
3708 padding: .65rem .5rem;
3709 border-bottom: 1px solid var(--border);
3710}
3711.pli-row:last-child { border-bottom: none; }
3712.pli-row-cover {
3713 width: 44px;
3714 height: 44px;
3715 border-radius: 6px;
3716 background-size: cover;
3717 background-position: center;
3718 background-color: color-mix(in srgb, var(--ink, #000) 8%, transparent);
3719 flex-shrink: 0;
3720 display: flex;
3721 align-items: center;
3722 justify-content: center;
3723 font-size: 1.4rem;
3724}
3725.pli-row-info {
3726 flex: 1;
3727 min-width: 0;
3728}
3729.pli-row-title {
3730 font-weight: 600;
3731 overflow: hidden;
3732 text-overflow: ellipsis;
3733 white-space: nowrap;
3734}
3735.pli-row-meta {
3736 font-size: .82rem;
3737 overflow: hidden;
3738 text-overflow: ellipsis;
3739 white-space: nowrap;
3740}
3741.post-playlist-placeholder {
3742 margin: 1rem 0;
3743 user-select: none;
3744}
3745
3746/* v9.4 — Generic modal classes (gebruikt door playlist-editor en andere modals) */
3747.pcms-modal-backdrop {
3748 position: fixed;
3749 inset: 0;
3750 background: rgba(0, 0, 0, .6);
3751 display: flex;
3752 align-items: center;
3753 justify-content: center;
3754 z-index: 9000;
3755 padding: 1rem;
3756 box-sizing: border-box;
3757 overflow-y: auto;
3758}
3759.pcms-modal {
3760 background: var(--paper, #fff);
3761 color: var(--ink, #000);
3762 border-radius: 12px;
3763 width: 100%;
3764 max-width: 640px;
3765 max-height: calc(100vh - 2rem);
3766 display: flex;
3767 flex-direction: column;
3768 overflow: hidden;
3769 box-shadow: 0 20px 60px rgba(0, 0, 0, .3);
3770}
3771.pcms-modal-header {
3772 display: flex;
3773 align-items: center;
3774 justify-content: space-between;
3775 padding: 1rem 1.25rem;
3776 border-bottom: 1px solid var(--border);
3777 flex-shrink: 0;
3778}
3779.pcms-modal-header h3 { font-size: 1.1rem; }
3780.pcms-modal-close {
3781 background: transparent;
3782 border: none;
3783 font-size: 1.6rem;
3784 line-height: 1;
3785 cursor: pointer;
3786 padding: .25rem .5rem;
3787 color: var(--fg-muted, #666);
3788 border-radius: 4px;
3789}
3790.pcms-modal-close:hover {
3791 background: color-mix(in srgb, var(--ink, #000) 8%, transparent);
3792}
3793.pcms-modal-body {
3794 padding: 1.25rem;
3795 overflow-y: auto;
3796 overscroll-behavior: contain;
3797 flex: 1;
3798 min-height: 0;
3799}
3800.pcms-modal-footer {
3801 display: flex;
3802 gap: .5rem;
3803 justify-content: flex-end;
3804 padding: .75rem 1.25rem;
3805 border-top: 1px solid var(--border);
3806 flex-shrink: 0;
3807 background: color-mix(in srgb, var(--ink, #000) 3%, transparent);
3808}
3809
3810/* On mobile: full-screen modal */
3811@media (max-width: 600px) {
3812 .pcms-modal-backdrop {
3813 padding: 0;
3814 }
3815 .pcms-modal {
3816 border-radius: 0;
3817 max-width: 100%;
3818 max-height: 100vh;
3819 height: 100vh;
3820 }
3821}
3822
3823/* v9.4 — Media → Playlists tab */
3824.playlists-page-header {
3825 display: flex;
3826 flex-wrap: wrap;
3827 gap: 1rem;
3828 align-items: center;
3829 justify-content: space-between;
3830 margin-bottom: 1.25rem;
3831}
3832.playlists-page-header > p { flex: 1; min-width: 200px; }
3833.playlists-grid {
3834 display: grid;
3835 grid-template-columns: 1fr;
3836 gap: .75rem;
3837}
3838@media (min-width: 720px) {
3839 .playlists-grid { grid-template-columns: repeat(2, 1fr); }
3840}
3841@media (min-width: 1100px) {
3842 .playlists-grid { grid-template-columns: repeat(3, 1fr); }
3843}
3844.playlist-card {
3845 display: grid;
3846 grid-template-columns: 64px 1fr auto;
3847 gap: .75rem;
3848 align-items: center;
3849 padding: .75rem;
3850 border: 1px solid var(--border);
3851 border-radius: var(--radius);
3852 background: var(--paper, #fff);
3853}
3854.playlist-card-cover {
3855 width: 64px;
3856 height: 64px;
3857 border-radius: 8px;
3858 overflow: hidden;
3859 background-color: color-mix(in srgb, var(--ink, #000) 6%, transparent);
3860 display: flex;
3861 align-items: center;
3862 justify-content: center;
3863}
3864.playlist-card-cover img {
3865 width: 100%;
3866 height: 100%;
3867 object-fit: cover;
3868}
3869.playlist-card-cover-empty { font-size: 1.6rem; opacity: .5; }
3870.playlist-card-info { min-width: 0; }
3871.playlist-card-title {
3872 font-weight: 600;
3873 overflow: hidden;
3874 text-overflow: ellipsis;
3875 white-space: nowrap;
3876}
3877.playlist-card-artist,
3878.playlist-card-meta {
3879 font-size: .82rem;
3880 overflow: hidden;
3881 text-overflow: ellipsis;
3882 white-space: nowrap;
3883}
3884.playlist-card-actions {
3885 display: flex;
3886 gap: .25rem;
3887 flex-shrink: 0;
3888}
3889
3890/* v9.4 — Playlist editor modal (mobile-friendly, single-column) */
3891.pl-editor {
3892 /* Erft van .pcms-modal */
3893}
3894.pl-editor-meta {
3895 display: grid;
3896 grid-template-columns: 1fr;
3897 gap: .75rem;
3898 margin-bottom: 1rem;
3899}
3900@media (min-width: 560px) {
3901 .pl-editor-meta {
3902 grid-template-columns: 1fr 1fr;
3903 }
3904 .pl-editor-meta .pl-editor-field-full { grid-column: 1 / -1; }
3905}
3906.pl-editor-field {
3907 display: flex;
3908 flex-direction: column;
3909 gap: .25rem;
3910 min-width: 0;
3911}
3912.pl-editor-field span {
3913 font-size: .82rem;
3914 color: var(--fg-muted, #666);
3915 font-weight: 500;
3916}
3917.pl-editor-field input,
3918.pl-editor-field select {
3919 width: 100%;
3920 box-sizing: border-box;
3921 padding: .5rem .65rem;
3922 font-size: .95rem;
3923 border: 1px solid var(--border);
3924 border-radius: 6px;
3925 background: var(--paper, #fff);
3926 color: var(--ink, #000);
3927}
3928.pl-editor-field input:focus,
3929.pl-editor-field select:focus {
3930 outline: 2px solid var(--accent, #5a8a5a);
3931 outline-offset: -1px;
3932}
3933.pl-editor-section-title {
3934 margin: 1.25rem 0 .5rem;
3935 font-size: 1rem;
3936 font-weight: 600;
3937}
3938.pl-tracks-selected {
3939 border: 1px solid var(--border);
3940 border-radius: var(--radius);
3941 background: var(--paper, #fff);
3942 min-height: 60px;
3943 margin-bottom: 1rem;
3944 padding: .25rem;
3945}
3946.pl-tracks-empty {
3947 padding: 1.5rem;
3948 text-align: center;
3949 color: var(--fg-muted, #666);
3950 font-size: .9rem;
3951}
3952.pl-track-row {
3953 display: grid;
3954 grid-template-columns: 32px 36px 1fr auto;
3955 gap: .5rem;
3956 align-items: center;
3957 padding: .5rem;
3958 border-bottom: 1px solid var(--border);
3959 background: var(--paper, #fff);
3960 user-select: none;
3961 touch-action: pan-x;
3962}
3963.pl-track-row:last-child { border-bottom: none; }
3964.pl-track-row.is-dragging {
3965 opacity: .55;
3966 transform: scale(.98);
3967 background: color-mix(in srgb, var(--accent, #5a8a5a) 10%, transparent);
3968 border-radius: 6px;
3969}
3970.pl-track-row.drop-target-above {
3971 box-shadow: inset 0 2px 0 0 var(--accent, #5a8a5a);
3972}
3973.pl-track-row.drop-target-below {
3974 box-shadow: inset 0 -2px 0 0 var(--accent, #5a8a5a);
3975}
3976.pl-track-handle {
3977 cursor: grab;
3978 font-size: 1.2rem;
3979 line-height: 1;
3980 color: var(--fg-muted, #666);
3981 display: flex;
3982 align-items: center;
3983 justify-content: center;
3984 height: 32px;
3985 width: 32px;
3986 border-radius: 4px;
3987 flex-shrink: 0;
3988}
3989.pl-track-handle:active { cursor: grabbing; }
3990.pl-track-handle:hover {
3991 background: color-mix(in srgb, var(--ink, #000) 8%, transparent);
3992}
3993.pl-track-num {
3994 text-align: center;
3995 color: var(--fg-muted, #666);
3996 font-size: .85rem;
3997 width: 36px;
3998}
3999.pl-track-info {
4000 min-width: 0;
4001 overflow: hidden;
4002}
4003.pl-track-title {
4004 font-weight: 500;
4005 overflow: hidden;
4006 text-overflow: ellipsis;
4007 white-space: nowrap;
4008}
4009.pl-track-artist {
4010 font-size: .78rem;
4011 color: var(--fg-muted, #666);
4012 overflow: hidden;
4013 text-overflow: ellipsis;
4014 white-space: nowrap;
4015}
4016.pl-track-remove {
4017 background: transparent;
4018 border: none;
4019 cursor: pointer;
4020 padding: .35rem;
4021 border-radius: 4px;
4022 color: var(--fg-muted, #666);
4023 font-size: 1.2rem;
4024 line-height: 1;
4025}
4026.pl-track-remove:hover {
4027 background: color-mix(in srgb, #c00 12%, transparent);
4028 color: #c00;
4029}
4030
4031/* Available tracks panel */
4032.pl-tracks-available-panel {
4033 border: 1px solid var(--border);
4034 border-radius: var(--radius);
4035 background: var(--paper, #fff);
4036}
4037.pl-tracks-available-search {
4038 padding: .5rem;
4039 border-bottom: 1px solid var(--border);
4040}
4041.pl-tracks-available-search input {
4042 width: 100%;
4043 box-sizing: border-box;
4044}
4045.pl-tracks-available-list {
4046 max-height: 30vh;
4047 overflow-y: auto;
4048}
4049.pl-track-row-available {
4050 display: grid;
4051 grid-template-columns: 1fr auto;
4052 gap: .5rem;
4053 align-items: center;
4054 padding: .5rem;
4055 border-bottom: 1px solid var(--border);
4056 cursor: pointer;
4057}
4058.pl-track-row-available:last-child { border-bottom: none; }
4059.pl-track-row-available:hover {
4060 background: color-mix(in srgb, var(--accent, #5a8a5a) 8%, transparent);
4061}
4062.pl-track-row-available.is-already-added {
4063 opacity: .4;
4064 pointer-events: none;
4065}
4066.pl-track-add-btn {
4067 background: transparent;
4068 border: 1px solid var(--border);
4069 border-radius: 4px;
4070 padding: .25rem .5rem;
4071 cursor: pointer;
4072 font-size: .85rem;
4073 color: var(--accent, #5a8a5a);
4074}
4075
4076/* v9.3 — Tracklist items zijn nu klikbare <button class="pat-row"> binnen <li>.
4077 De LI is puur een container zonder visuele styling; alles gebeurt op de button. */
4078.post-album-track-compact {
4079 padding: 0;
4080 margin: 0;
4081 border-bottom: 1px solid var(--rule);
4082 list-style: none;
4083}
4084.post-album-track-compact:last-child { border-bottom: none; }
4085
4086.pat-row {
4087 display: grid;
4088 grid-template-columns: 32px 1fr auto;
4089 gap: .65rem;
4090 align-items: center;
4091 width: 100%;
4092 padding: .5rem .85rem;
4093 background: transparent;
4094 border: none;
4095 color: inherit;
4096 font: inherit;
4097 font-size: .82rem;
4098 text-align: left;
4099 cursor: pointer;
4100 position: relative;
4101 transition: background .15s ease;
4102}
4103.pat-row:hover {
4104 background: color-mix(in srgb, var(--ink, #000) 6%, transparent);
4105}
4106.pat-row:active { transform: scale(.995); }
4107[data-theme="dark"] .pat-row:hover {
4108 background: color-mix(in srgb, var(--paper, #fff) 10%, transparent);
4109}
4110
4111/* Leader: track-nummer OF cover-thumb (afhankelijk van kind).
4112 v9.3 — pat-leader is altijd 32×32, met overgang voor spinner-vervanging. */
4113.pat-row .pat-num,
4114.pat-row .pat-cover {
4115 width: 32px;
4116 height: 32px;
4117 border-radius: 4px;
4118 flex-shrink: 0;
4119 transition: opacity .25s ease, transform .25s ease;
4120}
4121.pat-row .pat-num {
4122 font-family: ui-monospace, monospace;
4123 font-size: .8rem;
4124 opacity: .5;
4125 display: flex;
4126 align-items: center;
4127 justify-content: center;
4128}
4129.pat-row .pat-cover {
4130 background-size: cover;
4131 background-position: center;
4132 background-color: color-mix(in srgb, var(--ink, #000) 8%, transparent);
4133}
4134
4135/* v9.3 — Loading-spiraal als overlay op de leader-kolom.
4136 pat-num/pat-cover faden uit, spinner faded in via ::before. */
4137.pat-row::before {
4138 content: "";
4139 position: absolute;
4140 left: .85rem; top: 50%;
4141 width: 32px; height: 32px;
4142 transform: translateY(-50%);
4143 color: var(--accent, #c2410c);
4144 background-color: currentColor;
4145 -webkit-mask: url('/assets/spinner.svg') center/26px 26px no-repeat;
4146 mask: url('/assets/spinner.svg') center/26px 26px no-repeat;
4147 opacity: 0;
4148 transition: opacity .25s ease;
4149 pointer-events: none;
4150 animation: pat-spinner-rotate 1.2s linear infinite;
4151 animation-play-state: paused;
4152}
4153.pat-row.is-loading::before {
4154 opacity: 1;
4155 animation-play-state: running;
4156}
4157.pat-row.is-loading .pat-num,
4158.pat-row.is-loading .pat-cover {
4159 opacity: 0;
4160 transform: scale(.85);
4161}
4162@keyframes pat-spinner-rotate {
4163 from { transform: translateY(-50%) rotate(0deg); }
4164 to { transform: translateY(-50%) rotate(-360deg); }
4165}
4166
4167/* Meta-kolom */
4168.pat-row .pat-meta {
4169 display: flex;
4170 flex-direction: column;
4171 min-width: 0;
4172 gap: 1px;
4173 overflow: hidden;
4174}
4175.pat-row .pat-title {
4176 font-weight: 500;
4177 overflow: hidden;
4178 text-overflow: ellipsis;
4179 white-space: nowrap;
4180}
4181.pat-row .pat-artist {
4182 font-size: .72rem;
4183 opacity: .6;
4184 overflow: hidden;
4185 text-overflow: ellipsis;
4186 white-space: nowrap;
4187}
4188.pat-row .pat-duration {
4189 font-family: ui-monospace, monospace;
4190 font-size: .72rem;
4191 opacity: .55;
4192 font-variant-numeric: tabular-nums;
4193 white-space: nowrap;
4194}
4195.pat-row .pat-duration-empty {
4196 opacity: .25;
4197}
4198
4199/* is-current — actieve track in de player */
4200.pat-row.is-current {
4201 background: color-mix(in srgb, var(--accent, #c2410c) 12%, transparent);
4202}
4203.pat-row.is-current .pat-title,
4204.pat-row.is-current .pat-artist { color: var(--accent, #c2410c); }
4205
4206/* v9.3 — Marquee bij actief afspelen: titel scrollt heen-en-weer.
4207 --pat-shift wordt door JS gezet (= overflow in pixels). Bij 0 → geen
4208 beweging want translateX(0) blijft 0.
4209 Snelle cyclus (6s) met korte rust aan beide uiteinden (8%) zodat 't
4210 vlot voelt zonder onleesbaar te zijn. */
4211.pat-row.is-current.is-playing .pat-title {
4212 animation: pat-title-marquee 6s ease-in-out infinite alternate;
4213 text-overflow: clip;
4214 overflow: visible;
4215 will-change: transform;
4216}
4217@keyframes pat-title-marquee {
4218 0%, 8% { transform: translateX(0); }
4219 92%, 100% { transform: translateX(calc(-1 * var(--pat-shift, 0px))); }
4220}
4221
4222/* ============================================================
4223 v9.0 — CSS-migratie voor OUDE opgeslagen albums
4224 Oude posts hebben <li class="post-audio-track"> met play-knoppen + cover-spans.
4225 We renderen die VISUEEL als compact, zonder de HTML aan te passen.
4226 ============================================================ */
4227.post-album-tracks .post-audio-track {
4228 display: grid;
4229 grid-template-columns: 28px 1fr auto;
4230 gap: .75rem;
4231 align-items: center;
4232 padding: .5rem .85rem;
4233 margin: 0;
4234 border: none;
4235 border-bottom: 1px solid var(--rule);
4236 background: transparent;
4237 border-radius: 0;
4238 cursor: default;
4239 font-size: .92rem;
4240}
4241.post-album-tracks .post-audio-track:last-child { border-bottom: none; }
4242/* Verberg de cover-thumb en play-button in OUDE saved posts */
4243.post-album-tracks .post-audio-track .pat-cover,
4244.post-album-tracks .post-audio-track .pat-play {
4245 display: none !important;
4246}
4247.post-album-tracks .post-audio-track .pat-num {
4248 font-family: ui-monospace, monospace;
4249 font-size: .8rem;
4250 opacity: .45;
4251 text-align: center;
4252 width: auto;
4253}
4254.post-album-tracks .post-audio-track .pat-meta {
4255 display: flex;
4256 flex-direction: column;
4257 min-width: 0;
4258 gap: 1px;
4259}
4260.post-album-tracks .post-audio-track .pat-title {
4261 font-weight: 500;
4262 overflow: hidden;
4263 text-overflow: ellipsis;
4264 white-space: nowrap;
4265}
4266.post-album-tracks .post-audio-track .pat-artist {
4267 font-size: .78rem;
4268 opacity: .6;
4269}
4270.post-album-tracks .post-audio-track .pat-duration {
4271 font-family: ui-monospace, monospace;
4272 font-size: .78rem;
4273 opacity: .55;
4274}
4275.post-album-tracks .post-audio-track.is-current {
4276 background: color-mix(in srgb, var(--accent, #c2410c) 10%, transparent);
4277}
4278.post-album-tracks .post-audio-track.is-current .pat-num,
4279.post-album-tracks .post-audio-track.is-current .pat-title {
4280 color: var(--accent);
4281}
4282
4283@media (max-width: 540px) {
4284 .post-album-header { flex-direction: column; }
4285 .post-album-cover-btn .post-album-cover { width: 100%; max-width: 240px; height: auto; aspect-ratio: 1/1; }
4286}
4287@media (max-width: 380px) {
4288 .post-album-header { padding: .75rem; gap: .75rem; }
4289 .post-album-cover-btn .post-album-cover { max-width: 180px; }
4290 .post-album-title { font-size: 1.15rem; }
4291 .post-album-meta { font-size: .8rem; }
4292 .post-album-track-compact,
4293 .post-album-tracks .post-audio-track {
4294 grid-template-columns: 24px 1fr auto;
4295 gap: .5rem;
4296 padding: .4rem .6rem;
4297 font-size: .85rem;
4298 }
4299 .post-album-track-compact .pat-duration,
4300 .post-album-tracks .post-audio-track .pat-duration {
4301 font-size: .72rem;
4302 }
4303 /* Queue items in expand-sheet */
4304 .audio-sheet-queue-item { padding: .4rem .45rem; gap: .55rem; }
4305 .audio-sheet-queue-cover { width: 32px; height: 32px; }
4306 .audio-sheet-queue-title { font-size: .85rem; }
4307 .audio-sheet-queue-artist { font-size: .7rem; }
4308}
4309
4310/* External track (SoundCloud / YouTube / Spotify / etc) — klikbaar maar link-naar-platform */
4311.post-audio-external {
4312 display: flex;
4313 align-items: center;
4314 gap: .75rem;
4315 padding: .65rem .85rem;
4316 background: var(--paper-2, color-mix(in srgb, var(--ink) 4%, transparent));
4317 border: 1px solid var(--rule, rgba(0,0,0,.08));
4318 border-radius: 10px;
4319 margin: .75rem 0;
4320 text-decoration: none;
4321 color: var(--ink);
4322 transition: background .15s, border-color .15s;
4323}
4324.post-audio-external:hover {
4325 border-color: var(--accent);
4326 background: color-mix(in srgb, var(--accent) 5%, var(--paper-2, transparent));
4327}
4328.post-audio-external .pae-icon {
4329 flex-shrink: 0;
4330 width: 42px;
4331 height: 42px;
4332 border-radius: 8px;
4333 display: inline-flex;
4334 align-items: center;
4335 justify-content: center;
4336 background: var(--platform-color, #555);
4337 color: #fff;
4338 font-size: 1.2rem;
4339}
4340.post-audio-external .pae-icon-svg svg {
4341 width: 60%;
4342 height: 60%;
4343 fill: currentColor;
4344}
4345/* Per-platform vult de box net wat anders — brand-specifiek geoptimaliseerd */
4346.post-audio-external[data-platform="soundcloud"] .pae-icon-svg svg { width: 72%; height: auto; }
4347.post-audio-external[data-platform="spotify"] .pae-icon-svg svg { width: 72%; height: 72%; }
4348.post-audio-external[data-platform="youtube"] .pae-icon-svg svg { width: 68%; height: auto; }
4349.post-audio-external[data-platform="bandcamp"] .pae-icon-svg svg { width: 62%; height: auto; }
4350.post-audio-external[data-platform="apple"] .pae-icon-svg svg { width: 58%; height: 58%; }
4351.post-audio-external[data-platform="tidal"] .pae-icon-svg svg { width: 68%; height: auto; }
4352.post-audio-external[data-platform="deezer"] .pae-icon-svg svg { width: 65%; height: auto; }
4353.post-audio-external[data-platform="mixcloud"] .pae-icon-svg svg { width: 75%; height: auto; }
4354.post-audio-external[data-platform="soundcloud"] .pae-icon { background: #ff5500; }
4355.post-audio-external[data-platform="spotify"] .pae-icon { background: #1db954; }
4356.post-audio-external[data-platform="youtube"] .pae-icon { background: #ff0000; }
4357.post-audio-external[data-platform="bandcamp"] .pae-icon { background: #1da0c3; }
4358.post-audio-external[data-platform="apple"] .pae-icon { background: #fa243c; }
4359.post-audio-external[data-platform="tidal"] .pae-icon { background: #000; }
4360.post-audio-external[data-platform="deezer"] .pae-icon { background: #a238ff; }
4361.post-audio-external[data-platform="mixcloud"] .pae-icon { background: #314359; }
4362.post-audio-external[data-platform="other"] .pae-icon { background: #555; }
4363.post-audio-external .pae-meta {
4364 flex: 1;
4365 min-width: 0;
4366 display: flex;
4367 flex-direction: column;
4368 gap: 2px;
4369}
4370.post-audio-external .pae-title {
4371 display: block;
4372 font-weight: 600;
4373 overflow: hidden;
4374 text-overflow: ellipsis;
4375 white-space: nowrap;
4376 color: var(--ink);
4377}
4378.post-audio-external .pae-platform {
4379 display: block;
4380 font-size: .78rem;
4381 opacity: .65;
4382 text-transform: capitalize;
4383}
4384.post-audio-external .pae-go {
4385 flex-shrink: 0;
4386 opacity: .5;
4387 font-size: 1.1rem;
4388}
4389
4390/* =========================================================================
4391 v9.0 — Video player (inline)
4392 ========================================================================= */
4393
4394.post-video-figure {
4395 margin: 1.25rem 0;
4396 max-width: 100%;
4397}
4398
4399.post-video {
4400 display: block;
4401 width: 100%;
4402 max-width: 100%;
4403 height: auto;
4404 border-radius: 10px;
4405 background: #000;
4406 box-shadow: 0 4px 20px rgba(0,0,0,.15);
4407}
4408
4409.post-video-caption {
4410 margin-top: .5rem;
4411 font-size: .88rem;
4412 color: var(--ink-muted, color-mix(in srgb, var(--ink) 60%, transparent));
4413 text-align: center;
4414 line-height: 1.5;
4415}
4416
4417.post-video-caption strong {
4418 display: inline;
4419 font-weight: 600;
4420 color: var(--ink);
4421}
4422
4423@media (max-width: 640px) {
4424 .post-video-figure { margin: .75rem -.5rem; }
4425 .post-video { border-radius: 6px; }
4426}
4427
4428/* v9.3 — Floating "Bewerken" knop voor album-blokken in de post-editor.
4429 Verschijnt bij hover over een .post-album binnen #visual en wordt via JS
4430 geplaatst op de rechterbovenhoek van het blok. Niet in de opgeslagen HTML. */
4431.pcms-album-edit-overlay {
4432 position: absolute;
4433 z-index: 1000;
4434 transform: translateX(-100%);
4435 display: inline-flex;
4436 align-items: center;
4437 gap: .35rem;
4438 padding: .35rem .7rem;
4439 background: var(--accent, #c2410c);
4440 color: #fff;
4441 border: none;
4442 border-radius: 6px;
4443 font-size: .82rem;
4444 font-weight: 600;
4445 cursor: pointer;
4446 box-shadow: 0 4px 12px rgba(0, 0, 0, .18);
4447 transition: transform .12s ease, box-shadow .12s ease;
4448}
4449.pcms-album-edit-overlay:hover {
4450 transform: translateX(-100%) translateY(-1px);
4451 box-shadow: 0 6px 16px rgba(0, 0, 0, .24);
4452}
4453.pcms-album-edit-overlay:active {
4454 transform: translateX(-100%) translateY(0);
4455 box-shadow: 0 2px 6px rgba(0, 0, 0, .18);
4456}
4457
4458/* v9.3 — Drag-and-drop in de album-builder selected-lijst */
4459.ab-selected-row { cursor: default; }
4460.ab-selected-row .ab-drag-handle {
4461 display: inline-flex;
4462 align-items: center;
4463 justify-content: center;
4464 width: 18px;
4465 height: 100%;
4466 color: color-mix(in srgb, currentColor 40%, transparent);
4467 cursor: grab;
4468 user-select: none;
4469 font-size: .9rem;
4470 letter-spacing: -2px;
4471 flex-shrink: 0;
4472}
4473.ab-selected-row:hover .ab-drag-handle {
4474 color: color-mix(in srgb, currentColor 70%, transparent);
4475}
4476.ab-selected-row.is-dragging {
4477 opacity: .35;
4478 cursor: grabbing;
4479}
4480.ab-selected-row.is-dragging .ab-drag-handle { cursor: grabbing; }
4481/* Drop-indicator lijnen boven/onder de target rij */
4482.ab-selected-row.is-drag-target-before {
4483 box-shadow: 0 -2px 0 0 var(--accent, #c2410c) inset, 0 2px 0 0 var(--accent, #c2410c);
4484 /* Gebruik outline voor cross-browser zichtbaarheid */
4485 position: relative;
4486}
4487.ab-selected-row.is-drag-target-before::before {
4488 content: "";
4489 position: absolute;
4490 top: -1px; left: 0; right: 0;
4491 height: 2px;
4492 background: var(--accent, #c2410c);
4493 pointer-events: none;
4494}
4495.ab-selected-row.is-drag-target-after::after {
4496 content: "";
4497 position: absolute;
4498 bottom: -1px; left: 0; right: 0;
4499 height: 2px;
4500 background: var(--accent, #c2410c);
4501 pointer-events: none;
4502}
4503.ab-selected-row.is-drag-target-after { position: relative; }
4504
4505/* v9.3 — Playlist fallback states (missing of empty playlist reference in post) */
4506.post-playlist-missing, .post-playlist-empty {
4507 padding: 1rem;
4508 margin: .75rem 0;
4509 background: color-mix(in srgb, var(--accent, #c2410c) 8%, transparent);
4510 border: 1px dashed color-mix(in srgb, var(--accent, #c2410c) 30%, transparent);
4511 border-radius: 8px;
4512 font-size: .9rem;
4513}
4514.post-playlist-missing em, .post-playlist-empty em {
4515 opacity: .8;
4516}
4517
4518/* v9.3 — Install-app footer-knop */
4519.site-footer-install {
4520 display: flex;
4521 justify-content: center;
4522 padding: 1rem 1rem 1.25rem;
4523 border-top: 1px solid color-mix(in srgb, currentColor 8%, transparent);
4524 margin-top: .5rem;
4525}
4526
4527/* v9.4 — Cooler install-knop: gradient + shimmer + perfect centering.
4528 Twee kleur-stops voor diepte, animated shimmer-streep om aandacht te trekken,
4529 icon perfect verticaal gecentreerd via flex (was: net iets te hoog tov tekst). */
4530.install-app-btn {
4531 position: relative;
4532 display: inline-flex;
4533 align-items: center;
4534 justify-content: center;
4535 gap: .55rem;
4536 padding: .8rem 1.6rem;
4537 background: linear-gradient(135deg,
4538 var(--accent, #c2410c),
4539 color-mix(in srgb, var(--accent, #c2410c) 80%, #000));
4540 color: #fff;
4541 border: none;
4542 border-radius: 999px;
4543 font: inherit;
4544 font-weight: 600;
4545 font-size: .95rem;
4546 line-height: 1;
4547 letter-spacing: .01em;
4548 cursor: pointer;
4549 overflow: hidden;
4550 isolation: isolate;
4551 box-shadow:
4552 0 1px 0 rgba(255,255,255,.15) inset,
4553 0 -2px 0 rgba(0,0,0,.1) inset,
4554 0 4px 14px color-mix(in srgb, var(--accent, #c2410c) 40%, transparent),
4555 0 1px 3px rgba(0,0,0,.18);
4556 transition:
4557 transform .15s cubic-bezier(.4, 0, .2, 1),
4558 box-shadow .2s ease,
4559 filter .15s ease;
4560}
4561.install-app-btn svg {
4562 flex-shrink: 0;
4563 /* subtle bounce-on-hover trigger, separate animation */
4564 transition: transform .25s cubic-bezier(.34, 1.56, .64, 1);
4565}
4566.install-app-btn span {
4567 line-height: 1;
4568}
4569
4570/* Shimmer-streep die langzaam over de knop loopt — "alive" effect */
4571.install-app-btn::before {
4572 content: "";
4573 position: absolute;
4574 top: 0;
4575 left: -100%;
4576 width: 60%;
4577 height: 100%;
4578 background: linear-gradient(110deg,
4579 transparent 30%,
4580 rgba(255,255,255,.25) 50%,
4581 transparent 70%);
4582 z-index: -1;
4583 animation: pcmsInstallShimmer 4s ease-in-out infinite;
4584 pointer-events: none;
4585}
4586@keyframes pcmsInstallShimmer {
4587 0%, 35% { left: -100%; }
4588 65%, 100% { left: 200%; }
4589}
4590
4591.install-app-btn:hover {
4592 transform: translateY(-2px) scale(1.02);
4593 filter: brightness(1.06);
4594 box-shadow:
4595 0 1px 0 rgba(255,255,255,.2) inset,
4596 0 -2px 0 rgba(0,0,0,.1) inset,
4597 0 8px 24px color-mix(in srgb, var(--accent, #c2410c) 55%, transparent),
4598 0 2px 6px rgba(0,0,0,.2);
4599}
4600.install-app-btn:hover svg {
4601 transform: translateY(-2px);
4602}
4603.install-app-btn:active {
4604 transform: translateY(0) scale(.98);
4605 transition-duration: .05s;
4606}
4607.install-app-btn:focus-visible {
4608 outline: 2px solid var(--accent, #c2410c);
4609 outline-offset: 3px;
4610}
4611
4612/* Reduced motion: shimmer uit, alleen statisch */
4613@media (prefers-reduced-motion: reduce) {
4614 .install-app-btn::before { animation: none; left: -100%; }
4615 .install-app-btn:hover { transform: none; }
4616 .install-app-btn:hover svg { transform: none; }
4617}
4618
4619/* Install-instructions modal */
4620.install-modal {
4621 position: fixed;
4622 inset: 0;
4623 z-index: 10000;
4624 display: flex;
4625 align-items: center;
4626 justify-content: center;
4627 padding: 1rem;
4628}
4629.install-modal-backdrop {
4630 position: absolute;
4631 inset: 0;
4632 background: rgba(0,0,0,.55);
4633 backdrop-filter: blur(3px);
4634}
4635.install-modal-panel {
4636 position: relative;
4637 z-index: 1;
4638 background: var(--paper);
4639 color: var(--ink);
4640 border: 1px solid var(--rule);
4641 border-radius: 14px;
4642 padding: 1.5rem;
4643 max-width: 440px;
4644 width: 100%;
4645 max-height: 90vh;
4646 overflow-y: auto;
4647 box-shadow: 0 20px 60px rgba(0,0,0,.4);
4648}
4649.install-modal-panel h3 { font-size: 1.15rem; color: var(--ink); }
4650.install-modal-panel h4 {
4651 margin: 1rem 0 .4rem;
4652 font-size: .92rem;
4653 letter-spacing: .03em;
4654 text-transform: uppercase;
4655 opacity: .7;
4656 color: var(--ink);
4657}
4658.install-modal-panel p { color: var(--ink); }
4659.install-steps {
4660 margin: 0;
4661 padding-left: 1.35rem;
4662 display: flex;
4663 flex-direction: column;
4664 gap: .45rem;
4665 font-size: .95rem;
4666 line-height: 1.45;
4667 color: var(--ink);
4668}
4669.install-steps li::marker { color: var(--accent); font-weight: 700; }
4670.install-apk-block {
4671 margin-top: 1.25rem;
4672 padding-top: 1rem;
4673 border-top: 1px dashed var(--rule);
4674}
4675.install-apk-link {
4676 display: inline-flex;
4677 align-items: center;
4678 margin-top: .4rem;
4679 padding: .6rem 1rem;
4680 background: var(--accent);
4681 color: #fff;
4682 border-radius: 8px;
4683 text-decoration: none;
4684 font-weight: 600;
4685}
4686.install-apk-link:hover { filter: brightness(1.08); }
4687.install-modal-actions {
4688 display: flex;
4689 justify-content: flex-end;
4690 margin-top: 1.25rem;
4691}
4692.install-modal-actions .btn {
4693 padding: .5rem 1rem;
4694 background: var(--paper-2);
4695 border: 1px solid var(--rule);
4696 border-radius: 8px;
4697 color: var(--ink);
4698 cursor: pointer;
4699 font: inherit;
4700 font-weight: 500;
4701}
4702.install-modal-actions .btn:hover {
4703 background: color-mix(in srgb, var(--accent) 10%, var(--paper-2));
4704 border-color: var(--accent);
4705 color: var(--accent);
4706}
4707
4708@media (max-width: 520px) {
4709 .install-modal-panel { padding: 1.2rem; }
4710 .install-app-btn { width: 100%; justify-content: center; }
4711}
4712
4713/* v9.3 — Install-modal: choice-blocks met voor/nadelen */
4714.install-choice {
4715 margin-top: 1.25rem;
4716 padding: 1rem;
4717 border: 1px solid color-mix(in srgb, currentColor 15%, transparent);
4718 border-radius: 10px;
4719 background: color-mix(in srgb, currentColor 3%, transparent);
4720}
4721.install-choice + .install-choice { margin-top: 1rem; }
4722.install-choice h4 {
4723 margin: 0 0 .75rem;
4724 font-size: 1rem;
4725 letter-spacing: 0;
4726 text-transform: none;
4727 opacity: 1;
4728}
4729.install-pros-cons {
4730 display: flex;
4731 gap: 1rem;
4732 margin: .5rem 0 1rem;
4733}
4734.install-pros,
4735.install-cons {
4736 flex: 1;
4737 min-width: 0;
4738 font-size: .85rem;
4739 line-height: 1.45;
4740}
4741.install-pros strong,
4742.install-cons strong {
4743 display: block;
4744 margin-bottom: .35rem;
4745 font-size: .82rem;
4746 letter-spacing: .02em;
4747}
4748.install-pros strong { color: #16a34a; }
4749.install-cons strong { color: #dc2626; }
4750.install-pros ul,
4751.install-cons ul {
4752 margin: 0;
4753 padding-left: 1.1rem;
4754 display: flex;
4755 flex-direction: column;
4756 gap: .25rem;
4757}
4758.install-pros li::marker { color: #16a34a; }
4759.install-cons li::marker { color: #dc2626; }
4760
4761.install-choice-cta {
4762 display: inline-flex;
4763 align-items: center;
4764 justify-content: center;
4765 gap: .35rem;
4766 margin-top: .5rem;
4767 padding: .7rem 1.1rem;
4768 background: var(--accent, #c2410c);
4769 color: #fff;
4770 border: none;
4771 border-radius: 8px;
4772 text-decoration: none;
4773 font: inherit;
4774 font-weight: 600;
4775 font-size: .95rem;
4776 cursor: pointer;
4777 transition: filter .12s ease;
4778}
4779.install-choice-cta:hover { filter: brightness(1.08); }
4780.install-choice-note {
4781 margin: .5rem 0 0;
4782 padding: .6rem .8rem;
4783 background: color-mix(in srgb, currentColor 4%, transparent);
4784 border-left: 3px solid var(--accent, #c2410c);
4785 border-radius: 4px;
4786 font-size: .9rem;
4787 line-height: 1.45;
4788}
4789
4790@media (max-width: 520px) {
4791 .install-pros-cons { flex-direction: column; gap: .75rem; }
4792}
4793
4794/* v9.4 — Soft fade-overgang tussen posts bij navigatie.
4795 Fade-out is rustig (450ms): oude content vervaagt geleidelijk terwijl
4796 de scroll-naar-top loopt. Fade-in is snel (180ms) met een lichte blur-
4797 onscherp → scherp animatie zodat de nieuwe content niet abrupt verschijnt. */
4798#pcms-main {
4799 transition: opacity .45s ease-out;
4800}
4801#pcms-main.is-pcms-transitioning-out {
4802 opacity: 0;
4803}
4804#pcms-main.is-pcms-transitioning-in {
4805 opacity: 0;
4806 filter: blur(6px);
4807 animation: pcmsFadeIn .18s ease-out forwards;
4808 will-change: opacity, filter;
4809}
4810@keyframes pcmsFadeIn {
4811 from { opacity: 0; filter: blur(6px); }
4812 to { opacity: 1; filter: blur(0); }
4813}
4814
4815/* Respecteer reduced-motion voorkeur (iOS/Android accessibility setting) */
4816@media (prefers-reduced-motion: reduce) {
4817 #pcms-main {
4818 transition: opacity .15s ease-out;
4819 }
4820 #pcms-main.is-pcms-transitioning-in {
4821 filter: none;
4822 animation: none;
4823 opacity: 1;
4824 }
4825}
[c16e0a5]4826
[3a2c9d3]4827/* === Fediverse interactions — inherits the native .comment styling === */
[848b76d]4828.post-fediverse .fedi-stats { display: flex; gap: .45rem; margin: .35rem 0 1.5rem; align-items: center; }
4829.post-fediverse .fedi-stat {
4830 display: inline-flex; align-items: center; gap: .4rem;
4831 padding: .32rem .7rem; border-radius: 999px; font-size: .85rem; line-height: 1;
4832 font-variant-numeric: tabular-nums;
4833 color: var(--ink-muted); background: transparent;
4834 border: 1px solid var(--rule);
4835}
4836.post-fediverse .fedi-stat svg { width: 15px; height: 15px; }
4837.post-fediverse .fedi-stat-btn { cursor: pointer; font: inherit; line-height: 1; transition: color .15s, border-color .15s, background .15s; }
4838.post-fediverse .fedi-stat-btn:hover { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 55%, var(--rule)); background: var(--accent-tint); }
4839.post-fediverse .fedi-stat-btn:hover svg { fill: color-mix(in srgb, var(--accent) 22%, transparent); }
[3a2c9d3]4840.post-fediverse .fedi-handle { color: var(--ink-soft, #888); font-size: .82rem; }
4841.post-fediverse .comment-content p { margin: .2rem 0; }
4842.post-fediverse .comment-content p:first-child { margin-top: 0; }
4843.post-fediverse .comment-content p:last-child { margin-bottom: 0; }
4844/* reply toggle: a plain "Reageer" action like the comment buttons (no triangle) */
4845.post-fediverse .fedi-reply-toggle { list-style: none; cursor: pointer; display: inline-block; }
4846.post-fediverse .fedi-reply-toggle::-webkit-details-marker { display: none; }
4847.post-fediverse details[open] .fedi-reply-toggle { margin-bottom: .5rem; }
[3d7312a]4848
4849/* Reply-via-fediverse CTA on post pages */
[0dba092]4850.post-fediverse-cta { margin: 1.75rem 0; }
[7f46112b]4851.fedi-remote-reply-btn { display: inline-flex; align-items: center; gap: .45rem; }
4852.post-fediverse-cta .fedi-remote-reply-btn {
4853 border: 1px solid color-mix(in srgb, var(--accent, #888) 55%, transparent);
4854 background: color-mix(in srgb, var(--accent, #888) 10%, transparent);
4855 color: var(--ink, inherit); border-radius: 999px; padding: .5rem 1.05rem;
4856 font-weight: 600; cursor: pointer; transition: background .15s ease;
4857}
4858.post-fediverse-cta .fedi-remote-reply-btn:hover { background: color-mix(in srgb, var(--accent, #888) 22%, transparent); }
4859.post-fediverse-cta .fedi-remote-reply-btn svg { color: var(--accent, currentColor); }
4860.post-fediverse .comment-actions .fedi-remote-reply-btn { gap: .3rem; }
[40cf2ef]4861
4862/* Inline "reply via fediverse" address form (replaces the browser prompt) */
[0dba092]4863.fedi-remote-form {
4864 position: absolute; z-index: 60; display: inline-flex; align-items: center; gap: .4rem;
4865 padding: .4rem; border-radius: 999px;
4866 background: var(--paper-2, var(--paper, #fff));
4867 border: 1px solid color-mix(in srgb, var(--ink, #000) 12%, transparent);
4868 box-shadow: 0 10px 30px rgba(0,0,0,.28);
4869}
[40cf2ef]4870.fedi-remote-form input {
[c901131]4871 height: 2.2rem; padding: 0 .9rem; border-radius: 999px; font: inherit; min-width: 230px;
4872 border: 1px solid color-mix(in srgb, var(--ink, #000) 18%, transparent);
4873 background: color-mix(in srgb, var(--ink, #000) 4%, transparent); color: var(--ink, #000);
[40cf2ef]4874}
[c901131]4875.fedi-remote-form input::placeholder { color: var(--ink-soft, #999); }
4876.fedi-remote-form input:focus { outline: none; border-color: color-mix(in srgb, var(--accent, #888) 70%, transparent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent, #888) 22%, transparent); }
4877.fedi-remote-form .fedi-remote-go {
4878 height: 2.2rem; min-width: 2.2rem; padding: 0 .85rem; border-radius: 999px;
4879 display: inline-flex; align-items: center; justify-content: center; font-size: 1rem;
4880}
4881.fedi-remote-form .fedi-remote-cancel { background: none; border: none; color: var(--ink-soft, #888); cursor: pointer; font-size: 1.1rem; line-height: 1; padding: .25rem .35rem; }
[40cf2ef]4882.fedi-remote-form .fedi-remote-cancel:hover { color: var(--ink, #000); }
[837fc9c]4883
4884/* ── NSFW / sensitive content — blur + click to reveal ───────────────── */
4885.nsfw-media { position: relative; }
4886.nsfw-veil {
4887 position: absolute; inset: 0; z-index: 4; cursor: pointer; border-radius: inherit;
4888 display: flex; flex-direction: column; align-items: center; justify-content: center;
4889 gap: .5rem; padding: .75rem; text-align: center;
4890 background: color-mix(in srgb, var(--paper, #14141a) 50%, transparent);
4891 backdrop-filter: blur(22px) saturate(.6); -webkit-backdrop-filter: blur(22px) saturate(.6);
4892}
4893.nsfw-media.is-shown > .nsfw-veil { display: none; }
4894.nsfw-veil-label { font-weight: 700; font-size: .82rem; color: var(--ink, #f3f1ea); text-shadow: 0 1px 2px rgba(0,0,0,.5); }
4895.nsfw-veil-btn {
4896 font-size: .72rem; font-weight: 600; padding: .3rem .8rem; border-radius: 999px;
4897 border: 1px solid color-mix(in srgb, var(--ink, #fff) 55%, transparent);
4898 background: color-mix(in srgb, var(--paper, #000) 35%, transparent); color: var(--ink, #f3f1ea);
4899}
4900/* Post page: blur cover + body behind a content-warning banner until revealed */
4901.nsfw-gate .post-cover,
4902.nsfw-gate .post-content { filter: blur(26px); pointer-events: none; user-select: none; transition: filter .2s ease; }
4903.nsfw-gate.is-shown .post-cover,
4904.nsfw-gate.is-shown .post-content { filter: none; pointer-events: auto; user-select: auto; }
4905.nsfw-banner {
4906 display: flex; align-items: center; gap: .7rem; flex-wrap: wrap; margin: 0 0 1.5rem;
4907 padding: .8rem 1rem; border-radius: 12px;
4908 border: 1px solid color-mix(in srgb, var(--accent, #e8b04b) 45%, transparent);
4909 background: color-mix(in srgb, var(--accent, #e8b04b) 9%, transparent);
4910}
4911.nsfw-gate.is-shown .nsfw-banner { display: none; }
4912.nsfw-banner-icon { font-size: 1.2rem; }
4913.nsfw-banner-text { font-weight: 600; font-size: .92rem; color: var(--ink); }
4914.nsfw-banner-btn {
4915 margin-left: auto; cursor: pointer; font: inherit; font-size: .82rem; font-weight: 600;
4916 padding: .4rem 1rem; border-radius: 999px; border: 0;
4917 background: var(--accent, #e8b04b); color: #1a1205;
4918}
Note: See TracBrowser for help on using the repository browser.