diff --git a/.gitignore b/.gitignore
index 406c7f3af33e3247873f2458a5c1ff7cbbc16f9c..0d273426683ad888797b2024a6b8624292a8ba81 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
 node_modules
-dist
+/dist
 *.build-in-progress
 .parcel-cache
 yarn-error.log
@@ -11,7 +11,7 @@ __pycache__
 *.d.mk
 /templates
 /*.apkg
-hanzi-data
+/hanzi-data
 .data-test-ok
 .html-test-ok
 .lint-ok
diff --git a/.proxyrc.js b/.proxyrc.js
index 0a15292e7532ffb693160d8293f77c9ef29bd528..99c30f0a80dbef107486860f475b04c41f10e3f2 100644
--- a/.proxyrc.js
+++ b/.proxyrc.js
@@ -5,7 +5,6 @@ module.exports = function (app) {
   if (!('BUILD_PREFIX' in process.env)) {
     throw new Error(`Dunno where the chardata at, what BUILD_PREFIX?`)
   }
-  const dir = `${process.env.BUILD_PREFIX}hanzi-data`
-  app.use("/hanzi-data", serveStatic(dir))
-  console.error(('ok configured at '), dir)
+  app.use(`/${process.env.BUILD_PREFIX}`, serveStatic(process.env.BUILD_PREFIX))
+  console.error(`data at /${process.env.BUILD_PREFIX}`)
 }
diff --git a/NOTICE b/KA_TEMPLATES_NOTICE
similarity index 96%
rename from NOTICE
rename to KA_TEMPLATES_NOTICE
index 8858497880070dce8226ca7366cb301232179a54..324be8451fabe49dfc55fdae61ab16c385fea26b 100644
--- a/NOTICE
+++ b/KA_TEMPLATES_NOTICE
@@ -1,5 +1,5 @@
-sinologie-anki-pack
-Copyright (c) 2024–Present Sinologie Anki Pack Contributors
+card-templates by kartenaale
+Copyright (c) 2024–Present Kartenaale
 
 You are free to use, share and modify everything in the repository.
 
diff --git a/Makefile b/Makefile
index aa385f20e7b2831761b5d2796a62223d694c7903..73dd75521bb58270871847555e4b3a3b72a2a56f 100644
--- a/Makefile
+++ b/Makefile
@@ -4,6 +4,7 @@ make/defs.mk \
 make/src-common.mk \
 make/node.mk \
 make/hanzi-data.mk \
+make/jsonp.mk \
 make/html.mk \
 make/eslint.mk \
 make/dist.mk \
diff --git a/build/__init__.py b/build/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/make/dist.mk b/make/dist.mk
index 74d6557b5c5a3c2cf78dc80b4e8d031ee61fc5b3..e232b76ce60ee5b37e52249b3fca8679b2b346f0 100644
--- a/make/dist.mk
+++ b/make/dist.mk
@@ -1,6 +1,6 @@
 RELEASE_TAR := $(BUILD_PREFIX)card-templates-$(shell grep '"version":' package.json -m 1 | cut -d '"' -f 4).tar.gz
-RELEASE_INCLUDE_SRC := LICENSE NOTICE
-RELEASE_INCLUDE_ARTIFACTS := $(HANZI_DATA) $(BUILT_TEMPLATE_HTMLS) $(BUILT_TEMPLATE_SPECS)
+RELEASE_INCLUDE_SRC :=
+RELEASE_INCLUDE_ARTIFACTS := $(HANZI_DATA) $(BUILT_TEMPLATE_HTMLS) $(BUILT_TEMPLATE_SPECS) $(JSONP_OUTPUT)
 RELEASE_CONTENT_SRC := $(addprefix $(RELEASE_DIR)/,$(RELEASE_INCLUDE_SRC))
 RELEASE_CONTENT_ARTIFACTS := $(patsubst $(BUILD_PREFIX)%,$(RELEASE_DIR)/%,$(RELEASE_INCLUDE_ARTIFACTS))
 RELEASE_CONTENT := $(RELEASE_CONTENT_SRC) $(RELEASE_CONTENT_ARTIFACTS)
diff --git a/make/global.mk b/make/global.mk
index 31f7fd800e88d85bc7a55a01421069653a432db3..bd0af77d7e1567f9f87dda027a60c428ad5e6d62 100644
--- a/make/global.mk
+++ b/make/global.mk
@@ -23,4 +23,7 @@ deepclean:
 	rm -f $(MOSTLY_CLEAN) $(CLEAN)
 	rm -rf $(MOSTLY_CLEAN_DIRS) $(CLEAN_DIRS) $(DEEP_CLEAN_DIRS)
 
+.PHONY: install
+install: install-data
+
 .DEFAULT_GOAL := all
diff --git a/make/hanzi-data.mk b/make/hanzi-data.mk
index 2c218463f7ffd1940ed4e8538f3fc11e684fdf1e..42349f6fa83ceb9667f98158636281ca2d069465 100644
--- a/make/hanzi-data.mk
+++ b/make/hanzi-data.mk
@@ -7,12 +7,23 @@ TS_SRC += $(SRC_DATA_TESTS_TS) $(BUILD_TS_SOURCES)
 MOSTLY_CLEAN += $(DATA_TEST_OK_FLAG)
 MOSTLY_CLEAN_DIRS += $(HANZI_DATA)
 
+# hanzi data is installed here
+ANKI_COL_DIR := $(HOME)/.local/share/Anki2/Main
+ANKI_COL_WAL := $(ANKI_COL_DIR)/collection.anki2-wal
+
 .PHONY: data
 data: $(HANZI_DATA)
 
 .PHONY: test-data
 test-data: $(DATA_TEST_OK_FLAG)
 
+# debug only: this will overwrite existing data,
+# alternatively delete js files and reimport anki package
+.PHONY: install-data
+install-data: $(HANZI_DATA)
+	$(if $(wildcard $(ANKI_COL_WAL)), $(error Cannot install while Anki is open))
+	cp -f $(HANZI_DATA)/*.js $(ANKI_COL_DIR)/collection.media/
+
 $(HANZI_DATA): \
 $(GEN_HANZI_DATA) \
 $(wildcard build/gen-hanzi-data/pools/simplified/*.txt) \
diff --git a/make/html.mk b/make/html.mk
index 8978fc002a6ca4ed1871c1317ef132e3d8a61e79..92054d6a1164abcc6f773cca3ca6c19929ec4a42 100644
--- a/make/html.mk
+++ b/make/html.mk
@@ -22,7 +22,7 @@ DEEP_CLEAN_DIRS += .parcel-cache dist
 html: $(BUILT_TEMPLATE_HTMLS) $(BUILT_TEMPLATE_SPECS)
 
 .PHONY: dev
-dev: $(PARCEL) $(HANZI_DATA)
+dev: $(PARCEL) $(HANZI_DATA) $(JSONP_OUTPUT)
 	$(PARCEL) serve $(PARCEL_DEV_ENTRY_HTMLS) --config=./$(PARCEL_DEV_CONFIG)
 
 .PHONY: test-html
@@ -35,7 +35,7 @@ $(HTML_TEST_OK_FLAG): $(JEST) $(HANZI_DATA) $(SRC_TEMPLATE_TESTS) $(SRC_TEMPLATE
 
 # no parcel plugin or config required for production builds, Anki handles the
 # tags
-$(BUILT_TEMPLATE_HTMLS) &: $(HANZI_DATA) $(PARCEL) $(TEMPLATE_FILES) $(SRC_COMMON_TS)
+$(BUILT_TEMPLATE_HTMLS) &: $(HANZI_DATA) $(JSONP_OUTPUT) $(PARCEL) $(TEMPLATE_FILES) $(SRC_COMMON_TS)
 	@$(and $(BUILD_PREFIX),mkdir -p $(BUILD_PREFIX))
 	$(PARCEL) build --no-source-maps --dist-dir=$(BUILD_PREFIX)templates $(SRC_TEMPLATE_HTMLS)
 # set moddat even for files that did not need to be updated (to avoid redundant rebuilds)
diff --git a/make/jsonp.mk b/make/jsonp.mk
new file mode 100644
index 0000000000000000000000000000000000000000..9e8f4a84b7dcadd99368508e7a2eb01e2e8e6bf4
--- /dev/null
+++ b/make/jsonp.mk
@@ -0,0 +1,10 @@
+JSONP_INPUT := KA_TEMPLATES_NOTICE
+JSONP_OUTPUT := $(foreach I,$(JSONP_INPUT),$(BUILD_PREFIX)$(I).js)
+
+MOSTLY_CLEAN += $(JSONP_OUTPUT)
+
+.PHONY: jsonp
+jsonp: $(JSONP_OUTPUT)
+
+$(JSONP_OUTPUT): $(BUILD_PREFIX)%.js: % $(JSONP)
+	$(JSONP) --fn hd $< -f $@
diff --git a/make/node.mk b/make/node.mk
index a842561bd36b4dddb82aee3c0e500689dc16faff..02a53cb4ec90a7a475499fd700eac93468d9f548 100644
--- a/make/node.mk
+++ b/make/node.mk
@@ -2,7 +2,8 @@ PARCEL := node_modules/.bin/parcel
 ESLINT := node_modules/.bin/eslint
 JEST := node_modules/.bin/jest
 TSC := node_modules/.bin/tsc
-NODE_BINS := $(PARCEL) $(ESLINT) $(JEST) $(TSC)
+JSONP := node_modules/.bin/to-static-jsonp
+NODE_BINS := $(PARCEL) $(ESLINT) $(JEST) $(TSC) $(JSONP)
 
 GEN_HANZI_DATA := $(BUILD_PREFIX)build/gen-hanzi-data/run
 BUILD_TS_SOURCES := $(shell find build -name '*.ts')
diff --git a/package.json b/package.json
index d3b308ec9e62ec30d95c28d4521789171b5e20f5..d16de447c089f202f98426a365337269c7abad28 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "kartenaale-card-templates",
-  "version": "1.0.2",
+  "version": "2.0.0",
   "description": "HTML and data for Anki cards",
   "repository": "https://gitlab.phaidra.org/kartenaale/card-templates",
   "author": "Philipp Stadler <hello@phstadler.com>",
@@ -24,6 +24,7 @@
     "parcel-transformer-anki-tags": "0.0.1",
     "posthtml-include": "^2.0.1",
     "serve-static": "^1.15.0",
+    "to-static-jsonp": "^1.0.1",
     "ts-jest": "^29.2.3",
     "typescript": "*",
     "typescript-eslint": "^7.16.1"
diff --git a/src/components/data.ts b/src/components/data.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5b2dca1503ee4757b62944d2df4f3d2133540f59
--- /dev/null
+++ b/src/components/data.ts
@@ -0,0 +1,141 @@
+import { readFile } from 'fs/promises'
+
+export interface GetDataOpts {
+  /**
+   * The JS file to load for the data, e.g. `hanzi-data/_hdA.js'.
+   *
+   * Directories are handled in testing, but only the basename is considered in
+   * Anki, which does not support directories.
+   */
+  path: string
+  /**
+   * First argument to the JSONP callback before the actual data.
+   */
+  key: string
+}
+
+const jsonpCallbackFnName = 'hd'
+/** keys against functions to call on resolve. */
+const jsonpWaiters = new Map<string, Array<(unknown) => void>>()
+const cached: Record<string, Readonly<unknown>> = {}
+const canAccessFilesystem = typeof document === 'undefined'
+
+/**
+ * Fetches JSONP data with the specified key.
+ *
+ * For a key of A, will fetch `_hdA.js`, assuming it contains a function call
+ * to `hd`, with the key as the first param and the data (unknown type) as the
+ * second.
+ *
+ * Unsafe because it is up to the caller to cast to a concrete correct type.
+ */
+export async function getDataUnsafe (
+  opts: GetDataOpts
+): Promise<Readonly<unknown>> {
+  const { key } = opts
+  let data: Readonly<unknown>
+  if (key in cached) {
+    data = cached[key]
+  } else if (canAccessFilesystem) {
+    // read directly from disk when running in test and skip the cache
+    data = await fetchNonBrowser(opts)
+  } else {
+    // in production and parcel use a JSONP-like API because everything else
+    // failed in AnkiDroid
+    data = await fetchJsonp(opts)
+    // caching helps a lot with load speed since the same character often
+    // occurs multiple times on the same card
+    cached[key] = data
+  }
+  return data
+}
+
+/**
+ * Fetches the JSONP via direct filesystem access (for tests).
+ */
+async function fetchNonBrowser (opts: GetDataOpts): Promise<Readonly<unknown>> {
+  if (!('BUILD_PREFIX' in process.env)) {
+    throw new Error('Dunno where the data at, what BUILD_PREFIX?')
+  }
+  const path = `${process.env.BUILD_PREFIX}${opts.path}`
+  const jsonp = await readFile(path, { encoding: 'utf-8' })
+  const data = JSON.parse(jsonp.substring(
+    `${jsonpCallbackFnName}(${JSON.stringify(opts.key)},`.length,
+    jsonp.length - ')'.length
+  ))
+  // just for testing: we want to catch accidental modifications of data that
+  //                   would be shared if this were production
+  Object.freeze(data)
+  return data
+}
+
+/**
+ * Callback for the JSONP scripts with the data.
+ *
+ * Raw JSON would not work with AnkiDroid, which does not support XHR/fetch,
+ * but allows scripts.
+ *
+ * In AnkiDroid, every card gets a fresh window, but desktop and Anki Web
+ * preserved the callback from the last call. If window already contains a
+ * callback, it works to just overwrite the old callback here that is no longer
+ * needed. See #298 for details.
+ */
+if (!canAccessFilesystem) {
+  window[jsonpCallbackFnName] = (char: string, data: Readonly<unknown>) => {
+    (jsonpWaiters.get(char) ?? []).forEach(w => {
+      // careful: every consumer gets an identical object, don't modify
+      w(data)
+    })
+    jsonpWaiters.delete(char)
+  }
+}
+
+/**
+ * Registers a waiter for the specified key.
+ *
+ * It will be removed automatically after the data has been received.
+ */
+function registerJsonpWaiter (
+  char: string,
+  callback: (data: Readonly<unknown>) => void
+): void {
+  jsonpWaiters.set(
+    char,
+    [...(jsonpWaiters.get(char) ?? []), callback]
+  )
+}
+
+/**
+ * Fetches data over the network for the specified key.
+ */
+async function fetchJsonp (opts: GetDataOpts): Promise<Readonly<unknown>> {
+  return await new Promise((resolve, reject) => {
+    const url = process.env.NODE_ENV === 'production'
+      // No directories for Anki media possible, for prod use just filename
+      ? opts.path.split('/').pop()!
+      // For testing in parcel it works better to have a subpath that we can
+      // exclude from parcel.
+      : `/${process.env.BUILD_PREFIX}${opts.path}`
+    if (document.querySelector(`script[src="${url}"]`) !== null) {
+      // already being fetched, append to the list of existing waiters
+      registerJsonpWaiter(opts.key, resolve)
+    } else {
+      // no fetch in flight, inject a new script tag
+      const script = document.createElement('script')
+      registerJsonpWaiter(
+        opts.key,
+        data => {
+          script.remove()
+          resolve(data)
+        }
+      )
+      script.async = true
+      script.src = url
+      script.onerror = () => {
+        script.remove()
+        reject(new Error(`No character data available for ${opts.key}`))
+      }
+      document.body.appendChild(script)
+    }
+  })
+}
diff --git a/src/components/global.css b/src/components/global.css
index d132e03427a64c71596fdfef1681d441ba881847..36b148013e32751aad08916299e2a594b504d26c 100644
--- a/src/components/global.css
+++ b/src/components/global.css
@@ -1,7 +1,6 @@
 @import url(./theme.css);
 @import url(./debug/debug.css);
 @import url(./fira.css);
-@import url(./notice/notice.css);
 @import url(./tts/tts.css);
 @import url(./write/write.css);
 @import url(./answer-details.css);
diff --git a/src/components/hanzi-data/index.ts b/src/components/hanzi-data/index.ts
index a1f1b8ce10d61ef8e194ade01f56b94b42c179d3..eeaee842a134cdfce4fff2dd2504bb7dab750ed0 100644
--- a/src/components/hanzi-data/index.ts
+++ b/src/components/hanzi-data/index.ts
@@ -1,6 +1,6 @@
 import type { HanziData } from '../../../src-common/hanzi-data'
+import { getDataUnsafe } from '../data'
 import { lookup } from './lut'
-import { readFile } from 'fs/promises'
 
 export interface GetHanziDataOpts {
   char: string
@@ -23,13 +23,6 @@ export async function getHanziProp (
   return data[prop] ?? lookup(data, prop)
 }
 
-const dataFilePrefix = '_hd'
-const jsonpCallbackFnName = 'hd'
-/** chars against functions to call on resolve. */
-const jsonpWaiters = new Map<string, Array<(HanziData) => void>>()
-const cached: Record<string, Readonly<HanziData>> = {}
-const canAccessFilesystem = typeof document === 'undefined'
-
 export async function getHanziData (
   { char, kind }: GetHanziDataOpts
 ): Promise<Readonly<HanziData>> {
@@ -37,20 +30,7 @@ export async function getHanziData (
     throw new Error(`Can only get data for single chars, got: ${char}`)
   }
 
-  let data: Readonly<HanziData>
-  if (char in cached) {
-    data = cached[char]
-  } else if (canAccessFilesystem) {
-    // read directly from disk when running in test and skip the cache
-    data = await fetchNonBrowser(char)
-  } else {
-    // in production and parcel use a JSONP-like API because everything else
-    // failed in AnkiDroid
-    data = await fetchJsonp(char)
-    // caching helps a lot with load speed since the same character often
-    // occurs multiple times on the same card
-    cached[char] = data
-  }
+  const data = (await getDataUnsafe({ path: `hanzi-data/_hd${char}.js`, key: char })) as Readonly<HanziData>
   if (kind === GetHanziDataKind.TRADITIONAL && data.trad !== undefined) {
     // data in the cache is read-only => make a fresh copy with trad overrides
     return {
@@ -60,92 +40,3 @@ export async function getHanziData (
   }
   return data
 }
-
-async function fetchNonBrowser (char: string): Promise<HanziData> {
-  if (!('BUILD_PREFIX' in process.env)) {
-    throw new Error('Dunno where the chardata at, what BUILD_PREFIX?')
-  }
-  const dir = `${process.env.BUILD_PREFIX}hanzi-data`
-  const path = `${dir}/${dataFilePrefix}${char}.js`
-  const jsonp = await readFile(path, { encoding: 'utf-8' })
-  const data = JSON.parse(jsonp.substring(
-    'hd("A",'.length,
-    jsonp.length - ')'.length
-  ))
-  // just for testing: we want to catch accidental modifications of data that
-  //                   would be shared if this were production
-  Object.freeze(data)
-  return data
-}
-
-/**
- * Callback for the JSONP scripts with the data.
- *
- * Raw JSON would not work with AnkiDroid, which does not support XHR/fetch,
- * but allows scripts.
- *
- * In AnkiDroid, every card gets a fresh window, but desktop and Anki Web
- * preserved the callback from the last call. If window already contains a
- * callback, it works to just overwrite the old callback here that is no longer
- * needed. See #298 for details.
- */
-if (!canAccessFilesystem) {
-  window[jsonpCallbackFnName] = (char: string, data: HanziData) => {
-    (jsonpWaiters.get(char) ?? []).forEach(w => {
-      // careful: every consumer gets an identical object, don't modify
-      w(data)
-    })
-    jsonpWaiters.delete(char)
-  }
-}
-
-/**
- * Registers a waiter for the specified char.
- *
- * It will be removed automatically after the data has been received.
- */
-function registerJsonpWaiter (
-  char: string,
-  callback: (data: HanziData) => void
-): void {
-  jsonpWaiters.set(
-    char,
-    [...(jsonpWaiters.get(char) ?? []), callback]
-  )
-}
-
-/**
- * Fetches the character data (strokes, SVG, etc.) for the specified character.
- */
-async function fetchJsonp (char: string): Promise<Readonly<HanziData>> {
-  return await new Promise((resolve, reject) => {
-    const prefix = process.env.NODE_ENV === 'production'
-      // No directories for Anki media possible, for prod use just filename
-      ? ''
-      // For testing in parcel it works better to have a subpath that we can
-      // exclude from parcel.
-      : '/hanzi-data/'
-    const url = `${prefix}${dataFilePrefix}${char}.js`
-    if (document.querySelector(`script[src="${url}"]`) !== null) {
-      // already being fetched, append to the list of existing waiters
-      registerJsonpWaiter(char, resolve)
-    } else {
-      // no fetch in flight, inject a new script tag
-      const script = document.createElement('script')
-      registerJsonpWaiter(
-        char,
-        data => {
-          script.remove()
-          resolve(data)
-        }
-      )
-      script.async = true
-      script.src = url
-      script.onerror = () => {
-        script.remove()
-        reject(new Error(`No character data available for ${char}`))
-      }
-      document.body.appendChild(script)
-    }
-  })
-}
diff --git a/src/components/init.ts b/src/components/init.ts
index 99d463f9a7fe4806a5b310222662fc626e12c99d..70d73738200dfc5626fc9f910d93750c4d791128 100644
--- a/src/components/init.ts
+++ b/src/components/init.ts
@@ -1,4 +1,5 @@
 import { init as initHanziData } from './hanzi-data/init'
+import { initNotice } from './notice'
 import { init as initTts } from './tts/init'
 import { init as initWrite } from './write/init'
 
@@ -9,4 +10,5 @@ export async function init (within: HTMLElement | null): Promise<void> {
   await initHanziData(within)
   initTts(within)
   await initWrite(within)
+  await initNotice(within)
 }
diff --git a/src/components/load-text.ts b/src/components/load-text.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2dfbb32ab149922f7e1d814605921c61f304f209
--- /dev/null
+++ b/src/components/load-text.ts
@@ -0,0 +1,15 @@
+import { getDataUnsafe } from "./data";
+
+export async function loadText(filename: string): Promise<string> {
+  const data = await getDataUnsafe({ path: filename + '.js', key: filename })
+  if (typeof data !== 'string') {
+    throw new Error(`${filename} loaded, but is not text`)
+  }
+  return toHtml(data)
+}
+
+function toHtml(raw: string): string {
+  return raw.split(/[\n-]{2,}/).map(p => `<p>${
+    p.replace(/([a-z]+:\/\/[/a-zA-Z-.]+[/a-zA-Z])/g, '<a href="$1">$1</a>')
+  }</p>`).join('')
+}
diff --git a/src/components/notice.ts b/src/components/notice.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1fca444916d2c6bd35a59f27be0cb55518ce5047
--- /dev/null
+++ b/src/components/notice.ts
@@ -0,0 +1,12 @@
+import { loadText } from "./load-text"
+
+export async function initNotice(within: HTMLElement) {
+  within.querySelectorAll('[notice-file]').forEach(
+    async el => {
+      const noticeFile = el.getAttribute('notice-file') ?? ''
+      if (noticeFile !== '') {
+        el.innerHTML = await loadText(noticeFile)
+      }
+    }
+  )
+}
diff --git a/src/components/notice/notice.css b/src/components/notice/notice.css
deleted file mode 100644
index 4c8e028e579098a384dddbfc75d2c7bf8982a906..0000000000000000000000000000000000000000
--- a/src/components/notice/notice.css
+++ /dev/null
@@ -1,7 +0,0 @@
-.notice-contents {
-  text-align: justify;
-}
-
-.notice-contents ul {
-  list-style-type: none;
-}
diff --git a/src/components/notice/notice.html b/src/components/notice/notice.html
deleted file mode 100644
index 2067e20b2e55c1fdfe1129b63d9e4c9bd5e7853b..0000000000000000000000000000000000000000
--- a/src/components/notice/notice.html
+++ /dev/null
@@ -1,115 +0,0 @@
-<details class="answer-details">
-  <summary>
-    <span class="answer-details-more">About this deck…</span>
-    <span class="answer-details-less">Hide notice…</span>
-  </summary>
-  <aside class="notice-contents">
-    <p>
-      The code that makes this deck work is open source software available on
-      <a href="https://gitlab.phaidra.org/kartenaale/sinologie-anki-pack">University of Vienna GitLab</a>.
-      <br>Check out releases for more decks and updates, or file an issue if
-      you are experiencing issues or if you want to contribute.
-    </p>
-    <p>
-      Deck: Chinese Cultural Spaces<br>
-
-      Special thanks go out to Chris for making this deck!<br>
-
-      Please respect the rights of the lecturer that provided the content, as well as
-      of the photographers that made the images. Share the deck only with your fellow
-      students.
-    </p>
-    <p>
-      Decks: Chinesisch lernen für die Sinologie, Band 1&2<br>
-
-      Stefanie Yu kindly gave permission to make an Anki version of her vocabulary on
-      Quizlet that can be freely shared among students of the University of Vienna.
-      It is available with releases of this project on GitLab, and you are welcome to
-      improve on it and share your improvements with other students.<br>
-
-      The vocabulary and some additional content like stroke names are taken from the
-      book "Chinesisch lernen für die Sinologie, Band 1" by Xia Baige and Wolfgang
-      Zeidl. Xia Baige kindly gave permission to use their work in this Anki deck.
-      The book itself is available at Universität Wien.<br>
-
-      Please respect the rights of the original authors and share content from
-      Sinologie Anki Pack only with your fellow students.
-    </p>
-    <p>
-      Deck: Introduction to Chinese Cultural History<br>
-
-      This deck includes content from the slides of the lecture _Introduction to
-      Chinese Cultural History_ at Universität Wien, held by Dr. Rossella Ferrari.<br>
-
-      A separate part of the deck heavily relies on content from _The Columbia
-      Companion to Modern Chinese Literature_.<br>
-
-      Please respect the rights of the original authors and share this deck only with
-      your fellow students.
-    </p>
-    <p>
-      Deck: Einführung in die politische Geschichte Chinas<br>
-
-      This deck includes content from the slides of the lecture _Einführung in die
-      politische Geschichte Chinas_ at Universität Wien, held by Dr. Christian Göbel.<br>
-
-      Please respect the rights of the original authors and share this deck only with
-      your fellow students.
-    </p>
-    <p>
-      Deck: Wirtschaftliche Entwicklung Chinas<br>
-
-      This deck includes content from the slides of the lecture
-      _Wirtschaftliche Entwicklung Chinas_ at Universität Wien, held by Dr.
-      Christian Göbel.<br>
-
-      Please respect the rights of the original authors and share this deck only with
-      your fellow students.
-    </p>
-    <p>
-      German and Chinese radical names are taken from the German version of
-      Wikipedia. A hearty thank you to all authors and maintainers.
-    </p>
-    <p>
-      This product includes software from the hanzi-writer project (MIT).
-      <br>Copyright (c) 2014 David Chanin.
-      <br><a href="https://github.com/chanind/hanzi-writer">https://github.com/chanind/hanzi-writer</a>
-    </p>
-    <p>
-      COPYING notice from the hanzi-writer project:
-
-      Hanzi Writer uses data from the excellent Make Me a Hanzi project and fonts from Arphic. You can redistribute
-      and/or
-      modify the font data under the terms of the Arphic Public License as published by Arphic Technology Co., Ltd. You
-      should
-      have received a copy of this license (the directory "APL") in the data folder of this repository; if not, see
-      http://ftp.gnu.org/non-gnu/chinese-fonts-truetype/LICENSE.
-
-      Arphic PL KaitiM GB and UKai Copyright 1999 Arphic Technology Co., Ltd.; licensed under the Arphic Public License
-      http://www.arphic.com.tw/en/home/index
-
-      Make Me a Hanzi Copyright 1999 Arphic Technology Co., Ltd., copyright 2016 Shaunak Kishore; licensed under the
-      Arphic
-      Public License https://github.com/skishore/makemeahanzi
-
-    </p>
-    <p>
-      This product includes software from the cnchar project (MIT).
-      <br>Copyright (c) 2017 - present theajack &lt;theajack@qq.com&gt;
-      <br><a href="https://github.com/theajack/cnchar">https://github.com/theajack/cnchar</a>
-    </p>
-    <p>
-      This product includes software from the hanzi-tool project (MIT).
-      <br>Copyright (c) 2012-2014 Jeremiah Daneil de la Rouviere
-      <br><a href="https://github.com/ginsudev/hanzi">https://github.com/ginsudev/hanzi</a>
-    </p>
-    <p>
-      This project also would not have been possible without these projects and
-      the teams behind them:
-    </p>
-    <ul>
-      <li>Anki (<a href="https://apps.ankiweb.net/">https://apps.ankiweb.net/</a>)</li>
-      <li>parcel (<a href="https://parceljs.org/">https://parceljs.org/</a>)</li>
-    </ul>
-  </aside>
-</details>
\ No newline at end of file
diff --git a/src/templates/bijective/.template-spec.yaml b/src/templates/bijective/.template-spec.yaml
index ed45670a2d8a25a4528788b12ec8e6095e18541a..0074aaa735dc1301e5b5b4288a5815cf301f802a 100644
--- a/src/templates/bijective/.template-spec.yaml
+++ b/src/templates/bijective/.template-spec.yaml
@@ -1,4 +1,4 @@
-template_version: 2024-02-28 22:00:00+00:00
+template_version: 2024-07-20 10:00:00+00:00
 
 note_type:
   id: 2024-01-05 03:00:00+00:00
@@ -6,6 +6,7 @@ note_type:
   fields:
   - A
   - B
+  - Credits
 
 card_types:
 - name: Forward
@@ -13,4 +14,5 @@ card_types:
 - name: Backward
   template: backward
 
-resource_paths: []
+resource_paths:
+- '{{BUILD_PREFIX}}KA_TEMPLATES_NOTICE.js'
diff --git a/src/templates/bijective/backward/back.html b/src/templates/bijective/backward/back.html
index 84534fbef4bf17dc733bf2504a2833cf24a1529d..0a666c0ab64c60d4fa57dcd28fd9de644ddb151d 100644
--- a/src/templates/bijective/backward/back.html
+++ b/src/templates/bijective/backward/back.html
@@ -9,7 +9,15 @@
     {{A}}
   </div>
 
-  <include src="src/components/notice/notice.html"></include>
+  <details class="answer-details">
+    <summary>
+      <span class="answer-details-more">Über das Pack…</span>
+      <span class="answer-details-less">Info verbergen…</span>
+    </summary>
+
+    {{Credits}}
+    <div notice-file="KA_TEMPLATES_NOTICE"></div>
+  </details>
 </div>
 
 <!-- Suppress speech output on AnkiDroid if globally enabled -->
diff --git a/src/templates/bijective/forward/back.html b/src/templates/bijective/forward/back.html
index afbae1a920ec242f9d2fed054e70b5a6d895e16a..94470ebf9ed5260c4f74c702b345851cf53b9099 100644
--- a/src/templates/bijective/forward/back.html
+++ b/src/templates/bijective/forward/back.html
@@ -9,7 +9,15 @@
     {{B}}
   </div>
 
-  <include src="src/components/notice/notice.html"></include>
+  <details class="answer-details">
+    <summary>
+      <span class="answer-details-more">Über das Pack…</span>
+      <span class="answer-details-less">Info verbergen…</span>
+    </summary>
+
+    {{Credits}}
+    <div notice-file="KA_TEMPLATES_NOTICE"></div>
+  </details>
 </div>
 
 <!-- Suppress speech output on AnkiDroid if globally enabled -->
diff --git a/src/templates/facts/.template-spec.yaml b/src/templates/facts/.template-spec.yaml
index fe384c1e79bf439cf2299d42295600564245698c..b7796d519b44f2a55493e046fbdf9b868b5aee27 100644
--- a/src/templates/facts/.template-spec.yaml
+++ b/src/templates/facts/.template-spec.yaml
@@ -1,4 +1,4 @@
-template_version: 2024-02-28 22:00:00+00:00
+template_version: 2024-07-20 10:00:00+00:00
 
 note_type:
   id: 2024-01-04 03:00:00+00:00
@@ -6,9 +6,11 @@ note_type:
   fields:
   - Front
   - Back
+  - Credits
 
 card_types:
 - name: Q/A
   template: q_a
 
-resource_paths: []
+resource_paths:
+- '{{BUILD_PREFIX}}KA_TEMPLATES_NOTICE.js'
diff --git a/src/templates/facts/q_a/back.html b/src/templates/facts/q_a/back.html
index 1ac8a0788f6fcbe64b2bd300a560d7e6648180a2..6d92af2b0881f59c639a45dcda3f84e3cf63852c 100644
--- a/src/templates/facts/q_a/back.html
+++ b/src/templates/facts/q_a/back.html
@@ -9,7 +9,15 @@
     {{Back}}
   </div>
 
-  <include src="src/components/notice/notice.html"></include>
+  <details class="answer-details">
+    <summary>
+      <span class="answer-details-more">Über das Pack…</span>
+      <span class="answer-details-less">Info verbergen…</span>
+    </summary>
+
+    {{Credits}}
+    <div notice-file="KA_TEMPLATES_NOTICE"></div>
+  </details>
 </div>
 
 <!-- Suppress speech output on AnkiDroid if globally enabled -->
diff --git a/src/templates/hanzi/.template-spec.yaml b/src/templates/hanzi/.template-spec.yaml
index 0908f3094ee9c9766d2a2330c2fa076da85480a9..ce7c24504118c0f2a31d8c2dea3eb0f4407a2856 100644
--- a/src/templates/hanzi/.template-spec.yaml
+++ b/src/templates/hanzi/.template-spec.yaml
@@ -1,4 +1,4 @@
-template_version: 2024-03-20 10:00:00+00:00
+template_version: 2024-07-20 10:00:00+00:00
 
 note_type:
   id: 2024-02-21 12:00:00+00:00
@@ -17,6 +17,7 @@ note_type:
   - Notes (Back)
   - Traditional
   - Simplified
+  - Credits
 
 card_types:
 - name: Schreiben
@@ -24,3 +25,4 @@ card_types:
 
 resource_paths:
 - '{{BUILD_PREFIX}}hanzi-data'
+- '{{BUILD_PREFIX}}KA_TEMPLATES_NOTICE.js'
diff --git a/src/templates/hanzi/write/back.html b/src/templates/hanzi/write/back.html
index b176010e465ffba032bb66d8f77781403597df87..e9f44e384d35819b4676ad2a1f6fe08a457137e2 100644
--- a/src/templates/hanzi/write/back.html
+++ b/src/templates/hanzi/write/back.html
@@ -14,7 +14,15 @@
     <dd><span class="hanzi-print is-large">{{Hanzi}}</span></dd>
   </dl>
 
-  <include src="src/components/notice/notice.html"></include>
+  <details class="answer-details">
+    <summary>
+      <span class="answer-details-more">Über das Pack…</span>
+      <span class="answer-details-less">Info verbergen…</span>
+    </summary>
+
+    {{Credits}}
+    <div notice-file="KA_TEMPLATES_NOTICE"></div>
+  </details>
 </div>
 
 <!-- Suppress speech output on AnkiDroid if globally enabled -->
diff --git a/src/templates/molaoshi/.template-spec.yaml b/src/templates/molaoshi/.template-spec.yaml
index 5f982c729ae2c0b918880490d4f06b90c13f0568..3530da756a7ef3eeee041d72706f865b313eed00 100644
--- a/src/templates/molaoshi/.template-spec.yaml
+++ b/src/templates/molaoshi/.template-spec.yaml
@@ -1,4 +1,4 @@
-template_version: 2024-06-14 12:00:00+00:00
+template_version: 2024-07-20 10:00:00+00:00
 
 note_type:
   id: 2024-02-20 12:00:00+00:00
@@ -22,6 +22,7 @@ note_type:
   - Schreiben anlegen
   - Zhuyin
   - Lesen (繁體字) anlegen
+  - Credits
 
 card_types:
 - name: Hören
@@ -43,3 +44,4 @@ card_types:
 
 resource_paths:
 - '{{BUILD_PREFIX}}hanzi-data'
+- '{{BUILD_PREFIX}}KA_TEMPLATES_NOTICE.js'
diff --git a/src/templates/molaoshi/hear/back.html b/src/templates/molaoshi/hear/back.html
index a32ec6f63bf33e981ed055582dc2699bd5198b39..fe25e69b89582b12fae40d1cc40290552081d831 100644
--- a/src/templates/molaoshi/hear/back.html
+++ b/src/templates/molaoshi/hear/back.html
@@ -54,7 +54,15 @@
     </details>
   </dl>
 
-  <include src="src/components/notice/notice.html"></include>
+  <details class="answer-details">
+    <summary>
+      <span class="answer-details-more">Über das Pack…</span>
+      <span class="answer-details-less">Info verbergen…</span>
+    </summary>
+
+    {{Credits}}
+    <div notice-file="KA_TEMPLATES_NOTICE"></div>
+  </details>
 </div>
 
 <!-- Repeat only relevant text on the back side on AnkiDroid, not all of it -->
diff --git a/src/templates/molaoshi/identify_radical/back.html b/src/templates/molaoshi/identify_radical/back.html
index 0d1a17ecb421718485288e2dd8bfa750e56f1128..f9830e1ab08c0a1135b30538a4a78e992de7fa30 100644
--- a/src/templates/molaoshi/identify_radical/back.html
+++ b/src/templates/molaoshi/identify_radical/back.html
@@ -21,7 +21,15 @@
     <dd hanzi-data="{{text:简体字}}" hanzi-prop="count"></dd>
   </dl>
 
-  <include src="src/components/notice/notice.html"></include>
+  <details class="answer-details">
+    <summary>
+      <span class="answer-details-more">Über das Pack…</span>
+      <span class="answer-details-less">Info verbergen…</span>
+    </summary>
+
+    {{Credits}}
+    <div notice-file="KA_TEMPLATES_NOTICE"></div>
+  </details>
 </div>
 
 <!-- Suppress speech output on AnkiDroid if globally enabled -->
diff --git a/src/templates/molaoshi/identify_radical_traditional/back.html b/src/templates/molaoshi/identify_radical_traditional/back.html
index 7a642befa6dfc17535bd8a3ccd20f3cb490a1449..315c6ec517b717c266cb324fdf7d4ff5f15c812c 100644
--- a/src/templates/molaoshi/identify_radical_traditional/back.html
+++ b/src/templates/molaoshi/identify_radical_traditional/back.html
@@ -21,7 +21,15 @@
     <dd hanzi-data="{{text:繁體字}}" hanzi-kind="traditional" hanzi-prop="count"></dd>
   </dl>
 
-  <include src="src/components/notice/notice.html"></include>
+  <details class="answer-details">
+    <summary>
+      <span class="answer-details-more">Über das Pack…</span>
+      <span class="answer-details-less">Info verbergen…</span>
+    </summary>
+
+    {{Credits}}
+    <div notice-file="KA_TEMPLATES_NOTICE"></div>
+  </details>
 </div>
 
 <!-- Suppress speech output on AnkiDroid if globally enabled -->
diff --git a/src/templates/molaoshi/read_hanzi/back.html b/src/templates/molaoshi/read_hanzi/back.html
index a16bcfd82015db00e0c4a68db99b5cd33cca6372..403930242edcfe6606be7a672c5bb492a8a0af62 100644
--- a/src/templates/molaoshi/read_hanzi/back.html
+++ b/src/templates/molaoshi/read_hanzi/back.html
@@ -65,7 +65,15 @@
     </details>
   </dl>
 
-  <include src="src/components/notice/notice.html"></include>
+  <details class="answer-details">
+    <summary>
+      <span class="answer-details-more">Über das Pack…</span>
+      <span class="answer-details-less">Info verbergen…</span>
+    </summary>
+
+    {{Credits}}
+    <div notice-file="KA_TEMPLATES_NOTICE"></div>
+  </details>
 </div>
 
 <script type="module">
diff --git a/src/templates/molaoshi/read_hanzi_traditional/back.html b/src/templates/molaoshi/read_hanzi_traditional/back.html
index e95f0c09f4724f97995ec50a8f97f1cb7687c350..ad1accf8fb30ceac066995f4852eac25c17223b9 100644
--- a/src/templates/molaoshi/read_hanzi_traditional/back.html
+++ b/src/templates/molaoshi/read_hanzi_traditional/back.html
@@ -65,7 +65,15 @@
     </details>
   </dl>
 
-  <include src="src/components/notice/notice.html"></include>
+  <details class="answer-details">
+    <summary>
+      <span class="answer-details-more">Über das Pack…</span>
+      <span class="answer-details-less">Info verbergen…</span>
+    </summary>
+
+    {{Credits}}
+    <div notice-file="KA_TEMPLATES_NOTICE"></div>
+  </details>
 </div>
 
 <script type="module">
diff --git a/src/templates/molaoshi/read_pinyin/back.html b/src/templates/molaoshi/read_pinyin/back.html
index 71d713190f6f8922fb89900810f4e786aeaa8caf..c892d71d0b90b98d082e401010f8452c8697b753 100644
--- a/src/templates/molaoshi/read_pinyin/back.html
+++ b/src/templates/molaoshi/read_pinyin/back.html
@@ -70,7 +70,15 @@
     </details>
   </dl>
 
-  <include src="src/components/notice/notice.html"></include>
+  <details class="answer-details">
+    <summary>
+      <span class="answer-details-more">Über das Pack…</span>
+      <span class="answer-details-less">Info verbergen…</span>
+    </summary>
+
+    {{Credits}}
+    <div notice-file="KA_TEMPLATES_NOTICE"></div>
+  </details>
 </div>
 
 <script type="module">
diff --git a/src/templates/molaoshi/speak/back.html b/src/templates/molaoshi/speak/back.html
index b80aea9a7b0f06770e7a3c6d5944612bb0a5e33a..5fc56e8441bc212007ffff6107c6f9d138fe992c 100644
--- a/src/templates/molaoshi/speak/back.html
+++ b/src/templates/molaoshi/speak/back.html
@@ -70,7 +70,15 @@
     </details>
   </dl>
 
-  <include src="src/components/notice/notice.html"></include>
+  <details class="answer-details">
+    <summary>
+      <span class="answer-details-more">Über das Pack…</span>
+      <span class="answer-details-less">Info verbergen…</span>
+    </summary>
+
+    {{Credits}}
+    <div notice-file="KA_TEMPLATES_NOTICE"></div>
+  </details>
 </div>
 
 <script type="module">
diff --git a/src/templates/molaoshi/write/back.html b/src/templates/molaoshi/write/back.html
index 6417876fcdb6ba973116beaa957fc184cc5d7695..66e7c23bace84db5de587d36655443a297c2a1ef 100644
--- a/src/templates/molaoshi/write/back.html
+++ b/src/templates/molaoshi/write/back.html
@@ -70,7 +70,15 @@
     </details>
   </dl>
 
-  <include src="src/components/notice/notice.html"></include>
+  <details class="answer-details">
+    <summary>
+      <span class="answer-details-more">Über das Pack…</span>
+      <span class="answer-details-less">Info verbergen…</span>
+    </summary>
+
+    {{Credits}}
+    <div notice-file="KA_TEMPLATES_NOTICE"></div>
+  </details>
 </div>
 
 <script type="module">
diff --git a/yarn.lock b/yarn.lock
index f2dd0746d86b3062da77a11c5edbdece13299ce8..160906743abf56abf36f35c21042b0139615f271 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4174,6 +4174,11 @@ to-regex-range@^5.0.1:
   dependencies:
     is-number "^7.0.0"
 
+to-static-jsonp@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/to-static-jsonp/-/to-static-jsonp-1.0.1.tgz#bf6cda4746e01c44cf63112470ce183df2ca18c2"
+  integrity sha512-Q+32t6Or6MwXGtcTmnOoexZJNAVVDhWZX31aTdYc4lEMyG9RzGvYNfH4O5h5OBZJh6Lxf3wiQ98VzKXwB+Vrmg==
+
 toidentifier@1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"