/*
Theme Name: Yeshua Online
Theme URI: https://www.jesusmessiah.online
Author: Yeshua Online
Description: Blockthema (FSE) voor jesusmessiah.online, gebaseerd op de vastgestelde stijlgids (parchment/night paletten, Fraunces + Public Sans).
Version: 4.44
Requires at least: 6.4
Requires PHP: 7.4
Text Domain: yeshua-online

Changelog:
- 4.44 — **Heartbeat van de bezoekersteller stopt pas na 60 minuten** op dezelfde pagina (was 30 in 4.43), zodat lezers van lange artikelen (±5.000 woorden) niet onterecht uit "nu online" vallen. Verder gelijk aan 4.43; bevat alles van 4.43.
- 4.43 — **Zuinigere bezoekersteller** (minder serverbelasting, na CPU-overschrijdingen bij Namecheap). (1) **Eén verzoek in plaats van twee:** de beacon (`/wp-json/yeshua/v1/beacon`) registreert het bezoek én geeft de cijfers terug; het aparte `visitor-stats`-verzoek vervalt (endpoint blijft bestaan voor oude gecachete pagina's). (2) **Heartbeat elke 150 s i.p.v. 75 s, alleen als het tabblad zichtbaar is**, en na 30 minuten op dezelfde pagina stopt hij helemaal (in 4.44: 60 minuten). (3) **"Nu online"-venster 5 min** (was 3 min; constante `YESHUA_ONLINE_WINDOW`). (4) **Cijfers 30 s bewaard** (transient `yeshua_visitor_stats_cache`), zodat niet elk verzoek de database laat tellen. (5) **Opruimen van verlopen bezoekers hooguit 1× per minuut** (was bij elk signaal). (6) **Registratie bij paginaopbouw (`template_redirect`) uitgeschakeld**: dubbel met de beacon. Teller toont dezelfde cijfers; is niet afhankelijk van WP Statistics. Bevat alles van 4.42. Artikelen, menu's, vertalingen en zoekfunctie niet geraakt.
- 4.42 — **Melding op een nog niet vertaalde categorie** (alle talen): staat er in een categorie in de taal van de bezoeker (bv. Arabisch) nog geen enkel artikel, maar wel in de Engelse versie, dan staat bovenaan een balk in zijn eigen taal en leesrichting: "Deze categorie is nog niet in het <taal> vertaald. Hieronder vind je de artikelen in het Engels." met een knop "Ga terug" (vorige pagina op de site, anders de homepage in die taal). Het kopje "Meer artikelen in deze categorie" en de rode machinevertaling-melding vallen dan weg (body-class `en-fallback-only`). Helemaal leeg (ook in het Engels): de bestaande melding "Nog geen artikelen" krijgt "Ga terug" erbij. Gedeeltelijk vertaald: geen balk. Nieuwe shortcodes `[yeshua_category_lang_notice]` en `[yeshua_go_back]` in `templates/archive.html`, functie `yeshua_online_category_untranslated()`, strings `cat_untranslated_notice`/`go_back` in alle 8 talen, opmaak in `style.css`. **Voorwaarde:** de categorie moet in die taal bestaan en in Polylang aan de Engelse gekoppeld zijn; anders stuurt het menu (4.41) nog naar de Engelse categorie. Bevat alles van 4.41. Artikelen, menu's, zoekfunctie en Start Here verder niet geraakt.
- 4.41 — (1) **Menu altijd in de taal van de pagina** (alle talen): wijst een menu-item naar een categorie, pagina of bericht in een andere taal (bv. het Arabische item "دراسات كتابية" dat nog naar de Engelse categorie Bible Study linkte, waardoor de bezoeker op een Engelse pagina met Engels menu belandde), dan zet `yeshua_online_menu_follow_current_lang()` (filter `wp_nav_menu_objects`, priority 6) de link automatisch om naar de gekoppelde vertaling in de huidige taal, inclusief de actief-markering. Geen vertaling → link ongewijzigd. Menu's zelf hoeven niet aangepast te worden. (2) **Terugknop op Engelse terugval-artikelen:** klikt een bezoeker in een categorie in zijn eigen taal op een Engels kaartje ("Nog niet vertaald"), dan staat op dat Engelse artikel onder de header een balk in zijn eigen taal en leesrichting: "← Terug naar <categorie>" plus "Dit artikel is nog niet vertaald." en een sluitknop. Nieuwe shortcode `[yeshua_back_data]` in `templates/archive.html`, script in `parts/footer.html` (sessionStorage, alleen dit tabblad; geen extra URL's, geen invloed op cache of zoekmachines), opmaak in `style.css`. Nieuwe strings `back_label`/`back_note` in alle 8 talen. Bevat alles van 4.40. Artikelen, zoekfunctie en Start Here verder niet geraakt.
- 4.40 — (1) **Vaste mapnaam `yeshua-online-theme`** (was per versie een eigen map, bv. `yeshua-online-theme-v4_39`). Daardoor zag WordPress elke versie als een apart thema; zo bleef 4.38 live draaien terwijl 4.39 al bestond. Vanaf nu werkt elke volgende zip als echte update via *Thema uploaden → Vervangen door geüpload thema*. Eenmalig bij de overstap: activeren + menulocaties opnieuw instellen. (2) **Nieuwe 404-pagina voor alle talen** (`templates/404.html`): er was geen 404-sjabloon, dus WordPress viel terug op `index.html` met een lege berichtenlijst — bezoekers zagen bij een foute link alleen header en footer. Nu: titel, korte uitleg, zoekveld (naar de taal-root, zoals de zoekpagina) en knoppen naar de homepage en Start Here van de huidige taal. Nieuwe strings `nf_heading`/`nf_text`/`nf_home`/`nf_start` in alle 8 talen; opmaak in `style.css` (ook RTL en telefoon). Bevat alles van 4.39. Artikelen, categorieën, menu's en zoekfunctie verder niet geraakt.
- 4.39 — Eén taalregel voor alle talen, ook Arabisch: Engelse terugval in categorieën i.p.v. lege pagina's of doorverwijzingen. (1) **Categoriepagina's in elke taal behalve Engels** tonen onder de gewone lijst een blok "Meer artikelen in deze categorie" met alles wat in de Engelse versie van de categorie staat maar hier ontbreekt: bestaat er al een gepubliceerde vertaling die (nog) niet in deze categorie staat, dan die vertaling; anders het Engelse artikel met het label "Nog niet vertaald · Engels" (nieuw dynamisch blok `yeshua/untranslated-label`, Engelse kaartjes links-naar-rechts ook op RTL-pagina's). Nieuwe functies `yeshua_online_en_fallback_ids()`/`_all_ids()`, tweede Query Loop (queryId 77) in `templates/archive.html` gevuld via `query_loop_block_query_vars`, body-class `has-en-fallback` (verbergt dan de melding "nog geen artikelen"). Alleen op de laatste pagina van een categorie; niet op de Start Here-hoofdpagina met intro; intro-pagina's worden uitgesloten. Raster/lijst-schakelaar werkt nu op beide lijsten. Nieuwe strings `en_fallback_heading`/`en_fallback_label` in alle 8 talen. (2) **Arabische uitzonderingen vervallen:** `yeshua_online_empty_category_fallback_langs()` (doorverwijzen lege categorie → Engels, 4.22), `yeshua_online_menu_only_translated_langs()` (menu alleen vertaalde items + doorverwijzen naar Arabische homepage, 4.28) en `yeshua_online_switcher_partial_langs()` (4.23) geven nu een lege lijst: geen doorverwijzingen meer, het hoofdmenu toont in elke taal alle items, en de taalwisselaar volgt voor alle talen de Polylang-standaard plus de categorieregel uit 4.38. Functies blijven bestaan (taal terugzetten = lijst weer vullen). Artikelen, Start Here-intro en zoekfunctie niet geraakt.
- 4.38 — Taalwisselaar op categoriepagina's toont een taal alleen nog als de gekoppelde categorie in die taal minstens één gepubliceerd artikel (bericht of pagina, incl. subcategorieën) heeft. Was alleen voor Arabisch (4.22/4.29); nu voor alle talen, in `yeshua_online_lang_switcher_data_for_category()`. Doel: categorieën (zoals de Start Here-subcategorieën) kunnen alvast in alle talen worden aangemaakt en gekoppeld zonder dat bezoekers op een lege pagina belanden; de taal verschijnt vanzelf zodra er een artikel in staat. De doorverwijzing van lege categorieën (alleen Arabisch) en het Arabische menufilter zijn ongewijzigd. Losse artikelen/pagina's en de homepage niet geraakt.
- 4.37 — Fix: mobiele keuzetegels op Start Here vielen op een echte telefoon (Samsung S23, ook incognito) uit elkaar: titel en knoptekst liepen als één zin door elkaar en de donkerblauwe knop ontbrak, terwijl F12-mobielweergave wel klopte. Oorzaak: de opmaak herkende titel en knop op volgorde (`span:first-child`/`:last-child`), en wpautop/de tooltip-plugin (CM Tooltip Glossary) zetten extra opmaak in de tegel. (1) `[yeshua_start_here_intro]` haalt elk `<div class="start-choice">`-blok vóór `the_content` uit de inhoud en zet het daarna ongefilterd (alleen `wp_kses_post`) terug: geen wpautop en geen tooltips binnen de keuzetegels. (2) Nieuwe klassen `start-choice-title` en `start-choice-btn` in de pagina-inhoud; opmaak met `!important` zodat plugins die niet overschrijven. De oude `span`-opmaak blijft als terugval werken. Alleen de mobiele Start Here-tegels geraakt.
- 4.36 — Start Here: aparte mobiele weergave, volledig te beheren in de pagina `start-here-intro`. Nieuwe klassen voor de pagina-inhoud: `start-mobile` (alleen zichtbaar ≤700px) en `start-desktop` (verborgen ≤700px). In het mobiele deel: een korte welkomsttekst (`start-lead`), de twee keuzes naast elkaar als compacte tegels (`start-choice` met per keuze `<a><span>titel</span><span>knoptekst</span></a>`, 2 kolommen, knoppen van 44px+ hoog) en optioneel uitklapbare uitleg (`start-more` met `<details>`). **Veiligheid:** het computer-deel wordt op een telefoon alleen verborgen als de pagina ook echt een `start-mobile`-deel heeft (`:has()`), zodat talen die nog niet zijn bijgewerkt hun bestaande weergave houden. Alleen CSS (`style.css`); geen PHP- of sjabloonwijzigingen. Artikelen, tabellen en andere pagina's niet geraakt.
- 4.35 — Start Here op telefoons + zwevende knoppen + nieuwe-artikelen-melding. (1) **Tegels binnen het scherm:** de tegels hadden een minimale breedte van 300px; op een smal scherm (bv. Samsung S23, ~360px) bleef na de witruimte minder over, waardoor de tegel rechts buiten beeld liep. Nu `minmax(min(300px,100%),1fr)` en onder 700px één kolom met minder zijwitruimte. (2) **Tekst links uitgelijnd op telefoons, alleen in de Start Here-intro** (`.start-intro`, ≤700px, `text-align:start` — RTL dus rechts): uitvullen gaf in de smalle kolom grote gaten tussen woorden. Op de computer blijft de tekst uitgevuld; artikelen en tabellen elders zijn niet geraakt. (3) **Zwevende knoppen (Back/Share/Top) op telefoons (≤640px) als ronde icoontjes van 44px zonder zichtbare tekst** (keuze A), zodat ze minder tekst bedekken. Tekst blijft in de knop voor schermlezers; desktop ongewijzigd. Regels in `parts/header.html` direct onder de bestaande floating-actions-mediaquery. (4) **Intro-pagina's tellen niet meer als "nieuw artikel"** in de melding op de homepage: `/yeshua/v1/new-since` sluit via `post__not_in` alle pagina's met slug `start-here-intro`/`start-hier-intro` en hun Polylang-vertalingen uit (`yeshua_online_start_here_intro_ids()`).
- 4.34 — Opschoning Start Here-subcategorieën en categorielabels. (1) **Vak met beschrijving + "Also see" weg** op de Start Here-subcategorieën: `[yeshua_start_sub_bar]` uit `templates/archive.html` gehaald (functie blijft bestaan maar wordt niet meer gebruikt). (2) **"← Back to Start Here"** staat nu rechts in de zoekbalk-sectie (nieuwe shortcode `[yeshua_start_back_link]`, alleen op subcategorieën van Start Here; RTL links; onder 700px onder de zoekbalk). Spatie in de categorienaam wordt niet aangepast: hernoem de categorie zelf naar "Start Here!". (3) **Categorielabel op alle artikelkaartjes weg** (sitebreed): blok `wp:post-terms` met className `tag` uit `templates/archive.html` verwijderd. De opmaak (`.article-card .tag` in `parts/header.html`) is BEWUST bewaard met een terugzet-instructie erboven: pil boven de titel, hoofdletters, 0.72rem, gewicht 600, letterafstand 0.05em, tekst #2F4C82 (tekhelet) op #eef1f8, padding 4px 11px, radius 20px (lijstweergave 0.68rem, 3px 9px). (4) **Gouden label boven de artikeltitel** (`article-tag` in `parts/article-body.html`) toont alleen nog echte onderwerpen: taalcategorieën (op naam, lijst in `yeshua_online_hidden_label_category_names()`), de standaardcategorie in elke taal en Start Here + subcategorieën in elke taal worden verborgen via een `get_the_terms`-filter dat alleen tijdens het renderen van `core/post-terms` actief is. Geen onderwerp over = geen label. Menu's, categoriepagina's en de backend zien alle categorieën ongewijzigd. Termen-balk ongewijzigd (blijft vast, wegklikbaar).
- 4.33 — Knoppen onderaan de Start Here-tegels staan nu gecentreerd (ook in RTL-talen). Alleen opmaak (`style.css`), geen andere wijzigingen. Bevat alle wijzigingen van 4.30 en 4.32.
- 4.32 — Start Here: alleen de twee tegels, met een knop naar de eigen subcategorie (vervangt 4.31, die niet wordt gebruikt; bouwt verder op 4.30). (1) **"Daaronder niets":** bestaat de intro-pagina (`start-here-intro`) in de huidige taal, dan krijgt de eerste pagina van de Start Here-categorie de body-class `start-here--intro-only` en verbergt de CSS de zoekbalk en de artikellijst; alleen titel + tegels blijven. Zonder intro-pagina in die taal blijft de oude lijst zichtbaar. (2) **Knop onderaan elke tegel:** tegels zijn nu flex-kolommen; de laatste alinea (de knop) staat altijd onderaan, in beide tegels op gelijke hoogte. **Fix:** de knoptekst liep buiten de knop ("Begin with st | ep 1"); `.start-button` nu `inline-flex`, `width/height:auto !important`, tekst mag afbreken. (3) **Terug-balk op de subcategorieën** (`[yeshua_start_sub_bar]` in `templates/archive.html`): "← Terug naar Start Here", de categoriebeschrijving (bewerkbaar en vertaalbaar via Berichten → Categorieën + Polylang) en een link naar de andere subcategorie. Artikeltegels en raster/lijst-schakelaar daar ongewijzigd. (4) **Alle talen:** de termen-balk voor twee doelgroepen (4.30) en de nieuwe strings (`start_intro_aria`, `start_back`, `start_also`) nu ook in Hinglish, Hindi, Spaans, Chinees, Hebreeuws en Arabisch — eerste concept, laten nalezen door een native speaker.
- 4.30 — Start Here voor twee doelgroepen. (1) **Twee routes bovenaan de Start Here-categorie:** nieuwe shortcode `[yeshua_start_here_intro]` in `templates/archive.html` (direct onder de titel, boven de zoekbalk). Toont alleen iets op de eerste pagina van de Start Here-categorie (NL-ankerslug `start-hier`, vertaalde term via Polylang) én alleen als er een Pagina met slug `start-here-intro` of `start-hier-intro` in de huidige taal bestaat; die inhoud beheer je zelf in de klassieke editor (HTML-blok met de klassen `start-lead`, `start-paths`/`start-path`, `start-readlist`, `start-route`/`start-steps`, `start-button`, `start-all`). Bewust geen terugval op een andere taal: zonder vertaling blijft de categoriepagina ongewijzigd. Privé-status werkt als voorvertoning voor ingelogde beheerders; beheerders zien ook een bewerk-link. De bestaande artikellijst met raster/lijst-schakelaar blijft daaronder ongewijzigd. Opmaak (incl. RTL en mobiel) onderaan `style.css`. (2) **Termen-balk spreekt nu beide groepen aan (NL + EN):** nieuwe shortcode `[yeshua_terms_banner_text]` in `parts/header.html` toont "Nieuw met de Bijbel? Begin hier. Al christen? … lees eerst onze termen & definities." Nieuwe strings `terms_banner_start_pre/_start_link/_christian_pre/_christian_link` en `start_intro_aria` (alleen NL/EN). Overige talen houden exact de oude balktekst tot hun vertaling is toegevoegd. Link naar de definities-pagina ongewijzigd (zelfde vaste URL, nu via `yeshua_online_terms_page_url()`).
- 4.24 — Vertaalmelding ("deze pagina is machinaal vertaald…") uitgebreid naar Arabisch, en de "Lees in het Engels"-link verwijst nu naar de Engelse versie van het artikel zelf i.p.v. naar de Engelse homepage. (1) `ar` toegevoegd aan `yeshua_online_machine_translated_langs()` (bevestigd: Arabische tekst is machinevertaald) plus Arabische meldingstekst en linktekst (`اقرأ بالإنجليزية ←`, pijl naar links i.v.m. RTL, net als bij Hebreeuws) in `yeshua_online_shortcode_translation_notice()` — eerste concept, laten nalezen door een native speaker. Bewust een vaste lijst gehouden i.p.v. automatisch "alle talen behalve en/nl": de melding zegt iets over de kwaliteit per taal; na native nalezing haal je één taalcode uit de lijst. (2) **Verbetering voor alle talen met de melding (hi/es/zh/he/ar):** de link ging altijd naar `pll_home_url('en')`, waardoor een lezer het artikel in het Engels zelf opnieuw moest zoeken. Nieuwe functie `yeshua_online_translation_notice_english_url()`: op een artikel/pagina de gekoppelde, gepubliceerde Engelse vertaling; op een categoriepagina de Engelse categorie; anders (geen koppeling) zoals voorheen de Engelse homepage. Hinglish staat nog steeds niet in de lijst (ongewijzigd). **Controlepunt:** op staging (a) de Arabische pagina: melding in het Arabisch, rechts-naar-links, link leidt naar het Engelse "Who Is God"-artikel, (b) een Chinees/Spaans/Hindi/Hebreeuws artikel: melding ongewijzigd, link leidt nu naar het Engelse artikel i.p.v. de homepage, (c) een vertaald artikel zónder Engelse koppeling: link valt terug op de Engelse homepage, (d) Engelse, Nederlandse en Hinglish-pagina's: geen melding, (e) tooltips (CM Tooltip Glossary), shortcodes, custom fields, widgets en menu's werken. Na activeren de menu-locaties opnieuw instellen (Menu's → Locaties beheren). Syntax gecontroleerd met een PHP-parser (php-parser, PHP 8-modus): geen fouten. | `functions.php` (`yeshua_online_machine_translated_langs`, `yeshua_online_shortcode_translation_notice`, nieuwe `yeshua_online_translation_notice_english_url`), `style.css` (versie + changelog) |
- 4.23 — Arabisch verschijnt in de taalwisselaar niet meer op de homepage en op overige overzichtspagina's zolang daar geen Arabische inhoud is. Aanleiding: na route A (Engels menu op Arabische pagina's) bleek op de Engelse homepage op staging "العربية" in de dropdown te staan, terwijl er geen Arabische homepage bestaat — Polylang's `hide_if_no_translation` toont op de homepage en op zoek-/tag-/datumarchieven namelijk altijd alle talen. Nieuwe functies `yeshua_online_switcher_partial_langs()` (lijst: alleen `ar`) en `yeshua_online_switcher_allows_partial_lang()`, toegepast als extra filter in `yeshua_online_shortcode_lang_switcher()` na de bestaande `$active_langs`-filter. Regels voor Arabisch: homepage → alleen als er in Polylang een Arabische vertaling van de vaste voorpagina gekoppeld is (nu niet, dus verborgen; verschijnt vanzelf zodra die er is); losse artikelen/pagina's en categoriepagina's → ongewijzigd (al gefilterd op gekoppelde vertaling); overige overzichtspagina's (zoekresultaten, tag-/datumarchieven) → verborgen. Alle andere talen ongewijzigd. Gebouwd op v4.22 (zoals op staging geïnstalleerd); de v4.22-functionaliteit (lege Arabische categorieën → Engels) is ongewijzigd en heeft bij route A geen zichtbaar effect, omdat er geen lege Arabische categorieën zijn. De Polylang-melding over de ontbrekende Arabische voorpagina blijft staan (onschuldig). **Controlepunt:** op staging (a) Engelse (en Nederlandse) homepage: geen Arabisch in de dropdown, overige talen wel, (b) de "Who Is God"-pagina's (en/nl/zh): Arabisch wél in de dropdown, (c) een zoekresultatenpagina: geen Arabisch, (d) de Arabische pagina zelf: dropdown toont de andere talen, (e) dropdown in alle andere talen ongewijzigd, (f) tooltips (CM Tooltip Glossary), shortcodes, custom fields, widgets en menu's werken. Na activeren de menu-locaties opnieuw instellen (Menu's → Locaties beheren). Syntax gecontroleerd met een PHP-parser (php-parser, PHP 8-modus): geen fouten. | `functions.php` (`yeshua_online_shortcode_lang_switcher` + 2 nieuwe functies), `style.css` (versie + changelog) |
- 4.22 — Lege Arabische categorieën sturen nu automatisch door naar de Engelse versie van dezelfde categorie, op verzoek (Arabisch hoofdmenu met alle categorieën, maar zonder lege pagina's). Nieuwe functies `yeshua_online_empty_category_fallback_langs()` (lijst: alleen `ar`), `yeshua_online_category_has_posts()` (incl. subcategorieën, per verzoek gecachet) en `yeshua_online_empty_category_english_target()`. Werkt op drie plekken: (1) **menu** — via `wp_nav_menu_objects` wijzen menu-items naar een lege Arabische categorie meteen naar de Engelse categorie-URL (label blijft Arabisch); (2) **rechtstreeks bezoek** — `template_redirect` stuurt een lege Arabische categoriepagina tijdelijk (302, bewust geen 301: zodra er content komt moet de Arabische pagina weer bereikbaar zijn) door naar Engels; (3) **taalwisselaar** op categoriepagina's toont Arabisch niet zolang de Arabische categorie leeg is (anders een knop die meteen terugstuurt). Zodra er één gepubliceerd artikel in een Arabische categorie staat, vervalt de doorverwijzing vanzelf. Vereist dat elke Arabische categorie in Polylang als vertaling aan de Engelse categorie gekoppeld is; zonder koppeling geen doorverwijzing (dan gewoon de lege pagina, zoals voorheen). Andere talen ongewijzigd. **Controlepunt:** op staging (a) in het Arabische menu op een lege categorie klikken → Engelse categoriepagina, (b) op de gevulde categorie من هو الله؟ klikken → Arabische categoriepagina, (c) de URL van een lege Arabische categorie rechtstreeks openen → doorgestuurd naar Engels, (d) op een Engelse categoriepagina waarvan de Arabische versie leeg is: geen Arabisch in de dropdown; bij من هو الله؟ wél, (e) menu's en categoriepagina's in alle andere talen ongewijzigd, (f) tooltips (CM Tooltip Glossary), shortcodes, custom fields en widgets werken. Na activeren de menu-locaties opnieuw instellen (Menu's → Locaties beheren). Syntax gecontroleerd met een PHP-parser (php-parser, PHP 8-modus): geen fouten (`php -l` zelf niet beschikbaar in de bouwomgeving). | `functions.php` (nieuw blok na `yeshua_online_shortcode_main_menu`, `yeshua_online_lang_switcher_data_for_category`), `style.css` (versie + changelog) |
- 4.21 — Op de Arabische pagina('s) tonen de thema-teksten nu ENGELS i.p.v. Nederlands. Aanleiding: na test op staging (v4.20) stonden termen-balk, zwevende knoppen ("Terug"/"Delen"), CTA-blok en footer-teksten op de Arabische pagina in het Nederlands, omdat `yeshua_online_i18n_strings()` geen `ar`-blok had en `[yeshua_t]` dan terugvalt op `nl`. Een Arabische lezer begrijpt eerder Engels, en komt via de Engelse bronpagina binnen. Opgelost met één centrale terugval aan het eind van `yeshua_online_i18n_strings()`: ontbreekt `ar`, dan krijgt `ar` een kopie van het `en`-blok. Bewust centraal i.p.v. de standaard-fallback van `[yeshua_t]` (nl) te wijzigen, zodat geen enkele andere taal geraakt wordt. Links (categorie-/pagina-URL's) vielen al terug op Engels (bestaande logica in `yeshua_online_category_term_id()`/`yeshua_online_page_id()`), ongewijzigd. **Niet via code op te lossen, handmatige stap:** het hoofdmenu op de Arabische pagina is het menu dat Polylang aan de locatie "Hoofdmenu (header)" voor Arabisch koppelt -- in Menu's → Locaties beheren bij de Arabische regel "Hoofdmenu — EN" kiezen. **Bekende beperking, bewust buiten scope:** enkele losse labelsets buiten `yeshua_online_i18n_strings()` (o.a. zoekresultaten-labels) vallen voor Arabisch nog op Nederlands terug; alleen zichtbaar als iemand vanaf een Arabische pagina zoekt. **Controlepunt:** op staging (a) Arabische pagina: termen-balk, Terug/Delen-knoppen, CTA-blok en footer in het Engels, (b) na de menu-stap: hoofdmenu in het Engels, (c) alle andere talen (nl/en/es/hi/zh/he/hinglish) ongewijzigd, (d) tooltips (CM Tooltip Glossary), shortcodes, custom fields, widgets en menu's werken. Na activeren de menu-locaties opnieuw instellen (Menu's → Locaties beheren). `php -l` kon in de bouwomgeving niet draaien; syntax handmatig nagelopen. | `functions.php` (`yeshua_online_i18n_strings`), `style.css` (versie + changelog) |
- 4.20 — Arabisch (`ar`) toegevoegd aan de taalwisselaar ("Other languages"-dropdown), op verzoek na test op staging. `ar` toegevoegd aan `$active_langs` in `yeshua_online_shortcode_lang_switcher()` plus het dropdown-label in het Arabisch (`لغات أخرى`, eerste concept, laten nalezen). **Gedrag ongewijzigd t.o.v. de andere talen:** de wisselaar gebruikt `hide_if_no_translation`, dus Arabisch verschijnt UITSLUITEND op pagina's die in Polylang aan een Arabische vertaling gekoppeld zijn, en niet sitebreed. Bewust NIET gedaan: Arabisch hoofdmenu, categorieën of vertaalstrings voor header/footer — die vallen op de Arabische pagina nog steeds terug op Nederlands (`[yeshua_t]`). **Controlepunt:** op staging (a) de Arabische pagina in Polylang als vertaling koppelen aan de juiste bronpagina, (b) op die bronpagina controleren dat Arabisch in de dropdown staat en naar de juiste URL (`/ar/...`) leidt, (c) op een pagina zónder Arabische vertaling controleren dat Arabisch NIET verschijnt, (d) op de Arabische pagina zelf controleren dat de dropdown rechts-naar-links netjes opent, en (e) tooltips (CM Tooltip Glossary), shortcodes, custom fields, widgets en menu's ongewijzigd werken. Na activeren de menu-locaties opnieuw instellen (Menu's → Locaties beheren). PHP-wijziging: één extra waarde in twee bestaande arrays; `php -l` kon in de bouwomgeving niet draaien, syntax handmatig nagelopen. | `functions.php` (`yeshua_online_shortcode_lang_switcher`), `style.css` (versie + changelog) |
- 4.19 — Ondersteuning voor een losse Arabische pagina (taal `ar`, al toegevoegd in Polylang). (1) `yeshua_online_is_rtl_lang()` herkent nu ook `ar` naast `he`, zodat Arabische pagina's `dir="rtl"` op `<html>` en de class `rtl` op `<body>` krijgen en alle bestaande `body.rtl`-regels (gespiegelde pijlen, badge, zoekveld, talen-dropdown) automatisch meegaan. Bewust via de eigen functie i.p.v. Polylang's RTL-instelling, conform de bestaande aanpak. (2) **Bugfix, ook voor Hebreeuws:** de mobiele regel (≤480px) voor `.article-content p` zette `text-align:left`, waardoor RTL-tekst op mobiel tegen de verkeerde kant stond. Vervangen door `text-align:start` (links in LTR, rechts in RTL); voor NL/EN/ES/HI/ZH/Hinglish verandert er niets. (3) Arabische typografie op `html[lang^="ar"]`: Arabisch-geschikte font-fallback (Fraunces/Public Sans hebben geen Arabische tekens; Latijnse tekens blijven in het huisfont), geen nep-cursief op koppen/em/blockquote, geen `letter-spacing` in artikeltekst/titel/categorielabel (verbreekt Arabische letterverbindingen), iets ruimere regelafstand (1.9) in de artikeltekst. **Bewust NIET gedaan:** Arabisch toegevoegd aan de taalwisselaar (`$active_langs`) of aan de vertaalstrings — de pagina blijft daardoor buiten de taalwisselaar en het menu, zoals gevraagd. **Bekend gevolg:** thema-teksten rond de pagina (header, footer, CTA-blok onderaan, leestijd-labels) hebben geen Arabische vertaling en vallen terug op Nederlands (`[yeshua_t]`) of Engels (leestijd). **Controlepunt:** op staging de Arabische pagina openen op desktop én een echt mobiel toestel en controleren dat (a) de tekst rechts begint en uitgevuld staat, op mobiel rechts uitgelijnd, (b) Arabische letters aaneengesloten en zonder schuinstand worden weergegeven, (c) een Hebreeuwse pagina op mobiel nu ook rechts uitgelijnd staat, (d) Arabisch niet in de taalwisselaar of het menu verschijnt, en (e) tooltips (CM Tooltip Glossary), shortcodes, widgets en menu's elders ongewijzigd werken. Na activeren de menu-locaties opnieuw instellen (Menu's → Locaties beheren). PHP-wijziging is uitsluitend één extra waarde (`'ar'`) in een bestaande array; `php -l` kon in de bouwomgeving niet draaien, dus syntax handmatig nagelopen. | `functions.php` (`yeshua_online_is_rtl_lang` + commentaar), `style.css` (CSS + versie + changelog) |
- 4.18 — Fix: op mobiel duwde de leestijd-indicator op twee plekken de hele pagina horizontaal open i.p.v. netjes binnen zijn eigen kader te blijven. (1) `.reading-time` (leestijd-balk boven een los artikel, `parts/article-body.html`): er was geen vangnet dat een los item (icoon + label + waarde, bv. "Leestijd uitgebreide uitleg: 6 min") tegenhield als het niet paste -- toegevoegd: `min-width:0`/`max-width:100%`/`flex-wrap:wrap` op `.reading-time__item` en `overflow-wrap:break-word` op label/waarde, zodat de tekst nu naar een tweede regel afbreekt binnen het item. (2) `.archive-card-reading-time__item` (leestijd op de categorie/overzicht-kaartjes, `.article-grid` op mobiel 2 kolommen): had expliciet `white-space:nowrap` staan, wat het item dwong altijd op één regel te blijven, ook als dat breder was dan het kaartje -- op een screenshot bevestigd zichtbaar als afgekapte tekst ("66 m" i.p.v. "66 min") terwijl de pagina toch al horizontaal schoof. `nowrap` vervangen door dezelfde `min-width:0`/`overflow-wrap:break-word`-aanpak als (1). **Bewust gekozen voor wrappen (nieuwe regel binnen het kaartje), niet voor horizontaal scrollen zoals bij tabellen** -- dit is korte labeltekst, geen tabulaire data; scrollen in een klein pilletje zou de helft van de tekst verbergen totdat iemand toevallig veegt, wrappen blijft direct volledig leesbaar. Layout/kleur/grid-structuur verder ongewijzigd. **Controlepunt:** op staging en live, op een echt mobiel toestel (niet alleen devtools-resize), controleren dat (a) de leestijd-balk boven een artikel met een lange "Uitgebreide uitleg"-waarde nu naar een tweede regel afbreekt i.p.v. de pagina te verbreden, (b) hetzelfde geldt voor de leestijd op de categorie-kaartjes (2-koloms mobiele grid, met name bij hogere minutenwaarden zoals "66 min"), en (c) de pagina zelf nergens meer horizontaal scrollt op deze twee plekken. | `parts/header.html` (CSS), `style.css` (CSS + versie + changelog) |
- 4.17 — De begrippenlijst-kleurstijl (donkere/navy kop met witte tekst, afwisselende rijkleur parchment/parchment-deep) is niet langer alleen actief via de optionele class `glossary-table`, maar nu de sitebrede standaard voor élke tabel binnen `.article-content`. Op verzoek, na screenshot-voorbeeld van de gewenste look. Uitgevoerd door de kleurregels te verplaatsen van `.article-content table.glossary-table th` / `tr:nth-child(odd/even) td` naar de kale `.article-content th` / `tr:nth-child(odd/even) td` -- de eerdere lichte kop (`--parchment-deep` achtergrond, `--night` tekst) en het subtiele rgba-zebra-effect zijn hiermee vervangen. **Geen wijziging aan layout of mobiel gedrag:** `table-layout:auto`, het horizontaal-scrollen onder 640px en de `min-width:140px`-basis (v3.39) blijven ongewijzigd; dit betreft uitsluitend kleur, exact zoals bij de eerdere v4.15-aanpak. De class `glossary-table` zelf is hierdoor overbodig geworden voor kleur (bestaande tabellen met die class blijven gewoon werken, want ze krijgen de kleur nu al van de basisregel) maar blijft wel in gebruik voor de losse mobiele kolomverhouding (v4.16, `.term-cell`/`.definition-cell`) -- die regel is ongewijzigd. **Bekende beperking, bewust niet hier opgelost:** twee tabellen zijn aangetroffen (Table 1/Table 2, "Hidden Spiritual Realities"-artikel) met een inline `style="text-align:center"` op de `<th>`-elementen in de content zelf; inline stijl wint altijd van deze CSS (hogere specificiteit), dus de koptekst blijft daar gecentreerd staan i.p.v. links, ondanks de nieuwe kleur. Dit is een content-aanpassing (de inline stijl uit de artikeltekst verwijderen), geen thema-kwestie, en valt buiten deze wijziging. **Controlepunt:** op staging en live controleren dat alle bestaande tabellen op de site (niet alleen de begrippenlijst) de nieuwe navy/wit-koplook en afwisselende rijkleur tonen, dat er geen tabel is die op de oude lichte kop vertrouwde voor leesbaarheid/contrast in combinatie met eigen achtergrondkleuren in de content, en dat de eerder opgeloste mobiele problemen (scrollbalk, dichtgeknepen kolommen, leestijd-balk buiten beeld) ongewijzigd opgelost blijven. | `parts/header.html` (CSS), `style.css` (versie + changelog) |
- 4.16 — Kolomverhouding van de begrippenlijst-tabel (`.glossary-table`) op mobiel (<640px) aangepast van ~50/50 naar richting 30/70 (term-kolom smaller, definitie-kolom breder), plus iets compactere celpadding. Aanleiding: de sitebrede mobiele regel `min-width:140px` per cel (v3.39, bedoeld om onafhankelijk van kolomaantal te werken) gaf bij een 2-koloms term/definitie-tabel een gelijke ondergrens voor beide kolommen, waardoor ze op mobiel visueel even breed oogden ondanks sterk verschillende tekstlengte. **Bewust niet opnieuw `table-layout:fixed`, `<colgroup>` of een eigen media-query geïntroduceerd** — dat is exact de aanpak die bij v3.13/3.14 een platgeknepen kolom gaf en die bij v4.15 al eens als concurrerende regelset moest worden teruggedraaid vanwege onvoorspelbaar gedrag door dubbele CSS-specificiteit. In plaats daarvan: twee nieuwe, hoger-specifieke selectors (`.article-content table.glossary-table .term-cell` / `.definition-cell`, de classes staan al in de content-HTML) die uitsluitend een andere `min-width` zetten (100px / 220px) bovenop de bestaande v3.39-basisregels, zonder `!important`. `table-layout:auto` en het horizontaal-scroll-vangnet onder 640px blijven ongewijzigd van kracht — dit is dus een richting binnen het bestaande gedrag, geen afgedwongen percentage, en andere tabellen (zonder `glossary-table`-class) zijn op geen enkele manier geraakt. **Controlepunt:** op staging en live testen op een echt mobiel toestel (niet alleen devtools-resize) dat de begrippenlijst-tabel op de definities-pagina nu duidelijk asymmetrisch oogt zonder alsnog te moeten scrollen op gangbare telefoonbreedtes (~360–400px), dat een smaller scherm nog steeds netjes terugvalt op horizontaal scrollen i.p.v. dichtgeknepen tekst, en dat de "Misunderstanding / What This Website Actually Means"-tabel op dezelfde pagina (ook `glossary-table`) hetzelfde nieuwe gedrag meekrijgt. Zoals gebruikelijk ook checken: tooltips/CM Tooltip Glossary-content en overige shortcodes/widgets op de definities-pagina nog correct renderen, en na activeren de menu-locaties opnieuw instellen (Menu's → Locaties beheren). | `parts/header.html` (CSS), `style.css` (versie + changelog) |
- 4.15 — Kleuraccent (donkere kop, afwisselende rijkleur) toegevoegd voor de nieuwe begrippenlijst-tabel op de definities-pagina, via een nieuwe optionele class `glossary-table` op de tabel. **Root cause van een langere reeks mobiele scroll/layout-problemen tijdens het testen (buiten deze codebase, in het Custom HTML-blok van de pagina zelf) gevonden en hiermee voorkomen voor de toekomst:** er was los van het thema een eigen, concurrerende CSS-regelset opgebouwd (vaste kolombreedtes via `<colgroup>`, `table-layout:fixed`, een eigen media-query die de tabel op mobiel liet stapelen als kaartjes) die de bestaande, al sitebreed geldende en beproefde `.article-content table`-regels (v3.12–v3.39: `table-layout:auto`, horizontaal scrollen onder 640px, `min-width:140px` per cel) tegenwerkte. Omdat beide regelsets af en toe met vergelijkbare CSS-specificiteit op dezelfde `<table>` inwerkten, gaf dat wisselende, moeilijk te reproduceren resultaten al naargelang cache/omgeving. Opgelost door de externe regelset volledig te laten vervallen en in plaats daarvan alleen kleur toe te voegen — bovenop, niet in plaats van, de bestaande layoutregels — via twee nieuwe, doelbewust hoger-specifieke selectors (`.article-content table.glossary-table th` / `tr:nth-child(odd/even) td`) die zonder `!important` nette voorrang krijgen op de generieke `.article-content th/td`-basisregels. Kleuren zijn de bestaande sitepalet-variabelen (`--night`, `--parchment`, `--parchment-deep`), niet nieuwe hexwaarden. **Praktisch gevolg voor content-editors:** een tabel binnen `.article-content` krijgt het sitebrede tabelgedrag automatisch; voeg de class `glossary-table` toe aan een `<table>`-element (bv. `<table class="glossary-table">`) alleen als je ook de donkere kop + afwisselende rijkleur wilt. Geen `<colgroup>`, geen inline `style`, geen eigen media-query nodig — die zitten al in het thema. Gecontroleerd met een handmatige CSS-specificiteitsvergelijking tegen alle bestaande `.article-content`-tabelregels; geen `php -l` nodig, dit betreft alleen CSS. **Controlepunt:** op staging en live testen dat een `glossary-table` op de definities-pagina zowel op desktop (kleuren zichtbaar) als op mobiel (horizontaal scrollend, leesbare tekstgrootte, geen kaartweergave meer) het sitebrede tabelgedrag volgt, en dat een gewone tabel zonder deze class ongewijzigd blijft. | `parts/header.html` (CSS), `style.css` (versie + changelog) |
- 4.14 — Twee visuele correcties aan de hero, na livecontrole met de nieuwe (langere) titel/brugzin uit v4.13: (1) `.hero h1 em` stond op `font-style:normal` (bewuste contrast-keuze uit een eerdere versie, voor het goudkleurige woord "Yeshua"/"Jezus" t.o.v. de cursieve rest van de titel) — nu naar `font-style:italic` gezet, op verzoek, zodat het woord "Jezus" cursief meeloopt met de rest van de titel; vet (600) en goudkleur blijven behouden voor het contrast. (2) `.hero-name-bridge` had geen `max-width` en maar 4px margin-top — met de langere brugzin uit v4.13 rekte de regel uit tot de volle hero-breedte (1140px, tegenover 780px voor de titel en 600px voor de leadzin) en stond de tekst bovendien vrijwel tegen de onderstaartjes (descenders) van de titel aan. Opgelost met `max-width:680px` (gecentreerd) zodat de brugzin nu net als titel/leadzin netjes in het midden afbreekt over 2 regels, en `margin-top:18px` voor voldoende luchtruimte t.o.v. de titel erboven. **Controlepunt:** op staging in alle 6 aangepaste taalversies checken of de brugzin nu netjes afbreekt (langere talen zoals hinglish/es kunnen een andere regelverdeling geven dan het NL-voorbeeld), en of er nog steeds geen witruimte overblijft voor de Hebreeuwse (he) versie waar de brugzin leeg is (`:empty` regel is ongewijzigd, dus dit zou moeten blijven werken). | `parts/header.html` (hero h1 em), `style.css` (hero-name-bridge + versie/changelog) |
- 4.13 — Hero-titel omgedraaid van "Terug naar wie Yeshua werkelijk was" naar "Terug naar wie Jezus werkelijk was" (en het equivalent in de andere talen), met een herschreven `hero_name_bridge` die nu de "reveal"-volgorde volgt: start bij de bekende naam (Jezus), onthult daarna de eigen Hebreeuwse/native naam (Yeshua), en sluit af met de identiteitsclaim (Joodse Messias). Reden: de vorige titel ("wie Yeshua werkelijk was") veronderstelde dat de bezoeker Yeshua al kent; de nieuwe opbouw vertrekt bij het bekende (Jezus, ook consistent met de domeinnaam jesusmessiah.online) en leidt de bezoeker bewust naar de onthulling. Toegepast op 6 van de 7 talen (nl/en/hinglish/hi/es/zh). **Zh was al consistent** (titel gebruikte al "耶稣"/Jezus) — daar is alleen `hero_name_bridge` herschreven naar de nieuwe structuur, de titel zelf was ongewijzigd. **He (Hebreeuws) bewust ongewijzigd** — in het Hebreeuws is "ישוע" al de enige/native term, de Jezus-Yeshua-onthullingslogica is daar niet van toepassing (zie ook toelichting bij v4.12). `intro_p` is dit keer NIET aangepast — de bestaande introtekst blijft ongewijzigd staan; de scherpere, corrigerende boodschap ("niet de Jezus van de kerkelijke traditie") is bewust NIET doorgevoerd in deze versie op verzoek. **Controlepunten:** staging testen op alle 6 aangepaste taalversies + de ongewijzigde he-versie, mobiele weergave van de langere brugzin (kan meer regels innemen dan de vorige, kortere versie), en controleren of eventuele interne links/ankers die naar "Yeshua" in de titel verwezen (bv. `#hero` anchor-tekst, screenreader-verwijzingen) nog correct zijn. | `functions.php` (hero_h1_em + hero_name_bridge in 6 taalblokken), `style.css` (versie + changelog) |
- 4.12 — Nieuwe naam-brugzin in de hero, direct onder de titel: "Yeshua — beter bekend als Jezus/Jesus/etc. — maar dan zoals Hij werkelijk was: de [Joodse Messias]." Aanleiding: twijfel of "Yeshua" in de hero-titel verwarrend is voor bezoekers die de naam niet kennen; oplossing behoudt "Yeshua" in de titel (kern van de site-missie: terug naar de Joodse identiteit) en legt de brug naar de bekendere naam er direct onder, i.p.v. de titel zelf te wijzigen. Nieuwe vertaalsleutel `hero_name_bridge` toegevoegd aan `yeshua_online_i18n_strings()` voor 6 van de 7 talen (nl/en/hinglish/hi/es/zh); nieuw `<p class="hero-name-bridge">` in `templates/front-page.html`, nieuwe CSS-regel in `style.css` (kleiner, goudkleurig, met `:empty { display:none }` voor talen zonder ingevulde tekst — géén onopgemaakte witruimte). **Bewust NIET ingevuld voor Hebreeuws (he):** in het Hebreeuws is "ישוע" al de standaardterm, een brug naar "Jezus" is daar niet vanzelfsprekend en het onderscheid ישו/ישוע is theologisch gevoelig — aanbevolen om dit, indien gewenst, apart door een native (Messiaans-Joodse) Hebreeuwse spreker te laten formuleren in plaats van een vertaling te forceren. **Losstaande inconsistentie geconstateerd, niet gewijzigd:** de Chinese (zh) hero-TITEL zelf gebruikt al "耶稣" (Jezus) i.p.v. een Yeshua-transliteratie zoals bij de andere 6 taalversies — de nieuwe brugzin legt het Hebreeuwse-naam-verband voor het Chinese publiek nu alsnog, maar de titelkeuze zelf viel buiten deze opdracht; overweeg dit apart te bekijken. **Controlepunten om na te lopen:** staging testen op alle 7 taalversies (met name de 2 waar bewust geen/afwijkende brugzin staat), mobiele weergave van de hero (extra regel kan de "nieuwe artikelen"-tegel iets lager duwen), en RTL-weergave (Hebreeuws) om te bevestigen dat de lege paragraaf inderdaad onzichtbaar blijft. | `functions.php` (6 taalblokken), `templates/front-page.html`, `style.css` (versie + changelog) |
- 4.11 — Termen & definities-balk (v4.10) onthoudt nu of iemand 'm heeft weggeklikt, voor de rest van dat bezoek. Op verzoek na preview-feedback: bij nader inzien te opdringerig om bij ELKE paginaweergave terug te keren, ook binnen hetzelfde bezoek. Balk gebruikt nu `sessionStorage` (key `yeshuaTermsBannerDismissed`) — eenmaal weggeklikt blijft hij verborgen zolang de browser/tab open blijft; bij een nieuw bezoek (nieuwe sessie, bv. na het sluiten van de browser) verschijnt hij weer. Bewust géén `localStorage` (dat zou 'm permanent verbergen, ook bij een volgend bezoek — niet gevraagd). `sessionStorage`-check gebeurt synchroon vóór de rest van het script, om oplichten van de balk te voorkomen bij een teruggekeerde bezoeker binnen dezelfde sessie; try/catch eromheen voor browsers met sessionStorage uitgeschakeld (bv. strikte privacy-instellingen) — balk verschijnt dan gewoon zoals in v4.10 (geen onthouding, geen crash). Gecontroleerd met `php -l`.
- 4.10 — Nieuwe melding onder de header op elke pagina: "Nieuw hier? Sommige termen op deze site hebben een specifieke betekenis. Lees eerst onze termen & definities om alles goed te begrijpen.", met link naar https://www.jesusmessiah.online/definitions-theological-framework/. Aanleiding: bezoekers landen vaak direct op een artikelpagina (zoekmachine, gedeelde link) zonder eerst de termen/definities-context te zien, en haken daardoor soms af op inhoud die anders leest dan verwacht. Uitgevoerd als vaste balk (geen pop-up) in `parts/header.html`, direct onder de sticky header — bewust géén `localStorage`/cookie-onthouding: de balk verschijnt bij ELK paginabezoek opnieuw (ook voor vaste bezoekers), en verdwijnt alleen voor de rest van dat ene bezoek zodra iemand op het kruisje klikt. Positioneert zichzelf via JS (`getComputedStyle` op de header + `offsetHeight`) net onder de sticky header, zodat hij meebeweegt bij scrollen en correct blijft staan bij het admin-bar-hoogteverschil. Vertaalsleutels `terms_banner_pre`/`terms_banner_link`/`terms_banner_post` toegevoegd aan alle 7 taalblokken in `yeshua_online_i18n_strings()` (sluitknop hergebruikt de bestaande `new_articles_banner_close`-vertaling); Hindi- en Hebreeuwse tekst zijn een eerste concept — net als eerdere vertaalslagen in dit project aanbevolen om door een native speaker te laten nalezen vóór livegang, gezien de theologische lading. De linkende pagina is nu voor alle taalversies dezelfde (Engelstalige) URL; als er per taal een eigen vertaalde termen-pagina bestaat, moet die URL nog per taal worden ingevuld. **Controlepunten om na te lopen:** artikelen met tooltips/shortcodes/widgets in de directe omgeving van de header (balk mag niets overlappen), het menu (`[yeshua_main_menu]`, balk staat er los van maar deelt de sticky-ruimte), en de mobiele weergave (balk is getest op smalle breedte via eigen media query, maar controleer samen met het uitklapmenu). Gecontroleerd met `php -l`.
- 4.09 — Leestijd-label maakt nu onderscheid tussen "Samenvatting", "Inleiding" en "Instructie" i.p.v. altijd "Samenvatting" te tonen. Aanleiding: een artikel met een "Inleiding"-kop toonde toch het label "Leestijd samenvatting" — verwarrend voor bezoekers, die dan een samenvatting zoeken die er niet is. `yeshua_online_reading_time_find_intro_heading_end()` geeft nu ook terug WELK type kop gevonden is (`kind`: 'summary'/'intro'/'instruction'), doorgegeven via `yeshua_online_reading_time_compute()`. Het label op zowel de artikelpagina als de categorie-kaartjes volgt nu dat type, in alle 6 talen (nl/en/es/hi/zh/he). Het label voor het tweede deel ("Uitgebreide uitleg") blijft ongewijzigd, past bij alle drie de kop-types. Gecontroleerd met `php -l` en een gesimuleerde test op een "Inleiding"-kop: `kind` komt correct terug als "intro".
- 4.08 — Fix voor artikelen waarbij een uitgelichte afbeelding (met eigen `<hr>` erna, bv. onder een bijschrift) VOOR de samenvatting-kop staat. De vorige logica zocht naar een herkenbare kop vóór de EERSTE `<hr>` in het artikel; bij deze opbouw komt die eerste `<hr>` al vóór de kop te staan, waardoor de kop nooit gevonden werd en de splitsing uitbleef. Omgedraaid: de code zoekt nu eerst de samenvatting/inleiding/instructie-kop (waar dan ook in het artikel), en gebruikt dan de eerstvolgende `<hr>` ná die kop als scheidingspunt. Nieuwe functie `yeshua_online_reading_time_find_intro_heading_end()` vervangt `yeshua_online_reading_time_segment_has_intro_heading()`. Getest met een gesimuleerde versie van deze exacte structuur (afbeelding → hr → "Summary"-kop → tekst → hr → hoofdtekst): `has_summary` nu `true`, was `false`. **Bekend, geaccepteerd risico:** omdat nu in het hele artikel gezocht wordt i.p.v. alleen vóór de eerste `<hr>`, zou een toevallige kop met een van de trefwoorden verderop in een artikel (bv. "Samenvatting van hoofdstuk 3") ook een splitsing kunnen triggeren. Gecontroleerd met `php -l`: geen syntaxfouten.
- 4.07 — **Kritieke fix: de leestijd-splitsing werkte hoogstwaarschijnlijk nog nooit, bij geen enkel artikel.** Root cause: `yeshua_online_reading_time_compute()` splitste op `preg_split( '/<hr\s*\/?>/i', $raw, 2 )`, wat alleen een KALE `<hr>` of `<hr/>` herkent. WordPress' eigen "Scheidingslijn"-blok schrijft echter altijd een class-attribuut mee (bv. `<hr class="wp-block-separator has-alpha-channel-opacity"/>`), waardoor deze regex nooit matchte en de code altijd op de fallback (één totale leestijd) terugviel — ongeacht welke kop erboven stond of welke trefwoorden herkend werden. Bevestigd met een losse testregel: oude regex → 1 stuk (geen splitsing) op tekst met een realistische WordPress-scheidingslijn; nieuwe regex → 2 stukken (wél splitsing). Regex aangepast naar `/<hr\b[^>]*>/i`, die `<hr>` herkent ongeacht eventuele attributen. Dit verklaart met terugwerkende kracht waarom de kop-detectie-verbeteringen van v4.05/v4.06 geen zichtbaar effect hadden op staging — die losten een secundair probleem op, terwijl dit de eigenlijke blokkade was. Gecontroleerd met `php -l`: geen syntaxfouten.
- 4.06 — "Introductie" toegevoegd aan de herkende inleiding/samenvatting/instructie-trefwoorden (naast de al bestaande "introduction", "inleiding", "samenvatting" en "instructie") — deze Nederlandse variant ontbrak nog, waardoor artikelen met een kop als "Introductie" ten onrechte geen leestijd-splitsing kregen. Ter controle nagelopen op tikfouten in de eerder toegevoegde labels en vertaalsleutels (leestijd + weergaveschakelaar) — geen gevonden. Losse spelfouten in bestaande artikelkoppen zelf (bv. "Samenvtting") vallen buiten deze fix; dat corrigeer je het beste rechtstreeks in het artikel, zie toelichting in de chat.
- 4.05 — Leestijd-splitsing (samenvatting/instructie + uitgebreide uitleg) hersteld en uitgebreid, na preview-overleg. (1) De detectie van een inleiding/samenvatting/instructie-kop keek voorheen alleen naar de ALLEREERSTE kop in de content; bij artikelen met een uitgelicht kaartje/afbeelding vóór de echte samenvatting-kop (bv. "The Seed of the Woman...") werd de splitsing daardoor nooit herkend. yeshua_online_reading_time_segment_has_intro_heading() kijkt nu naar alle koppen in het stuk vóór de eerste <hr>. "instructie"/"instruction"/"instrucción" toegevoegd aan de herkende trefwoorden. Labels op de artikelpagina hernoemd naar "Leestijd samenvatting" / "Leestijd uitgebreide uitleg". (2) Rekenlogica samengevoegd in gedeelde functie yeshua_online_reading_time_compute(), zodat de artikelpagina en de categorie-kaartjes gegarandeerd dezelfde splitsing tonen. (3) Nieuw dynamisch block yeshua/archive-reading-time toont de (gesplitste) leestijd direct onder de titel op de categorie-kaartjes, met compactere labels ("Samenvatting"/"Uitgebreide uitleg") i.v.m. de beperkte kaartbreedte; datum blijft bewust onderaan (beslissingsinfo boven, herkomstinfo onderaan). (4) Reacties-teller op de kaartjes tijdelijk verborgen (comments-functie staat nog niet live) via een losse $show_comments-vlag in yeshua_online_render_archive_meta_for_post() — op true zetten zodra reacties live gaan, verder geen wijziging nodig; bijvangst: de oude regel toonde ook het woord "read" altijd hardcoded in het Engels, ongeacht de paginataal — verdwenen samen met het verwijderen van die regel. (5) Weergaveschakelaar op categoriepagina's ("Weergave"/"Tegels"/"Lijst") bleek volledig buiten het vertaalsysteem te staan — hardgecodeerd Nederlands, ook op andere taalversies. Omgezet naar [yeshua_t key="..."] en de {{}}-attribuutmarker, met 4 nieuwe vertaalsleutels (archive_view_switcher_aria/label/grid/list) in alle 7 talen. **Nog te doen vóór livegang:** vertalingen van de nieuwe leestijd- en weergave-teksten voor Hindi (beide registers), Chinees en Hebreeuws laten nalopen door een native speaker, zoals bij eerdere vertalingen in dit project.
- 4.04 — Metadata op artikelkaarten (datum, leestijd en reacties) visueel verkleind en compacter gemaakt; alleen presentatie, geen wijziging aan de dynamische berekening.
- 3.99 — Categorie-lijstweergave compacter gemaakt n.a.v. preview: de kaart gebruikt nu twee kolommen (inhoud + actieknop) i.p.v. een aparte lege linkerkolom; titel, samenvatting en metadata benutten daardoor vrijwel de volledige kaartbreedte. De samenvatting in lijstweergave wordt uitgevuld (text-align:justify) voor een rustigere tekstkolom en de verticale padding is verkleind. De bestaande tegelweergave blijft ongewijzigd. Alleen `parts/header.html` aangepast voor de lijst-CSS; gecontroleerd met `php -l` op functions.php.
- 3.97 — JM-merkkleuren (Goud #c99a3d/#dba63c, Navy #122142/#0a1424, Parchment #f2ede2) toegevoegd aan het "Tekstkleur"-palet van de Klassieke Editor (Advanced Editor Tools/TinyMCE), via nieuwe functie yeshua_online_tinymce_brand_colors() op tiny_mce_before_init. TinyMCE's textcolor_map vervangt het hele palet i.p.v. erop aan te vullen, dus is het volledige standaard WordPress-kleurenpalet overgenomen (niets verdwenen) met de JM-kleuren als extra rij erachter. Geen wijziging aan bestaand gedrag elders. Gecontroleerd met php -l: geen syntaxfouten.
- 3.96 — Body-tekst van pagina's/artikelen (.article-content p) is nu standaard uitgevuld (text-align:justify) i.p.v. links uitgelijnd, op verzoek als vaste stijlregel voor alle taalversies. Taalbewust gemaakt: Latijns schrift (NL/EN/ES/Hinglish) en Hindi gebruiken text-justify:inter-word (rekt woord-spaties uit); Chinees krijgt een eigen regel op html[lang^="zh"] met text-justify:inter-character, omdat Chinees geen woord-spaties heeft en de browser anders niets kan uitrekken. Hebreeuws (RTL) volgt de basisregel ongewijzigd -- CSS justify werkt vanzelf rechts-naar-links zodra dir="rtl" staat, wat al gebeurt via de bestaande yeshua_online_is_rtl_lang()-filter. Op schermen tot 480px wordt justify uitgeschakeld (terug naar links uitgelijnd), in elke taal, om de "rivertjes"-van-witruimte te voorkomen die uitgerekte woord-spaties op smalle kolommen geven. Geen PHP gewijzigd, alleen style.css.
- 3.95 — Footerlink "Over deze website" (parts/footer.html) wees via [yeshua_href key='over_contact'] naar de categorie-slug 'over-en-contact', die niet correct resolveerde en zo op de homepage uitkwam. Omgebouwd naar het bestaande, betrouwbaardere paginapatroon (zelfde aanpak als de contactpagina): nieuwe key 'transparantie' toegevoegd aan yeshua_online_i18n_page_links() (NL-slug 'over-deze-website'), footer.html gebruikt nu [yeshua_page_href key='transparantie']. Vereist een WordPress-Pagina met exact die NL-slug (en voor volledige meertalige werking: Polylang-vertalingen per taal) -- zonder die pagina geeft de shortcode '#' terug, zelfde stille-fallback-gedrag als de rest van dit systeem. Gecontroleerd met php -l: geen syntaxfouten.
- 3.94 — Vervolg op v3.93: ook home_url('/') bleek op productie de paginaslug-URL van de vaste voorpagina terug te geven, zelfs voor de standaardtaal (Engels), ondanks schone instellingen bij Instellingen > Algemeen -- wijst op een Polylang-filter op de 'home_url'-hook. yeshua_online_replace_search_action() gebruikt nu site_url() i.p.v. home_url(), een ander WordPress-veld dat Polylang doorgaans niet op dezelfde manier herschrijft. Nog niet 100% bevestigd of dit het probleem volledig oplost. Nieuw diagnose-blokje bovenaan het testpaneel (Gereedschap > Yeshua zoekindex): toont per taal wat site_url()/home_url()/pll_home_url() daadwerkelijk teruggeven, zodat dit voortaan in wp-admin te zien is i.p.v. via screenshots heen en weer. Gecontroleerd met php -l: geen syntaxfouten. — KRITIEKE fix na livegang van v3.92: zoeken werkte niet op productie, ondanks succesvolle staging-tests. Oorzaak: yeshua_online_replace_search_action() gebruikte pll_home_url(), die op productie de volledige paginaslug-URL van de vaste voorpagina teruggaf (bv. .../home-cloud-nl/) i.p.v. de kale taal-root (.../nl/) -- exact hetzelfde onderliggende probleem als de oorspronkelijke v3.77-bug (WordPress negeert ?s= op een paginaslug-URL). Bevestigd: .../nl/ laadt de homepage prima, maar het zoekformulier postte naar .../home-cloud-nl/. Taal-root wordt nu handmatig opgebouwd (Engels = standaardtaal zonder prefix, overige talen met /{taalcode}/-prefix) i.p.v. via pll_home_url(). Gecontroleerd met php -l: geen syntaxfouten. — Spring-link laat voortaan het WOORD zelf oplichten i.p.v. de eerste acht woorden van de hele alinea. Nieuwe functie yeshua_online_build_word_text_fragment() gebruikt de browser-ondersteunde "prefix-,woord,-suffix"-syntax van de Text Fragment-functie: een paar woorden vóór/na dienen als context zodat de browser de juiste plek vindt, maar alleen het woord ertussen wordt gemarkeerd. Zelfde evenredige woordstam-logica als yeshua_online_find_relevant_paragraph() (v3.91) hergebruikt, voor consistentie tussen "welke alinea" en "welk woord daarin". Valt terug op de oude eerste-acht-woorden-frase als er onverhoopt geen specifiek woord gevonden wordt. Gecontroleerd met php -l: geen syntaxfouten. — Fix n.a.v. staging-feedback: bij "volharding" sprong de spring-link naar de verkeerde alinea. Oorzaak: de vaste woordstam-lengte van 3 tekens ("vol") matchte ook "volmaakte" en "volledig" -- compleet andere woorden die toevallig hetzelfde beginnen. yeshua_online_find_relevant_paragraph() gebruikt nu een stam-lengte die evenredig is met de woordlengte (helft van de woordlengte, minimaal 3) i.p.v. altijd 3 tekens: korte woorden (bv. "redding") houden hun korte stam nodig voor de eerder opgeloste redding/gered-vervoeging, langere woorden (bv. "volharding" -> "volha") krijgen een langere, specifiekere stam. Blijft bewust een onverankerde substring-match (geen woordgrens-eis) -- die zou "red" in "gered" (middenin het woord) juist weer breken. Gecontroleerd met php -l: geen syntaxfouten. — "+ Zoektips" verwijderd uit de smalle header-nav-zoekpopup (280px breed) waar de tekst buiten de box brak; blijft ongewijzigd op de resultatenpagina en categoriepagina's. Daar de tekst 24px naar rechts opgeschoven (margin-left op .search-tips). — Resultatenlijst (badge + titel + fragment samen) laat 52px inspringen t.o.v. de sectiekop, na drie preview-iteraties tot de juiste maat gevonden. Sectiekoppen ("Exacte resultaten", "Mogelijk ook interessant") blijven ongewijzigd, niet ingesprongen. .search-result-list en .search-section-legend aangepast in parts/header.html. — Beide zoekresultatensecties omgebouwd van kaartjes-grid naar een compacte rijenlijst, na overleg over overzichtelijkheid (voorstel eerst als preview getoond, daarna ook op de AI-sectie toegepast op verzoek). Nieuwe CSS-classes .search-result-list/.search-result-row (los van de bestaande .article-grid/.article-card, die nog gebruikt worden op categoriepagina's -- niet aangeraakt). Badge + titel (zelf de link) + kort fragment op één regel, dun lijntje tussen resultaten, geen kaartrand/categorielabel/losse "Lees artikel"-knop meer. AI-sectie: "Gouden randje" vervangen door een expliciete "Betekenis"-badge (goudkleurig), voor consistentie met de badge-aanpak van de exacte-resultatensectie. Gecontroleerd met php -l: geen syntaxfouten. — Drie verbeteringen aan "Exacte resultaten" na staging-feedback ("ik vind het niks"). (1) Term-bewust fragment: nieuwe yeshua_online_find_relevant_paragraph() (uit yeshua_online_smart_result_url() getrokken, nu gedeeld) + nieuwe yeshua_online_term_aware_snippet() -- tekst-matches tonen nu het daadwerkelijke fragment met de zoekterm erin, niet meer de generieke post-samenvatting. (2) Relevantie-sortering + lagere limiet: yeshua_online_get_literal_content_matches() telt nu ook hoe vaak de zoekterm in het artikel voorkomt; yeshua_online_get_exact_results() sorteert tekst-matches daarop (aflopend) vóór het afkappen. YESHUA_SEARCH_EXACT_MAX_RESULTS verlaagd van 20 naar 10. (3) Badge altijd tonen (niet meer alleen bij een mix van titel-/tekst-matches) -- bij deze site-omvang leverden de meeste zoekopdrachten toch al vrijwel uitsluitend tekst-matches op, waardoor de badge in de praktijk bijna nooit verscheen. Gecontroleerd met php -l: geen syntaxfouten. — Fix n.a.v. staging-feedback: tekst-matches in "Exacte resultaten" (sinds v3.83) kregen geen spring-naar-alinea-link, alleen een link naar de bovenkant van het artikel -- juist bij een tekst-match (het woord zit ergens middenin een lang artikel) is dat het meest nodig. yeshua_online_get_literal_content_matches() herzien: onthoudt nu per match ook de specifieke chunk_text waarin alle zoekwoorden samen voorkomen (chunk_index toegevoegd aan de query, chunks per artikel op volgorde doorzocht), i.p.v. alleen een lijst post_id's. yeshua_online_get_exact_results() geeft nu per resultaat een array ('type' + 'chunk_text') terug i.p.v. alleen een type-string. yeshua_online_shortcode_exact_results_section() bouwt voor 'content'-resultaten nu een link via de bestaande yeshua_online_smart_result_url() (dezelfde term-bewuste alinea-selectie als de AI-sectie, v3.82); 'title'-resultaten blijven een gewone link (ongewijzigd). Gecontroleerd met php -l: geen syntaxfouten. — TWEEDE kritieke hotfix, gevonden via een ECHTE PHP-syntaxcontrole (php -l) i.p.v. handmatige/heuristische scripts (die faalden, zie v3.84's notitie). v3.84 loste één probleem op (ontbrekende functie-declaratieregel) maar bevatte zelf nog een tweede, aparte fout uit dezelfde v3.83-bewerking: het if-blok rond de nieuwe constante YESHUA_SEARCH_EXACT_MAX_RESULTS werd nooit gesloten (ontbrekende `}`), waardoor alle code erna -- inclusief yeshua_online_get_smart_search_results() zelf -- proces-technisch binnen dat if-blok kwam te vallen, met een "Unclosed brace"-fatal error tot gevolg (WordPress' eigen crash-scherm: "There has been a critical error"). Ontbrekende `}` toegevoegd. `php -l functions.php` bevestigt nu: "No syntax errors detected". Vanaf deze versie wordt elke wijziging aan functions.php vóór levering gecontroleerd met een echte PHP-linter, niet meer met eigen heuristische scripts. — KRITIEKE hotfix: v3.83 bevatte een fatale PHP-fout die de hele site brak (elke shortcode ná een bepaald punt in functions.php bleef onverwerkt staan, inclusief het al langer bestaande [yeshua_main_menu] -- niet alleen de nieuwe zoekfunctie-shortcodes). Oorzaak: bij het invoegen van yeshua_online_get_exact_results() is per ongeluk de functie-declaratieregel van de daaropvolgende yeshua_online_get_smart_search_results() overschreven, waardoor de rest van die functie als losse, niet-omsloten code in het bestand terechtkwam -- een PHP fatal error die alle code erna onbereikbaar maakte. Regel hersteld. Bevestigd via een handmatige, inspringings-bewuste scan op ontbrekende functie-omhulling door de rest van het bestand: geen andere plekken met hetzelfde probleem gevonden. — "Exacte resultaten" uitgebreid van titel-only naar titel + letterlijke tekst-matches, na overleg (optie A gekozen: badges per kaartje i.p.v. samengevoegde lijst). Nieuwe functies yeshua_online_get_literal_content_matches() (doorzoekt de bestaande NL/EN-zoekindex, woordgrens-matching zoals de titelzoekfunctie) en yeshua_online_get_exact_results() (voegt titel- en tekst-matches samen, titel eerst, afgekapt op nieuwe constante YESHUA_SEARCH_EXACT_MAX_RESULTS = 20). Nieuwe shortcode [yeshua_exact_results_section] vervangt zowel [yeshua_exact_results_heading] als het native wp:query/wp:post-template/wp:query-pagination-blok in templates/search.html -- bewust GEEN paginering meer voor deze sectie (afgesproken: bij ~130 artikelen zelden nodig, samengevoegde paginering over twee bronnen te complex voor het voordeel). Badge per kaartje ("Titel"/"In tekst gevonden"), alleen zichtbaar als de resultatenlijst een mix van beide bevat. Hoofdquery haalt nu in één keer YESHUA_SEARCH_EXACT_MAX_RESULTS titel-matches op i.p.v. de site-brede standaardinstelling. AI-sectie sluit voortaan ook tekst-matches uit (niet meer alleen titel-matches). — Fix n.a.v. staging-feedback: spring-link koos altijd blind de EERSTE alinea van het gevonden fragment, ongeacht of die alinea inhoudelijk iets met de zoekterm te maken had (bv. bij "redding" sprong het naar "Dit is misschien wel het moeilijkste onderdeel van..." -- correct artikel, nietszeggend ankerpunt). yeshua_online_smart_result_url() krijgt nu de zoekterm mee (nieuwe 4e parameter $term) en kiest bij voorkeur de eerste alinea die een woordstam (3 tekens, kort gehouden i.v.m. Nederlandse werkwoordsvervoeging zoals redding/gered) van de zoekterm bevat. Vindt niets, dan blijft het oude gedrag (eerste alinea) als vangnet intact. — Twee verbeteringen na overleg. (1) Spring-naar-paragraaf-link geldt nu voor ALLE slimme-zoekresultaten, niet meer alleen chunk_index > 0 -- yeshua_online_smart_result_url() bouwde voorheen alleen een link als het best passende fragment toevallig niet het eerste stuk van een artikel was; dat was toeval, geen relevantie-indicator, en gaf inconsistent gedrag (sommige, "minder relevante" resultaten sprongen wél, andere niet). (2) Nieuwe taalcheck op de zoekresultatenpagina: yeshua_online_detect_query_language() + shortcode [yeshua_search_language_notice] waarschuwt als een zoekterm niet in de paginataal lijkt te zijn. Waterdicht via schriftherkenning voor Hebreeuws/Chinees/Hindi (eigen alfabet/schrift = onmiskenbaar bewijs); voor Nederlands/Engels/Spaans (alle Latijns schrift) via een korte, ondubbelzinnige woordenlijst -- bewust STIL bij een onherkend woord (bv. een theologische term) i.p.v. een foutieve gok. Hinglish bewust uitgesloten (te vermengd met Engels om betrouwbaar te onderscheiden). Nieuwe vertaalsleutel search_lang_mismatch in alle 7 talen. — Kritieke fix n.a.v. staging-test v3.79 (dankzij de nieuwe diagnose meteen zichtbaar): yeshua_online_voyage_rerank() controleerde en las het verkeerde JSON-veld ('results' i.p.v. 'data') uit Voyage's antwoord. Gevolg: ELKE geslaagde reranker-aanroep (HTTP 200, met prima scores) werd door de code als mislukt behandeld, waarna stil werd teruggevallen op de oude cosine-drempel -- de nieuwe reranker deed dus feitelijk nooit iets, ook niet toen 'ie perfect werkte. Veldnaam gecorrigeerd naar 'data' op beide plekken (leegte-check en de foreach die scores uitleest). Bevestigd met echte staging-data: "redding" gaf voorheen onterecht 0 resultaten, terwijl Voyage al die tijd sterke, goed onderscheidende scores teruggaf (0,82 / 0,60 / 0,52 / 0,48 / ...). — Fix n.a.v. staging-test v3.78: testpaneel zei bij "redding" en "warning" alleen "geen resultaten boven de drempelwaarde" -- gaf geen enkel inzicht of dat kwam door een lege zoekindex, een mislukte reranker-aanroep, of gewoon een te hoge drempel. Nieuwe diagnostische functie yeshua_online_get_smart_search_results_debug() (uitsluitend voor het testpaneel, publieke zoekfunctie ongewijzigd): toont voortaan het aantal indexrijen voor de gekozen taal, een eventuele embedding- of reranker-foutmelding apart, en de VOLLEDIGE kandidatenpool met cosine- én rerank-score per artikel -- ook de kandidaten die onder de drempel vallen (gemarkeerd met ✓/·). Zo is in één test te zien in welke stap het misgaat. — Drie samenhangende zoekverbeteringen, op verzoek na overleg (bugmelding: zoeken op "warning" leverde niets op, ondanks relevante content). NIET automatisch live — dit vraagt eerst een backfill-onafhankelijke staging-test, zie testpaneel. (1) Titel-zoekfunctie matcht voortaan automatisch vanaf het BEGIN van een woord i.p.v. overal in de titel (yeshua_online_title_only_search(), REGEXP i.p.v. LIKE) — "wet" vindt "wetten", niet meer "geweten". Een optionele trailing * (bv. "wet*") wordt herkend maar heeft bewust hetzelfde effect als zonder, want de verruiming gebeurt al automatisch. (2) Nieuwe reranker-stap in de slimme zoekfunctie (yeshua_online_voyage_rerank(), nieuwe /v1/rerank-aanroep bij Voyage, model rerank-2.5): i.p.v. meteen alles onder de cosine-drempel weg te gooien, wordt een kandidatenpool van de 20 best scorende fragmenten (YESHUA_SEARCH_RERANK_CANDIDATE_POOL) alsnog opnieuw beoordeeld door de reranker, die zoekterm+tekst SAMEN leest i.p.v. twee losse vectoren te vergelijken — bedoeld om korte, kale zoekwoorden beter te laten scoren. Nieuwe drempelwaarde YESHUA_SEARCH_RERANK_THRESHOLD (startwaarde 0,3, NOG NIET gevalideerd, andere schaal dan de cosine-score). Bij een reranker-storing valt de functie terug op de oude cosine-drempel (YESHUA_SEARCH_SMART_THRESHOLD) — zelfde "stil falen"-filosofie als de rest van dit systeem. Testpaneel (Gereedschap → Yeshua zoekindex) toont nu zowel de cosine- als de rerank-score naast elkaar, om de nieuwe drempelwaarde te kunnen valideren vóór livegang. (3) Nieuwe shortcode [yeshua_search_tips]: klein uitklapbaar "Zoektips"-blokje (zelfde <details>-patroon als het header-zoekicoon), geplaatst bij alle drie de zoekvelden (header, categoriepagina's, resultatenpagina), legt uit dat een los woord én een hele vraag werken, en dat een * optioneel is. Nieuwe vertaalsleutels search_tips_label/search_tips_text in alle 7 talen (NL/EN zelf geschreven; Hinglish/HI/ES/ZH/HE aanbevolen voor te leggen aan een native speaker vóór livegang, zoals bij eerdere vertalingen in dit project). **Nog te doen vóór livegang:** op staging testen met "warning" en een paar andere korte woorden via het testpaneel, rerank-drempel bijstellen op basis daarvan, en de vertalingen van punt 3 laten nalopen. — Kritieke fix: het zoekveld deed helemaal niets (invullen van een zoekterm leverde gewoon de normale pagina terug, geen resultaten, geen foutmelding). Oorzaak: alle drie de plekken waarmee het .cat-search-formulier voorkomt (header-zoekicoon, categoriepagina's, resultatenpagina zelf) hadden action="" staan, dus het formulier postte terug naar de HUIDIGE pagina-URL. Op een gewone WordPress-pagina/categorie-URL (met "mooie" permalink) geeft WordPress voorrang aan de pagename/category_name-rewrite boven de s-parameter, waardoor is_search() nooit true werd en search.html nooit geladen werd — ook al stond ?s=... gewoon zichtbaar in de adresbalk. Opgelost door action="" te vervangen door de nieuwe marker {{search_action}}, die via een nieuwe, met priority 5 vóór de bestaande vertaal-marker-vervanger draaiende filter (yeshua_online_replace_search_action) wordt omgezet naar de root-URL van de huidige taalversie (via pll_home_url()). Er bleek geen AJAX-onderschepping op dit formulier te zitten (nooit gebouwd) — de fix maakt gebruik van de al langer bestaande, werkende search.html-route.
- 3.76 — Placeholder-tekst van het zoekveld (search_placeholder, gebruikt in zowel het header-zoekicoon als de resultatenpagina) aangepast naar "Zoek of omschrijf een onderwerp…" (en per taal), zodat duidelijker is dat zowel een los woord als een hele beschrijving/vraag werkt. Alle 7 talen bijgewerkt. De categorie-zoekbalk (cat_search_placeholder, "Zoek in deze categorie…") blijft ongewijzigd — dat was niet het onderwerp van deze aanpassing.
- 3.75 — Fase 5: zoekicoon in de header, overal op de site zichtbaar (desktop en mobiel). Nieuw <details class="header-search"> element in parts/header.html, links van de taalwissel-knop, in dezelfde stijl (rond icoon, dropdown-paneel bij klikken, sluit bij klik erbuiten). Hergebruikt de bestaande .cat-search-opmaak en de kruisje-logica uit v3.72/v3.73 (geen dubbele code). Focus springt automatisch naar het invoerveld bij openen. Mobiele variant: compact, rond icoon, zelfde behandeling als de taalwissel-knop op smalle schermen.
- 3.74 — Lengtebeperking op zoekopdrachten (150 tekens), op drie niveaus: maxlength-attribuut op beide zoekvelden (archive.html, search.html), een pre_get_posts-hook die de zoekterm serverside afkapt (dekt ook een rechtstreeks aangepaste ?s=-URL, buiten het veld om), en een laatste vangnet direct in yeshua_online_get_smart_search_results() zelf (dekt ook het testpaneel in wp-admin). Voorkomt onnodige Voyage-kosten bij een kunstmatig lange zoekvraag.
- 3.73 — Fix op het kruisje uit v3.72: werkte helemaal niet op staging. Oorzaak: het script staat in parts/header.html, dat eerder op de pagina wordt weergegeven dan het zoekveld zelf (dat in de hoofdinhoud van archive.html/search.html staat) -- het script probeerde het zoekveld te vinden voordat dat deel van de pagina bestond. Nieuwe code nu binnen een DOMContentLoaded-listener, zodat 'm pas draait als de hele pagina (inclusief het zoekveld) geladen is. Bestaande scripts (menutoggle, taalwissel) ongewijzigd gelaten, die stonden al goed.
- 3.72 — Eigen kruisje-knop toegevoegd aan alle zoekvelden (categoriepagina's + zoekresultatenpagina), consistent qua stijl in elke browser i.p.v. te vertrouwen op het (per browser wisselende) ingebouwde exemplaar. Verschijnt alleen zodra er tekst in het veld staat, verbergt zichzelf weer bij een leeg veld. Nieuwe vertaalsleutel search_clear_aria (7 talen). Nieuwe CSS: .search-clear + varianten, plus onderdrukking van de WebKit-standaard cancel-button.
- 3.71 — Fix: het gouden randje op de slimme-resultaat-kaartjes was onzichtbaar. Oorzaak: de .article-card--smart-regel (border-left) stond in het bestand vóór de basisstijl .article-card (border op alle zijden) — bij gelijke CSS-specificiteit wint de later gedefinieerde regel, dus de basisstijl overschreef steeds de linkerrand terug naar normaal. Regel verplaatst naar direct ná .article-card.
- 3.70 — Fix: grote lege ruimte tussen "Exacte resultaten (0)" en "Mogelijk ook interessant" weggehaald. Oorzaak: een overgebleven, inmiddels ongebruikte "search-empty-state"-div in templates/search.html had nog zijn oude padding (50px), ook al bevatte hij geen tekst meer sinds de symmetrische-kopjes-herziening (v3.66). Div uit de template gehaald.
- 3.69 — Layout-verbetering op de zoekresultatenpagina (na preview-overleg): ronde telbadges i.p.v. platte "(N)"-tekst (navy voor Exacte resultaten, goud voor Mogelijk ook interessant), een dun gouden randje links op de slimme-resultaat-kaartjes, en een legenderegel "Gouden randje = AI-gesuggereerd op betekenis, niet op letterlijke tekst" erboven. Nieuwe CSS-klassen .search-count-badge(--exact/--smart), .article-card--smart, .search-section-legend.
- 3.68 — Structurele fix op de spring-naar-paragraaf-link: v3.67 loste het ene geval op maar verplaatste het probleem alleen (nieuwe test toonde een fragment dat over de grens van een alinea in een kop heen liep). Root cause: bij het omzetten van artikel-HTML naar platte tekst voor de zoekindex gingen alle bloksgrenzen (alinea's, koppen, citaatblokken) verloren -- alles werd zonder scheiding aan elkaar geplakt. yeshua_online_get_plain_text_for_embedding() voegt nu een onzichtbaar alinea-merkteken ("¶") toe op elke blokgrens vóór het strippen van tags; yeshua_online_smart_result_url() gebruikt dat merkteken om een fragment te kiezen dat gegarandeerd binnen één blok blijft; yeshua_online_smart_result_snippet() verbergt het merkteken bij weergave. BELANGRIJK: bestaande, al verwerkte artikelen bevatten deze markering nog niet -- de volledige backfill (Gereedschap > Yeshua zoekindex) moet nog één keer opnieuw draaien voordat deze fix voor alle 102 artikelen geldt.
- 3.67 — Fix op de spring-naar-paragraaf-link (Text Fragments): bij een staging-test bleek een link niet te springen naar de juiste passage, ondanks dat de tekst wel degelijk letterlijk op de pagina stond (bevestigd via Ctrl+F). Oorzaak: het gekozen tekstfragment begon precies op de overgang tussen twee los opgemaakte alinea's, wat browsers onbetrouwbaar matchen over een blok-grens heen. yeshua_online_smart_result_url() zoekt nu eerst de eerste volledige-zin-grens binnen de chunk en start de frase pas daarna, in plaats van simpelweg de eerste 8 woorden van de chunk te nemen.
- 3.66 — Symmetrische kopjes op de zoekresultatenpagina (na overleg): "Exacte resultaten (N)" en "Mogelijk ook interessant (N)" staan nu allebei altijd, ook bij 0, met een korte neutrale subtekst i.p.v. helemaal weg te blijven of een alarmerende "geen resultaten"-melding. Slim-zoeken-sectie blijft wel volledig weg in talen waar die functie niet actief is (alleen NL/EN). De oude, nu overlappende tellerregel bovenaan de pagina ([yeshua_search_result_count]) is uit de template gehaald (functie blijft ongebruikt aanwezig, geen risico). Nieuwe .search-section-note CSS-klasse.
- 3.65 — Fix n.a.v. staging-test van Fase 4: de bestaande "Geen resultaten gevonden voor..."-regel bovenaan de zoekresultatenpagina bleek verwarrend te blijven staan wanneer de slimme zoekfunctie wél resultaten toonde in "Mogelijk ook interessant" verderop. yeshua_online_shortcode_search_result_count() checkt bij 0 exacte titel-treffers nu eerst of de slimme zoekfunctie iets vindt; zo ja, blijft de regel gewoon weg (geen dubbele/tegenstrijdige boodschap).
- 3.64 — Fase 4 van de nieuwe zoekfunctie: de zoekresultatenpagina (templates/search.html) toont nu twee secties. "Exacte resultaten" (kopje via [yeshua_exact_results_heading], alleen zichtbaar bij treffers) boven de bestaande, ongewijzigde titel-matches-grid. Daaronder "Mogelijk ook interessant" ([yeshua_smart_search_section]): eigen kaartjes-grid in dezelfde .article-card-stijl, met een korte toelichting uit het best-matchende tekstdeel en, bij lange artikelen, een spring-naar-paragraaf-link (Text Fragments, #:~:text=...) — werkt in Chrome/Edge/moderne Firefox, valt in overige browsers terug op een gewone link. De gedeelde "niets gevonden"-melding verschijnt nu alleen als zowel de exacte als de slimme sectie leeg zijn. Nog geen zoekicoon in de header (Fase 5).
- 3.63 — Fase 3 van de nieuwe zoekfunctie: de standaard WordPress-zoekfunctie zoekt nu alleen nog in artikeltitels (was titel+inhoud+excerpt), via yeshua_online_title_only_search(). Nieuwe semantische zoeklogica (yeshua_online_get_smart_search_results() + yeshua_online_cosine_similarity()): embedt de zoekterm van de bezoeker en vergelijkt die met alle opgeslagen artikel-vectoren, met een drempelwaarde (YESHUA_SEARCH_SMART_THRESHOLD, start 0,5) en een maximum van 8 resultaten; faalt bewust stil bij een Voyage-storing (geen sectie i.p.v. een kapotte pagina). Nieuw testpaneel op Gereedschap > Yeshua zoekindex om de kwaliteit/drempelwaarde te beoordelen vóór de echte resultatenpagina (Fase 4) gebouwd wordt. Nog geen wijziging aan de resultatenpagina zelf en nog geen zoekicoon in de header.
- 3.62 — Diagnostische verbetering i.p.v. nog een blinde timing-fix: alle voorgaande timing-fixes (v3.57 t/m v3.61) losten steeds een deel op, maar 7 specifieke artikelen (zonder uitzondering: precies de langste op de site, 4.900-14.100 woorden, allemaal met meerdere chunks) bleven ondanks alles 100% van de tijd mislukken — dat wijst niet meer op timing maar mogelijk op een aparte limiet op de omvang van één aanvraag. yeshua_online_voyage_call_api() toont nu de daadwerkelijke ruwe respons van Voyage AI (inclusief eventuele Retry-After/rate-limit-headers) in plaats van de generieke "(HTTP 429)"-tekst, zodat de werkelijke oorzaak zichtbaar wordt. Sub-batchgrootte voorzorgshalve terug naar 3 (was tijdelijk 10 in v3.61). Nog niets zichtbaars voor bezoekers.
- 3.61 — Vijfde fix: een artikel van ~4.900 woorden ("Yeshua als Zichtbare openbaring van God", 2 sub-batches) bleef ondanks v3.60 structureel mislukken. Oorzaak: de pauze tússen sub-batches van hetzelfde artikel stond nog vast op 2s (uit v3.59), losgekoppeld van de intussen server-side geleerde wachttijd — dus zelfs als het systeem al had geleerd dat bv. 24s nodig was, gebruikte dit interne stukje nog steeds de oude 2s. Sub-batches gebruiken nu dezelfde geleerde wachttijd (met een plafond van 15s, omdat deze functie ook synchroon draait bij het gewone opslaan van een artikel — zonder plafond zou een opgelopen wachttijd de 'Bijwerken'-knop in de editor kunnen laten hangen). Sub-batchgrootte ook verhoogd van 5 naar 10 tekstdelen, zodat zelfs de langste artikelen met minder interne pauzes toekunnen. Nog niets zichtbaars voor bezoekers.
- 3.60 — Vierde fix op de backfill: de wachttijd tussen aanvragen werd tot nu toe in de browser bijgehouden en "vergat" zichzelf bij elke nieuwe poging (opnieuw op de pagina komen of nogmaals op Start klikken begon steevast weer optimistisch bij 6s), waardoor telkens dezelfde vroege artikelen opnieuw tegen de rate limit aanliepen. De wachttijd wordt nu server-side onthouden (option yeshua_online_search_backfill_delay_ms) en blijft dus geldig over losse pogingen/paginaherladingen heen — pas als hij écht een tijd lang goed gaat, zakt hij weer geleidelijk. Nieuw op het backfill-scherm: de huidige onthouden wachttijd wordt getoond. Nog niets zichtbaars voor bezoekers.
- 3.59 — Derde fix op de embeddings-verwerking: een klein groepje artikelen (herkenbaar als de langste op de site, o.a. "Once Saved, Always Saved?" en "Eens Gered, Altijd Gered?", ~14.000 woorden / ~20 chunks) bleef ondanks v3.58 hardnekkig mislukken bij elke poging — geen timing-probleem (rate limit) maar vermoedelijk een aparte tokens-per-aanvraag-limiet bij Voyage AI, omdat alle chunks van zo'n artikel in één keer werden verstuurd. yeshua_online_voyage_get_embeddings() splitst nu automatisch in sub-batches van 5 tekstdelen met 2s pauze ertussen bij artikelen met meer chunks; de daadwerkelijke API-aanroep zit nu in de nieuwe helper yeshua_online_voyage_call_api(). Nog niets zichtbaars voor bezoekers.
- 3.58 — Ondergrens van de adaptieve backfill-pauze verhoogd van 3s naar 6s: uit een testlog met nog v3.56 actief bleek een vrijwel perfect afwisselend OK/MISLUKT-patroon (elke 2e aanvraag een HTTP 429), wat aangeeft dat Voyage AI's werkelijke veilige grens ergens tussen 3 en 6 seconden ligt. Start nu meteen op 6s in plaats van dat eerst te moeten "ontdekken" via mislukte pogingen. De v3.57-logica (mislukte rate-limit-artikelen terug de wachtrij in, adaptief oplopen/afbouwen) blijft ongewijzigd. Nog niets zichtbaars voor bezoekers.
- 3.57 — Tweede fix op de backfill n.a.v. staging-test: v3.56 loste de rate limit-detectie op, maar 32 van de 102 artikelen bleven blijvend "MISLUKT" omdat ze na 1 mislukte poging niet opnieuw werden geprobeerd binnen dezelfde ronde. Nu: (1) een artikel dat mislukt door een HTTP 429/rate-limit-fout gaat terug de wachtrij in (achteraan) i.p.v. definitief te worden overgeslagen. (2) De pauze tussen porties is nu adaptief: verdubbelt bij elke rate-limit-fout (tot max. 60s), zakt bij succes geleidelijk terug naar de ondergrens van 3s — in plaats van een simpele aan/uit-schakeling tussen 3s en 20s. "Klaar" verschijnt nu pas echt als alles gelukt is (of definitief anders mislukt is, niet door een rate limit). Nog niets zichtbaars voor bezoekers.
- 3.56 — Fix op de v3.55 backfill: eerste staging-test liep na 3 geslaagde artikelen structureel vast (rate limit bij Voyage AI, vermoedelijk een laag aanvragen-per-minuut-plafond op het instapplan). Portiegrootte van 5 naar 1 artikel per AJAX-aanroep, vaste pauze van 3s tussen porties, en automatische verlenging naar 20s zodra een rate-limit-foutmelding (HTTP 429 / "rate limit" / "too many requests") wordt gezien in de respons — valt daarna vanzelf weer terug naar de normale pauze. De echte Voyage-foutmelding wordt nu ook getoond in het logje op het backfill-scherm (was alleen "MISLUKT" zonder reden). Nog niets zichtbaars voor bezoekers.
- 3.55 — Fase 2 van de nieuwe zoekfunctie: artikelen worden nu automatisch (her)verwerkt voor de zoekindex bij het opslaan (save_post_page-hook, alleen NL/EN gepubliceerde Pagina's; depubliceren/verwijderen haalt ze ook weer uit de index). Nieuw admin-scherm Gereedschap > Yeshua zoekindex voor de eenmalige backfill van bestaande artikelen, in porties van 5 via AJAX (bewust geen stil WP-Cron, onbetrouwbaar op laag-bezochte staging zonder serverside cronjob). Eenmalige retry bij een mislukte Voyage-aanroep + admin-notice op het bewerkscherm. Nog niets zichtbaars voor bezoekers.
- 3.54 — Fase 1 van de nieuwe zoekfunctie (semantisch/"slim" zoeken naast de bestaande titel-zoekfunctie): databasetabel yeshua_online_search_index (chunks + vectoren), Voyage AI embeddings-koppeling (API-key via wp-config.php, YESHUA_VOYAGE_API_KEY), en chunking-logica voor lange artikelen (drempel 3.000 woorden). Nog niets automatisch/zichtbaar — vervolgfases volgen. Alleen NL/EN vooralsnog.
- 3.53 — Fix op v3.52: Fraunces/Public Sans verschenen na installatie alsnog niet in de TinyMCE-lettertype-dropdown. Oorzaak: de plugin Advanced Editor Tools registreert zelf ook een 'tiny_mce_before_init'-filter om zijn font_formats-lijst te zetten; zonder expliciete prioriteit liep die na de onze en overschreef de volledige waarde weer, inclusief onze toevoeging. yeshua_online_tinymce_font_formats() draait nu met prioriteit PHP_INT_MAX, zodat 'ie gegarandeerd als allerlaatste draait, ná de plugin. Functionaliteit van de filter zelf ongewijzigd t.o.v. v3.52. Nog te testen: harde refresh (Ctrl+F5) in de pagina-editor na installatie.
- 3.52 — Twee losse fixes. (1) Fraunces en Public Sans ontbraken in de lettertype-dropdown van de klassieke (TinyMCE) editor, ook al zijn beide fonts sinds v3.47 correct lokaal gehost en geregistreerd (theme.json + editor-style.css) -- gecontroleerd dat Advanced Editor Tools (voorheen TinyMCE Advanced) hier geen eigen instelling voor biedt (alleen de zichtbaarheid van de dropdown-knop is instelbaar, niet de inhoud). Nieuwe functie yeshua_online_tinymce_font_formats() toegevoegd (functions.php), hookt in 'tiny_mce_before_init' en voegt beide fonts vooraan toe aan TinyMCE's standaard font_formats-lijst, zonder de bestaande fonts (Arial, Georgia, etc.) te verwijderen. (2) Het WP Statistics-vergelijkingsblokje uit v3.50 (footer.html, [wpstatistics stat="usersonline"]) verwijderd -- de controleperiode is afgerond, de eigen "nu online"-teller (v3.45/v3.49/v3.51) is voldoende vertrouwd bevonden. Kanttekening: dit verwijdert alleen de weergave in het theme; de WP Statistics-plugin zelf staat nog actief en moet apart in Plugins → Geïnstalleerde plugins gedeactiveerd/verwijderd worden. Nog te testen: harde refresh (Ctrl+F5) in de pagina-editor nodig om de nieuwe fontlijst te zien i.v.m. browsercaching van TinyMCE-instellingen; footer controleren in alle 6 taalversies na verwijdering van het blokje (grid-indeling moet netjes blijven bij 4 i.p.v. 5 tegels).
- 3.51 — "Nu online"-teller structureel realistischer gemaakt, na constatering dat rustige, langdurige lezers (bij lange theologische artikelen precies de kerndoelgroep) ten onrechte na een paar minuten uit de teller vielen, terwijl ze nog gewoon aanwezig waren. Twee samenhangende wijzigingen: (1) Heartbeat toegevoegd (parts/footer.html): zolang de pagina open blijft, stuurt de browser elke 75 sec opnieuw een beacon-signaal (was voorheen eenmalig, alleen bij laden). (2) Het "online"-venster is daardoor verkort van 5 naar 3 minuten (functions.php, zowel de opruim-query als de telquery) -- ruim boven de heartbeat-frequentie (zodat één gemiste heartbeat door een trage verbinding niet meteen iemand als "weg" telt), maar wel kort genoeg om daadwerkelijk te reageren zodra iemand de pagina sluit. Tegelijk IP-gebaseerde rate-limiting toegevoegd op het registratiepad (nieuwe functies yeshua_online_get_client_ip(), yeshua_online_is_rate_limited(), toegepast in yeshua_online_register_visit()) als vangnet tegen pieken van bots/scrapers met een vervalste user-agent (dus onzichtbaar voor de bestaande v3.49-botfilter) die kort na elkaar veel losse registraties veroorzaken -- drempel bewust ruim (60 registraties/IP/minuut) zodat een gedeeld IP-adres met meerdere echte, gelijktijdige lezers hier nooit tegenaan loopt. Rate-limiter gebruikt een kortlevende (max. 1 min) transient, uitsluitend voor deze technische telling, niet gekoppeld aan een profiel. Nog te testen op staging (/enterprise/): heartbeat-gedrag controleren (interval-timer, geen dubbele registraties door de gecombineerde beacon+heartbeat-aanroepen), en de rate-limiter niet per ongeluk laten afgaan bij normaal gebruik.
- 3.50 — WP Statistics-cijfer ("Online bezoekers") als vergelijkingsblokje toegevoegd naast de bestaande "nu online"-teller in de footer (parts/footer.html), via shortcode [wpstatistics stat="usersonline"]. Bewust NAAST de bestaande teller (niet ter vervanging) zodat beide cijfers doorlopend, live naast elkaar te vergelijken zijn -- vervolg op de v3.49 bot-filtering, ter voortzetting van de vertrouwenscontrole. Kanttekening: het label van dit blokje volgt niet de Polylang-vertaling (vast "WP Statistics (ter controle)", geen [yeshua_t]-sleutel), bewust zo gelaten omdat dit een tijdelijk controle-blokje is, geen permanent site-onderdeel. Als WP Statistics ooit weer verwijderd wordt: dit blokje (en de LiteSpeed JS/URI-uitsluitingen voor tracker.js) dan ook opruimen.
- 3.49 — Bot-/crawler-filtering toegevoegd aan de bezoekersteller (vervolg op de v3.45 beacon-fix). Aanleiding: WP Statistics geïnstalleerd als onafhankelijke tweede meting ter controle van de eigen "nu online"-teller. Die gaf op hetzelfde moment "Online bezoekers: 1" terwijl de eigen teller "11" toonde -- bevestigd dat dit niet kwam door actief zijn in wp-admin (eerder vermoede SEO-preview-verklaring dus uitgesloten). Waarschijnlijke oorzaak: de v3.45 beacon-aanpak telt bewust via JavaScript (nodig om paginacache te omzeilen), maar telde daardoor ook élke geautomatiseerde, JS-uitvoerende bezoeker mee, zoals LiteSpeed's eigen achtergrondprocessen voor Critical CSS/UCSS-generatie -- WP Statistics heeft hiervoor al een uitgebreide, onderhouden bot-lijst; de eigen code had die nog niet. Nieuwe functie yeshua_online_is_bot_request() toegevoegd: herkent bekende bots/crawlers/headless-browsers via de User-Agent header (zoekmachine-crawlers, social-media-linkpreview-bots, generieke headless-browsers/scripts, en specifiek LiteSpeed's eigen processen). Toegepast in yeshua_online_register_visit(), dus geldt automatisch voor zowel het bestaande template_redirect-pad als het beacon-pad. Kanttekening: user-agent-detectie is, net als bij WP Statistics en vergelijkbare tools, geen waterdichte garantie (een bot kan een user-agent vervalsen) maar dekt de meest voorkomende gevallen af. Deze wijziging is gebouwd op v3.45's beacon-logica (functioneel ongewijzigd t.o.v. v3.45/3.48 overgenomen) -- geen overlap met de font-optimalisatie (3.46/3.47) of de contactlink-fix (3.48), die blijven ongewijzigd. Nog te testen op staging (/enterprise/): "nu online" vergelijken met het WP Statistics-cijfer op hetzelfde moment; bij overeenstemming doorzetten naar live.
- 3.48 — Fix: de footer-contactlink ([yeshua_page_href key='contact'] in parts/footer.html) wees voor Nederlandse bezoekers naar de Engelse contactpagina i.p.v. de Nederlandse. Oorzaak: de sleutel 'contact' was gekoppeld aan slug 'supportcandy-portal' -- dat is de Engelse pagina's eigen slug, niet een taalneutrale referentie. yeshua_online_page_id() zoekt eerst een pagina op exact die slug (over alle talen heen) en past de vertaalstap alleen toe als de bezoektaal niet Nederlands is; voor NL-bezoekers werd dus zonder vertaalstap de rechtstreeks gevonden (Engelse) pagina teruggegeven. Bevestigd via de WordPress-export dat de Nederlandse pagina "Contactformulier" in dezelfde Polylang-vertaalgroep zit, met eigen slug 'contactformulier'. Opgelost door de sleutel naar die correcte NL-slug te wijzigen; voor de overige talen (EN/ES/ZH/HI/HE/Hinglish) verandert er niets, die liepen al correct via de vertaalstap. De hoofdmenu-link "Contact" (bovenaan, los WordPress-menu-item per taal) was hier nooit door geraakt en werkte al correct in elke taal -- alleen de footer-link gebruikte deze shortcode. Los, blijvend punt (geen actie via deze fix): de SupportCandy-formuliervelden zelf (Customer/Subject/Description) blijven in elke taal Engels, dat is de plugin's eigen UI-tekst en staat los van Polylang-paginavertaling.
- 3.47 — Fonts (Fraunces + Public Sans) van Google Fonts (extern, drie afzonderlijke aanroepen met onderling afwijkende gewichten) omgezet naar lokaal gehoste variabele woff2-bestanden, geregistreerd via theme.json (settings.typography.fontFamilies[].fontFace). Voordien werden de fonts op DRIE plekken geladen -- de @import in parts/header.html (Fraunces gewichten 300/500/600 + cursief 400, met opsz-as), de wp_enqueue_style() in functions.php (dezelfde gewichten maar cursief 500 i.p.v. 400, zonder opsz-as) en add_editor_style() voor de editor (idem als de enqueue) -- deze onderlinge afwijking (cursief 400 vs 500) betekende dat voorkant en editor mogelijk niet exact hetzelfde cursieve gewicht toonden. Vóór de omzetting is de CSS doorzocht op alle daadwerkelijk gebruikte gewicht/stijl-combinaties (recht: 400/500/600, cursief: 400/500 -- cursief 600 komt nergens voor) en zijn variabele fonts gekozen (i.p.v. losse statische gewichten) zodat geen enkele combinatie kan ontbreken en de opsz-as (optische grootte, bepaalt de subtiel andere vorm van Fraunces bij koppen t.o.v. kleine tekst) behouden blijft. De bestanden zijn gesubset naar Latijns schrift (dekt nl/en/es; hi/zh/he gebruiken sowieso al een systeem-fallback, dat gedrag verandert niet) en naar alleen de wght+opsz-assen (SOFT/WONK-assen van de bovenstroomse Fraunces-familie waren niet in gebruik, vastgezet i.p.v. meegenomen) -- resultaat: 3 bestanden, samen ca. 179 KB, eenmalig gecached door de browser, geen enkele externe aanvraag meer naar fonts.googleapis.com/fonts.gstatic.com. Reden voor deze stap: PageSpeed-rapport toonde bij herhaling renderblokkering door de dubbele Google Fonts-aanvraag (laatst gemeten: 2.500 ms geschatte besparing, oplopend t.o.v. een eerdere meting van 590 ms). De preconnect-hints uit v3.46 zijn verwijderd (overbodig nu er niets meer extern wordt opgehaald). Licentiebestanden (OFL) van beide families meegenomen in assets/fonts/ ter documentatie. Nog te doen: op staging (/enterprise/) testen in alle 6 taalversies, met name de cursieve koppen (bv. .seal blockquote, .trust-num) en de hero-h1 (cursief 500), vóór livegang. Bij problemen: terug naar v3.46.
- 3.46 — PageSpeed: preconnect-hints toegevoegd voor fonts.googleapis.com en fonts.gstatic.com (functions.php, via het standaard wp_resource_hints-filter). Verandert niets aan hoe/waar fonts geladen worden (die blijven voorlopig zoals ze waren, op de drie bekende plekken: header.html @import, functions.php enqueue, functions.php add_editor_style) -- versnelt alleen de verbinding vooraf. Bewust de kleinste, meest risicoarme stap; het self-hosten van de fonts (en het opschonen van de drie plekken) staat nog open voor een moment met meer tijd om rustig te testen op staging.
- 3.45 — Structurele fix voor de bezoekersteller ("nu online"): de teller werd tot nu toe alleen bijgewerkt via 'template_redirect' (functions.php), wat betekent dat een bezoek NIET geregistreerd werd wanneer de pagina uit LiteSpeed-paginacache werd geserveerd (PHP draait dan niet). Dit verklaarde waarom "nu online" structureel te laag bleef, ook nadat de LiteSpeed-instellingen zelf (REST API cachen uit, /wp-json/yeshua/ uitgesloten) correct waren gezet en bevestigd getest -- geverifieerd met een schone test vanaf een uitgelogd mobiel toestel, waarbij de teller alsnog niet meebewoog. Kernlogica van yeshua_online_track_visitor() uitgesplitst naar een herbruikbare functie yeshua_online_register_visit(), die nu op TWEE manieren wordt aangeroepen: (1) zoals voorheen via 'template_redirect' (blijft staan, harmless als aanvulling bij een toevallige cache-miss), en (2) NIEUW via een REST-beacon-endpoint (/wp-json/yeshua/v1/beacon, POST), aangeroepen door JavaScript in parts/footer.html ná het laden van de pagina -- dit pad werkt gegarandeerd ongeacht paginacache, want JavaScript in de browser voert altijd uit, en het beacon-endpoint valt al onder de bestaande cache-uitsluiting "/wp-json/yeshua/". Beide paden zijn veilig te combineren: de upsert naar de eigen tabel is idempotent, en de dagteller is al beveiligd tegen dubbeltellen via het bestaande yeshua_counted_today-cookie. Bijkomend voordeel: LiteSpeed's eigen achtergrond-crawler (die geen JavaScript uitvoert) telt hierdoor niet langer per ongeluk mee als bezoeker, wat eerder de wisselende lage getallen (1-3) kan hebben veroorzaakt. Nog te testen op staging/productie: bevestigen dat "nu online" nu wél meebeweegt bij een schone test vanaf een uitgelogd apparaat.
- 3.44 — Volgorde van de 2 footer-copyright-regels (v3.43) omgedraaid op verzoek: de beschrijvende zin nu boven, "© jesusmessiah.online" eronder. Geen andere wijziging -- geen kleur, font of link toegevoegd; de tekstkleur is ongewijzigd t.o.v. v3.43 (overgenomen uit bestaande, ambient stijl van de footer-sectie, niet apart aangepast).
- 3.43 — Footer-copyright (alle 6 taalversies) omgebouwd van 1 naar 2 regels op verzoek: "© jesusmessiah.online" nu als eigen regel bovenaan, de beschrijvende zin ("Bijbelse waarheid over Yeshua." / vertaald equivalent) eronder, zonder het liggende streepje dat er eerder tussen stond. Nieuwe vertaalstring footer_copyright_domain toegevoegd (x7 talen); footer_copyright_pre per taal ontdaan van het domein+streepje-gedeelte, alleen de beschrijvende tekst blijft over (Hindi's pre-string werd hierdoor leeg, aangezien die taal de zin volledig in de post-string had staan).
- 3.42 — Twee correcties, geen relatie met de bezoekersteller-fix uit v3.41: (1) "jezus.online" was nog op 7 plekken hardcoded (footer-copyright in alle 6 talen, plus het contactadres info@jezus.online) -- vervangen door "jesusmessiah.online", inclusief de Theme URI/Description-metadata in de style.css-header. (2) Bevestigd (via handmatige herinspectie van parts/footer.html) dat de v3.41-padverdubbelingsfix wél correct in het bestand staat -- wat na uploaden alsnog als het oude, dubbele pad verscheen op staging bleek een LiteSpeed-cache-kwestie: de pagina-HTML met het oude data-endpoint-attribuut was nog gecached van vóór de fix. Geen codewijziging nodig voor dit deel; opgelost door de LiteSpeed-cache op staging te legen na het uploaden van een nieuwe thema-versie. Aandachtspunt voor toekomstige updates: front-end HTML-wijzigingen (zoals data-attributen) worden pas zichtbaar ná een cache-purge, ook al is het thema-bestand zelf al correct bijgewerkt.
- 3.41 — Fix: bezoekersteller (totaal/dit jaar/vandaag/nu online, parts/footer.html) bleef op "—" staan op de staging-submap /enterprise/, zonder zichtbare foutmelding (de fetch faalt bewust stil). Oorzaak: het endpoint was nog hardcoded als "/wp-json/yeshua/v1/visitor-stats" -- exact dezelfde bug die al eerder is opgelost voor de "nieuwe artikelen"-banner (zie v-geschiedenis van [yeshua_rest_url]), maar die fix was destijds niet doorgevoerd naar de bezoekersteller. Op staging wees dat hardcoded pad naar de REST-API van de live site in de root i.p.v. de staging-installatie zelf. Opgelost met dezelfde aanpak: nieuwe shortcode [yeshua_rest_url_base] (rest_url('yeshua/v1/'), kent het daadwerkelijke installatiepad) gevuld in een data-endpoint-attribuut, uitgelezen door de JS i.p.v. een hardcoded pad -- inclusief een vroege return zonder hardcoded terugval-pad als het attribuut onverhoopt ontbreekt (zelfde defensieve patroon als de banner al gebruikte). Tijdens implementatie zelf een padverdubbelingsfout (.../yeshua/v1/yeshua/v1/...) ontdekt en gecorrigeerd vóórdat dit naar staging ging -- eindresultaat handmatig nagerekend voor zowel root- als submap-installatie. Volledige theamscan uitgevoerd op andere hardcoded /wp-json-, /wp-admin- of /wp-content-paden: geen andere plekken gevonden. Getest op staging (/enterprise/): teller toont nu correcte cijfers i.p.v. "—".
- 3.40 — Fix, admin-only (raakt de voorkant van de site niet): een bug in de AIOSEO Broken Link Checker-module (v5.0.0.1, door AIOSEO zelf gemarkeerd als "niet getest met je huidige WordPress-versie") crashte met "Cannot read properties of undefined (reading 'urls')" op ELKE wp-admin-pagina, niet alleen AIOSEO's eigen scherm -- ontdekt doordat SupportCandy-ticketrijen (Support -> Customers -> Tickets) nergens meer op reageerden. De crash stopte de rest van AIOSEO's script, waardoor ook andere JS op diezelfde pagina (incl. click-handlers van andere plugins) niet meer uitgevoerd werd. Bevestigd via browserconsole + Sources-tab (pad: /wp-content/plugins/broken-link-checker-.../app-core...js) dat dit een AIOSEO-bug is, geen thema- of SupportCandy-probleem. Opgelost met een kleine shim (yeshua_online_fix_aioseo_blc_shim, admin_head) die het door AIOSEO verwachte window.aioseoBrokenLinkChecker.urls-object alvast leeg aanmaakt vóór hun script laadt -- alleen als het nog niet bestaat (||), dus geen overschrijving. Op AIOSEO's eigen instellingenpagina vult hun script dit gewoon met de echte data, geen functieverlies daar. Wordt vanzelf een dode letter (geen conflict) zodra AIOSEO dit zelf oplost in een toekomstige update, aangezien het object dan al bestaat en de || niet meer aanslaat -- kan dan verwijderd worden, puur voor nette code, niet uit noodzaak. Getest op staging (/enterprise/) vóór livegang: SupportCandy-tickets weer klikbaar, AIOSEO-schermen ongewijzigd, voorkant niet geraakt.
- 3.39 — Vervolgfix op v3.38: de eerste/laatste-kolom-breedte (32/68) loste het probleem alleen op voor 2-koloms tabellen. Een tabel met 3+ kolommen (bv. een "schaduw/vervulling"-tabel) had nog steeds een te smalle middelste kolom, met hetzelfde letter-voor-letter-afbreekprobleem op mobiel. Structureel opgelost, onafhankelijk van het aantal kolommen: table-layout van fixed naar auto, en op mobiel (<640px) scrollt de tabel nu horizontaal (met een leesbare minimumbreedte van 140px per cel) in plaats van kolommen geforceerd samen te persen.
- 3.38 — Fix (geen LiteSpeed-probleem, wel gemeld als zodanig): de TERM-kolom-breedte-fix uit v3.14 was alleen aan page-id-119928 (de Engelse definities-pagina) gekoppeld. Alle andere taalversies van dezelfde tabel (nl/hinglish/hi/es/zh/he) hadden deze verruiming nooit gekregen en liepen op mobiel tegen hetzelfde letter-voor-letter-afbreekprobleem aan dat de Engelse pagina ooit ook had. Opgelost door de 32/68-kolomverdeling algemeen te maken (elke tabel binnen .article-content, ongeacht pagina-ID), zodat dit niet meer per taal apart kan stukgaan.
- 3.37 — De v3.36-fix (transients) vervangen door een structureel robuustere aanpak: een eigen databasetabel (yeshua_online_visitors) i.p.v. WordPress-transients. Reden: transients worden door WordPress automatisch omgeleid naar een object-cache (Redis/Memcached) zodra die ooit actief wordt (bv. bij een toekomstige LiteSpeed/hosting-instelling) -- dan zou de tel-query in de database niets meer vinden. Een eigen tabel wordt nooit op die manier omgeleid, dus dit blijft werken ongeacht toekomstige hostingwijzigingen. Bijwerken gebeurt via een atomische upsert (INSERT ... ON DUPLICATE KEY UPDATE, MySQL regelt zelf de gelijktijdigheid). Opruimen van verlopen rijen lift mee op ieder bezoek, geen aparte cron/geplande taak nodig. Tabel wordt aangemaakt bij thema-activatie (after_switch_theme), met een vangnet (init-check) mocht hij onverhoopt ontbreken.
- 3.36 — Fix (los van de banner): de "nu online"-teller bleef op live constant rond de 1 hangen, terwijl "bezoekers vandaag" wel gewoon opliep. Oorzaak: een race condition -- bij 10k+ bezoekers/dag schreef iedereen tegelijk naar één gedeelde lijst-optie (yeshua_visitors_online); gelijktijdige bezoekers overschreven elkaars toevoeging voordat die was weggeschreven, waardoor er structureel maar 1 overbleef. Opgelost door elke bezoeker een eigen, individuele transient te geven (yeshua_online_{vid}, 5 min geldig) i.p.v. een gedeelde lijst -- niemand overschrijft nu nog een ander. "Nu online" wordt geteld via een directe COUNT-query op de nog geldige transients.
- 3.35 — Kleine correctie: de gouden samenvattingszin ("X nieuwe artikelen...") teruggezet van vetgedrukt (v3.33) naar normaal gewicht.
- 3.34 — Fundamentele gedragswijziging van de "nieuwe artikelen"-melding, na brainstorm: klikken op één artikel verwijdert voortaan ALLEEN dat artikel uit de lijst (i.p.v. de hele melding te laten verdwijnen zoals in v3.33). De overige, nog ongelezen artikelen blijven zichtbaar, en het aantal in de tekst ("X nieuwe artikelen") telt mee terug. Wordt de lijst leeg (alles aangeklikt), dan verdwijnt de melding vanzelf. De melding verdwijnt verder ALLEEN nog volledig via het kruisje -- dat is nu een echte reset: zowel het "sinds wanneer is iets nieuw"-tijdstip als de nieuwe "welke heb ik al aangeklikt"-lijst (yeshua_banner_seen_articles, apart van het bestaande site-brede yeshua_read_pages-systeem) worden dan gewist. URL-normalisatie voor die nieuwe lijst hergebruikt dezelfde aanpak (pad + querystring) als de v3.31-fix voor het groene-vinkje-systeem.
- 3.33 — Drie verfijningen aan de tegel-versie van de banner (v3.32), na een preview-ronde: (1) ruimte onder de tegel gelijkgetrokken aan de vaste ruimte erboven (beide 70px, gebaseerd op hero padding-top -- alleen de tegel-marge aangepast, hero-basisafstand blijft ongewijzigd voor de situatie zonder banner). (2) Kleuren omgedraaid t.o.v. v3.30/3.32: samenvattingszin nu vetgedrukt in --gold, artikel-links in --ink zonder vet (i.p.v. de dunnere/gemengde combinatie ervoor) -- gebaseerd op de kleur die elders op de site al voor gewone body-tekst wordt gebruikt (bv. de "Hebraïsche context"-alinea). (3) Gedrag: klikken op een artikel in de lijst werkt nu ook als bevestiging (net als het kruisje) -- het laatste-bezoek-tijdstip wordt dan meteen bijgewerkt, zodat de melding niet blijft terugkomen nadat je al een artikel hebt gelezen.
- 3.32 — De "nieuwe artikelen"-melding omgebouwd van een volledige-breedte balk tussen header en hero naar een gecentreerde, zwevende tegel bovenaan IN de hero-sectie zelf (na een preview-ronde met meerdere tussenstappen: eigen site-componenten hergebruikt zoals de tag-pil en Fraunces-tekst, en varianten voor de invulling van de restruimte). Dit lost het "grote lege witte vlak rechts"-probleem structureel op: de tegel is nu alleen zo breed als de inhoud vraagt (max. 640px), met een kaart-achtige schaduw en afgeronde hoeken passend bij de rest van de site, in plaats van een balk die de volle paginabreedte opeiste. Bullets in goud voor elk artikel, "Nieuw"-tag-pil (nieuwe vertaalstring x7 talen) naast de samenvattingszin. Het draadmotief (v3.29) en de losse achtergrondstijl (v3.30) zijn hiermee overbodig en verwijderd. Omdat de tegel nu binnen de normale flow van .hero-inner staat, schuift de overige hero-content vanzelf naar beneden zolang de melding zichtbaar is, en veert alles terug naar de oorspronkelijke positie zodra op het kruisje wordt geklikt.
- 3.31 — Fix (los van de banner, bestaand "gelezen"-vinkje-systeem): op staging ('gewone' permalinken, ?page_id=...) normaliseerde normalizeUrl() alle artikel-URL's naar hetzelfde pad, omdat alleen de querystring (waar bij plain permalinks het page_id in zit) het ene artikel van het andere onderscheidt -- die werd genegeerd. Gevolg: zodra één artikel als gelezen gemarkeerd werd, kregen alle artikelen op categoriepagina's het groene vinkje, ook artikelen die nooit geopend waren. Opgelost door de querystring mee te nemen in de normalisatie.
- 3.30 — Kleurstelling van de "nieuwe artikelen"-banner omgezet van goud-op-goud (voelde somber/druk) naar parchment-achtergrond met eenkleurige donkerblauwe tekst (--night), na een preview-ronde met twee opties (goud vs. donkerblauw voor de samenvattingszin) -- donkerblauw gekozen zodat goud exclusief de klik-kleur blijft voor de artikel-links, i.p.v. te concurreren met de samenvattingstekst. Het draadmotief onderaan is meegewisseld naar de tekhelet/gold-variant die de site al gebruikt bij overgangen vanaf een lichte (parchment) achtergrond.
- 3.29 — UI-verfijning van de "nieuwe artikelen"-banner: elk artikel in het lijstje heeft nu een bullet (klein rond puntje) en staat op zijn eigen regel, i.p.v. naast elkaar met komma-achtige spatiëring. Onderaan de banner is een subtiel draadmotief toegevoegd -- exact dezelfde stijl (kleuren, dikte, schaduwverloop) als de bestaande overgang tussen header en hero -- voor een vloeiendere overgang naar de hero-sectie eronder.
- 3.28 — Drie verbeteringen aan de "nieuwe artikelen"-banner, n.a.v. live feedback op staging: (1) de "Bekijk ze"-link wees altijd naar de Bijbelstudie-categorie, ongeacht de werkelijke categorie van het nieuwe artikel -- vervangen door een lijstje met de daadwerkelijke artikelen, elk met een link naar het artikel zelf. (2) De banner verdween al bij een simpele verversing (het "laatste bezoek"-tijdstip werd bij elk bezoek stilzwijgend bijgewerkt) -- dat tijdstip wordt nu alleen nog bijgewerkt bij het eerste bezoek (nulmeting) en zodra de bezoeker zelf op het kruisje klikt, zodat de banner zichtbaar blijft totdat hij bewust wordt weggeklikt. (3) Lijstje met artikeltitels + links toegevoegd (uit de al bestaande `articles`-data van het `new-since`-endpoint, voorheen ongebruikt).
- 3.27 — Fix: het REST-verzoek van de banner gaf een 404, zichtbaar in de Network-tab als `index.php?rest_route=/yeshua/v1/new-since?since=...` (dubbel vraagteken). Oorzaak: op staging ('gewone' permalinken, geen mooie URL-structuur) bevat de door rest_url() gegenereerde basis-URL zelf al een "?". De JS plakte daar zonder controle nóg een "?" achteraan, waardoor alles erna onbedoeld bij de rest_route-waarde ging horen i.p.v. als los parameter herkend te worden -- WordPress vond de route daardoor niet meer. Opgelost: JS kiest nu "?" of "&" afhankelijk van of het endpoint al een querystring bevat.
- 3.26 — Fix: de "nieuwe artikelen"-banner (endpoint `yeshua/v1/new-since`) telde alleen post-type 'post' mee. Artikelen op deze site staan echter als WordPress-Pagina, niet als Bericht (dezelfde constatering als de categorie-archief-fix in v3.22) — daardoor werd een net toegevoegd artikel (aangemaakt als Pagina) nooit als "nieuw" herkend en bleef de banner verborgen. Opgelost door zowel 'post' als 'page' mee te tellen, met een extra filter dat alleen content mét een gekoppelde categorie meetelt (zodat het bewerken van bijv. de Contact- of Over ons-pagina niet ten onrechte als "nieuw artikel" wordt gemeld).
- 3.25 — Fix: het "Home"-item in het (gemigreerde) hoofdmenu stond vast opgeslagen als URL "/", berekend toen de site nog op de domein-root draaide. Bij een staging-kloon in een submap (WP Staging Pro, /enterprise/) reisde die vaste tekst mee en stuurde klikken op "Home" bezoekers terug naar de live site i.p.v. binnen staging te blijven. Blijvend opgelost: elk menu-item met exact "/" als URL wordt nu bij het renderen live herberekend via `home_url()` van de huidige installatie — werkt daardoor vanzelf correct op productie, op deze staging-submap, en op elke toekomstige kloon, zonder ooit nog handmatig een menu-item te hoeven aanpassen.
- 3.24 — Fix: de "nieuwe artikelen"-banner deed het REST-verzoek naar een hardcoded pad ("/wp-json/..."), wat alleen klopt als WordPress in de domein-root draait. Op een staging-kloon in een submap (bv. WP Staging Pro op /enterprise/) wees dit per ongeluk naar de REST-API van de live site in de root, waardoor het verzoek daar faalde en de banner nooit verscheen. Opgelost met `rest_url()` (nieuwe shortcode `[yeshua_rest_url]`), die altijd het juiste installatiepad gebruikt — werkt nu correct in zowel de root als een submap.
- 3.23 — "Nieuwe artikelen sinds je laatste bezoek"-banner toegevoegd op de homepage, onder de header. Toont alleen bij terugkerende bezoekers (via localStorage, geen accounts) en alleen als er sinds hun vorige bezoek daadwerkelijk nieuwe artikelen gepubliceerd zijn; zelf wegklikbaar met een kruisje. Nieuw REST-endpoint `yeshua/v1/new-since` telt/levert de nieuwe artikelen per taal op. Vertaald voor alle 7 taalvarianten (nl/en/hinglish/hi/es/zh/he) — machine-vertaald net als de rest, dus laat door een native speaker nalezen vóór je 'm live zet.
- 3.22 — Fix: categorie-archiefpagina's toonden niets, omdat de standaard query alleen naar post-type 'post' zocht terwijl deze content als Pagina's is aangemaakt.
- 3.21 — Volledige Hinglish-vertaling toegevoegd voor alle site-teksten (hero, footer, contact, zoekfunctie, enz.) — voorheen viel Hinglish terug op Nederlands omdat er geen "hinglish"-vermelding in de tekstenlijst stond. De WP-pagina "Home (hinglish)" die je zelf aanmaakte werd hier nooit voor gebruikt (die homepage-tekst staat vast in de code, niet in een bewerkbare pagina) — dat blijft zo, dit is puur een codewijziging.
- 3.20 — Hinglish toegevoegd aan de toegestane talen voor de taalknop ("Other languages"), zodat Hinglish daarin verschijnt zodra een pagina een Hinglish-vertaling heeft (te beginnen met Home). Knoptekst-label toegevoegd voor Hinglish-bezoekers.
- 3.19 — Menu-item van een categorie blijft nu ook "actief" (opgelicht + onderstreept) op losse artikelpagina's binnen die categorie, niet alleen op de categorie-overzichtspagina zelf. Gold zowel voor het echte WordPress-menu als de terugval-lijst.
- 3.18 — Waarschuwingsbalkje bij machinevertalingen ([yeshua_translation_notice]) is nu rood in plaats van geel/beige, in alle talen (HI/ES/ZH/HE). Alleen CSS-wijziging (.translation-notice in parts/header.html), geen functionele wijziging.
- 3.17 — Header-menu is nu volledig bewerkbaar via Weergave → Menu's (i.p.v. hardgecodeerd in functions.php). Registreert menu-locatie "Hoofdmenu (header)"; Polylang koppelt automatisch het juiste menu per taal. Eenmalige migratie bouwt bij activatie de 6 bestaande taalmenu's (NL/EN/HI/ES/ZH/HE) voor met de huidige items. Bevat fallback naar de oude vaste lijst zolang een taal nog geen eigen menu heeft gekoppeld, dus niets breekt tijdens de overstap. Visuele opmaak/CSS-classes ongewijzigd.
- 3.16 — Fix: tabellen met inline style="width:...; margin-left:...; padding-left:..." (bv. geplakt vanuit AI-tools/chatomgevingen) werden op mobiel platgedrukt omdat inline stijlen wonnen van de thema-CSS. Tabel-breedte, marge en celopvulling nu met !important afgedwongen op 100%/0/standaard, voor alle huidige én toekomstige tabellen.
- 3.15 — Toegevoegd: screenshot.png (thema-voorbeeldafbeelding voor Weergave → Thema's), was leeg/blanco. Echte screenshot van de live homepage-hero (aangeleverd door gebruiker), 1200x900.
- 3.14 — Fix: TERM-kolom op de definities-pagina (page-id-119928) werd platgeknepen door table-layout:fixed. Vaste 32/68-kolomverdeling toegevoegd, alleen op deze pagina — andere tabellen op de site blijven ongemoeid.
- 3.13 — Fix: scrollbalk naast tabellen (definities-pagina) verwijderd. Tabel gebruikt nu table-layout:fixed + word-wrap, zodat tekst afbreekt i.p.v. dat de tabel breder wordt dan de pagina.
- 3.12 — Fix: pillars-tegelbreedte (homepage) kwam niet overeen met de rest van de site, op zowel mobiel als desktop (dubbele padding-stapeling opgeheven). Fix: tabellen op artikelpagina's (bv. definities-pagina) scrollen nu binnen zichzelf i.p.v. de hele pagina te verschuiven. Toegevoegd: algemeen overflow-x vangnet op html, tegen toekomstige horizontale overflow-bugs.
- 3.11 — Fix: tegels (pillars-grid) op de homepage vielen op mobiel buiten de pagina (CSS grid-overflow bug, min-width:auto). Opgelost met minmax(0,1fr) + min-width:0.
- 3.10 (en eerder) — geen changelog bijgehouden; vanaf hier wordt elke versie hieronder kort genoteerd.
*/

/* v4.03 — leestijdcorrectie: machine-readable content telt niet mee; categorie-lijst volgens compact voorbeeld: thumbnail + titel + samenvatting + datum/leestijd/reacties + actieknop ===== */

/* ===== Geen automatische ruimte tussen topsecties (header/hero/etc.) — die sluiten naadloos aan ===== */
.is-root-container {
  --wp--style--block-gap: 0px;
}

/* ===== Draadmotief (signatuur-scheidingslijn, verwijzing naar tzitzit / Numeri 15:38) ===== */
.stripes {
  width: 100%;
  height: 14px;
  display: block;
  background-repeat: repeat-x;
  background-size: 56px 14px;
  opacity: 0.9;
}
/* Op lichte achtergrond: tekhelet + goud */
.stripes {
  background-image:
    linear-gradient(135deg, transparent 47%, var(--wp--preset--color--tekhelet) 47%, var(--wp--preset--color--tekhelet) 53%, transparent 53%),
    linear-gradient(45deg, transparent 47%, var(--wp--preset--color--gold) 47%, var(--wp--preset--color--gold) 53%, transparent 53%);
  background-position: 0 0, 28px 0;
}
/* Op donkere achtergrond: lichtere, warmere variant — voeg className "stripes on-night" toe */
.stripes.on-night {
  background-image:
    linear-gradient(135deg, transparent 47%, var(--wp--preset--color--gold-light) 47%, var(--wp--preset--color--gold-light) 53%, transparent 53%),
    linear-gradient(45deg, transparent 47%, var(--wp--preset--color--tekhelet-light) 47%, var(--wp--preset--color--tekhelet-light) 53%, transparent 53%);
}

/* ===== Hero: radiale gloed + rand, zoals origineel ===== */
.hero-glow {
  background-image:
    radial-gradient(ellipse 900px 500px at 80% -10%, rgba(47,76,130,0.55), transparent 60%),
    radial-gradient(ellipse 600px 400px at 10% 110%, rgba(192,138,46,0.18), transparent 60%);
  border-top: 1px solid rgba(221,176,92,0.35);
  border-bottom: 1px solid rgba(221,176,92,0.35);
  box-shadow: 0 20px 50px -20px rgba(0,0,0,0.5);
  position: relative;
}

/* ===== Sticky header met blur ===== */
.site-header-sticky {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(14,24,48,0.92) !important;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

/* ===== Eyebrow label ===== */
.eyebrow {
  font-family: var(--wp--preset--font-family--public-sans);
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--wp--preset--color--gold);
}
.eyebrow.on-dark { color: var(--wp--preset--color--gold-light); }
.eyebrow {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  font-size: 15px;
}
.eyebrow::before,
.eyebrow::after {
  content: '';
  width: 40px;
  height: 2px;
  background: currentColor;
  display: inline-block;
}

/* ===== Kaarten (thema-kaarten / artikelkaarten) ===== */
.theme-card {
  background: #fff;
  border: 1px solid rgba(38,36,30,0.14);
  border-radius: 4px;
  padding: 26px;
  transition: transform .15s ease, box-shadow .15s ease;
}
.theme-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 12px 26px rgba(38,36,30,.10);
}
.icon-badge {
  width: 44px;
  height: 44px;
  border-radius: 4px;
  background: var(--wp--preset--color--parchment-deep);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 16px;
}

/* ===== Knoppen ===== */
.wp-block-button.is-style-ghost .wp-block-button__link {
  background: transparent !important;
  color: var(--wp--preset--color--parchment) !important;
  border: 1px solid rgba(255,255,255,0.14) !important;
}
.wp-block-button.is-style-ghost .wp-block-button__link:hover {
  border-color: var(--wp--preset--color--gold-light) !important;
  color: var(--wp--preset--color--gold-light) !important;
}
.wp-block-button__link {
  border-radius: 3px !important;
  font-weight: 600 !important;
  font-size: 14px !important;
  padding: 12px 24px !important;
}

/* ===== Uitvulling body-tekst (v3.96) =====
   Standaard: justify voor Latijns schrift (NL/EN/ES/Hinglish) en Hindi
   (Devanagari) -- deze rekken woord-spaties uit, dus text-justify:inter-word.
   Chinees heeft geen woord-spaties; de browser moet daar TEKENS spreiden
   i.p.v. woorden, vandaar de aparte regel op html[lang^="zh"] met
   text-justify:inter-character. Hebreeuws (RTL) volgt de basisregel --
   CSS justify werkt vanzelf van rechts naar links zodra dir="rtl" staat
   (zie yeshua_online_is_rtl_lang() in functions.php).
   Op smalle schermen (mobiel) schakelen we justify uit: bij een smalle
   kolom worden de uitgerekte woord-spaties al snel lelijke "rivertjes"
   van witruimte, in élke taal -- links uitgelijnd blijft daar leesbaarder. */
.article-content p {
  text-align: justify;
  text-justify: inter-word;
}
html[lang^="zh"] .article-content p {
  text-justify: inter-character;
}
@media (max-width: 480px) {
  .article-content p {
    /* v4.19: 'start' i.p.v. 'left' -- links in LTR-talen, rechts in
       RTL-talen (he/ar). 'left' zette RTL-tekst op mobiel ten onrechte
       tegen de linkerkant. */
    text-align: start;
  }
}

/* ===== Arabische typografie (v4.19) =====
   html[lang^="ar"] wordt door WordPress/Polylang gezet op Arabische
   pagina's; dir="rtl" + body.rtl komen uit yeshua_online_is_rtl_lang().
   (1) Fraunces en Public Sans bevatten geen Arabische tekens. Zonder
       eigen fallback kiest de browser een willekeurig systeemfont.
       Latijnse tekens blijven in Fraunces/Public Sans (per-teken
       fallback), Arabisch valt terug op een leesbaar Arabisch font.
   (2) Geen cursief: Arabisch heeft geen echte italic, de browser maakt
       dan een scheef, vervormd 'nep-cursief'.
   (3) Geen letter-spacing in de artikeltekst/titel: extra spatiëring
       verbreekt de verbindingen tussen Arabische letters. */
html[lang^="ar"],
html[lang^="ar"] body {
  --sans: 'Public Sans', 'Noto Naskh Arabic', 'Segoe UI', Tahoma, 'Geeza Pro', sans-serif;
  --serif: 'Fraunces', 'Noto Naskh Arabic', 'Times New Roman', 'Geeza Pro', serif;
  --wp--preset--font-family--public-sans: var(--sans);
  --wp--preset--font-family--fraunces: var(--serif);
}
html[lang^="ar"] :is(em, i, cite, blockquote, h1, h2, h3, h4) {
  font-style: normal;
}
html[lang^="ar"] :is(.article-content, .article-title, .article-tag),
html[lang^="ar"] :is(.article-content, .article-title, .article-tag) * {
  letter-spacing: normal;
}
html[lang^="ar"] .article-content {
  line-height: 1.9;
}

/* ===== Naam-brug in hero (Yeshua <-> Jezus/lokale naam), v4.12 =====
   Lege string (bv. taal 'he', waar de brug bewust niet ingevuld is)
   mag geen extra witruimte overhouden. */
.hero-name-bridge {
  font-family: var(--wp--preset--font-family--public-sans);
  font-size: 15px;
  font-weight: 500;
  color: var(--wp--preset--color--gold-light);
  margin: 18px 0 0;
  max-width: 680px;
  margin-left: auto;
  margin-right: auto;
}
.hero-name-bridge:empty {
  display: none;
  margin: 0;
}

/* ===== Bijbelvers-blok ===== */
.verse-block {
  text-align: center;
}
.verse-block p {
  font-family: var(--wp--preset--font-family--fraunces);
  font-style: italic;
  font-weight: 500;
}
.verse-block cite {
  color: var(--wp--preset--color--gold-light);
  font-style: normal;
  font-size: 13px;
  letter-spacing: 0.06em;
}

/* ===== Zoek/filter toolbar (categoriepagina) ===== */
.filter-chip {
  display: inline-block;
  font-size: 13px;
  font-weight: 500;
  padding: 8px 14px;
  border-radius: 20px;
  border: 1px solid rgba(38,36,30,0.14);
  background: #fff;
  margin: 0 6px 6px 0;
}
.filter-chip.is-active {
  background: var(--wp--preset--color--gold);
  border-color: var(--wp--preset--color--gold);
  color: var(--wp--preset--color--night-deep);
}

/* ===== Progress check op artikelkaarten ===== */
.read-check {
  color: var(--wp--preset--color--tekhelet);
  font-weight: 700;
}

/* ===== Leestijd-indicator (boven artikel) =====
   Zelfde kolombreedte als .article-content (zie parts/header.html,
   embedded <style>: .article-content{max-width:900px;margin:0 auto})
   zodat de linkerkantlijn exact parallel loopt met de artikeltekst. */
.reading-time {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px;
  max-width: 900px;
  margin: 4px auto 24px;
  font-family: var(--wp--preset--font-family--public-sans);
  font-size: 13px;
  color: var(--wp--preset--color--tekhelet);
}
/* v4.18: min-width:0 + flex-wrap:wrap + overflow-wrap zorgen dat een
   los item (icoon + label + waarde) nooit breder kan blijven dan zijn
   eigen rij -- de tekst breekt dan naar een tweede regel binnen het
   item, in plaats van dat er niets is dat een te brede combinatie
   tegenhoudt en de hele pagina horizontaal meeschuift. Geen
   horizontaal scrollen hier (i.t.t. tabellen): dit is korte
   labeltekst, geen tabulaire data, dus wrappen blijft in één
   oogopslag leesbaar. */
.reading-time__item {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  min-width: 0;
  max-width: 100%;
}
.reading-time__icon {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
}
.reading-time__label,
.reading-time__value {
  color: inherit;
  font-weight: inherit;
  font-size: inherit;
  overflow-wrap: break-word;
  min-width: 0;
}

/* ===== Google Fonts fallback als lokale fonts niet laden ===== */
body { font-family: var(--wp--preset--font-family--public-sans); }

/* ==========================================================================
   v4.30 — Start Here: twee routes bovenaan de Start Here-categorie
   (inhoud komt uit de pagina "start-here-intro", zie [yeshua_start_here_intro])
   ========================================================================== */
.terms-banner__sep{ display:inline; }

.start-intro{
  background:var(--parchment, #F6F1E4);
  padding:48px 28px 24px;
}
.start-intro__inner{ max-width:1140px; margin:0 auto; }
.start-intro__inner > p:empty{ display:none; }
.start-intro__edit{ margin:0 0 12px; font-size:0.8rem; text-align:right; }
.start-intro__edit a{ color:var(--tekhelet, #2F4C82); }

.start-intro .start-lead{
  max-width:720px; margin:0 auto 32px; text-align:center;
  font-size:1.1rem; line-height:1.65; color:var(--ink, #26241E);
}

/* Twee kaarten naast elkaar, op mobiel onder elkaar */
.start-intro .start-paths{
  display:grid;
  grid-template-columns:repeat(auto-fit, minmax(300px, 1fr));
  gap:22px;
  margin:0 0 56px;
}
.start-intro .start-path{
  background:#FFFDF7;
  border:1px solid var(--parchment-deep, #EFE7D3);
  border-top:4px solid var(--gold, #C08A2E);
  border-radius:8px;
  padding:28px 28px 24px;
  box-shadow:0 6px 20px rgba(21,34,66,0.08);
}
.start-intro .start-eyebrow{
  margin:0 0 6px;
  font-size:0.78rem; font-weight:700; letter-spacing:0.12em; text-transform:uppercase;
  color:#7A5714;
}
.start-intro h2{
  font-family:var(--serif, 'Fraunces', Georgia, serif);
  color:var(--night, #152242);
  font-size:1.7rem; line-height:1.2; margin:0 0 12px;
}
.start-intro .start-path{ display:flex; flex-direction:column; }
.start-intro .start-path p{ margin:0 0 16px; line-height:1.6; text-align:left; }
/* v4.32: de knop staat altijd onderaan de tegel, in beide tegels op dezelfde hoogte */
.start-intro .start-path > p:last-child{ margin:auto 0 0; padding-top:12px; text-align:center !important; }
body.rtl .start-intro .start-path > p:last-child{ text-align:center !important; }
.start-intro .start-button{
  display:inline-flex !important; align-items:center; justify-content:center;
  width:auto !important; max-width:100%; height:auto !important;
  white-space:normal; text-align:center; line-height:1.3;
  background:var(--night, #152242); color:var(--parchment, #F6F1E4) !important;
  font-weight:600; text-decoration:none !important;
  padding:12px 22px; border-radius:4px; min-height:44px; box-sizing:border-box;
}
.start-intro .start-button:hover{ background:var(--tekhelet, #2F4C82); }

/* Leeslijst in kaart 2 */
.start-intro .start-readlist{ list-style:none; margin:0; padding:0; counter-reset:readlist; }
.start-intro .start-readlist li{
  counter-increment:readlist;
  border-bottom:1px solid var(--parchment-deep, #EFE7D3);
  padding:10px 0; margin:0;
}
.start-intro .start-readlist li:last-child{ border-bottom:0; }
.start-intro .start-readlist li::before{ content:counter(readlist) ". "; color:#7A5714; font-weight:700; }
.start-intro .start-readlist a{ color:var(--night, #152242); text-decoration:none; }
.start-intro .start-readlist a:hover{ text-decoration:underline; }
.start-intro .start-readlist li:first-child a{ font-weight:700; }

/* Genummerde stappen (route 1) */
.start-intro .start-route{ max-width:860px; margin:0 auto 48px; }
.start-intro .start-route > p{ text-align:left; }
.start-intro .start-steps{ list-style:none; margin:24px 0 0; padding:0; counter-reset:step; }
.start-intro .start-steps li{
  counter-increment:step;
  position:relative;
  background:#FFFDF7;
  border:1px solid var(--parchment-deep, #EFE7D3);
  border-radius:8px;
  padding:20px 22px 20px 88px;
  margin:0 0 14px;
  line-height:1.6;
}
.start-intro .start-steps li::before{
  content:counter(step);
  position:absolute; left:22px; top:18px;
  width:46px; height:46px; border-radius:50%;
  background:var(--night, #152242); color:var(--parchment, #F6F1E4);
  font-family:var(--serif, 'Fraunces', Georgia, serif); font-size:1.35rem; font-weight:700;
  display:flex; align-items:center; justify-content:center;
}
.start-intro .start-steps a{
  display:block; margin-bottom:4px;
  font-family:var(--serif, 'Fraunces', Georgia, serif);
  font-size:1.2rem; font-weight:600; color:var(--night, #152242); text-decoration:none;
}
.start-intro .start-steps a:hover{ text-decoration:underline; }
.start-intro .start-steps .start-meta{ display:block; font-size:0.85rem; color:#5B6075; margin-top:4px; }

.start-intro .start-all{ text-align:center; margin:8px 0 0; }

body.rtl .start-intro .start-path p,
body.rtl .start-intro .start-route > p{ text-align:right; }
body.rtl .start-intro .start-steps li{ padding:20px 88px 20px 22px; }
body.rtl .start-intro .start-steps li::before{ left:auto; right:22px; }

@media (max-width:600px){
  .start-intro{ padding:32px 16px 16px; }
  .start-intro .start-path{ padding:22px 18px 18px; }
  .start-intro h2{ font-size:1.4rem; }
  .start-intro .start-steps li{ padding:16px 16px 16px 72px; }
  .start-intro .start-steps li::before{ left:16px; width:40px; height:40px; font-size:1.15rem; }
  body.rtl .start-intro .start-steps li{ padding:16px 72px 16px 16px; }
  body.rtl .start-intro .start-steps li::before{ right:16px; }
}

/* v4.32 — "daaronder niets": op Start Here met intro-pagina geen zoekbalk en geen lijst */
body.start-here--intro-only .toolbar-section,
body.start-here--intro-only main.wp-block-group{ display:none !important; }
body.start-here--intro-only .start-intro{ padding-bottom:64px; }

/* v4.32 — terug-balk op de subcategorieën van Start Here */
.start-sub{ background:var(--parchment, #F6F1E4); padding:22px 28px 6px; }
.start-sub .wrap{ max-width:900px; }
.start-sub__back{ display:inline-block; font-weight:600; color:var(--tekhelet, #2F4C82); text-decoration:none; padding:10px 0; }
.start-sub__back:hover{ text-decoration:underline; }
.start-sub__desc{
  margin:8px 0 0; padding:16px 20px;
  background:#FFFDF7; border:1px solid var(--parchment-deep, #EFE7D3);
  border-left:4px solid var(--gold, #C08A2E); border-radius:6px; line-height:1.65;
}
.start-sub__desc p{ margin:0 0 8px; }
.start-sub__desc p:last-child{ margin:0; }
.start-sub__also{ margin:12px 0 0; font-size:0.92rem; color:#5B6075; }
.start-sub__also a{ color:var(--tekhelet, #2F4C82); font-weight:600; }
body.rtl .start-sub__desc{ border-left:1px solid var(--parchment-deep, #EFE7D3); border-right:4px solid var(--gold, #C08A2E); }
@media (max-width:600px){ .start-sub{ padding:16px 16px 4px; } }

/* v4.34 — "← Back to Start Here" rechts in de zoekbalk-sectie (alleen op Start Here-subcategorieën) */
.toolbar-section .wrap{ position:relative; }
.start-back-link{
  position:absolute; right:28px; top:0;
  display:inline-flex; align-items:center; min-height:46px;
  font-weight:600; color:var(--tekhelet, #2F4C82); text-decoration:none;
}
.start-back-link:hover{ text-decoration:underline; }
body.rtl .start-back-link{ right:auto; left:28px; }
@media (max-width:700px){
  .start-back-link,
  body.rtl .start-back-link{ position:static; display:flex; min-height:44px; margin-top:8px; }
}

/* v4.35 — Start Here-tegels op telefoons: binnen het scherm, tekst links uitgelijnd */
.start-intro .start-paths{ grid-template-columns:repeat(auto-fit, minmax(min(300px, 100%), 1fr)); }
.start-intro .start-path{ min-width:0; }
@media (max-width:700px){
  .start-intro{ padding-left:12px; padding-right:12px; }
  .start-intro .start-intro__inner.wrap{ padding-left:4px; padding-right:4px; }
  .start-intro .start-paths{ grid-template-columns:1fr; gap:18px; }
  .start-intro .start-path{ padding:22px 18px 20px; }
  .start-intro .start-intro__inner p,
  .start-intro .start-intro__inner li,
  .start-intro .start-path p{ text-align:start !important; hyphens:manual; word-spacing:normal; }
}

/* ==========================================================================
   v4.36 — Start Here: aparte mobiele inhoud (start-mobile / start-desktop)
   Beide delen staan in de pagina start-here-intro en worden daar beheerd.
   ========================================================================== */
.start-intro .start-mobile{ display:none; }

@media (max-width:700px){
  /* Alleen wisselen als de pagina een mobiel deel HEEFT; anders blijft
     de computerversie ook op telefoons zichtbaar (bv. nog niet vertaald). */
  .start-intro .start-intro__inner:has(.start-mobile) .start-desktop{ display:none; }
  .start-intro .start-mobile{ display:block; }

  .start-intro .start-mobile h2{ font-size:1.35rem; margin:0 0 8px; text-align:start; }
  .start-intro .start-mobile .start-lead{ margin:0 0 18px; text-align:start !important; font-size:0.98rem; line-height:1.55; max-width:none; }

  .start-intro .start-choice{
    display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:10px;
    margin:0 0 22px;
  }
  /* De klassieke editor (wpautop) kan <p> of <br> rond de links zetten: neutraliseren */
  .start-intro .start-choice > p{ display:contents; }
  .start-intro .start-choice br{ display:none; }
  .start-intro .start-choice a{
    display:flex; flex-direction:column; justify-content:space-between; gap:12px;
    min-height:132px; box-sizing:border-box;
    background:#FFFDF7; border:1px solid var(--parchment-deep, #EFE7D3);
    border-top:4px solid var(--gold, #C08A2E); border-radius:8px;
    padding:14px 12px; text-decoration:none !important;
    color:var(--night, #152242) !important;
    box-shadow:0 4px 14px rgba(21,34,66,0.08);
  }
  .start-intro .start-choice a > span:first-child{
    font-family:var(--serif, 'Fraunces', Georgia, serif);
    font-size:1rem; line-height:1.25; font-weight:600;
  }
  .start-intro .start-choice a > span:last-child{
    display:block; background:var(--night, #152242); color:var(--parchment, #F6F1E4);
    font-size:0.82rem; font-weight:600; text-align:center; line-height:1.25;
    border-radius:4px; padding:11px 6px;
  }
  .start-intro .start-choice a:hover > span:last-child{ background:var(--tekhelet, #2F4C82); }
  .start-intro .start-choice a:focus-visible{ outline:3px solid var(--gold-light, #DDB05C); outline-offset:2px; }

  .start-intro .start-more{ border-top:1px solid var(--parchment-deep, #EFE7D3); padding-top:16px; }
  .start-intro .start-more > p:first-child{
    margin:0 0 8px; font-size:0.75rem; letter-spacing:0.1em; text-transform:uppercase;
    color:#7A5714; font-weight:700; text-align:start !important;
  }
  .start-intro .start-more details{
    background:#FFFDF7; border:1px solid var(--parchment-deep, #EFE7D3);
    border-radius:6px; padding:12px 14px; margin:0 0 8px;
  }
  .start-intro .start-more summary{ font-weight:600; color:var(--night, #152242); cursor:pointer; min-height:24px; }
  .start-intro .start-more details p,
  .start-intro .start-more details li{ font-size:0.92rem; line-height:1.55; text-align:start !important; }
  .start-intro .start-more details p{ margin:10px 0 0; }
  .start-intro .start-more .start-readlist{ margin-top:8px; }
}

/* v4.37 — keuzetegels op naam i.p.v. volgorde (start-choice-title / start-choice-btn),
   en steviger, zodat plugins (tooltip, editor) de opmaak niet meer kunnen breken. */
@media (max-width:700px){
  .start-intro .start-choice a{
    display:flex !important; flex-direction:column !important; justify-content:space-between !important;
    text-align:start !important; font-family:var(--sans, 'Public Sans', sans-serif);
  }
  .start-intro .start-choice .start-choice-title{
    display:block !important;
    font-family:var(--serif, 'Fraunces', Georgia, serif) !important;
    font-size:1rem !important; line-height:1.25 !important; font-weight:600 !important;
    color:var(--night, #152242) !important;
  }
  .start-intro .start-choice .start-choice-btn{
    display:block !important; margin-top:12px;
    background:var(--night, #152242) !important; color:var(--parchment, #F6F1E4) !important;
    font-family:var(--sans, 'Public Sans', sans-serif) !important;
    font-size:0.82rem !important; font-weight:600 !important; text-align:center !important; line-height:1.25 !important;
    border-radius:4px; padding:11px 6px !important;
  }
  .start-intro .start-choice a:hover .start-choice-btn{ background:var(--tekhelet, #2F4C82) !important; }
  /* Eventuele tooltip-opmaak binnen de tegel neutraal houden */
  .start-intro .start-choice .start-choice-title *,
  .start-intro .start-choice .start-choice-btn *{
    color:inherit !important; border:0 !important; background:none !important;
    text-decoration:none !important; font:inherit !important; padding:0 !important;
  }
}


/* v4.39 — Engelse terugval in categorieën (alle talen). */
.en-fallback-section{ display:none; margin-top:48px; }
body.has-en-fallback .en-fallback-section{ display:block; }
body.has-en-fallback .archive-empty-hint{ display:none; }
.en-fallback-heading{ font-family:'Fraunces', Georgia, serif; font-size:1.5rem; font-weight:600; margin:0 0 22px; }

/* v4.42 — melding op een nog niet vertaalde categorie + "Ga terug". */
.cat-lang-notice{ background:#f6eedc; border-bottom:1px solid #e3d2a8; padding:14px 28px; display:flex; flex-wrap:wrap; align-items:center; justify-content:center; gap:8px 18px; text-align:center; }
.cat-lang-notice p{ margin:0; font-size:0.95rem; color:#5c4415; max-width:720px; }
.yeshua-go-back{ font-weight:600; color:#2F4C82; text-decoration:underline; white-space:nowrap; }
.yeshua-go-back:hover{ text-decoration:none; }
.cat-lang-notice .yeshua-go-back{ font-size:0.95rem; }
.archive-empty-hint .yeshua-go-back{ margin-inline-start:10px; }
body.en-fallback-only .en-fallback-heading{ display:none; }
body.en-fallback-only .en-fallback-section{ margin-top:8px; }
@media (max-width:700px){ .cat-lang-notice{ padding:12px 16px; } }
.untranslated-label{
  display:inline-block; margin:0 0 8px; padding:3px 10px; border-radius:20px;
  font-size:.7rem; font-weight:600; letter-spacing:.04em; text-transform:uppercase;
  color:#7a5b1e; background:#f6eedc;
}
.article-card:has(.untranslated-label){ direction:ltr; text-align:left; }
.article-card:has(.untranslated-label) .untranslated-label{ direction:rtl; }
body:not(.rtl) .article-card:has(.untranslated-label) .untranslated-label{ direction:ltr; }


/* v4.40 — 404-pagina (alle talen, ook RTL). */
.nf-title{
  font-family:var(--serif, 'Fraunces', Georgia, serif); font-weight:500; font-size:clamp(1.8rem,4vw,2.4rem);
  color:var(--parchment, #F6F1E4); background:var(--night, #152242); text-align:center;
  margin:0 auto; padding:56px 28px 44px; max-width:1140px; box-sizing:border-box;
}
.nf-section{ background:var(--parchment, #F6F1E4); padding:48px 28px 80px; }
.nf-inner{ max-width:640px; margin:0 auto; text-align:center; }
.nf-text{ font-size:1.05rem; line-height:1.7; margin:0 0 28px; }
.nf-search{ margin:0 auto 32px; }
.nf-buttons{ display:flex; flex-wrap:wrap; justify-content:center; gap:14px; }
.nf-btn-outline{ color:var(--night, #152242); border:1px solid var(--night, #152242); }
.nf-btn-outline:hover{ background:var(--night, #152242); color:var(--parchment, #F6F1E4); }
@media (max-width:640px){
  .nf-section{ padding:36px 16px 60px; }
  .nf-buttons .btn{ width:100%; justify-content:center; box-sizing:border-box; }
}


/* v4.41 — terugknop op Engelse terugval-artikelen. */
.yeshua-back-bar{ background:#f6eedc; border-bottom:1px solid var(--line, #e2d8bf); }
.yeshua-back-bar__inner{ max-width:1140px; margin:0 auto; padding:12px 28px; display:flex; align-items:center; gap:16px; flex-wrap:wrap; box-sizing:border-box; }
.yeshua-back-bar__link{ font-weight:600; color:var(--night, #152242); text-decoration:none; border:1px solid var(--night, #152242); border-radius:3px; padding:8px 16px; }
.yeshua-back-bar__link:hover{ background:var(--night, #152242); color:var(--parchment, #F6F1E4); }
.yeshua-back-bar__note{ font-size:.9rem; color:#7a5b1e; flex:1; }
.yeshua-back-bar__close{ background:none; border:0; font-size:1.3rem; line-height:1; cursor:pointer; color:#7a5b1e; padding:4px 8px; }
@media (max-width:640px){
  .yeshua-back-bar__inner{ padding:10px 16px; gap:10px; }
  .yeshua-back-bar__link{ flex:1 1 100%; text-align:center; order:1; }
  .yeshua-back-bar__note{ order:2; }
  .yeshua-back-bar__close{ order:3; }
}
