{"key":"pubmed_list","name":"PubMed → Formatted Citations (Batch)","instructions":"Füge eine oder mehrere PubMed-IDs (PMIDs) ein – folgende Formate werden erkannt:\n 12345678 (bare PMID)\n PMID: 12345678 (mit Präfix)\n pmid:12345678 (ohne Leerzeichen)\nTrenner: Leerzeichen, Komma oder Semikolon. Bis zu 100 PMIDs pro Filter.\n\nDie PMID eines Artikels findet man:\n - auf pubmed.ncbi.nlm.nih.gov (in der URL und oben rechts)\n - im PDF vieler Artikel (\"PMID: xxxxx\" am Ende)\n\nBeispiele (Kommas zwischen Parametern sind Pflicht):\n {GENERICO:type=\"pubmed_list\", pmid=\"26378978\"}\n {GENERICO:type=\"pubmed_list\", pmids=\"26378978 25176015 24678782\"}\n\nOptionen (alle optional – Standard ist Vancouver auf Deutsch):\n preset : Zitierstil wählen\n vancouver → Vancouver (Standard)\n apa-de → APA auf Deutsch\n apa → APA auf Englisch\n harvard → Harvard\n chicago-ad → Chicago Author-Date\n mla → MLA\n din-1505-2 → DIN 1505-2\n iso-690-author-date→ ISO 690 Author-Date\n iso-690-numeric → ISO 690 Numeric\n locale : de-DE | en-US | en-GB\n heading : true | false → Überschrift „Literatur\" / „References\"\n design : classic | academic | modern\n spacing : comfortable | compact | loose\n list : br | ol | ul\n link : true | false → klickbarer PubMed-Link hinter jede Angabe\n ttl : Cache-Dauer in Tagen (Standard: 30; ttl=0 = kein Cache)\n vancspace : true | false → Leerzeichen nach Semikolon (nur Vancouver)\n\nHinweis: Kann eine PMID nicht aufgelöst werden, erscheint der\nklickbare Link https://pubmed.ncbi.nlm.nih.gov/… als Fallback.\n\nTipp: Nutze den Generico-Button im Editor für korrekte Tag-Syntax.","requirecss":"","requirejs":"","shim":"","defaults":"pmids=, pmid=, preset=vancouver|apa-de|apa|harvard|chicago-ad|mla|din-1505-2|iso-690-author-date|iso-690-numeric, style=, locale=de-DE|en-US|en-GB, heading=true|false, design=classic|academic|modern, spacing=comfortable|compact|loose, list=br|ol|ul, link=true|false, ttl=30|7|90|0, vancspace=false|true","amd":"1","body":"
\n\n
\n\n
\n
Formatting citations …
\n \n
\n
","bodyend":"","script":"(function () {\n \"use strict\";\n\n // =========================================================\n // CONFIG\n // =========================================================\n var MAX_IDS = 100;\n var TIMEOUT_MS = 8000;\n var CONCURRENCY = 5; // increased from 3 – faster for large lists\n var REQUEST_GAP_MS = 100; // reduced from 150ms\n var PER_DOI_DEADLINE_MS = 16000;\n var RETRY_BACKOFF_MS = 300;\n var CACHE_KEY = \"pmidCiteCache::v2\";\n\n // =========================================================\n // UTILITIES\n // =========================================================\n\n function escapeHtml(s) {\n return (s || \"\").replace(/[&<>\"']/g, function (c) {\n return { \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\", \"'\": \"'\" }[c];\n });\n }\n\n\n\n // Accepts all PMID formats:\n // 12345678 (bare PMID)\n // PMID: 12345678 (with prefix)\n // pmid:12345678 (no space)\n function extractPmids(raw) {\n if (!raw) return [];\n var normalized = raw.replace(/\\bpmid[:\\s]*/gi, \"\").replace(/\\bpubmed[:\\s]*/gi, \"\");\n var re = /\\b(\\d{5,9})\\b/g;\n var out = [];\n var seen = {};\n var m;\n while ((m = re.exec(normalized)) !== null) {\n var id = m[1].replace(/^0+/, \"\");\n if (id && !seen[id]) {\n seen[id] = true;\n out.push(id);\n if (out.length >= MAX_IDS) break;\n }\n }\n return out;\n }\n\n function isHtml(text) {\n if (!text) return false;\n var t = text.trim().toLowerCase();\n return (\n t.startsWith(\" 2000) return false;\n if (t.split(/\\s+/).length < 4) return false;\n if (!t.includes(\".\")) return false;\n return true;\n }\n\n function stripLeadingNumber(text) {\n return (text || \"\").replace(/^\\s*[\\(\\[]?\\d+[\\]\\).]?\\s*[-–—]?\\s*/, \"\").trim();\n }\n\n function removeProviderRefLines(text) {\n if (!text) return text;\n return text\n .replace(/verfügbar\\s+unter:\\s*\\S+/gi, \"\")\n .replace(/available\\s+(?:from|at):\\s*\\S+/gi, \"\")\n .replace(/\\bdoi:\\s*\\S+/gi, \"\")\n .replace(/\\burl:\\s*\\S+/gi, \"\")\n .replace(/https?:\\/\\/(dx\\.)?doi\\.org\\/\\S+/gi, \"\")\n .replace(/\\s{2,}/g, \" \")\n .trim();\n }\n\n // =========================================================\n // DOI LINK\n // =========================================================\n\n\n // =========================================================\n // CACHE (with pruning of expired entries on write)\n // =========================================================\n\n function nowSec() { return Math.floor(Date.now() / 1000); }\n\n function getCache() {\n try { return JSON.parse(localStorage.getItem(CACHE_KEY) || \"{}\"); }\n catch (e) { return {}; }\n }\n\n function setCache(obj, maxAgeSec) {\n var now = nowSec();\n var pruned = {};\n Object.keys(obj).forEach(function (k) {\n var e = obj[k];\n if (e && e.t && (now - e.t) < maxAgeSec) pruned[k] = e;\n });\n try { localStorage.setItem(CACHE_KEY, JSON.stringify(pruned)); }\n catch (ex) { /* storage full – silently ignore */ }\n }\n\n function cacheKey(doi, style, locale, linkFlag) {\n return style + \"|\" + locale + \"|L\" + (linkFlag ? \"1\" : \"0\") + \"|\" + doi;\n }\n\n // =========================================================\n // PROMISE HELPERS\n // =========================================================\n\n function withTimeout(promise, ms) {\n return Promise.race([\n promise,\n new Promise(function (_, reject) {\n setTimeout(function () { reject(new Error(\"timeout\")); }, ms);\n })\n ]);\n }\n\n function sleep(ms) {\n return new Promise(function (res) { setTimeout(res, ms); });\n }\n\n function withRetry(fn) {\n return fn().catch(function () {\n return sleep(RETRY_BACKOFF_MS).then(fn);\n });\n }\n\n // =========================================================\n // CSL PRESETS\n // =========================================================\n var PRESETS = {\n \"vancouver\": { style: \"vancouver\" },\n \"apa\": { style: \"apa\" },\n \"apa-de\": { style: \"apa\", locale: \"de-DE\" },\n \"harvard\": { style: \"harvard1\" },\n \"chicago-ad\": { style: \"chicago-author-date\" },\n \"mla\": { style: \"mla\" },\n \"din-1505-2\": { style: \"din-1505-2\" },\n \"iso-690-author-date\": { style: \"iso690-author-date\" },\n \"iso-690-numeric\": { style: \"iso690-numeric\" }\n };\n\n function resolveStyleLocale(presetAttr, styleAttr, localeAttr) {\n var p = (presetAttr || \"\").trim().toLowerCase();\n var pre = PRESETS[p] || {};\n var style = pre.style || \"vancouver\";\n var locale = pre.locale || \"de-DE\";\n if (styleAttr && styleAttr.trim()) style = styleAttr.trim();\n if (localeAttr && localeAttr.trim()) locale = localeAttr.trim();\n return { style: style, locale: locale };\n }\n\n // =========================================================\n // PMID UTILITIES\n // =========================================================\n\n function cleanPmid(raw) {\n return (raw || \"\")\n .trim()\n .replace(/^(?:pmid|pubmed)[:\\s]*/gi, \"\")\n .replace(/[^0-9]/g, \"\")\n .replace(/^0+/, \"\");\n }\n\n function extractPmids(raw) {\n if (!raw) return [];\n var normalized = raw.replace(/\\bpmid[:\\s]*/gi, \"\").replace(/\\bpubmed[:\\s]*/gi, \"\");\n var re = /\\b(\\d{5,9})\\b/g;\n var out = [];\n var seen = {};\n var m;\n while ((m = re.exec(normalized)) !== null) {\n var id = m[1].replace(/^0+/, \"\");\n if (id && !seen[id]) {\n seen[id] = true;\n out.push(id);\n if (out.length >= MAX_IDS) break;\n }\n }\n return out;\n }\n\n function pmidLink(id) {\n var clean = (id || \"\").replace(/\\s+/g, \"\").trim();\n var href = \"https://pubmed.ncbi.nlm.nih.gov/\" + clean + \"/\";\n return (\n '' +\n escapeHtml(href) +\n \"\"\n );\n }\n\n // =========================================================\n // PROVIDERS\n // =========================================================\n\n // Provider 1: NCBI esummary – most reliable for journal name\n // Returns: title, source (journal), authors, year, volume, issue, pages\n function providerNCBIsummary(pmid) {\n var url = \"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi\" +\n \"?db=pubmed&id=\" + encodeURIComponent(pmid) +\n \"&retmode=json&tool=vetucation_moodle&email=elearning@vetmeduni.ac.at\";\n return withTimeout(\n fetch(url)\n .then(function (r) {\n if (!r.ok) throw new Error(\"HTTP \" + r.status);\n return r.json();\n })\n .then(function (json) {\n var result = json && json.result && json.result[pmid];\n if (!result || result.error) throw new Error(\"no result\");\n\n var title = (result.title || \"\").replace(/\\.$/, \"\");\n var journal = result.source || \"\";\n var year = (result.pubdate || \"\").substring(0, 4);\n var vol = result.volume || \"\";\n var issue = result.issue || \"\";\n var pages = result.pages || \"\";\n\n var authors = (result.authors || []).slice(0, 6).map(function (a) {\n return a.name || \"\";\n }).filter(Boolean);\n if ((result.authors || []).length > 6) authors.push(\"u.\\u00a0a.\");\n var authorStr = authors.join(\", \");\n\n if (!title) throw new Error(\"no title\");\n\n var vol_issue = vol ? (vol + (issue ? \"(\" + issue + \")\" : \"\")) : \"\";\n var pagination = (vol_issue && pages) ? vol_issue + \":\" + pages\n : (vol_issue || pages);\n\n var ref = \"\";\n if (authorStr) ref += authorStr.replace(/\\.\\s*$/, \"\") + \". \";\n ref += title + \".\";\n if (journal) ref += \" \" + journal + \".\";\n if (year) ref += \" \" + year;\n if (pagination) ref += \";\" + pagination + \".\";\n\n return ref.trim();\n }),\n TIMEOUT_MS\n );\n }\n\n // Provider 2: Europe PMC – CORS-friendly fallback with full detail\n function providerEuropePMC(pmid) {\n var url = \"https://www.ebi.ac.uk/europepmc/webservices/rest/search\" +\n \"?query=EXT_ID:\" + encodeURIComponent(pmid) + \"%20AND%20SRC:MED\" +\n \"&format=json&resulttype=core\";\n return withTimeout(\n fetch(url)\n .then(function (r) {\n if (!r.ok) throw new Error(\"HTTP \" + r.status);\n return r.json();\n })\n .then(function (json) {\n var list = json && json.resultList && json.resultList.result;\n if (!list || !list.length) throw new Error(\"no results\");\n var it = list[0];\n\n var title = (it.title || \"\").replace(/\\.$/, \"\");\n var journal = it.journalTitle || it.journalAbbreviation || it.journal || it.bookOrReportDetails && it.bookOrReportDetails.publisher || \"\";\n var year = it.pubYear || \"\";\n var vol = it.journalVolume || \"\";\n var issue = it.issue || \"\";\n var pages = it.pageInfo || \"\";\n var doi = it.doi || \"\";\n\n var authorList = (it.authorList && it.authorList.author) || [];\n var authors = authorList.slice(0, 6).map(function (a) {\n var ln = a.lastName || \"\";\n var fn = a.initials || a.firstName || \"\";\n return ln && fn ? ln + \" \" + fn : (ln || fn);\n }).filter(Boolean);\n if (authorList.length > 6) authors.push(\"u.\\u00a0a.\");\n var authorStr = authors.join(\", \");\n\n if (!title) throw new Error(\"no title\");\n\n var vol_issue = vol ? (vol + (issue ? \"(\" + issue + \")\" : \"\")) : \"\";\n var pagination = (vol_issue && pages) ? vol_issue + \":\" + pages\n : (vol_issue || pages);\n\n var ref = \"\";\n if (authorStr) ref += authorStr.replace(/\\.\\s*$/, \"\") + \". \";\n ref += title + \".\";\n if (journal) ref += \" \" + journal + \".\";\n if (year) ref += \" \" + year;\n if (pagination) ref += \";\" + pagination + \".\";\n if (doi) ref += \" https://doi.org/\" + doi;\n\n return ref.trim();\n }),\n TIMEOUT_MS\n );\n }\n\n // Provider 3: Europe PMC minimal – authorString fallback\n function providerEuropePMCminimal(pmid) {\n var url = \"https://www.ebi.ac.uk/europepmc/webservices/rest/search\" +\n \"?query=EXT_ID:\" + encodeURIComponent(pmid) + \"%20AND%20SRC:MED\" +\n \"&format=json\";\n return withTimeout(\n fetch(url)\n .then(function (r) {\n if (!r.ok) throw new Error(\"HTTP \" + r.status);\n return r.json();\n })\n .then(function (json) {\n var list = json && json.resultList && json.resultList.result;\n if (!list || !list.length) throw new Error(\"no results\");\n var it = list[0];\n var title = it.title || \"\";\n var authors = (it.authorString|| \"\").trim();\n var journal = it.journalTitle || it.journalAbbreviation || it.source || \"\";\n var year = it.pubYear || \"\";\n if (!title) throw new Error(\"no title\");\n return [authors, title, journal, year].map(function(s){ return s.replace(/\\.\\s*$/, \"\"); }).filter(Boolean).join(\". \") + \".\";\n }),\n TIMEOUT_MS\n );\n }\n\n function fetchCitation(pmid, style, locale, vancspace) {\n var deadline = Date.now() + PER_DOI_DEADLINE_MS;\n\n var providers = [\n function () { return providerNCBIsummary(pmid); },\n function () { return providerEuropePMC(pmid); },\n function () { return providerEuropePMCminimal(pmid); }\n ];\n\n function tryNext(i) {\n if (i >= providers.length || Date.now() > deadline) {\n return Promise.resolve(null);\n }\n return withRetry(providers[i])\n .then(function (text) {\n if (!text || isHtml(text) || looksLikeError(text) || !looksLikeCitation(text)) {\n return tryNext(i + 1);\n }\n text = stripLeadingNumber(text);\n text = removeProviderRefLines(text);\n if (style.toLowerCase() === \"vancouver\" && vancspace) {\n text = text.replace(\n /(\\b\\d{4}(?:\\s+[A-Za-z]{3}\\s+\\d{1,2})?)\\s*;\\s*(?=\\d)/,\n \"$1; \"\n );\n }\n return escapeHtml(text.trim());\n })\n .catch(function () { return tryNext(i + 1); });\n }\n\n return tryNext(0);\n }\n\n // =========================================================\n // PROGRESSIVE RENDERING\n // Placeholders appear immediately; each citation fills in\n // as soon as its fetch resolves – no waiting for the whole list.\n // =========================================================\n\n function buildItem(doi, citationText, linkFlag) {\n if (!citationText) return pmidLink(doi);\n return linkFlag ? citationText + \" \" + pmidLink(doi) : citationText;\n }\n\n function safeId(doi) {\n return \"cit-\" + doi.replace(/[^a-zA-Z0-9]/g, \"-\");\n }\n\n // Create the skeleton list with loading placeholders immediately\n function initPlaceholders(container, pmids, list) {\n var placeholders = {};\n\n var html;\n if (list === \"br\") {\n container.setAttribute(\"role\", \"list\");\n html = pmids.map(function (pmid) {\n var id = safeId(pmid);\n placeholders[pmid] = id;\n return (\n '
' +\n '' +\n pmidLink(pmid) +\n \"
\"\n );\n }).join(\"\");\n } else {\n container.removeAttribute(\"role\");\n var tag = list === \"ul\" ? \"ul\" : \"ol\";\n html = \"<\" + tag + \">\" +\n pmids.map(function (pmid) {\n var id = safeId(pmid);\n placeholders[pmid] = id;\n return (\n '
  • ' +\n '' +\n pmidLink(pmid) +\n \"
  • \"\n );\n }).join(\"\") +\n \"\";\n }\n container.innerHTML = html;\n return placeholders;\n }\n\n // Replace a single placeholder with resolved content\n function updatePlaceholder(container, id, html) {\n var el = container.querySelector(\"#\" + id);\n if (!el) return;\n el.innerHTML = html;\n el.classList.remove(\"citation-item--loading\");\n }\n\n function updateCounter(loadEl, done, total) {\n if (!loadEl) return;\n loadEl.textContent = done + \" / \" + total + \" \\u2026\";\n }\n\n // =========================================================\n // PROCESS ONE BLOCK\n // =========================================================\n\n function processBlock(root) {\n if (root.hasAttribute(\"data-citations-processed\")) return;\n root.setAttribute(\"data-citations-processed\", \"1\");\n\n\n\n var rawDois = root.getAttribute(\"data-pmids\") || \"\";\n var single = root.getAttribute(\"data-pmid\") || \"\";\n var preset = root.getAttribute(\"data-preset\") || \"\";\n var styleAttr = root.getAttribute(\"data-style\") || \"\";\n var localeAttr = root.getAttribute(\"data-locale\") || \"\";\n var sl = resolveStyleLocale(preset, styleAttr, localeAttr);\n var style = sl.style;\n var locale = sl.locale;\n\n var list = (root.getAttribute(\"data-list\") || \"br\").trim();\n var linkFlag = (root.getAttribute(\"data-link\") || \"true\").toLowerCase() === \"true\";\n var heading = (root.getAttribute(\"data-heading\") || \"true\").toLowerCase() === \"true\";\n var design = (root.getAttribute(\"data-design\") || \"classic\").trim();\n var spacing = (root.getAttribute(\"data-spacing\") || \"comfortable\").trim();\n var vspace = (root.getAttribute(\"data-vancspace\") || \"false\").toLowerCase() === \"true\";\n\n var ttlDays = parseInt(root.getAttribute(\"data-ttl\") || \"30\", 10);\n if (isNaN(ttlDays) || ttlDays <= 0) ttlDays = 0;\n var ttlSec = ttlDays * 24 * 3600;\n\n root.setAttribute(\"data-design\", design);\n root.setAttribute(\"data-spacing\", spacing);\n\n // Heading\n var h = root.querySelector(\".citation-heading\");\n if (h) {\n if (heading) {\n h.textContent = locale.toLowerCase().startsWith(\"de\") ? \"Literatur\" : \"References\";\n h.style.display = \"\";\n var hId = \"cit-h-\" + Math.random().toString(36).slice(2, 9);\n h.id = hId;\n root.setAttribute(\"aria-labelledby\", hId);\n } else {\n h.style.display = \"none\";\n root.removeAttribute(\"aria-labelledby\");\n }\n }\n\n // DOIs\n var dois = extractPmids(rawDois);\n if (!dois.length && single.trim()) dois = extractPmids(single);\n\n var block = root.querySelector(\".citation-block\") || root;\n var load = root.querySelector(\".pmid-citation-loading\");\n\n if (!dois.length) {\n if (load && load.parentNode) load.parentNode.removeChild(load);\n root.setAttribute(\"aria-busy\", \"false\");\n return;\n }\n\n // Fetch citations\n\n // Deduplicate preserving order\n var seen2 = {};\n dois = dois.filter(function (d) {\n if (seen2[d]) return false;\n seen2[d] = true;\n return true;\n }).slice(0, MAX_IDS);\n\n // Cache split\n var cache = ttlSec > 0 ? getCache() : {};\n var now = nowSec();\n var toFetch = [];\n var cached = {};\n\n dois.forEach(function (doi) {\n var key = cacheKey(doi, style, locale, linkFlag);\n var hit = cache[key];\n if (ttlSec > 0 && hit && hit.t && (now - hit.t) < ttlSec && hit.v) {\n cached[doi] = hit.v;\n } else {\n toFetch.push(doi);\n }\n });\n\n // Fully cached: instant render, no placeholders needed\n if (toFetch.length === 0) {\n var tag0 = list === \"ul\" ? \"ul\" : \"ol\";\n var html0;\n if (list === \"br\") {\n block.setAttribute(\"role\", \"list\");\n html0 = dois.map(function (d) {\n return '
    ' + cached[d] + \"
    \";\n }).join(\"\");\n } else {\n block.removeAttribute(\"role\");\n html0 = \"<\" + tag0 + \">\" +\n dois.map(function (d) {\n return '
  • ' + cached[d] + \"
  • \";\n }).join(\"\") +\n \"\";\n }\n block.innerHTML = html0;\n if (load && load.parentNode) load.parentNode.removeChild(load);\n root.setAttribute(\"aria-busy\", \"false\");\n return;\n }\n\n // Mixed/uncached: show placeholders immediately (each shows pmidLink)\n var placeholders = initPlaceholders(block, dois, list);\n\n // Fill cached items right away\n dois.forEach(function (doi) {\n if (cached[doi]) updatePlaceholder(block, placeholders[doi], cached[doi]);\n });\n\n // Progress counter – hide loading div, placeholders already show links\n if (load && load.parentNode) load.parentNode.removeChild(load);\n var done = dois.length - toFetch.length;\n var total = dois.length;\n\n // Fetch with progressive per-item updates\n var idx = 0;\n var active = 0;\n var dirty = false; // cache has new entries to write\n\n function next() {\n if (idx >= toFetch.length && active === 0) {\n if (dirty && ttlSec > 0) setCache(cache, ttlSec * 2);\n if (load && load.parentNode) load.parentNode.removeChild(load);\n root.setAttribute(\"aria-busy\", \"false\");\n return;\n }\n while (active < CONCURRENCY && idx < toFetch.length) {\n (function (doi) {\n active++;\n idx++;\n fetchCitation(doi, style, locale, vspace)\n .then(function (raw) {\n var item = buildItem(doi, raw, linkFlag);\n updatePlaceholder(block, placeholders[doi], item);\n done++;\n if (load) updateCounter(load, done, total);\n if (ttlSec > 0 && raw) {\n cache[cacheKey(doi, style, locale, linkFlag)] = { t: nowSec(), v: item };\n dirty = true;\n }\n })\n .catch(function () {\n // Placeholder already shows DOI link as fallback – nothing more needed\n done++;\n if (load) updateCounter(load, done, total);\n })\n .then(function () {\n active--;\n setTimeout(next, REQUEST_GAP_MS);\n });\n })(toFetch[idx]);\n }\n }\n next();\n\n\n }\n\n // =========================================================\n // INIT\n // =========================================================\n\n function init() {\n var nodes = document.querySelectorAll(\".generico-pubmed-cite-list\");\n for (var i = 0; i < nodes.length; i++) {\n processBlock(nodes[i]);\n }\n\n }\n\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", init);\n } else {\n init();\n }\n\n})();","style":"/* ============================================================\n Generico PubMed Citation List – Moodle-integrated styles\n Compatible: Boost, Classic, Snap, Fordson, all Moodle themes\n Supports: LTR + RTL, light + dark mode, print/PDF export\n ============================================================ */\n\n/* ----------------------------------------------------------\n CSS custom properties\n Falls back through Moodle Boost vars → hardcoded defaults\n ---------------------------------------------------------- */\n.generico-pubmed-cite-list {\n --doi-accent: var(--primary, var(--core-color-primary, #0f6cbf));\n --doi-accent-faint: var(--primary-low-light, rgba(15, 108, 191, 0.07));\n --doi-border: rgba(0, 0, 0, 0.12);\n --doi-border-mid: rgba(0, 0, 0, 0.22);\n --doi-muted: var(--secondary, #6a737b);\n --doi-link: var(--link-color, var(--primary, #0f6cbf));\n --doi-indent: 1.25em;\n}\n\n/* Dark-mode overrides\n Moodle dark themes either set prefers-color-scheme:dark or a\n .dark/.theme-dark body class – both are covered here. */\n@media (prefers-color-scheme: dark) {\n .generico-pubmed-cite-list {\n --doi-border: rgba(255, 255, 255, 0.15);\n --doi-border-mid: rgba(255, 255, 255, 0.28);\n --doi-accent-faint: rgba(15, 108, 191, 0.14);\n --doi-muted: rgba(255, 255, 255, 0.55);\n }\n}\n/* Moodle themes that add a class instead of using media query */\n.dark .generico-pubmed-cite-list,\n.theme-dark .generico-pubmed-cite-list {\n --doi-border: rgba(255, 255, 255, 0.15);\n --doi-border-mid: rgba(255, 255, 255, 0.28);\n --doi-accent-faint: rgba(15, 108, 191, 0.14);\n --doi-muted: rgba(255, 255, 255, 0.55);\n}\n\n/* ----------------------------------------------------------\n Typography inheritance\n font + line-height: inherit on component and direct children.\n color: NOT forced on * – preserves Moodle link colours.\n ---------------------------------------------------------- */\n.generico-pubmed-cite-list,\n.generico-pubmed-cite-list .citation-heading,\n.generico-pubmed-cite-list .citation-block,\n.generico-pubmed-cite-list .citation-item {\n font: inherit;\n line-height: inherit;\n color: inherit;\n}\n\n/* ----------------------------------------------------------\n Base block\n ---------------------------------------------------------- */\n.generico-pubmed-cite-list {\n display: block;\n max-width: 100%;\n white-space: normal;\n word-break: break-word;\n overflow-wrap: anywhere;\n padding: 0;\n margin: 0.75em 0;\n border: none;\n background: none;\n}\n\n/* ----------------------------------------------------------\n Heading (\"Literatur\" / \"References\")\n ---------------------------------------------------------- */\n.generico-pubmed-cite-list .citation-heading {\n margin: 0 0 0.35em 0;\n font-weight: 600;\n font-size: 1em;\n}\n\n/* ----------------------------------------------------------\n Citation block wrapper\n Uses logical properties → RTL-safe automatically\n ---------------------------------------------------------- */\n.generico-pubmed-cite-list .citation-block {\n border-inline-start: 2px solid var(--doi-border);\n padding-inline-start: 0.8em;\n margin-block: 0.4em 0;\n}\n\n/* ----------------------------------------------------------\n Individual citation items\n Hanging indent only on div (br-mode).\n li items in ol/ul use the list marker for spacing.\n ---------------------------------------------------------- */\n.generico-pubmed-cite-list div.citation-item {\n text-indent: calc(-1 * var(--doi-indent));\n padding-inline-start: var(--doi-indent);\n margin-block: 0.9em;\n}\n\n.generico-pubmed-cite-list li.citation-item {\n text-indent: 0;\n padding-left: 0;\n margin-block: 0.5em;\n}\n\n/* ----------------------------------------------------------\n ol / ul list wrapper\n ---------------------------------------------------------- */\n.generico-pubmed-cite-list ol,\n.generico-pubmed-cite-list ul {\n margin: 0.2em 0 0 1.4em;\n padding: 0;\n}\n\n/* ----------------------------------------------------------\n Loading state\n ---------------------------------------------------------- */\n.generico-pubmed-cite-list .pmid-citation-loading {\n color: var(--doi-muted);\n font-style: italic;\n font-size: 0.9em;\n padding-inline-start: 0.2em;\n}\n\n/* Partially-loaded items: slightly dimmed */\n.generico-pubmed-cite-list .citation-item--loading {\n opacity: 0.65;\n}\n\n/* Shimmer placeholder bar shown while a citation is fetching */\n.generico-pubmed-cite-list .pmid-citation-placeholder {\n display: inline-block;\n width: 55%;\n height: 0.85em;\n vertical-align: middle;\n margin-inline-end: 0.5em;\n border-radius: 0.2em;\n background: linear-gradient(\n 90deg,\n var(--doi-border) 25%,\n var(--doi-border-mid) 50%,\n var(--doi-border) 75%\n );\n background-size: 200% 100%;\n animation: pmid-shimmer 1.5s ease-in-out infinite;\n}\n@keyframes pmid-shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* Hide shimmer once item has resolved (--loading class removed) */\n.generico-pubmed-cite-list .citation-item:not(.citation-item--loading) .pmid-citation-placeholder {\n display: none;\n}\n\n/* ----------------------------------------------------------\n DOI link\n ---------------------------------------------------------- */\n.generico-pubmed-cite-list .pmid-citation-link {\n display: inline;\n margin-inline-start: 0.35em;\n font-size: 0.88em;\n color: var(--doi-link);\n text-decoration: none;\n word-break: break-all;\n overflow-wrap: anywhere;\n}\n.generico-pubmed-cite-list .pmid-citation-link:hover {\n text-decoration: underline;\n}\n/* Keyboard focus ring – works across all Moodle themes */\n.generico-pubmed-cite-list .pmid-citation-link:focus-visible {\n outline: 2px solid var(--doi-accent);\n outline-offset: 2px;\n border-radius: 2px;\n text-decoration: none;\n}\n\n/* ----------------------------------------------------------\n Spacing presets (data-spacing attribute)\n ---------------------------------------------------------- */\n.generico-pubmed-cite-list[data-spacing=\"compact\"] div.citation-item { margin-block: 0.2em; }\n.generico-pubmed-cite-list[data-spacing=\"compact\"] li.citation-item { margin-block: 0.15em; }\n.generico-pubmed-cite-list[data-spacing=\"comfortable\"] div.citation-item { margin-block: 0.9em; }\n.generico-pubmed-cite-list[data-spacing=\"comfortable\"] li.citation-item { margin-block: 0.5em; }\n.generico-pubmed-cite-list[data-spacing=\"loose\"] div.citation-item { margin-block: 1.5em; }\n.generico-pubmed-cite-list[data-spacing=\"loose\"] li.citation-item { margin-block: 0.9em; }\n\n/* ----------------------------------------------------------\n Design presets (data-design attribute)\n ---------------------------------------------------------- */\n\n/* classic: subtle neutral border, no background */\n.generico-pubmed-cite-list[data-design=\"classic\"] .citation-block {\n border-inline-start-color: var(--doi-border);\n}\n\n/* academic: stronger border, slightly wider hanging indent */\n.generico-pubmed-cite-list[data-design=\"academic\"] .citation-block {\n border-inline-start-color: var(--doi-border-mid);\n border-inline-start-width: 2px;\n}\n.generico-pubmed-cite-list[data-design=\"academic\"] div.citation-item {\n --doi-indent: 1.5em;\n}\n\n/* modern: coloured accent border + tinted background panel */\n.generico-pubmed-cite-list[data-design=\"modern\"] .citation-block {\n border-inline-start-color: var(--doi-accent);\n border-inline-start-width: 3px;\n background: var(--doi-accent-faint);\n border-radius: 0 0.3rem 0.3rem 0;\n padding-inline-start: 1em;\n}\n\n/* ----------------------------------------------------------\n Print / PDF export\n Removes decorative backgrounds and animations.\n Keeps structure readable on paper.\n ---------------------------------------------------------- */\n@media print {\n .generico-pubmed-cite-list .citation-block {\n border-inline-start: 1px solid #888;\n background: none !important;\n border-radius: 0;\n }\n .generico-pubmed-cite-list .pmid-citation-loading,\n .generico-pubmed-cite-list .pmid-citation-placeholder {\n display: none !important;\n }\n .generico-pubmed-cite-list .citation-item--loading {\n opacity: 1;\n }\n .generico-pubmed-cite-list .pmid-citation-link {\n color: #000;\n text-decoration: none;\n font-size: 0.82em;\n }\n /* Suppress URL-after-link that some print stylesheets add */\n .generico-pubmed-cite-list .pmid-citation-link::after {\n content: none !important;\n }\n @keyframes pmid-shimmer {\n 0%, 100% { background-position: 0 0; }\n }\n}","dataset":"","datasetvars":"","alternate":"","alternateend":"","version":"1.0.0."}