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

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

Account-verhuizingen slice 3: het wegwijsbord (movedTo + homepage-link)

Het sluitstuk van shaer-0j2's federatiekant. De oude Klonkt blijft
staan en ZEGT waar hij heen ging, op twee plekken.

Voor servers: het actor-document draagt movedTo zodra moved_to gezet is
(FEP-7628: een verhuisd account moet dat publiceren en geldt als
inactief). Dat is precies waarom de oude actor online blijft: wie de
Move-activity miste (server offline, latere bezoeker) leert de
verhuizing alsnog door ons op te halen. Een kolomwaarde die geen URL is
haalt de draad nooit.

Voor mensen: de homepage opent met een groot wegwijsbord boven de feed,
met de handle van het nieuwe adres als grote link. Boven de posts met
opzet: niemand hoort een dode tijdlijn door te scrollen om te ontdekken
dat we weg zijn.

En de verhuizing zelf vertelt het nu twee keer: naast de Move gaat er
een Update van de actor naar elke volger-inbox, gebouwd uit de VERSE
rij, zodat het bord ook staat als de Move onderweg verdwijnt (FEP-7628
SHOULD).

Changed files:
src/services/ActivityPubService.js

  • buildActor: movedTo bij een geldige moved_to
  • moveAccount: Update(actor) naast de Move, per inbox

src/routes/posts.js

  • home: movedTo + leesbaar label (actorDisplay) naar de view

src/views/pages/home.ejs

  • wegwijsbord boven de feed, typeof-guard voor deploy-races

src/assets/css/style.css

  • .moved-banner: accentrand, grote link, tekst breekt netjes af

src/services/i18n.js

  • phome.moved_lead/_hint in nl/en/de

test/move-actor.test.js

  • movedTo aan/uit/rommel; Update draagt het bord naast de Move
  • slice-2-test telt nu Moves apart (Update rijdt mee)

remarks: banner visueel gecontroleerd (mobiel en desktop) door het echte
templateblok met de echte CSS te renderen; suite 372 groen.

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

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