/*
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: 3.97
Requires at least: 6.4
Requires PHP: 7.4
Text Domain: yeshua-online

Changelog:
- 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.
*/

/* ===== 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 {
    text-align: left;
  }
}

/* ===== 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);
}
.reading-time__item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.reading-time__icon {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
}
.reading-time__label,
.reading-time__value {
  color: inherit;
  font-weight: inherit;
  font-size: inherit;
}

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