source: Klonkt/src/assets/css/style.css@ 48481cd

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

Lezen: snappen dat je laat lezen, en geen lege schermen meer

Barts meldingen van 20 augustus, in een stuk of zes rondes bijgesteld. De
uitkomst is korter dan de weg ernaartoe, en die weg is het waard om vast te
leggen omdat ik er twee keer overheen ben geschoten.

SNAPPEN. De regel is nu in drie zinnen te zeggen:

omhoog scrollen nooit snappen -- je zoekt iets terug en bepaalt zelf

waar je stopt

omlaag, ver weg vrij scrollen
omlaag, laatste
150px van een
bericht vangt, en je landt op de bovenkant van het volgende

Er is geen top-zone: de bovenkant van het bericht waar je IN zit is geen
doelwit meer. Dat was de oorspronkelijke klacht -- je las een paar regels
verder en proximity trok je terug naar de bovenrand, waardoor het leek of
het scrollen vastliep. De grens die wel vangt is de onderkant van je huidige
bericht, en dat is hetzelfde punt als de bovenkant van het volgende.

Onderweg twee doodlopende wegen, allebei door Robin gecorrigeerd:

  • Eerst zette ik de snap UIT voor berichten langer dan het scherm. Op een telefoon is bijna elk bericht net iets langer dan de viewport, dus daar verdween het snappen overal: op 812px hoog kregen berichten van 1009 en zelfs 839 al geen snap meer.
  • Toen probeerde ik de vangzone aan de VOET van het bericht te hangen ("ben je de reacties voorbij"). Bij een kort bericht staat die voet middenin de lege ruimte die min-height maakte, dus de zone begon op een willekeurige plek. Gelukkig ving Robin dat voordat het uitgerold stond.

Het moest dus een getal in pixels zijn, en 150 is dat getal.

GEEN LEGE SCHERMEN MEER. min-height:100svh rekte elk bericht op tot een vol
scherm. Bij een kort bericht gaf dat een halve pagina leegte onder "Replies
and reactions" -- je keek naar niets en moest doorscrollen om te ontdekken
dat er nog iets kwam. Weg dus: berichten hebben hun eigen hoogte (gemeten:
360/1009/839/250 waar het eerst 888/888/888/888 was) en de stroom is gewoon
bericht na bericht. Het snappen hangt aan scroll-snap-align en niet aan die
hoogte, dus dat werkt onveranderd.

VLOEIEND: scroll-behavior:smooth, want zonder dat springt een snap er in een
frame naartoe en voelt het als een hik. Uit bij prefers-reduced-motion.

TERUG NAAR BOVEN, rechtsonder, in twee stappen: eerst naar het begin van DIT
bericht, daarna pas naar de kop van de pagina. Die knop is de enige die naar
een bovenkant mag springen, en hij heeft het snappen daar niet voor nodig --
scrollIntoView stuurt zelf. Nagemeten, juist omdat omhoog-snappen uit staat:
1706 -> 1206, exact de bovenkant.

COVERS nemen de volle kolombreedte met de verhouding intact. De ronde ervoor
haalde het opblazen eruit maar liet kleine afbeeldingen op ware grootte
staan, en dat was als postzegel in een brede kolom te klein.

DE CIRKEL. Lezen blijft daar dood (berichten van anderen), maar een tijdlijn
werkt er juist bij uitstek. Die dwong ik eerst af zodra de site geen
Lezen-site was, en dan kon je in de cirkel geen Grid meer kiezen. Nu is Grid
de landing en staat Tijdlijn ernaast: bij feed_alt_view=timeline altijd, bij
auto op desktop. De cirkel krijgt zijn eigen geheugen terug, met een eigen
sleutel zodat een keuze daar je thuisweergave niet aanraakt.

style.css naar v77 en MOD_V naar 13.

Suite 1165/1165.

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

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