diff --git a/chinese/edit.py b/chinese/edit.py
index b9c5e39..7b76cb2 100644
--- a/chinese/edit.py
+++ b/chinese/edit.py
@@ -17,8 +17,14 @@
# You should have received a copy of the GNU General Public License along with
# Chinese Support Redux. If not, see .
+import re
+import json
+
+import anki.buildinfo
from anki.hooks import addHook
+from aqt.utils import showWarning
from aqt import mw
+from aqt.editor import Editor
from .behavior import update_fields
from .main import config
@@ -80,12 +86,95 @@ def onFocusLost(self, _, note, index):
return False
-def append_tone_styling(editor):
- js = 'var css = document.styleSheets[0];'
+TONE_CSS_RULE = re.compile("(\\.tone\\d) *\\{([^}]*)\\}")
+
+# append_tone_styling(editor: Editor)
+#
+# Extracts the CSS rules for tones (i.e. matching TONE_CSS_RULE) from the
+# user defined CSS style sheet. For the sake of simplicity, a tone CSS rule
+# must be a one liner.
+#
+# IMPLEMENTATION NOTES:
+#
+# The code makes heavily use of internal APIs in Anki that may change in
+# future releases. Hopefully, these notes are useful to adapt the code to
+# new releases in case of breaking.
+#
+# The solution is based on Anki 2.1.54.
+#
+# The Javascript code being evaluated in the QWebView executes the following steps:
+# 1. Wait until the UI has been loaded. The code for that is based on [1].
+# 2. Loop through all RichTextInput Svelte component instances. They are
+# reachable via "require" because they have been registered before here [2].
+# Unfortunately, this method is only available since 2.1.54.
+# 3. Using the RichTextInputAPI [3], we can query the associated CustomStyles
+# instance. A CustomStyles instance has a `styleMap` [4] that contains an
+# "userBase" entry, which wraps a