/* ============================================================ LOKALE FONTS — SIL OFL 1.1 licensed, self-hosted Geen third-party requests, geen privacy-leak naar Google. Variable WOFF2 bestanden onder /assets/fonts/ Licenses in /assets/fonts/licenses/ ============================================================ */ @font-face { font-family: 'Fraunces'; font-style: normal; font-display: swap; font-weight: 100 900; src: url('/assets/fonts/fraunces-latin-full-normal.woff2') format('woff2-variations'); 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; } @font-face { font-family: 'Fraunces'; font-style: italic; font-display: swap; font-weight: 100 900; src: url('/assets/fonts/fraunces-latin-full-italic.woff2') format('woff2-variations'); 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; } @font-face { font-family: 'Literata'; font-style: normal; font-display: swap; font-weight: 400 700; src: url('/assets/fonts/literata-latin-opsz-normal.woff2') format('woff2-variations'); 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; } @font-face { font-family: 'Literata'; font-style: italic; font-display: swap; font-weight: 400 700; src: url('/assets/fonts/literata-latin-opsz-italic.woff2') format('woff2-variations'); 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; } @font-face { font-family: 'Plus Jakarta Sans'; font-style: normal; font-display: swap; font-weight: 400 700; src: url('/assets/fonts/plus-jakarta-sans-latin-wght-normal.woff2') format('woff2-variations'); 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; } @font-face { font-family: 'Plus Jakarta Sans'; font-style: italic; font-display: swap; font-weight: 400 700; src: url('/assets/fonts/plus-jakarta-sans-latin-wght-italic.woff2') format('woff2-variations'); 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; } /* PrutCMS publieke stijl — editorial-ish, geen emoji-UI */ :root { --font-display: 'Fraunces', Georgia, serif; --font-body: 'Literata', Georgia, serif; --font-ui: 'Plus Jakarta Sans', system-ui, sans-serif; --font-mono: ui-monospace, Menlo, Consolas, monospace; --radius: 8px; --transition: 180ms cubic-bezier(.4,0,.2,1); --safe-top: env(safe-area-inset-top, 0); --safe-bot: env(safe-area-inset-bottom, 0); color-scheme: light dark; } /* Native controls (datum/tijd-picker, scrollbars) het SITE-thema laten volgen i.p.v. de OS-voorkeur, en de datum/tijd-velden de site-accentkleur geven. Zo staat de ingebouwde kalender-popup in dark + accent (de popup zelf is een browser-widget, dus fonts/randen blijven van de browser). */ [data-theme="dark"] { color-scheme: dark; } [data-theme="light"] { color-scheme: light; } input[type="date"], input[type="time"], input[type="datetime-local"] { accent-color: var(--accent, #6b8f71); } input[type="date"]::-webkit-calendar-picker-indicator, input[type="time"]::-webkit-calendar-picker-indicator, input[type="datetime-local"]::-webkit-calendar-picker-indicator { cursor: pointer; opacity: .7; } input[type="date"]:hover::-webkit-calendar-picker-indicator, input[type="time"]:hover::-webkit-calendar-picker-indicator, input[type="datetime-local"]:hover::-webkit-calendar-picker-indicator { opacity: 1; } /* ============================================================ PALETTES — elk palette definieert alleen bg/tekst/rand shades. --accent wordt LOS ingesteld via de accent-kleur config (inline in template). Palette-selector: en optioneel data-theme="dark"|"light". Als geen data-palette = Sage default. ============================================================ */ /* ── SAGE (default) ── warme crème ── */ :root, [data-palette="sage"] { --paper: #faf8f3; --paper-2: #f2ede0; --ink: #1a1a1a; --ink-soft: #3d3833; --ink-muted: #6b6560; --ink-faint: #a8a29e; --rule: #e8e2d5; --rule-2: #d4ccb8; } @media (prefers-color-scheme: dark) { :root:not([data-theme="light"]):not([data-palette]), [data-palette="sage"]:not([data-theme="light"]) { --paper: #1c1a17; --paper-2: #252220; --ink: #f4ede0; --ink-soft: #d4ccb8; --ink-muted: #a8a29e; --ink-faint: #6b6560; --rule: #3d3833; --rule-2: #4d4740; } } [data-theme="dark"]:not([data-palette]), [data-theme="dark"][data-palette="sage"] { --paper: #1c1a17; --paper-2: #252220; --ink: #f4ede0; --ink-soft: #d4ccb8; --ink-muted: #a8a29e; --ink-faint: #6b6560; --rule: #3d3833; --rule-2: #4d4740; } /* ── PAPER ── minimalistisch wit → zwart ── */ [data-palette="paper"] { --paper: #ffffff; --paper-2: #f4f4f5; --ink: #09090b; --ink-soft: #27272a; --ink-muted: #52525b; --ink-faint: #a1a1aa; --rule: #e4e4e7; --rule-2: #d4d4d8; } @media (prefers-color-scheme: dark) { [data-palette="paper"]:not([data-theme="light"]) { --paper: #0a0a0a; --paper-2: #18181b; --ink: #fafafa; --ink-soft: #d4d4d8; --ink-muted: #a1a1aa; --ink-faint: #71717a; --rule: #27272a; --rule-2: #3f3f46; } } [data-theme="dark"][data-palette="paper"] { --paper: #0a0a0a; --paper-2: #18181b; --ink: #fafafa; --ink-soft: #d4d4d8; --ink-muted: #a1a1aa; --ink-faint: #71717a; --rule: #27272a; --rule-2: #3f3f46; } /* ── OCEAN ── koel blauw-grijs → diep navy ── */ [data-palette="ocean"] { --paper: #f0f6fb; --paper-2: #dce9f4; --ink: #0f1e2e; --ink-soft: #1e3a52; --ink-muted: #475569; --ink-faint: #94a3b8; --rule: #c7d9ea; --rule-2: #a8c0d6; } @media (prefers-color-scheme: dark) { [data-palette="ocean"]:not([data-theme="light"]) { --paper: #0a1929; --paper-2: #152a3f; --ink: #e0f2fe; --ink-soft: #bfdbfe; --ink-muted: #93c5fd; --ink-faint: #64748b; --rule: #1e3a52; --rule-2: #2a4a68; } } [data-theme="dark"][data-palette="ocean"] { --paper: #0a1929; --paper-2: #152a3f; --ink: #e0f2fe; --ink-soft: #bfdbfe; --ink-muted: #93c5fd; --ink-faint: #64748b; --rule: #1e3a52; --rule-2: #2a4a68; } /* ── FOREST ── olijfgroen → donker bos ── */ [data-palette="forest"] { --paper: #f2f6ed; --paper-2: #e1ead6; --ink: #1a2e15; --ink-soft: #2d4a26; --ink-muted: #5a6f52; --ink-faint: #8aa080; --rule: #ccddbd; --rule-2: #adc396; } @media (prefers-color-scheme: dark) { [data-palette="forest"]:not([data-theme="light"]) { --paper: #0d1f12; --paper-2: #1a331e; --ink: #dcf2d0; --ink-soft: #b8d8a8; --ink-muted: #8aad7c; --ink-faint: #5a7a50; --rule: #2d4a30; --rule-2: #3d5e42; } } [data-theme="dark"][data-palette="forest"] { --paper: #0d1f12; --paper-2: #1a331e; --ink: #dcf2d0; --ink-soft: #b8d8a8; --ink-muted: #8aad7c; --ink-faint: #5a7a50; --rule: #2d4a30; --rule-2: #3d5e42; } /* ── STONE ── beige bruin → koffie ── */ [data-palette="stone"] { --paper: #f5f0e8; --paper-2: #e7ddce; --ink: #2b2218; --ink-soft: #4a3a2a; --ink-muted: #78614a; --ink-faint: #a8927b; --rule: #d6c6ac; --rule-2: #bda98a; } @media (prefers-color-scheme: dark) { [data-palette="stone"]:not([data-theme="light"]) { --paper: #1a130b; --paper-2: #2d2416; --ink: #f5e9d5; --ink-soft: #d4c0a3; --ink-muted: #a8927b; --ink-faint: #786452; --rule: #3d2f1e; --rule-2: #534029; } } [data-theme="dark"][data-palette="stone"] { --paper: #1a130b; --paper-2: #2d2416; --ink: #f5e9d5; --ink-soft: #d4c0a3; --ink-muted: #a8927b; --ink-faint: #786452; --rule: #3d2f1e; --rule-2: #534029; } /* ── MIDNIGHT ── lavendel → donker paars ── */ [data-palette="midnight"] { --paper: #f3f1f8; --paper-2: #e3ddf0; --ink: #1e1a2e; --ink-soft: #332c4d; --ink-muted: #5e5478; --ink-faint: #9288a8; --rule: #d4cae3; --rule-2: #b8a9cc; } @media (prefers-color-scheme: dark) { [data-palette="midnight"]:not([data-theme="light"]) { --paper: #0f0a1f; --paper-2: #1c1432; --ink: #e9def7; --ink-soft: #c4b5d9; --ink-muted: #9d88b8; --ink-faint: #6b5a85; --rule: #2d1f4a; --rule-2: #3d2b5e; } } [data-theme="dark"][data-palette="midnight"] { --paper: #0f0a1f; --paper-2: #1c1432; --ink: #e9def7; --ink-soft: #c4b5d9; --ink-muted: #9d88b8; --ink-faint: #6b5a85; --rule: #2d1f4a; --rule-2: #3d2b5e; } /* ── SUNSET ── roze crème → diep paars-roze ── */ [data-palette="sunset"] { --paper: #fdf4f3; --paper-2: #f7e1dc; --ink: #2e1618; --ink-soft: #4d282b; --ink-muted: #7a4a4e; --ink-faint: #b08589; --rule: #ebcac3; --rule-2: #d9a8a0; } @media (prefers-color-scheme: dark) { [data-palette="sunset"]:not([data-theme="light"]) { --paper: #1f0a14; --paper-2: #321525; --ink: #fce7f3; --ink-soft: #f0c5d3; --ink-muted: #c896a8; --ink-faint: #8a6878; --rule: #4a1f35; --rule-2: #5e2d43; } } [data-theme="dark"][data-palette="sunset"] { --paper: #1f0a14; --paper-2: #321525; --ink: #fce7f3; --ink-soft: #f0c5d3; --ink-muted: #c896a8; --ink-faint: #8a6878; --rule: #4a1f35; --rule-2: #5e2d43; } /* ── CREAM ── warm papier → caramel-donker ── */ [data-palette="cream"] { --paper: #fefaf0; --paper-2: #f5ebd5; --ink: #2a1f0f; --ink-soft: #4a3820; --ink-muted: #786140; --ink-faint: #ad9068; --rule: #e8d9b0; --rule-2: #d1bc8a; } @media (prefers-color-scheme: dark) { [data-palette="cream"]:not([data-theme="light"]) { --paper: #1a1208; --paper-2: #2e2012; --ink: #fef3d6; --ink-soft: #e0cfa0; --ink-muted: #b0996b; --ink-faint: #7a6848; --rule: #3d2c16; --rule-2: #523d1f; } } [data-theme="dark"][data-palette="cream"] { --paper: #1a1208; --paper-2: #2e2012; --ink: #fef3d6; --ink-soft: #e0cfa0; --ink-muted: #b0996b; --ink-faint: #7a6848; --rule: #3d2c16; --rule-2: #523d1f; } /* Accent-tint wordt berekend uit --accent, zodat hij meegaat bij elke accent-keuze. Wordt in template inline gezet; hier alleen een fallback. */ :root { --accent: #c2410c; --accent-soft: #ea580c; --accent-tint: #fef2e8; } * { box-sizing: border-box; } html { -webkit-text-size-adjust: 100%; -webkit-tap-highlight-color: transparent; overscroll-behavior-y: none; /* Horizontaal clippen op ROOT-niveau: dit propageert naar de viewport (geen horizontale scroll) ZONDER position:fixed te breken — html is sowieso de document-scroller. De body mag GEEN overflow-x krijgen, want dan zou die een tweede scroll-container worden en zou de fixed bottom-tab meeschuiven. */ overflow-x: hidden; } body { margin: 0; } /* ── Thema-scrollbar: slank, afgerond, subtiel — vervangt de standaard chunky browser-scrollbar (met pijltjes) die niet bij het donkere thema past. Werkt op de pagina én op interne scrollers (queue, chat-thread, dropdowns). ── */ * { scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--ink) 28%, transparent) transparent; } ::-webkit-scrollbar { width: 10px; height: 10px; } ::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-thumb { background-color: color-mix(in srgb, var(--ink) 24%, transparent); border-radius: 999px; border: 2px solid transparent; /* transparante rand → optisch slanker (≈6px) */ background-clip: content-box; } ::-webkit-scrollbar-thumb:hover { background-color: color-mix(in srgb, var(--accent) 60%, var(--ink)); } ::-webkit-scrollbar-corner { background: transparent; } /* Login/auth = focus-scherm. Bij htmx-navigatie naar login blijft de bottom-tab uit de vorige pagina in de DOM staan → hier verbergen zodat het login-scherm net zo "kaal" is als bij een full-load (waar de tab niet eens gerenderd wordt). */ body.on-auth .bottom-tab { display: none; } body:not(.admin) { min-height: 100dvh; background: var(--paper); color: var(--ink); font-family: var(--font-body); font-size: 1.0625rem; line-height: 1.65; font-feature-settings: "liga" 1, "kern" 1, "onum" 1; -webkit-font-smoothing: antialiased; /* v9.4 — Sticky footer: body als flex-kolom, main groeit, footer onderaan */ display: flex; flex-direction: column; } body:not(.admin) #pcms-main { flex: 1 0 auto; } body:not(.admin) .site-footer { flex-shrink: 0; } body:not(.admin)::before { content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none; background: radial-gradient(ellipse at top, color-mix(in srgb, var(--accent) 3%, transparent), transparent 60%), radial-gradient(ellipse at bottom right, color-mix(in srgb, var(--accent) 4%, transparent), transparent 55%); } ::selection { background: var(--accent-tint); color: var(--accent); } h1, 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; } h1 { font-size: clamp(2rem, 4vw + 1rem, 3.5rem); letter-spacing: -0.022em; } h2 { font-size: clamp(1.5rem, 2vw + 1rem, 2.25rem); margin: 1.5rem 0 .4rem; } h3 { font-size: 1.375rem; margin: 1.25rem 0 .3rem; } p { margin: 0 0 .85em; text-wrap: pretty; hyphens: auto; } a { 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); } a:hover { color: var(--accent); text-decoration-color: var(--accent); } /* Knop-ankers houden hun eigen tekstkleur bij hover. Zonder dit overschrijft de globale a:hover{color:accent} de knop-tekst → die wordt dezelfde kleur als de accent-achtergrond en valt weg (vooral op sites met een felle accent). */ a.btn:hover, a.epk-btn:hover { color: var(--ink); } a.btn-primary:hover, a.btn-danger:hover, a.btn-success:hover, a.button:hover, a.epk-btn-primary:hover, a.dls-btn:hover, a.sh-tix:hover, a.dl-go:hover { color: #fff; text-decoration-color: currentColor; } a:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; text-decoration: none; } blockquote { 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); } code { font-family: var(--font-mono); font-size: .9em; padding: .15em .4em; background: var(--paper-2); border: 1px solid var(--rule); border-radius: 4px; } pre { 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; } pre code { padding: 0; background: none; border: none; } hr { border: 0; border-top: 1px solid var(--rule); margin: 3em auto; max-width: 4rem; } /* Container — schaalt mee met schermgrootte. 42rem default (optimale leesbreedte voor tekst), breder op HD/2.5K/4K waar je meer ademruimte hebt. Grid-view heeft z'n eigen bredere variant (zie .feed-grid). */ /* Container max-width schaalt per schermformaat. 42rem is optimale leesbreedte voor tekst. Op grotere schermen ademruimte geven zonder uitwaaieren. Grid apart geregeld. */ .container { max-width: 42rem; margin-inline: auto; padding-inline: clamp(1.25rem, 4vw, 2rem); } /* Laptop / Full HD — 1440px viewport of groter */ @media (min-width: 1440px) { .container { max-width: 56rem; } } /* Desktop / QHD 2.5K — 1920px viewport of groter */ @media (min-width: 1920px) { .container { max-width: 72rem; } } /* 4K UHD — 2560px viewport of groter */ @media (min-width: 2560px) { .container { max-width: 88rem; } } /* Grid-view tiles: Instagram-feel. Max-width schaalt met gekozen kolommen zodat tegels niet te groot of te klein worden. */ @media (min-width: 1200px) { body[data-grid-cols="4"] .feed-grid.container { max-width: 80rem; } body[data-grid-cols="3"] .feed-grid.container { max-width: 64rem; } body[data-grid-cols="2"] .feed-grid.container { max-width: 48rem; } } @media (min-width: 1920px) { body[data-grid-cols="4"] .feed-grid.container { max-width: 96rem; } } .icon { width: 1.125em; height: 1.125em; flex-shrink: 0; vertical-align: -0.15em; stroke: currentColor; fill: none; display: inline-block; } /* Masthead */ .masthead { border-bottom: 1px solid var(--rule); padding: calc(1rem + var(--safe-top)) 0 1rem; /* GEEN backdrop-filter hier: een voorouder met backdrop-filter blokkeert de frosted blur van het user-menu-dropdown eronder. Masthead is toch bijna dekkend, dus solide bg i.p.v. blur. */ background: color-mix(in srgb, var(--paper) 94%, transparent); position: sticky; top: 0; z-index: 20; } .masthead-inner { display: flex; align-items: center; justify-content: flex-end; gap: 1.5rem; } .masthead-brand { min-width: 0; flex: 1 1 auto; overflow: hidden; } .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; } .site-title:hover { color: var(--accent); } /* v9.0 — nav-home icon (replaces site-title text in nav) */ .nav-home { display: inline-flex; align-items: center; justify-content: center; width: 2.25rem; height: 2.25rem; color: var(--ink-soft); text-decoration: none; border-radius: 6px; border: 1px solid transparent; transition: all var(--transition); } .nav-home:hover { color: var(--ink); background: var(--paper-2); border-color: var(--rule); } .nav-home .icon { width: 1.15rem; height: 1.15rem; } .top-nav { display: flex; align-items: center; gap: .25rem; flex-shrink: 0; } .nav-link, .nav-btn { font-family: var(--font-ui); font-size: .875rem; font-weight: 500; color: var(--ink-soft); text-decoration: none; padding: .5rem .85rem; border-radius: 6px; background: transparent; border: 1px solid transparent; cursor: pointer; display: inline-flex; align-items: center; gap: .4rem; min-height: 2.25rem; transition: all var(--transition); } .nav-link:hover, .nav-btn:hover { color: var(--ink); background: var(--paper-2); border-color: var(--rule); } .nav-link-muted { color: var(--ink-muted); } .nav-label { display: none; } @media (min-width: 560px) { .nav-label { display: inline; } } /* Article */ main { padding-top: 2rem; } .page { padding-block: 2rem 3rem; } page-container { display: block; font-size: 1.125rem; line-height: 1.75; } page-container h1 { font-size: clamp(2rem, 5vw + 1rem, 3.75rem); margin-bottom: 1rem; letter-spacing: -0.025em; } page-container img, page-container iframe, page-container video { max-width: 100%; height: auto; display: block; margin: 2rem auto; border-radius: var(--radius); } page-container audio { width: 100%; margin: 1.5rem 0; } page-container figure { margin: 2rem 0; } page-container figcaption { font-family: var(--font-ui); font-size: .85rem; color: var(--ink-muted); text-align: center; margin-top: .5rem; } page-container[contenteditable="true"] { outline: 2px dashed var(--accent); outline-offset: .5rem; border-radius: var(--radius); } .empty { text-align: center; padding: 4rem 1rem; } .empty h1 { font-size: 2rem; } .empty p { color: var(--ink-muted); } /* Embeds */ .pcms-embed, .folio-embed { margin: 2rem 0; } .pcms-embed iframe, .folio-embed iframe { width: 100%; display: block; border: 0; border-radius: var(--radius); } /* Article footer */ .article-footer { display: flex; justify-content: center; padding-top: 2rem; margin-top: 2rem; border-top: 1px solid var(--rule); } /* Buttons */ .button { font-family: var(--font-ui); font-size: .875rem; font-weight: 500; padding: .6rem 1.1rem; min-height: 2.5rem; display: inline-flex; align-items: center; gap: .5rem; background: var(--ink); color: var(--paper); border: 1px solid var(--ink); border-radius: 6px; text-decoration: none; cursor: pointer; transition: all var(--transition); } .button:hover { background: var(--accent); border-color: var(--accent); color: #fff; } .button-ghost { background: transparent; color: var(--ink); border-color: var(--rule-2); } .button-ghost:hover { background: var(--paper-2); border-color: var(--accent); color: var(--accent); } /* Pagination */ .pagination { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; padding-block: 2rem 4rem; margin-top: 2rem; border-top: 1px solid var(--rule); } a.pagination-item { display: flex; align-items: center; gap: 1rem; padding: 1rem 1.25rem; border: 2px solid var(--rule-2, var(--rule)); border-radius: var(--radius); text-decoration: none; transition: all .15s ease; font-size: .9rem; background: var(--paper-2); min-height: 5rem; min-width: 0; overflow: hidden; cursor: pointer; box-shadow: 0 1px 0 rgba(0,0,0,.02); -webkit-tap-highlight-color: color-mix(in srgb, var(--accent) 30%, transparent); position: relative; } .pagination-item:not(a) { display: flex; align-items: center; gap: 1rem; padding: 1rem 1.25rem; border: 1px dashed var(--rule); border-radius: var(--radius); font-size: .9rem; background: transparent; min-height: 5rem; min-width: 0; overflow: hidden; } .pagination-next { flex-direction: row-reverse; text-align: right; } a.pagination-item:hover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 5%, var(--paper-2)); transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,.08); } a.pagination-item:active { transform: translateY(0); transition-duration: .05s; } .pagination-disabled { opacity: .5; cursor: default; font-style: italic; } .pagination-body { display: flex; flex-direction: column; gap: .15rem; min-width: 0; flex: 1; } .pagination-label { display: block; font-family: var(--font-ui); font-size: .7rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--accent); margin-bottom: .15rem; } .pagination-slug { display: block; font-size: .72rem; color: var(--ink-muted); opacity: .75; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-style: italic; } .pagination-title { display: block; font-family: var(--font-display); font-weight: 600; color: var(--ink); font-variation-settings: "opsz" 72; font-style: normal; line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 1.05rem; text-decoration: underline; text-decoration-color: var(--rule-2, var(--rule)); text-decoration-thickness: 1px; text-underline-offset: 3px; transition: text-decoration-color .15s; } a.pagination-item:hover .pagination-title { text-decoration-color: var(--accent); } .pagination .icon { width: 1.75em; height: 1.75em; flex-shrink: 0; color: var(--accent); transition: transform .15s; } a.pagination-prev:hover .icon { transform: translateX(-4px); } a.pagination-next:hover .icon { transform: translateX(4px); } /* Pinned-targets → accent-tint en dikkere rand voor duidelijkheid */ .pagination-item.is-pinned { background: color-mix(in srgb, var(--accent) 8%, var(--paper-2)); border-color: color-mix(in srgb, var(--accent) 45%, var(--rule)); } a.pagination-item.is-pinned:hover { background: color-mix(in srgb, var(--accent) 15%, var(--paper-2)); border-color: var(--accent); } @media (max-width: 800px) { .pagination { grid-template-columns: 1fr; } } /* Footer */ .site-footer { padding: 2rem 0 calc(2rem + var(--safe-bot)); border-top: 1px solid var(--rule); margin-top: 4rem; font-family: var(--font-ui); font-size: .85rem; color: var(--ink-muted); } .site-footer-inner { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 1rem; align-items: center; } .site-footer a { color: var(--ink-muted); text-decoration-color: var(--rule); } .site-footer a:hover { color: var(--accent); } .site-footer-links { display: flex; gap: 1rem; } .sep { color: var(--ink-faint); margin: 0 .5rem; } .footer-tagline { font-style: italic; opacity: .8; } @media print { .masthead, .pagination, .site-footer, .article-footer, .top-nav { display: none; } body { background: #fff; color: #000; } } @media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition: none !important; animation: none !important; } } /* ============================================================ V7 ADDITIONS — post metadata UI + audio player + post-images ============================================================ */ /* Post header */ .post-header { margin: 0 0 2rem; } .post-cover { margin: 0 0 1.5rem; border-radius: 8px; overflow: hidden; background: color-mix(in srgb, var(--fg) 4%, transparent); } .post-cover img { display: block; width: 100%; height: auto; max-height: 50vh; object-fit: cover; } .post-title { font-size: clamp(1.6rem, 4vw, 2.6rem); line-height: 1.15; margin: 0 0 .5rem; letter-spacing: -.02em; } /* Pin banner — duidelijk zichtbaar dat een post gepind is */ .post-pin-banner { display: inline-flex; align-items: center; gap: .5rem; background: color-mix(in srgb, var(--accent) 14%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent); color: var(--accent); padding: .4rem .8rem; border-radius: 999px; font-size: .75rem; font-weight: 600; text-transform: uppercase; letter-spacing: .08em; margin: 0 0 .85rem; line-height: 1; } .post-pin-banner-icon { font-size: 1rem; line-height: 1; } .post-pin-banner-sep { opacity: .5; } .post-pin-banner-pos { opacity: .85; } .post-date { color: var(--fg-muted, #888); font-size: .85rem; letter-spacing: .05em; text-transform: uppercase; margin: 0 0 1.5rem; } /* Post-images in content (resize + align) */ .post-image { margin: 1.5rem 0; } .post-image img { display: block; height: auto; border-radius: 6px; max-width: 100%; } .post-image figcaption { font-size: .85rem; color: var(--fg-muted, #888); margin-top: .5rem; font-style: italic; text-align: center; } .post-image--small img { max-width: 240px; } .post-image--medium img { max-width: 440px; } .post-image--large img { max-width: 720px; } .post-image--full img { width: 100%; max-width: 100%; } .post-image--left { text-align: left; } .post-image--left img { margin-left: 0; margin-right: auto; } .post-image--center { text-align: center; } .post-image--center img { margin-left: auto; margin-right: auto; } .post-image--right { text-align: right; } .post-image--right img { margin-left: auto; margin-right: 0; } /* Afbeeldingen in de post-tekst vullen ALTIJD de containerbreedte en houden hun natuurlijke (niet-bijgesneden) hoogte — geen vaste hoogte / geen crop. */ .post-content img { display: block; width: 100%; max-width: 100%; height: auto; border-radius: 6px; margin: 1.4em auto; } /* Mini-player + bottom-tab clearance: applied to .pcms-main so the footer is NOT pushed below the viewport bottom. The bars are position:fixed so they overlap whatever they sit on top of; the padding ensures the last content row isn't covered. Footer naturally follows main and now sits exactly at viewport-bottom on short pages (sticky footer flex). */ .pcms-main { padding-bottom: 5.5rem; } body.has-audio-player .pcms-main { padding-bottom: 5.5rem; } /* Mobiel toetsenbord open (body.kb-open, gezet via visualViewport in shell.ejs): verberg de vaste onderbalken — anders zweven de bottom-tab + mini-speler boven het toetsenbord of overlappen ze het invoerveld. Ze komen terug zodra het toetsenbord sluit. De extra clearance onderaan is dan ook niet meer nodig. */ body.kb-open .bottom-tab, body.kb-open .audio-player { display: none !important; } body.kb-open .pcms-main { padding-bottom: 1rem; } /* Mobiel & tablet (touch): scrollbalken verbergen — scrollen blijft werken, alleen de balk-UI is weg (geen verwarrende/dubbele balken). */ @media (pointer: coarse) { * { scrollbar-width: none; -ms-overflow-style: none; } *::-webkit-scrollbar { width: 0; height: 0; display: none; } } /* Afbeeldingen lastiger op te slaan (frictie, geen echte beveiliging): geen sleep-naar-bureaublad, geen iOS long-press-bewaarmenu. Rechtsklik wordt in JS geblokkeerd (zie shell.ejs). Covers/hero zijn al CSS-achtergronden = niet via "afbeelding opslaan" te pakken. */ img { -webkit-user-drag: none; -khtml-user-drag: none; -moz-user-drag: none; user-drag: none; -webkit-touch-callout: none; } /* ============================================================ AUDIO PLAYER v7.1 — SVG iconen, thema-aware, geen emoji ============================================================ */ .audio-player { position: fixed; left: 0; right: 0; bottom: 0; background: color-mix(in srgb, var(--paper, #fff) 96%, var(--ink, #000)); border-top: 1px solid var(--rule, rgba(0,0,0,.1)); color: var(--ink, #222); z-index: 1000; backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); box-shadow: 0 -4px 20px rgba(0,0,0,.04); } [data-theme="dark"] .audio-player { background: color-mix(in srgb, var(--paper, #1a1a1a) 92%, #fff); box-shadow: 0 -4px 20px rgba(0,0,0,.3); } .audio-player-inner { display: grid; grid-template-columns: minmax(0, 1.6fr) auto minmax(180px, 2fr) auto; gap: 1rem; align-items: center; padding: .65rem 1.25rem; max-width: 1400px; margin: 0 auto; } /* v9.0 — Clickable trigger dat cover + meta combineert zodat klikken erop sheet opent */ .audio-player-expand-trigger { display: flex; align-items: center; gap: .65rem; min-width: 0; background: none; border: none; padding: 0; margin: 0; cursor: pointer; color: inherit; text-align: left; font: inherit; border-radius: 6px; transition: background .15s; } .audio-player-expand-trigger:hover { background: color-mix(in srgb, var(--ink, #000) 6%, transparent); } /* Cover art */ .audio-player-cover { width: 48px; height: 48px; border-radius: 4px; background: linear-gradient(135deg, var(--accent, #c2410c), color-mix(in srgb, var(--accent, #c2410c) 55%, #000)); background-size: cover; background-position: center; flex-shrink: 0; position: relative; } .audio-player-cover.has-image { background-blend-mode: normal; } /* Meta — titel + artiest */ .audio-player-meta { min-width: 0; display: flex; flex-direction: column; gap: 2px; } .audio-player-title-wrap { overflow: hidden; white-space: nowrap; position: relative; } .audio-player-title { display: inline-block; font-family: var(--font-ui, inherit); font-weight: 600; font-size: .9rem; line-height: 1.3; letter-spacing: -.01em; color: var(--ink, inherit); white-space: nowrap; } .audio-player-title.is-overflowing { animation: audio-title-marquee 6s ease-in-out infinite alternate; } @keyframes audio-title-marquee { 0%, 8% { transform: translateX(0); } 92%, 100% { transform: translateX(calc(-1 * var(--audio-shift, 0px))); } } .audio-player-artist { font-family: var(--font-ui, inherit); font-size: .74rem; line-height: 1.3; color: var(--ink-muted, rgba(0,0,0,.55)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* Controls — prev / play / next */ .audio-player-controls { display: flex; gap: .1rem; align-items: center; } .audio-btn { background: transparent; border: none; color: inherit; cursor: pointer; padding: .5rem; border-radius: 50%; transition: background .15s, color .15s, transform .08s; display: inline-flex; align-items: center; justify-content: center; position: relative; } .audio-btn svg { width: 18px; height: 18px; display: block; } .audio-btn:hover { background: color-mix(in srgb, var(--ink, #000) 8%, transparent); } .audio-btn:active { transform: scale(.94); } .audio-btn-play { background: var(--accent, #c2410c); color: #fff; width: 38px; height: 38px; padding: 0; } .audio-btn-play:hover { background: color-mix(in srgb, var(--accent, #c2410c) 85%, #fff); } [data-theme="dark"] .audio-btn-play:hover { background: color-mix(in srgb, var(--accent, #c2410c) 85%, #000); } .audio-btn-play svg { width: 16px; height: 16px; } .audio-btn-play .icon-pause { display: none; } .audio-player.is-playing .audio-btn-play .icon-play { display: none; } .audio-player.is-playing .audio-btn-play .icon-pause { display: block; } /* Progress bar */ .audio-player-progress { display: flex; gap: .75rem; align-items: center; min-width: 0; } .audio-time { font-size: .7rem; color: var(--ink-muted, rgba(0,0,0,.55)); font-variant-numeric: tabular-nums; min-width: 2.7em; text-align: center; } .audio-seek { flex: 1; min-width: 0; cursor: pointer; padding: .5rem 0; position: relative; } .audio-seek-bar { height: 3px; background: color-mix(in srgb, var(--ink, #000) 12%, transparent); border-radius: 2px; overflow: hidden; transition: height .15s; } .audio-seek:hover .audio-seek-bar { height: 5px; } .audio-seek-fill { height: 100%; background: var(--accent, #c2410c); width: 0%; transition: width .1s linear; } /* Volume — popup on hover */ .audio-player-volume { position: relative; display: flex; align-items: center; } .audio-btn .icon-mute { display: none; } .audio-player.is-muted .audio-btn .icon-vol { display: none; } .audio-player.is-muted .audio-btn .icon-mute { display: block; } .audio-volume-popup { position: absolute; bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%) scale(.95); transform-origin: bottom center; background: var(--paper, #fff); border: 1px solid var(--rule, rgba(0,0,0,.1)); border-radius: 8px; padding: .75rem .5rem; box-shadow: 0 4px 16px rgba(0,0,0,.15); opacity: 0; pointer-events: none; transition: opacity .15s, transform .15s, visibility .15s; height: 110px; visibility: hidden; } /* Invisible bridge tussen knop en popup zodat hover niet breekt */ .audio-volume-popup::after { content: ''; position: absolute; bottom: -12px; left: -10px; right: -10px; height: 16px; } [data-theme="dark"] .audio-volume-popup { background: color-mix(in srgb, var(--paper, #111) 92%, #fff); } .audio-player-volume:hover .audio-volume-popup, .audio-player-volume:focus-within .audio-volume-popup, .audio-player-volume.is-open .audio-volume-popup { opacity: 1; visibility: visible; transform: translateX(-50%) scale(1); pointer-events: auto; } .audio-volume-popup input[type=range] { /* Standard vertical slider — replaces deprecated -webkit-appearance: slider-vertical. */ writing-mode: vertical-lr; direction: rtl; width: 6px; height: 90px; accent-color: var(--accent, #c2410c); /* Grotere hit-area via pseudo-touch padding */ padding: 0 12px; box-sizing: content-box; cursor: pointer; } /* Mobile */ @media (max-width: 720px) { .audio-player-inner { /* v9.0 — 3 cols: expand-trigger (cover+meta) | controls | volume */ grid-template-columns: minmax(0, 1fr) auto auto; gap: .5rem; padding: .5rem .8rem; } .audio-player-progress { display: none; } .audio-player-cover { width: 40px; height: 40px; } .audio-btn-play { width: 34px; height: 34px; } body.has-audio-player .pcms-main { padding-bottom: 4.2rem; } /* Verberg titel-artiest op bijzonder smal, verstop volume op mobile */ .audio-player-volume { display: none; } } /* Ultra-small schermen (iPhone 4 = 320px; iPhone SE 1st gen = 320px; iPhone mini ~360px). v9.3 — alles vanaf 320px moet werken; daaronder accepteren we wel/niet. */ @media (max-width: 380px) { .audio-player-inner { gap: .35rem; padding: .4rem .6rem; } .audio-player-expand-trigger { gap: .45rem; } .audio-player-cover { width: 36px; height: 36px; } .audio-player-title { font-size: .88rem; } .audio-player-artist { font-size: .72rem; } .audio-player-controls { gap: .15rem; } .audio-btn { width: 30px; height: 30px; } .audio-btn svg { width: 16px; height: 16px; } .audio-btn-play { width: 32px; height: 32px; } .audio-btn-play svg { width: 18px; height: 18px; } /* v9.3 — Tracklist compact op smalle telefoons. Leader 28×28, kleinere gap, padding strakker. Tijd in monoscript blijft leesbaar; titel krijgt 5-10px meer ruimte. */ .pat-row { grid-template-columns: 28px 1fr auto; gap: .5rem; padding: .45rem .65rem; } .pat-row .pat-num, .pat-row .pat-cover { width: 28px; height: 28px; } .pat-row::before { left: .65rem; width: 28px; height: 28px; -webkit-mask-size: 22px 22px; mask-size: 22px 22px; } .pat-row .pat-title { font-size: .92rem; } .pat-row .pat-artist { font-size: .74rem; } .pat-row .pat-duration { font-size: .74rem; } /* v9.3 — Album binnen post: cover + tracks compacter */ .post-album-cover { width: 90px; height: 90px; } .post-album-header { gap: .65rem; padding: .65rem; } .post-album-title { font-size: 1rem; } /* v9.3 — Profile-header bovenin compacter */ .profile-photo { width: 48px !important; height: 48px !important; } .profile-content { gap: .65rem; } /* v9.3 — Install-app modal: minder padding, kleinere knoppen */ .install-modal-inner { padding: 1rem; } .install-app-btn { padding: .55rem 1rem; font-size: .9rem; } /* v9.3 — horizontaal clippen gebeurt nu globaal op html (zie de html-regel bovenaan). Hier bewust NIETS op body zetten: body als scroll-container zou de fixed bottom-tab op mobiel laten meeschuiven. */ } /* iPhone 4 / iPhone SE 1st gen / iPhone 5/5s (320px) — strakste niveau */ @media (max-width: 340px) { .audio-player-inner { padding: .35rem .5rem; } .audio-player-artist { display: none; } .audio-player-cover { width: 32px; height: 32px; } body.has-audio-player .pcms-main { padding-bottom: 3.6rem; } /* Expand-sheet wat strakker */ .audio-sheet-panel { padding: .5rem 1rem 1.5rem; } .audio-sheet-title { font-size: 1.2rem; } .audio-sheet-artist { font-size: .9rem; } .audio-sheet-play { width: 60px; height: 60px; } .audio-sheet-play svg { width: 26px; height: 26px; } .audio-sheet-btn { width: 42px; height: 42px; } .audio-sheet-btn svg { width: 24px; height: 24px; } .audio-sheet-controls { gap: 1rem; } /* v9.3 — Op iPhone 4 (320px): tracklist nog strakker */ .pat-row { grid-template-columns: 26px 1fr auto; gap: .4rem; padding: .4rem .55rem; } .pat-row .pat-num, .pat-row .pat-cover { width: 26px; height: 26px; } .pat-row::before { left: .55rem; width: 26px; height: 26px; -webkit-mask-size: 20px 20px; mask-size: 20px 20px; } .pat-row .pat-artist { display: none; /* op extreem smal weglaten ten gunste van titel */ } .pat-row .pat-title { font-size: .9rem; } .pat-row .pat-duration { font-size: .72rem; } /* Container padding reduceren voor max content-breedte */ .container { padding-inline: 1rem !important; } /* Post-cover (de grote bovenste) krimpen */ .post-cover { max-height: 200px; } } /* ============================================================ v9.0 — Audio player expand-sheet (Spotify-style "now playing") Slide-up half-screen met grote cover, track info, big controls ============================================================ */ .audio-sheet { position: fixed; inset: 0; z-index: 1100; pointer-events: none; opacity: 0; transition: opacity .25s ease; } .audio-sheet.is-open { pointer-events: auto; opacity: 1; } .audio-sheet-backdrop { position: absolute; inset: 0; /* v9.3 — Blur en overlay-dim allebei via CSS-variabele --pcms-sheet-progress (1 = volledig, 0 = weg). JS update tijdens drag; CSS-transition pakt open/close af. Sterke blur (24px) zodat 't effect goed zichtbaar is. */ background: rgb(0 0 0 / calc(.4 * var(--pcms-sheet-progress, 1))); backdrop-filter: blur(calc(24px * var(--pcms-sheet-progress, 1))); -webkit-backdrop-filter: blur(calc(24px * var(--pcms-sheet-progress, 1))); transition: background .25s ease, backdrop-filter .25s ease, -webkit-backdrop-filter .25s ease; will-change: backdrop-filter, background; } /* Tijdens drag: instant updates vanuit JS, geen transition */ .audio-sheet-panel.is-dragging ~ .audio-sheet-backdrop, .audio-sheet-backdrop.is-dragging { transition: none; } .audio-sheet-panel { position: absolute; left: 0; right: 0; bottom: 0; background: var(--paper, #fff); border-top-left-radius: 20px; border-top-right-radius: 20px; box-shadow: 0 -20px 60px rgba(0, 0, 0, .25); padding: .75rem 1.5rem 2rem; max-height: 85vh; overflow-y: auto; /* v9.2.1 — scroll blijft binnen panel, geen chaining naar body (iOS-proof) */ overscroll-behavior: contain; touch-action: pan-y; /* Hide scrollbar but keep scrollable */ scrollbar-width: none; /* Firefox */ -ms-overflow-style: none; /* IE/Edge */ transform: translateY(100%); transition: transform .3s cubic-bezier(.22, .9, .3, 1), opacity .3s cubic-bezier(.22, .9, .3, 1); display: flex; flex-direction: column; gap: 1rem; color: var(--ink); } .audio-sheet-panel::-webkit-scrollbar { display: none; /* Chrome/Safari */ } /* Body scroll lock wanneer sheet open is */ body.audio-sheet-locked { overflow: hidden; } .audio-sheet.is-open .audio-sheet-panel { transform: translateY(0); } /* v9.3 — Drag-zone: pill bovenaan + cover. Hele strook is touch-target voor swipe-down-to-close. Pull-to-refresh is uitgeschakeld op html-niveau dus geen interferentie. Onder de cover (info/progress/controls/queue) werkt normale touch — knoppen, scroll in queue, etc. */ .audio-sheet-drag-zone { flex-shrink: 0; display: flex; flex-direction: column; align-items: stretch; gap: 1rem; /* v9.3 — touch-action: pan-y staat verticale scroll toe (zodat queue eronder scrollt als gebruiker omhoog veegt over cover). Onze JS detecteert intent: alleen omlaag-swipe vanaf de top sluit de sheet, omhoog-swipe = scroll. */ touch-action: pan-y; user-select: none; -webkit-user-select: none; cursor: grab; margin: -.75rem -1.5rem 0; padding: .75rem 1.5rem 0; } .audio-sheet-drag-zone:active { cursor: grabbing; } /* v9.4 — Drag alleen actief op touch-only apparaten (telefoons). Desktop met muis + tablets met muis-cursor → geen drag-grip, gebruiker sluit via × pill-knop bovenin of klik op backdrop. */ @media (hover: hover) and (pointer: fine) { .audio-sheet-drag-zone { touch-action: auto; cursor: default; pointer-events: none; } /* Pill blijft klikbaar als sluit-knop */ .audio-sheet-drag-zone .audio-sheet-handle { pointer-events: auto; cursor: pointer; } } /* Pill (handle) gecentreerd boven de cover */ .audio-sheet-drag-zone .audio-sheet-handle { margin: 0 auto .25rem; } /* Tijdens dragging: panel volgt vinger realtime; geen transition */ .audio-sheet-panel.is-dragging { transition: none; will-change: transform; } [data-theme="dark"] .audio-sheet-panel { background: var(--paper, #1a1a1a); box-shadow: 0 -20px 60px rgba(0, 0, 0, .5); } /* Drag-handle + close button in één */ .audio-sheet-handle { display: block; width: 48px; height: 4px; border-radius: 2px; background: color-mix(in srgb, var(--ink, #000) 25%, transparent); border: none; margin: 0 auto .5rem; padding: 0; cursor: pointer; flex-shrink: 0; position: relative; } .audio-sheet-handle::before { content: ""; position: absolute; /* v9.3 — Drag-strip wrapper neemt nu de hit-area-rol over. ::before blijft als kleine extra padding voor click-comfort. */ inset: -10px -20px; } .audio-sheet-handle:hover { background: color-mix(in srgb, var(--ink, #000) 45%, transparent); } /* Grote cover */ .audio-sheet-cover { width: 100%; max-width: 360px; aspect-ratio: 1/1; margin: 0 auto; border-radius: 12px; background: linear-gradient(135deg, var(--accent, #c2410c), color-mix(in srgb, var(--accent, #c2410c) 55%, #000)); background-size: cover; background-position: center; box-shadow: 0 20px 40px rgba(0, 0, 0, .15); flex-shrink: 0; } [data-theme="dark"] .audio-sheet-cover { box-shadow: 0 20px 40px rgba(0, 0, 0, .4); } .audio-sheet-info { text-align: center; padding: 0 1rem; } .audio-sheet-title { font-family: var(--font-display, inherit); font-size: 1.5rem; font-weight: 600; line-height: 1.2; margin: 0 0 .25rem; letter-spacing: -0.01em; color: var(--ink); } .audio-sheet-artist { font-size: 1rem; color: var(--ink-muted, var(--ink)); opacity: .7; } .audio-sheet-album { margin-top: .35rem; font-size: .82rem; opacity: .5; text-transform: uppercase; letter-spacing: .05em; } .audio-sheet-album:empty { display: none; } /* Progress + time */ .audio-sheet-progress { display: grid; grid-template-columns: auto 1fr auto; gap: .6rem; align-items: center; padding: 0 .5rem; } .audio-sheet-progress .audio-seek { width: 100%; } .audio-sheet-progress .audio-time { font-size: .78rem; opacity: .55; } /* Grote controls */ .audio-sheet-controls { display: flex; align-items: center; justify-content: center; gap: 1.75rem; } .audio-sheet-btn { width: 48px; height: 48px; padding: 0; } .audio-sheet-btn svg { width: 28px; height: 28px; } .audio-sheet-play { width: 72px; height: 72px; border-radius: 50%; background: var(--accent, #c2410c); color: var(--paper, #fff); border: none; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; transition: transform .1s; } .audio-sheet-play:hover { transform: scale(1.05); } .audio-sheet-play:active { transform: scale(.95); } .audio-sheet-play svg { width: 30px; height: 30px; } .audio-sheet-play .icon-pause { display: none; } /* v9.2.1 — sheet staat nu als sibling van .audio-player buiten de balk, dus ancestor-selector .audio-player.is-playing werkt niet meer voor de sheet. JS zet is-playing ook rechtstreeks op sheet.play (regel 551 app.js). */ .audio-sheet-play.is-playing .icon-play { display: none; } .audio-sheet-play.is-playing .icon-pause { display: block; } /* v9.2.1 — fallback: als sheet buiten alle ancestors zit, tag body */ body.audio-is-playing .audio-sheet-play .icon-play { display: none; } body.audio-is-playing .audio-sheet-play .icon-pause { display: block; } /* v9.3 — Loading state: roterende spiraal (het roboburr logo). Button-achtergrond wordt transparant, play/pause svgs verbergen, en de spiraal verschijnt als roterende background via ::after pseudo-element. Cool-effect: zachte hue-drift geeft de kleur een levend gevoel. */ .audio-player.is-loading .audio-btn-play, .audio-player.is-loading .audio-sheet-play, body.audio-is-loading .audio-sheet-play, .pat-row.is-loading { pointer-events: none; } .audio-player.is-loading .audio-btn-play, .audio-player.is-loading .audio-sheet-play, body.audio-is-loading .audio-sheet-play { background: transparent; box-shadow: none; } /* v9.3 — Play/pause-icons in de player-knoppen faden smooth uit/in tijdens loading. Pseudo-spiraal faded tegelijkertijd in (geen instant pop). */ .audio-btn-play > svg, .audio-sheet-play > svg { transition: opacity .35s cubic-bezier(.4, 0, .2, 1), transform .35s cubic-bezier(.4, 0, .2, 1); } .audio-player.is-loading .audio-btn-play > svg, .audio-player.is-loading .audio-sheet-play > svg, body.audio-is-loading .audio-sheet-play > svg { opacity: 0; transform: scale(.7); } .pat-row.is-loading .pat-play-icon > svg, .pat-row.is-loading .pat-num, .pat-row.is-loading .pat-cover { opacity: 0; } /* v9.3 — Spiraal als pseudo-element, ALTIJD aanwezig met opacity 0 default. Bij is-loading faden 'ie smooth in (opacity + scale-bounce), bij klaar faden 'ie weer uit. Pure accent-kleur, geen hue-drift. */ .audio-player .audio-btn-play, .audio-player .audio-sheet-play, .pat-row .pat-play-icon { position: relative; } .audio-btn-play::after, .audio-sheet-play::after { content: ""; position: absolute; inset: 0; background-color: var(--accent, #c2410c); -webkit-mask: url('/assets/spinner.svg') center/contain no-repeat; mask: url('/assets/spinner.svg') center/contain no-repeat; opacity: 0; transform: scale(.6); transition: opacity .4s cubic-bezier(.4, 0, .2, 1), transform .4s cubic-bezier(.34, 1.56, .64, 1); pointer-events: none; animation: pcms-spiral-spin 1.2s linear infinite paused; will-change: opacity, transform; } .audio-player.is-loading .audio-btn-play::after, .audio-player.is-loading .audio-sheet-play::after, body.audio-is-loading .audio-sheet-play::after { opacity: 1; transform: scale(1); animation-play-state: running; } /* Pat-row keeps its existing ::before spinner from earlier change. Voor backward-compat als oude HTML nog .pat-play-icon::after spinner had */ .pat-row.is-loading .pat-play-icon::after { content: ""; position: absolute; inset: 0; background-color: var(--accent, #c2410c); -webkit-mask: url('/assets/spinner.svg') center/contain no-repeat; mask: url('/assets/spinner.svg') center/contain no-repeat; opacity: 1; animation: pcms-spiral-spin 1.2s linear infinite; pointer-events: none; } @keyframes pcms-spiral-spin { to { transform: scale(1) rotate(-360deg); } } /* Queue list */ .audio-sheet-queue { margin-top: .5rem; padding-top: 1rem; border-top: 1px solid var(--rule); } .audio-sheet-queue-label { font-size: .75rem; text-transform: uppercase; letter-spacing: .08em; opacity: .5; font-weight: 600; margin-bottom: .5rem; padding: 0 .5rem; } .audio-sheet-queue-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 2px; } .audio-sheet-queue-item { display: flex; align-items: center; gap: .75rem; padding: .5rem .6rem; border-radius: 6px; cursor: pointer; transition: background .15s; background: none; border: none; width: 100%; color: inherit; font: inherit; text-align: left; } .audio-sheet-queue-item:hover { background: color-mix(in srgb, var(--ink, #000) 6%, transparent); } .audio-sheet-queue-item.is-current { background: color-mix(in srgb, var(--accent, #c2410c) 14%, transparent); color: var(--accent, #c2410c); } .audio-sheet-queue-cover { width: 36px; height: 36px; border-radius: 4px; background-size: cover; background-position: center; background-color: var(--rule); flex-shrink: 0; } .audio-sheet-queue-meta { flex: 1; min-width: 0; display: flex; flex-direction: column; } .audio-sheet-queue-title { font-size: .9rem; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .audio-sheet-queue-artist { font-size: .75rem; opacity: .55; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .audio-sheet-queue-duration { font-family: ui-monospace, monospace; font-size: .72rem; opacity: .5; flex-shrink: 0; } /* Desktop: sheet is max 480px wide and centered for bigger screens */ @media (min-width: 720px) { .audio-sheet-panel { left: 50%; right: auto; width: 480px; transform: translate(-50%, 100%); border-top-left-radius: 20px; border-top-right-radius: 20px; } .audio-sheet.is-open .audio-sheet-panel { transform: translate(-50%, 0); } } /* v9.2.1 — Mobiel: sheet is fullscreen, alleen te sluiten via handle-knop bovenin. Geen rounded corners, volledige viewport, safe-area voor notches/status bar. */ @media (max-width: 719.98px) { .audio-sheet-panel { inset: 0; max-height: none; border-top-left-radius: 0; border-top-right-radius: 0; box-shadow: none; padding-top: calc(.75rem + env(safe-area-inset-top, 0px)); padding-bottom: calc(2rem + env(safe-area-inset-bottom, 0px)); } /* v9.3 — Backdrop blijft visible op mobile zodat drag-gesture de blur laat doorschemeren naar helder. */ } /* ============================================================ Mobile masthead + pagination ============================================================ */ @media (max-width: 600px) { .masthead-inner { gap: .35rem; } .site-title { font-size: 1.2rem; } .site-subtitle { display: none; } .top-nav { gap: .1rem; } .nav-label { display: none; } .nav-btn, .nav-link { padding: .4rem .45rem; min-width: 38px; justify-content: center; } .pagination { flex-direction: column; gap: .5rem; } .pagination-item { width: 100%; } } @media (max-width: 400px) { .masthead { padding: calc(.5rem + var(--safe-top)) 0 .5rem; } .masthead-inner { gap: .25rem; } .site-title { font-size: 1.05rem; } .nav-btn, .nav-link { padding: .35rem .3rem; min-width: 34px; } .nav-btn .icon, .nav-link .icon { width: 1rem; height: 1rem; } /* PWA-install knop verbergen op klein scherm — kan ook via menu */ .nav-install-btn { display: none !important; } } @media (max-width: 340px) { .site-title { font-size: .95rem; } .nav-btn, .nav-link { padding: .3rem .25rem; min-width: 30px; } /* Theme-toggle verbergen op ultra-klein — kan via user-menu */ [data-pcms-theme-toggle] { display: none; } } .post-date-ago { margin-left: .5em; opacity: .6; font-size: .9em; font-style: italic; text-transform: none; letter-spacing: 0; } /* HTMX loading indicator — subtle progress-bar aan de top van de content */ .pcms-loading { position: fixed; top: 0; left: 0; height: 2px; width: 0%; background: var(--accent, #c2410c); z-index: 9999; transition: width .3s ease, opacity .2s; opacity: 0; pointer-events: none; } .pcms-loading.htmx-request { opacity: 1; width: 80%; transition: width 6s cubic-bezier(.1,.9,.2,1), opacity .2s; } /* subtile fade wanneer content gewisseld wordt */ #pcms-main.htmx-swapping { opacity: .5; transition: opacity .15s; } /* Masthead brand group (site-title + optional tagline) */ .masthead-brand { display: flex; flex-direction: column; gap: 2px; } .site-subtitle { font-family: var(--font-ui, inherit); font-size: .75rem; color: var(--ink-muted, rgba(0,0,0,.55)); letter-spacing: 0; line-height: 1.3; } /* ============================================================ v7.3 — TAGS, TYPE, ARCHIEF, ZOEK, RELATED, SPECIAL VIEWS ============================================================ */ /* Post-meta row — datum + type-chip + tags samen onder de titel */ .post-meta { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .85rem; margin-top: .5rem; } .post-meta .post-date { margin: 0; } /* Type-chip (groter, als een label) */ .post-type-chip { display: inline-flex; align-items: center; padding: .2rem .6rem; background: color-mix(in srgb, var(--accent) 10%, transparent); color: var(--accent); border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent); border-radius: 999px; font-family: var(--font-ui); font-size: .72rem; font-weight: 600; text-decoration: none; letter-spacing: .04em; text-transform: uppercase; transition: background .15s; } .post-type-chip:hover { background: color-mix(in srgb, var(--accent) 20%, transparent); } /* Tag-chips — klein, subtiel, gelinkt */ .post-tags, .post-list-tags { display: inline-flex; flex-wrap: wrap; gap: .3rem; } .tag-chip { display: inline-block; padding: .15rem .55rem; background: color-mix(in srgb, var(--ink) 5%, transparent); color: var(--ink-muted); border-radius: 999px; font-family: var(--font-ui); font-size: .72rem; font-weight: 500; text-decoration: none; transition: background .15s, color .15s; } .tag-chip:hover { background: color-mix(in srgb, var(--accent) 12%, transparent); color: var(--accent); } /* ============================================================ SPECIAL PAGES (archief, tag, type, zoek) ============================================================ */ .special-page .post-header { margin-bottom: 2rem; } .special-eyebrow { font-size: .72rem; color: var(--ink-muted); text-transform: uppercase; letter-spacing: .12em; margin: 0 0 .25rem; } /* Archief: jaar-overzicht */ .archive-years { display: flex; flex-direction: column; gap: 2rem; } .archive-year h2 { font-family: var(--font-display); font-size: 1.75rem; margin: 0 0 .75rem; } .archive-year h2 a { color: var(--ink); text-decoration: none; } .archive-year h2 a:hover { color: var(--accent); } .archive-year h2 .admin-muted { font-size: .9rem; font-weight: normal; color: var(--ink-muted); } .archive-months { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: .5rem; } .archive-months li { display: flex; align-items: center; gap: .4rem; padding: .55rem .75rem; background: color-mix(in srgb, var(--ink) 3%, transparent); border-radius: var(--radius); transition: background .15s; } .archive-months li:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); } .archive-months a { color: var(--ink); text-decoration: none; font-weight: 500; font-size: .95rem; } .archive-months .admin-muted { font-size: .75rem; color: var(--ink-muted); margin-left: auto; } /* Archief: jaar drill-down */ .archive-month-list { display: flex; flex-direction: column; gap: 2rem; } .archive-month h2 { font-family: var(--font-display); font-size: 1.35rem; margin: 0 0 .5rem; padding-bottom: .35rem; border-bottom: 1px solid var(--rule); } .archive-month h2 a { color: var(--ink); text-decoration: none; } .archive-month h2 a:hover { color: var(--accent); } /* Compact post-list (gebruikt in archief drill-down per maand) */ .post-compact-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; } .post-compact-list li { border-bottom: 1px solid var(--rule); } .post-compact-list li:last-child { border-bottom: none; } .post-compact-list a { display: grid; grid-template-columns: 3em 1fr; gap: .75rem; padding: .6rem .2rem; text-decoration: none; color: var(--ink); transition: background .12s; border-radius: 4px; } .post-compact-list a:hover { background: color-mix(in srgb, var(--accent) 6%, transparent); } .post-compact-date { color: var(--ink-muted); font-size: .8rem; align-self: center; } .post-compact-title { font-weight: 500; font-size: 1rem; align-self: center; } .post-compact-list.large a { grid-template-columns: 4em 1fr; padding: .8rem .3rem; } .post-compact-list.large .post-compact-title { font-family: var(--font-display); font-size: 1.15rem; } .post-compact-excerpt { grid-column: 2; color: var(--ink-muted); font-size: .88rem; line-height: 1.5; } /* Post-list (gebruikt in tag / type / zoek pagina's) */ .post-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 1.5rem; } .post-list-item { display: grid; grid-template-columns: 120px 1fr; gap: 1.25rem; padding-bottom: 1.5rem; border-bottom: 1px solid var(--rule); } .post-list-item:last-child { border-bottom: none; } .post-list-item:has(> .post-list-cover + .post-list-body) { grid-template-columns: 120px 1fr; } .post-list-item:not(:has(.post-list-cover)) { grid-template-columns: 1fr; } .post-list-cover { display: block; aspect-ratio: 1; overflow: hidden; border-radius: var(--radius); } .post-list-cover img { width: 100%; height: 100%; object-fit: cover; display: block; } .post-list-body { display: flex; flex-direction: column; gap: .35rem; } .post-list-meta { color: var(--ink-muted); font-size: .75rem; display: flex; gap: .35rem; align-items: center; } .post-list-title { font-family: var(--font-display); font-size: 1.3rem; font-weight: 450; margin: 0; line-height: 1.2; } .post-list-title a { color: var(--ink); text-decoration: none; } .post-list-title a:hover { color: var(--accent); } .post-list-excerpt { color: var(--ink-muted); font-size: .95rem; margin: 0; line-height: 1.5; } /* Zoek-formulier binnen special view */ .search-form { display: flex; gap: .5rem; margin-bottom: 2rem; } .search-form input[type=search] { flex: 1; padding: .75rem 1rem; background: var(--paper-2); border: 1px solid var(--rule); border-radius: var(--radius); font: inherit; color: var(--ink); } .search-form input[type=search]:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 20%, transparent); } /* ============================================================ SEARCH OVERLAY (masthead → full-screen zoekbalk) ============================================================ */ .search-overlay { position: fixed; inset: 0; background: color-mix(in srgb, var(--ink) 50%, transparent); z-index: 1500; display: flex; justify-content: center; align-items: flex-start; padding-top: 10vh; backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); } .search-overlay[hidden] { display: none; } .search-overlay-form { width: min(90vw, 600px); background: var(--paper); border-radius: calc(var(--radius) * 1.5); padding: .75rem 1rem; display: flex; align-items: center; gap: .6rem; box-shadow: 0 20px 60px rgba(0,0,0,.3); border: 1px solid var(--rule); } .search-overlay-form .icon { width: 1.2rem; height: 1.2rem; color: var(--ink-muted); flex-shrink: 0; } .search-overlay-form input[type=search] { flex: 1; background: transparent; border: none; font-family: var(--font-body); font-size: 1.1rem; color: var(--ink); padding: .5rem 0; } .search-overlay-form input[type=search]:focus { outline: none; } .search-overlay-form .nav-btn { background: transparent; border: none; color: var(--ink-muted); cursor: pointer; font-size: 1.25rem; line-height: 1; padding: .3rem .5rem; } .search-overlay-form .nav-btn:hover { color: var(--ink); } body.search-open { overflow: hidden; } /* ============================================================ RELATED POSTS (onder elke post-view) ============================================================ */ .related-posts { margin-top: 2.5rem; padding-top: 2rem; border-top: 1px solid var(--rule); } .related-title { font-family: var(--font-mono); font-size: .7rem; color: var(--ink-muted); text-transform: uppercase; letter-spacing: .12em; margin: 0 0 1rem; } .related-grid { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; } .related-grid a { display: flex; flex-direction: column; gap: .5rem; text-decoration: none; color: var(--ink); border: 1px solid var(--rule); border-radius: var(--radius); overflow: hidden; transition: border-color .15s, transform .15s; height: 100%; } .related-grid a:hover { border-color: color-mix(in srgb, var(--accent) 50%, var(--rule)); transform: translateY(-2px); } .related-cover { display: block; aspect-ratio: 16/10; background-size: cover; background-position: center; background-color: var(--paper-2); } /* v9.4 — Wanneer related-cover ook .grid-tile-gradient class heeft (lege cover fallback), erft 'ie automatisch de hue/gradient/title styling van grid-tiles. Geen aparte related-cover-gradient meer nodig. */ .related-body { display: flex; flex-direction: column; gap: .25rem; padding: .6rem .75rem .9rem; } .related-meta { color: var(--ink-muted); font-size: .7rem; } .related-name { font-family: var(--font-display); font-weight: 450; font-size: 1rem; line-height: 1.25; } /* ============================================================ MOBILE TWEAKS voor v7.3 ============================================================ */ @media (max-width: 600px) { .post-list-item { grid-template-columns: 1fr; } .post-list-cover { aspect-ratio: 16/9; } .archive-months { grid-template-columns: repeat(2, 1fr); } .related-grid { grid-template-columns: 1fr; } .search-overlay { padding-top: 4vh; } } /* ============================================================ v7.4 — PROFILE HEADER + VIEW SWITCHER + GRID + POST-TYPE LAYOUTS MOBILE-FIRST — belangrijkste eis ============================================================ */ /* -------- PROFILE HEADER (Optie C: full op home, compact op post/special) -------- */ .profile-header { background: var(--paper-2, var(--paper)); border-bottom: 1px solid var(--rule); transition: padding .25s ease, background .2s; } /* Mobiel default = full-mode padding */ .profile-header { padding: 1.25rem 0; } .profile-header-inner { display: flex; gap: .9rem; align-items: flex-start; } .profile-photo { flex-shrink: 0; width: 80px; height: 80px; border-radius: 50%; overflow: hidden; display: block; background: var(--paper); border: 2px solid var(--rule); transition: width .25s ease, height .25s ease, border-color .2s; text-decoration: none; } .profile-photo:hover { border-color: var(--accent); } .profile-photo img { width: 100%; height: 100%; object-fit: cover; display: block; } .profile-photo-fallback { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; background: var(--accent); color: var(--paper); font-family: var(--font-display); font-weight: 700; font-size: 2.2rem; text-transform: uppercase; line-height: 1; transition: font-size .25s ease; } .profile-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: .3rem; } .profile-name { margin: 0; font-family: var(--font-display); font-size: 1.2rem; font-weight: 500; line-height: 1.15; transition: font-size .25s ease; } .profile-name a { color: var(--ink); text-decoration: none; } .profile-name a:hover { color: var(--accent); } .profile-bio { margin: 0; color: var(--ink-muted); font-size: .92rem; line-height: 1.45; max-height: 200px; overflow: hidden; transition: max-height .25s ease, margin .25s ease, opacity .2s; } .profile-links { list-style: none; padding: 0; margin: .15rem 0 0; display: flex; flex-wrap: wrap; gap: .4rem; max-height: 50px; overflow: hidden; transition: max-height .25s ease, margin .25s ease, opacity .2s; } .profile-links li { margin: 0; } .profile-links a { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 50%; background: color-mix(in srgb, var(--ink) 5%, transparent); color: var(--ink-muted); text-decoration: none; transition: background .15s, color .15s; } .profile-links a:hover { background: color-mix(in srgb, var(--accent) 15%, transparent); color: var(--accent); } .profile-links .icon { width: 1.1rem; height: 1.1rem; } /* -------- COMPACT MODE: op post + special pages -------- */ .on-post .profile-header, .on-special .profile-header { padding: .5rem 0; } .on-post .profile-photo, .on-special .profile-photo { width: 36px; height: 36px; border-width: 1px; } .on-post .profile-photo-fallback, .on-special .profile-photo-fallback { font-size: 1rem; } .on-post .profile-name, .on-special .profile-name { font-size: 1rem; align-self: center; } .on-post .profile-bio, .on-special .profile-bio, .on-post .profile-links, .on-special .profile-links { display: none; } .on-post .profile-header-inner, .on-special .profile-header-inner { align-items: center; justify-content: flex-start; gap: .6rem; } .on-post .profile-info, .on-special .profile-info { flex: 0 1 auto; min-width: 0; } .on-post .profile-name, .on-special .profile-name { text-align: left; } /* -------- DESKTOP: meer ruimte, grotere foto -------- */ @media (min-width: 768px) { .profile-header { padding: 2rem 0; } .profile-photo { width: 120px; height: 120px; } .profile-photo-fallback { font-size: 3.2rem; } .profile-name { font-size: 1.5rem; } .profile-bio { font-size: 1rem; } .profile-header-inner { gap: 1.5rem; } .on-post .profile-header, .on-special .profile-header { padding: .6rem 0; } .on-post .profile-photo, .on-special .profile-photo { width: 42px; height: 42px; } /* Compact mode: gap blijft klein, ook op desktop */ .on-post .profile-header-inner, .on-special .profile-header-inner { gap: .75rem; } .on-post .profile-name, .on-special .profile-name { font-size: 1.1rem; } } /* -------- VIEW SWITCHER -------- */ .view-switcher-wrap { border-bottom: 1px solid var(--rule); background: var(--paper); /* Bottom margin gives breathing room between the switcher bar and the first post. margin-top staat in shared-styles.ejs (de winnende inline