source: Klonkt/src/assets/css/style.css@ 6dd26e5

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

De audio-tegel opgevrolijkt: golfvorm als thumbnail en een echte titel

Een audiopost uit Shaer was op Klonkt een kale gradient met (untitled)
(Robins schermafdruk, 30-7). Twee dingen tegelijk gefixt.

De thumbnail: de upload-leg tekent bij audio nu een golfvorm met de
gebundelde ffmpeg (showwavespic, wit op transparant) naar
<naam>.poster.png, precies zoals video zijn stilstaand beeld krijgt. Die
golfvorm rijdt mee als data-poster op de audio-tag (voor de tegels), in
c2s_attachments en als AS2-icon op het gefedereerde Audio-attachment. De
tegel toont hem OVER de eigen hue-gradient, dus elke audiopost houdt
zijn kleur en krijgt zijn vorm.

De titel: C2S-posts hebben geen titel, dus elke Shaer-post toonde
(untitled). Tegels en kaarten leiden de titel nu af: eerst de eigen
woorden van de post (afgekapt op 64), anders een vriendelijk typelabel
(muzieknoot audio, pijl video), en pas als er echt niets is (untitled).
Een tegel die zijn beeld al toont forceert geen label meer.

Changed files:
src/routes/activitypub.js

  • uploadMedia: audio/* -> showwavespic-golfvorm naar .poster.png (best-effort, zelfde patroon als de videoposter)

src/services/ActivityPubService.js

  • c2sCreatePost: posterExt per type (video .jpg, audio .png); de audio-tag krijgt data-poster

src/views/partials/post-tile.ejs

  • audio-detectie + golfvorm over de gradient; titelcascade (titel -> tekst -> typelabel)

src/views/partials/post-card.ejs

  • zelfde spiegel: golfvorm als cover met eigen accent-gradient, zelfde titelcascade

src/assets/css/style.css

  • .grid-tile-wave: contain, padding, transparant op de gradient

test/c2s-compose.test.js

  • audio-golfvormketen: data-poster op de tag, poster in de store, icon op het gefedereerde attachment

remarks: bestaande audioposts kregen hun upload voor deze code en hebben
dus nog geen golfvorm-bestand; die tonen nu wel het muzieknoot-label. Een
verse audiopost laat het hele effect zien. ffmpeg-commando en beide
templates hier lokaal gesmoke-test (RGBA-png, render ok), 345 tests
groen.

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

  • Property mode set to 100644
File size: 148.8 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.empty h1 { font-size: 2rem; }
562.empty p { color: var(--ink-muted); }
563
564/* Embeds */
565.pcms-embed, .folio-embed { margin: 2rem 0; }
566.pcms-embed iframe, .pcms-embed video, .pcms-embed audio,
567.folio-embed iframe, .folio-embed video, .folio-embed audio { width: 100%; display: block; border: 0; border-radius: var(--radius); }
568
569/* Article footer */
570.article-footer { display: flex; justify-content: center; padding-top: 2rem; margin-top: 2rem; border-top: 1px solid var(--rule); }
571
572/* Buttons */
573.button {
574 font-family: var(--font-ui); font-size: .875rem; font-weight: 500;
575 padding: .6rem 1.1rem; min-height: 2.5rem;
576 display: inline-flex; align-items: center; gap: .5rem;
577 background: var(--ink); color: var(--paper);
578 border: 1px solid var(--ink);
579 border-radius: 6px;
580 text-decoration: none; cursor: pointer;
581 transition: all var(--transition);
582}
583.button:hover { background: var(--accent); border-color: var(--accent); color: #fff; }
584.button-ghost { background: transparent; color: var(--ink); border-color: var(--rule-2); }
585.button-ghost:hover { background: var(--paper-2); border-color: var(--accent); color: var(--accent); }
586
587/* Pagination */
588.pagination {
589 display: grid;
590 grid-template-columns: 1fr 1fr;
591 gap: 1rem;
592 padding-block: 2rem 4rem;
593 margin-top: 2rem;
594 border-top: 1px solid var(--rule);
595}
596a.pagination-item {
597 display: flex; align-items: center; gap: 1rem; padding: 1rem 1.25rem;
598 border: 2px solid var(--rule-2, var(--rule));
599 border-radius: var(--radius);
600 text-decoration: none; transition: all .15s ease; font-size: .9rem;
601 background: var(--paper-2);
602 min-height: 5rem;
603 min-width: 0;
604 overflow: hidden;
605 cursor: pointer;
606 box-shadow: 0 1px 0 rgba(0,0,0,.02);
607 -webkit-tap-highlight-color: color-mix(in srgb, var(--accent) 30%, transparent);
608 position: relative;
609}
610.pagination-item:not(a) {
611 display: flex; align-items: center; gap: 1rem; padding: 1rem 1.25rem;
612 border: 1px dashed var(--rule); border-radius: var(--radius);
613 font-size: .9rem; background: transparent; min-height: 5rem;
614 min-width: 0; overflow: hidden;
615}
616.pagination-next { flex-direction: row-reverse; text-align: right; }
617a.pagination-item:hover {
618 border-color: var(--accent);
619 background: color-mix(in srgb, var(--accent) 5%, var(--paper-2));
620 transform: translateY(-2px);
621 box-shadow: 0 4px 12px rgba(0,0,0,.08);
622}
623a.pagination-item:active {
624 transform: translateY(0);
625 transition-duration: .05s;
626}
627.pagination-disabled { opacity: .5; cursor: default; font-style: italic; }
628.pagination-body { display: flex; flex-direction: column; gap: .15rem; min-width: 0; flex: 1; }
629.pagination-label {
630 display: block; font-family: var(--font-ui); font-size: .7rem; font-weight: 700;
631 letter-spacing: .08em; text-transform: uppercase; color: var(--accent);
632 margin-bottom: .15rem;
633}
634.pagination-slug {
635 display: block; font-size: .72rem; color: var(--ink-muted);
636 opacity: .75; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
637 font-style: italic;
638}
639.pagination-title {
640 display: block; font-family: var(--font-display); font-weight: 600; color: var(--ink);
641 font-variation-settings: "opsz" 72; font-style: normal;
642 line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
643 font-size: 1.05rem;
644 text-decoration: underline;
645 text-decoration-color: var(--rule-2, var(--rule));
646 text-decoration-thickness: 1px;
647 text-underline-offset: 3px;
648 transition: text-decoration-color .15s;
649}
650a.pagination-item:hover .pagination-title {
651 text-decoration-color: var(--accent);
652}
653.pagination .icon {
654 width: 1.75em; height: 1.75em; flex-shrink: 0;
655 color: var(--accent);
656 transition: transform .15s;
657}
658a.pagination-prev:hover .icon { transform: translateX(-4px); }
659a.pagination-next:hover .icon { transform: translateX(4px); }
660
661/* Pinned-targets → accent-tint en dikkere rand voor duidelijkheid */
662.pagination-item.is-pinned {
663 background: color-mix(in srgb, var(--accent) 8%, var(--paper-2));
664 border-color: color-mix(in srgb, var(--accent) 45%, var(--rule));
665}
666a.pagination-item.is-pinned:hover {
667 background: color-mix(in srgb, var(--accent) 15%, var(--paper-2));
668 border-color: var(--accent);
669}
670
671@media (max-width: 800px) { .pagination { grid-template-columns: 1fr; } }
672
673/* Footer */
674.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); }
675.site-footer-inner { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 1rem; align-items: center; }
676.site-footer a { color: var(--ink-muted); text-decoration-color: var(--rule); }
677.site-footer a:hover { color: var(--accent); }
678.site-footer-links { display: flex; gap: 1rem; }
679.sep { color: var(--ink-faint); margin: 0 .5rem; }
680.footer-tagline { font-style: italic; opacity: .8; }
681
682@media print {
683 .masthead, .pagination, .site-footer, .article-footer, .top-nav { display: none; }
684 body { background: #fff; color: #000; }
685}
686@media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition: none !important; animation: none !important; } }
687
688/* ============================================================
689 V7 ADDITIONS — post metadata UI + audio player + post-images
690 ============================================================ */
691
692/* Post header */
693.post-header { margin: 0 0 2rem; }
694.post-cover {
695 margin: 0 0 1.5rem;
696 border-radius: 8px;
697 overflow: hidden;
698 background: color-mix(in srgb, var(--fg) 4%, transparent);
699}
700.post-cover img {
701 display: block;
702 width: 100%;
703 height: auto; /* volledige (niet-bijgesneden) hoogte */
704 /* geen max-height/object-fit: cover meer → de hele afbeelding toont,
705 volle containerbreedte, zijkanten gerespecteerd. */
706}
707.post-title { font-size: clamp(1.6rem, 4vw, 2.6rem); line-height: 1.15; margin: 0 0 .5rem; letter-spacing: -.02em; }
708
709/* Pin banner — duidelijk zichtbaar dat een post gepind is */
710.post-pin-banner {
711 display: inline-flex;
712 align-items: center;
713 gap: .5rem;
714 background: color-mix(in srgb, var(--accent) 14%, transparent);
715 border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
716 color: var(--accent);
717 padding: .4rem .8rem;
718 border-radius: 999px;
719 font-size: .75rem;
720 font-weight: 600;
721 text-transform: uppercase;
722 letter-spacing: .08em;
723 margin: 0 0 .85rem;
724 line-height: 1;
725}
726.post-pin-banner-icon { font-size: 1rem; line-height: 1; }
727.post-pin-banner-sep { opacity: .5; }
728.post-pin-banner-pos { opacity: .85; }
729.post-date {
730 color: var(--fg-muted, #888);
731 font-size: .85rem;
732 letter-spacing: .05em;
733 text-transform: uppercase;
734 margin: 0 0 1.5rem;
735}
736
737/* Post-images in content (resize + align) */
738.post-image {
739 margin: 1.5rem 0;
740}
741.post-image img {
742 display: block;
743 height: auto;
744 border-radius: 6px;
745 max-width: 100%;
746}
747.post-image figcaption {
748 font-size: .85rem;
749 color: var(--fg-muted, #888);
750 margin-top: .5rem;
751 font-style: italic;
752 text-align: center;
753}
754.post-image--small img { max-width: 240px; }
755.post-image--medium img { max-width: 440px; }
756.post-image--large img { max-width: 720px; }
757.post-image--full img { width: 100%; max-width: 100%; }
758.post-image--left { text-align: left; }
759.post-image--left img { margin-left: 0; margin-right: auto; }
760.post-image--center { text-align: center; }
761.post-image--center img { margin-left: auto; margin-right: auto; }
762.post-image--right { text-align: right; }
763.post-image--right img { margin-left: auto; margin-right: 0; }
764
765/* Afbeeldingen in de post-tekst vullen ALTIJD de containerbreedte en houden hun
766 natuurlijke (niet-bijgesneden) hoogte — geen vaste hoogte / geen crop. */
767.post-content img {
768 display: block;
769 width: 100%;
770 max-width: 100%;
771 height: auto;
772 border-radius: 6px;
773 margin: 1.4em auto;
774}
775
776/* Video in de post-tekst (C2S-uploads uit Shaer): dezelfde maatvoering als
777 afbeeldingen, plus een plafond. Zonder deze regel rendert een <video> op
778 zijn natuurlijke maat en duwt een portret-video de hele kolom vol; met
779 object-fit blijft het beeld heel binnen het kader. Geldt ook voor de
780 Krant/Berichten (tl-content), waar dezelfde content langskomt. */
781.post-content video, .tl-content video {
782 display: block;
783 width: 100%;
784 max-width: 100%;
785 max-height: min(70vh, 540px);
786 height: auto;
787 object-fit: contain;
788 background: #000;
789 border-radius: 6px;
790 margin: 1.4em auto;
791}
792.post-content audio, .tl-content audio { width: 100%; display: block; margin: 1em auto; }
793
794/* Mini-player + bottom-tab clearance: applied to .pcms-main so the footer
795 is NOT pushed below the viewport bottom. The bars are position:fixed so
796 they overlap whatever they sit on top of; the padding ensures the last
797 content row isn't covered. Footer naturally follows main and now sits
798 exactly at viewport-bottom on short pages (sticky footer flex). */
799.pcms-main { padding-bottom: 5.5rem; }
800body.has-audio-player .pcms-main { padding-bottom: 5.5rem; }
801
802/* Mobiel toetsenbord open (body.kb-open, gezet via visualViewport in shell.ejs):
803 verberg de vaste onderbalken — anders zweven de bottom-tab + mini-speler boven
804 het toetsenbord of overlappen ze het invoerveld. Ze komen terug zodra het
805 toetsenbord sluit. De extra clearance onderaan is dan ook niet meer nodig. */
806body.kb-open .bottom-tab,
807body.kb-open .audio-player { display: none !important; }
808body.kb-open .pcms-main { padding-bottom: 1rem; }
809
810/* Mobiel & tablet (touch): scrollbalken verbergen — scrollen blijft werken, alleen
811 de balk-UI is weg (geen verwarrende/dubbele balken). */
812@media (pointer: coarse) {
813 * { scrollbar-width: none; -ms-overflow-style: none; }
814 *::-webkit-scrollbar { width: 0; height: 0; display: none; }
815}
816
817/* Afbeeldingen lastiger op te slaan (frictie, geen echte beveiliging): geen
818 sleep-naar-bureaublad, geen iOS long-press-bewaarmenu. Rechtsklik wordt in JS
819 geblokkeerd (zie shell.ejs). Covers/hero zijn al CSS-achtergronden = niet via
820 "afbeelding opslaan" te pakken. */
821img { -webkit-user-drag: none; -khtml-user-drag: none; -moz-user-drag: none; user-drag: none; -webkit-touch-callout: none; }
822
823/* ============================================================
824 AUDIO PLAYER v7.1 — SVG iconen, thema-aware, geen emoji
825 ============================================================ */
826.audio-player {
827 position: fixed;
828 left: 0; right: 0; bottom: 0;
829 background: color-mix(in srgb, var(--paper, #fff) 96%, var(--ink, #000));
830 border-top: 1px solid var(--rule, rgba(0,0,0,.1));
831 color: var(--ink, #222);
832 z-index: 1000;
833 backdrop-filter: blur(12px);
834 -webkit-backdrop-filter: blur(12px);
835 box-shadow: 0 -4px 20px rgba(0,0,0,.04);
836}
837[data-theme="dark"] .audio-player {
838 background: color-mix(in srgb, var(--paper, #1a1a1a) 92%, #fff);
839 box-shadow: 0 -4px 20px rgba(0,0,0,.3);
840}
841.audio-player-inner {
842 display: grid;
843 grid-template-columns: minmax(0, 1.6fr) auto minmax(180px, 2fr) auto;
844 gap: 1rem;
845 align-items: center;
846 padding: .65rem 1.25rem;
847 max-width: 1400px;
848 margin: 0 auto;
849}
850
851/* v9.0 — Clickable trigger dat cover + meta combineert zodat klikken erop sheet opent */
852.audio-player-expand-trigger {
853 display: flex;
854 align-items: center;
855 gap: .65rem;
856 min-width: 0;
857 background: none;
858 border: none;
859 padding: 0;
860 margin: 0;
861 cursor: pointer;
862 color: inherit;
863 text-align: left;
864 font: inherit;
865 border-radius: 6px;
866 transition: background .15s;
867}
868.audio-player-expand-trigger:hover {
869 background: color-mix(in srgb, var(--ink, #000) 6%, transparent);
870}
871
872/* Cover art */
873.audio-player-cover {
874 width: 48px; height: 48px;
875 border-radius: 4px;
876 background: linear-gradient(135deg,
877 var(--accent, #c2410c),
878 color-mix(in srgb, var(--accent, #c2410c) 55%, #000));
879 background-size: cover;
880 background-position: center;
881 flex-shrink: 0;
882 position: relative;
883}
884.audio-player-cover.has-image {
885 background-blend-mode: normal;
886}
887
888/* Meta — titel + artiest */
889.audio-player-meta {
890 min-width: 0;
891 display: flex;
892 flex-direction: column;
893 gap: 2px;
894}
895.audio-player-title-wrap {
896 overflow: hidden;
897 white-space: nowrap;
898 position: relative;
899}
900.audio-player-title {
901 display: inline-block;
902 font-family: var(--font-ui, inherit);
903 font-weight: 600;
904 font-size: .9rem;
905 line-height: 1.3;
906 letter-spacing: -.01em;
907 color: var(--ink, inherit);
908 white-space: nowrap;
909}
910.audio-player-title.is-overflowing {
911 animation: audio-title-marquee 6s ease-in-out infinite alternate;
912}
913@keyframes audio-title-marquee {
914 0%, 8% { transform: translateX(0); }
915 92%, 100% { transform: translateX(calc(-1 * var(--audio-shift, 0px))); }
916}
917.audio-player-artist {
918 font-family: var(--font-ui, inherit);
919 font-size: .74rem;
920 line-height: 1.3;
921 color: var(--ink-muted, rgba(0,0,0,.55));
922 white-space: nowrap;
923 overflow: hidden;
924 text-overflow: ellipsis;
925}
926
927/* Controls — prev / play / next */
928.audio-player-controls {
929 display: flex;
930 gap: .1rem;
931 align-items: center;
932}
933.audio-btn {
934 background: transparent;
935 border: none;
936 color: inherit;
937 cursor: pointer;
938 padding: .5rem;
939 border-radius: 50%;
940 transition: background .15s, color .15s, transform .08s;
941 display: inline-flex;
942 align-items: center;
943 justify-content: center;
944 position: relative;
945}
946.audio-btn svg {
947 width: 18px; height: 18px;
948 display: block;
949}
950.audio-btn:hover { background: color-mix(in srgb, var(--ink, #000) 8%, transparent); }
951.audio-btn:active { transform: scale(.94); }
952.audio-btn-play {
953 background: var(--accent, #c2410c);
954 color: #fff;
955 width: 38px; height: 38px;
956 padding: 0;
957}
958.audio-btn-play:hover {
959 background: color-mix(in srgb, var(--accent, #c2410c) 85%, #fff);
960}
961[data-theme="dark"] .audio-btn-play:hover {
962 background: color-mix(in srgb, var(--accent, #c2410c) 85%, #000);
963}
964.audio-btn-play svg { width: 16px; height: 16px; }
965.audio-btn-play .icon-pause { display: none; }
966.audio-player.is-playing .audio-btn-play .icon-play { display: none; }
967.audio-player.is-playing .audio-btn-play .icon-pause { display: block; }
968
969/* Progress bar */
970.audio-player-progress {
971 display: flex;
972 gap: .75rem;
973 align-items: center;
974 min-width: 0;
975}
976.audio-time {
977 font-size: .7rem;
978 color: var(--ink-muted, rgba(0,0,0,.55));
979 font-variant-numeric: tabular-nums;
980 min-width: 2.7em;
981 text-align: center;
982}
983.audio-seek {
984 flex: 1;
985 min-width: 0;
986 cursor: pointer;
987 padding: .5rem 0;
988 position: relative;
989}
990.audio-seek-bar {
991 height: 3px;
992 background: color-mix(in srgb, var(--ink, #000) 12%, transparent);
993 border-radius: 2px;
994 overflow: hidden;
995 transition: height .15s;
996}
997.audio-seek:hover .audio-seek-bar { height: 5px; }
998.audio-seek-fill {
999 height: 100%;
1000 background: var(--accent, #c2410c);
1001 width: 0%;
1002 transition: width .1s linear;
1003}
1004
1005/* Volume — popup on hover */
1006.audio-player-volume {
1007 position: relative;
1008 display: flex;
1009 align-items: center;
1010}
1011.audio-btn .icon-mute { display: none; }
1012.audio-player.is-muted .audio-btn .icon-vol { display: none; }
1013.audio-player.is-muted .audio-btn .icon-mute { display: block; }
1014.audio-volume-popup {
1015 position: absolute;
1016 bottom: calc(100% + 8px);
1017 left: 50%;
1018 transform: translateX(-50%) scale(.95);
1019 transform-origin: bottom center;
1020 background: var(--paper, #fff);
1021 border: 1px solid var(--rule, rgba(0,0,0,.1));
1022 border-radius: 8px;
1023 padding: .75rem .5rem;
1024 box-shadow: 0 4px 16px rgba(0,0,0,.15);
1025 opacity: 0;
1026 pointer-events: none;
1027 transition: opacity .15s, transform .15s, visibility .15s;
1028 height: 110px;
1029 visibility: hidden;
1030}
1031/* Invisible bridge tussen knop en popup zodat hover niet breekt */
1032.audio-volume-popup::after {
1033 content: '';
1034 position: absolute;
1035 bottom: -12px;
1036 left: -10px;
1037 right: -10px;
1038 height: 16px;
1039}
1040[data-theme="dark"] .audio-volume-popup {
1041 background: color-mix(in srgb, var(--paper, #111) 92%, #fff);
1042}
1043.audio-player-volume:hover .audio-volume-popup,
1044.audio-player-volume:focus-within .audio-volume-popup,
1045.audio-player-volume.is-open .audio-volume-popup {
1046 opacity: 1;
1047 visibility: visible;
1048 transform: translateX(-50%) scale(1);
1049 pointer-events: auto;
1050}
1051.audio-volume-popup input[type=range] {
1052 /* Standard vertical slider — replaces deprecated -webkit-appearance: slider-vertical. */
1053 writing-mode: vertical-lr;
1054 direction: rtl;
1055 width: 6px;
1056 height: 90px;
1057 accent-color: var(--accent, #c2410c);
1058 /* Grotere hit-area via pseudo-touch padding */
1059 padding: 0 12px;
1060 box-sizing: content-box;
1061 cursor: pointer;
1062}
1063
1064/* Mobile */
1065@media (max-width: 720px) {
1066 .audio-player-inner {
1067 /* v9.0 — 3 cols: expand-trigger (cover+meta) | controls | volume */
1068 grid-template-columns: minmax(0, 1fr) auto auto;
1069 gap: .5rem;
1070 padding: .5rem .8rem;
1071 }
1072 .audio-player-progress {
1073 display: none;
1074 }
1075 .audio-player-cover { width: 40px; height: 40px; }
1076 .audio-btn-play { width: 34px; height: 34px; }
1077 body.has-audio-player .pcms-main { padding-bottom: 4.2rem; }
1078 /* Verberg titel-artiest op bijzonder smal, verstop volume op mobile */
1079 .audio-player-volume { display: none; }
1080}
1081
1082/* Ultra-small schermen (iPhone 4 = 320px; iPhone SE 1st gen = 320px;
1083 iPhone mini ~360px). v9.3 — alles vanaf 320px moet werken; daaronder
1084 accepteren we wel/niet. */
1085@media (max-width: 380px) {
1086 .audio-player-inner {
1087 gap: .35rem;
1088 padding: .4rem .6rem;
1089 }
1090 .audio-player-expand-trigger {
1091 gap: .45rem;
1092 }
1093 .audio-player-cover { width: 36px; height: 36px; }
1094 .audio-player-title { font-size: .88rem; }
1095 .audio-player-artist { font-size: .72rem; }
1096 .audio-player-controls { gap: .15rem; }
1097 .audio-btn { width: 30px; height: 30px; }
1098 .audio-btn svg { width: 16px; height: 16px; }
1099 .audio-btn-play { width: 32px; height: 32px; }
1100 .audio-btn-play svg { width: 18px; height: 18px; }
1101
1102 /* v9.3 — Tracklist compact op smalle telefoons.
1103 Leader 28×28, kleinere gap, padding strakker. Tijd in monoscript blijft
1104 leesbaar; titel krijgt 5-10px meer ruimte. */
1105 .pat-row {
1106 grid-template-columns: 28px 1fr auto;
1107 gap: .5rem;
1108 padding: .45rem .65rem;
1109 }
1110 .pat-row .pat-num,
1111 .pat-row .pat-cover {
1112 width: 28px;
1113 height: 28px;
1114 }
1115 .pat-row::before {
1116 left: .65rem;
1117 width: 28px; height: 28px;
1118 -webkit-mask-size: 22px 22px;
1119 mask-size: 22px 22px;
1120 }
1121 .pat-row .pat-title { font-size: .92rem; }
1122 .pat-row .pat-artist { font-size: .74rem; }
1123 .pat-row .pat-duration { font-size: .74rem; }
1124
1125 /* v9.3 — Album binnen post: cover + tracks compacter */
1126 .post-album-cover {
1127 width: 90px;
1128 height: 90px;
1129 }
1130 .post-album-header {
1131 gap: .65rem;
1132 padding: .65rem;
1133 }
1134 .post-album-title { font-size: 1rem; }
1135
1136 /* v9.3 — Profile-header bovenin compacter */
1137 .profile-photo {
1138 width: 48px !important;
1139 height: 48px !important;
1140 }
1141 .profile-content {
1142 gap: .65rem;
1143 }
1144
1145 /* v9.3 — Install-app modal: minder padding, kleinere knoppen */
1146 .install-modal-inner {
1147 padding: 1rem;
1148 }
1149 .install-app-btn {
1150 padding: .55rem 1rem;
1151 font-size: .9rem;
1152 }
1153
1154 /* v9.3 — horizontaal clippen gebeurt nu globaal op html (zie de html-regel
1155 bovenaan). Hier bewust NIETS op body zetten: body als scroll-container zou
1156 de fixed bottom-tab op mobiel laten meeschuiven. */
1157}
1158
1159/* iPhone 4 / iPhone SE 1st gen / iPhone 5/5s (320px) — strakste niveau */
1160@media (max-width: 340px) {
1161 .audio-player-inner {
1162 padding: .35rem .5rem;
1163 }
1164 .audio-player-artist { display: none; }
1165 .audio-player-cover { width: 32px; height: 32px; }
1166 body.has-audio-player .pcms-main { padding-bottom: 3.6rem; }
1167 /* Expand-sheet wat strakker */
1168 .audio-sheet-panel {
1169 padding: .5rem 1rem 1.5rem;
1170 }
1171 .audio-sheet-title { font-size: 1.2rem; }
1172 .audio-sheet-artist { font-size: .9rem; }
1173 .audio-sheet-play { width: 60px; height: 60px; }
1174 .audio-sheet-play svg { width: 26px; height: 26px; }
1175 .audio-sheet-btn { width: 42px; height: 42px; }
1176 .audio-sheet-btn svg { width: 24px; height: 24px; }
1177 .audio-sheet-controls { gap: 1rem; }
1178
1179 /* v9.3 — Op iPhone 4 (320px): tracklist nog strakker */
1180 .pat-row {
1181 grid-template-columns: 26px 1fr auto;
1182 gap: .4rem;
1183 padding: .4rem .55rem;
1184 }
1185 .pat-row .pat-num,
1186 .pat-row .pat-cover {
1187 width: 26px;
1188 height: 26px;
1189 }
1190 .pat-row::before {
1191 left: .55rem;
1192 width: 26px; height: 26px;
1193 -webkit-mask-size: 20px 20px;
1194 mask-size: 20px 20px;
1195 }
1196 .pat-row .pat-artist {
1197 display: none; /* op extreem smal weglaten ten gunste van titel */
1198 }
1199 .pat-row .pat-title { font-size: .9rem; }
1200 .pat-row .pat-duration { font-size: .72rem; }
1201
1202 /* Container padding reduceren voor max content-breedte */
1203 .container {
1204 padding-inline: 1rem !important;
1205 }
1206
1207 /* Post-cover (de grote bovenste) krimpen */
1208 .post-cover {
1209 max-height: 200px;
1210 }
1211}
1212
1213/* ============================================================
1214 v9.0 — Audio player expand-sheet (Spotify-style "now playing")
1215 Slide-up half-screen met grote cover, track info, big controls
1216 ============================================================ */
1217.audio-sheet {
1218 position: fixed;
1219 inset: 0;
1220 z-index: 1100;
1221 pointer-events: none;
1222 opacity: 0;
1223 transition: opacity .25s ease;
1224}
1225.audio-sheet.is-open {
1226 pointer-events: auto;
1227 opacity: 1;
1228}
1229.audio-sheet-backdrop {
1230 position: absolute;
1231 inset: 0;
1232 /* v9.3 — Blur en overlay-dim allebei via CSS-variabele --pcms-sheet-progress
1233 (1 = volledig, 0 = weg). JS update tijdens drag; CSS-transition pakt
1234 open/close af. Sterke blur (24px) zodat 't effect goed zichtbaar is. */
1235 background: rgb(0 0 0 / calc(.4 * var(--pcms-sheet-progress, 1)));
1236 backdrop-filter: blur(calc(24px * var(--pcms-sheet-progress, 1)));
1237 -webkit-backdrop-filter: blur(calc(24px * var(--pcms-sheet-progress, 1)));
1238 transition: background .25s ease,
1239 backdrop-filter .25s ease,
1240 -webkit-backdrop-filter .25s ease;
1241 will-change: backdrop-filter, background;
1242}
1243/* Tijdens drag: instant updates vanuit JS, geen transition */
1244.audio-sheet-panel.is-dragging ~ .audio-sheet-backdrop,
1245.audio-sheet-backdrop.is-dragging {
1246 transition: none;
1247}
1248.audio-sheet-panel {
1249 position: absolute;
1250 left: 0; right: 0; bottom: 0;
1251 background: var(--paper, #fff);
1252 border-top-left-radius: 20px;
1253 border-top-right-radius: 20px;
1254 box-shadow: 0 -20px 60px rgba(0, 0, 0, .25);
1255 padding: .75rem 1.5rem 2rem;
1256 max-height: 85vh;
1257 overflow-y: auto;
1258 /* v9.2.1 — scroll blijft binnen panel, geen chaining naar body (iOS-proof) */
1259 overscroll-behavior: contain;
1260 touch-action: pan-y;
1261 /* Hide scrollbar but keep scrollable */
1262 scrollbar-width: none; /* Firefox */
1263 -ms-overflow-style: none; /* IE/Edge */
1264 transform: translateY(100%);
1265 transition: transform .3s cubic-bezier(.22, .9, .3, 1),
1266 opacity .3s cubic-bezier(.22, .9, .3, 1);
1267 display: flex;
1268 flex-direction: column;
1269 gap: 1rem;
1270 color: var(--ink);
1271}
1272.audio-sheet-panel::-webkit-scrollbar {
1273 display: none; /* Chrome/Safari */
1274}
1275/* Body scroll lock wanneer sheet open is */
1276body.audio-sheet-locked {
1277 overflow: hidden;
1278}
1279.audio-sheet.is-open .audio-sheet-panel {
1280 transform: translateY(0);
1281}
1282
1283/* v9.3 — Drag-zone: pill bovenaan + cover. Hele strook is touch-target voor
1284 swipe-down-to-close. Pull-to-refresh is uitgeschakeld op html-niveau dus
1285 geen interferentie. Onder de cover (info/progress/controls/queue) werkt
1286 normale touch — knoppen, scroll in queue, etc. */
1287.audio-sheet-drag-zone {
1288 flex-shrink: 0;
1289 display: flex;
1290 flex-direction: column;
1291 align-items: stretch;
1292 gap: 1rem;
1293 /* v9.3 — touch-action: pan-y staat verticale scroll toe (zodat queue
1294 eronder scrollt als gebruiker omhoog veegt over cover). Onze JS
1295 detecteert intent: alleen omlaag-swipe vanaf de top sluit de sheet,
1296 omhoog-swipe = scroll. */
1297 touch-action: pan-y;
1298 user-select: none;
1299 -webkit-user-select: none;
1300 cursor: grab;
1301 margin: -.75rem -1.5rem 0;
1302 padding: .75rem 1.5rem 0;
1303}
1304.audio-sheet-drag-zone:active { cursor: grabbing; }
1305
1306/* v9.4 — Drag alleen actief op touch-only apparaten (telefoons).
1307 Desktop met muis + tablets met muis-cursor → geen drag-grip,
1308 gebruiker sluit via × pill-knop bovenin of klik op backdrop. */
1309@media (hover: hover) and (pointer: fine) {
1310 .audio-sheet-drag-zone {
1311 touch-action: auto;
1312 cursor: default;
1313 pointer-events: none;
1314 }
1315 /* Pill blijft klikbaar als sluit-knop */
1316 .audio-sheet-drag-zone .audio-sheet-handle {
1317 pointer-events: auto;
1318 cursor: pointer;
1319 }
1320}
1321
1322/* Pill (handle) gecentreerd boven de cover */
1323.audio-sheet-drag-zone .audio-sheet-handle {
1324 margin: 0 auto .25rem;
1325}
1326
1327/* Tijdens dragging: panel volgt vinger realtime; geen transition */
1328.audio-sheet-panel.is-dragging {
1329 transition: none;
1330 will-change: transform;
1331}
1332[data-theme="dark"] .audio-sheet-panel {
1333 background: var(--paper, #1a1a1a);
1334 box-shadow: 0 -20px 60px rgba(0, 0, 0, .5);
1335}
1336/* Drag-handle + close button in één */
1337.audio-sheet-handle {
1338 display: block;
1339 width: 48px;
1340 height: 4px;
1341 border-radius: 2px;
1342 background: color-mix(in srgb, var(--ink, #000) 25%, transparent);
1343 border: none;
1344 margin: 0 auto .5rem;
1345 padding: 0;
1346 cursor: pointer;
1347 flex-shrink: 0;
1348 position: relative;
1349}
1350.audio-sheet-handle::before {
1351 content: "";
1352 position: absolute;
1353 /* v9.3 — Drag-strip wrapper neemt nu de hit-area-rol over. ::before
1354 blijft als kleine extra padding voor click-comfort. */
1355 inset: -10px -20px;
1356}
1357.audio-sheet-handle:hover {
1358 background: color-mix(in srgb, var(--ink, #000) 45%, transparent);
1359}
1360/* Grote cover */
1361.audio-sheet-cover {
1362 width: 100%;
1363 max-width: 360px;
1364 aspect-ratio: 1/1;
1365 margin: 0 auto;
1366 border-radius: 12px;
1367 background: linear-gradient(135deg,
1368 var(--accent, #c2410c),
1369 color-mix(in srgb, var(--accent, #c2410c) 55%, #000));
1370 background-size: cover;
1371 background-position: center;
1372 box-shadow: 0 20px 40px rgba(0, 0, 0, .15);
1373 flex-shrink: 0;
1374}
1375[data-theme="dark"] .audio-sheet-cover {
1376 box-shadow: 0 20px 40px rgba(0, 0, 0, .4);
1377}
1378.audio-sheet-info {
1379 text-align: center;
1380 padding: 0 1rem;
1381}
1382.audio-sheet-title {
1383 font-family: var(--font-display, inherit);
1384 font-size: 1.5rem;
1385 font-weight: 600;
1386 line-height: 1.2;
1387 margin: 0 0 .25rem;
1388 letter-spacing: -0.01em;
1389 color: var(--ink);
1390}
1391.audio-sheet-artist {
1392 font-size: 1rem;
1393 color: var(--ink-muted, var(--ink));
1394 opacity: .7;
1395}
1396.audio-sheet-album {
1397 margin-top: .35rem;
1398 font-size: .82rem;
1399 opacity: .5;
1400 text-transform: uppercase;
1401 letter-spacing: .05em;
1402}
1403.audio-sheet-album:empty { display: none; }
1404/* Progress + time */
1405.audio-sheet-progress {
1406 display: grid;
1407 grid-template-columns: auto 1fr auto;
1408 gap: .6rem;
1409 align-items: center;
1410 padding: 0 .5rem;
1411}
1412.audio-sheet-progress .audio-seek { width: 100%; }
1413.audio-sheet-progress .audio-time {
1414 font-size: .78rem;
1415 opacity: .55;
1416}
1417/* Grote controls */
1418.audio-sheet-controls {
1419 display: flex;
1420 align-items: center;
1421 justify-content: center;
1422 gap: 1.75rem;
1423}
1424.audio-sheet-btn {
1425 width: 48px;
1426 height: 48px;
1427 padding: 0;
1428}
1429.audio-sheet-btn svg { width: 28px; height: 28px; }
1430.audio-sheet-play {
1431 width: 72px;
1432 height: 72px;
1433 border-radius: 50%;
1434 background: var(--accent, #c2410c);
1435 color: var(--paper, #fff);
1436 border: none;
1437 cursor: pointer;
1438 display: inline-flex;
1439 align-items: center;
1440 justify-content: center;
1441 transition: transform .1s;
1442}
1443.audio-sheet-play:hover { transform: scale(1.05); }
1444.audio-sheet-play:active { transform: scale(.95); }
1445.audio-sheet-play svg { width: 30px; height: 30px; }
1446.audio-sheet-play .icon-pause { display: none; }
1447/* v9.2.1 — sheet staat nu als sibling van .audio-player buiten de balk,
1448 dus ancestor-selector .audio-player.is-playing werkt niet meer voor de
1449 sheet. JS zet is-playing ook rechtstreeks op sheet.play (regel 551 app.js). */
1450.audio-sheet-play.is-playing .icon-play { display: none; }
1451.audio-sheet-play.is-playing .icon-pause { display: block; }
1452/* v9.2.1 — fallback: als sheet buiten alle ancestors zit, tag body */
1453body.audio-is-playing .audio-sheet-play .icon-play { display: none; }
1454body.audio-is-playing .audio-sheet-play .icon-pause { display: block; }
1455
1456/* v9.3 — Loading state: roterende spiraal (het roboburr logo).
1457 Button-achtergrond wordt transparant, play/pause svgs verbergen, en de
1458 spiraal verschijnt als roterende background via ::after pseudo-element.
1459 Cool-effect: zachte hue-drift geeft de kleur een levend gevoel. */
1460.audio-player.is-loading .audio-btn-play,
1461.audio-player.is-loading .audio-sheet-play,
1462body.audio-is-loading .audio-sheet-play,
1463.pat-row.is-loading {
1464 pointer-events: none;
1465}
1466.audio-player.is-loading .audio-btn-play,
1467.audio-player.is-loading .audio-sheet-play,
1468body.audio-is-loading .audio-sheet-play {
1469 background: transparent;
1470 box-shadow: none;
1471}
1472
1473/* v9.3 — Play/pause-icons in de player-knoppen faden smooth uit/in tijdens
1474 loading. Pseudo-spiraal faded tegelijkertijd in (geen instant pop). */
1475.audio-btn-play > svg,
1476.audio-sheet-play > svg {
1477 transition: opacity .35s cubic-bezier(.4, 0, .2, 1),
1478 transform .35s cubic-bezier(.4, 0, .2, 1);
1479}
1480.audio-player.is-loading .audio-btn-play > svg,
1481.audio-player.is-loading .audio-sheet-play > svg,
1482body.audio-is-loading .audio-sheet-play > svg {
1483 opacity: 0;
1484 transform: scale(.7);
1485}
1486.pat-row.is-loading .pat-play-icon > svg,
1487.pat-row.is-loading .pat-num,
1488.pat-row.is-loading .pat-cover {
1489 opacity: 0;
1490}
1491
1492/* v9.3 — Spiraal als pseudo-element, ALTIJD aanwezig met opacity 0 default.
1493 Bij is-loading faden 'ie smooth in (opacity + scale-bounce), bij klaar
1494 faden 'ie weer uit. Pure accent-kleur, geen hue-drift. */
1495.audio-player .audio-btn-play,
1496.audio-player .audio-sheet-play,
1497.pat-row .pat-play-icon {
1498 position: relative;
1499}
1500.audio-btn-play::after,
1501.audio-sheet-play::after {
1502 content: "";
1503 position: absolute;
1504 inset: 0;
1505 background-color: var(--accent, #c2410c);
1506 -webkit-mask: url('/assets/spinner.svg') center/contain no-repeat;
1507 mask: url('/assets/spinner.svg') center/contain no-repeat;
1508 opacity: 0;
1509 transform: scale(.6);
1510 transition: opacity .4s cubic-bezier(.4, 0, .2, 1),
1511 transform .4s cubic-bezier(.34, 1.56, .64, 1);
1512 pointer-events: none;
1513 animation: pcms-spiral-spin 1.2s linear infinite paused;
1514 will-change: opacity, transform;
1515}
1516.audio-player.is-loading .audio-btn-play::after,
1517.audio-player.is-loading .audio-sheet-play::after,
1518body.audio-is-loading .audio-sheet-play::after {
1519 opacity: 1;
1520 transform: scale(1);
1521 animation-play-state: running;
1522}
1523/* Pat-row keeps its existing ::before spinner from earlier change.
1524 Voor backward-compat als oude HTML nog .pat-play-icon::after spinner had */
1525.pat-row.is-loading .pat-play-icon::after {
1526 content: "";
1527 position: absolute;
1528 inset: 0;
1529 background-color: var(--accent, #c2410c);
1530 -webkit-mask: url('/assets/spinner.svg') center/contain no-repeat;
1531 mask: url('/assets/spinner.svg') center/contain no-repeat;
1532 opacity: 1;
1533 animation: pcms-spiral-spin 1.2s linear infinite;
1534 pointer-events: none;
1535}
1536@keyframes pcms-spiral-spin {
1537 to { transform: scale(1) rotate(-360deg); }
1538}
1539/* Queue list */
1540.audio-sheet-queue {
1541 margin-top: .5rem;
1542 padding-top: 1rem;
1543 border-top: 1px solid var(--rule);
1544}
1545.audio-sheet-queue-label {
1546 font-size: .75rem;
1547 text-transform: uppercase;
1548 letter-spacing: .08em;
1549 opacity: .5;
1550 font-weight: 600;
1551 margin-bottom: .5rem;
1552 padding: 0 .5rem;
1553}
1554.audio-sheet-queue-list {
1555 list-style: none;
1556 padding: 0;
1557 margin: 0;
1558 display: flex;
1559 flex-direction: column;
1560 gap: 2px;
1561}
1562.audio-sheet-queue-item {
1563 display: flex;
1564 align-items: center;
1565 gap: .75rem;
1566 padding: .5rem .6rem;
1567 border-radius: 6px;
1568 cursor: pointer;
1569 transition: background .15s;
1570 background: none;
1571 border: none;
1572 width: 100%;
1573 color: inherit;
1574 font: inherit;
1575 text-align: left;
1576}
1577.audio-sheet-queue-item:hover {
1578 background: color-mix(in srgb, var(--ink, #000) 6%, transparent);
1579}
1580.audio-sheet-queue-item.is-current {
1581 background: color-mix(in srgb, var(--accent, #c2410c) 14%, transparent);
1582 color: var(--accent, #c2410c);
1583}
1584.audio-sheet-queue-cover {
1585 width: 36px;
1586 height: 36px;
1587 border-radius: 4px;
1588 background-size: cover;
1589 background-position: center;
1590 background-color: var(--rule);
1591 flex-shrink: 0;
1592}
1593.audio-sheet-queue-meta {
1594 flex: 1;
1595 min-width: 0;
1596 display: flex;
1597 flex-direction: column;
1598}
1599.audio-sheet-queue-title {
1600 font-size: .9rem;
1601 font-weight: 500;
1602 overflow: hidden;
1603 text-overflow: ellipsis;
1604 white-space: nowrap;
1605}
1606.audio-sheet-queue-artist {
1607 font-size: .75rem;
1608 opacity: .55;
1609 overflow: hidden;
1610 text-overflow: ellipsis;
1611 white-space: nowrap;
1612}
1613.audio-sheet-queue-duration {
1614 font-family: ui-monospace, monospace;
1615 font-size: .72rem;
1616 opacity: .5;
1617 flex-shrink: 0;
1618}
1619
1620/* Desktop: sheet is max 480px wide and centered for bigger screens */
1621@media (min-width: 720px) {
1622 .audio-sheet-panel {
1623 left: 50%;
1624 right: auto;
1625 width: 480px;
1626 transform: translate(-50%, 100%);
1627 border-top-left-radius: 20px;
1628 border-top-right-radius: 20px;
1629 }
1630 .audio-sheet.is-open .audio-sheet-panel {
1631 transform: translate(-50%, 0);
1632 }
1633}
1634
1635/* v9.2.1 — Mobiel: sheet is fullscreen, alleen te sluiten via handle-knop bovenin.
1636 Geen rounded corners, volledige viewport, safe-area voor notches/status bar. */
1637@media (max-width: 719.98px) {
1638 .audio-sheet-panel {
1639 inset: 0;
1640 max-height: none;
1641 border-top-left-radius: 0;
1642 border-top-right-radius: 0;
1643 box-shadow: none;
1644 padding-top: calc(.75rem + var(--ios-safe-top, 0px));
1645 padding-bottom: calc(2rem + env(safe-area-inset-bottom, 0px));
1646 }
1647 /* v9.3 — Backdrop blijft visible op mobile zodat drag-gesture de blur
1648 laat doorschemeren naar helder. */
1649}
1650
1651/* ============================================================
1652 Mobile masthead + pagination
1653 ============================================================ */
1654@media (max-width: 600px) {
1655 .masthead-inner { gap: .35rem; }
1656 .site-title { font-size: 1.2rem; }
1657 .site-subtitle { display: none; }
1658 .top-nav { gap: .1rem; }
1659 .nav-label { display: none; }
1660 .nav-btn, .nav-link {
1661 padding: .4rem .45rem;
1662 min-width: 38px;
1663 justify-content: center;
1664 }
1665 .pagination { flex-direction: column; gap: .5rem; }
1666 .pagination-item { width: 100%; }
1667}
1668
1669/* Taal-keuze in de header-nav (NL/EN/DE) — eigen gestylede dropdown. */
1670.lang-menu { position: relative; }
1671.lang-menu > summary {
1672 list-style: none; cursor: pointer;
1673 display: inline-flex; align-items: center; gap: .3rem;
1674 padding: .35rem .55rem; border-radius: 999px;
1675 border: 1px solid var(--rule); background: transparent; color: var(--ink);
1676}
1677.lang-menu > summary::-webkit-details-marker { display: none; }
1678.lang-menu > summary:hover { border-color: var(--accent); }
1679.lang-toggle .lang-code { font-size: .8rem; font-weight: 700; letter-spacing: .02em; }
1680.lang-toggle .icon { width: 16px; height: 16px; opacity: .8; }
1681.lang-caret { width: 12px; height: 12px; opacity: .7; transition: transform .15s; }
1682.lang-menu[open] .lang-caret { transform: rotate(180deg); }
1683.lang-dropdown {
1684 position: absolute; top: calc(100% + 8px); right: 0;
1685 min-width: 170px; z-index: 60;
1686 background: var(--paper); border: 1px solid var(--rule);
1687 border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,.22);
1688 padding: .35rem; display: flex; flex-direction: column;
1689}
1690.lang-item {
1691 display: flex; align-items: center; gap: .6rem;
1692 padding: .5rem .65rem; border-radius: 8px;
1693 color: var(--ink); text-decoration: none; font-size: .9rem;
1694}
1695.lang-item:hover { background: var(--paper-2); }
1696.lang-item.is-active { color: var(--accent); font-weight: 600; }
1697.lang-item-code {
1698 font-size: .7rem; font-weight: 700; opacity: .6;
1699 min-width: 1.6em;
1700}
1701@media (max-width: 400px) {
1702 .masthead { padding: calc(.5rem + var(--ios-safe-top, 0px)) 0 .5rem; }
1703 .masthead-inner { gap: .25rem; }
1704 .site-title { font-size: 1.05rem; }
1705 .nav-btn, .nav-link {
1706 padding: .35rem .3rem;
1707 min-width: 34px;
1708 }
1709 .nav-btn .icon, .nav-link .icon { width: 1rem; height: 1rem; }
1710 /* PWA-install knop verbergen op klein scherm — kan ook via menu */
1711 .nav-install-btn { display: none !important; }
1712}
1713@media (max-width: 340px) {
1714 .site-title { font-size: .95rem; }
1715 .nav-btn, .nav-link { padding: .3rem .25rem; min-width: 30px; }
1716 /* Theme-toggle verbergen op ultra-klein — kan via user-menu */
1717 [data-pcms-theme-toggle] { display: none; }
1718}
1719
1720.post-date-ago {
1721 margin-left: .5em;
1722 opacity: .6;
1723 font-size: .9em;
1724 font-style: italic;
1725 text-transform: none;
1726 letter-spacing: 0;
1727}
1728
1729/* HTMX loading indicator — subtle progress-bar aan de top van de content */
1730.pcms-loading {
1731 position: fixed;
1732 top: 0; left: 0;
1733 height: 2px;
1734 width: 0%;
1735 background: var(--accent, #c2410c);
1736 z-index: 9999;
1737 transition: width .3s ease, opacity .2s;
1738 opacity: 0;
1739 pointer-events: none;
1740}
1741.pcms-loading.htmx-request {
1742 opacity: 1;
1743 width: 80%;
1744 transition: width 6s cubic-bezier(.1,.9,.2,1), opacity .2s;
1745}
1746/* subtile fade wanneer content gewisseld wordt */
1747#pcms-main.htmx-swapping {
1748 opacity: .5;
1749 transition: opacity .15s;
1750}
1751
1752/* Masthead brand group (site-title + optional tagline) */
1753.masthead-brand { display: flex; flex-direction: column; gap: 2px; }
1754.site-subtitle {
1755 font-family: var(--font-ui, inherit);
1756 font-size: .75rem;
1757 color: var(--ink-muted, rgba(0,0,0,.55));
1758 letter-spacing: 0;
1759 line-height: 1.3;
1760}
1761
1762/* ============================================================
1763 v7.3 — TAGS, TYPE, ARCHIEF, ZOEK, RELATED, SPECIAL VIEWS
1764 ============================================================ */
1765
1766/* Post-meta row — datum + type-chip + tags samen onder de titel */
1767.post-meta {
1768 display: flex;
1769 flex-wrap: wrap;
1770 align-items: center;
1771 gap: .5rem .85rem;
1772 margin-top: .5rem;
1773}
1774.post-meta .post-date { margin: 0; }
1775
1776/* Type-chip (groter, als een label) */
1777.post-type-chip {
1778 display: inline-flex;
1779 align-items: center;
1780 padding: .2rem .6rem;
1781 background: color-mix(in srgb, var(--accent) 10%, transparent);
1782 color: var(--accent);
1783 border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
1784 border-radius: 999px;
1785 font-family: var(--font-ui);
1786 font-size: .72rem;
1787 font-weight: 600;
1788 text-decoration: none;
1789 letter-spacing: .04em;
1790 text-transform: uppercase;
1791 transition: background .15s;
1792}
1793.post-type-chip:hover { background: color-mix(in srgb, var(--accent) 20%, transparent); }
1794
1795/* Tag-chips — klein, subtiel, gelinkt */
1796.post-tags, .post-list-tags {
1797 display: inline-flex;
1798 flex-wrap: wrap;
1799 gap: .3rem;
1800}
1801.tag-chip {
1802 display: inline-block;
1803 padding: .15rem .55rem;
1804 background: color-mix(in srgb, var(--ink) 5%, transparent);
1805 color: var(--ink-muted);
1806 border-radius: 999px;
1807 font-family: var(--font-ui);
1808 font-size: .72rem;
1809 font-weight: 500;
1810 text-decoration: none;
1811 transition: background .15s, color .15s;
1812}
1813.tag-chip:hover {
1814 background: color-mix(in srgb, var(--accent) 12%, transparent);
1815 color: var(--accent);
1816}
1817
1818/* ============================================================
1819 SPECIAL PAGES (archief, tag, type, zoek)
1820 ============================================================ */
1821.special-page .post-header { margin-bottom: 2rem; }
1822.special-eyebrow {
1823 font-size: .72rem;
1824 color: var(--ink-muted);
1825 text-transform: uppercase;
1826 letter-spacing: .12em;
1827 margin: 0 0 .25rem;
1828}
1829
1830/* Archief: jaar-overzicht */
1831.archive-years {
1832 display: flex;
1833 flex-direction: column;
1834 gap: 2rem;
1835}
1836.archive-year h2 {
1837 font-family: var(--font-display);
1838 font-size: 1.75rem;
1839 margin: 0 0 .75rem;
1840}
1841.archive-year h2 a {
1842 color: var(--ink);
1843 text-decoration: none;
1844}
1845.archive-year h2 a:hover { color: var(--accent); }
1846.archive-year h2 .admin-muted { font-size: .9rem; font-weight: normal; color: var(--ink-muted); }
1847.archive-months {
1848 list-style: none;
1849 padding: 0; margin: 0;
1850 display: grid;
1851 grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
1852 gap: .5rem;
1853}
1854.archive-months li {
1855 display: flex;
1856 align-items: center;
1857 gap: .4rem;
1858 padding: .55rem .75rem;
1859 background: color-mix(in srgb, var(--ink) 3%, transparent);
1860 border-radius: var(--radius);
1861 transition: background .15s;
1862}
1863.archive-months li:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); }
1864.archive-months a {
1865 color: var(--ink);
1866 text-decoration: none;
1867 font-weight: 500;
1868 font-size: .95rem;
1869}
1870.archive-months .admin-muted { font-size: .75rem; color: var(--ink-muted); margin-left: auto; }
1871
1872/* Archief: jaar drill-down */
1873.archive-month-list {
1874 display: flex;
1875 flex-direction: column;
1876 gap: 2rem;
1877}
1878.archive-month h2 {
1879 font-family: var(--font-display);
1880 font-size: 1.35rem;
1881 margin: 0 0 .5rem;
1882 padding-bottom: .35rem;
1883 border-bottom: 1px solid var(--rule);
1884}
1885.archive-month h2 a {
1886 color: var(--ink);
1887 text-decoration: none;
1888}
1889.archive-month h2 a:hover { color: var(--accent); }
1890
1891/* Compact post-list (gebruikt in archief drill-down per maand) */
1892.post-compact-list {
1893 list-style: none;
1894 padding: 0; margin: 0;
1895 display: flex;
1896 flex-direction: column;
1897}
1898.post-compact-list li {
1899 border-bottom: 1px solid var(--rule);
1900}
1901.post-compact-list li:last-child { border-bottom: none; }
1902.post-compact-list a {
1903 display: grid;
1904 grid-template-columns: 3em 1fr;
1905 gap: .75rem;
1906 padding: .6rem .2rem;
1907 text-decoration: none;
1908 color: var(--ink);
1909 transition: background .12s;
1910 border-radius: 4px;
1911}
1912.post-compact-list a:hover {
1913 background: color-mix(in srgb, var(--accent) 6%, transparent);
1914}
1915.post-compact-date {
1916 color: var(--ink-muted);
1917 font-size: .8rem;
1918 align-self: center;
1919}
1920.post-compact-title { font-weight: 500; font-size: 1rem; align-self: center; }
1921.post-compact-list.large a { grid-template-columns: 4em 1fr; padding: .8rem .3rem; }
1922.post-compact-list.large .post-compact-title { font-family: var(--font-display); font-size: 1.15rem; }
1923.post-compact-excerpt {
1924 grid-column: 2;
1925 color: var(--ink-muted);
1926 font-size: .88rem;
1927 line-height: 1.5;
1928}
1929
1930/* Post-list (gebruikt in tag / type / zoek pagina's) */
1931.post-list {
1932 list-style: none;
1933 padding: 0; margin: 0;
1934 display: flex;
1935 flex-direction: column;
1936 gap: 1.5rem;
1937}
1938.post-list-item {
1939 display: grid;
1940 grid-template-columns: 120px 1fr;
1941 gap: 1.25rem;
1942 padding-bottom: 1.5rem;
1943 border-bottom: 1px solid var(--rule);
1944}
1945.post-list-item:last-child { border-bottom: none; }
1946.post-list-item:has(> .post-list-cover + .post-list-body) { grid-template-columns: 120px 1fr; }
1947.post-list-item:not(:has(.post-list-cover)) { grid-template-columns: 1fr; }
1948.post-list-cover {
1949 display: block;
1950 aspect-ratio: 1;
1951 overflow: hidden;
1952 border-radius: var(--radius);
1953 /* Accent-gradient placeholder while the cover image loads (image fades in over it). */
1954 background-image: linear-gradient(135deg,
1955 color-mix(in srgb, var(--accent, #888) 22%, var(--paper-2, var(--paper))) 0%,
1956 color-mix(in srgb, var(--accent, #888) 6%, var(--paper-2, var(--paper))) 100%);
1957}
1958.post-list-cover img, .post-list-cover video {
1959 width: 100%; height: 100%;
1960 object-fit: cover; /* fill the square, keep aspect, crop the overflow, centered */
1961 object-position: center;
1962 display: block;
1963 background-color: #fff; /* transparent logos sit on white once loaded */
1964 transition: opacity .4s ease;
1965}
1966.post-list-cover img.is-loading { opacity: 0; }
1967.post-list-body { display: flex; flex-direction: column; gap: .35rem; }
1968.post-list-meta {
1969 color: var(--ink-muted);
1970 font-size: .75rem;
1971 display: flex; gap: .35rem; align-items: center;
1972}
1973.post-list-title {
1974 font-family: var(--font-display);
1975 font-size: 1.3rem;
1976 font-weight: 450;
1977 margin: 0;
1978 line-height: 1.2;
1979}
1980.post-list-title a {
1981 color: var(--ink);
1982 text-decoration: none;
1983}
1984.post-list-title a:hover { color: var(--accent); }
1985.post-list-excerpt {
1986 color: var(--ink-muted);
1987 font-size: .95rem;
1988 margin: 0;
1989 line-height: 1.5;
1990}
1991
1992/* Zoek-formulier binnen special view */
1993.search-form {
1994 display: flex;
1995 gap: .5rem;
1996 margin-bottom: 2rem;
1997}
1998.search-form input[type=search] {
1999 flex: 1;
2000 padding: .75rem 1rem;
2001 background: var(--paper-2);
2002 border: 1px solid var(--rule);
2003 border-radius: var(--radius);
2004 font: inherit;
2005 color: var(--ink);
2006}
2007.search-form input[type=search]:focus {
2008 outline: none;
2009 border-color: var(--accent);
2010 box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 20%, transparent);
2011}
2012
2013/* ============================================================
2014 SEARCH OVERLAY (masthead → full-screen zoekbalk)
2015 ============================================================ */
2016.search-overlay {
2017 position: fixed;
2018 inset: 0;
2019 background: color-mix(in srgb, var(--ink) 50%, transparent);
2020 z-index: 1500;
2021 display: flex;
2022 justify-content: center;
2023 align-items: flex-start;
2024 padding-top: 10vh;
2025 backdrop-filter: blur(6px);
2026 -webkit-backdrop-filter: blur(6px);
2027}
2028.search-overlay[hidden] { display: none; }
2029.search-overlay-form {
2030 width: min(90vw, 600px);
2031 background: var(--paper);
2032 border-radius: calc(var(--radius) * 1.5);
2033 padding: .75rem 1rem;
2034 display: flex;
2035 align-items: center;
2036 gap: .6rem;
2037 box-shadow: 0 20px 60px rgba(0,0,0,.3);
2038 border: 1px solid var(--rule);
2039}
2040.search-overlay-form .icon {
2041 width: 1.2rem; height: 1.2rem;
2042 color: var(--ink-muted);
2043 flex-shrink: 0;
2044}
2045.search-overlay-form input[type=search] {
2046 flex: 1;
2047 background: transparent;
2048 border: none;
2049 font-family: var(--font-body);
2050 font-size: 1.1rem;
2051 color: var(--ink);
2052 padding: .5rem 0;
2053}
2054.search-overlay-form input[type=search]:focus { outline: none; }
2055.search-overlay-form .nav-btn {
2056 background: transparent;
2057 border: none;
2058 color: var(--ink-muted);
2059 cursor: pointer;
2060 font-size: 1.25rem;
2061 line-height: 1;
2062 padding: .3rem .5rem;
2063}
2064.search-overlay-form .nav-btn:hover { color: var(--ink); }
2065body.search-open { overflow: hidden; }
2066
2067/* ============================================================
2068 RELATED POSTS (onder elke post-view)
2069 ============================================================ */
2070.related-posts {
2071 margin-top: 2.5rem;
2072 padding-top: 2rem;
2073 border-top: 1px solid var(--rule);
2074}
2075.related-title {
2076 font-family: var(--font-mono);
2077 font-size: .7rem;
2078 color: var(--ink-muted);
2079 text-transform: uppercase;
2080 letter-spacing: .12em;
2081 margin: 0 0 1rem;
2082}
2083.related-grid {
2084 list-style: none;
2085 padding: 0; margin: 0;
2086 display: grid;
2087 grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
2088 gap: 1rem;
2089}
2090.related-grid a {
2091 display: flex;
2092 flex-direction: column;
2093 gap: .5rem;
2094 text-decoration: none;
2095 color: var(--ink);
2096 border: 1px solid var(--rule);
2097 border-radius: var(--radius);
2098 overflow: hidden;
2099 transition: border-color .15s, transform .15s;
2100 height: 100%;
2101}
2102.related-grid a:hover {
2103 border-color: color-mix(in srgb, var(--accent) 50%, var(--rule));
2104 transform: translateY(-2px);
2105}
2106.related-cover {
2107 display: block;
2108 aspect-ratio: 16/10;
2109 background-size: cover;
2110 background-position: center;
2111 background-color: var(--paper-2);
2112}
2113
2114/* v9.4 — Wanneer related-cover ook .grid-tile-gradient class heeft (lege cover
2115 fallback), erft 'ie automatisch de hue/gradient/title styling van grid-tiles.
2116 Geen aparte related-cover-gradient meer nodig. */
2117.related-body {
2118 display: flex;
2119 flex-direction: column;
2120 gap: .25rem;
2121 padding: .6rem .75rem .9rem;
2122}
2123.related-meta { color: var(--ink-muted); font-size: .7rem; }
2124.related-name {
2125 font-family: var(--font-display);
2126 font-weight: 450;
2127 font-size: 1rem;
2128 line-height: 1.25;
2129}
2130
2131/* ============================================================
2132 MOBILE TWEAKS voor v7.3
2133 ============================================================ */
2134@media (max-width: 600px) {
2135 .post-list-item { grid-template-columns: 1fr; }
2136 .post-list-cover { aspect-ratio: 16/9; }
2137 .archive-months { grid-template-columns: repeat(2, 1fr); }
2138 .related-grid { grid-template-columns: 1fr; }
2139 .search-overlay { padding-top: 4vh; }
2140}
2141
2142/* ============================================================
2143 v7.4 — PROFILE HEADER + VIEW SWITCHER + GRID + POST-TYPE LAYOUTS
2144 MOBILE-FIRST — belangrijkste eis
2145 ============================================================ */
2146
2147/* -------- PROFILE HEADER (Optie C: full op home, compact op post/special) -------- */
2148
2149.profile-header {
2150 background: var(--paper-2, var(--paper));
2151 border-bottom: 1px solid var(--rule);
2152 transition: padding .25s ease, background .2s;
2153}
2154/* Mobiel default = full-mode padding */
2155.profile-header { padding: 1.25rem 0; }
2156.profile-header-inner {
2157 display: flex;
2158 gap: .9rem;
2159 align-items: flex-start;
2160}
2161
2162.profile-photo {
2163 flex-shrink: 0;
2164 width: 80px;
2165 height: 80px;
2166 border-radius: 50%;
2167 overflow: hidden;
2168 display: block;
2169 background: var(--paper);
2170 border: 2px solid var(--rule);
2171 transition: width .25s ease, height .25s ease, border-color .2s;
2172 text-decoration: none;
2173}
2174.profile-photo:hover { border-color: var(--accent); }
2175.profile-photo img {
2176 width: 100%; height: 100%;
2177 object-fit: cover;
2178 display: block;
2179}
2180.profile-photo-fallback {
2181 display: flex;
2182 align-items: center;
2183 justify-content: center;
2184 width: 100%; height: 100%;
2185 background: var(--accent);
2186 color: var(--paper);
2187 font-family: var(--font-display);
2188 font-weight: 700;
2189 font-size: 2.2rem;
2190 text-transform: uppercase;
2191 line-height: 1;
2192 transition: font-size .25s ease;
2193}
2194
2195.profile-info {
2196 flex: 1;
2197 min-width: 0;
2198 display: flex;
2199 flex-direction: column;
2200 gap: .3rem;
2201}
2202.profile-name {
2203 margin: 0;
2204 font-family: var(--font-display);
2205 font-size: 1.2rem;
2206 font-weight: 500;
2207 line-height: 1.15;
2208 transition: font-size .25s ease;
2209}
2210.profile-name a {
2211 color: var(--ink);
2212 text-decoration: none;
2213}
2214.profile-name a:hover { color: var(--accent); }
2215.profile-bio {
2216 margin: 0;
2217 color: var(--ink-muted);
2218 font-size: .92rem;
2219 line-height: 1.45;
2220 max-height: 200px;
2221 overflow: hidden;
2222 transition: max-height .25s ease, margin .25s ease, opacity .2s;
2223}
2224.profile-links {
2225 list-style: none;
2226 padding: 0;
2227 margin: .15rem 0 0;
2228 display: flex;
2229 flex-wrap: wrap;
2230 gap: .4rem;
2231 max-height: 50px;
2232 overflow: hidden;
2233 transition: max-height .25s ease, margin .25s ease, opacity .2s;
2234}
2235.profile-links li { margin: 0; }
2236.profile-links a,
2237.profile-links .profile-fedi-link {
2238 display: inline-flex;
2239 align-items: center;
2240 justify-content: center;
2241 width: 40px;
2242 height: 40px;
2243 border-radius: 50%;
2244 background: color-mix(in srgb, var(--ink) 5%, transparent);
2245 color: var(--ink-muted);
2246 text-decoration: none;
2247 transition: background .15s, color .15s;
2248}
2249.profile-links a:hover,
2250.profile-links .profile-fedi-link:hover {
2251 background: color-mix(in srgb, var(--accent) 15%, transparent);
2252 color: var(--accent);
2253}
2254.profile-links .icon { width: 1.1rem; height: 1.1rem; }
2255
2256/* -------- COMPACT MODE: op post + special pages -------- */
2257
2258.on-post .profile-header,
2259.on-special .profile-header {
2260 padding: .5rem 0;
2261}
2262.on-post .profile-photo,
2263.on-special .profile-photo {
2264 width: 36px;
2265 height: 36px;
2266 border-width: 1px;
2267}
2268.on-post .profile-photo-fallback,
2269.on-special .profile-photo-fallback {
2270 font-size: 1rem;
2271}
2272.on-post .profile-name,
2273.on-special .profile-name {
2274 font-size: 1rem;
2275 align-self: center;
2276}
2277.on-post .profile-bio,
2278.on-special .profile-bio,
2279.on-post .profile-links,
2280.on-special .profile-links {
2281 display: none;
2282}
2283.on-post .profile-header-inner,
2284.on-special .profile-header-inner {
2285 align-items: center;
2286 justify-content: flex-start;
2287 gap: .6rem;
2288}
2289.on-post .profile-info,
2290.on-special .profile-info {
2291 flex: 0 1 auto;
2292 min-width: 0;
2293}
2294.on-post .profile-name,
2295.on-special .profile-name {
2296 text-align: left;
2297}
2298
2299/* -------- DESKTOP: meer ruimte, grotere foto -------- */
2300@media (min-width: 768px) {
2301 .profile-header { padding: 2rem 0; }
2302 .profile-photo { width: 120px; height: 120px; }
2303 .profile-photo-fallback { font-size: 3.2rem; }
2304 .profile-name { font-size: 1.5rem; }
2305 .profile-bio { font-size: 1rem; }
2306 .profile-header-inner { gap: 1.5rem; }
2307 .on-post .profile-header,
2308 .on-special .profile-header { padding: .6rem 0; }
2309 .on-post .profile-photo,
2310 .on-special .profile-photo { width: 42px; height: 42px; }
2311 /* Compact mode: gap blijft klein, ook op desktop */
2312 .on-post .profile-header-inner,
2313 .on-special .profile-header-inner { gap: .75rem; }
2314 .on-post .profile-name,
2315 .on-special .profile-name { font-size: 1.1rem; }
2316}
2317
2318/* -------- VIEW SWITCHER -------- */
2319.view-switcher-wrap {
2320 border-bottom: 1px solid var(--rule);
2321 background: var(--paper);
2322 /* Bottom margin gives breathing room between the switcher bar and the
2323 first post. margin-top staat in shared-styles.ejs (de winnende inline
2324 <style>) — symmetrisch op 1.5rem. */
2325 margin-bottom: 1.5rem;
2326}
2327.view-switcher {
2328 display: flex;
2329 justify-content: center;
2330 gap: .35rem;
2331 /* Slimmer bar — was .6rem, now .35rem so the bar reads as a divider
2332 rather than a row of weight equal to the header. */
2333 padding: .35rem 0;
2334}
2335.view-switch-btn {
2336 display: inline-flex;
2337 align-items: center;
2338 gap: .4rem;
2339 padding: .35rem .85rem; /* was .55rem 1rem */
2340 min-height: 32px; /* was 44px */
2341 background: transparent;
2342 border: 1px solid var(--rule);
2343 border-radius: 999px;
2344 color: var(--ink-muted);
2345 font-family: var(--font-ui);
2346 font-size: .82rem; /* was .85rem */
2347 cursor: pointer;
2348 transition: all .15s;
2349}
2350.view-switch-btn:hover {
2351 color: var(--ink);
2352 border-color: var(--ink-muted);
2353}
2354/* Actieve state: puur afgeleid van body[data-feed-view]. Geen .is-active class meer.
2355 Niet op de Archive-pagina: daar is geen "huidige" timeline/grid-keuze, dus beide
2356 knoppen blijven neutraal (grijs). */
2357/* Actieve Tijdlijn/Grid-state wordt nu gestuurd via [aria-selected="true"] (gezet
2358 door syncAria, die óók op htmx:afterSettle draait) i.p.v. body[data-feed-view].
2359 Reden: body-class/attribuut-CSS pakte niet betrouwbaar na een htmx-OOB-swap;
2360 een element-attribuut wel. De witte active-regel staat in shared-styles. */
2361.view-switch-btn .icon { width: 1rem; height: 1rem; }
2362
2363/* -------- FEED TOGGLE VIA BODY --------
2364 Grid-modus werkt op de feed (home, cirkel). Het ARCHIEF negeert de grid-keuze
2365 bewust: dat is altijd de chronologische jaar/maand-lijst (de switcher is daar
2366 grijs en springt bij klik terug naar de feed). Post-pagina's tonen de
2367 feed-timeline article sowieso altijd. Alle andere body-classes negeren
2368 data-feed-view en houden timeline visible. */
2369body.on-home[data-feed-view="grid"] .feed-timeline,
2370body.on-home[data-feed-view="grid"] .pagination,
2371body.on-home[data-feed-view="grid"] .related-posts,
2372body.on-home[data-feed-view="grid"] .article-footer,
2373body.on-cirkel[data-feed-view="grid"] .feed-timeline {
2374 display: none !important;
2375}
2376/* Grid-sectie alleen zichtbaar op de feed in grid-mode (NIET op archief) */
2377.feed-grid { display: none; }
2378body.on-home[data-feed-view="grid"] .feed-grid,
2379body.on-cirkel[data-feed-view="grid"] .feed-grid { display: block; }
2380
2381/* -------- GRID VIEW TILES (Instagram-stijl) -------- */
2382.feed-grid {
2383 padding: 1rem 0 2rem;
2384}
2385.grid-tiles {
2386 display: grid;
2387 gap: 4px;
2388 grid-template-columns: repeat(2, 1fr);
2389}
2390.grid-tile {
2391 position: relative;
2392 display: block;
2393 aspect-ratio: 1;
2394 background-size: cover;
2395 background-position: center;
2396 background-color: var(--paper-2);
2397 overflow: hidden;
2398 text-decoration: none;
2399 color: var(--ink);
2400 transition: transform .2s;
2401 cursor: pointer;
2402 -webkit-tap-highlight-color: rgba(0,0,0,.1);
2403}
2404
2405/* Transparent covers (PNG logos etc.) sit on white so they don't blend into a dark
2406 theme. The white is on the IMG, so the tile's accent-gradient placeholder shows
2407 while the image is still loading. */
2408.post-cover img,
2409.post-list-cover img,
2410.grid-tile-img { background-color: #fff; }
2411/* Accent-gradient placeholder shown while the cover image loads (the image fades in
2412 over it), instead of a white flash on cover tiles. */
2413.grid-tile:not(.grid-tile-gradient) {
2414 background-image: linear-gradient(135deg,
2415 color-mix(in srgb, var(--accent, #888) 22%, var(--paper-2, var(--paper))) 0%,
2416 color-mix(in srgb, var(--accent, #888) 6%, var(--paper-2, var(--paper))) 100%);
2417}
2418/* Cover as a real <img> (not background-image): browsers downsample <img> with the
2419 high-quality image pipeline, so high-res line-art covers don't go jagged when shrunk.
2420 Fades in on load (.is-loading removed) so the placeholder shows meanwhile. */
2421.grid-tile-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; transition: opacity .4s ease; }
2422.grid-tile-img.is-loading { opacity: 0; }
2423/* Audio tile (Shaer, Robins vraag 30-7): the waveform PNG is white on
2424 transparent and floats OVER the tile's own hue gradient, so every audio
2425 post keeps its color and gets its shape. Contain + padding leaves the
2426 centered title readable. */
2427.grid-tile-img.grid-tile-wave {
2428 background-color: transparent;
2429 object-fit: contain;
2430 padding: 26% 10%;
2431 opacity: .85;
2432}
2433/* Cover videos are decorative, not players: let clicks + right-click pass through to the
2434 tile link so you get the normal link menu (not the browser's <video> menu/controls).
2435 Autoplay is independent of pointer-events, so the video still plays. */
2436video.grid-tile-img,
2437.post-list-cover video,
2438.post-cover video { pointer-events: none; }
2439.grid-tile:hover { transform: scale(0.98); }
2440.grid-tile-overlay {
2441 position: absolute;
2442 inset: 0;
2443 padding: .6rem;
2444 display: flex;
2445 flex-direction: column;
2446 justify-content: flex-end;
2447 align-items: flex-start;
2448 background: linear-gradient(to top, rgba(0,0,0,.65) 0%, rgba(0,0,0,0) 50%);
2449 opacity: 0;
2450 transition: opacity .2s;
2451 pointer-events: none; /* klik moet naar de <a> eronder gaan, niet naar de overlay */
2452}
2453/* Bron-site (cirkel-feed): toont bij hover "van <site>" onder de titel. */
2454/* Source label: small text that wraps to 2 lines if needed, with a big chain icon
2455 beside it (the text was 1.44rem — bigger than the title — and overflowed on mobile). */
2456.grid-tile-overlay-src {
2457 color: #fff; opacity: .85;
2458 font-size: .72rem; line-height: 1.2; margin-top: .25rem;
2459 display: flex; align-items: center; gap: .3rem; width: 100%;
2460}
2461.grid-tile-overlay-src::before { content: "⛓"; font-size: 1.3rem; line-height: 1; flex: 0 0 auto; }
2462.grid-tile-gradient-src {
2463 margin-top: .35rem; font-size: .72rem; line-height: 1.2; opacity: .85;
2464 color: var(--ink-soft);
2465 display: flex; align-items: center; gap: .3rem; width: 100%;
2466}
2467.grid-tile-gradient-src::before { content: "⛓"; font-size: 1.3rem; line-height: 1; flex: 0 0 auto; }
2468.grid-tile-overlay strong {
2469 color: #fff;
2470 font-family: var(--font-display);
2471 font-size: .9rem;
2472 font-weight: 500;
2473 line-height: 1.15;
2474 display: -webkit-box;
2475 -webkit-line-clamp: 3;
2476 -webkit-box-orient: vertical;
2477 overflow: hidden;
2478}
2479@media (hover: hover) {
2480 .grid-tile:hover .grid-tile-overlay { opacity: 1; }
2481}
2482@media (hover: none) {
2483 /* Op touch-devices altijd overlay tonen zodat titels zichtbaar zijn */
2484 .grid-tile-overlay { opacity: 1; background: linear-gradient(to top, rgba(0,0,0,.7) 0%, rgba(0,0,0,0) 70%); }
2485}
2486
2487.grid-tile-gradient {
2488 background-image: none;
2489 background-color: hsl(var(--tile-hue, 30), 40%, 85%);
2490 background-image: linear-gradient(135deg, hsl(var(--tile-hue, 30), 45%, 88%), hsl(calc(var(--tile-hue, 30) + 30), 35%, 75%));
2491 display: flex;
2492 flex-direction: column;
2493 align-items: center;
2494 justify-content: center;
2495 padding: 1rem;
2496 text-align: center;
2497}
2498[data-theme="dark"] .grid-tile-gradient,
2499.grid-tile-gradient[data-theme="dark"] {
2500 background-image: linear-gradient(135deg, hsl(var(--tile-hue, 30), 30%, 18%), hsl(calc(var(--tile-hue, 30) + 30), 25%, 12%));
2501}
2502.grid-tile-title {
2503 font-family: var(--font-display);
2504 font-size: 1rem;
2505 font-weight: 500;
2506 color: var(--ink);
2507 line-height: 1.2;
2508 display: -webkit-box;
2509 -webkit-line-clamp: 4;
2510 -webkit-box-orient: vertical;
2511 overflow: hidden;
2512 z-index: 1;
2513 /* Federated link posts can have a long bare URL as their title — break it so it wraps
2514 inside the tile and clamps cleanly instead of overflowing past both edges. */
2515 max-width: 100%;
2516 overflow-wrap: anywhere;
2517 word-break: break-word;
2518 hyphens: auto;
2519}
2520
2521.grid-tile-pin {
2522 position: absolute;
2523 top: .5rem;
2524 right: .5rem;
2525 display: inline-flex;
2526 align-items: center;
2527 gap: .25rem;
2528 padding: .2rem .55rem;
2529 background: var(--accent);
2530 color: #fff;
2531 border-radius: 999px;
2532 font-family: var(--font-ui);
2533 font-size: .65rem;
2534 font-weight: 700;
2535 text-transform: uppercase;
2536 letter-spacing: .06em;
2537 z-index: 3;
2538 box-shadow: 0 2px 6px rgba(0,0,0,.3);
2539 pointer-events: none;
2540}
2541.grid-tile-pin svg {
2542 width: .95em;
2543 height: .95em;
2544 margin-top: -1px;
2545}
2546/* Pinned/boosted tile: accent ring. An outline on the tile is painted UNDER the absolute
2547 cover <img>, so draw the ring as a pseudo-element overlay ABOVE the image (z-index above
2548 the img, below the corner badges + nsfw veil). */
2549.grid-tile.is-pinned { position: relative; z-index: 1; }
2550.grid-tile.is-pinned::after {
2551 content: '';
2552 position: absolute;
2553 inset: 0;
2554 border: 3px solid var(--accent);
2555 border-radius: inherit;
2556 pointer-events: none;
2557 z-index: 1;
2558}
2559.grid-tile-type {
2560 position: absolute;
2561 top: .4rem;
2562 left: .4rem;
2563 padding: .15rem .5rem;
2564 background: rgba(0,0,0,.55);
2565 color: #fff;
2566 border-radius: 999px;
2567 font-family: var(--font-ui);
2568 font-size: .6rem;
2569 font-weight: 600;
2570 text-transform: uppercase;
2571 letter-spacing: .05em;
2572 z-index: 2;
2573}
2574
2575@media (min-width: 600px) {
2576 .grid-tiles { grid-template-columns: repeat(3, 1fr); }
2577}
2578@media (min-width: 900px) {
2579 .grid-tiles { grid-template-columns: repeat(3, 1fr); gap: 8px; }
2580}
2581
2582/* -------- POST-TYPE SPECIFIEKE LAYOUTS -------- */
2583
2584/* Foto-post: beeld prominent, geen titel bovenaan, caption onder */
2585.feed-timeline[data-post-type="foto"] .post-title {
2586 font-size: 1.1rem;
2587 color: var(--ink-muted);
2588 font-weight: 400;
2589}
2590.feed-timeline[data-post-type="foto"] .post-cover {
2591 margin: 0 -1rem 1rem;
2592 border-radius: 0;
2593}
2594.feed-timeline[data-post-type="foto"] .post-cover img {
2595 width: 100%;
2596 border-radius: 0;
2597}
2598
2599/* Post-caption onder de cover */
2600.post-caption {
2601 font-family: var(--font-body);
2602 font-size: 1rem;
2603 color: var(--ink);
2604 line-height: 1.5;
2605 margin: 0 0 1.25rem;
2606 padding: 0 0 1rem;
2607 border-bottom: 1px solid var(--rule);
2608 white-space: pre-wrap;
2609}
2610.feed-timeline[data-post-type="foto"] .post-caption {
2611 font-size: 1.05rem;
2612 margin-top: -.5rem;
2613 padding-bottom: 1.25rem;
2614}
2615
2616/* Audio/video posts — type-chip helder, content eronder zoals normaal */
2617.feed-timeline[data-post-type="audio"] .post-title,
2618.feed-timeline[data-post-type="video"] .post-title {
2619 font-size: 1.5rem;
2620}
2621
2622@media (min-width: 768px) {
2623 .feed-timeline[data-post-type="foto"] .post-cover {
2624 margin: 0 0 1.5rem;
2625 border-radius: var(--radius);
2626 }
2627}
2628
2629/* -------- ADMIN EDIT-BUTTON op post-view (alleen zichtbaar voor ingelogde admin) -------- */
2630.post-edit-btn {
2631 position: absolute;
2632 top: 1rem;
2633 right: 1rem;
2634 display: inline-flex;
2635 align-items: center;
2636 justify-content: center;
2637 width: 44px;
2638 height: 44px;
2639 background: var(--paper);
2640 border: 1px solid var(--rule);
2641 border-radius: 50%;
2642 color: var(--ink-muted);
2643 text-decoration: none;
2644 box-shadow: 0 2px 8px rgba(0,0,0,.08);
2645 transition: background .15s, color .15s, transform .15s, border-color .15s;
2646 z-index: 10;
2647}
2648.post-edit-btn:hover {
2649 background: var(--accent);
2650 border-color: var(--accent);
2651 color: var(--paper);
2652 transform: scale(1.05);
2653}
2654.post-edit-btn .icon {
2655 width: 1.1rem;
2656 height: 1.1rem;
2657}
2658/* Zorg dat de article relative is zodat absolute positionering werkt */
2659.feed-timeline { position: relative; }
2660
2661@media (min-width: 768px) {
2662 .post-edit-btn {
2663 top: 1.5rem;
2664 right: 1.5rem;
2665 }
2666}
2667
2668/* ============================================================
2669 v8.0 — ACCENT SPAN + POST-TABLE (published posts)
2670 ============================================================ */
2671.post span.accent,
2672.post-content span.accent,
2673article span.accent,
2674page-container span.accent {
2675 color: var(--accent);
2676 font-weight: 500;
2677}
2678
2679.post-table,
2680article table.post-table {
2681 width: 100%;
2682 max-width: 100%;
2683 border-collapse: collapse;
2684 margin: 1.25rem 0;
2685 font-size: .95rem;
2686 display: block;
2687 overflow-x: auto;
2688 -webkit-overflow-scrolling: touch;
2689}
2690.post-table thead { background: color-mix(in srgb, var(--accent) 10%, transparent); }
2691.post-table th,
2692.post-table td {
2693 padding: .6rem .8rem;
2694 text-align: left;
2695 border: 1px solid var(--rule);
2696 vertical-align: top;
2697}
2698.post-table th {
2699 font-family: var(--font-ui);
2700 font-weight: 600;
2701 font-size: .88rem;
2702 color: var(--ink);
2703 letter-spacing: .02em;
2704}
2705.post-table tbody tr:nth-child(even) {
2706 background: color-mix(in srgb, var(--ink) 3%, transparent);
2707}
2708@media (min-width: 700px) {
2709 .post-table { display: table; overflow: visible; }
2710}
2711
2712/* ============================================================
2713 v8.0 fix — grid-cols picker (desktop only) + grid col overrides
2714 ============================================================ */
2715
2716/* Switcher-wrap bevat nu ook de cols-picker; layout side-by-side */
2717.view-switcher-wrap .container {
2718 display: flex;
2719 align-items: center;
2720 justify-content: center;
2721 gap: 1rem;
2722 flex-wrap: wrap;
2723}
2724
2725/* Solo / Cirkel scope-switcher (alleen in circle-modus) — segmented toggle, centraal.
2726 Hoge specificiteit (+ !important op tekst) zodat 'ie globale link-stijlen wint. */
2727.view-switcher-wrap .feed-scope {
2728 display: inline-flex;
2729 background: var(--paper-2);
2730 border: 1px solid var(--rule);
2731 border-radius: 999px;
2732 padding: 3px;
2733}
2734.view-switcher-wrap .feed-scope-btn {
2735 display: inline-flex;
2736 align-items: center;
2737 padding: .32rem .95rem;
2738 min-height: 30px;
2739 border: none !important;
2740 border-radius: 999px !important;
2741 background: transparent !important;
2742 color: var(--ink-muted) !important;
2743 font-family: var(--font-ui);
2744 font-size: .82rem;
2745 font-weight: 500 !important;
2746 text-decoration: none !important;
2747 cursor: pointer;
2748 transition: all .15s;
2749}
2750.view-switcher-wrap .feed-scope-btn:hover { color: var(--ink) !important; }
2751.view-switcher-wrap .feed-scope-btn.is-active {
2752 background: var(--ink) !important;
2753 color: var(--paper) !important;
2754}
2755
2756.grid-cols-picker {
2757 display: none; /* default hidden — desktop + grid-active maakt 'm zichtbaar */
2758 gap: 2px;
2759 padding: 0;
2760}
2761.grid-cols-btn {
2762 display: inline-flex;
2763 align-items: center;
2764 justify-content: center;
2765 min-width: 36px;
2766 height: 32px;
2767 padding: 0 .6rem;
2768 background: transparent;
2769 border: 1px solid var(--rule);
2770 color: var(--ink-muted);
2771 font-family: var(--font-ui);
2772 font-size: .85rem;
2773 font-weight: 500;
2774 cursor: pointer;
2775 transition: all .12s;
2776}
2777.grid-cols-btn:first-child { border-radius: 999px 0 0 999px; }
2778.grid-cols-btn:last-child { border-radius: 0 999px 999px 0; }
2779.grid-cols-btn:not(:first-child):not(:last-child) { border-left: none; border-right: none; }
2780.grid-cols-btn:hover { color: var(--ink); }
2781/* Active state puur via body[data-grid-cols] — geen is-active-class meer. */
2782body[data-grid-cols="2"] .grid-cols-btn[data-cols="2"],
2783body[data-grid-cols="3"] .grid-cols-btn[data-cols="3"],
2784body[data-grid-cols="4"] .grid-cols-btn[data-cols="4"] {
2785 background: var(--ink);
2786 color: var(--paper);
2787 border-color: var(--ink);
2788}
2789
2790/* Desktop + grid-view → toon cols-picker (op de home-feed; niet op archief) */
2791@media (min-width: 600px) {
2792 body.on-home[data-feed-view="grid"] .grid-cols-picker {
2793 display: inline-flex;
2794 }
2795}
2796
2797/* Kolom-overrides op desktop. Mobiel negeert dit (staat vast op 2). Geldt op ELKE
2798 feed met grid (home én cirkel/tag/type/user) — scope op .feed-grid .grid-tiles. */
2799@media (min-width: 600px) {
2800 body[data-grid-cols="2"] .feed-grid .grid-tiles { grid-template-columns: repeat(2, 1fr); }
2801 body[data-grid-cols="3"] .feed-grid .grid-tiles { grid-template-columns: repeat(3, 1fr); }
2802 body[data-grid-cols="4"] .feed-grid .grid-tiles { grid-template-columns: repeat(4, 1fr); }
2803}
2804
2805/* Gradient-tile: iets meer contrast voor light + dark mode zodat titel altijd leesbaar is */
2806.grid-tile-gradient {
2807 background-image: linear-gradient(135deg,
2808 hsl(var(--tile-hue, 30), 55%, 72%),
2809 hsl(calc(var(--tile-hue, 30) + 40), 45%, 60%));
2810}
2811[data-theme="dark"] .grid-tile-gradient {
2812 background-image: linear-gradient(135deg,
2813 hsl(var(--tile-hue, 30), 40%, 30%),
2814 hsl(calc(var(--tile-hue, 30) + 40), 30%, 18%));
2815}
2816.grid-tile-gradient .grid-tile-title {
2817 color: #fff;
2818 text-shadow: 0 1px 3px rgba(0,0,0,.25);
2819}
2820[data-theme="dark"] .grid-tile-gradient .grid-tile-title {
2821 color: #fff;
2822 text-shadow: 0 1px 2px rgba(0,0,0,.5);
2823}
2824
2825/* ============================================================
2826 v8.0.2 — COMPACT DESIGN OVERRIDES
2827 Tighter masthead, padding, margins overall. Profiel-header
2828 collapse/expand blijft zoals 'ie was.
2829 ============================================================ */
2830
2831/* Masthead: compacter */
2832.masthead { padding: calc(.55rem + var(--ios-safe-top, 0px)) 0 .55rem; }
2833.masthead-inner { gap: 1rem; }
2834.site-title { font-size: 1.25rem; }
2835.nav-link, .nav-btn { padding: .4rem .7rem; min-height: 2rem; font-size: .82rem; }
2836
2837/* Main content padding */
2838main { padding-top: 1rem; }
2839.page { padding-block: 1rem 1.75rem; }
2840
2841/* View switcher-bar strakker */
2842.view-switcher { padding: .4rem 0; gap: .3rem; }
2843.view-switch-btn { padding: .4rem .85rem; min-height: 38px; font-size: .8rem; }
2844.grid-cols-btn { min-width: 32px; height: 28px; padding: 0 .5rem; font-size: .8rem; }
2845
2846/* Post header spacing terug */
2847.post-header { margin: 0 0 1.25rem; }
2848.post-title { margin-bottom: .35rem; }
2849.post-meta { font-size: .78rem; }
2850.post-tags { margin-top: .6rem; gap: .3rem; }
2851.post-tag { font-size: .7rem; padding: .15rem .55rem; }
2852
2853/* Article footer + pagination compacter */
2854.article-footer { padding-top: 1.25rem; margin-top: 1.5rem; }
2855.pagination { padding-block: 1.25rem 2rem; margin-top: 1.5rem; }
2856.pagination-item { padding: .75rem .95rem; min-height: 4rem; }
2857.pagination-title { font-size: .95rem; }
2858
2859/* Site footer compacter */
2860.site-footer { padding: 1.25rem 0 calc(1.25rem + env(safe-area-inset-bottom, 0px)); margin-top: 2rem; font-size: .78rem; }
2861.site-footer-inner { gap: .75rem; }
2862
2863/* Profiel-header: full mode iets minder riant (compact mode blijft hetzelfde) */
2864.profile-header { padding: 1rem 0; }
2865.profile-photo { width: 72px; height: 72px; }
2866.profile-photo-fallback { font-size: 1.8rem; }
2867.profile-name { font-size: 1.2rem; }
2868.profile-bio { font-size: .85rem; margin-top: .15rem; }
2869.profile-links { margin-top: .5rem; gap: .4rem; }
2870.profile-links a,
2871.profile-links .profile-fedi-link { width: 32px; height: 32px; }
2872
2873@media (min-width: 768px) {
2874 .profile-header { padding: 1.35rem 0; }
2875 .profile-photo { width: 92px; height: 92px; }
2876 .profile-photo-fallback { font-size: 2.4rem; }
2877 .profile-name { font-size: 1.4rem; }
2878 .profile-bio { font-size: .95rem; }
2879 .profile-header-inner { gap: 1.1rem; }
2880 /* Compact-mode op desktop blijft klein zoals we hadden afgesproken */
2881 .on-post .profile-photo,
2882 .on-special .profile-photo { width: 42px; height: 42px; }
2883}
2884
2885/* Grid-tegels iets strakker gaten */
2886.grid-tiles { gap: 3px; }
2887
2888/* Post-cover margin */
2889.post-cover { margin: 0 0 1rem; }
2890
2891/* Audio player wat lichter */
2892#pcms-audio-bar { padding: .55rem 1rem; }
2893
2894/* v8.1 — pagination CTA + mobile tap target */
2895.pagination-cta {
2896 display: inline-block;
2897 font-family: var(--font-ui);
2898 font-size: .72rem;
2899 font-weight: 600;
2900 color: var(--accent);
2901 margin-top: .35rem;
2902 letter-spacing: .02em;
2903 opacity: .9;
2904}
2905a.pagination-item:hover .pagination-cta { opacity: 1; }
2906
2907/* Mobiel: nog meer tap-feedback + iets prominenter */
2908@media (max-width: 640px) {
2909 a.pagination-item {
2910 padding: 1.1rem 1rem;
2911 min-height: 5.5rem;
2912 border-width: 2px;
2913 }
2914 a.pagination-item:active {
2915 background: color-mix(in srgb, var(--accent) 10%, var(--paper-2));
2916 transform: scale(.98);
2917 }
2918 .pagination-title { font-size: 1rem; }
2919 .pagination-cta { font-size: .75rem; }
2920 .pagination .icon { width: 1.5em; height: 1.5em; }
2921}
2922
2923
2924
2925/* v8.3 / v9.4 — PWA install button (alleen zichtbaar als browser install ondersteunt) */
2926.nav-install-btn[hidden] { display: none; }
2927.nav-install-btn {
2928 position: relative;
2929 display: inline-flex;
2930 align-items: center;
2931 justify-content: center;
2932 gap: .35rem;
2933 background: linear-gradient(135deg,
2934 var(--accent),
2935 color-mix(in srgb, var(--accent) 80%, #000));
2936 color: #fff;
2937 border: none;
2938 border-radius: .65rem;
2939 padding: .45rem .85rem;
2940 font-size: .8rem;
2941 font-weight: 600;
2942 line-height: 1;
2943 cursor: pointer;
2944 overflow: hidden;
2945 isolation: isolate;
2946 box-shadow:
2947 0 1px 0 rgba(255,255,255,.15) inset,
2948 0 2px 6px color-mix(in srgb, var(--accent) 35%, transparent);
2949 transition:
2950 transform .15s cubic-bezier(.4, 0, .2, 1),
2951 box-shadow .2s ease,
2952 filter .15s ease;
2953}
2954.nav-install-btn::before {
2955 content: "";
2956 position: absolute;
2957 top: 0;
2958 left: -100%;
2959 width: 60%;
2960 height: 100%;
2961 background: linear-gradient(110deg,
2962 transparent 30%,
2963 rgba(255,255,255,.22) 50%,
2964 transparent 70%);
2965 z-index: -1;
2966 animation: pcmsInstallShimmer 4s ease-in-out infinite;
2967 pointer-events: none;
2968}
2969.nav-install-btn:hover {
2970 transform: translateY(-1px);
2971 filter: brightness(1.08);
2972 box-shadow:
2973 0 1px 0 rgba(255,255,255,.2) inset,
2974 0 4px 10px color-mix(in srgb, var(--accent) 50%, transparent);
2975}
2976.nav-install-btn:active { transform: translateY(0); }
2977.nav-install-btn .icon {
2978 flex-shrink: 0;
2979 transition: transform .25s cubic-bezier(.34, 1.56, .64, 1);
2980}
2981.nav-install-btn:hover .icon { transform: translateY(-1px); }
2982@media (prefers-reduced-motion: reduce) {
2983 .nav-install-btn::before { animation: none; left: -100%; }
2984 .nav-install-btn:hover { transform: none; }
2985 .nav-install-btn:hover .icon { transform: none; }
2986}
2987/* Als PWA al draait (standalone mode) — verberg install-prompt knop volledig */
2988@media all and (display-mode: standalone) {
2989 #pwa-install-btn { display: none !important; }
2990}
2991
2992/* ========== v8.9.9 — Privé-post indicators ========== */
2993.post-private-banner {
2994 display: flex;
2995 align-items: center;
2996 gap: .6rem;
2997 padding: .75rem 1rem;
2998 background: color-mix(in srgb, #eab308 12%, var(--paper, #fff));
2999 border: 1px solid color-mix(in srgb, #eab308 40%, transparent);
3000 border-radius: 8px;
3001 margin: 0 0 1rem;
3002 font-size: .88rem;
3003 color: var(--ink, #1a1a1a);
3004}
3005.post-private-banner strong {
3006 color: #b45309;
3007}
3008
3009.grid-tile-private {
3010 position: absolute;
3011 top: 8px;
3012 left: 8px;
3013 padding: 3px 8px;
3014 background: rgba(0,0,0,0.7);
3015 color: #fde68a;
3016 font-size: .7rem;
3017 font-weight: 700;
3018 border-radius: 999px;
3019 z-index: 3;
3020 backdrop-filter: blur(4px);
3021 -webkit-backdrop-filter: blur(4px);
3022}
3023
3024/* ========== v8.9.10 — Social chip (inline in post-body) ========== */
3025.social-chip {
3026 display: inline-flex;
3027 align-items: center;
3028 gap: .45rem;
3029 padding: .35rem .75rem;
3030 background: color-mix(in srgb, var(--accent) 10%, transparent);
3031 border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
3032 border-radius: 999px;
3033 color: var(--ink, #1a1a1a);
3034 text-decoration: none;
3035 font-family: var(--font-ui, system-ui);
3036 font-size: .85rem;
3037 font-weight: 600;
3038 line-height: 1.2;
3039 transition: all .15s;
3040 vertical-align: middle;
3041 margin: 0 .1rem;
3042}
3043.social-chip:hover {
3044 background: var(--accent);
3045 color: #fff;
3046 border-color: var(--accent);
3047 text-decoration: none;
3048 transform: translateY(-1px);
3049 box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 40%, transparent);
3050}
3051.social-chip .icon {
3052 width: 16px;
3053 height: 16px;
3054 flex-shrink: 0;
3055}
3056.social-chip-icon-only {
3057 width: 36px;
3058 height: 36px;
3059 padding: 0;
3060 justify-content: center;
3061 border-radius: 50%;
3062}
3063.social-chip-icon-only .icon {
3064 width: 18px;
3065 height: 18px;
3066}
3067
3068/* v8.9.34 — player hidden state + post audio blocks
3069 v9.3 — Hide-rules uitgeschakeld: mini-player blijft permanent zichtbaar
3070 zodat 'ie niet meer verdwijnt bij browser-back of navigatie. */
3071.audio-player.is-hidden {
3072 /* display: none !important; */
3073}
3074body:not(.has-audio-player) #pcms-audio-player.is-hidden {
3075 /* display: none !important; */
3076}
3077
3078/* Post audio track — single track row in een post */
3079/* Lokale audio-track — visueel consistent met .post-audio-external */
3080.post-audio-track {
3081 display: flex;
3082 align-items: center;
3083 gap: .75rem;
3084 padding: .65rem .85rem;
3085 background: var(--paper-2, color-mix(in srgb, var(--ink) 4%, transparent));
3086 border: 1px solid var(--rule, rgba(0,0,0,.08));
3087 border-radius: 10px;
3088 margin: .75rem 0;
3089 transition: background .15s, border-color .15s;
3090}
3091.post-audio-track:hover {
3092 border-color: var(--accent, #c2410c);
3093 background: color-mix(in srgb, var(--accent, #c2410c) 5%, var(--paper-2, transparent));
3094}
3095/* Korte highlight wanneer je via de mini-speler naar deze track springt. */
3096.post-audio-track.pat-flash,
3097.post-album-track-compact.pat-flash {
3098 animation: patFlash 1.6s ease-out;
3099 border-radius: 8px;
3100}
3101/* Blijvende highlight op de track die NU actief is in de speler. */
3102.post-audio-track.pat-playing,
3103.post-album-track-compact.pat-playing {
3104 background: color-mix(in srgb, var(--accent, #c2410c) 12%, var(--paper-2, transparent));
3105 box-shadow: inset 3px 0 0 0 var(--accent, #c2410c);
3106 border-radius: 8px;
3107}
3108@keyframes patFlash {
3109 0%, 30% { border-color: var(--accent, #c2410c); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent, #c2410c) 35%, transparent); }
3110 100% { box-shadow: 0 0 0 0 transparent; }
3111}
3112.post-audio-track .pat-play {
3113 flex-shrink: 0;
3114 width: 42px;
3115 height: 42px;
3116 border-radius: 8px; /* zelfde rounded-square als pae-icon */
3117 border: none;
3118 background: var(--accent, #c2410c);
3119 color: var(--paper, #fff);
3120 cursor: pointer;
3121 display: inline-flex;
3122 align-items: center;
3123 justify-content: center;
3124 transition: transform .1s, background .15s;
3125 padding: 0;
3126 position: relative;
3127 overflow: hidden;
3128}
3129.post-audio-track .pat-play:hover { transform: scale(1.04); }
3130.post-audio-track .pat-play:active { transform: scale(.96); }
3131.post-audio-track .pat-play svg,
3132.post-audio-track .pat-play .pat-sitelogo {
3133 width: 100%; height: 100%;
3134 position: absolute;
3135 top: 0; left: 0;
3136 transition: opacity .15s;
3137}
3138.post-audio-track .pat-play .icon-play,
3139.post-audio-track .pat-play .icon-pause {
3140 width: 18px; height: 18px;
3141 position: absolute;
3142 top: 50%; left: 50%;
3143 transform: translate(-50%, -50%);
3144 fill: currentColor;
3145 opacity: 0; /* verborgen tot hover of is-current */
3146}
3147/* Site logo: object-cover binnen 42x42 box */
3148.post-audio-track .pat-play .pat-sitelogo {
3149 object-fit: cover;
3150 opacity: 1;
3151}
3152.post-audio-track .pat-play .pat-sitelogo-fallback {
3153 padding: 11px; /* SVG music-note iets kleiner in box */
3154 opacity: 1;
3155}
3156/* Bij hover: site logo faded, play-icoon verschijnt */
3157.post-audio-track:hover .pat-play .pat-sitelogo { opacity: 0.25; }
3158.post-audio-track:hover .pat-play .icon-play { opacity: 1; }
3159/* Bij current + playing: toon pause-icon */
3160.post-audio-track.is-current .pat-play .pat-sitelogo { opacity: 0.25; }
3161.post-audio-track.is-current .pat-play .icon-play { opacity: 1; }
3162.post-audio-track.is-current.is-playing .pat-play .icon-play { opacity: 0; }
3163.post-audio-track.is-current.is-playing .pat-play .icon-pause { opacity: 1; }
3164.post-audio-track.is-current {
3165 border-color: var(--accent, #c2410c);
3166 background: color-mix(in srgb, var(--accent, #c2410c) 10%, transparent);
3167}
3168.post-audio-track .pat-meta {
3169 flex: 1;
3170 min-width: 0;
3171 display: flex;
3172 flex-direction: column;
3173 gap: 2px;
3174}
3175.post-audio-track .pat-title {
3176 display: block;
3177 font-weight: 600;
3178 color: var(--ink);
3179 font-size: .95rem;
3180 overflow: hidden;
3181 text-overflow: ellipsis;
3182 white-space: nowrap;
3183}
3184.post-audio-track .pat-artist {
3185 display: block;
3186 font-size: .78rem;
3187 color: var(--ink-muted, var(--ink));
3188 opacity: .65;
3189 overflow: hidden;
3190 text-overflow: ellipsis;
3191 white-space: nowrap;
3192}
3193.post-audio-track .pat-duration {
3194 flex-shrink: 0;
3195 font-family: ui-monospace, monospace;
3196 font-size: .8rem;
3197 opacity: .55;
3198}
3199
3200/* Album block in een post */
3201.post-album {
3202 position: relative;
3203 border: 1px solid var(--rule, rgba(0,0,0,.1));
3204 border-radius: 14px;
3205 overflow: hidden;
3206 margin: 1.25rem 0;
3207 background: var(--paper-2, color-mix(in srgb, var(--ink) 3%, transparent));
3208}
3209.post-album-header {
3210 display: flex;
3211 gap: .75rem;
3212 padding: .55rem .7rem;
3213 align-items: center;
3214}
3215.post-album-cover {
3216 width: 120px;
3217 height: 120px;
3218 border-radius: 8px;
3219 background-size: cover;
3220 background-position: center;
3221 background-color: var(--rule);
3222 flex-shrink: 0;
3223}
3224/* v9.0 — Collage van track-covers als album-cover leeg is */
3225.post-album-cover-collage {
3226 display: grid;
3227 grid-template-columns: 1fr 1fr;
3228 grid-template-rows: 1fr 1fr;
3229 gap: 0;
3230 overflow: hidden;
3231 background: transparent;
3232}
3233.post-album-cover-collage .post-album-cover-tile {
3234 background-size: cover;
3235 background-position: center;
3236 width: 100%;
3237 height: 100%;
3238}
3239/* Empty state: gradient met muziek-noot */
3240.post-album-cover-empty {
3241 display: flex;
3242 align-items: center;
3243 justify-content: center;
3244 background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 25%, var(--paper-2)), color-mix(in srgb, var(--accent) 10%, var(--paper)));
3245 color: var(--accent, #c2410c);
3246}
3247.post-album-cover-empty svg {
3248 width: 42%;
3249 height: 42%;
3250 opacity: .55;
3251}
3252.post-album-info {
3253 flex: 1;
3254 min-width: 0;
3255}
3256.post-album-label {
3257 text-transform: uppercase;
3258 font-size: .68rem;
3259 letter-spacing: .1em;
3260 opacity: .55;
3261 margin: 0 0 .15rem;
3262 font-weight: 700;
3263}
3264.post-album-title {
3265 font-family: var(--font-display);
3266 font-size: 1.1rem;
3267 font-weight: 600;
3268 margin: 0 0 .1rem;
3269 line-height: 1.15;
3270 letter-spacing: -0.01em;
3271}
3272.post-album-artist {
3273 font-size: .88rem;
3274 opacity: .8;
3275 margin: 0 0 .12rem;
3276 line-height: 1.25;
3277}
3278.post-album-meta {
3279 font-size: .74rem;
3280 opacity: .55;
3281 margin: 0;
3282 line-height: 1.2;
3283}
3284.post-album-playall {
3285 margin-top: .75rem;
3286 padding: .45rem .9rem;
3287 background: var(--accent, #c2410c);
3288 color: var(--paper, #fff);
3289 border: none;
3290 border-radius: 6px;
3291 font-weight: 600;
3292 cursor: pointer;
3293 font-size: .88rem;
3294 display: inline-flex;
3295 align-items: center;
3296 gap: .35rem;
3297}
3298.post-album-playall:hover { filter: brightness(1.08); }
3299
3300/* ============================================================
3301 v9.0 — Album cover clickable button
3302 ============================================================ */
3303.post-album-cover-btn {
3304 position: relative;
3305 background: none;
3306 border: none;
3307 padding: 0;
3308 margin: 0;
3309 cursor: pointer;
3310 flex-shrink: 0;
3311 border-radius: 8px;
3312 overflow: hidden;
3313 display: block;
3314 width: auto;
3315 /* v9.1 — voorkom mobile 300ms double-tap zoom delay, anders zou 2× snel klikken
3316 een zoom triggeren i.p.v. 2× click-events */
3317 touch-action: manipulation;
3318 -webkit-tap-highlight-color: transparent;
3319}
3320.post-album-cover-btn .post-album-cover {
3321 display: block;
3322 width: 76px;
3323 height: 76px;
3324 border-radius: 7px;
3325 background-size: cover;
3326 background-position: center;
3327 background-color: var(--rule);
3328 transition: transform .25s ease;
3329}
3330.post-album-cover-btn:hover .post-album-cover {
3331 transform: scale(1.04);
3332}
3333.post-album-cover-btn .post-album-cover-empty {
3334 background: linear-gradient(135deg,
3335 color-mix(in srgb, var(--accent, #c2410c) 35%, var(--paper)),
3336 color-mix(in srgb, var(--accent, #c2410c) 10%, var(--paper-2)));
3337 display: flex;
3338 align-items: center;
3339 justify-content: center;
3340}
3341.post-album-cover-btn .post-album-cover-empty svg {
3342 width: 28px;
3343 height: 28px;
3344 color: color-mix(in srgb, var(--accent, #c2410c) 60%, transparent);
3345}
3346/* Play overlay op hover */
3347.post-album-cover-play {
3348 position: absolute;
3349 inset: 0;
3350 display: flex;
3351 align-items: center;
3352 justify-content: center;
3353 background: rgba(0, 0, 0, .35);
3354 opacity: 0;
3355 transition: opacity .2s ease;
3356 border-radius: 8px;
3357 pointer-events: none;
3358}
3359.post-album-cover-play svg {
3360 width: 48px;
3361 height: 48px;
3362 color: #fff;
3363 filter: drop-shadow(0 2px 8px rgba(0,0,0,.4));
3364}
3365.post-album-cover-btn:hover .post-album-cover-play,
3366.post-album-cover-btn:focus-visible .post-album-cover-play {
3367 opacity: 1;
3368}
3369
3370/* ============================================================
3371 v1 P52 — Admin actions overlay (edit / delete)
3372 Only rendered when the viewer has god role. Sits top-right
3373 of the card so it doesn't compete with the cover play affordance.
3374 ============================================================ */
3375.post-album-actions {
3376 position: absolute;
3377 top: .4rem;
3378 right: .4rem;
3379 display: flex;
3380 gap: .25rem;
3381 z-index: 2;
3382}
3383.post-album-action {
3384 width: 28px;
3385 height: 28px;
3386 border-radius: 6px;
3387 border: 1px solid var(--rule);
3388 background: color-mix(in srgb, var(--paper) 78%, transparent);
3389 backdrop-filter: blur(8px);
3390 -webkit-backdrop-filter: blur(8px);
3391 color: var(--ink);
3392 display: inline-flex;
3393 align-items: center;
3394 justify-content: center;
3395 cursor: pointer;
3396 text-decoration: none;
3397 opacity: .65;
3398 padding: 0;
3399 transition: opacity .15s ease, transform .15s ease, background .15s ease, color .15s ease, border-color .15s ease;
3400 -webkit-tap-highlight-color: transparent;
3401}
3402.post-album-action:hover,
3403.post-album-action:focus-visible {
3404 opacity: 1;
3405 transform: translateY(-1px);
3406 outline: none;
3407}
3408.post-album-action.is-danger:hover,
3409.post-album-action.is-danger:focus-visible {
3410 background: color-mix(in srgb, #c2410c 18%, var(--paper));
3411 border-color: color-mix(in srgb, #c2410c 45%, var(--rule));
3412 color: #c2410c;
3413}
3414.post-album-action svg {
3415 width: 15px;
3416 height: 15px;
3417 display: block;
3418}
3419
3420/* ============================================================
3421 v9.0 — Compacte tracklist (informatief, niet-klikbaar)
3422 ============================================================ */
3423.post-album-tracks {
3424 list-style: none;
3425 padding: 0;
3426 margin: 0;
3427 border-top: 1px solid var(--rule);
3428}
3429/* v9.4 — Playlist insert modal rows */
3430.pli-row {
3431 display: flex;
3432 align-items: center;
3433 gap: .75rem;
3434 padding: .65rem .5rem;
3435 border-bottom: 1px solid var(--border);
3436}
3437.pli-row:last-child { border-bottom: none; }
3438.pli-row-cover {
3439 width: 44px;
3440 height: 44px;
3441 border-radius: 6px;
3442 background-size: cover;
3443 background-position: center;
3444 background-color: color-mix(in srgb, var(--ink, #000) 8%, transparent);
3445 flex-shrink: 0;
3446 display: flex;
3447 align-items: center;
3448 justify-content: center;
3449 font-size: 1.4rem;
3450}
3451.pli-row-info {
3452 flex: 1;
3453 min-width: 0;
3454}
3455.pli-row-title {
3456 font-weight: 600;
3457 overflow: hidden;
3458 text-overflow: ellipsis;
3459 white-space: nowrap;
3460}
3461.pli-row-meta {
3462 font-size: .82rem;
3463 overflow: hidden;
3464 text-overflow: ellipsis;
3465 white-space: nowrap;
3466}
3467.post-playlist-placeholder {
3468 margin: 1rem 0;
3469 user-select: none;
3470}
3471
3472/* v9.4 — Generic modal classes (gebruikt door playlist-editor en andere modals) */
3473.pcms-modal-backdrop {
3474 position: fixed;
3475 inset: 0;
3476 background: rgba(0, 0, 0, .6);
3477 display: flex;
3478 align-items: center;
3479 justify-content: center;
3480 z-index: 9000;
3481 padding: 1rem;
3482 box-sizing: border-box;
3483 overflow-y: auto;
3484}
3485.pcms-modal {
3486 background: var(--paper, #fff);
3487 color: var(--ink, #000);
3488 border-radius: 12px;
3489 width: 100%;
3490 max-width: 640px;
3491 max-height: calc(100vh - 2rem);
3492 display: flex;
3493 flex-direction: column;
3494 overflow: hidden;
3495 box-shadow: 0 20px 60px rgba(0, 0, 0, .3);
3496}
3497.pcms-modal-header {
3498 display: flex;
3499 align-items: center;
3500 justify-content: space-between;
3501 padding: 1rem 1.25rem;
3502 border-bottom: 1px solid var(--border);
3503 flex-shrink: 0;
3504}
3505.pcms-modal-header h3 { font-size: 1.1rem; }
3506.pcms-modal-close {
3507 background: transparent;
3508 border: none;
3509 font-size: 1.6rem;
3510 line-height: 1;
3511 cursor: pointer;
3512 padding: .25rem .5rem;
3513 color: var(--fg-muted, #666);
3514 border-radius: 4px;
3515}
3516.pcms-modal-close:hover {
3517 background: color-mix(in srgb, var(--ink, #000) 8%, transparent);
3518}
3519.pcms-modal-body {
3520 padding: 1.25rem;
3521 overflow-y: auto;
3522 overscroll-behavior: contain;
3523 flex: 1;
3524 min-height: 0;
3525}
3526.pcms-modal-footer {
3527 display: flex;
3528 gap: .5rem;
3529 justify-content: flex-end;
3530 padding: .75rem 1.25rem;
3531 border-top: 1px solid var(--border);
3532 flex-shrink: 0;
3533 background: color-mix(in srgb, var(--ink, #000) 3%, transparent);
3534}
3535
3536/* On mobile: full-screen modal */
3537@media (max-width: 600px) {
3538 .pcms-modal-backdrop {
3539 padding: 0;
3540 }
3541 .pcms-modal {
3542 border-radius: 0;
3543 max-width: 100%;
3544 max-height: 100vh;
3545 height: 100vh;
3546 }
3547}
3548
3549/* v9.4 — Media → Playlists tab */
3550.playlists-page-header {
3551 display: flex;
3552 flex-wrap: wrap;
3553 gap: 1rem;
3554 align-items: center;
3555 justify-content: space-between;
3556 margin-bottom: 1.25rem;
3557}
3558.playlists-page-header > p { flex: 1; min-width: 200px; }
3559.playlists-grid {
3560 display: grid;
3561 grid-template-columns: 1fr;
3562 gap: .75rem;
3563}
3564@media (min-width: 720px) {
3565 .playlists-grid { grid-template-columns: repeat(2, 1fr); }
3566}
3567@media (min-width: 1100px) {
3568 .playlists-grid { grid-template-columns: repeat(3, 1fr); }
3569}
3570.playlist-card {
3571 display: grid;
3572 grid-template-columns: 64px 1fr auto;
3573 gap: .75rem;
3574 align-items: center;
3575 padding: .75rem;
3576 border: 1px solid var(--border);
3577 border-radius: var(--radius);
3578 background: var(--paper, #fff);
3579}
3580.playlist-card-cover {
3581 width: 64px;
3582 height: 64px;
3583 border-radius: 8px;
3584 overflow: hidden;
3585 background-color: color-mix(in srgb, var(--ink, #000) 6%, transparent);
3586 display: flex;
3587 align-items: center;
3588 justify-content: center;
3589}
3590.playlist-card-cover img {
3591 width: 100%;
3592 height: 100%;
3593 object-fit: cover;
3594}
3595.playlist-card-cover-empty { font-size: 1.6rem; opacity: .5; }
3596.playlist-card-info { min-width: 0; }
3597.playlist-card-title {
3598 font-weight: 600;
3599 overflow: hidden;
3600 text-overflow: ellipsis;
3601 white-space: nowrap;
3602}
3603.playlist-card-artist,
3604.playlist-card-meta {
3605 font-size: .82rem;
3606 overflow: hidden;
3607 text-overflow: ellipsis;
3608 white-space: nowrap;
3609}
3610.playlist-card-actions {
3611 display: flex;
3612 gap: .25rem;
3613 flex-shrink: 0;
3614}
3615
3616/* v9.4 — Playlist editor modal (mobile-friendly, single-column) */
3617.pl-editor {
3618 /* Erft van .pcms-modal */
3619}
3620.pl-editor-meta {
3621 display: grid;
3622 grid-template-columns: 1fr;
3623 gap: .75rem;
3624 margin-bottom: 1rem;
3625}
3626@media (min-width: 560px) {
3627 .pl-editor-meta {
3628 grid-template-columns: 1fr 1fr;
3629 }
3630 .pl-editor-meta .pl-editor-field-full { grid-column: 1 / -1; }
3631}
3632.pl-editor-field {
3633 display: flex;
3634 flex-direction: column;
3635 gap: .25rem;
3636 min-width: 0;
3637}
3638.pl-editor-field span {
3639 font-size: .82rem;
3640 color: var(--fg-muted, #666);
3641 font-weight: 500;
3642}
3643.pl-editor-field input,
3644.pl-editor-field select {
3645 width: 100%;
3646 box-sizing: border-box;
3647 padding: .5rem .65rem;
3648 font-size: .95rem;
3649 border: 1px solid var(--border);
3650 border-radius: 6px;
3651 background: var(--paper, #fff);
3652 color: var(--ink, #000);
3653}
3654.pl-editor-field input:focus,
3655.pl-editor-field select:focus {
3656 outline: 2px solid var(--accent, #5a8a5a);
3657 outline-offset: -1px;
3658}
3659.pl-editor-section-title {
3660 margin: 1.25rem 0 .5rem;
3661 font-size: 1rem;
3662 font-weight: 600;
3663}
3664.pl-tracks-selected {
3665 border: 1px solid var(--border);
3666 border-radius: var(--radius);
3667 background: var(--paper, #fff);
3668 min-height: 60px;
3669 margin-bottom: 1rem;
3670 padding: .25rem;
3671}
3672.pl-tracks-empty {
3673 padding: 1.5rem;
3674 text-align: center;
3675 color: var(--fg-muted, #666);
3676 font-size: .9rem;
3677}
3678.pl-track-row {
3679 display: grid;
3680 grid-template-columns: 32px 36px 1fr auto;
3681 gap: .5rem;
3682 align-items: center;
3683 padding: .5rem;
3684 border-bottom: 1px solid var(--border);
3685 background: var(--paper, #fff);
3686 user-select: none;
3687 touch-action: pan-x;
3688}
3689.pl-track-row:last-child { border-bottom: none; }
3690.pl-track-row.is-dragging {
3691 opacity: .55;
3692 transform: scale(.98);
3693 background: color-mix(in srgb, var(--accent, #5a8a5a) 10%, transparent);
3694 border-radius: 6px;
3695}
3696.pl-track-row.drop-target-above {
3697 box-shadow: inset 0 2px 0 0 var(--accent, #5a8a5a);
3698}
3699.pl-track-row.drop-target-below {
3700 box-shadow: inset 0 -2px 0 0 var(--accent, #5a8a5a);
3701}
3702.pl-track-handle {
3703 cursor: grab;
3704 font-size: 1.2rem;
3705 line-height: 1;
3706 color: var(--fg-muted, #666);
3707 display: flex;
3708 align-items: center;
3709 justify-content: center;
3710 height: 32px;
3711 width: 32px;
3712 border-radius: 4px;
3713 flex-shrink: 0;
3714}
3715.pl-track-handle:active { cursor: grabbing; }
3716.pl-track-handle:hover {
3717 background: color-mix(in srgb, var(--ink, #000) 8%, transparent);
3718}
3719.pl-track-num {
3720 text-align: center;
3721 color: var(--fg-muted, #666);
3722 font-size: .85rem;
3723 width: 36px;
3724}
3725.pl-track-info {
3726 min-width: 0;
3727 overflow: hidden;
3728}
3729.pl-track-title {
3730 font-weight: 500;
3731 overflow: hidden;
3732 text-overflow: ellipsis;
3733 white-space: nowrap;
3734}
3735.pl-track-artist {
3736 font-size: .78rem;
3737 color: var(--fg-muted, #666);
3738 overflow: hidden;
3739 text-overflow: ellipsis;
3740 white-space: nowrap;
3741}
3742.pl-track-remove {
3743 background: transparent;
3744 border: none;
3745 cursor: pointer;
3746 padding: .35rem;
3747 border-radius: 4px;
3748 color: var(--fg-muted, #666);
3749 font-size: 1.2rem;
3750 line-height: 1;
3751}
3752.pl-track-remove:hover {
3753 background: color-mix(in srgb, #c00 12%, transparent);
3754 color: #c00;
3755}
3756
3757/* Available tracks panel */
3758.pl-tracks-available-panel {
3759 border: 1px solid var(--border);
3760 border-radius: var(--radius);
3761 background: var(--paper, #fff);
3762}
3763.pl-tracks-available-search {
3764 padding: .5rem;
3765 border-bottom: 1px solid var(--border);
3766}
3767.pl-tracks-available-search input {
3768 width: 100%;
3769 box-sizing: border-box;
3770}
3771.pl-tracks-available-list {
3772 max-height: 30vh;
3773 overflow-y: auto;
3774}
3775.pl-track-row-available {
3776 display: grid;
3777 grid-template-columns: 1fr auto;
3778 gap: .5rem;
3779 align-items: center;
3780 padding: .5rem;
3781 border-bottom: 1px solid var(--border);
3782 cursor: pointer;
3783}
3784.pl-track-row-available:last-child { border-bottom: none; }
3785.pl-track-row-available:hover {
3786 background: color-mix(in srgb, var(--accent, #5a8a5a) 8%, transparent);
3787}
3788.pl-track-row-available.is-already-added {
3789 opacity: .4;
3790 pointer-events: none;
3791}
3792.pl-track-add-btn {
3793 background: transparent;
3794 border: 1px solid var(--border);
3795 border-radius: 4px;
3796 padding: .25rem .5rem;
3797 cursor: pointer;
3798 font-size: .85rem;
3799 color: var(--accent, #5a8a5a);
3800}
3801
3802/* v9.3 — Tracklist items zijn nu klikbare <button class="pat-row"> binnen <li>.
3803 De LI is puur een container zonder visuele styling; alles gebeurt op de button. */
3804.post-album-track-compact {
3805 padding: 0;
3806 margin: 0;
3807 border-bottom: 1px solid var(--rule);
3808 list-style: none;
3809}
3810.post-album-track-compact:last-child { border-bottom: none; }
3811
3812.pat-row {
3813 display: grid;
3814 grid-template-columns: 32px 1fr auto;
3815 gap: .65rem;
3816 align-items: center;
3817 width: 100%;
3818 padding: .5rem .85rem;
3819 background: transparent;
3820 border: none;
3821 color: inherit;
3822 font: inherit;
3823 font-size: .82rem;
3824 text-align: left;
3825 cursor: pointer;
3826 position: relative;
3827 transition: background .15s ease;
3828}
3829.pat-row:hover {
3830 background: color-mix(in srgb, var(--ink, #000) 6%, transparent);
3831}
3832.pat-row:active { transform: scale(.995); }
3833[data-theme="dark"] .pat-row:hover {
3834 background: color-mix(in srgb, var(--paper, #fff) 10%, transparent);
3835}
3836
3837/* Leader: track-nummer OF cover-thumb (afhankelijk van kind).
3838 v9.3 — pat-leader is altijd 32×32, met overgang voor spinner-vervanging. */
3839.pat-row .pat-num,
3840.pat-row .pat-cover {
3841 width: 32px;
3842 height: 32px;
3843 border-radius: 4px;
3844 flex-shrink: 0;
3845 transition: opacity .25s ease, transform .25s ease;
3846}
3847.pat-row .pat-num {
3848 font-family: ui-monospace, monospace;
3849 font-size: .8rem;
3850 opacity: .5;
3851 display: flex;
3852 align-items: center;
3853 justify-content: center;
3854}
3855.pat-row .pat-cover {
3856 background-size: cover;
3857 background-position: center;
3858 background-color: color-mix(in srgb, var(--ink, #000) 8%, transparent);
3859}
3860
3861/* v9.3 — Loading-spiraal als overlay op de leader-kolom.
3862 pat-num/pat-cover faden uit, spinner faded in via ::before. */
3863.pat-row::before {
3864 content: "";
3865 position: absolute;
3866 left: .85rem; top: 50%;
3867 width: 32px; height: 32px;
3868 transform: translateY(-50%);
3869 color: var(--accent, #c2410c);
3870 background-color: currentColor;
3871 -webkit-mask: url('/assets/spinner.svg') center/26px 26px no-repeat;
3872 mask: url('/assets/spinner.svg') center/26px 26px no-repeat;
3873 opacity: 0;
3874 transition: opacity .25s ease;
3875 pointer-events: none;
3876 animation: pat-spinner-rotate 1.2s linear infinite;
3877 animation-play-state: paused;
3878}
3879.pat-row.is-loading::before {
3880 opacity: 1;
3881 animation-play-state: running;
3882}
3883.pat-row.is-loading .pat-num,
3884.pat-row.is-loading .pat-cover {
3885 opacity: 0;
3886 transform: scale(.85);
3887}
3888@keyframes pat-spinner-rotate {
3889 from { transform: translateY(-50%) rotate(0deg); }
3890 to { transform: translateY(-50%) rotate(-360deg); }
3891}
3892
3893/* Meta-kolom */
3894.pat-row .pat-meta {
3895 display: flex;
3896 flex-direction: column;
3897 min-width: 0;
3898 gap: 1px;
3899 overflow: hidden;
3900}
3901.pat-row .pat-title {
3902 font-weight: 500;
3903 overflow: hidden;
3904 text-overflow: ellipsis;
3905 white-space: nowrap;
3906}
3907.pat-row .pat-artist {
3908 font-size: .72rem;
3909 opacity: .6;
3910 overflow: hidden;
3911 text-overflow: ellipsis;
3912 white-space: nowrap;
3913}
3914.pat-row .pat-duration {
3915 font-family: ui-monospace, monospace;
3916 font-size: .72rem;
3917 opacity: .55;
3918 font-variant-numeric: tabular-nums;
3919 white-space: nowrap;
3920}
3921.pat-row .pat-duration-empty {
3922 opacity: .25;
3923}
3924
3925/* is-current — actieve track in de player */
3926.pat-row.is-current {
3927 background: color-mix(in srgb, var(--accent, #c2410c) 12%, transparent);
3928}
3929.pat-row.is-current .pat-title,
3930.pat-row.is-current .pat-artist { color: var(--accent, #c2410c); }
3931
3932/* v9.3 — Marquee bij actief afspelen: titel scrollt heen-en-weer.
3933 --pat-shift wordt door JS gezet (= overflow in pixels). Bij 0 → geen
3934 beweging want translateX(0) blijft 0.
3935 Snelle cyclus (6s) met korte rust aan beide uiteinden (8%) zodat 't
3936 vlot voelt zonder onleesbaar te zijn. */
3937.pat-row.is-current.is-playing .pat-title {
3938 animation: pat-title-marquee 6s ease-in-out infinite alternate;
3939 text-overflow: clip;
3940 overflow: visible;
3941 will-change: transform;
3942}
3943@keyframes pat-title-marquee {
3944 0%, 8% { transform: translateX(0); }
3945 92%, 100% { transform: translateX(calc(-1 * var(--pat-shift, 0px))); }
3946}
3947
3948/* ============================================================
3949 v9.0 — CSS-migratie voor OUDE opgeslagen albums
3950 Oude posts hebben <li class="post-audio-track"> met play-knoppen + cover-spans.
3951 We renderen die VISUEEL als compact, zonder de HTML aan te passen.
3952 ============================================================ */
3953.post-album-tracks .post-audio-track {
3954 display: grid;
3955 grid-template-columns: 28px 1fr auto;
3956 gap: .75rem;
3957 align-items: center;
3958 padding: .5rem .85rem;
3959 margin: 0;
3960 border: none;
3961 border-bottom: 1px solid var(--rule);
3962 background: transparent;
3963 border-radius: 0;
3964 cursor: default;
3965 font-size: .92rem;
3966}
3967.post-album-tracks .post-audio-track:last-child { border-bottom: none; }
3968/* Verberg de cover-thumb en play-button in OUDE saved posts */
3969.post-album-tracks .post-audio-track .pat-cover,
3970.post-album-tracks .post-audio-track .pat-play {
3971 display: none !important;
3972}
3973.post-album-tracks .post-audio-track .pat-num {
3974 font-family: ui-monospace, monospace;
3975 font-size: .8rem;
3976 opacity: .45;
3977 text-align: center;
3978 width: auto;
3979}
3980.post-album-tracks .post-audio-track .pat-meta {
3981 display: flex;
3982 flex-direction: column;
3983 min-width: 0;
3984 gap: 1px;
3985}
3986.post-album-tracks .post-audio-track .pat-title {
3987 font-weight: 500;
3988 overflow: hidden;
3989 text-overflow: ellipsis;
3990 white-space: nowrap;
3991}
3992.post-album-tracks .post-audio-track .pat-artist {
3993 font-size: .78rem;
3994 opacity: .6;
3995}
3996.post-album-tracks .post-audio-track .pat-duration {
3997 font-family: ui-monospace, monospace;
3998 font-size: .78rem;
3999 opacity: .55;
4000}
4001.post-album-tracks .post-audio-track.is-current {
4002 background: color-mix(in srgb, var(--accent, #c2410c) 10%, transparent);
4003}
4004.post-album-tracks .post-audio-track.is-current .pat-num,
4005.post-album-tracks .post-audio-track.is-current .pat-title {
4006 color: var(--accent);
4007}
4008
4009@media (max-width: 540px) {
4010 .post-album-header { flex-direction: column; }
4011 .post-album-cover-btn .post-album-cover { width: 100%; max-width: 240px; height: auto; aspect-ratio: 1/1; }
4012}
4013@media (max-width: 380px) {
4014 .post-album-header { padding: .75rem; gap: .75rem; }
4015 .post-album-cover-btn .post-album-cover { max-width: 180px; }
4016 .post-album-title { font-size: 1.15rem; }
4017 .post-album-meta { font-size: .8rem; }
4018 .post-album-track-compact,
4019 .post-album-tracks .post-audio-track {
4020 grid-template-columns: 24px 1fr auto;
4021 gap: .5rem;
4022 padding: .4rem .6rem;
4023 font-size: .85rem;
4024 }
4025 .post-album-track-compact .pat-duration,
4026 .post-album-tracks .post-audio-track .pat-duration {
4027 font-size: .72rem;
4028 }
4029 /* Queue items in expand-sheet */
4030 .audio-sheet-queue-item { padding: .4rem .45rem; gap: .55rem; }
4031 .audio-sheet-queue-cover { width: 32px; height: 32px; }
4032 .audio-sheet-queue-title { font-size: .85rem; }
4033 .audio-sheet-queue-artist { font-size: .7rem; }
4034}
4035
4036/* External track (SoundCloud / YouTube / Spotify / etc) — klikbaar maar link-naar-platform */
4037.post-audio-external {
4038 display: flex;
4039 align-items: center;
4040 gap: .75rem;
4041 padding: .65rem .85rem;
4042 background: var(--paper-2, color-mix(in srgb, var(--ink) 4%, transparent));
4043 border: 1px solid var(--rule, rgba(0,0,0,.08));
4044 border-radius: 10px;
4045 margin: .75rem 0;
4046 text-decoration: none;
4047 color: var(--ink);
4048 transition: background .15s, border-color .15s;
4049}
4050.post-audio-external:hover {
4051 border-color: var(--accent);
4052 background: color-mix(in srgb, var(--accent) 5%, var(--paper-2, transparent));
4053}
4054.post-audio-external .pae-icon {
4055 flex-shrink: 0;
4056 width: 42px;
4057 height: 42px;
4058 border-radius: 8px;
4059 display: inline-flex;
4060 align-items: center;
4061 justify-content: center;
4062 background: var(--platform-color, #555);
4063 color: #fff;
4064 font-size: 1.2rem;
4065}
4066.post-audio-external .pae-icon-svg svg {
4067 width: 60%;
4068 height: 60%;
4069 fill: currentColor;
4070}
4071/* Per-platform vult de box net wat anders — brand-specifiek geoptimaliseerd */
4072.post-audio-external[data-platform="soundcloud"] .pae-icon-svg svg { width: 72%; height: auto; }
4073.post-audio-external[data-platform="spotify"] .pae-icon-svg svg { width: 72%; height: 72%; }
4074.post-audio-external[data-platform="youtube"] .pae-icon-svg svg { width: 68%; height: auto; }
4075.post-audio-external[data-platform="bandcamp"] .pae-icon-svg svg { width: 62%; height: auto; }
4076.post-audio-external[data-platform="apple"] .pae-icon-svg svg { width: 58%; height: 58%; }
4077.post-audio-external[data-platform="tidal"] .pae-icon-svg svg { width: 68%; height: auto; }
4078.post-audio-external[data-platform="deezer"] .pae-icon-svg svg { width: 65%; height: auto; }
4079.post-audio-external[data-platform="mixcloud"] .pae-icon-svg svg { width: 75%; height: auto; }
4080.post-audio-external[data-platform="soundcloud"] .pae-icon { background: #ff5500; }
4081.post-audio-external[data-platform="spotify"] .pae-icon { background: #1db954; }
4082.post-audio-external[data-platform="youtube"] .pae-icon { background: #ff0000; }
4083.post-audio-external[data-platform="bandcamp"] .pae-icon { background: #1da0c3; }
4084.post-audio-external[data-platform="apple"] .pae-icon { background: #fa243c; }
4085.post-audio-external[data-platform="tidal"] .pae-icon { background: #000; }
4086.post-audio-external[data-platform="deezer"] .pae-icon { background: #a238ff; }
4087.post-audio-external[data-platform="mixcloud"] .pae-icon { background: #314359; }
4088.post-audio-external[data-platform="other"] .pae-icon { background: #555; }
4089.post-audio-external .pae-meta {
4090 flex: 1;
4091 min-width: 0;
4092 display: flex;
4093 flex-direction: column;
4094 gap: 2px;
4095}
4096.post-audio-external .pae-title {
4097 display: block;
4098 font-weight: 600;
4099 overflow: hidden;
4100 text-overflow: ellipsis;
4101 white-space: nowrap;
4102 color: var(--ink);
4103}
4104.post-audio-external .pae-platform {
4105 display: block;
4106 font-size: .78rem;
4107 opacity: .65;
4108 text-transform: capitalize;
4109}
4110.post-audio-external .pae-go {
4111 flex-shrink: 0;
4112 opacity: .5;
4113 font-size: 1.1rem;
4114}
4115
4116/* =========================================================================
4117 v9.0 — Video player (inline)
4118 ========================================================================= */
4119
4120.post-video-figure {
4121 margin: 1.25rem 0;
4122 max-width: 100%;
4123}
4124
4125.post-video {
4126 display: block;
4127 width: 100%;
4128 max-width: 100%;
4129 height: auto;
4130 border-radius: 10px;
4131 background: #000;
4132 box-shadow: 0 4px 20px rgba(0,0,0,.15);
4133}
4134
4135.post-video-caption {
4136 margin-top: .5rem;
4137 font-size: .88rem;
4138 color: var(--ink-muted, color-mix(in srgb, var(--ink) 60%, transparent));
4139 text-align: center;
4140 line-height: 1.5;
4141}
4142
4143.post-video-caption strong {
4144 display: inline;
4145 font-weight: 600;
4146 color: var(--ink);
4147}
4148
4149@media (max-width: 640px) {
4150 .post-video-figure { margin: .75rem -.5rem; }
4151 .post-video { border-radius: 6px; }
4152}
4153
4154/* v9.3 — Floating "Bewerken" knop voor album-blokken in de post-editor.
4155 Verschijnt bij hover over een .post-album binnen #visual en wordt via JS
4156 geplaatst op de rechterbovenhoek van het blok. Niet in de opgeslagen HTML. */
4157.pcms-album-edit-overlay {
4158 position: absolute;
4159 z-index: 1000;
4160 transform: translateX(-100%);
4161 display: inline-flex;
4162 align-items: center;
4163 gap: .35rem;
4164 padding: .35rem .7rem;
4165 background: var(--accent, #c2410c);
4166 color: #fff;
4167 border: none;
4168 border-radius: 6px;
4169 font-size: .82rem;
4170 font-weight: 600;
4171 cursor: pointer;
4172 box-shadow: 0 4px 12px rgba(0, 0, 0, .18);
4173 transition: transform .12s ease, box-shadow .12s ease;
4174}
4175.pcms-album-edit-overlay:hover {
4176 transform: translateX(-100%) translateY(-1px);
4177 box-shadow: 0 6px 16px rgba(0, 0, 0, .24);
4178}
4179.pcms-album-edit-overlay:active {
4180 transform: translateX(-100%) translateY(0);
4181 box-shadow: 0 2px 6px rgba(0, 0, 0, .18);
4182}
4183
4184/* v9.3 — Drag-and-drop in de album-builder selected-lijst */
4185.ab-selected-row { cursor: default; }
4186.ab-selected-row .ab-drag-handle {
4187 display: inline-flex;
4188 align-items: center;
4189 justify-content: center;
4190 width: 18px;
4191 height: 100%;
4192 color: color-mix(in srgb, currentColor 40%, transparent);
4193 cursor: grab;
4194 user-select: none;
4195 font-size: .9rem;
4196 letter-spacing: -2px;
4197 flex-shrink: 0;
4198}
4199.ab-selected-row:hover .ab-drag-handle {
4200 color: color-mix(in srgb, currentColor 70%, transparent);
4201}
4202.ab-selected-row.is-dragging {
4203 opacity: .35;
4204 cursor: grabbing;
4205}
4206.ab-selected-row.is-dragging .ab-drag-handle { cursor: grabbing; }
4207/* Drop-indicator lijnen boven/onder de target rij */
4208.ab-selected-row.is-drag-target-before {
4209 box-shadow: 0 -2px 0 0 var(--accent, #c2410c) inset, 0 2px 0 0 var(--accent, #c2410c);
4210 /* Gebruik outline voor cross-browser zichtbaarheid */
4211 position: relative;
4212}
4213.ab-selected-row.is-drag-target-before::before {
4214 content: "";
4215 position: absolute;
4216 top: -1px; left: 0; right: 0;
4217 height: 2px;
4218 background: var(--accent, #c2410c);
4219 pointer-events: none;
4220}
4221.ab-selected-row.is-drag-target-after::after {
4222 content: "";
4223 position: absolute;
4224 bottom: -1px; left: 0; right: 0;
4225 height: 2px;
4226 background: var(--accent, #c2410c);
4227 pointer-events: none;
4228}
4229.ab-selected-row.is-drag-target-after { position: relative; }
4230
4231/* v9.3 — Playlist fallback states (missing of empty playlist reference in post) */
4232.post-playlist-missing, .post-playlist-empty {
4233 padding: 1rem;
4234 margin: .75rem 0;
4235 background: color-mix(in srgb, var(--accent, #c2410c) 8%, transparent);
4236 border: 1px dashed color-mix(in srgb, var(--accent, #c2410c) 30%, transparent);
4237 border-radius: 8px;
4238 font-size: .9rem;
4239}
4240.post-playlist-missing em, .post-playlist-empty em {
4241 opacity: .8;
4242}
4243
4244/* v9.3 — Install-app footer-knop */
4245.site-footer-install {
4246 display: flex;
4247 justify-content: center;
4248 padding: 1rem 1rem 1.25rem;
4249 border-top: 1px solid color-mix(in srgb, currentColor 8%, transparent);
4250 margin-top: .5rem;
4251}
4252
4253/* v9.4 — Cooler install-knop: gradient + shimmer + perfect centering.
4254 Twee kleur-stops voor diepte, animated shimmer-streep om aandacht te trekken,
4255 icon perfect verticaal gecentreerd via flex (was: net iets te hoog tov tekst). */
4256.install-app-btn {
4257 position: relative;
4258 display: inline-flex;
4259 align-items: center;
4260 justify-content: center;
4261 gap: .55rem;
4262 padding: .8rem 1.6rem;
4263 background: linear-gradient(135deg,
4264 var(--accent, #c2410c),
4265 color-mix(in srgb, var(--accent, #c2410c) 80%, #000));
4266 color: #fff;
4267 border: none;
4268 border-radius: 999px;
4269 font: inherit;
4270 font-weight: 600;
4271 font-size: .95rem;
4272 line-height: 1;
4273 letter-spacing: .01em;
4274 cursor: pointer;
4275 overflow: hidden;
4276 isolation: isolate;
4277 box-shadow:
4278 0 1px 0 rgba(255,255,255,.15) inset,
4279 0 -2px 0 rgba(0,0,0,.1) inset,
4280 0 4px 14px color-mix(in srgb, var(--accent, #c2410c) 40%, transparent),
4281 0 1px 3px rgba(0,0,0,.18);
4282 transition:
4283 transform .15s cubic-bezier(.4, 0, .2, 1),
4284 box-shadow .2s ease,
4285 filter .15s ease;
4286}
4287.install-app-btn svg {
4288 flex-shrink: 0;
4289 /* subtle bounce-on-hover trigger, separate animation */
4290 transition: transform .25s cubic-bezier(.34, 1.56, .64, 1);
4291}
4292.install-app-btn span {
4293 line-height: 1;
4294}
4295
4296/* Shimmer-streep die langzaam over de knop loopt — "alive" effect */
4297.install-app-btn::before {
4298 content: "";
4299 position: absolute;
4300 top: 0;
4301 left: -100%;
4302 width: 60%;
4303 height: 100%;
4304 background: linear-gradient(110deg,
4305 transparent 30%,
4306 rgba(255,255,255,.25) 50%,
4307 transparent 70%);
4308 z-index: -1;
4309 animation: pcmsInstallShimmer 4s ease-in-out infinite;
4310 pointer-events: none;
4311}
4312@keyframes pcmsInstallShimmer {
4313 0%, 35% { left: -100%; }
4314 65%, 100% { left: 200%; }
4315}
4316
4317.install-app-btn:hover {
4318 transform: translateY(-2px) scale(1.02);
4319 filter: brightness(1.06);
4320 box-shadow:
4321 0 1px 0 rgba(255,255,255,.2) inset,
4322 0 -2px 0 rgba(0,0,0,.1) inset,
4323 0 8px 24px color-mix(in srgb, var(--accent, #c2410c) 55%, transparent),
4324 0 2px 6px rgba(0,0,0,.2);
4325}
4326.install-app-btn:hover svg {
4327 transform: translateY(-2px);
4328}
4329.install-app-btn:active {
4330 transform: translateY(0) scale(.98);
4331 transition-duration: .05s;
4332}
4333.install-app-btn:focus-visible {
4334 outline: 2px solid var(--accent, #c2410c);
4335 outline-offset: 3px;
4336}
4337
4338/* Reduced motion: shimmer uit, alleen statisch */
4339@media (prefers-reduced-motion: reduce) {
4340 .install-app-btn::before { animation: none; left: -100%; }
4341 .install-app-btn:hover { transform: none; }
4342 .install-app-btn:hover svg { transform: none; }
4343}
4344
4345/* Install-instructions modal */
4346.install-modal {
4347 position: fixed;
4348 inset: 0;
4349 z-index: 10000;
4350 display: flex;
4351 align-items: center;
4352 justify-content: center;
4353 padding: 1rem;
4354}
4355.install-modal-backdrop {
4356 position: absolute;
4357 inset: 0;
4358 background: rgba(0,0,0,.55);
4359 backdrop-filter: blur(3px);
4360}
4361.install-modal-panel {
4362 position: relative;
4363 z-index: 1;
4364 background: var(--paper);
4365 color: var(--ink);
4366 border: 1px solid var(--rule);
4367 border-radius: 14px;
4368 padding: 1.5rem;
4369 max-width: 440px;
4370 width: 100%;
4371 max-height: 90vh;
4372 overflow-y: auto;
4373 box-shadow: 0 20px 60px rgba(0,0,0,.4);
4374}
4375.install-modal-panel h3 { font-size: 1.15rem; color: var(--ink); }
4376.install-modal-panel h4 {
4377 margin: 1rem 0 .4rem;
4378 font-size: .92rem;
4379 letter-spacing: .03em;
4380 text-transform: uppercase;
4381 opacity: .7;
4382 color: var(--ink);
4383}
4384.install-modal-panel p { color: var(--ink); }
4385.install-steps {
4386 margin: 0;
4387 padding-left: 1.35rem;
4388 display: flex;
4389 flex-direction: column;
4390 gap: .45rem;
4391 font-size: .95rem;
4392 line-height: 1.45;
4393 color: var(--ink);
4394}
4395.install-steps li::marker { color: var(--accent); font-weight: 700; }
4396.install-apk-block {
4397 margin-top: 1.25rem;
4398 padding-top: 1rem;
4399 border-top: 1px dashed var(--rule);
4400}
4401.install-apk-link {
4402 display: inline-flex;
4403 align-items: center;
4404 margin-top: .4rem;
4405 padding: .6rem 1rem;
4406 background: var(--accent);
4407 color: #fff;
4408 border-radius: 8px;
4409 text-decoration: none;
4410 font-weight: 600;
4411}
4412.install-apk-link:hover { filter: brightness(1.08); }
4413.install-modal-actions {
4414 display: flex;
4415 justify-content: flex-end;
4416 margin-top: 1.25rem;
4417}
4418.install-modal-actions .btn {
4419 padding: .5rem 1rem;
4420 background: var(--paper-2);
4421 border: 1px solid var(--rule);
4422 border-radius: 8px;
4423 color: var(--ink);
4424 cursor: pointer;
4425 font: inherit;
4426 font-weight: 500;
4427}
4428.install-modal-actions .btn:hover {
4429 background: color-mix(in srgb, var(--accent) 10%, var(--paper-2));
4430 border-color: var(--accent);
4431 color: var(--accent);
4432}
4433
4434@media (max-width: 520px) {
4435 .install-modal-panel { padding: 1.2rem; }
4436 .install-app-btn { width: 100%; justify-content: center; }
4437}
4438
4439/* v9.3 — Install-modal: choice-blocks met voor/nadelen */
4440.install-choice {
4441 margin-top: 1.25rem;
4442 padding: 1rem;
4443 border: 1px solid color-mix(in srgb, currentColor 15%, transparent);
4444 border-radius: 10px;
4445 background: color-mix(in srgb, currentColor 3%, transparent);
4446}
4447.install-choice + .install-choice { margin-top: 1rem; }
4448.install-choice h4 {
4449 margin: 0 0 .75rem;
4450 font-size: 1rem;
4451 letter-spacing: 0;
4452 text-transform: none;
4453 opacity: 1;
4454}
4455.install-pros-cons {
4456 display: flex;
4457 gap: 1rem;
4458 margin: .5rem 0 1rem;
4459}
4460.install-pros,
4461.install-cons {
4462 flex: 1;
4463 min-width: 0;
4464 font-size: .85rem;
4465 line-height: 1.45;
4466}
4467.install-pros strong,
4468.install-cons strong {
4469 display: block;
4470 margin-bottom: .35rem;
4471 font-size: .82rem;
4472 letter-spacing: .02em;
4473}
4474.install-pros strong { color: #16a34a; }
4475.install-cons strong { color: #dc2626; }
4476.install-pros ul,
4477.install-cons ul {
4478 margin: 0;
4479 padding-left: 1.1rem;
4480 display: flex;
4481 flex-direction: column;
4482 gap: .25rem;
4483}
4484.install-pros li::marker { color: #16a34a; }
4485.install-cons li::marker { color: #dc2626; }
4486
4487.install-choice-cta {
4488 display: inline-flex;
4489 align-items: center;
4490 justify-content: center;
4491 gap: .35rem;
4492 margin-top: .5rem;
4493 padding: .7rem 1.1rem;
4494 background: var(--accent, #c2410c);
4495 color: #fff;
4496 border: none;
4497 border-radius: 8px;
4498 text-decoration: none;
4499 font: inherit;
4500 font-weight: 600;
4501 font-size: .95rem;
4502 cursor: pointer;
4503 transition: filter .12s ease;
4504}
4505.install-choice-cta:hover { filter: brightness(1.08); }
4506.install-choice-note {
4507 margin: .5rem 0 0;
4508 padding: .6rem .8rem;
4509 background: color-mix(in srgb, currentColor 4%, transparent);
4510 border-left: 3px solid var(--accent, #c2410c);
4511 border-radius: 4px;
4512 font-size: .9rem;
4513 line-height: 1.45;
4514}
4515
4516@media (max-width: 520px) {
4517 .install-pros-cons { flex-direction: column; gap: .75rem; }
4518}
4519
4520/* v9.4 — Soft fade-overgang tussen posts bij navigatie.
4521 Fade-out is rustig (450ms): oude content vervaagt geleidelijk terwijl
4522 de scroll-naar-top loopt. Fade-in is snel (180ms) met een lichte blur-
4523 onscherp → scherp animatie zodat de nieuwe content niet abrupt verschijnt. */
4524#pcms-main {
4525 transition: opacity .45s ease-out;
4526}
4527#pcms-main.is-pcms-transitioning-out {
4528 opacity: 0;
4529}
4530#pcms-main.is-pcms-transitioning-in {
4531 opacity: 0;
4532 filter: blur(6px);
4533 animation: pcmsFadeIn .18s ease-out forwards;
4534 will-change: opacity, filter;
4535}
4536@keyframes pcmsFadeIn {
4537 from { opacity: 0; filter: blur(6px); }
4538 to { opacity: 1; filter: blur(0); }
4539}
4540
4541/* Respecteer reduced-motion voorkeur (iOS/Android accessibility setting) */
4542@media (prefers-reduced-motion: reduce) {
4543 #pcms-main {
4544 transition: opacity .15s ease-out;
4545 }
4546 #pcms-main.is-pcms-transitioning-in {
4547 filter: none;
4548 animation: none;
4549 opacity: 1;
4550 }
4551}
4552
4553/* === Fediverse interactions — inherits the native .comment styling === */
4554.post-fediverse .fedi-stats { display: flex; gap: .45rem; margin: .35rem 0 1.5rem; align-items: center; }
4555.post-fediverse .fedi-stat {
4556 display: inline-flex; align-items: center; gap: .4rem;
4557 padding: .32rem .7rem; border-radius: 999px; font-size: .85rem; line-height: 1;
4558 font-variant-numeric: tabular-nums;
4559 color: var(--ink-muted); background: transparent;
4560 border: 1px solid var(--rule);
4561}
4562.post-fediverse .fedi-stat svg { width: 15px; height: 15px; }
4563.post-fediverse .fedi-stat-btn { cursor: pointer; font: inherit; line-height: 1; transition: color .15s, border-color .15s, background .15s; }
4564.post-fediverse .fedi-stat-btn:hover { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 55%, var(--rule)); background: var(--accent-tint); }
4565.post-fediverse .fedi-stat-btn:hover svg { fill: color-mix(in srgb, var(--accent) 22%, transparent); }
4566.post-fediverse .fedi-handle { color: var(--ink-soft, #888); font-size: .82rem; }
4567.post-fediverse .comment-content p { margin: .2rem 0; }
4568.post-fediverse .comment-content p:first-child { margin-top: 0; }
4569.post-fediverse .comment-content p:last-child { margin-bottom: 0; }
4570/* reply toggle: a plain "Reageer" action like the comment buttons (no triangle) */
4571.post-fediverse .fedi-reply-toggle { list-style: none; cursor: pointer; display: inline-block; }
4572.post-fediverse .fedi-reply-toggle::-webkit-details-marker { display: none; }
4573.post-fediverse details[open] .fedi-reply-toggle { margin-bottom: .5rem; }
4574
4575/* Reply-via-fediverse CTA on post pages */
4576.post-fediverse-cta { margin: 1.75rem 0; }
4577.fedi-remote-reply-btn { display: inline-flex; align-items: center; gap: .45rem; }
4578.post-fediverse-cta .fedi-remote-reply-btn {
4579 border: 1px solid color-mix(in srgb, var(--accent, #888) 55%, transparent);
4580 background: color-mix(in srgb, var(--accent, #888) 10%, transparent);
4581 color: var(--ink, inherit); border-radius: 999px; padding: .5rem 1.05rem;
4582 font-weight: 600; cursor: pointer; transition: background .15s ease;
4583}
4584.post-fediverse-cta .fedi-remote-reply-btn:hover { background: color-mix(in srgb, var(--accent, #888) 22%, transparent); }
4585.post-fediverse-cta .fedi-remote-reply-btn svg { color: var(--accent, currentColor); }
4586.post-fediverse .comment-actions .fedi-remote-reply-btn { gap: .3rem; }
4587
4588/* Inline "reply via fediverse" address form (replaces the browser prompt) */
4589.fedi-remote-form {
4590 position: absolute; z-index: 60; display: inline-flex; align-items: center; gap: .4rem;
4591 padding: .4rem; border-radius: 999px;
4592 background: var(--paper-2, var(--paper, #fff));
4593 border: 1px solid color-mix(in srgb, var(--ink, #000) 12%, transparent);
4594 box-shadow: 0 10px 30px rgba(0,0,0,.28);
4595}
4596.fedi-remote-form input {
4597 height: 2.2rem; padding: 0 .9rem; border-radius: 999px; font: inherit; min-width: 230px;
4598 border: 1px solid color-mix(in srgb, var(--ink, #000) 18%, transparent);
4599 background: color-mix(in srgb, var(--ink, #000) 4%, transparent); color: var(--ink, #000);
4600}
4601.fedi-remote-form input::placeholder { color: var(--ink-soft, #999); }
4602.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); }
4603.fedi-remote-form .fedi-remote-go {
4604 height: 2.2rem; min-width: 2.2rem; padding: 0 .85rem; border-radius: 999px;
4605 display: inline-flex; align-items: center; justify-content: center; font-size: 1rem;
4606}
4607.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; }
4608.fedi-remote-form .fedi-remote-cancel:hover { color: var(--ink, #000); }
4609
4610/* ── NSFW / sensitive content — blur + click to reveal ───────────────── */
4611.nsfw-media { position: relative; }
4612.nsfw-veil {
4613 position: absolute; inset: 0; z-index: 4; cursor: pointer; border-radius: inherit;
4614 display: flex; flex-direction: column; align-items: center; justify-content: center;
4615 gap: .5rem; padding: .75rem; text-align: center;
4616 background: color-mix(in srgb, var(--paper, #14141a) 50%, transparent);
4617 backdrop-filter: blur(22px) saturate(.6); -webkit-backdrop-filter: blur(22px) saturate(.6);
4618}
4619.nsfw-media.is-shown > .nsfw-veil { display: none; }
4620.nsfw-veil-label { font-weight: 700; font-size: .82rem; color: var(--ink, #f3f1ea); text-shadow: 0 1px 2px rgba(0,0,0,.5); }
4621.nsfw-veil-btn {
4622 font-size: .72rem; font-weight: 600; padding: .3rem .8rem; border-radius: 999px;
4623 border: 1px solid color-mix(in srgb, var(--ink, #fff) 55%, transparent);
4624 background: color-mix(in srgb, var(--paper, #000) 35%, transparent); color: var(--ink, #f3f1ea);
4625}
4626/* Post page: blur cover + body behind a content-warning banner until revealed */
4627.nsfw-gate .post-cover,
4628.nsfw-gate .post-content { filter: blur(26px); pointer-events: none; user-select: none; transition: filter .2s ease; }
4629.nsfw-gate.is-shown .post-cover,
4630.nsfw-gate.is-shown .post-content { filter: none; pointer-events: auto; user-select: auto; }
4631.nsfw-banner {
4632 display: flex; align-items: center; gap: .7rem; flex-wrap: wrap; margin: 0 0 1.5rem;
4633 padding: .8rem 1rem; border-radius: 12px;
4634 border: 1px solid color-mix(in srgb, var(--accent, #e8b04b) 45%, transparent);
4635 background: color-mix(in srgb, var(--accent, #e8b04b) 9%, transparent);
4636}
4637.nsfw-gate.is-shown .nsfw-banner { display: none; }
4638.nsfw-banner-icon { font-size: 1.2rem; }
4639.nsfw-banner-text { font-weight: 600; font-size: .92rem; color: var(--ink); }
4640.nsfw-banner-btn {
4641 margin-left: auto; cursor: pointer; font: inherit; font-size: .82rem; font-weight: 600;
4642 padding: .4rem 1rem; border-radius: 999px; border: 0;
4643 background: var(--accent, #e8b04b); color: #1a1205;
4644}
Note: See TracBrowser for help on using the repository browser.