source: Klonkt/src/assets/css/style.css@ 7cf8144

main
Last change on this file since 7cf8144 was 7cf8144, checked in by Bart <bart@…>, 3 weeks ago

Lezen is een weergave van de feed, geen eigen plek

/read was een route met een eigen shell: eigen pagina, eigen chrome-gedrag, en
op een site zonder berichten een 404 -- een dode knop in de switcher. Nu is het
wat het altijd had moeten zijn: een derde waarde van body[data-feed-view], naast
timeline en grid. Dezelfde berichten, andere vorm.

De feed stuurt ze alledrie mee en CSS kiest, precies zoals timeline/grid dat al
deden. Het lijf loopt door PostAccessService, dus een gesloten poort levert ook
hier geen tekst op. "Meer laden" vult de leesstroom OOB mee aan, net als de
tegels.

DE LEGE STAAT zit in de :has(.feed-reader) op de verbergregel. Zonder berichten
rendert de leessectie niet, en dan blijft de tijdlijn staan -- want daar staat
"nog niets geschreven" met de knop om te beginnen. Zonder die voorwaarde was
Lezen op een verse site een wit scherm. Feeds zonder leessectie (cirkel,
archief) houden om dezelfde reden gewoon hun tijdlijn.

Wat weg kon, en dat is de winst:

  • de route, pages/read.ejs, en 'on-read' als page-class;
  • mod/read.js van 222 naar 51 regels. Het ophalen van buren, het corrigeren van de scrollpositie bij invoegen en het onderbreken van het snappen zijn niet opgelost maar OVERBODIG: de feed levert de berichten al. Wat blijft is de tik.
  • read.end en read.load_error: het script plaatst geen zinnen meer.

De balken schuiven niet meer weg. Dat was mooi op een eigen scherm, maar hier
zou het de switcher verbergen waarmee je net koos -- en dan kun je niet terug.

MOD_V naar 4, style.css naar v70.

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

  • Property mode set to 100644
File size: 153.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/* Actieve state: puur afgeleid van body[data-feed-view]. Geen .is-active class meer.
2375 Niet op de Archive-pagina: daar is geen "huidige" timeline/grid-keuze, dus beide
2376 knoppen blijven neutraal (grijs). */
2377/* Actieve Tijdlijn/Grid-state wordt nu gestuurd via [aria-selected="true"] (gezet
2378 door syncAria, die óók op htmx:afterSettle draait) i.p.v. body[data-feed-view].
2379 Reden: body-class/attribuut-CSS pakte niet betrouwbaar na een htmx-OOB-swap;
2380 een element-attribuut wel. De witte active-regel staat in shared-styles. */
2381.view-switch-btn .icon { width: 1rem; height: 1rem; }
2382
2383/* -------- FEED TOGGLE VIA BODY --------
2384 Grid-modus werkt op de feed (home, cirkel). Het ARCHIEF negeert de grid-keuze
2385 bewust: dat is altijd de chronologische jaar/maand-lijst (de switcher is daar
2386 grijs en springt bij klik terug naar de feed). Post-pagina's tonen de
2387 feed-timeline article sowieso altijd. Alle andere body-classes negeren
2388 data-feed-view en houden timeline visible. */
2389body.on-home[data-feed-view="grid"] .feed-timeline,
2390body.on-home[data-feed-view="grid"] .pagination,
2391body.on-home[data-feed-view="grid"] .related-posts,
2392body.on-home[data-feed-view="grid"] .article-footer,
2393body.on-cirkel[data-feed-view="grid"] .feed-timeline {
2394 display: none !important;
2395}
2396/* Grid-sectie alleen zichtbaar op de feed in grid-mode (NIET op archief) */
2397.feed-grid { display: none; }
2398body.on-home[data-feed-view="grid"] .feed-grid,
2399body.on-cirkel[data-feed-view="grid"] .feed-grid { display: block; }
2400
2401/* -------- LEESWEERGAVE (data-feed-view="reader") --------
2402 Dezelfde berichten als de tijdlijn, maar heel: één per scherm, grenzen door
2403 scroll-snapping. GEEN eigen route en geen eigen shell -- de balken blijven
2404 staan, want je bent nog op de feed en moet terug kunnen schakelen.
2405 Pagina's zonder .feed-reader (cirkel, archief, post) negeren de keuze en
2406 houden hun tijdlijn: er is hieronder simpelweg geen regel die die daar
2407 verbergt. Zo is Lezen nooit een leeg scherm. */
2408.feed-reader { display: none; }
2409body.on-home[data-feed-view="reader"] .feed-reader { display: block; }
2410/* :has(.feed-reader) is hier de LEGE STAAT, niet een truc. Zonder berichten
2411 rendert de leessectie niet, en dan mag de tijdlijn niet verborgen worden --
2412 want dáár staat "nog niets geschreven" met de knop om te beginnen. Zonder deze
2413 voorwaarde is Lezen op een verse site een wit scherm. Hetzelfde geldt voor
2414 feeds die (nog) geen leessectie hebben. */
2415body.on-home[data-feed-view="reader"]:has(.feed-reader) .feed-timeline,
2416body.on-home[data-feed-view="reader"]:has(.feed-reader) .feed-grid,
2417body.on-home[data-feed-view="reader"]:has(.feed-reader) .pagination,
2418body.on-home[data-feed-view="reader"]:has(.feed-reader) .related-posts,
2419body.on-home[data-feed-view="reader"]:has(.feed-reader) .article-footer {
2420 display: none !important;
2421}
2422
2423/* Snappen doet de SCROLLCONTAINER, en dat is het document -- niet .read-stream,
2424 die heeft overflow: visible en scrollt zelf niet. Proximity en geen mandatory:
2425 in een bericht dat langer is dan het scherm moet je rustig door kunnen lezen. */
2426html:has(body.on-home[data-feed-view="reader"]) { scroll-snap-type: y proximity; }
2427/* En de browser niet óók laten compenseren als Load more er berichten bij zet:
2428 Chrome en Firefox schuiven bij invoegen zelf mee (scroll anchoring), en dat
2429 vecht met het snappen. */
2430html:has(body.on-home[data-feed-view="reader"]),
2431.feed-reader .read-stream { overflow-anchor: none; }
2432
2433.feed-reader .read-post {
2434 scroll-snap-align: start;
2435 scroll-snap-stop: normal;
2436 min-height: 100svh;
2437 max-width: 46rem;
2438 margin: 0 auto;
2439 /* De onderrand loopt achter de vaste tabbalk door; deze padding houdt de
2440 TEKST erboven. */
2441 padding: 2rem 1.2rem 4rem;
2442 box-sizing: border-box;
2443}
2444/* Een lijn tussen twee berichten: zonder grens is een stroom een lange brij. */
2445.feed-reader .read-post + .read-post { border-top: 1px solid color-mix(in srgb, currentColor 12%, transparent); }
2446
2447.feed-reader .read-head { padding-bottom: .5rem; }
2448.feed-reader .read-title { font-size: clamp(1.6rem, 4vw, 2.4rem); line-height: 1.15; margin: 0 0 .3rem; }
2449/* De titel is een link, maar mag er niet als een link uitzien: dit is een
2450 leesscherm, geen index. */
2451.feed-reader .read-title a { color: inherit; text-decoration: none; }
2452.feed-reader .read-title a:hover,
2453.feed-reader .read-title a:focus-visible { text-decoration: underline; }
2454.feed-reader .read-when { font-size: .85rem; opacity: .6; margin: 0; }
2455
2456.feed-reader .read-foot { margin-top: 2rem; }
2457.feed-reader .read-open {
2458 display: inline-block; font-size: .9rem; opacity: .75;
2459 text-decoration: none; border-bottom: 1px solid currentColor; padding-bottom: 1px;
2460}
2461.feed-reader .read-open:hover,
2462.feed-reader .read-open:focus-visible { opacity: 1; }
2463
2464@media (prefers-reduced-motion: reduce) {
2465 html:has(body.on-home[data-feed-view="reader"]) { scroll-snap-type: none; }
2466}
2467
2468/* -------- GRID VIEW TILES (Instagram-stijl) -------- */
2469.feed-grid {
2470 padding: 1rem 0 2rem;
2471}
2472.grid-tiles {
2473 display: grid;
2474 gap: 4px;
2475 grid-template-columns: repeat(2, 1fr);
2476}
2477.grid-tile {
2478 position: relative;
2479 display: block;
2480 aspect-ratio: 1;
2481 background-size: cover;
2482 background-position: center;
2483 background-color: var(--paper-2);
2484 overflow: hidden;
2485 text-decoration: none;
2486 color: var(--ink);
2487 transition: transform .2s;
2488 cursor: pointer;
2489 -webkit-tap-highlight-color: rgba(0,0,0,.1);
2490}
2491
2492/* Transparent covers (PNG logos etc.) sit on white so they don't blend into a dark
2493 theme. The white is on the IMG, so the tile's accent-gradient placeholder shows
2494 while the image is still loading. */
2495.post-cover img,
2496.post-list-cover img,
2497.grid-tile-img { background-color: #fff; }
2498/* Accent-gradient placeholder shown while the cover image loads (the image fades in
2499 over it), instead of a white flash on cover tiles. */
2500.grid-tile:not(.grid-tile-gradient) {
2501 background-image: linear-gradient(135deg,
2502 color-mix(in srgb, var(--accent, #888) 22%, var(--paper-2, var(--paper))) 0%,
2503 color-mix(in srgb, var(--accent, #888) 6%, var(--paper-2, var(--paper))) 100%);
2504}
2505/* Cover as a real <img> (not background-image): browsers downsample <img> with the
2506 high-quality image pipeline, so high-res line-art covers don't go jagged when shrunk.
2507 Fades in on load (.is-loading removed) so the placeholder shows meanwhile. */
2508.grid-tile-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; transition: opacity .4s ease; }
2509.grid-tile-img.is-loading { opacity: 0; }
2510/* Audio tile (Shaer, Robins vraag 30-7): the waveform PNG is white on
2511 transparent and floats OVER the tile's own hue gradient, so every audio
2512 post keeps its color and gets its shape. Wave and title each get their
2513 own band (wave upper, title lower): centering both stacked them right
2514 through each other (Robins schermafdruk). */
2515.grid-tile-img.grid-tile-wave {
2516 background-color: transparent;
2517 object-fit: contain;
2518 /* explicit box, not auto: an absolutely positioned img falls back to its
2519 intrinsic size when width/height are auto, collapsing the band */
2520 top: 8%; left: 8%; right: auto; bottom: auto;
2521 width: 84%; height: 46%;
2522 opacity: .85;
2523}
2524.grid-tile-audio .grid-tile-title { position: absolute; left: 10%; right: 10%; top: 60%; }
2525.grid-tile-audio .grid-tile-gradient-src { position: absolute; left: 10%; right: 10%; top: 76%; }
2526/* Cover videos are decorative, not players: let clicks + right-click pass through to the
2527 tile link so you get the normal link menu (not the browser's <video> menu/controls).
2528 Autoplay is independent of pointer-events, so the video still plays. */
2529video.grid-tile-img,
2530.post-list-cover video,
2531.post-cover video { pointer-events: none; }
2532.grid-tile:hover { transform: scale(0.98); }
2533.grid-tile-overlay {
2534 position: absolute;
2535 inset: 0;
2536 padding: .6rem;
2537 display: flex;
2538 flex-direction: column;
2539 justify-content: flex-end;
2540 align-items: flex-start;
2541 background: linear-gradient(to top, rgba(0,0,0,.65) 0%, rgba(0,0,0,0) 50%);
2542 opacity: 0;
2543 transition: opacity .2s;
2544 pointer-events: none; /* klik moet naar de <a> eronder gaan, niet naar de overlay */
2545}
2546/* Bron-site (cirkel-feed): toont bij hover "van <site>" onder de titel. */
2547/* Source label: small text that wraps to 2 lines if needed, with a big chain icon
2548 beside it (the text was 1.44rem — bigger than the title — and overflowed on mobile). */
2549.grid-tile-overlay-src {
2550 color: #fff; opacity: .85;
2551 font-size: .72rem; line-height: 1.2; margin-top: .25rem;
2552 display: flex; align-items: center; gap: .3rem; width: 100%;
2553}
2554.grid-tile-overlay-src::before { content: "⛓"; font-size: 1.3rem; line-height: 1; flex: 0 0 auto; }
2555.grid-tile-gradient-src {
2556 margin-top: .35rem; font-size: .72rem; line-height: 1.2; opacity: .85;
2557 color: var(--ink-soft);
2558 display: flex; align-items: center; gap: .3rem; width: 100%;
2559}
2560.grid-tile-gradient-src::before { content: "⛓"; font-size: 1.3rem; line-height: 1; flex: 0 0 auto; }
2561.grid-tile-overlay strong {
2562 color: #fff;
2563 font-family: var(--font-display);
2564 font-size: .9rem;
2565 font-weight: 500;
2566 line-height: 1.15;
2567 display: -webkit-box;
2568 -webkit-line-clamp: 3;
2569 -webkit-box-orient: vertical;
2570 overflow: hidden;
2571}
2572@media (hover: hover) {
2573 .grid-tile:hover .grid-tile-overlay { opacity: 1; }
2574}
2575@media (hover: none) {
2576 /* Op touch-devices altijd overlay tonen zodat titels zichtbaar zijn */
2577 .grid-tile-overlay { opacity: 1; background: linear-gradient(to top, rgba(0,0,0,.7) 0%, rgba(0,0,0,0) 70%); }
2578}
2579
2580.grid-tile-gradient {
2581 background-image: none;
2582 background-color: hsl(var(--tile-hue, 30), 40%, 85%);
2583 background-image: linear-gradient(135deg, hsl(var(--tile-hue, 30), 45%, 88%), hsl(calc(var(--tile-hue, 30) + 30), 35%, 75%));
2584 display: flex;
2585 flex-direction: column;
2586 align-items: center;
2587 justify-content: center;
2588 padding: 1rem;
2589 text-align: center;
2590}
2591[data-theme="dark"] .grid-tile-gradient,
2592.grid-tile-gradient[data-theme="dark"] {
2593 background-image: linear-gradient(135deg, hsl(var(--tile-hue, 30), 30%, 18%), hsl(calc(var(--tile-hue, 30) + 30), 25%, 12%));
2594}
2595.grid-tile-title {
2596 font-family: var(--font-display);
2597 font-size: 1rem;
2598 font-weight: 500;
2599 color: var(--ink);
2600 line-height: 1.2;
2601 display: -webkit-box;
2602 -webkit-line-clamp: 4;
2603 -webkit-box-orient: vertical;
2604 overflow: hidden;
2605 z-index: 1;
2606 /* Federated link posts can have a long bare URL as their title — break it so it wraps
2607 inside the tile and clamps cleanly instead of overflowing past both edges. */
2608 max-width: 100%;
2609 overflow-wrap: anywhere;
2610 word-break: break-word;
2611 hyphens: auto;
2612}
2613
2614.grid-tile-pin {
2615 position: absolute;
2616 top: .5rem;
2617 right: .5rem;
2618 display: inline-flex;
2619 align-items: center;
2620 gap: .25rem;
2621 padding: .2rem .55rem;
2622 background: var(--accent);
2623 color: #fff;
2624 border-radius: 999px;
2625 font-family: var(--font-ui);
2626 font-size: .65rem;
2627 font-weight: 700;
2628 text-transform: uppercase;
2629 letter-spacing: .06em;
2630 z-index: 3;
2631 box-shadow: 0 2px 6px rgba(0,0,0,.3);
2632 pointer-events: none;
2633}
2634.grid-tile-pin svg {
2635 width: .95em;
2636 height: .95em;
2637 margin-top: -1px;
2638}
2639/* Pinned/boosted tile: accent ring. An outline on the tile is painted UNDER the absolute
2640 cover <img>, so draw the ring as a pseudo-element overlay ABOVE the image (z-index above
2641 the img, below the corner badges + nsfw veil). */
2642.grid-tile.is-pinned { position: relative; z-index: 1; }
2643.grid-tile.is-pinned::after {
2644 content: '';
2645 position: absolute;
2646 inset: 0;
2647 border: 3px solid var(--accent);
2648 border-radius: inherit;
2649 pointer-events: none;
2650 z-index: 1;
2651}
2652.grid-tile-type {
2653 position: absolute;
2654 top: .4rem;
2655 left: .4rem;
2656 padding: .15rem .5rem;
2657 background: rgba(0,0,0,.55);
2658 color: #fff;
2659 border-radius: 999px;
2660 font-family: var(--font-ui);
2661 font-size: .6rem;
2662 font-weight: 600;
2663 text-transform: uppercase;
2664 letter-spacing: .05em;
2665 z-index: 2;
2666}
2667
2668@media (min-width: 600px) {
2669 .grid-tiles { grid-template-columns: repeat(3, 1fr); }
2670}
2671@media (min-width: 900px) {
2672 .grid-tiles { grid-template-columns: repeat(3, 1fr); gap: 8px; }
2673}
2674
2675/* -------- POST-TYPE SPECIFIEKE LAYOUTS -------- */
2676
2677/* Foto-post: beeld prominent, geen titel bovenaan, caption onder */
2678.feed-timeline[data-post-type="foto"] .post-title {
2679 font-size: 1.1rem;
2680 color: var(--ink-muted);
2681 font-weight: 400;
2682}
2683.feed-timeline[data-post-type="foto"] .post-cover {
2684 margin: 0 -1rem 1rem;
2685 border-radius: 0;
2686}
2687.feed-timeline[data-post-type="foto"] .post-cover img {
2688 width: 100%;
2689 border-radius: 0;
2690}
2691
2692/* Post-caption onder de cover */
2693.post-caption {
2694 font-family: var(--font-body);
2695 font-size: 1rem;
2696 color: var(--ink);
2697 line-height: 1.5;
2698 margin: 0 0 1.25rem;
2699 padding: 0 0 1rem;
2700 border-bottom: 1px solid var(--rule);
2701 white-space: pre-wrap;
2702}
2703.feed-timeline[data-post-type="foto"] .post-caption {
2704 font-size: 1.05rem;
2705 margin-top: -.5rem;
2706 padding-bottom: 1.25rem;
2707}
2708
2709/* Audio/video posts — type-chip helder, content eronder zoals normaal */
2710.feed-timeline[data-post-type="audio"] .post-title,
2711.feed-timeline[data-post-type="video"] .post-title {
2712 font-size: 1.5rem;
2713}
2714
2715@media (min-width: 768px) {
2716 .feed-timeline[data-post-type="foto"] .post-cover {
2717 margin: 0 0 1.5rem;
2718 border-radius: var(--radius);
2719 }
2720}
2721
2722/* -------- ADMIN EDIT-BUTTON op post-view (alleen zichtbaar voor ingelogde admin) -------- */
2723.post-edit-btn {
2724 position: absolute;
2725 top: 1rem;
2726 right: 1rem;
2727 display: inline-flex;
2728 align-items: center;
2729 justify-content: center;
2730 width: 44px;
2731 height: 44px;
2732 background: var(--paper);
2733 border: 1px solid var(--rule);
2734 border-radius: 50%;
2735 color: var(--ink-muted);
2736 text-decoration: none;
2737 box-shadow: 0 2px 8px rgba(0,0,0,.08);
2738 transition: background .15s, color .15s, transform .15s, border-color .15s;
2739 z-index: 10;
2740}
2741.post-edit-btn:hover {
2742 background: var(--accent);
2743 border-color: var(--accent);
2744 color: var(--paper);
2745 transform: scale(1.05);
2746}
2747.post-edit-btn .icon {
2748 width: 1.1rem;
2749 height: 1.1rem;
2750}
2751/* Zorg dat de article relative is zodat absolute positionering werkt */
2752.feed-timeline { position: relative; }
2753
2754@media (min-width: 768px) {
2755 .post-edit-btn {
2756 top: 1.5rem;
2757 right: 1.5rem;
2758 }
2759}
2760
2761/* ============================================================
2762 v8.0 — ACCENT SPAN + POST-TABLE (published posts)
2763 ============================================================ */
2764.post span.accent,
2765.post-content span.accent,
2766article span.accent,
2767page-container span.accent {
2768 color: var(--accent);
2769 font-weight: 500;
2770}
2771
2772.post-table,
2773article table.post-table {
2774 width: 100%;
2775 max-width: 100%;
2776 border-collapse: collapse;
2777 margin: 1.25rem 0;
2778 font-size: .95rem;
2779 display: block;
2780 overflow-x: auto;
2781 -webkit-overflow-scrolling: touch;
2782}
2783.post-table thead { background: color-mix(in srgb, var(--accent) 10%, transparent); }
2784.post-table th,
2785.post-table td {
2786 padding: .6rem .8rem;
2787 text-align: left;
2788 border: 1px solid var(--rule);
2789 vertical-align: top;
2790}
2791.post-table th {
2792 font-family: var(--font-ui);
2793 font-weight: 600;
2794 font-size: .88rem;
2795 color: var(--ink);
2796 letter-spacing: .02em;
2797}
2798.post-table tbody tr:nth-child(even) {
2799 background: color-mix(in srgb, var(--ink) 3%, transparent);
2800}
2801@media (min-width: 700px) {
2802 .post-table { display: table; overflow: visible; }
2803}
2804
2805/* ============================================================
2806 v8.0 fix — grid-cols picker (desktop only) + grid col overrides
2807 ============================================================ */
2808
2809/* Switcher-wrap bevat nu ook de cols-picker; layout side-by-side */
2810.view-switcher-wrap .container {
2811 display: flex;
2812 align-items: center;
2813 justify-content: center;
2814 gap: 1rem;
2815 flex-wrap: wrap;
2816}
2817
2818/* Solo / Cirkel scope-switcher (alleen in circle-modus) — segmented toggle, centraal.
2819 Hoge specificiteit (+ !important op tekst) zodat 'ie globale link-stijlen wint. */
2820.view-switcher-wrap .feed-scope {
2821 display: inline-flex;
2822 background: var(--paper-2);
2823 border: 1px solid var(--rule);
2824 border-radius: 999px;
2825 padding: 3px;
2826}
2827.view-switcher-wrap .feed-scope-btn {
2828 display: inline-flex;
2829 align-items: center;
2830 padding: .32rem .95rem;
2831 min-height: 30px;
2832 border: none !important;
2833 border-radius: 999px !important;
2834 background: transparent !important;
2835 color: var(--ink-muted) !important;
2836 font-family: var(--font-ui);
2837 font-size: .82rem;
2838 font-weight: 500 !important;
2839 text-decoration: none !important;
2840 cursor: pointer;
2841 transition: all .15s;
2842}
2843.view-switcher-wrap .feed-scope-btn:hover { color: var(--ink) !important; }
2844.view-switcher-wrap .feed-scope-btn.is-active {
2845 background: var(--ink) !important;
2846 color: var(--paper) !important;
2847}
2848
2849.grid-cols-picker {
2850 display: none; /* default hidden — desktop + grid-active maakt 'm zichtbaar */
2851 gap: 2px;
2852 padding: 0;
2853}
2854.grid-cols-btn {
2855 display: inline-flex;
2856 align-items: center;
2857 justify-content: center;
2858 min-width: 36px;
2859 height: 32px;
2860 padding: 0 .6rem;
2861 background: transparent;
2862 border: 1px solid var(--rule);
2863 color: var(--ink-muted);
2864 font-family: var(--font-ui);
2865 font-size: .85rem;
2866 font-weight: 500;
2867 cursor: pointer;
2868 transition: all .12s;
2869}
2870.grid-cols-btn:first-child { border-radius: 999px 0 0 999px; }
2871.grid-cols-btn:last-child { border-radius: 0 999px 999px 0; }
2872.grid-cols-btn:not(:first-child):not(:last-child) { border-left: none; border-right: none; }
2873.grid-cols-btn:hover { color: var(--ink); }
2874/* Active state puur via body[data-grid-cols] — geen is-active-class meer. */
2875body[data-grid-cols="2"] .grid-cols-btn[data-cols="2"],
2876body[data-grid-cols="3"] .grid-cols-btn[data-cols="3"],
2877body[data-grid-cols="4"] .grid-cols-btn[data-cols="4"] {
2878 background: var(--ink);
2879 color: var(--paper);
2880 border-color: var(--ink);
2881}
2882
2883/* Desktop + grid-view → toon cols-picker (op de home-feed; niet op archief) */
2884@media (min-width: 600px) {
2885 body.on-home[data-feed-view="grid"] .grid-cols-picker {
2886 display: inline-flex;
2887 }
2888}
2889
2890/* Kolom-overrides op desktop. Mobiel negeert dit (staat vast op 2). Geldt op ELKE
2891 feed met grid (home én cirkel/tag/type/user) — scope op .feed-grid .grid-tiles. */
2892@media (min-width: 600px) {
2893 body[data-grid-cols="2"] .feed-grid .grid-tiles { grid-template-columns: repeat(2, 1fr); }
2894 body[data-grid-cols="3"] .feed-grid .grid-tiles { grid-template-columns: repeat(3, 1fr); }
2895 body[data-grid-cols="4"] .feed-grid .grid-tiles { grid-template-columns: repeat(4, 1fr); }
2896}
2897
2898/* Gradient-tile: iets meer contrast voor light + dark mode zodat titel altijd leesbaar is */
2899.grid-tile-gradient {
2900 background-image: linear-gradient(135deg,
2901 hsl(var(--tile-hue, 30), 55%, 72%),
2902 hsl(calc(var(--tile-hue, 30) + 40), 45%, 60%));
2903}
2904[data-theme="dark"] .grid-tile-gradient {
2905 background-image: linear-gradient(135deg,
2906 hsl(var(--tile-hue, 30), 40%, 30%),
2907 hsl(calc(var(--tile-hue, 30) + 40), 30%, 18%));
2908}
2909.grid-tile-gradient .grid-tile-title {
2910 color: #fff;
2911 text-shadow: 0 1px 3px rgba(0,0,0,.25);
2912}
2913[data-theme="dark"] .grid-tile-gradient .grid-tile-title {
2914 color: #fff;
2915 text-shadow: 0 1px 2px rgba(0,0,0,.5);
2916}
2917
2918/* ============================================================
2919 v8.0.2 — COMPACT DESIGN OVERRIDES
2920 Tighter masthead, padding, margins overall. Profiel-header
2921 collapse/expand blijft zoals 'ie was.
2922 ============================================================ */
2923
2924/* Masthead: compacter */
2925.masthead { padding: calc(.55rem + var(--ios-safe-top, 0px)) 0 .55rem; }
2926.masthead-inner { gap: 1rem; }
2927.site-title { font-size: 1.25rem; }
2928.nav-link, .nav-btn { padding: .4rem .7rem; min-height: 2rem; font-size: .82rem; }
2929
2930/* Main content padding */
2931main { padding-top: 1rem; }
2932.page { padding-block: 1rem 1.75rem; }
2933
2934/* View switcher-bar strakker */
2935.view-switcher { padding: .4rem 0; gap: .3rem; }
2936.view-switch-btn { padding: .4rem .85rem; min-height: 38px; font-size: .8rem; }
2937.grid-cols-btn { min-width: 32px; height: 28px; padding: 0 .5rem; font-size: .8rem; }
2938
2939/* Post header spacing terug */
2940.post-header { margin: 0 0 1.25rem; }
2941.post-title { margin-bottom: .35rem; }
2942.post-meta { font-size: .78rem; }
2943.post-tags { margin-top: .6rem; gap: .3rem; }
2944.post-tag { font-size: .7rem; padding: .15rem .55rem; }
2945
2946/* Article footer + pagination compacter */
2947.article-footer { padding-top: 1.25rem; margin-top: 1.5rem; }
2948.pagination { padding-block: 1.25rem 2rem; margin-top: 1.5rem; }
2949.pagination-item { padding: .75rem .95rem; min-height: 4rem; }
2950.pagination-title { font-size: .95rem; }
2951
2952/* Site footer compacter */
2953.site-footer { padding: 1.25rem 0 calc(1.25rem + env(safe-area-inset-bottom, 0px)); margin-top: 2rem; font-size: .78rem; }
2954.site-footer-inner { gap: .75rem; }
2955
2956/* Profiel-header: full mode iets minder riant (compact mode blijft hetzelfde) */
2957.profile-header { padding: 1rem 0; }
2958.profile-photo { width: 72px; height: 72px; }
2959.profile-photo-fallback { font-size: 1.8rem; }
2960.profile-name { font-size: 1.2rem; }
2961.profile-bio { font-size: .85rem; margin-top: .15rem; }
2962.profile-links { margin-top: .5rem; gap: .4rem; }
2963.profile-links a,
2964.profile-links .profile-fedi-link { width: 32px; height: 32px; }
2965
2966@media (min-width: 768px) {
2967 .profile-header { padding: 1.35rem 0; }
2968 .profile-photo { width: 92px; height: 92px; }
2969 .profile-photo-fallback { font-size: 2.4rem; }
2970 .profile-name { font-size: 1.4rem; }
2971 .profile-bio { font-size: .95rem; }
2972 .profile-header-inner { gap: 1.1rem; }
2973 /* Compact-mode op desktop blijft klein zoals we hadden afgesproken */
2974 .on-post .profile-photo,
2975 .on-special .profile-photo { width: 42px; height: 42px; }
2976}
2977
2978/* Grid-tegels iets strakker gaten */
2979.grid-tiles { gap: 3px; }
2980
2981/* Post-cover margin */
2982.post-cover { margin: 0 0 1rem; }
2983
2984/* Audio player wat lichter */
2985#pcms-audio-bar { padding: .55rem 1rem; }
2986
2987/* v8.1 — pagination CTA + mobile tap target */
2988.pagination-cta {
2989 display: inline-block;
2990 font-family: var(--font-ui);
2991 font-size: .72rem;
2992 font-weight: 600;
2993 color: var(--accent);
2994 margin-top: .35rem;
2995 letter-spacing: .02em;
2996 opacity: .9;
2997}
2998a.pagination-item:hover .pagination-cta { opacity: 1; }
2999
3000/* Mobiel: nog meer tap-feedback + iets prominenter */
3001@media (max-width: 640px) {
3002 a.pagination-item {
3003 padding: 1.1rem 1rem;
3004 min-height: 5.5rem;
3005 border-width: 2px;
3006 }
3007 a.pagination-item:active {
3008 background: color-mix(in srgb, var(--accent) 10%, var(--paper-2));
3009 transform: scale(.98);
3010 }
3011 .pagination-title { font-size: 1rem; }
3012 .pagination-cta { font-size: .75rem; }
3013 .pagination .icon { width: 1.5em; height: 1.5em; }
3014}
3015
3016
3017
3018/* v8.3 / v9.4 — PWA install button (alleen zichtbaar als browser install ondersteunt) */
3019.nav-install-btn[hidden] { display: none; }
3020.nav-install-btn {
3021 position: relative;
3022 display: inline-flex;
3023 align-items: center;
3024 justify-content: center;
3025 gap: .35rem;
3026 background: linear-gradient(135deg,
3027 var(--accent),
3028 color-mix(in srgb, var(--accent) 80%, #000));
3029 color: #fff;
3030 border: none;
3031 border-radius: .65rem;
3032 padding: .45rem .85rem;
3033 font-size: .8rem;
3034 font-weight: 600;
3035 line-height: 1;
3036 cursor: pointer;
3037 overflow: hidden;
3038 isolation: isolate;
3039 box-shadow:
3040 0 1px 0 rgba(255,255,255,.15) inset,
3041 0 2px 6px color-mix(in srgb, var(--accent) 35%, transparent);
3042 transition:
3043 transform .15s cubic-bezier(.4, 0, .2, 1),
3044 box-shadow .2s ease,
3045 filter .15s ease;
3046}
3047.nav-install-btn::before {
3048 content: "";
3049 position: absolute;
3050 top: 0;
3051 left: -100%;
3052 width: 60%;
3053 height: 100%;
3054 background: linear-gradient(110deg,
3055 transparent 30%,
3056 rgba(255,255,255,.22) 50%,
3057 transparent 70%);
3058 z-index: -1;
3059 animation: pcmsInstallShimmer 4s ease-in-out infinite;
3060 pointer-events: none;
3061}
3062.nav-install-btn:hover {
3063 transform: translateY(-1px);
3064 filter: brightness(1.08);
3065 box-shadow:
3066 0 1px 0 rgba(255,255,255,.2) inset,
3067 0 4px 10px color-mix(in srgb, var(--accent) 50%, transparent);
3068}
3069.nav-install-btn:active { transform: translateY(0); }
3070.nav-install-btn .icon {
3071 flex-shrink: 0;
3072 transition: transform .25s cubic-bezier(.34, 1.56, .64, 1);
3073}
3074.nav-install-btn:hover .icon { transform: translateY(-1px); }
3075@media (prefers-reduced-motion: reduce) {
3076 .nav-install-btn::before { animation: none; left: -100%; }
3077 .nav-install-btn:hover { transform: none; }
3078 .nav-install-btn:hover .icon { transform: none; }
3079}
3080/* Als PWA al draait (standalone mode) — verberg install-prompt knop volledig */
3081@media all and (display-mode: standalone) {
3082 #pwa-install-btn { display: none !important; }
3083}
3084
3085/* ========== v8.9.9 — Privé-post indicators ========== */
3086.post-private-banner {
3087 display: flex;
3088 align-items: center;
3089 gap: .6rem;
3090 padding: .75rem 1rem;
3091 background: color-mix(in srgb, #eab308 12%, var(--paper, #fff));
3092 border: 1px solid color-mix(in srgb, #eab308 40%, transparent);
3093 border-radius: 8px;
3094 margin: 0 0 1rem;
3095 font-size: .88rem;
3096 color: var(--ink, #1a1a1a);
3097}
3098.post-private-banner strong {
3099 color: #b45309;
3100}
3101
3102.grid-tile-private {
3103 position: absolute;
3104 top: 8px;
3105 left: 8px;
3106 padding: 3px 8px;
3107 background: rgba(0,0,0,0.7);
3108 color: #fde68a;
3109 font-size: .7rem;
3110 font-weight: 700;
3111 border-radius: 999px;
3112 z-index: 3;
3113 backdrop-filter: blur(4px);
3114 -webkit-backdrop-filter: blur(4px);
3115}
3116
3117/* ========== v8.9.10 — Social chip (inline in post-body) ========== */
3118.social-chip {
3119 display: inline-flex;
3120 align-items: center;
3121 gap: .45rem;
3122 padding: .35rem .75rem;
3123 background: color-mix(in srgb, var(--accent) 10%, transparent);
3124 border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
3125 border-radius: 999px;
3126 color: var(--ink, #1a1a1a);
3127 text-decoration: none;
3128 font-family: var(--font-ui, system-ui);
3129 font-size: .85rem;
3130 font-weight: 600;
3131 line-height: 1.2;
3132 transition: all .15s;
3133 vertical-align: middle;
3134 margin: 0 .1rem;
3135}
3136.social-chip:hover {
3137 background: var(--accent);
3138 color: #fff;
3139 border-color: var(--accent);
3140 text-decoration: none;
3141 transform: translateY(-1px);
3142 box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 40%, transparent);
3143}
3144.social-chip .icon {
3145 width: 16px;
3146 height: 16px;
3147 flex-shrink: 0;
3148}
3149.social-chip-icon-only {
3150 width: 36px;
3151 height: 36px;
3152 padding: 0;
3153 justify-content: center;
3154 border-radius: 50%;
3155}
3156.social-chip-icon-only .icon {
3157 width: 18px;
3158 height: 18px;
3159}
3160
3161/* v8.9.34 — player hidden state + post audio blocks
3162 v9.3 — Hide-rules uitgeschakeld: mini-player blijft permanent zichtbaar
3163 zodat 'ie niet meer verdwijnt bij browser-back of navigatie. */
3164.audio-player.is-hidden {
3165 /* display: none !important; */
3166}
3167body:not(.has-audio-player) #pcms-audio-player.is-hidden {
3168 /* display: none !important; */
3169}
3170
3171/* Post audio track — single track row in een post */
3172/* Lokale audio-track — visueel consistent met .post-audio-external */
3173.post-audio-track {
3174 display: flex;
3175 align-items: center;
3176 gap: .75rem;
3177 padding: .65rem .85rem;
3178 background: var(--paper-2, color-mix(in srgb, var(--ink) 4%, transparent));
3179 border: 1px solid var(--rule, rgba(0,0,0,.08));
3180 border-radius: 10px;
3181 margin: .75rem 0;
3182 transition: background .15s, border-color .15s;
3183}
3184.post-audio-track:hover {
3185 border-color: var(--accent, #c2410c);
3186 background: color-mix(in srgb, var(--accent, #c2410c) 5%, var(--paper-2, transparent));
3187}
3188/* Korte highlight wanneer je via de mini-speler naar deze track springt. */
3189.post-audio-track.pat-flash,
3190.post-album-track-compact.pat-flash {
3191 animation: patFlash 1.6s ease-out;
3192 border-radius: 8px;
3193}
3194/* Blijvende highlight op de track die NU actief is in de speler. */
3195.post-audio-track.pat-playing,
3196.post-album-track-compact.pat-playing {
3197 background: color-mix(in srgb, var(--accent, #c2410c) 12%, var(--paper-2, transparent));
3198 box-shadow: inset 3px 0 0 0 var(--accent, #c2410c);
3199 border-radius: 8px;
3200}
3201@keyframes patFlash {
3202 0%, 30% { border-color: var(--accent, #c2410c); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent, #c2410c) 35%, transparent); }
3203 100% { box-shadow: 0 0 0 0 transparent; }
3204}
3205.post-audio-track .pat-play {
3206 flex-shrink: 0;
3207 width: 42px;
3208 height: 42px;
3209 border-radius: 8px; /* zelfde rounded-square als pae-icon */
3210 border: none;
3211 background: var(--accent, #c2410c);
3212 color: var(--paper, #fff);
3213 cursor: pointer;
3214 display: inline-flex;
3215 align-items: center;
3216 justify-content: center;
3217 transition: transform .1s, background .15s;
3218 padding: 0;
3219 position: relative;
3220 overflow: hidden;
3221}
3222.post-audio-track .pat-play:hover { transform: scale(1.04); }
3223.post-audio-track .pat-play:active { transform: scale(.96); }
3224.post-audio-track .pat-play svg,
3225.post-audio-track .pat-play .pat-sitelogo {
3226 width: 100%; height: 100%;
3227 position: absolute;
3228 top: 0; left: 0;
3229 transition: opacity .15s;
3230}
3231.post-audio-track .pat-play .icon-play,
3232.post-audio-track .pat-play .icon-pause {
3233 width: 18px; height: 18px;
3234 position: absolute;
3235 top: 50%; left: 50%;
3236 transform: translate(-50%, -50%);
3237 fill: currentColor;
3238 opacity: 0; /* verborgen tot hover of is-current */
3239}
3240/* Site logo: object-cover binnen 42x42 box */
3241.post-audio-track .pat-play .pat-sitelogo {
3242 object-fit: cover;
3243 opacity: 1;
3244}
3245.post-audio-track .pat-play .pat-sitelogo-fallback {
3246 padding: 11px; /* SVG music-note iets kleiner in box */
3247 opacity: 1;
3248}
3249/* Bij hover: site logo faded, play-icoon verschijnt */
3250.post-audio-track:hover .pat-play .pat-sitelogo { opacity: 0.25; }
3251.post-audio-track:hover .pat-play .icon-play { opacity: 1; }
3252/* Bij current + playing: toon pause-icon */
3253.post-audio-track.is-current .pat-play .pat-sitelogo { opacity: 0.25; }
3254.post-audio-track.is-current .pat-play .icon-play { opacity: 1; }
3255.post-audio-track.is-current.is-playing .pat-play .icon-play { opacity: 0; }
3256.post-audio-track.is-current.is-playing .pat-play .icon-pause { opacity: 1; }
3257.post-audio-track.is-current {
3258 border-color: var(--accent, #c2410c);
3259 background: color-mix(in srgb, var(--accent, #c2410c) 10%, transparent);
3260}
3261.post-audio-track .pat-meta {
3262 flex: 1;
3263 min-width: 0;
3264 display: flex;
3265 flex-direction: column;
3266 gap: 2px;
3267}
3268.post-audio-track .pat-title {
3269 display: block;
3270 font-weight: 600;
3271 color: var(--ink);
3272 font-size: .95rem;
3273 overflow: hidden;
3274 text-overflow: ellipsis;
3275 white-space: nowrap;
3276}
3277.post-audio-track .pat-artist {
3278 display: block;
3279 font-size: .78rem;
3280 color: var(--ink-muted, var(--ink));
3281 opacity: .65;
3282 overflow: hidden;
3283 text-overflow: ellipsis;
3284 white-space: nowrap;
3285}
3286.post-audio-track .pat-duration {
3287 flex-shrink: 0;
3288 font-family: ui-monospace, monospace;
3289 font-size: .8rem;
3290 opacity: .55;
3291}
3292
3293/* Album block in een post */
3294.post-album {
3295 position: relative;
3296 border: 1px solid var(--rule, rgba(0,0,0,.1));
3297 border-radius: 14px;
3298 overflow: hidden;
3299 margin: 1.25rem 0;
3300 background: var(--paper-2, color-mix(in srgb, var(--ink) 3%, transparent));
3301}
3302.post-album-header {
3303 display: flex;
3304 gap: .75rem;
3305 padding: .55rem .7rem;
3306 align-items: center;
3307}
3308.post-album-cover {
3309 width: 120px;
3310 height: 120px;
3311 border-radius: 8px;
3312 background-size: cover;
3313 background-position: center;
3314 background-color: var(--rule);
3315 flex-shrink: 0;
3316}
3317/* v9.0 — Collage van track-covers als album-cover leeg is */
3318.post-album-cover-collage {
3319 display: grid;
3320 grid-template-columns: 1fr 1fr;
3321 grid-template-rows: 1fr 1fr;
3322 gap: 0;
3323 overflow: hidden;
3324 background: transparent;
3325}
3326.post-album-cover-collage .post-album-cover-tile {
3327 background-size: cover;
3328 background-position: center;
3329 width: 100%;
3330 height: 100%;
3331}
3332/* Empty state: gradient met muziek-noot */
3333.post-album-cover-empty {
3334 display: flex;
3335 align-items: center;
3336 justify-content: center;
3337 background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 25%, var(--paper-2)), color-mix(in srgb, var(--accent) 10%, var(--paper)));
3338 color: var(--accent, #c2410c);
3339}
3340.post-album-cover-empty svg {
3341 width: 42%;
3342 height: 42%;
3343 opacity: .55;
3344}
3345.post-album-info {
3346 flex: 1;
3347 min-width: 0;
3348}
3349.post-album-label {
3350 text-transform: uppercase;
3351 font-size: .68rem;
3352 letter-spacing: .1em;
3353 opacity: .55;
3354 margin: 0 0 .15rem;
3355 font-weight: 700;
3356}
3357.post-album-title {
3358 font-family: var(--font-display);
3359 font-size: 1.1rem;
3360 font-weight: 600;
3361 margin: 0 0 .1rem;
3362 line-height: 1.15;
3363 letter-spacing: -0.01em;
3364}
3365.post-album-artist {
3366 font-size: .88rem;
3367 opacity: .8;
3368 margin: 0 0 .12rem;
3369 line-height: 1.25;
3370}
3371.post-album-meta {
3372 font-size: .74rem;
3373 opacity: .55;
3374 margin: 0;
3375 line-height: 1.2;
3376}
3377.post-album-playall {
3378 margin-top: .75rem;
3379 padding: .45rem .9rem;
3380 background: var(--accent, #c2410c);
3381 color: var(--paper, #fff);
3382 border: none;
3383 border-radius: 6px;
3384 font-weight: 600;
3385 cursor: pointer;
3386 font-size: .88rem;
3387 display: inline-flex;
3388 align-items: center;
3389 gap: .35rem;
3390}
3391.post-album-playall:hover { filter: brightness(1.08); }
3392
3393/* ============================================================
3394 v9.0 — Album cover clickable button
3395 ============================================================ */
3396.post-album-cover-btn {
3397 position: relative;
3398 background: none;
3399 border: none;
3400 padding: 0;
3401 margin: 0;
3402 cursor: pointer;
3403 flex-shrink: 0;
3404 border-radius: 8px;
3405 overflow: hidden;
3406 display: block;
3407 width: auto;
3408 /* v9.1 — voorkom mobile 300ms double-tap zoom delay, anders zou 2× snel klikken
3409 een zoom triggeren i.p.v. 2× click-events */
3410 touch-action: manipulation;
3411 -webkit-tap-highlight-color: transparent;
3412}
3413.post-album-cover-btn .post-album-cover {
3414 display: block;
3415 width: 76px;
3416 height: 76px;
3417 border-radius: 7px;
3418 background-size: cover;
3419 background-position: center;
3420 background-color: var(--rule);
3421 transition: transform .25s ease;
3422}
3423.post-album-cover-btn:hover .post-album-cover {
3424 transform: scale(1.04);
3425}
3426.post-album-cover-btn .post-album-cover-empty {
3427 background: linear-gradient(135deg,
3428 color-mix(in srgb, var(--accent, #c2410c) 35%, var(--paper)),
3429 color-mix(in srgb, var(--accent, #c2410c) 10%, var(--paper-2)));
3430 display: flex;
3431 align-items: center;
3432 justify-content: center;
3433}
3434.post-album-cover-btn .post-album-cover-empty svg {
3435 width: 28px;
3436 height: 28px;
3437 color: color-mix(in srgb, var(--accent, #c2410c) 60%, transparent);
3438}
3439/* Play overlay op hover */
3440.post-album-cover-play {
3441 position: absolute;
3442 inset: 0;
3443 display: flex;
3444 align-items: center;
3445 justify-content: center;
3446 background: rgba(0, 0, 0, .35);
3447 opacity: 0;
3448 transition: opacity .2s ease;
3449 border-radius: 8px;
3450 pointer-events: none;
3451}
3452.post-album-cover-play svg {
3453 width: 48px;
3454 height: 48px;
3455 color: #fff;
3456 filter: drop-shadow(0 2px 8px rgba(0,0,0,.4));
3457}
3458.post-album-cover-btn:hover .post-album-cover-play,
3459.post-album-cover-btn:focus-visible .post-album-cover-play {
3460 opacity: 1;
3461}
3462
3463/* ============================================================
3464 v1 P52 — Admin actions overlay (edit / delete)
3465 Only rendered when the viewer has god role. Sits top-right
3466 of the card so it doesn't compete with the cover play affordance.
3467 ============================================================ */
3468.post-album-actions {
3469 position: absolute;
3470 top: .4rem;
3471 right: .4rem;
3472 display: flex;
3473 gap: .25rem;
3474 z-index: 2;
3475}
3476.post-album-action {
3477 width: 28px;
3478 height: 28px;
3479 border-radius: 6px;
3480 border: 1px solid var(--rule);
3481 background: color-mix(in srgb, var(--paper) 78%, transparent);
3482 backdrop-filter: blur(8px);
3483 -webkit-backdrop-filter: blur(8px);
3484 color: var(--ink);
3485 display: inline-flex;
3486 align-items: center;
3487 justify-content: center;
3488 cursor: pointer;
3489 text-decoration: none;
3490 opacity: .65;
3491 padding: 0;
3492 transition: opacity .15s ease, transform .15s ease, background .15s ease, color .15s ease, border-color .15s ease;
3493 -webkit-tap-highlight-color: transparent;
3494}
3495.post-album-action:hover,
3496.post-album-action:focus-visible {
3497 opacity: 1;
3498 transform: translateY(-1px);
3499 outline: none;
3500}
3501.post-album-action.is-danger:hover,
3502.post-album-action.is-danger:focus-visible {
3503 background: color-mix(in srgb, #c2410c 18%, var(--paper));
3504 border-color: color-mix(in srgb, #c2410c 45%, var(--rule));
3505 color: #c2410c;
3506}
3507.post-album-action svg {
3508 width: 15px;
3509 height: 15px;
3510 display: block;
3511}
3512
3513/* ============================================================
3514 v9.0 — Compacte tracklist (informatief, niet-klikbaar)
3515 ============================================================ */
3516.post-album-tracks {
3517 list-style: none;
3518 padding: 0;
3519 margin: 0;
3520 border-top: 1px solid var(--rule);
3521}
3522/* v9.4 — Playlist insert modal rows */
3523.pli-row {
3524 display: flex;
3525 align-items: center;
3526 gap: .75rem;
3527 padding: .65rem .5rem;
3528 border-bottom: 1px solid var(--border);
3529}
3530.pli-row:last-child { border-bottom: none; }
3531.pli-row-cover {
3532 width: 44px;
3533 height: 44px;
3534 border-radius: 6px;
3535 background-size: cover;
3536 background-position: center;
3537 background-color: color-mix(in srgb, var(--ink, #000) 8%, transparent);
3538 flex-shrink: 0;
3539 display: flex;
3540 align-items: center;
3541 justify-content: center;
3542 font-size: 1.4rem;
3543}
3544.pli-row-info {
3545 flex: 1;
3546 min-width: 0;
3547}
3548.pli-row-title {
3549 font-weight: 600;
3550 overflow: hidden;
3551 text-overflow: ellipsis;
3552 white-space: nowrap;
3553}
3554.pli-row-meta {
3555 font-size: .82rem;
3556 overflow: hidden;
3557 text-overflow: ellipsis;
3558 white-space: nowrap;
3559}
3560.post-playlist-placeholder {
3561 margin: 1rem 0;
3562 user-select: none;
3563}
3564
3565/* v9.4 — Generic modal classes (gebruikt door playlist-editor en andere modals) */
3566.pcms-modal-backdrop {
3567 position: fixed;
3568 inset: 0;
3569 background: rgba(0, 0, 0, .6);
3570 display: flex;
3571 align-items: center;
3572 justify-content: center;
3573 z-index: 9000;
3574 padding: 1rem;
3575 box-sizing: border-box;
3576 overflow-y: auto;
3577}
3578.pcms-modal {
3579 background: var(--paper, #fff);
3580 color: var(--ink, #000);
3581 border-radius: 12px;
3582 width: 100%;
3583 max-width: 640px;
3584 max-height: calc(100vh - 2rem);
3585 display: flex;
3586 flex-direction: column;
3587 overflow: hidden;
3588 box-shadow: 0 20px 60px rgba(0, 0, 0, .3);
3589}
3590.pcms-modal-header {
3591 display: flex;
3592 align-items: center;
3593 justify-content: space-between;
3594 padding: 1rem 1.25rem;
3595 border-bottom: 1px solid var(--border);
3596 flex-shrink: 0;
3597}
3598.pcms-modal-header h3 { font-size: 1.1rem; }
3599.pcms-modal-close {
3600 background: transparent;
3601 border: none;
3602 font-size: 1.6rem;
3603 line-height: 1;
3604 cursor: pointer;
3605 padding: .25rem .5rem;
3606 color: var(--fg-muted, #666);
3607 border-radius: 4px;
3608}
3609.pcms-modal-close:hover {
3610 background: color-mix(in srgb, var(--ink, #000) 8%, transparent);
3611}
3612.pcms-modal-body {
3613 padding: 1.25rem;
3614 overflow-y: auto;
3615 overscroll-behavior: contain;
3616 flex: 1;
3617 min-height: 0;
3618}
3619.pcms-modal-footer {
3620 display: flex;
3621 gap: .5rem;
3622 justify-content: flex-end;
3623 padding: .75rem 1.25rem;
3624 border-top: 1px solid var(--border);
3625 flex-shrink: 0;
3626 background: color-mix(in srgb, var(--ink, #000) 3%, transparent);
3627}
3628
3629/* On mobile: full-screen modal */
3630@media (max-width: 600px) {
3631 .pcms-modal-backdrop {
3632 padding: 0;
3633 }
3634 .pcms-modal {
3635 border-radius: 0;
3636 max-width: 100%;
3637 max-height: 100vh;
3638 height: 100vh;
3639 }
3640}
3641
3642/* v9.4 — Media → Playlists tab */
3643.playlists-page-header {
3644 display: flex;
3645 flex-wrap: wrap;
3646 gap: 1rem;
3647 align-items: center;
3648 justify-content: space-between;
3649 margin-bottom: 1.25rem;
3650}
3651.playlists-page-header > p { flex: 1; min-width: 200px; }
3652.playlists-grid {
3653 display: grid;
3654 grid-template-columns: 1fr;
3655 gap: .75rem;
3656}
3657@media (min-width: 720px) {
3658 .playlists-grid { grid-template-columns: repeat(2, 1fr); }
3659}
3660@media (min-width: 1100px) {
3661 .playlists-grid { grid-template-columns: repeat(3, 1fr); }
3662}
3663.playlist-card {
3664 display: grid;
3665 grid-template-columns: 64px 1fr auto;
3666 gap: .75rem;
3667 align-items: center;
3668 padding: .75rem;
3669 border: 1px solid var(--border);
3670 border-radius: var(--radius);
3671 background: var(--paper, #fff);
3672}
3673.playlist-card-cover {
3674 width: 64px;
3675 height: 64px;
3676 border-radius: 8px;
3677 overflow: hidden;
3678 background-color: color-mix(in srgb, var(--ink, #000) 6%, transparent);
3679 display: flex;
3680 align-items: center;
3681 justify-content: center;
3682}
3683.playlist-card-cover img {
3684 width: 100%;
3685 height: 100%;
3686 object-fit: cover;
3687}
3688.playlist-card-cover-empty { font-size: 1.6rem; opacity: .5; }
3689.playlist-card-info { min-width: 0; }
3690.playlist-card-title {
3691 font-weight: 600;
3692 overflow: hidden;
3693 text-overflow: ellipsis;
3694 white-space: nowrap;
3695}
3696.playlist-card-artist,
3697.playlist-card-meta {
3698 font-size: .82rem;
3699 overflow: hidden;
3700 text-overflow: ellipsis;
3701 white-space: nowrap;
3702}
3703.playlist-card-actions {
3704 display: flex;
3705 gap: .25rem;
3706 flex-shrink: 0;
3707}
3708
3709/* v9.4 — Playlist editor modal (mobile-friendly, single-column) */
3710.pl-editor {
3711 /* Erft van .pcms-modal */
3712}
3713.pl-editor-meta {
3714 display: grid;
3715 grid-template-columns: 1fr;
3716 gap: .75rem;
3717 margin-bottom: 1rem;
3718}
3719@media (min-width: 560px) {
3720 .pl-editor-meta {
3721 grid-template-columns: 1fr 1fr;
3722 }
3723 .pl-editor-meta .pl-editor-field-full { grid-column: 1 / -1; }
3724}
3725.pl-editor-field {
3726 display: flex;
3727 flex-direction: column;
3728 gap: .25rem;
3729 min-width: 0;
3730}
3731.pl-editor-field span {
3732 font-size: .82rem;
3733 color: var(--fg-muted, #666);
3734 font-weight: 500;
3735}
3736.pl-editor-field input,
3737.pl-editor-field select {
3738 width: 100%;
3739 box-sizing: border-box;
3740 padding: .5rem .65rem;
3741 font-size: .95rem;
3742 border: 1px solid var(--border);
3743 border-radius: 6px;
3744 background: var(--paper, #fff);
3745 color: var(--ink, #000);
3746}
3747.pl-editor-field input:focus,
3748.pl-editor-field select:focus {
3749 outline: 2px solid var(--accent, #5a8a5a);
3750 outline-offset: -1px;
3751}
3752.pl-editor-section-title {
3753 margin: 1.25rem 0 .5rem;
3754 font-size: 1rem;
3755 font-weight: 600;
3756}
3757.pl-tracks-selected {
3758 border: 1px solid var(--border);
3759 border-radius: var(--radius);
3760 background: var(--paper, #fff);
3761 min-height: 60px;
3762 margin-bottom: 1rem;
3763 padding: .25rem;
3764}
3765.pl-tracks-empty {
3766 padding: 1.5rem;
3767 text-align: center;
3768 color: var(--fg-muted, #666);
3769 font-size: .9rem;
3770}
3771.pl-track-row {
3772 display: grid;
3773 grid-template-columns: 32px 36px 1fr auto;
3774 gap: .5rem;
3775 align-items: center;
3776 padding: .5rem;
3777 border-bottom: 1px solid var(--border);
3778 background: var(--paper, #fff);
3779 user-select: none;
3780 touch-action: pan-x;
3781}
3782.pl-track-row:last-child { border-bottom: none; }
3783.pl-track-row.is-dragging {
3784 opacity: .55;
3785 transform: scale(.98);
3786 background: color-mix(in srgb, var(--accent, #5a8a5a) 10%, transparent);
3787 border-radius: 6px;
3788}
3789.pl-track-row.drop-target-above {
3790 box-shadow: inset 0 2px 0 0 var(--accent, #5a8a5a);
3791}
3792.pl-track-row.drop-target-below {
3793 box-shadow: inset 0 -2px 0 0 var(--accent, #5a8a5a);
3794}
3795.pl-track-handle {
3796 cursor: grab;
3797 font-size: 1.2rem;
3798 line-height: 1;
3799 color: var(--fg-muted, #666);
3800 display: flex;
3801 align-items: center;
3802 justify-content: center;
3803 height: 32px;
3804 width: 32px;
3805 border-radius: 4px;
3806 flex-shrink: 0;
3807}
3808.pl-track-handle:active { cursor: grabbing; }
3809.pl-track-handle:hover {
3810 background: color-mix(in srgb, var(--ink, #000) 8%, transparent);
3811}
3812.pl-track-num {
3813 text-align: center;
3814 color: var(--fg-muted, #666);
3815 font-size: .85rem;
3816 width: 36px;
3817}
3818.pl-track-info {
3819 min-width: 0;
3820 overflow: hidden;
3821}
3822.pl-track-title {
3823 font-weight: 500;
3824 overflow: hidden;
3825 text-overflow: ellipsis;
3826 white-space: nowrap;
3827}
3828.pl-track-artist {
3829 font-size: .78rem;
3830 color: var(--fg-muted, #666);
3831 overflow: hidden;
3832 text-overflow: ellipsis;
3833 white-space: nowrap;
3834}
3835.pl-track-remove {
3836 background: transparent;
3837 border: none;
3838 cursor: pointer;
3839 padding: .35rem;
3840 border-radius: 4px;
3841 color: var(--fg-muted, #666);
3842 font-size: 1.2rem;
3843 line-height: 1;
3844}
3845.pl-track-remove:hover {
3846 background: color-mix(in srgb, #c00 12%, transparent);
3847 color: #c00;
3848}
3849
3850/* Available tracks panel */
3851.pl-tracks-available-panel {
3852 border: 1px solid var(--border);
3853 border-radius: var(--radius);
3854 background: var(--paper, #fff);
3855}
3856.pl-tracks-available-search {
3857 padding: .5rem;
3858 border-bottom: 1px solid var(--border);
3859}
3860.pl-tracks-available-search input {
3861 width: 100%;
3862 box-sizing: border-box;
3863}
3864.pl-tracks-available-list {
3865 max-height: 30vh;
3866 overflow-y: auto;
3867}
3868.pl-track-row-available {
3869 display: grid;
3870 grid-template-columns: 1fr auto;
3871 gap: .5rem;
3872 align-items: center;
3873 padding: .5rem;
3874 border-bottom: 1px solid var(--border);
3875 cursor: pointer;
3876}
3877.pl-track-row-available:last-child { border-bottom: none; }
3878.pl-track-row-available:hover {
3879 background: color-mix(in srgb, var(--accent, #5a8a5a) 8%, transparent);
3880}
3881.pl-track-row-available.is-already-added {
3882 opacity: .4;
3883 pointer-events: none;
3884}
3885.pl-track-add-btn {
3886 background: transparent;
3887 border: 1px solid var(--border);
3888 border-radius: 4px;
3889 padding: .25rem .5rem;
3890 cursor: pointer;
3891 font-size: .85rem;
3892 color: var(--accent, #5a8a5a);
3893}
3894
3895/* v9.3 — Tracklist items zijn nu klikbare <button class="pat-row"> binnen <li>.
3896 De LI is puur een container zonder visuele styling; alles gebeurt op de button. */
3897.post-album-track-compact {
3898 padding: 0;
3899 margin: 0;
3900 border-bottom: 1px solid var(--rule);
3901 list-style: none;
3902}
3903.post-album-track-compact:last-child { border-bottom: none; }
3904
3905.pat-row {
3906 display: grid;
3907 grid-template-columns: 32px 1fr auto;
3908 gap: .65rem;
3909 align-items: center;
3910 width: 100%;
3911 padding: .5rem .85rem;
3912 background: transparent;
3913 border: none;
3914 color: inherit;
3915 font: inherit;
3916 font-size: .82rem;
3917 text-align: left;
3918 cursor: pointer;
3919 position: relative;
3920 transition: background .15s ease;
3921}
3922.pat-row:hover {
3923 background: color-mix(in srgb, var(--ink, #000) 6%, transparent);
3924}
3925.pat-row:active { transform: scale(.995); }
3926[data-theme="dark"] .pat-row:hover {
3927 background: color-mix(in srgb, var(--paper, #fff) 10%, transparent);
3928}
3929
3930/* Leader: track-nummer OF cover-thumb (afhankelijk van kind).
3931 v9.3 — pat-leader is altijd 32×32, met overgang voor spinner-vervanging. */
3932.pat-row .pat-num,
3933.pat-row .pat-cover {
3934 width: 32px;
3935 height: 32px;
3936 border-radius: 4px;
3937 flex-shrink: 0;
3938 transition: opacity .25s ease, transform .25s ease;
3939}
3940.pat-row .pat-num {
3941 font-family: ui-monospace, monospace;
3942 font-size: .8rem;
3943 opacity: .5;
3944 display: flex;
3945 align-items: center;
3946 justify-content: center;
3947}
3948.pat-row .pat-cover {
3949 background-size: cover;
3950 background-position: center;
3951 background-color: color-mix(in srgb, var(--ink, #000) 8%, transparent);
3952}
3953
3954/* v9.3 — Loading-spiraal als overlay op de leader-kolom.
3955 pat-num/pat-cover faden uit, spinner faded in via ::before. */
3956.pat-row::before {
3957 content: "";
3958 position: absolute;
3959 left: .85rem; top: 50%;
3960 width: 32px; height: 32px;
3961 transform: translateY(-50%);
3962 color: var(--accent, #c2410c);
3963 background-color: currentColor;
3964 -webkit-mask: url('/assets/spinner.svg') center/26px 26px no-repeat;
3965 mask: url('/assets/spinner.svg') center/26px 26px no-repeat;
3966 opacity: 0;
3967 transition: opacity .25s ease;
3968 pointer-events: none;
3969 animation: pat-spinner-rotate 1.2s linear infinite;
3970 animation-play-state: paused;
3971}
3972.pat-row.is-loading::before {
3973 opacity: 1;
3974 animation-play-state: running;
3975}
3976.pat-row.is-loading .pat-num,
3977.pat-row.is-loading .pat-cover {
3978 opacity: 0;
3979 transform: scale(.85);
3980}
3981@keyframes pat-spinner-rotate {
3982 from { transform: translateY(-50%) rotate(0deg); }
3983 to { transform: translateY(-50%) rotate(-360deg); }
3984}
3985
3986/* Meta-kolom */
3987.pat-row .pat-meta {
3988 display: flex;
3989 flex-direction: column;
3990 min-width: 0;
3991 gap: 1px;
3992 overflow: hidden;
3993}
3994.pat-row .pat-title {
3995 font-weight: 500;
3996 overflow: hidden;
3997 text-overflow: ellipsis;
3998 white-space: nowrap;
3999}
4000.pat-row .pat-artist {
4001 font-size: .72rem;
4002 opacity: .6;
4003 overflow: hidden;
4004 text-overflow: ellipsis;
4005 white-space: nowrap;
4006}
4007.pat-row .pat-duration {
4008 font-family: ui-monospace, monospace;
4009 font-size: .72rem;
4010 opacity: .55;
4011 font-variant-numeric: tabular-nums;
4012 white-space: nowrap;
4013}
4014.pat-row .pat-duration-empty {
4015 opacity: .25;
4016}
4017
4018/* is-current — actieve track in de player */
4019.pat-row.is-current {
4020 background: color-mix(in srgb, var(--accent, #c2410c) 12%, transparent);
4021}
4022.pat-row.is-current .pat-title,
4023.pat-row.is-current .pat-artist { color: var(--accent, #c2410c); }
4024
4025/* v9.3 — Marquee bij actief afspelen: titel scrollt heen-en-weer.
4026 --pat-shift wordt door JS gezet (= overflow in pixels). Bij 0 → geen
4027 beweging want translateX(0) blijft 0.
4028 Snelle cyclus (6s) met korte rust aan beide uiteinden (8%) zodat 't
4029 vlot voelt zonder onleesbaar te zijn. */
4030.pat-row.is-current.is-playing .pat-title {
4031 animation: pat-title-marquee 6s ease-in-out infinite alternate;
4032 text-overflow: clip;
4033 overflow: visible;
4034 will-change: transform;
4035}
4036@keyframes pat-title-marquee {
4037 0%, 8% { transform: translateX(0); }
4038 92%, 100% { transform: translateX(calc(-1 * var(--pat-shift, 0px))); }
4039}
4040
4041/* ============================================================
4042 v9.0 — CSS-migratie voor OUDE opgeslagen albums
4043 Oude posts hebben <li class="post-audio-track"> met play-knoppen + cover-spans.
4044 We renderen die VISUEEL als compact, zonder de HTML aan te passen.
4045 ============================================================ */
4046.post-album-tracks .post-audio-track {
4047 display: grid;
4048 grid-template-columns: 28px 1fr auto;
4049 gap: .75rem;
4050 align-items: center;
4051 padding: .5rem .85rem;
4052 margin: 0;
4053 border: none;
4054 border-bottom: 1px solid var(--rule);
4055 background: transparent;
4056 border-radius: 0;
4057 cursor: default;
4058 font-size: .92rem;
4059}
4060.post-album-tracks .post-audio-track:last-child { border-bottom: none; }
4061/* Verberg de cover-thumb en play-button in OUDE saved posts */
4062.post-album-tracks .post-audio-track .pat-cover,
4063.post-album-tracks .post-audio-track .pat-play {
4064 display: none !important;
4065}
4066.post-album-tracks .post-audio-track .pat-num {
4067 font-family: ui-monospace, monospace;
4068 font-size: .8rem;
4069 opacity: .45;
4070 text-align: center;
4071 width: auto;
4072}
4073.post-album-tracks .post-audio-track .pat-meta {
4074 display: flex;
4075 flex-direction: column;
4076 min-width: 0;
4077 gap: 1px;
4078}
4079.post-album-tracks .post-audio-track .pat-title {
4080 font-weight: 500;
4081 overflow: hidden;
4082 text-overflow: ellipsis;
4083 white-space: nowrap;
4084}
4085.post-album-tracks .post-audio-track .pat-artist {
4086 font-size: .78rem;
4087 opacity: .6;
4088}
4089.post-album-tracks .post-audio-track .pat-duration {
4090 font-family: ui-monospace, monospace;
4091 font-size: .78rem;
4092 opacity: .55;
4093}
4094.post-album-tracks .post-audio-track.is-current {
4095 background: color-mix(in srgb, var(--accent, #c2410c) 10%, transparent);
4096}
4097.post-album-tracks .post-audio-track.is-current .pat-num,
4098.post-album-tracks .post-audio-track.is-current .pat-title {
4099 color: var(--accent);
4100}
4101
4102@media (max-width: 540px) {
4103 .post-album-header { flex-direction: column; }
4104 .post-album-cover-btn .post-album-cover { width: 100%; max-width: 240px; height: auto; aspect-ratio: 1/1; }
4105}
4106@media (max-width: 380px) {
4107 .post-album-header { padding: .75rem; gap: .75rem; }
4108 .post-album-cover-btn .post-album-cover { max-width: 180px; }
4109 .post-album-title { font-size: 1.15rem; }
4110 .post-album-meta { font-size: .8rem; }
4111 .post-album-track-compact,
4112 .post-album-tracks .post-audio-track {
4113 grid-template-columns: 24px 1fr auto;
4114 gap: .5rem;
4115 padding: .4rem .6rem;
4116 font-size: .85rem;
4117 }
4118 .post-album-track-compact .pat-duration,
4119 .post-album-tracks .post-audio-track .pat-duration {
4120 font-size: .72rem;
4121 }
4122 /* Queue items in expand-sheet */
4123 .audio-sheet-queue-item { padding: .4rem .45rem; gap: .55rem; }
4124 .audio-sheet-queue-cover { width: 32px; height: 32px; }
4125 .audio-sheet-queue-title { font-size: .85rem; }
4126 .audio-sheet-queue-artist { font-size: .7rem; }
4127}
4128
4129/* External track (SoundCloud / YouTube / Spotify / etc) — klikbaar maar link-naar-platform */
4130.post-audio-external {
4131 display: flex;
4132 align-items: center;
4133 gap: .75rem;
4134 padding: .65rem .85rem;
4135 background: var(--paper-2, color-mix(in srgb, var(--ink) 4%, transparent));
4136 border: 1px solid var(--rule, rgba(0,0,0,.08));
4137 border-radius: 10px;
4138 margin: .75rem 0;
4139 text-decoration: none;
4140 color: var(--ink);
4141 transition: background .15s, border-color .15s;
4142}
4143.post-audio-external:hover {
4144 border-color: var(--accent);
4145 background: color-mix(in srgb, var(--accent) 5%, var(--paper-2, transparent));
4146}
4147.post-audio-external .pae-icon {
4148 flex-shrink: 0;
4149 width: 42px;
4150 height: 42px;
4151 border-radius: 8px;
4152 display: inline-flex;
4153 align-items: center;
4154 justify-content: center;
4155 background: var(--platform-color, #555);
4156 color: #fff;
4157 font-size: 1.2rem;
4158}
4159.post-audio-external .pae-icon-svg svg {
4160 width: 60%;
4161 height: 60%;
4162 fill: currentColor;
4163}
4164/* Per-platform vult de box net wat anders — brand-specifiek geoptimaliseerd */
4165.post-audio-external[data-platform="soundcloud"] .pae-icon-svg svg { width: 72%; height: auto; }
4166.post-audio-external[data-platform="spotify"] .pae-icon-svg svg { width: 72%; height: 72%; }
4167.post-audio-external[data-platform="youtube"] .pae-icon-svg svg { width: 68%; height: auto; }
4168.post-audio-external[data-platform="bandcamp"] .pae-icon-svg svg { width: 62%; height: auto; }
4169.post-audio-external[data-platform="apple"] .pae-icon-svg svg { width: 58%; height: 58%; }
4170.post-audio-external[data-platform="tidal"] .pae-icon-svg svg { width: 68%; height: auto; }
4171.post-audio-external[data-platform="deezer"] .pae-icon-svg svg { width: 65%; height: auto; }
4172.post-audio-external[data-platform="mixcloud"] .pae-icon-svg svg { width: 75%; height: auto; }
4173.post-audio-external[data-platform="soundcloud"] .pae-icon { background: #ff5500; }
4174.post-audio-external[data-platform="spotify"] .pae-icon { background: #1db954; }
4175.post-audio-external[data-platform="youtube"] .pae-icon { background: #ff0000; }
4176.post-audio-external[data-platform="bandcamp"] .pae-icon { background: #1da0c3; }
4177.post-audio-external[data-platform="apple"] .pae-icon { background: #fa243c; }
4178.post-audio-external[data-platform="tidal"] .pae-icon { background: #000; }
4179.post-audio-external[data-platform="deezer"] .pae-icon { background: #a238ff; }
4180.post-audio-external[data-platform="mixcloud"] .pae-icon { background: #314359; }
4181.post-audio-external[data-platform="other"] .pae-icon { background: #555; }
4182.post-audio-external .pae-meta {
4183 flex: 1;
4184 min-width: 0;
4185 display: flex;
4186 flex-direction: column;
4187 gap: 2px;
4188}
4189.post-audio-external .pae-title {
4190 display: block;
4191 font-weight: 600;
4192 overflow: hidden;
4193 text-overflow: ellipsis;
4194 white-space: nowrap;
4195 color: var(--ink);
4196}
4197.post-audio-external .pae-platform {
4198 display: block;
4199 font-size: .78rem;
4200 opacity: .65;
4201 text-transform: capitalize;
4202}
4203.post-audio-external .pae-go {
4204 flex-shrink: 0;
4205 opacity: .5;
4206 font-size: 1.1rem;
4207}
4208
4209/* =========================================================================
4210 v9.0 — Video player (inline)
4211 ========================================================================= */
4212
4213.post-video-figure {
4214 margin: 1.25rem 0;
4215 max-width: 100%;
4216}
4217
4218.post-video {
4219 display: block;
4220 width: 100%;
4221 max-width: 100%;
4222 height: auto;
4223 border-radius: 10px;
4224 background: #000;
4225 box-shadow: 0 4px 20px rgba(0,0,0,.15);
4226}
4227
4228.post-video-caption {
4229 margin-top: .5rem;
4230 font-size: .88rem;
4231 color: var(--ink-muted, color-mix(in srgb, var(--ink) 60%, transparent));
4232 text-align: center;
4233 line-height: 1.5;
4234}
4235
4236.post-video-caption strong {
4237 display: inline;
4238 font-weight: 600;
4239 color: var(--ink);
4240}
4241
4242@media (max-width: 640px) {
4243 .post-video-figure { margin: .75rem -.5rem; }
4244 .post-video { border-radius: 6px; }
4245}
4246
4247/* v9.3 — Floating "Bewerken" knop voor album-blokken in de post-editor.
4248 Verschijnt bij hover over een .post-album binnen #visual en wordt via JS
4249 geplaatst op de rechterbovenhoek van het blok. Niet in de opgeslagen HTML. */
4250.pcms-album-edit-overlay {
4251 position: absolute;
4252 z-index: 1000;
4253 transform: translateX(-100%);
4254 display: inline-flex;
4255 align-items: center;
4256 gap: .35rem;
4257 padding: .35rem .7rem;
4258 background: var(--accent, #c2410c);
4259 color: #fff;
4260 border: none;
4261 border-radius: 6px;
4262 font-size: .82rem;
4263 font-weight: 600;
4264 cursor: pointer;
4265 box-shadow: 0 4px 12px rgba(0, 0, 0, .18);
4266 transition: transform .12s ease, box-shadow .12s ease;
4267}
4268.pcms-album-edit-overlay:hover {
4269 transform: translateX(-100%) translateY(-1px);
4270 box-shadow: 0 6px 16px rgba(0, 0, 0, .24);
4271}
4272.pcms-album-edit-overlay:active {
4273 transform: translateX(-100%) translateY(0);
4274 box-shadow: 0 2px 6px rgba(0, 0, 0, .18);
4275}
4276
4277/* v9.3 — Drag-and-drop in de album-builder selected-lijst */
4278.ab-selected-row { cursor: default; }
4279.ab-selected-row .ab-drag-handle {
4280 display: inline-flex;
4281 align-items: center;
4282 justify-content: center;
4283 width: 18px;
4284 height: 100%;
4285 color: color-mix(in srgb, currentColor 40%, transparent);
4286 cursor: grab;
4287 user-select: none;
4288 font-size: .9rem;
4289 letter-spacing: -2px;
4290 flex-shrink: 0;
4291}
4292.ab-selected-row:hover .ab-drag-handle {
4293 color: color-mix(in srgb, currentColor 70%, transparent);
4294}
4295.ab-selected-row.is-dragging {
4296 opacity: .35;
4297 cursor: grabbing;
4298}
4299.ab-selected-row.is-dragging .ab-drag-handle { cursor: grabbing; }
4300/* Drop-indicator lijnen boven/onder de target rij */
4301.ab-selected-row.is-drag-target-before {
4302 box-shadow: 0 -2px 0 0 var(--accent, #c2410c) inset, 0 2px 0 0 var(--accent, #c2410c);
4303 /* Gebruik outline voor cross-browser zichtbaarheid */
4304 position: relative;
4305}
4306.ab-selected-row.is-drag-target-before::before {
4307 content: "";
4308 position: absolute;
4309 top: -1px; left: 0; right: 0;
4310 height: 2px;
4311 background: var(--accent, #c2410c);
4312 pointer-events: none;
4313}
4314.ab-selected-row.is-drag-target-after::after {
4315 content: "";
4316 position: absolute;
4317 bottom: -1px; left: 0; right: 0;
4318 height: 2px;
4319 background: var(--accent, #c2410c);
4320 pointer-events: none;
4321}
4322.ab-selected-row.is-drag-target-after { position: relative; }
4323
4324/* v9.3 — Playlist fallback states (missing of empty playlist reference in post) */
4325.post-playlist-missing, .post-playlist-empty {
4326 padding: 1rem;
4327 margin: .75rem 0;
4328 background: color-mix(in srgb, var(--accent, #c2410c) 8%, transparent);
4329 border: 1px dashed color-mix(in srgb, var(--accent, #c2410c) 30%, transparent);
4330 border-radius: 8px;
4331 font-size: .9rem;
4332}
4333.post-playlist-missing em, .post-playlist-empty em {
4334 opacity: .8;
4335}
4336
4337/* v9.3 — Install-app footer-knop */
4338.site-footer-install {
4339 display: flex;
4340 justify-content: center;
4341 padding: 1rem 1rem 1.25rem;
4342 border-top: 1px solid color-mix(in srgb, currentColor 8%, transparent);
4343 margin-top: .5rem;
4344}
4345
4346/* v9.4 — Cooler install-knop: gradient + shimmer + perfect centering.
4347 Twee kleur-stops voor diepte, animated shimmer-streep om aandacht te trekken,
4348 icon perfect verticaal gecentreerd via flex (was: net iets te hoog tov tekst). */
4349.install-app-btn {
4350 position: relative;
4351 display: inline-flex;
4352 align-items: center;
4353 justify-content: center;
4354 gap: .55rem;
4355 padding: .8rem 1.6rem;
4356 background: linear-gradient(135deg,
4357 var(--accent, #c2410c),
4358 color-mix(in srgb, var(--accent, #c2410c) 80%, #000));
4359 color: #fff;
4360 border: none;
4361 border-radius: 999px;
4362 font: inherit;
4363 font-weight: 600;
4364 font-size: .95rem;
4365 line-height: 1;
4366 letter-spacing: .01em;
4367 cursor: pointer;
4368 overflow: hidden;
4369 isolation: isolate;
4370 box-shadow:
4371 0 1px 0 rgba(255,255,255,.15) inset,
4372 0 -2px 0 rgba(0,0,0,.1) inset,
4373 0 4px 14px color-mix(in srgb, var(--accent, #c2410c) 40%, transparent),
4374 0 1px 3px rgba(0,0,0,.18);
4375 transition:
4376 transform .15s cubic-bezier(.4, 0, .2, 1),
4377 box-shadow .2s ease,
4378 filter .15s ease;
4379}
4380.install-app-btn svg {
4381 flex-shrink: 0;
4382 /* subtle bounce-on-hover trigger, separate animation */
4383 transition: transform .25s cubic-bezier(.34, 1.56, .64, 1);
4384}
4385.install-app-btn span {
4386 line-height: 1;
4387}
4388
4389/* Shimmer-streep die langzaam over de knop loopt — "alive" effect */
4390.install-app-btn::before {
4391 content: "";
4392 position: absolute;
4393 top: 0;
4394 left: -100%;
4395 width: 60%;
4396 height: 100%;
4397 background: linear-gradient(110deg,
4398 transparent 30%,
4399 rgba(255,255,255,.25) 50%,
4400 transparent 70%);
4401 z-index: -1;
4402 animation: pcmsInstallShimmer 4s ease-in-out infinite;
4403 pointer-events: none;
4404}
4405@keyframes pcmsInstallShimmer {
4406 0%, 35% { left: -100%; }
4407 65%, 100% { left: 200%; }
4408}
4409
4410.install-app-btn:hover {
4411 transform: translateY(-2px) scale(1.02);
4412 filter: brightness(1.06);
4413 box-shadow:
4414 0 1px 0 rgba(255,255,255,.2) inset,
4415 0 -2px 0 rgba(0,0,0,.1) inset,
4416 0 8px 24px color-mix(in srgb, var(--accent, #c2410c) 55%, transparent),
4417 0 2px 6px rgba(0,0,0,.2);
4418}
4419.install-app-btn:hover svg {
4420 transform: translateY(-2px);
4421}
4422.install-app-btn:active {
4423 transform: translateY(0) scale(.98);
4424 transition-duration: .05s;
4425}
4426.install-app-btn:focus-visible {
4427 outline: 2px solid var(--accent, #c2410c);
4428 outline-offset: 3px;
4429}
4430
4431/* Reduced motion: shimmer uit, alleen statisch */
4432@media (prefers-reduced-motion: reduce) {
4433 .install-app-btn::before { animation: none; left: -100%; }
4434 .install-app-btn:hover { transform: none; }
4435 .install-app-btn:hover svg { transform: none; }
4436}
4437
4438/* Install-instructions modal */
4439.install-modal {
4440 position: fixed;
4441 inset: 0;
4442 z-index: 10000;
4443 display: flex;
4444 align-items: center;
4445 justify-content: center;
4446 padding: 1rem;
4447}
4448.install-modal-backdrop {
4449 position: absolute;
4450 inset: 0;
4451 background: rgba(0,0,0,.55);
4452 backdrop-filter: blur(3px);
4453}
4454.install-modal-panel {
4455 position: relative;
4456 z-index: 1;
4457 background: var(--paper);
4458 color: var(--ink);
4459 border: 1px solid var(--rule);
4460 border-radius: 14px;
4461 padding: 1.5rem;
4462 max-width: 440px;
4463 width: 100%;
4464 max-height: 90vh;
4465 overflow-y: auto;
4466 box-shadow: 0 20px 60px rgba(0,0,0,.4);
4467}
4468.install-modal-panel h3 { font-size: 1.15rem; color: var(--ink); }
4469.install-modal-panel h4 {
4470 margin: 1rem 0 .4rem;
4471 font-size: .92rem;
4472 letter-spacing: .03em;
4473 text-transform: uppercase;
4474 opacity: .7;
4475 color: var(--ink);
4476}
4477.install-modal-panel p { color: var(--ink); }
4478.install-steps {
4479 margin: 0;
4480 padding-left: 1.35rem;
4481 display: flex;
4482 flex-direction: column;
4483 gap: .45rem;
4484 font-size: .95rem;
4485 line-height: 1.45;
4486 color: var(--ink);
4487}
4488.install-steps li::marker { color: var(--accent); font-weight: 700; }
4489.install-apk-block {
4490 margin-top: 1.25rem;
4491 padding-top: 1rem;
4492 border-top: 1px dashed var(--rule);
4493}
4494.install-apk-link {
4495 display: inline-flex;
4496 align-items: center;
4497 margin-top: .4rem;
4498 padding: .6rem 1rem;
4499 background: var(--accent);
4500 color: #fff;
4501 border-radius: 8px;
4502 text-decoration: none;
4503 font-weight: 600;
4504}
4505.install-apk-link:hover { filter: brightness(1.08); }
4506.install-modal-actions {
4507 display: flex;
4508 justify-content: flex-end;
4509 margin-top: 1.25rem;
4510}
4511.install-modal-actions .btn {
4512 padding: .5rem 1rem;
4513 background: var(--paper-2);
4514 border: 1px solid var(--rule);
4515 border-radius: 8px;
4516 color: var(--ink);
4517 cursor: pointer;
4518 font: inherit;
4519 font-weight: 500;
4520}
4521.install-modal-actions .btn:hover {
4522 background: color-mix(in srgb, var(--accent) 10%, var(--paper-2));
4523 border-color: var(--accent);
4524 color: var(--accent);
4525}
4526
4527@media (max-width: 520px) {
4528 .install-modal-panel { padding: 1.2rem; }
4529 .install-app-btn { width: 100%; justify-content: center; }
4530}
4531
4532/* v9.3 — Install-modal: choice-blocks met voor/nadelen */
4533.install-choice {
4534 margin-top: 1.25rem;
4535 padding: 1rem;
4536 border: 1px solid color-mix(in srgb, currentColor 15%, transparent);
4537 border-radius: 10px;
4538 background: color-mix(in srgb, currentColor 3%, transparent);
4539}
4540.install-choice + .install-choice { margin-top: 1rem; }
4541.install-choice h4 {
4542 margin: 0 0 .75rem;
4543 font-size: 1rem;
4544 letter-spacing: 0;
4545 text-transform: none;
4546 opacity: 1;
4547}
4548.install-pros-cons {
4549 display: flex;
4550 gap: 1rem;
4551 margin: .5rem 0 1rem;
4552}
4553.install-pros,
4554.install-cons {
4555 flex: 1;
4556 min-width: 0;
4557 font-size: .85rem;
4558 line-height: 1.45;
4559}
4560.install-pros strong,
4561.install-cons strong {
4562 display: block;
4563 margin-bottom: .35rem;
4564 font-size: .82rem;
4565 letter-spacing: .02em;
4566}
4567.install-pros strong { color: #16a34a; }
4568.install-cons strong { color: #dc2626; }
4569.install-pros ul,
4570.install-cons ul {
4571 margin: 0;
4572 padding-left: 1.1rem;
4573 display: flex;
4574 flex-direction: column;
4575 gap: .25rem;
4576}
4577.install-pros li::marker { color: #16a34a; }
4578.install-cons li::marker { color: #dc2626; }
4579
4580.install-choice-cta {
4581 display: inline-flex;
4582 align-items: center;
4583 justify-content: center;
4584 gap: .35rem;
4585 margin-top: .5rem;
4586 padding: .7rem 1.1rem;
4587 background: var(--accent, #c2410c);
4588 color: #fff;
4589 border: none;
4590 border-radius: 8px;
4591 text-decoration: none;
4592 font: inherit;
4593 font-weight: 600;
4594 font-size: .95rem;
4595 cursor: pointer;
4596 transition: filter .12s ease;
4597}
4598.install-choice-cta:hover { filter: brightness(1.08); }
4599.install-choice-note {
4600 margin: .5rem 0 0;
4601 padding: .6rem .8rem;
4602 background: color-mix(in srgb, currentColor 4%, transparent);
4603 border-left: 3px solid var(--accent, #c2410c);
4604 border-radius: 4px;
4605 font-size: .9rem;
4606 line-height: 1.45;
4607}
4608
4609@media (max-width: 520px) {
4610 .install-pros-cons { flex-direction: column; gap: .75rem; }
4611}
4612
4613/* v9.4 — Soft fade-overgang tussen posts bij navigatie.
4614 Fade-out is rustig (450ms): oude content vervaagt geleidelijk terwijl
4615 de scroll-naar-top loopt. Fade-in is snel (180ms) met een lichte blur-
4616 onscherp → scherp animatie zodat de nieuwe content niet abrupt verschijnt. */
4617#pcms-main {
4618 transition: opacity .45s ease-out;
4619}
4620#pcms-main.is-pcms-transitioning-out {
4621 opacity: 0;
4622}
4623#pcms-main.is-pcms-transitioning-in {
4624 opacity: 0;
4625 filter: blur(6px);
4626 animation: pcmsFadeIn .18s ease-out forwards;
4627 will-change: opacity, filter;
4628}
4629@keyframes pcmsFadeIn {
4630 from { opacity: 0; filter: blur(6px); }
4631 to { opacity: 1; filter: blur(0); }
4632}
4633
4634/* Respecteer reduced-motion voorkeur (iOS/Android accessibility setting) */
4635@media (prefers-reduced-motion: reduce) {
4636 #pcms-main {
4637 transition: opacity .15s ease-out;
4638 }
4639 #pcms-main.is-pcms-transitioning-in {
4640 filter: none;
4641 animation: none;
4642 opacity: 1;
4643 }
4644}
4645
4646/* === Fediverse interactions — inherits the native .comment styling === */
4647.post-fediverse .fedi-stats { display: flex; gap: .45rem; margin: .35rem 0 1.5rem; align-items: center; }
4648.post-fediverse .fedi-stat {
4649 display: inline-flex; align-items: center; gap: .4rem;
4650 padding: .32rem .7rem; border-radius: 999px; font-size: .85rem; line-height: 1;
4651 font-variant-numeric: tabular-nums;
4652 color: var(--ink-muted); background: transparent;
4653 border: 1px solid var(--rule);
4654}
4655.post-fediverse .fedi-stat svg { width: 15px; height: 15px; }
4656.post-fediverse .fedi-stat-btn { cursor: pointer; font: inherit; line-height: 1; transition: color .15s, border-color .15s, background .15s; }
4657.post-fediverse .fedi-stat-btn:hover { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 55%, var(--rule)); background: var(--accent-tint); }
4658.post-fediverse .fedi-stat-btn:hover svg { fill: color-mix(in srgb, var(--accent) 22%, transparent); }
4659.post-fediverse .fedi-handle { color: var(--ink-soft, #888); font-size: .82rem; }
4660.post-fediverse .comment-content p { margin: .2rem 0; }
4661.post-fediverse .comment-content p:first-child { margin-top: 0; }
4662.post-fediverse .comment-content p:last-child { margin-bottom: 0; }
4663/* reply toggle: a plain "Reageer" action like the comment buttons (no triangle) */
4664.post-fediverse .fedi-reply-toggle { list-style: none; cursor: pointer; display: inline-block; }
4665.post-fediverse .fedi-reply-toggle::-webkit-details-marker { display: none; }
4666.post-fediverse details[open] .fedi-reply-toggle { margin-bottom: .5rem; }
4667
4668/* Reply-via-fediverse CTA on post pages */
4669.post-fediverse-cta { margin: 1.75rem 0; }
4670.fedi-remote-reply-btn { display: inline-flex; align-items: center; gap: .45rem; }
4671.post-fediverse-cta .fedi-remote-reply-btn {
4672 border: 1px solid color-mix(in srgb, var(--accent, #888) 55%, transparent);
4673 background: color-mix(in srgb, var(--accent, #888) 10%, transparent);
4674 color: var(--ink, inherit); border-radius: 999px; padding: .5rem 1.05rem;
4675 font-weight: 600; cursor: pointer; transition: background .15s ease;
4676}
4677.post-fediverse-cta .fedi-remote-reply-btn:hover { background: color-mix(in srgb, var(--accent, #888) 22%, transparent); }
4678.post-fediverse-cta .fedi-remote-reply-btn svg { color: var(--accent, currentColor); }
4679.post-fediverse .comment-actions .fedi-remote-reply-btn { gap: .3rem; }
4680
4681/* Inline "reply via fediverse" address form (replaces the browser prompt) */
4682.fedi-remote-form {
4683 position: absolute; z-index: 60; display: inline-flex; align-items: center; gap: .4rem;
4684 padding: .4rem; border-radius: 999px;
4685 background: var(--paper-2, var(--paper, #fff));
4686 border: 1px solid color-mix(in srgb, var(--ink, #000) 12%, transparent);
4687 box-shadow: 0 10px 30px rgba(0,0,0,.28);
4688}
4689.fedi-remote-form input {
4690 height: 2.2rem; padding: 0 .9rem; border-radius: 999px; font: inherit; min-width: 230px;
4691 border: 1px solid color-mix(in srgb, var(--ink, #000) 18%, transparent);
4692 background: color-mix(in srgb, var(--ink, #000) 4%, transparent); color: var(--ink, #000);
4693}
4694.fedi-remote-form input::placeholder { color: var(--ink-soft, #999); }
4695.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); }
4696.fedi-remote-form .fedi-remote-go {
4697 height: 2.2rem; min-width: 2.2rem; padding: 0 .85rem; border-radius: 999px;
4698 display: inline-flex; align-items: center; justify-content: center; font-size: 1rem;
4699}
4700.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; }
4701.fedi-remote-form .fedi-remote-cancel:hover { color: var(--ink, #000); }
4702
4703/* ── NSFW / sensitive content — blur + click to reveal ───────────────── */
4704.nsfw-media { position: relative; }
4705.nsfw-veil {
4706 position: absolute; inset: 0; z-index: 4; cursor: pointer; border-radius: inherit;
4707 display: flex; flex-direction: column; align-items: center; justify-content: center;
4708 gap: .5rem; padding: .75rem; text-align: center;
4709 background: color-mix(in srgb, var(--paper, #14141a) 50%, transparent);
4710 backdrop-filter: blur(22px) saturate(.6); -webkit-backdrop-filter: blur(22px) saturate(.6);
4711}
4712.nsfw-media.is-shown > .nsfw-veil { display: none; }
4713.nsfw-veil-label { font-weight: 700; font-size: .82rem; color: var(--ink, #f3f1ea); text-shadow: 0 1px 2px rgba(0,0,0,.5); }
4714.nsfw-veil-btn {
4715 font-size: .72rem; font-weight: 600; padding: .3rem .8rem; border-radius: 999px;
4716 border: 1px solid color-mix(in srgb, var(--ink, #fff) 55%, transparent);
4717 background: color-mix(in srgb, var(--paper, #000) 35%, transparent); color: var(--ink, #f3f1ea);
4718}
4719/* Post page: blur cover + body behind a content-warning banner until revealed */
4720.nsfw-gate .post-cover,
4721.nsfw-gate .post-content { filter: blur(26px); pointer-events: none; user-select: none; transition: filter .2s ease; }
4722.nsfw-gate.is-shown .post-cover,
4723.nsfw-gate.is-shown .post-content { filter: none; pointer-events: auto; user-select: auto; }
4724.nsfw-banner {
4725 display: flex; align-items: center; gap: .7rem; flex-wrap: wrap; margin: 0 0 1.5rem;
4726 padding: .8rem 1rem; border-radius: 12px;
4727 border: 1px solid color-mix(in srgb, var(--accent, #e8b04b) 45%, transparent);
4728 background: color-mix(in srgb, var(--accent, #e8b04b) 9%, transparent);
4729}
4730.nsfw-gate.is-shown .nsfw-banner { display: none; }
4731.nsfw-banner-icon { font-size: 1.2rem; }
4732.nsfw-banner-text { font-weight: 600; font-size: .92rem; color: var(--ink); }
4733.nsfw-banner-btn {
4734 margin-left: auto; cursor: pointer; font: inherit; font-size: .82rem; font-weight: 600;
4735 padding: .4rem 1rem; border-radius: 999px; border: 0;
4736 background: var(--accent, #e8b04b); color: #1a1205;
4737}
Note: See TracBrowser for help on using the repository browser.