source: Klonkt/src/assets/css/style.css@ 520c993

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

Lezen: elk bericht een eigen scherm wordt een keuze

Robins vraag (20-8): de lege ruimtes tussen berichten optioneel maken, en
specifiek voor Lezen.

Nieuwe kolom reader_full_page op sites, standaard UIT zodat bestaande
sites niet ineens anders lezen:

uit bericht na bericht, geen lege ruimte eronder
aan elk bericht vult minstens een scherm (min-height:100svh)

Dit stond eerst vast op AAN, is op 20-8 vast op UIT gezet omdat een kort
bericht een halve pagina leegte gaf onder "Replies and reactions", en hoort
dus eigenlijk bij de schrijver: lange stukken lezen prettiger in de stroom,
korte losse berichten juist als eigen scherm.

De keuze staat in Beheer -> Instellingen bij de andere feed-keuzes, en gaat
via een attribuut op body zodat CSS het werk doet.

OVER DE SQL, want daar ging het deze week twee keer mis: deze wijziging
voegt een kolom toe aan dezelfde UPDATE waar ik eerder een kolom zonder
waarde in zette, waarna show_search de waarde van zijn buurman kreeg en
alles erna een plek opschoof. De tests gaan daarom door de ECHTE route en
toetsen expliciet de buurkolommen. Controleproef gedaan: laat je de waarde
weg, dan vallen 6 van de 8 tests om.

style.css naar v83, MOD_V naar 21.

Suite 1172/1172.

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

  • Property mode set to 100644
File size: 164.4 KB
Line 
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
56/* Klonkt publieke stijl — editorial-ish, geen emoji-UI */
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);
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);
68 color-scheme: light dark;
69}
70
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
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
114/* ── KLONKT ── merk-standaard: clean wit → bijna-zwart (neutraal, gouden accent) ── */
115[data-palette="klonkt"] {
116 --paper: #ffffff; --paper-2: #f4f4f5;
117 --ink: #09090b; --ink-soft: #27272a; --ink-muted: #52525b; --ink-faint: #a1a1aa;
118 --rule: #e4e4e7; --rule-2: #d4d4d8;
119}
120@media (prefers-color-scheme: dark) {
121 [data-palette="klonkt"]:not([data-theme="light"]) {
122 --paper: #0a0a0a; --paper-2: #18181b;
123 --ink: #fafafa; --ink-soft: #d4d4d8; --ink-muted: #a1a1aa; --ink-faint: #71717a;
124 --rule: #27272a; --rule-2: #3f3f46;
125 }
126}
127[data-theme="dark"][data-palette="klonkt"] {
128 --paper: #0a0a0a; --paper-2: #18181b;
129 --ink: #fafafa; --ink-soft: #d4d4d8; --ink-muted: #a1a1aa; --ink-faint: #71717a;
130 --rule: #27272a; --rule-2: #3f3f46;
131}
132
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
229/* ── SAND ── warm papier (subtiel, niet fel geel) → warm donker ── (key blijft 'cream') */
230[data-palette="cream"] {
231 --paper: #f7f3ec; --paper-2: #ece5d8;
232 --ink: #232019; --ink-soft: #43392c; --ink-muted: #6f6149; --ink-faint: #a3957c;
233 --rule: #ddd3c0; --rule-2: #c9bca3;
234}
235@media (prefers-color-scheme: dark) {
236 [data-palette="cream"]:not([data-theme="light"]) {
237 --paper: #14120d; --paper-2: #221e15;
238 --ink: #efe9dd; --ink-soft: #d0c6b2; --ink-muted: #a3957c; --ink-faint: #6f6149;
239 --rule: #322c20; --rule-2: #463d2c;
240 }
241}
242[data-theme="dark"][data-palette="cream"] {
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
248/* ── OCEAN ── helder blauw → diep oceaanblauw ── */
249[data-palette="ocean"] {
250 --paper: #eef4fb; --paper-2: #d8e6f7;
251 --ink: #0f2942; --ink-soft: #1d4368; --ink-muted: #4a6e90; --ink-faint: #87a3c0;
252 --rule: #c2d8ee; --rule-2: #a3c2e0;
253}
254@media (prefers-color-scheme: dark) {
255 [data-palette="ocean"]:not([data-theme="light"]) {
256 --paper: #081726; --paper-2: #102a42;
257 --ink: #d6e8fb; --ink-soft: #aecbe8; --ink-muted: #7e9fc0; --ink-faint: #547390;
258 --rule: #1d3a56; --rule-2: #2a4d6e;
259 }
260}
261[data-theme="dark"][data-palette="ocean"] {
262 --paper: #081726; --paper-2: #102a42;
263 --ink: #d6e8fb; --ink-soft: #aecbe8; --ink-muted: #7e9fc0; --ink-faint: #547390;
264 --rule: #1d3a56; --rule-2: #2a4d6e;
265}
266
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 ── */
287[data-palette="candy"] {
288 --paper: #fdf1f3; --paper-2: #f8d8de;
289 --ink: #3a1018; --ink-soft: #5e1f2a; --ink-muted: #8e4450; --ink-faint: #c2868f;
290 --rule: #f0c5cd; --rule-2: #e3a0ab;
291}
292@media (prefers-color-scheme: dark) {
293 [data-palette="candy"]:not([data-theme="light"]) {
294 --paper: #220810; --paper-2: #3a121d;
295 --ink: #fde0e6; --ink-soft: #f5b8c4; --ink-muted: #cd8b98; --ink-faint: #8e5f6a;
296 --rule: #4d1a28; --rule-2: #632536;
297 }
298}
299[data-theme="dark"][data-palette="candy"] {
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;
322}
323
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
344/* ── TERRACOTTA ── warme klei → diep brick ── (key blijft 'mint' voor DB-compat) */
345[data-palette="mint"] {
346 --paper: #faf2ee; --paper-2: #f2ddd0;
347 --ink: #2e1a12; --ink-soft: #4a2c1e; --ink-muted: #7a5544; --ink-faint: #b3917e;
348 --rule: #eccdbb; --rule-2: #ddb49d;
349}
350@media (prefers-color-scheme: dark) {
351 [data-palette="mint"]:not([data-theme="light"]) {
352 --paper: #1f120c; --paper-2: #2e1c13;
353 --ink: #f7e6da; --ink-soft: #e0c3b0; --ink-muted: #b3917c; --ink-faint: #7a5544;
354 --rule: #4a2c1e; --rule-2: #5e3a28;
355 }
356}
357[data-theme="dark"][data-palette="mint"] {
358 --paper: #1f120c; --paper-2: #2e1c13;
359 --ink: #f7e6da; --ink-soft: #e0c3b0; --ink-muted: #b3917c; --ink-faint: #7a5544;
360 --rule: #4a2c1e; --rule-2: #5e3a28;
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
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; }
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}
396body {
397 margin: 0;
398}
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; }
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; }
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;
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%);
444}
445/* Klonkt-palet gebruikt nu (net als de andere paletten) de generieke accent-glow
446 hierboven → de achtergrond-gradient volgt de gekozen accentkleur. */
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); }
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; }
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
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; }
482
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);
512 padding: calc(1rem + var(--ios-safe-top, 0px)) 0 1rem;
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);
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; }
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); }
581.empty h1 { font-size: 2rem; }
582.empty p { color: var(--ink-muted); }
583
584/* Embeds */
585.pcms-embed, .folio-embed { margin: 2rem 0; }
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); }
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 */
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); }
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%;
723 height: auto; /* volledige (niet-bijgesneden) hoogte */
724 /* geen max-height/object-fit: cover meer → de hele afbeelding toont,
725 volle containerbreedte, zijkanten gerespecteerd. */
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
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
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
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
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
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
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
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
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. */
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;
1664 padding-top: calc(.75rem + var(--ios-safe-top, 0px));
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}
1688
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}
1721@media (max-width: 400px) {
1722 .masthead { padding: calc(.5rem + var(--ios-safe-top, 0px)) 0 .5rem; }
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);
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%);
1977}
1978.post-list-cover img, .post-list-cover video {
1979 width: 100%; height: 100%;
1980 object-fit: cover; /* fill the square, keep aspect, crop the overflow, centered */
1981 object-position: center;
1982 display: block;
1983 background-color: #fff; /* transparent logos sit on white once loaded */
1984 transition: opacity .4s ease;
1985}
1986.post-list-cover img.is-loading { opacity: 0; }
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; }
2256.profile-links a,
2257.profile-links .profile-fedi-link {
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}
2269.profile-links a:hover,
2270.profile-links .profile-fedi-link:hover {
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);
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. */
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}
2355.view-switch-btn {
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}
2370.view-switch-btn:hover {
2371 color: var(--ink);
2372 border-color: var(--ink-muted);
2373}
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}
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). */
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. */
2390.view-switch-btn .icon { width: 1rem; height: 1rem; }
2391
2392/* -------- FEED TOGGLE VIA BODY --------
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
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,
2402body.on-cirkel[data-feed-view="grid"] .feed-timeline {
2403 display: none !important;
2404}
2405/* Grid-sectie alleen zichtbaar op de feed in grid-mode (NIET op archief) */
2406.feed-grid { display: none; }
2407body.on-home[data-feed-view="grid"] .feed-grid,
2408body.on-cirkel[data-feed-view="grid"] .feed-grid { display: block; }
2409
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
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
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. */
2462html:has(body.on-home[data-feed-view="reader"]) {
2463 scroll-snap-type: y proximity;
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. */
2470}
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 {
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. */
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;
2498 scroll-snap-stop: normal;
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. */
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}
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
2551/* ELK BERICHT EEN EIGEN SCHERM, als de site dat wil (Instellingen -> Weergave).
2552 Aan: een kort bericht vult het scherm en je ziet het volgende pas na een snap.
2553 Uit (standaard): de stroom is bericht na bericht, zonder lege ruimte eronder.
2554 Dit stond eerst vast op AAN, is toen vast op UIT gezet omdat een kort bericht
2555 een halve pagina leegte gaf onder "Replies and reactions", en is nu een keuze
2556 -- want welke van de twee prettiger leest hangt af van wat je schrijft. */
2557body[data-reader-pages="1"] .feed-reader .read-post { min-height: 100svh; }
2558
2559/* Een lijn tussen twee berichten: zonder grens is een stroom een lange brij. */
2560.feed-reader .read-post + .read-post { border-top: 1px solid color-mix(in srgb, currentColor 12%, transparent); }
2561
2562/* De cover vult de leeskolom. Eigen regel, niet .post-cover hergebruikt: die
2563 heeft een marge van 2rem die hier tegen de scroll-snap aan duwt.
2564 De hoogtebegrenzing is er met opzet. Een paneel is min-height:100svh en snapt,
2565 dus een staande foto op volle breedte zou de titel en de eerste alinea onder
2566 de vouw duwen -- dan begint elk bericht met een plaat waar je langs moet
2567 scrollen om te zien wat het IS. */
2568.feed-reader .read-cover {
2569 /* Volle kolombreedte: de afbeelding erin neemt die breedte, dus de figure
2570 hoeft niet meer om het beeld te krimpen. */
2571 width: 100%;
2572 margin: 0 0 1.2rem;
2573 border-radius: 10px;
2574 overflow: hidden;
2575}
2576.feed-reader .read-cover img,
2577.feed-reader .read-cover video {
2578 display: block;
2579 /* Neemt de VOLLE kolombreedte, met de verhouding intact (object-fit
2580 weggelaten, dus geen bijsnijden). Een cover die van zichzelf kleiner is
2581 wordt netjes tot de kolom opgeschaald in plaats van als postzegeltje te
2582 blijven staan -- dat was te klein. De hoogtegrens houdt een staande foto
2583 nog binnen de perken zodat titel + eerste alinea boven de vouw blijven;
2584 hij krimpt dan mee in plaats van bijgesneden te worden. */
2585 display: block;
2586 width: 100%;
2587 height: auto;
2588 max-height: 70svh;
2589 object-fit: contain;
2590 /* Een logo met doorzichtige achtergrond zweeft anders op de paginakleur;
2591 dezelfde keuze als bij .post-list-cover in de tijdlijn. */
2592 background-color: #fff;
2593}
2594
2595.feed-reader .read-head { padding-bottom: .5rem; }
2596.feed-reader .read-title { font-size: clamp(1.6rem, 4vw, 2.4rem); line-height: 1.15; margin: 0 0 .3rem; }
2597/* Het pin-icoon voor de titel: meeschalend met de kop, maar duidelijk kleiner --
2598 het is een markering en geen deel van de titel. */
2599.feed-reader .read-pin {
2600 display: inline-block;
2601 vertical-align: baseline;
2602 width: .62em; height: .62em;
2603 margin-right: .35em;
2604 color: var(--ink-muted);
2605}
2606.feed-reader .read-pin svg { width: 100%; height: 100%; display: block; }
2607/* De titel is een link, maar mag er niet als een link uitzien: dit is een
2608 leesscherm, geen index. */
2609.feed-reader .read-title a { color: inherit; text-decoration: none; }
2610.feed-reader .read-title a:hover,
2611.feed-reader .read-title a:focus-visible { text-decoration: underline; }
2612.feed-reader .read-when { font-size: .85rem; opacity: .6; margin: 0; }
2613
2614.feed-reader .read-foot { margin-top: 2rem; }
2615.feed-reader .read-open {
2616 display: inline-block; font-size: .9rem; opacity: .75;
2617 text-decoration: none; border-bottom: 1px solid currentColor; padding-bottom: 1px;
2618}
2619.feed-reader .read-open:hover,
2620.feed-reader .read-open:focus-visible { opacity: 1; }
2621
2622/* Terug naar boven. Rechtsonder, want daar zit de duim -- en boven de tabbalk,
2623 die op mobiel 1050 is en anders overheen zou vallen. Onzichtbaar tot je ver
2624 genoeg bent, zodat hij niet meteen in de weg staat bij het eerste bericht. */
2625.read-top {
2626 position: fixed;
2627 right: max(1rem, env(safe-area-inset-right, 0));
2628 bottom: calc(env(safe-area-inset-bottom, 0) + 4.75rem);
2629 z-index: 1040;
2630 display: grid;
2631 place-items: center;
2632 width: 44px;
2633 height: 44px; /* 44px = de kleinste maat die een duim betrouwbaar raakt */
2634 border-radius: 999px;
2635 border: 1px solid var(--rule);
2636 background: color-mix(in srgb, var(--paper) 88%, transparent);
2637 backdrop-filter: blur(14px) saturate(140%);
2638 -webkit-backdrop-filter: blur(14px) saturate(140%);
2639 color: var(--ink);
2640 box-shadow: 0 2px 12px color-mix(in srgb, var(--ink) 12%, transparent);
2641 cursor: pointer;
2642 opacity: 0;
2643 pointer-events: none;
2644 transition: opacity .18s ease, transform .18s ease;
2645 transform: translateY(6px);
2646}
2647.read-top.is-zichtbaar { opacity: 1; pointer-events: auto; transform: none; }
2648/* Buiten de leesweergave bestaat hij niet -- home.ejs rendert alle drie de
2649 secties, dus zonder deze regel zweeft hij ook boven Tijdlijn en Grid. */
2650body:not([data-feed-view="reader"]) .read-top,
2651body:not(.on-home) .read-top { display: none; }
2652/* Op desktop is er geen tabbalk, dus mag hij lager staan. */
2653@media (min-width: 768px) {
2654 .read-top { bottom: 1.5rem; right: 1.5rem; }
2655}
2656/* Staat de mini-speler onderin, dan wijkt de knop daarvoor -- anders komt hij er
2657 bovenop te liggen (Robins schermafbeelding, 20-8). body.has-audio-player wordt
2658 door audio-player.js gezet zodra de speler zichtbaar is, en weer weggehaald
2659 als hij verdwijnt, dus dit volgt vanzelf.
2660 Op mobiel staat de speler BOVEN de tabbalk gestapeld, dus daar komt zijn
2661 hoogte bovenop de ruimte die er al gereserveerd was. */
2662body.has-audio-player .read-top { bottom: calc(env(safe-area-inset-bottom, 0) + 4.75rem + 4.25rem); }
2663@media (min-width: 768px) {
2664 body.has-audio-player .read-top { bottom: calc(1.5rem + 4.25rem); }
2665}
2666@media (prefers-reduced-motion: reduce) {
2667 .read-top { transition: none; transform: none; }
2668}
2669
2670@media (prefers-reduced-motion: reduce) {
2671 html:has(body.on-home[data-feed-view="reader"]) {
2672 scroll-snap-type: none;
2673 scroll-behavior: auto;
2674 }
2675}
2676
2677/* -------- GRID VIEW TILES (Instagram-stijl) -------- */
2678.feed-grid {
2679 padding: 1rem 0 2rem;
2680}
2681.grid-tiles {
2682 display: grid;
2683 gap: 4px;
2684 grid-template-columns: repeat(2, 1fr);
2685}
2686.grid-tile {
2687 position: relative;
2688 display: block;
2689 aspect-ratio: 1;
2690 background-size: cover;
2691 background-position: center;
2692 background-color: var(--paper-2);
2693 overflow: hidden;
2694 text-decoration: none;
2695 color: var(--ink);
2696 transition: transform .2s;
2697 cursor: pointer;
2698 -webkit-tap-highlight-color: rgba(0,0,0,.1);
2699}
2700
2701/* Transparent covers (PNG logos etc.) sit on white so they don't blend into a dark
2702 theme. The white is on the IMG, so the tile's accent-gradient placeholder shows
2703 while the image is still loading. */
2704.post-cover img,
2705.post-list-cover img,
2706.grid-tile-img { background-color: #fff; }
2707/* Accent-gradient placeholder shown while the cover image loads (the image fades in
2708 over it), instead of a white flash on cover tiles. */
2709.grid-tile:not(.grid-tile-gradient) {
2710 background-image: linear-gradient(135deg,
2711 color-mix(in srgb, var(--accent, #888) 22%, var(--paper-2, var(--paper))) 0%,
2712 color-mix(in srgb, var(--accent, #888) 6%, var(--paper-2, var(--paper))) 100%);
2713}
2714/* Cover as a real <img> (not background-image): browsers downsample <img> with the
2715 high-quality image pipeline, so high-res line-art covers don't go jagged when shrunk.
2716 Fades in on load (.is-loading removed) so the placeholder shows meanwhile. */
2717.grid-tile-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; transition: opacity .4s ease; }
2718.grid-tile-img.is-loading { opacity: 0; }
2719/* Audio tile (Shaer, Robins vraag 30-7): the waveform PNG is white on
2720 transparent and floats OVER the tile's own hue gradient, so every audio
2721 post keeps its color and gets its shape. Wave and title each get their
2722 own band (wave upper, title lower): centering both stacked them right
2723 through each other (Robins schermafdruk). */
2724.grid-tile-img.grid-tile-wave {
2725 background-color: transparent;
2726 object-fit: contain;
2727 /* explicit box, not auto: an absolutely positioned img falls back to its
2728 intrinsic size when width/height are auto, collapsing the band */
2729 top: 8%; left: 8%; right: auto; bottom: auto;
2730 width: 84%; height: 46%;
2731 opacity: .85;
2732}
2733.grid-tile-audio .grid-tile-title { position: absolute; left: 10%; right: 10%; top: 60%; }
2734.grid-tile-audio .grid-tile-gradient-src { position: absolute; left: 10%; right: 10%; top: 76%; }
2735/* Cover videos are decorative, not players: let clicks + right-click pass through to the
2736 tile link so you get the normal link menu (not the browser's <video> menu/controls).
2737 Autoplay is independent of pointer-events, so the video still plays. */
2738video.grid-tile-img,
2739.post-list-cover video,
2740.post-cover video { pointer-events: none; }
2741.grid-tile:hover { transform: scale(0.98); }
2742.grid-tile-overlay {
2743 position: absolute;
2744 inset: 0;
2745 padding: .6rem;
2746 display: flex;
2747 flex-direction: column;
2748 justify-content: flex-end;
2749 align-items: flex-start;
2750 background: linear-gradient(to top, rgba(0,0,0,.65) 0%, rgba(0,0,0,0) 50%);
2751 opacity: 0;
2752 transition: opacity .2s;
2753 pointer-events: none; /* klik moet naar de <a> eronder gaan, niet naar de overlay */
2754}
2755/* Bron-site (cirkel-feed): toont bij hover "van <site>" onder de titel. */
2756/* Source label: small text that wraps to 2 lines if needed, with a big chain icon
2757 beside it (the text was 1.44rem — bigger than the title — and overflowed on mobile). */
2758.grid-tile-overlay-src {
2759 color: #fff; opacity: .85;
2760 font-size: .72rem; line-height: 1.2; margin-top: .25rem;
2761 display: flex; align-items: center; gap: .3rem; width: 100%;
2762}
2763.grid-tile-overlay-src::before { content: "⛓"; font-size: 1.3rem; line-height: 1; flex: 0 0 auto; }
2764.grid-tile-gradient-src {
2765 margin-top: .35rem; font-size: .72rem; line-height: 1.2; opacity: .85;
2766 color: var(--ink-soft);
2767 display: flex; align-items: center; gap: .3rem; width: 100%;
2768}
2769.grid-tile-gradient-src::before { content: "⛓"; font-size: 1.3rem; line-height: 1; flex: 0 0 auto; }
2770.grid-tile-overlay strong {
2771 color: #fff;
2772 font-family: var(--font-display);
2773 font-size: .9rem;
2774 font-weight: 500;
2775 line-height: 1.15;
2776 display: -webkit-box;
2777 -webkit-line-clamp: 3;
2778 -webkit-box-orient: vertical;
2779 overflow: hidden;
2780}
2781@media (hover: hover) {
2782 .grid-tile:hover .grid-tile-overlay { opacity: 1; }
2783}
2784@media (hover: none) {
2785 /* Op touch-devices altijd overlay tonen zodat titels zichtbaar zijn */
2786 .grid-tile-overlay { opacity: 1; background: linear-gradient(to top, rgba(0,0,0,.7) 0%, rgba(0,0,0,0) 70%); }
2787}
2788
2789.grid-tile-gradient {
2790 background-image: none;
2791 background-color: hsl(var(--tile-hue, 30), 40%, 85%);
2792 background-image: linear-gradient(135deg, hsl(var(--tile-hue, 30), 45%, 88%), hsl(calc(var(--tile-hue, 30) + 30), 35%, 75%));
2793 display: flex;
2794 flex-direction: column;
2795 align-items: center;
2796 justify-content: center;
2797 padding: 1rem;
2798 text-align: center;
2799}
2800[data-theme="dark"] .grid-tile-gradient,
2801.grid-tile-gradient[data-theme="dark"] {
2802 background-image: linear-gradient(135deg, hsl(var(--tile-hue, 30), 30%, 18%), hsl(calc(var(--tile-hue, 30) + 30), 25%, 12%));
2803}
2804.grid-tile-title {
2805 font-family: var(--font-display);
2806 font-size: 1rem;
2807 font-weight: 500;
2808 color: var(--ink);
2809 line-height: 1.2;
2810 display: -webkit-box;
2811 -webkit-line-clamp: 4;
2812 -webkit-box-orient: vertical;
2813 overflow: hidden;
2814 z-index: 1;
2815 /* Federated link posts can have a long bare URL as their title — break it so it wraps
2816 inside the tile and clamps cleanly instead of overflowing past both edges. */
2817 max-width: 100%;
2818 overflow-wrap: anywhere;
2819 word-break: break-word;
2820 hyphens: auto;
2821}
2822
2823.grid-tile-pin {
2824 position: absolute;
2825 top: .5rem;
2826 right: .5rem;
2827 display: inline-flex;
2828 align-items: center;
2829 gap: .25rem;
2830 padding: .2rem .55rem;
2831 background: var(--accent);
2832 color: #fff;
2833 border-radius: 999px;
2834 font-family: var(--font-ui);
2835 font-size: .65rem;
2836 font-weight: 700;
2837 text-transform: uppercase;
2838 letter-spacing: .06em;
2839 z-index: 3;
2840 box-shadow: 0 2px 6px rgba(0,0,0,.3);
2841 pointer-events: none;
2842}
2843.grid-tile-pin svg {
2844 width: .95em;
2845 height: .95em;
2846 margin-top: -1px;
2847}
2848/* Pinned/boosted tile: accent ring. An outline on the tile is painted UNDER the absolute
2849 cover <img>, so draw the ring as a pseudo-element overlay ABOVE the image (z-index above
2850 the img, below the corner badges + nsfw veil). */
2851.grid-tile.is-pinned { position: relative; z-index: 1; }
2852.grid-tile.is-pinned::after {
2853 content: '';
2854 position: absolute;
2855 inset: 0;
2856 border: 3px solid var(--accent);
2857 border-radius: inherit;
2858 pointer-events: none;
2859 z-index: 1;
2860}
2861.grid-tile-type {
2862 position: absolute;
2863 top: .4rem;
2864 left: .4rem;
2865 padding: .15rem .5rem;
2866 background: rgba(0,0,0,.55);
2867 color: #fff;
2868 border-radius: 999px;
2869 font-family: var(--font-ui);
2870 font-size: .6rem;
2871 font-weight: 600;
2872 text-transform: uppercase;
2873 letter-spacing: .05em;
2874 z-index: 2;
2875}
2876
2877@media (min-width: 600px) {
2878 .grid-tiles { grid-template-columns: repeat(3, 1fr); }
2879}
2880@media (min-width: 900px) {
2881 .grid-tiles { grid-template-columns: repeat(3, 1fr); gap: 8px; }
2882}
2883
2884/* -------- POST-TYPE SPECIFIEKE LAYOUTS -------- */
2885
2886/* Foto-post: beeld prominent, geen titel bovenaan, caption onder */
2887.feed-timeline[data-post-type="foto"] .post-title {
2888 font-size: 1.1rem;
2889 color: var(--ink-muted);
2890 font-weight: 400;
2891}
2892.feed-timeline[data-post-type="foto"] .post-cover {
2893 margin: 0 -1rem 1rem;
2894 border-radius: 0;
2895}
2896.feed-timeline[data-post-type="foto"] .post-cover img {
2897 width: 100%;
2898 border-radius: 0;
2899}
2900
2901/* Post-caption onder de cover */
2902.post-caption {
2903 font-family: var(--font-body);
2904 font-size: 1rem;
2905 color: var(--ink);
2906 line-height: 1.5;
2907 margin: 0 0 1.25rem;
2908 padding: 0 0 1rem;
2909 border-bottom: 1px solid var(--rule);
2910 white-space: pre-wrap;
2911}
2912.feed-timeline[data-post-type="foto"] .post-caption {
2913 font-size: 1.05rem;
2914 margin-top: -.5rem;
2915 padding-bottom: 1.25rem;
2916}
2917
2918/* Audio/video posts — type-chip helder, content eronder zoals normaal */
2919.feed-timeline[data-post-type="audio"] .post-title,
2920.feed-timeline[data-post-type="video"] .post-title {
2921 font-size: 1.5rem;
2922}
2923
2924@media (min-width: 768px) {
2925 .feed-timeline[data-post-type="foto"] .post-cover {
2926 margin: 0 0 1.5rem;
2927 border-radius: var(--radius);
2928 }
2929}
2930
2931/* -------- ADMIN EDIT-BUTTON op post-view (alleen zichtbaar voor ingelogde admin) -------- */
2932.post-edit-btn {
2933 position: absolute;
2934 top: 1rem;
2935 right: 1rem;
2936 display: inline-flex;
2937 align-items: center;
2938 justify-content: center;
2939 width: 44px;
2940 height: 44px;
2941 background: var(--paper);
2942 border: 1px solid var(--rule);
2943 border-radius: 50%;
2944 color: var(--ink-muted);
2945 text-decoration: none;
2946 box-shadow: 0 2px 8px rgba(0,0,0,.08);
2947 transition: background .15s, color .15s, transform .15s, border-color .15s;
2948 z-index: 10;
2949}
2950.post-edit-btn:hover {
2951 background: var(--accent);
2952 border-color: var(--accent);
2953 color: var(--paper);
2954 transform: scale(1.05);
2955}
2956.post-edit-btn .icon {
2957 width: 1.1rem;
2958 height: 1.1rem;
2959}
2960/* Zorg dat de article relative is zodat absolute positionering werkt */
2961.feed-timeline { position: relative; }
2962
2963@media (min-width: 768px) {
2964 .post-edit-btn {
2965 top: 1.5rem;
2966 right: 1.5rem;
2967 }
2968}
2969
2970/* ============================================================
2971 v8.0 — ACCENT SPAN + POST-TABLE (published posts)
2972 ============================================================ */
2973.post span.accent,
2974.post-content span.accent,
2975article span.accent,
2976page-container span.accent {
2977 color: var(--accent);
2978 font-weight: 500;
2979}
2980
2981.post-table,
2982article table.post-table {
2983 width: 100%;
2984 max-width: 100%;
2985 border-collapse: collapse;
2986 margin: 1.25rem 0;
2987 font-size: .95rem;
2988 display: block;
2989 overflow-x: auto;
2990 -webkit-overflow-scrolling: touch;
2991}
2992.post-table thead { background: color-mix(in srgb, var(--accent) 10%, transparent); }
2993.post-table th,
2994.post-table td {
2995 padding: .6rem .8rem;
2996 text-align: left;
2997 border: 1px solid var(--rule);
2998 vertical-align: top;
2999}
3000.post-table th {
3001 font-family: var(--font-ui);
3002 font-weight: 600;
3003 font-size: .88rem;
3004 color: var(--ink);
3005 letter-spacing: .02em;
3006}
3007.post-table tbody tr:nth-child(even) {
3008 background: color-mix(in srgb, var(--ink) 3%, transparent);
3009}
3010@media (min-width: 700px) {
3011 .post-table { display: table; overflow: visible; }
3012}
3013
3014/* ============================================================
3015 v8.0 fix — grid-cols picker (desktop only) + grid col overrides
3016 ============================================================ */
3017
3018/* Switcher-wrap bevat nu ook de cols-picker; layout side-by-side */
3019.view-switcher-wrap .container {
3020 display: flex;
3021 align-items: center;
3022 justify-content: center;
3023 gap: 1rem;
3024 flex-wrap: wrap;
3025}
3026
3027/* Solo / Cirkel scope-switcher (alleen in circle-modus) — segmented toggle, centraal.
3028 Hoge specificiteit (+ !important op tekst) zodat 'ie globale link-stijlen wint. */
3029.view-switcher-wrap .feed-scope {
3030 display: inline-flex;
3031 background: var(--paper-2);
3032 border: 1px solid var(--rule);
3033 border-radius: 999px;
3034 padding: 3px;
3035}
3036.view-switcher-wrap .feed-scope-btn {
3037 display: inline-flex;
3038 align-items: center;
3039 padding: .32rem .95rem;
3040 min-height: 30px;
3041 border: none !important;
3042 border-radius: 999px !important;
3043 background: transparent !important;
3044 color: var(--ink-muted) !important;
3045 font-family: var(--font-ui);
3046 font-size: .82rem;
3047 font-weight: 500 !important;
3048 text-decoration: none !important;
3049 cursor: pointer;
3050 transition: all .15s;
3051}
3052.view-switcher-wrap .feed-scope-btn:hover { color: var(--ink) !important; }
3053.view-switcher-wrap .feed-scope-btn.is-active {
3054 background: var(--ink) !important;
3055 color: var(--paper) !important;
3056}
3057
3058.grid-cols-picker {
3059 display: none; /* default hidden — desktop + grid-active maakt 'm zichtbaar */
3060 gap: 2px;
3061 padding: 0;
3062}
3063.grid-cols-btn {
3064 display: inline-flex;
3065 align-items: center;
3066 justify-content: center;
3067 min-width: 36px;
3068 height: 32px;
3069 padding: 0 .6rem;
3070 background: transparent;
3071 border: 1px solid var(--rule);
3072 color: var(--ink-muted);
3073 font-family: var(--font-ui);
3074 font-size: .85rem;
3075 font-weight: 500;
3076 cursor: pointer;
3077 transition: all .12s;
3078}
3079.grid-cols-btn:first-child { border-radius: 999px 0 0 999px; }
3080.grid-cols-btn:last-child { border-radius: 0 999px 999px 0; }
3081.grid-cols-btn:not(:first-child):not(:last-child) { border-left: none; border-right: none; }
3082.grid-cols-btn:hover { color: var(--ink); }
3083/* Active state puur via body[data-grid-cols] — geen is-active-class meer. */
3084body[data-grid-cols="2"] .grid-cols-btn[data-cols="2"],
3085body[data-grid-cols="3"] .grid-cols-btn[data-cols="3"],
3086body[data-grid-cols="4"] .grid-cols-btn[data-cols="4"] {
3087 background: var(--ink);
3088 color: var(--paper);
3089 border-color: var(--ink);
3090}
3091
3092/* Desktop + grid-view → toon cols-picker (op de home-feed; niet op archief) */
3093@media (min-width: 600px) {
3094 body.on-home[data-feed-view="grid"] .grid-cols-picker {
3095 display: inline-flex;
3096 }
3097}
3098
3099/* Kolom-overrides op desktop. Mobiel negeert dit (staat vast op 2). Geldt op ELKE
3100 feed met grid (home én cirkel/tag/type/user) — scope op .feed-grid .grid-tiles. */
3101@media (min-width: 600px) {
3102 body[data-grid-cols="2"] .feed-grid .grid-tiles { grid-template-columns: repeat(2, 1fr); }
3103 body[data-grid-cols="3"] .feed-grid .grid-tiles { grid-template-columns: repeat(3, 1fr); }
3104 body[data-grid-cols="4"] .feed-grid .grid-tiles { grid-template-columns: repeat(4, 1fr); }
3105}
3106
3107/* Gradient-tile: iets meer contrast voor light + dark mode zodat titel altijd leesbaar is */
3108.grid-tile-gradient {
3109 background-image: linear-gradient(135deg,
3110 hsl(var(--tile-hue, 30), 55%, 72%),
3111 hsl(calc(var(--tile-hue, 30) + 40), 45%, 60%));
3112}
3113[data-theme="dark"] .grid-tile-gradient {
3114 background-image: linear-gradient(135deg,
3115 hsl(var(--tile-hue, 30), 40%, 30%),
3116 hsl(calc(var(--tile-hue, 30) + 40), 30%, 18%));
3117}
3118.grid-tile-gradient .grid-tile-title {
3119 color: #fff;
3120 text-shadow: 0 1px 3px rgba(0,0,0,.25);
3121}
3122[data-theme="dark"] .grid-tile-gradient .grid-tile-title {
3123 color: #fff;
3124 text-shadow: 0 1px 2px rgba(0,0,0,.5);
3125}
3126
3127/* ============================================================
3128 v8.0.2 — COMPACT DESIGN OVERRIDES
3129 Tighter masthead, padding, margins overall. Profiel-header
3130 collapse/expand blijft zoals 'ie was.
3131 ============================================================ */
3132
3133/* Masthead: compacter */
3134.masthead { padding: calc(.55rem + var(--ios-safe-top, 0px)) 0 .55rem; }
3135.masthead-inner { gap: 1rem; }
3136.site-title { font-size: 1.25rem; }
3137.nav-link, .nav-btn { padding: .4rem .7rem; min-height: 2rem; font-size: .82rem; }
3138
3139/* Main content padding */
3140main { padding-top: 1rem; }
3141.page { padding-block: 1rem 1.75rem; }
3142
3143/* View switcher-bar strakker */
3144.view-switcher { padding: .4rem 0; gap: .3rem; }
3145.view-switch-btn { padding: .4rem .85rem; min-height: 38px; font-size: .8rem; }
3146.grid-cols-btn { min-width: 32px; height: 28px; padding: 0 .5rem; font-size: .8rem; }
3147
3148/* Post header spacing terug */
3149.post-header { margin: 0 0 1.25rem; }
3150.post-title { margin-bottom: .35rem; }
3151.post-meta { font-size: .78rem; }
3152.post-tags { margin-top: .6rem; gap: .3rem; }
3153.post-tag { font-size: .7rem; padding: .15rem .55rem; }
3154
3155/* Article footer + pagination compacter */
3156.article-footer { padding-top: 1.25rem; margin-top: 1.5rem; }
3157.pagination { padding-block: 1.25rem 2rem; margin-top: 1.5rem; }
3158.pagination-item { padding: .75rem .95rem; min-height: 4rem; }
3159.pagination-title { font-size: .95rem; }
3160
3161/* Site footer compacter */
3162.site-footer { padding: 1.25rem 0 calc(1.25rem + env(safe-area-inset-bottom, 0px)); margin-top: 2rem; font-size: .78rem; }
3163.site-footer-inner { gap: .75rem; }
3164
3165/* Profiel-header: full mode iets minder riant (compact mode blijft hetzelfde) */
3166.profile-header { padding: 1rem 0; }
3167.profile-photo { width: 72px; height: 72px; }
3168.profile-photo-fallback { font-size: 1.8rem; }
3169.profile-name { font-size: 1.2rem; }
3170.profile-bio { font-size: .85rem; margin-top: .15rem; }
3171.profile-links { margin-top: .5rem; gap: .4rem; }
3172.profile-links a,
3173.profile-links .profile-fedi-link { width: 32px; height: 32px; }
3174
3175@media (min-width: 768px) {
3176 .profile-header { padding: 1.35rem 0; }
3177 .profile-photo { width: 92px; height: 92px; }
3178 .profile-photo-fallback { font-size: 2.4rem; }
3179 .profile-name { font-size: 1.4rem; }
3180 .profile-bio { font-size: .95rem; }
3181 .profile-header-inner { gap: 1.1rem; }
3182 /* Compact-mode op desktop blijft klein zoals we hadden afgesproken */
3183 .on-post .profile-photo,
3184 .on-special .profile-photo { width: 42px; height: 42px; }
3185}
3186
3187/* Grid-tegels iets strakker gaten */
3188.grid-tiles { gap: 3px; }
3189
3190/* Post-cover margin */
3191.post-cover { margin: 0 0 1rem; }
3192
3193/* Audio player wat lichter */
3194#pcms-audio-bar { padding: .55rem 1rem; }
3195
3196/* v8.1 — pagination CTA + mobile tap target */
3197.pagination-cta {
3198 display: inline-block;
3199 font-family: var(--font-ui);
3200 font-size: .72rem;
3201 font-weight: 600;
3202 color: var(--accent);
3203 margin-top: .35rem;
3204 letter-spacing: .02em;
3205 opacity: .9;
3206}
3207a.pagination-item:hover .pagination-cta { opacity: 1; }
3208
3209/* Mobiel: nog meer tap-feedback + iets prominenter */
3210@media (max-width: 640px) {
3211 a.pagination-item {
3212 padding: 1.1rem 1rem;
3213 min-height: 5.5rem;
3214 border-width: 2px;
3215 }
3216 a.pagination-item:active {
3217 background: color-mix(in srgb, var(--accent) 10%, var(--paper-2));
3218 transform: scale(.98);
3219 }
3220 .pagination-title { font-size: 1rem; }
3221 .pagination-cta { font-size: .75rem; }
3222 .pagination .icon { width: 1.5em; height: 1.5em; }
3223}
3224
3225
3226
3227/* v8.3 / v9.4 — PWA install button (alleen zichtbaar als browser install ondersteunt) */
3228.nav-install-btn[hidden] { display: none; }
3229.nav-install-btn {
3230 position: relative;
3231 display: inline-flex;
3232 align-items: center;
3233 justify-content: center;
3234 gap: .35rem;
3235 background: linear-gradient(135deg,
3236 var(--accent),
3237 color-mix(in srgb, var(--accent) 80%, #000));
3238 color: #fff;
3239 border: none;
3240 border-radius: .65rem;
3241 padding: .45rem .85rem;
3242 font-size: .8rem;
3243 font-weight: 600;
3244 line-height: 1;
3245 cursor: pointer;
3246 overflow: hidden;
3247 isolation: isolate;
3248 box-shadow:
3249 0 1px 0 rgba(255,255,255,.15) inset,
3250 0 2px 6px color-mix(in srgb, var(--accent) 35%, transparent);
3251 transition:
3252 transform .15s cubic-bezier(.4, 0, .2, 1),
3253 box-shadow .2s ease,
3254 filter .15s ease;
3255}
3256.nav-install-btn::before {
3257 content: "";
3258 position: absolute;
3259 top: 0;
3260 left: -100%;
3261 width: 60%;
3262 height: 100%;
3263 background: linear-gradient(110deg,
3264 transparent 30%,
3265 rgba(255,255,255,.22) 50%,
3266 transparent 70%);
3267 z-index: -1;
3268 animation: pcmsInstallShimmer 4s ease-in-out infinite;
3269 pointer-events: none;
3270}
3271.nav-install-btn:hover {
3272 transform: translateY(-1px);
3273 filter: brightness(1.08);
3274 box-shadow:
3275 0 1px 0 rgba(255,255,255,.2) inset,
3276 0 4px 10px color-mix(in srgb, var(--accent) 50%, transparent);
3277}
3278.nav-install-btn:active { transform: translateY(0); }
3279.nav-install-btn .icon {
3280 flex-shrink: 0;
3281 transition: transform .25s cubic-bezier(.34, 1.56, .64, 1);
3282}
3283.nav-install-btn:hover .icon { transform: translateY(-1px); }
3284@media (prefers-reduced-motion: reduce) {
3285 .nav-install-btn::before { animation: none; left: -100%; }
3286 .nav-install-btn:hover { transform: none; }
3287 .nav-install-btn:hover .icon { transform: none; }
3288}
3289/* Als PWA al draait (standalone mode) — verberg install-prompt knop volledig */
3290@media all and (display-mode: standalone) {
3291 #pwa-install-btn { display: none !important; }
3292}
3293
3294/* ========== v8.9.9 — Privé-post indicators ========== */
3295.post-private-banner {
3296 display: flex;
3297 align-items: center;
3298 gap: .6rem;
3299 padding: .75rem 1rem;
3300 background: color-mix(in srgb, #eab308 12%, var(--paper, #fff));
3301 border: 1px solid color-mix(in srgb, #eab308 40%, transparent);
3302 border-radius: 8px;
3303 margin: 0 0 1rem;
3304 font-size: .88rem;
3305 color: var(--ink, #1a1a1a);
3306}
3307.post-private-banner strong {
3308 color: #b45309;
3309}
3310
3311.grid-tile-private {
3312 position: absolute;
3313 top: 8px;
3314 left: 8px;
3315 padding: 3px 8px;
3316 background: rgba(0,0,0,0.7);
3317 color: #fde68a;
3318 font-size: .7rem;
3319 font-weight: 700;
3320 border-radius: 999px;
3321 z-index: 3;
3322 backdrop-filter: blur(4px);
3323 -webkit-backdrop-filter: blur(4px);
3324}
3325
3326/* ========== v8.9.10 — Social chip (inline in post-body) ========== */
3327.social-chip {
3328 display: inline-flex;
3329 align-items: center;
3330 gap: .45rem;
3331 padding: .35rem .75rem;
3332 background: color-mix(in srgb, var(--accent) 10%, transparent);
3333 border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
3334 border-radius: 999px;
3335 color: var(--ink, #1a1a1a);
3336 text-decoration: none;
3337 font-family: var(--font-ui, system-ui);
3338 font-size: .85rem;
3339 font-weight: 600;
3340 line-height: 1.2;
3341 transition: all .15s;
3342 vertical-align: middle;
3343 margin: 0 .1rem;
3344}
3345.social-chip:hover {
3346 background: var(--accent);
3347 color: #fff;
3348 border-color: var(--accent);
3349 text-decoration: none;
3350 transform: translateY(-1px);
3351 box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 40%, transparent);
3352}
3353.social-chip .icon {
3354 width: 16px;
3355 height: 16px;
3356 flex-shrink: 0;
3357}
3358.social-chip-icon-only {
3359 width: 36px;
3360 height: 36px;
3361 padding: 0;
3362 justify-content: center;
3363 border-radius: 50%;
3364}
3365.social-chip-icon-only .icon {
3366 width: 18px;
3367 height: 18px;
3368}
3369
3370/* v8.9.34 — player hidden state + post audio blocks
3371 v9.3 — Hide-rules uitgeschakeld: mini-player blijft permanent zichtbaar
3372 zodat 'ie niet meer verdwijnt bij browser-back of navigatie. */
3373.audio-player.is-hidden {
3374 /* display: none !important; */
3375}
3376body:not(.has-audio-player) #pcms-audio-player.is-hidden {
3377 /* display: none !important; */
3378}
3379
3380/* Post audio track — single track row in een post */
3381/* Lokale audio-track — visueel consistent met .post-audio-external */
3382.post-audio-track {
3383 display: flex;
3384 align-items: center;
3385 gap: .75rem;
3386 padding: .65rem .85rem;
3387 background: var(--paper-2, color-mix(in srgb, var(--ink) 4%, transparent));
3388 border: 1px solid var(--rule, rgba(0,0,0,.08));
3389 border-radius: 10px;
3390 margin: .75rem 0;
3391 transition: background .15s, border-color .15s;
3392}
3393.post-audio-track:hover {
3394 border-color: var(--accent, #c2410c);
3395 background: color-mix(in srgb, var(--accent, #c2410c) 5%, var(--paper-2, transparent));
3396}
3397/* Korte highlight wanneer je via de mini-speler naar deze track springt. */
3398.post-audio-track.pat-flash,
3399.post-album-track-compact.pat-flash {
3400 animation: patFlash 1.6s ease-out;
3401 border-radius: 8px;
3402}
3403/* Blijvende highlight op de track die NU actief is in de speler. */
3404.post-audio-track.pat-playing,
3405.post-album-track-compact.pat-playing {
3406 background: color-mix(in srgb, var(--accent, #c2410c) 12%, var(--paper-2, transparent));
3407 box-shadow: inset 3px 0 0 0 var(--accent, #c2410c);
3408 border-radius: 8px;
3409}
3410@keyframes patFlash {
3411 0%, 30% { border-color: var(--accent, #c2410c); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent, #c2410c) 35%, transparent); }
3412 100% { box-shadow: 0 0 0 0 transparent; }
3413}
3414.post-audio-track .pat-play {
3415 flex-shrink: 0;
3416 width: 42px;
3417 height: 42px;
3418 border-radius: 8px; /* zelfde rounded-square als pae-icon */
3419 border: none;
3420 background: var(--accent, #c2410c);
3421 color: var(--paper, #fff);
3422 cursor: pointer;
3423 display: inline-flex;
3424 align-items: center;
3425 justify-content: center;
3426 transition: transform .1s, background .15s;
3427 padding: 0;
3428 position: relative;
3429 overflow: hidden;
3430}
3431.post-audio-track .pat-play:hover { transform: scale(1.04); }
3432.post-audio-track .pat-play:active { transform: scale(.96); }
3433.post-audio-track .pat-play svg,
3434.post-audio-track .pat-play .pat-sitelogo {
3435 width: 100%; height: 100%;
3436 position: absolute;
3437 top: 0; left: 0;
3438 transition: opacity .15s;
3439}
3440.post-audio-track .pat-play .icon-play,
3441.post-audio-track .pat-play .icon-pause {
3442 width: 18px; height: 18px;
3443 position: absolute;
3444 top: 50%; left: 50%;
3445 transform: translate(-50%, -50%);
3446 fill: currentColor;
3447 opacity: 0; /* verborgen tot hover of is-current */
3448}
3449/* Site logo: object-cover binnen 42x42 box */
3450.post-audio-track .pat-play .pat-sitelogo {
3451 object-fit: cover;
3452 opacity: 1;
3453}
3454.post-audio-track .pat-play .pat-sitelogo-fallback {
3455 padding: 11px; /* SVG music-note iets kleiner in box */
3456 opacity: 1;
3457}
3458/* Bij hover: site logo faded, play-icoon verschijnt */
3459.post-audio-track:hover .pat-play .pat-sitelogo { opacity: 0.25; }
3460.post-audio-track:hover .pat-play .icon-play { opacity: 1; }
3461/* Bij current + playing: toon pause-icon */
3462.post-audio-track.is-current .pat-play .pat-sitelogo { opacity: 0.25; }
3463.post-audio-track.is-current .pat-play .icon-play { opacity: 1; }
3464.post-audio-track.is-current.is-playing .pat-play .icon-play { opacity: 0; }
3465.post-audio-track.is-current.is-playing .pat-play .icon-pause { opacity: 1; }
3466.post-audio-track.is-current {
3467 border-color: var(--accent, #c2410c);
3468 background: color-mix(in srgb, var(--accent, #c2410c) 10%, transparent);
3469}
3470.post-audio-track .pat-meta {
3471 flex: 1;
3472 min-width: 0;
3473 display: flex;
3474 flex-direction: column;
3475 gap: 2px;
3476}
3477.post-audio-track .pat-title {
3478 display: block;
3479 font-weight: 600;
3480 color: var(--ink);
3481 font-size: .95rem;
3482 overflow: hidden;
3483 text-overflow: ellipsis;
3484 white-space: nowrap;
3485}
3486.post-audio-track .pat-artist {
3487 display: block;
3488 font-size: .78rem;
3489 color: var(--ink-muted, var(--ink));
3490 opacity: .65;
3491 overflow: hidden;
3492 text-overflow: ellipsis;
3493 white-space: nowrap;
3494}
3495.post-audio-track .pat-duration {
3496 flex-shrink: 0;
3497 font-family: ui-monospace, monospace;
3498 font-size: .8rem;
3499 opacity: .55;
3500}
3501
3502/* Album block in een post */
3503.post-album {
3504 position: relative;
3505 border: 1px solid var(--rule, rgba(0,0,0,.1));
3506 border-radius: 14px;
3507 overflow: hidden;
3508 margin: 1.25rem 0;
3509 background: var(--paper-2, color-mix(in srgb, var(--ink) 3%, transparent));
3510}
3511.post-album-header {
3512 display: flex;
3513 gap: .75rem;
3514 padding: .55rem .7rem;
3515 align-items: center;
3516}
3517.post-album-cover {
3518 width: 120px;
3519 height: 120px;
3520 border-radius: 8px;
3521 background-size: cover;
3522 background-position: center;
3523 background-color: var(--rule);
3524 flex-shrink: 0;
3525}
3526/* v9.0 — Collage van track-covers als album-cover leeg is */
3527.post-album-cover-collage {
3528 display: grid;
3529 grid-template-columns: 1fr 1fr;
3530 grid-template-rows: 1fr 1fr;
3531 gap: 0;
3532 overflow: hidden;
3533 background: transparent;
3534}
3535.post-album-cover-collage .post-album-cover-tile {
3536 background-size: cover;
3537 background-position: center;
3538 width: 100%;
3539 height: 100%;
3540}
3541/* Empty state: gradient met muziek-noot */
3542.post-album-cover-empty {
3543 display: flex;
3544 align-items: center;
3545 justify-content: center;
3546 background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 25%, var(--paper-2)), color-mix(in srgb, var(--accent) 10%, var(--paper)));
3547 color: var(--accent, #c2410c);
3548}
3549.post-album-cover-empty svg {
3550 width: 42%;
3551 height: 42%;
3552 opacity: .55;
3553}
3554.post-album-info {
3555 flex: 1;
3556 min-width: 0;
3557}
3558.post-album-label {
3559 text-transform: uppercase;
3560 font-size: .68rem;
3561 letter-spacing: .1em;
3562 opacity: .55;
3563 margin: 0 0 .15rem;
3564 font-weight: 700;
3565}
3566.post-album-title {
3567 font-family: var(--font-display);
3568 font-size: 1.1rem;
3569 font-weight: 600;
3570 margin: 0 0 .1rem;
3571 line-height: 1.15;
3572 letter-spacing: -0.01em;
3573}
3574.post-album-artist {
3575 font-size: .88rem;
3576 opacity: .8;
3577 margin: 0 0 .12rem;
3578 line-height: 1.25;
3579}
3580.post-album-meta {
3581 font-size: .74rem;
3582 opacity: .55;
3583 margin: 0;
3584 line-height: 1.2;
3585}
3586.post-album-playall {
3587 margin-top: .75rem;
3588 padding: .45rem .9rem;
3589 background: var(--accent, #c2410c);
3590 color: var(--paper, #fff);
3591 border: none;
3592 border-radius: 6px;
3593 font-weight: 600;
3594 cursor: pointer;
3595 font-size: .88rem;
3596 display: inline-flex;
3597 align-items: center;
3598 gap: .35rem;
3599}
3600.post-album-playall:hover { filter: brightness(1.08); }
3601
3602/* ============================================================
3603 v9.0 — Album cover clickable button
3604 ============================================================ */
3605.post-album-cover-btn {
3606 position: relative;
3607 background: none;
3608 border: none;
3609 padding: 0;
3610 margin: 0;
3611 cursor: pointer;
3612 flex-shrink: 0;
3613 border-radius: 8px;
3614 overflow: hidden;
3615 display: block;
3616 width: auto;
3617 /* v9.1 — voorkom mobile 300ms double-tap zoom delay, anders zou 2× snel klikken
3618 een zoom triggeren i.p.v. 2× click-events */
3619 touch-action: manipulation;
3620 -webkit-tap-highlight-color: transparent;
3621}
3622.post-album-cover-btn .post-album-cover {
3623 display: block;
3624 width: 76px;
3625 height: 76px;
3626 border-radius: 7px;
3627 background-size: cover;
3628 background-position: center;
3629 background-color: var(--rule);
3630 transition: transform .25s ease;
3631}
3632.post-album-cover-btn:hover .post-album-cover {
3633 transform: scale(1.04);
3634}
3635.post-album-cover-btn .post-album-cover-empty {
3636 background: linear-gradient(135deg,
3637 color-mix(in srgb, var(--accent, #c2410c) 35%, var(--paper)),
3638 color-mix(in srgb, var(--accent, #c2410c) 10%, var(--paper-2)));
3639 display: flex;
3640 align-items: center;
3641 justify-content: center;
3642}
3643.post-album-cover-btn .post-album-cover-empty svg {
3644 width: 28px;
3645 height: 28px;
3646 color: color-mix(in srgb, var(--accent, #c2410c) 60%, transparent);
3647}
3648/* Play overlay op hover */
3649.post-album-cover-play {
3650 position: absolute;
3651 inset: 0;
3652 display: flex;
3653 align-items: center;
3654 justify-content: center;
3655 background: rgba(0, 0, 0, .35);
3656 opacity: 0;
3657 transition: opacity .2s ease;
3658 border-radius: 8px;
3659 pointer-events: none;
3660}
3661.post-album-cover-play svg {
3662 width: 48px;
3663 height: 48px;
3664 color: #fff;
3665 filter: drop-shadow(0 2px 8px rgba(0,0,0,.4));
3666}
3667.post-album-cover-btn:hover .post-album-cover-play,
3668.post-album-cover-btn:focus-visible .post-album-cover-play {
3669 opacity: 1;
3670}
3671
3672/* ============================================================
3673 v1 P52 — Admin actions overlay (edit / delete)
3674 Only rendered when the viewer has god role. Sits top-right
3675 of the card so it doesn't compete with the cover play affordance.
3676 ============================================================ */
3677.post-album-actions {
3678 position: absolute;
3679 top: .4rem;
3680 right: .4rem;
3681 display: flex;
3682 gap: .25rem;
3683 z-index: 2;
3684}
3685.post-album-action {
3686 width: 28px;
3687 height: 28px;
3688 border-radius: 6px;
3689 border: 1px solid var(--rule);
3690 background: color-mix(in srgb, var(--paper) 78%, transparent);
3691 backdrop-filter: blur(8px);
3692 -webkit-backdrop-filter: blur(8px);
3693 color: var(--ink);
3694 display: inline-flex;
3695 align-items: center;
3696 justify-content: center;
3697 cursor: pointer;
3698 text-decoration: none;
3699 opacity: .65;
3700 padding: 0;
3701 transition: opacity .15s ease, transform .15s ease, background .15s ease, color .15s ease, border-color .15s ease;
3702 -webkit-tap-highlight-color: transparent;
3703}
3704.post-album-action:hover,
3705.post-album-action:focus-visible {
3706 opacity: 1;
3707 transform: translateY(-1px);
3708 outline: none;
3709}
3710.post-album-action.is-danger:hover,
3711.post-album-action.is-danger:focus-visible {
3712 background: color-mix(in srgb, #c2410c 18%, var(--paper));
3713 border-color: color-mix(in srgb, #c2410c 45%, var(--rule));
3714 color: #c2410c;
3715}
3716.post-album-action svg {
3717 width: 15px;
3718 height: 15px;
3719 display: block;
3720}
3721
3722/* ============================================================
3723 v9.0 — Compacte tracklist (informatief, niet-klikbaar)
3724 ============================================================ */
3725.post-album-tracks {
3726 list-style: none;
3727 padding: 0;
3728 margin: 0;
3729 border-top: 1px solid var(--rule);
3730}
3731/* v9.4 — Playlist insert modal rows */
3732.pli-row {
3733 display: flex;
3734 align-items: center;
3735 gap: .75rem;
3736 padding: .65rem .5rem;
3737 border-bottom: 1px solid var(--border);
3738}
3739.pli-row:last-child { border-bottom: none; }
3740.pli-row-cover {
3741 width: 44px;
3742 height: 44px;
3743 border-radius: 6px;
3744 background-size: cover;
3745 background-position: center;
3746 background-color: color-mix(in srgb, var(--ink, #000) 8%, transparent);
3747 flex-shrink: 0;
3748 display: flex;
3749 align-items: center;
3750 justify-content: center;
3751 font-size: 1.4rem;
3752}
3753.pli-row-info {
3754 flex: 1;
3755 min-width: 0;
3756}
3757.pli-row-title {
3758 font-weight: 600;
3759 overflow: hidden;
3760 text-overflow: ellipsis;
3761 white-space: nowrap;
3762}
3763.pli-row-meta {
3764 font-size: .82rem;
3765 overflow: hidden;
3766 text-overflow: ellipsis;
3767 white-space: nowrap;
3768}
3769.post-playlist-placeholder {
3770 margin: 1rem 0;
3771 user-select: none;
3772}
3773
3774/* v9.4 — Generic modal classes (gebruikt door playlist-editor en andere modals) */
3775.pcms-modal-backdrop {
3776 position: fixed;
3777 inset: 0;
3778 background: rgba(0, 0, 0, .6);
3779 display: flex;
3780 align-items: center;
3781 justify-content: center;
3782 z-index: 9000;
3783 padding: 1rem;
3784 box-sizing: border-box;
3785 overflow-y: auto;
3786}
3787.pcms-modal {
3788 background: var(--paper, #fff);
3789 color: var(--ink, #000);
3790 border-radius: 12px;
3791 width: 100%;
3792 max-width: 640px;
3793 max-height: calc(100vh - 2rem);
3794 display: flex;
3795 flex-direction: column;
3796 overflow: hidden;
3797 box-shadow: 0 20px 60px rgba(0, 0, 0, .3);
3798}
3799.pcms-modal-header {
3800 display: flex;
3801 align-items: center;
3802 justify-content: space-between;
3803 padding: 1rem 1.25rem;
3804 border-bottom: 1px solid var(--border);
3805 flex-shrink: 0;
3806}
3807.pcms-modal-header h3 { font-size: 1.1rem; }
3808.pcms-modal-close {
3809 background: transparent;
3810 border: none;
3811 font-size: 1.6rem;
3812 line-height: 1;
3813 cursor: pointer;
3814 padding: .25rem .5rem;
3815 color: var(--fg-muted, #666);
3816 border-radius: 4px;
3817}
3818.pcms-modal-close:hover {
3819 background: color-mix(in srgb, var(--ink, #000) 8%, transparent);
3820}
3821.pcms-modal-body {
3822 padding: 1.25rem;
3823 overflow-y: auto;
3824 overscroll-behavior: contain;
3825 flex: 1;
3826 min-height: 0;
3827}
3828.pcms-modal-footer {
3829 display: flex;
3830 gap: .5rem;
3831 justify-content: flex-end;
3832 padding: .75rem 1.25rem;
3833 border-top: 1px solid var(--border);
3834 flex-shrink: 0;
3835 background: color-mix(in srgb, var(--ink, #000) 3%, transparent);
3836}
3837
3838/* On mobile: full-screen modal */
3839@media (max-width: 600px) {
3840 .pcms-modal-backdrop {
3841 padding: 0;
3842 }
3843 .pcms-modal {
3844 border-radius: 0;
3845 max-width: 100%;
3846 max-height: 100vh;
3847 height: 100vh;
3848 }
3849}
3850
3851/* v9.4 — Media → Playlists tab */
3852.playlists-page-header {
3853 display: flex;
3854 flex-wrap: wrap;
3855 gap: 1rem;
3856 align-items: center;
3857 justify-content: space-between;
3858 margin-bottom: 1.25rem;
3859}
3860.playlists-page-header > p { flex: 1; min-width: 200px; }
3861.playlists-grid {
3862 display: grid;
3863 grid-template-columns: 1fr;
3864 gap: .75rem;
3865}
3866@media (min-width: 720px) {
3867 .playlists-grid { grid-template-columns: repeat(2, 1fr); }
3868}
3869@media (min-width: 1100px) {
3870 .playlists-grid { grid-template-columns: repeat(3, 1fr); }
3871}
3872.playlist-card {
3873 display: grid;
3874 grid-template-columns: 64px 1fr auto;
3875 gap: .75rem;
3876 align-items: center;
3877 padding: .75rem;
3878 border: 1px solid var(--border);
3879 border-radius: var(--radius);
3880 background: var(--paper, #fff);
3881}
3882.playlist-card-cover {
3883 width: 64px;
3884 height: 64px;
3885 border-radius: 8px;
3886 overflow: hidden;
3887 background-color: color-mix(in srgb, var(--ink, #000) 6%, transparent);
3888 display: flex;
3889 align-items: center;
3890 justify-content: center;
3891}
3892.playlist-card-cover img {
3893 width: 100%;
3894 height: 100%;
3895 object-fit: cover;
3896}
3897.playlist-card-cover-empty { font-size: 1.6rem; opacity: .5; }
3898.playlist-card-info { min-width: 0; }
3899.playlist-card-title {
3900 font-weight: 600;
3901 overflow: hidden;
3902 text-overflow: ellipsis;
3903 white-space: nowrap;
3904}
3905.playlist-card-artist,
3906.playlist-card-meta {
3907 font-size: .82rem;
3908 overflow: hidden;
3909 text-overflow: ellipsis;
3910 white-space: nowrap;
3911}
3912.playlist-card-actions {
3913 display: flex;
3914 gap: .25rem;
3915 flex-shrink: 0;
3916}
3917
3918/* v9.4 — Playlist editor modal (mobile-friendly, single-column) */
3919.pl-editor {
3920 /* Erft van .pcms-modal */
3921}
3922.pl-editor-meta {
3923 display: grid;
3924 grid-template-columns: 1fr;
3925 gap: .75rem;
3926 margin-bottom: 1rem;
3927}
3928@media (min-width: 560px) {
3929 .pl-editor-meta {
3930 grid-template-columns: 1fr 1fr;
3931 }
3932 .pl-editor-meta .pl-editor-field-full { grid-column: 1 / -1; }
3933}
3934.pl-editor-field {
3935 display: flex;
3936 flex-direction: column;
3937 gap: .25rem;
3938 min-width: 0;
3939}
3940.pl-editor-field span {
3941 font-size: .82rem;
3942 color: var(--fg-muted, #666);
3943 font-weight: 500;
3944}
3945.pl-editor-field input,
3946.pl-editor-field select {
3947 width: 100%;
3948 box-sizing: border-box;
3949 padding: .5rem .65rem;
3950 font-size: .95rem;
3951 border: 1px solid var(--border);
3952 border-radius: 6px;
3953 background: var(--paper, #fff);
3954 color: var(--ink, #000);
3955}
3956.pl-editor-field input:focus,
3957.pl-editor-field select:focus {
3958 outline: 2px solid var(--accent, #5a8a5a);
3959 outline-offset: -1px;
3960}
3961.pl-editor-section-title {
3962 margin: 1.25rem 0 .5rem;
3963 font-size: 1rem;
3964 font-weight: 600;
3965}
3966.pl-tracks-selected {
3967 border: 1px solid var(--border);
3968 border-radius: var(--radius);
3969 background: var(--paper, #fff);
3970 min-height: 60px;
3971 margin-bottom: 1rem;
3972 padding: .25rem;
3973}
3974.pl-tracks-empty {
3975 padding: 1.5rem;
3976 text-align: center;
3977 color: var(--fg-muted, #666);
3978 font-size: .9rem;
3979}
3980.pl-track-row {
3981 display: grid;
3982 grid-template-columns: 32px 36px 1fr auto;
3983 gap: .5rem;
3984 align-items: center;
3985 padding: .5rem;
3986 border-bottom: 1px solid var(--border);
3987 background: var(--paper, #fff);
3988 user-select: none;
3989 touch-action: pan-x;
3990}
3991.pl-track-row:last-child { border-bottom: none; }
3992.pl-track-row.is-dragging {
3993 opacity: .55;
3994 transform: scale(.98);
3995 background: color-mix(in srgb, var(--accent, #5a8a5a) 10%, transparent);
3996 border-radius: 6px;
3997}
3998.pl-track-row.drop-target-above {
3999 box-shadow: inset 0 2px 0 0 var(--accent, #5a8a5a);
4000}
4001.pl-track-row.drop-target-below {
4002 box-shadow: inset 0 -2px 0 0 var(--accent, #5a8a5a);
4003}
4004.pl-track-handle {
4005 cursor: grab;
4006 font-size: 1.2rem;
4007 line-height: 1;
4008 color: var(--fg-muted, #666);
4009 display: flex;
4010 align-items: center;
4011 justify-content: center;
4012 height: 32px;
4013 width: 32px;
4014 border-radius: 4px;
4015 flex-shrink: 0;
4016}
4017.pl-track-handle:active { cursor: grabbing; }
4018.pl-track-handle:hover {
4019 background: color-mix(in srgb, var(--ink, #000) 8%, transparent);
4020}
4021.pl-track-num {
4022 text-align: center;
4023 color: var(--fg-muted, #666);
4024 font-size: .85rem;
4025 width: 36px;
4026}
4027.pl-track-info {
4028 min-width: 0;
4029 overflow: hidden;
4030}
4031.pl-track-title {
4032 font-weight: 500;
4033 overflow: hidden;
4034 text-overflow: ellipsis;
4035 white-space: nowrap;
4036}
4037.pl-track-artist {
4038 font-size: .78rem;
4039 color: var(--fg-muted, #666);
4040 overflow: hidden;
4041 text-overflow: ellipsis;
4042 white-space: nowrap;
4043}
4044.pl-track-remove {
4045 background: transparent;
4046 border: none;
4047 cursor: pointer;
4048 padding: .35rem;
4049 border-radius: 4px;
4050 color: var(--fg-muted, #666);
4051 font-size: 1.2rem;
4052 line-height: 1;
4053}
4054.pl-track-remove:hover {
4055 background: color-mix(in srgb, #c00 12%, transparent);
4056 color: #c00;
4057}
4058
4059/* Available tracks panel */
4060.pl-tracks-available-panel {
4061 border: 1px solid var(--border);
4062 border-radius: var(--radius);
4063 background: var(--paper, #fff);
4064}
4065.pl-tracks-available-search {
4066 padding: .5rem;
4067 border-bottom: 1px solid var(--border);
4068}
4069.pl-tracks-available-search input {
4070 width: 100%;
4071 box-sizing: border-box;
4072}
4073.pl-tracks-available-list {
4074 max-height: 30vh;
4075 overflow-y: auto;
4076}
4077.pl-track-row-available {
4078 display: grid;
4079 grid-template-columns: 1fr auto;
4080 gap: .5rem;
4081 align-items: center;
4082 padding: .5rem;
4083 border-bottom: 1px solid var(--border);
4084 cursor: pointer;
4085}
4086.pl-track-row-available:last-child { border-bottom: none; }
4087.pl-track-row-available:hover {
4088 background: color-mix(in srgb, var(--accent, #5a8a5a) 8%, transparent);
4089}
4090.pl-track-row-available.is-already-added {
4091 opacity: .4;
4092 pointer-events: none;
4093}
4094.pl-track-add-btn {
4095 background: transparent;
4096 border: 1px solid var(--border);
4097 border-radius: 4px;
4098 padding: .25rem .5rem;
4099 cursor: pointer;
4100 font-size: .85rem;
4101 color: var(--accent, #5a8a5a);
4102}
4103
4104/* v9.3 — Tracklist items zijn nu klikbare <button class="pat-row"> binnen <li>.
4105 De LI is puur een container zonder visuele styling; alles gebeurt op de button. */
4106.post-album-track-compact {
4107 padding: 0;
4108 margin: 0;
4109 border-bottom: 1px solid var(--rule);
4110 list-style: none;
4111}
4112.post-album-track-compact:last-child { border-bottom: none; }
4113
4114.pat-row {
4115 display: grid;
4116 grid-template-columns: 32px 1fr auto;
4117 gap: .65rem;
4118 align-items: center;
4119 width: 100%;
4120 padding: .5rem .85rem;
4121 background: transparent;
4122 border: none;
4123 color: inherit;
4124 font: inherit;
4125 font-size: .82rem;
4126 text-align: left;
4127 cursor: pointer;
4128 position: relative;
4129 transition: background .15s ease;
4130}
4131.pat-row:hover {
4132 background: color-mix(in srgb, var(--ink, #000) 6%, transparent);
4133}
4134.pat-row:active { transform: scale(.995); }
4135[data-theme="dark"] .pat-row:hover {
4136 background: color-mix(in srgb, var(--paper, #fff) 10%, transparent);
4137}
4138
4139/* Leader: track-nummer OF cover-thumb (afhankelijk van kind).
4140 v9.3 — pat-leader is altijd 32×32, met overgang voor spinner-vervanging. */
4141.pat-row .pat-num,
4142.pat-row .pat-cover {
4143 width: 32px;
4144 height: 32px;
4145 border-radius: 4px;
4146 flex-shrink: 0;
4147 transition: opacity .25s ease, transform .25s ease;
4148}
4149.pat-row .pat-num {
4150 font-family: ui-monospace, monospace;
4151 font-size: .8rem;
4152 opacity: .5;
4153 display: flex;
4154 align-items: center;
4155 justify-content: center;
4156}
4157.pat-row .pat-cover {
4158 background-size: cover;
4159 background-position: center;
4160 background-color: color-mix(in srgb, var(--ink, #000) 8%, transparent);
4161}
4162
4163/* v9.3 — Loading-spiraal als overlay op de leader-kolom.
4164 pat-num/pat-cover faden uit, spinner faded in via ::before. */
4165.pat-row::before {
4166 content: "";
4167 position: absolute;
4168 left: .85rem; top: 50%;
4169 width: 32px; height: 32px;
4170 transform: translateY(-50%);
4171 color: var(--accent, #c2410c);
4172 background-color: currentColor;
4173 -webkit-mask: url('/assets/spinner.svg') center/26px 26px no-repeat;
4174 mask: url('/assets/spinner.svg') center/26px 26px no-repeat;
4175 opacity: 0;
4176 transition: opacity .25s ease;
4177 pointer-events: none;
4178 animation: pat-spinner-rotate 1.2s linear infinite;
4179 animation-play-state: paused;
4180}
4181.pat-row.is-loading::before {
4182 opacity: 1;
4183 animation-play-state: running;
4184}
4185.pat-row.is-loading .pat-num,
4186.pat-row.is-loading .pat-cover {
4187 opacity: 0;
4188 transform: scale(.85);
4189}
4190@keyframes pat-spinner-rotate {
4191 from { transform: translateY(-50%) rotate(0deg); }
4192 to { transform: translateY(-50%) rotate(-360deg); }
4193}
4194
4195/* Meta-kolom */
4196.pat-row .pat-meta {
4197 display: flex;
4198 flex-direction: column;
4199 min-width: 0;
4200 gap: 1px;
4201 overflow: hidden;
4202}
4203.pat-row .pat-title {
4204 font-weight: 500;
4205 overflow: hidden;
4206 text-overflow: ellipsis;
4207 white-space: nowrap;
4208}
4209.pat-row .pat-artist {
4210 font-size: .72rem;
4211 opacity: .6;
4212 overflow: hidden;
4213 text-overflow: ellipsis;
4214 white-space: nowrap;
4215}
4216.pat-row .pat-duration {
4217 font-family: ui-monospace, monospace;
4218 font-size: .72rem;
4219 opacity: .55;
4220 font-variant-numeric: tabular-nums;
4221 white-space: nowrap;
4222}
4223.pat-row .pat-duration-empty {
4224 opacity: .25;
4225}
4226
4227/* is-current — actieve track in de player */
4228.pat-row.is-current {
4229 background: color-mix(in srgb, var(--accent, #c2410c) 12%, transparent);
4230}
4231.pat-row.is-current .pat-title,
4232.pat-row.is-current .pat-artist { color: var(--accent, #c2410c); }
4233
4234/* v9.3 — Marquee bij actief afspelen: titel scrollt heen-en-weer.
4235 --pat-shift wordt door JS gezet (= overflow in pixels). Bij 0 → geen
4236 beweging want translateX(0) blijft 0.
4237 Snelle cyclus (6s) met korte rust aan beide uiteinden (8%) zodat 't
4238 vlot voelt zonder onleesbaar te zijn. */
4239.pat-row.is-current.is-playing .pat-title {
4240 animation: pat-title-marquee 6s ease-in-out infinite alternate;
4241 text-overflow: clip;
4242 overflow: visible;
4243 will-change: transform;
4244}
4245@keyframes pat-title-marquee {
4246 0%, 8% { transform: translateX(0); }
4247 92%, 100% { transform: translateX(calc(-1 * var(--pat-shift, 0px))); }
4248}
4249
4250/* ============================================================
4251 v9.0 — CSS-migratie voor OUDE opgeslagen albums
4252 Oude posts hebben <li class="post-audio-track"> met play-knoppen + cover-spans.
4253 We renderen die VISUEEL als compact, zonder de HTML aan te passen.
4254 ============================================================ */
4255.post-album-tracks .post-audio-track {
4256 display: grid;
4257 grid-template-columns: 28px 1fr auto;
4258 gap: .75rem;
4259 align-items: center;
4260 padding: .5rem .85rem;
4261 margin: 0;
4262 border: none;
4263 border-bottom: 1px solid var(--rule);
4264 background: transparent;
4265 border-radius: 0;
4266 cursor: default;
4267 font-size: .92rem;
4268}
4269.post-album-tracks .post-audio-track:last-child { border-bottom: none; }
4270/* Verberg de cover-thumb en play-button in OUDE saved posts */
4271.post-album-tracks .post-audio-track .pat-cover,
4272.post-album-tracks .post-audio-track .pat-play {
4273 display: none !important;
4274}
4275.post-album-tracks .post-audio-track .pat-num {
4276 font-family: ui-monospace, monospace;
4277 font-size: .8rem;
4278 opacity: .45;
4279 text-align: center;
4280 width: auto;
4281}
4282.post-album-tracks .post-audio-track .pat-meta {
4283 display: flex;
4284 flex-direction: column;
4285 min-width: 0;
4286 gap: 1px;
4287}
4288.post-album-tracks .post-audio-track .pat-title {
4289 font-weight: 500;
4290 overflow: hidden;
4291 text-overflow: ellipsis;
4292 white-space: nowrap;
4293}
4294.post-album-tracks .post-audio-track .pat-artist {
4295 font-size: .78rem;
4296 opacity: .6;
4297}
4298.post-album-tracks .post-audio-track .pat-duration {
4299 font-family: ui-monospace, monospace;
4300 font-size: .78rem;
4301 opacity: .55;
4302}
4303.post-album-tracks .post-audio-track.is-current {
4304 background: color-mix(in srgb, var(--accent, #c2410c) 10%, transparent);
4305}
4306.post-album-tracks .post-audio-track.is-current .pat-num,
4307.post-album-tracks .post-audio-track.is-current .pat-title {
4308 color: var(--accent);
4309}
4310
4311@media (max-width: 540px) {
4312 .post-album-header { flex-direction: column; }
4313 .post-album-cover-btn .post-album-cover { width: 100%; max-width: 240px; height: auto; aspect-ratio: 1/1; }
4314}
4315@media (max-width: 380px) {
4316 .post-album-header { padding: .75rem; gap: .75rem; }
4317 .post-album-cover-btn .post-album-cover { max-width: 180px; }
4318 .post-album-title { font-size: 1.15rem; }
4319 .post-album-meta { font-size: .8rem; }
4320 .post-album-track-compact,
4321 .post-album-tracks .post-audio-track {
4322 grid-template-columns: 24px 1fr auto;
4323 gap: .5rem;
4324 padding: .4rem .6rem;
4325 font-size: .85rem;
4326 }
4327 .post-album-track-compact .pat-duration,
4328 .post-album-tracks .post-audio-track .pat-duration {
4329 font-size: .72rem;
4330 }
4331 /* Queue items in expand-sheet */
4332 .audio-sheet-queue-item { padding: .4rem .45rem; gap: .55rem; }
4333 .audio-sheet-queue-cover { width: 32px; height: 32px; }
4334 .audio-sheet-queue-title { font-size: .85rem; }
4335 .audio-sheet-queue-artist { font-size: .7rem; }
4336}
4337
4338/* External track (SoundCloud / YouTube / Spotify / etc) — klikbaar maar link-naar-platform */
4339.post-audio-external {
4340 display: flex;
4341 align-items: center;
4342 gap: .75rem;
4343 padding: .65rem .85rem;
4344 background: var(--paper-2, color-mix(in srgb, var(--ink) 4%, transparent));
4345 border: 1px solid var(--rule, rgba(0,0,0,.08));
4346 border-radius: 10px;
4347 margin: .75rem 0;
4348 text-decoration: none;
4349 color: var(--ink);
4350 transition: background .15s, border-color .15s;
4351}
4352.post-audio-external:hover {
4353 border-color: var(--accent);
4354 background: color-mix(in srgb, var(--accent) 5%, var(--paper-2, transparent));
4355}
4356.post-audio-external .pae-icon {
4357 flex-shrink: 0;
4358 width: 42px;
4359 height: 42px;
4360 border-radius: 8px;
4361 display: inline-flex;
4362 align-items: center;
4363 justify-content: center;
4364 background: var(--platform-color, #555);
4365 color: #fff;
4366 font-size: 1.2rem;
4367}
4368.post-audio-external .pae-icon-svg svg {
4369 width: 60%;
4370 height: 60%;
4371 fill: currentColor;
4372}
4373/* Per-platform vult de box net wat anders — brand-specifiek geoptimaliseerd */
4374.post-audio-external[data-platform="soundcloud"] .pae-icon-svg svg { width: 72%; height: auto; }
4375.post-audio-external[data-platform="spotify"] .pae-icon-svg svg { width: 72%; height: 72%; }
4376.post-audio-external[data-platform="youtube"] .pae-icon-svg svg { width: 68%; height: auto; }
4377.post-audio-external[data-platform="bandcamp"] .pae-icon-svg svg { width: 62%; height: auto; }
4378.post-audio-external[data-platform="apple"] .pae-icon-svg svg { width: 58%; height: 58%; }
4379.post-audio-external[data-platform="tidal"] .pae-icon-svg svg { width: 68%; height: auto; }
4380.post-audio-external[data-platform="deezer"] .pae-icon-svg svg { width: 65%; height: auto; }
4381.post-audio-external[data-platform="mixcloud"] .pae-icon-svg svg { width: 75%; height: auto; }
4382.post-audio-external[data-platform="soundcloud"] .pae-icon { background: #ff5500; }
4383.post-audio-external[data-platform="spotify"] .pae-icon { background: #1db954; }
4384.post-audio-external[data-platform="youtube"] .pae-icon { background: #ff0000; }
4385.post-audio-external[data-platform="bandcamp"] .pae-icon { background: #1da0c3; }
4386.post-audio-external[data-platform="apple"] .pae-icon { background: #fa243c; }
4387.post-audio-external[data-platform="tidal"] .pae-icon { background: #000; }
4388.post-audio-external[data-platform="deezer"] .pae-icon { background: #a238ff; }
4389.post-audio-external[data-platform="mixcloud"] .pae-icon { background: #314359; }
4390.post-audio-external[data-platform="other"] .pae-icon { background: #555; }
4391.post-audio-external .pae-meta {
4392 flex: 1;
4393 min-width: 0;
4394 display: flex;
4395 flex-direction: column;
4396 gap: 2px;
4397}
4398.post-audio-external .pae-title {
4399 display: block;
4400 font-weight: 600;
4401 overflow: hidden;
4402 text-overflow: ellipsis;
4403 white-space: nowrap;
4404 color: var(--ink);
4405}
4406.post-audio-external .pae-platform {
4407 display: block;
4408 font-size: .78rem;
4409 opacity: .65;
4410 text-transform: capitalize;
4411}
4412.post-audio-external .pae-go {
4413 flex-shrink: 0;
4414 opacity: .5;
4415 font-size: 1.1rem;
4416}
4417
4418/* =========================================================================
4419 v9.0 — Video player (inline)
4420 ========================================================================= */
4421
4422.post-video-figure {
4423 margin: 1.25rem 0;
4424 max-width: 100%;
4425}
4426
4427.post-video {
4428 display: block;
4429 width: 100%;
4430 max-width: 100%;
4431 height: auto;
4432 border-radius: 10px;
4433 background: #000;
4434 box-shadow: 0 4px 20px rgba(0,0,0,.15);
4435}
4436
4437.post-video-caption {
4438 margin-top: .5rem;
4439 font-size: .88rem;
4440 color: var(--ink-muted, color-mix(in srgb, var(--ink) 60%, transparent));
4441 text-align: center;
4442 line-height: 1.5;
4443}
4444
4445.post-video-caption strong {
4446 display: inline;
4447 font-weight: 600;
4448 color: var(--ink);
4449}
4450
4451@media (max-width: 640px) {
4452 .post-video-figure { margin: .75rem -.5rem; }
4453 .post-video { border-radius: 6px; }
4454}
4455
4456/* v9.3 — Floating "Bewerken" knop voor album-blokken in de post-editor.
4457 Verschijnt bij hover over een .post-album binnen #visual en wordt via JS
4458 geplaatst op de rechterbovenhoek van het blok. Niet in de opgeslagen HTML. */
4459.pcms-album-edit-overlay {
4460 position: absolute;
4461 z-index: 1000;
4462 transform: translateX(-100%);
4463 display: inline-flex;
4464 align-items: center;
4465 gap: .35rem;
4466 padding: .35rem .7rem;
4467 background: var(--accent, #c2410c);
4468 color: #fff;
4469 border: none;
4470 border-radius: 6px;
4471 font-size: .82rem;
4472 font-weight: 600;
4473 cursor: pointer;
4474 box-shadow: 0 4px 12px rgba(0, 0, 0, .18);
4475 transition: transform .12s ease, box-shadow .12s ease;
4476}
4477.pcms-album-edit-overlay:hover {
4478 transform: translateX(-100%) translateY(-1px);
4479 box-shadow: 0 6px 16px rgba(0, 0, 0, .24);
4480}
4481.pcms-album-edit-overlay:active {
4482 transform: translateX(-100%) translateY(0);
4483 box-shadow: 0 2px 6px rgba(0, 0, 0, .18);
4484}
4485
4486/* v9.3 — Drag-and-drop in de album-builder selected-lijst */
4487.ab-selected-row { cursor: default; }
4488.ab-selected-row .ab-drag-handle {
4489 display: inline-flex;
4490 align-items: center;
4491 justify-content: center;
4492 width: 18px;
4493 height: 100%;
4494 color: color-mix(in srgb, currentColor 40%, transparent);
4495 cursor: grab;
4496 user-select: none;
4497 font-size: .9rem;
4498 letter-spacing: -2px;
4499 flex-shrink: 0;
4500}
4501.ab-selected-row:hover .ab-drag-handle {
4502 color: color-mix(in srgb, currentColor 70%, transparent);
4503}
4504.ab-selected-row.is-dragging {
4505 opacity: .35;
4506 cursor: grabbing;
4507}
4508.ab-selected-row.is-dragging .ab-drag-handle { cursor: grabbing; }
4509/* Drop-indicator lijnen boven/onder de target rij */
4510.ab-selected-row.is-drag-target-before {
4511 box-shadow: 0 -2px 0 0 var(--accent, #c2410c) inset, 0 2px 0 0 var(--accent, #c2410c);
4512 /* Gebruik outline voor cross-browser zichtbaarheid */
4513 position: relative;
4514}
4515.ab-selected-row.is-drag-target-before::before {
4516 content: "";
4517 position: absolute;
4518 top: -1px; left: 0; right: 0;
4519 height: 2px;
4520 background: var(--accent, #c2410c);
4521 pointer-events: none;
4522}
4523.ab-selected-row.is-drag-target-after::after {
4524 content: "";
4525 position: absolute;
4526 bottom: -1px; left: 0; right: 0;
4527 height: 2px;
4528 background: var(--accent, #c2410c);
4529 pointer-events: none;
4530}
4531.ab-selected-row.is-drag-target-after { position: relative; }
4532
4533/* v9.3 — Playlist fallback states (missing of empty playlist reference in post) */
4534.post-playlist-missing, .post-playlist-empty {
4535 padding: 1rem;
4536 margin: .75rem 0;
4537 background: color-mix(in srgb, var(--accent, #c2410c) 8%, transparent);
4538 border: 1px dashed color-mix(in srgb, var(--accent, #c2410c) 30%, transparent);
4539 border-radius: 8px;
4540 font-size: .9rem;
4541}
4542.post-playlist-missing em, .post-playlist-empty em {
4543 opacity: .8;
4544}
4545
4546/* v9.3 — Install-app footer-knop */
4547.site-footer-install {
4548 display: flex;
4549 justify-content: center;
4550 padding: 1rem 1rem 1.25rem;
4551 border-top: 1px solid color-mix(in srgb, currentColor 8%, transparent);
4552 margin-top: .5rem;
4553}
4554
4555/* v9.4 — Cooler install-knop: gradient + shimmer + perfect centering.
4556 Twee kleur-stops voor diepte, animated shimmer-streep om aandacht te trekken,
4557 icon perfect verticaal gecentreerd via flex (was: net iets te hoog tov tekst). */
4558.install-app-btn {
4559 position: relative;
4560 display: inline-flex;
4561 align-items: center;
4562 justify-content: center;
4563 gap: .55rem;
4564 padding: .8rem 1.6rem;
4565 background: linear-gradient(135deg,
4566 var(--accent, #c2410c),
4567 color-mix(in srgb, var(--accent, #c2410c) 80%, #000));
4568 color: #fff;
4569 border: none;
4570 border-radius: 999px;
4571 font: inherit;
4572 font-weight: 600;
4573 font-size: .95rem;
4574 line-height: 1;
4575 letter-spacing: .01em;
4576 cursor: pointer;
4577 overflow: hidden;
4578 isolation: isolate;
4579 box-shadow:
4580 0 1px 0 rgba(255,255,255,.15) inset,
4581 0 -2px 0 rgba(0,0,0,.1) inset,
4582 0 4px 14px color-mix(in srgb, var(--accent, #c2410c) 40%, transparent),
4583 0 1px 3px rgba(0,0,0,.18);
4584 transition:
4585 transform .15s cubic-bezier(.4, 0, .2, 1),
4586 box-shadow .2s ease,
4587 filter .15s ease;
4588}
4589.install-app-btn svg {
4590 flex-shrink: 0;
4591 /* subtle bounce-on-hover trigger, separate animation */
4592 transition: transform .25s cubic-bezier(.34, 1.56, .64, 1);
4593}
4594.install-app-btn span {
4595 line-height: 1;
4596}
4597
4598/* Shimmer-streep die langzaam over de knop loopt — "alive" effect */
4599.install-app-btn::before {
4600 content: "";
4601 position: absolute;
4602 top: 0;
4603 left: -100%;
4604 width: 60%;
4605 height: 100%;
4606 background: linear-gradient(110deg,
4607 transparent 30%,
4608 rgba(255,255,255,.25) 50%,
4609 transparent 70%);
4610 z-index: -1;
4611 animation: pcmsInstallShimmer 4s ease-in-out infinite;
4612 pointer-events: none;
4613}
4614@keyframes pcmsInstallShimmer {
4615 0%, 35% { left: -100%; }
4616 65%, 100% { left: 200%; }
4617}
4618
4619.install-app-btn:hover {
4620 transform: translateY(-2px) scale(1.02);
4621 filter: brightness(1.06);
4622 box-shadow:
4623 0 1px 0 rgba(255,255,255,.2) inset,
4624 0 -2px 0 rgba(0,0,0,.1) inset,
4625 0 8px 24px color-mix(in srgb, var(--accent, #c2410c) 55%, transparent),
4626 0 2px 6px rgba(0,0,0,.2);
4627}
4628.install-app-btn:hover svg {
4629 transform: translateY(-2px);
4630}
4631.install-app-btn:active {
4632 transform: translateY(0) scale(.98);
4633 transition-duration: .05s;
4634}
4635.install-app-btn:focus-visible {
4636 outline: 2px solid var(--accent, #c2410c);
4637 outline-offset: 3px;
4638}
4639
4640/* Reduced motion: shimmer uit, alleen statisch */
4641@media (prefers-reduced-motion: reduce) {
4642 .install-app-btn::before { animation: none; left: -100%; }
4643 .install-app-btn:hover { transform: none; }
4644 .install-app-btn:hover svg { transform: none; }
4645}
4646
4647/* Install-instructions modal */
4648.install-modal {
4649 position: fixed;
4650 inset: 0;
4651 z-index: 10000;
4652 display: flex;
4653 align-items: center;
4654 justify-content: center;
4655 padding: 1rem;
4656}
4657.install-modal-backdrop {
4658 position: absolute;
4659 inset: 0;
4660 background: rgba(0,0,0,.55);
4661 backdrop-filter: blur(3px);
4662}
4663.install-modal-panel {
4664 position: relative;
4665 z-index: 1;
4666 background: var(--paper);
4667 color: var(--ink);
4668 border: 1px solid var(--rule);
4669 border-radius: 14px;
4670 padding: 1.5rem;
4671 max-width: 440px;
4672 width: 100%;
4673 max-height: 90vh;
4674 overflow-y: auto;
4675 box-shadow: 0 20px 60px rgba(0,0,0,.4);
4676}
4677.install-modal-panel h3 { font-size: 1.15rem; color: var(--ink); }
4678.install-modal-panel h4 {
4679 margin: 1rem 0 .4rem;
4680 font-size: .92rem;
4681 letter-spacing: .03em;
4682 text-transform: uppercase;
4683 opacity: .7;
4684 color: var(--ink);
4685}
4686.install-modal-panel p { color: var(--ink); }
4687.install-steps {
4688 margin: 0;
4689 padding-left: 1.35rem;
4690 display: flex;
4691 flex-direction: column;
4692 gap: .45rem;
4693 font-size: .95rem;
4694 line-height: 1.45;
4695 color: var(--ink);
4696}
4697.install-steps li::marker { color: var(--accent); font-weight: 700; }
4698.install-apk-block {
4699 margin-top: 1.25rem;
4700 padding-top: 1rem;
4701 border-top: 1px dashed var(--rule);
4702}
4703.install-apk-link {
4704 display: inline-flex;
4705 align-items: center;
4706 margin-top: .4rem;
4707 padding: .6rem 1rem;
4708 background: var(--accent);
4709 color: #fff;
4710 border-radius: 8px;
4711 text-decoration: none;
4712 font-weight: 600;
4713}
4714.install-apk-link:hover { filter: brightness(1.08); }
4715.install-modal-actions {
4716 display: flex;
4717 justify-content: flex-end;
4718 margin-top: 1.25rem;
4719}
4720.install-modal-actions .btn {
4721 padding: .5rem 1rem;
4722 background: var(--paper-2);
4723 border: 1px solid var(--rule);
4724 border-radius: 8px;
4725 color: var(--ink);
4726 cursor: pointer;
4727 font: inherit;
4728 font-weight: 500;
4729}
4730.install-modal-actions .btn:hover {
4731 background: color-mix(in srgb, var(--accent) 10%, var(--paper-2));
4732 border-color: var(--accent);
4733 color: var(--accent);
4734}
4735
4736@media (max-width: 520px) {
4737 .install-modal-panel { padding: 1.2rem; }
4738 .install-app-btn { width: 100%; justify-content: center; }
4739}
4740
4741/* v9.3 — Install-modal: choice-blocks met voor/nadelen */
4742.install-choice {
4743 margin-top: 1.25rem;
4744 padding: 1rem;
4745 border: 1px solid color-mix(in srgb, currentColor 15%, transparent);
4746 border-radius: 10px;
4747 background: color-mix(in srgb, currentColor 3%, transparent);
4748}
4749.install-choice + .install-choice { margin-top: 1rem; }
4750.install-choice h4 {
4751 margin: 0 0 .75rem;
4752 font-size: 1rem;
4753 letter-spacing: 0;
4754 text-transform: none;
4755 opacity: 1;
4756}
4757.install-pros-cons {
4758 display: flex;
4759 gap: 1rem;
4760 margin: .5rem 0 1rem;
4761}
4762.install-pros,
4763.install-cons {
4764 flex: 1;
4765 min-width: 0;
4766 font-size: .85rem;
4767 line-height: 1.45;
4768}
4769.install-pros strong,
4770.install-cons strong {
4771 display: block;
4772 margin-bottom: .35rem;
4773 font-size: .82rem;
4774 letter-spacing: .02em;
4775}
4776.install-pros strong { color: #16a34a; }
4777.install-cons strong { color: #dc2626; }
4778.install-pros ul,
4779.install-cons ul {
4780 margin: 0;
4781 padding-left: 1.1rem;
4782 display: flex;
4783 flex-direction: column;
4784 gap: .25rem;
4785}
4786.install-pros li::marker { color: #16a34a; }
4787.install-cons li::marker { color: #dc2626; }
4788
4789.install-choice-cta {
4790 display: inline-flex;
4791 align-items: center;
4792 justify-content: center;
4793 gap: .35rem;
4794 margin-top: .5rem;
4795 padding: .7rem 1.1rem;
4796 background: var(--accent, #c2410c);
4797 color: #fff;
4798 border: none;
4799 border-radius: 8px;
4800 text-decoration: none;
4801 font: inherit;
4802 font-weight: 600;
4803 font-size: .95rem;
4804 cursor: pointer;
4805 transition: filter .12s ease;
4806}
4807.install-choice-cta:hover { filter: brightness(1.08); }
4808.install-choice-note {
4809 margin: .5rem 0 0;
4810 padding: .6rem .8rem;
4811 background: color-mix(in srgb, currentColor 4%, transparent);
4812 border-left: 3px solid var(--accent, #c2410c);
4813 border-radius: 4px;
4814 font-size: .9rem;
4815 line-height: 1.45;
4816}
4817
4818@media (max-width: 520px) {
4819 .install-pros-cons { flex-direction: column; gap: .75rem; }
4820}
4821
4822/* v9.4 — Soft fade-overgang tussen posts bij navigatie.
4823 Fade-out is rustig (450ms): oude content vervaagt geleidelijk terwijl
4824 de scroll-naar-top loopt. Fade-in is snel (180ms) met een lichte blur-
4825 onscherp → scherp animatie zodat de nieuwe content niet abrupt verschijnt. */
4826#pcms-main {
4827 transition: opacity .45s ease-out;
4828}
4829#pcms-main.is-pcms-transitioning-out {
4830 opacity: 0;
4831}
4832#pcms-main.is-pcms-transitioning-in {
4833 opacity: 0;
4834 filter: blur(6px);
4835 animation: pcmsFadeIn .18s ease-out forwards;
4836 will-change: opacity, filter;
4837}
4838@keyframes pcmsFadeIn {
4839 from { opacity: 0; filter: blur(6px); }
4840 to { opacity: 1; filter: blur(0); }
4841}
4842
4843/* Respecteer reduced-motion voorkeur (iOS/Android accessibility setting) */
4844@media (prefers-reduced-motion: reduce) {
4845 #pcms-main {
4846 transition: opacity .15s ease-out;
4847 }
4848 #pcms-main.is-pcms-transitioning-in {
4849 filter: none;
4850 animation: none;
4851 opacity: 1;
4852 }
4853}
4854
4855/* === Fediverse interactions — inherits the native .comment styling === */
4856.post-fediverse .fedi-stats { display: flex; gap: .45rem; margin: .35rem 0 1.5rem; align-items: center; }
4857.post-fediverse .fedi-stat {
4858 display: inline-flex; align-items: center; gap: .4rem;
4859 padding: .32rem .7rem; border-radius: 999px; font-size: .85rem; line-height: 1;
4860 font-variant-numeric: tabular-nums;
4861 color: var(--ink-muted); background: transparent;
4862 border: 1px solid var(--rule);
4863}
4864.post-fediverse .fedi-stat svg { width: 15px; height: 15px; }
4865.post-fediverse .fedi-stat-btn { cursor: pointer; font: inherit; line-height: 1; transition: color .15s, border-color .15s, background .15s; }
4866.post-fediverse .fedi-stat-btn:hover { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 55%, var(--rule)); background: var(--accent-tint); }
4867.post-fediverse .fedi-stat-btn:hover svg { fill: color-mix(in srgb, var(--accent) 22%, transparent); }
4868.post-fediverse .fedi-handle { color: var(--ink-soft, #888); font-size: .82rem; }
4869.post-fediverse .comment-content p { margin: .2rem 0; }
4870.post-fediverse .comment-content p:first-child { margin-top: 0; }
4871.post-fediverse .comment-content p:last-child { margin-bottom: 0; }
4872/* reply toggle: a plain "Reageer" action like the comment buttons (no triangle) */
4873.post-fediverse .fedi-reply-toggle { list-style: none; cursor: pointer; display: inline-block; }
4874.post-fediverse .fedi-reply-toggle::-webkit-details-marker { display: none; }
4875.post-fediverse details[open] .fedi-reply-toggle { margin-bottom: .5rem; }
4876
4877/* Reply-via-fediverse CTA on post pages */
4878.post-fediverse-cta { margin: 1.75rem 0; }
4879.fedi-remote-reply-btn { display: inline-flex; align-items: center; gap: .45rem; }
4880.post-fediverse-cta .fedi-remote-reply-btn {
4881 border: 1px solid color-mix(in srgb, var(--accent, #888) 55%, transparent);
4882 background: color-mix(in srgb, var(--accent, #888) 10%, transparent);
4883 color: var(--ink, inherit); border-radius: 999px; padding: .5rem 1.05rem;
4884 font-weight: 600; cursor: pointer; transition: background .15s ease;
4885}
4886.post-fediverse-cta .fedi-remote-reply-btn:hover { background: color-mix(in srgb, var(--accent, #888) 22%, transparent); }
4887.post-fediverse-cta .fedi-remote-reply-btn svg { color: var(--accent, currentColor); }
4888.post-fediverse .comment-actions .fedi-remote-reply-btn { gap: .3rem; }
4889
4890/* Inline "reply via fediverse" address form (replaces the browser prompt) */
4891.fedi-remote-form {
4892 position: absolute; z-index: 60; display: inline-flex; align-items: center; gap: .4rem;
4893 padding: .4rem; border-radius: 999px;
4894 background: var(--paper-2, var(--paper, #fff));
4895 border: 1px solid color-mix(in srgb, var(--ink, #000) 12%, transparent);
4896 box-shadow: 0 10px 30px rgba(0,0,0,.28);
4897}
4898.fedi-remote-form input {
4899 height: 2.2rem; padding: 0 .9rem; border-radius: 999px; font: inherit; min-width: 230px;
4900 border: 1px solid color-mix(in srgb, var(--ink, #000) 18%, transparent);
4901 background: color-mix(in srgb, var(--ink, #000) 4%, transparent); color: var(--ink, #000);
4902}
4903.fedi-remote-form input::placeholder { color: var(--ink-soft, #999); }
4904.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); }
4905.fedi-remote-form .fedi-remote-go {
4906 height: 2.2rem; min-width: 2.2rem; padding: 0 .85rem; border-radius: 999px;
4907 display: inline-flex; align-items: center; justify-content: center; font-size: 1rem;
4908}
4909.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; }
4910.fedi-remote-form .fedi-remote-cancel:hover { color: var(--ink, #000); }
4911
4912/* ── NSFW / sensitive content — blur + click to reveal ───────────────── */
4913.nsfw-media { position: relative; }
4914.nsfw-veil {
4915 position: absolute; inset: 0; z-index: 4; cursor: pointer; border-radius: inherit;
4916 display: flex; flex-direction: column; align-items: center; justify-content: center;
4917 gap: .5rem; padding: .75rem; text-align: center;
4918 background: color-mix(in srgb, var(--paper, #14141a) 50%, transparent);
4919 backdrop-filter: blur(22px) saturate(.6); -webkit-backdrop-filter: blur(22px) saturate(.6);
4920}
4921.nsfw-media.is-shown > .nsfw-veil { display: none; }
4922.nsfw-veil-label { font-weight: 700; font-size: .82rem; color: var(--ink, #f3f1ea); text-shadow: 0 1px 2px rgba(0,0,0,.5); }
4923.nsfw-veil-btn {
4924 font-size: .72rem; font-weight: 600; padding: .3rem .8rem; border-radius: 999px;
4925 border: 1px solid color-mix(in srgb, var(--ink, #fff) 55%, transparent);
4926 background: color-mix(in srgb, var(--paper, #000) 35%, transparent); color: var(--ink, #f3f1ea);
4927}
4928/* Post page: blur cover + body behind a content-warning banner until revealed */
4929.nsfw-gate .post-cover,
4930.nsfw-gate .post-content { filter: blur(26px); pointer-events: none; user-select: none; transition: filter .2s ease; }
4931.nsfw-gate.is-shown .post-cover,
4932.nsfw-gate.is-shown .post-content { filter: none; pointer-events: auto; user-select: auto; }
4933.nsfw-banner {
4934 display: flex; align-items: center; gap: .7rem; flex-wrap: wrap; margin: 0 0 1.5rem;
4935 padding: .8rem 1rem; border-radius: 12px;
4936 border: 1px solid color-mix(in srgb, var(--accent, #e8b04b) 45%, transparent);
4937 background: color-mix(in srgb, var(--accent, #e8b04b) 9%, transparent);
4938}
4939.nsfw-gate.is-shown .nsfw-banner { display: none; }
4940.nsfw-banner-icon { font-size: 1.2rem; }
4941.nsfw-banner-text { font-weight: 600; font-size: .92rem; color: var(--ink); }
4942.nsfw-banner-btn {
4943 margin-left: auto; cursor: pointer; font: inherit; font-size: .82rem; font-weight: 600;
4944 padding: .4rem 1rem; border-radius: 999px; border: 0;
4945 background: var(--accent, #e8b04b); color: #1a1205;
4946}
Note: See TracBrowser for help on using the repository browser.