diff --git a/README.md b/README.md
index 38001fc49106d83f962059ddd20304e7e0ba3f84..9bc0ff7a2992bda2793b1a06212ce77b51d5a3f8 100644
--- a/README.md
+++ b/README.md
@@ -96,7 +96,7 @@ TermLayout is _not_ a Web browser: it has no facilities for navigating links. It
 
 If you are using TermLayout with an annotator generated by Annotator Generator, you might also be interested in `tmux-annotator.sh` which sets up tmux with a “hotkey” to annotate the current screen and display the result in TermLayout.
 
-Options for Web Adjuster v3.17
+Options for Web Adjuster v3.18
 ============
 
 General options
@@ -641,7 +641,7 @@ Logging options
 
 Tornado-provided logging options are not listed above because they might vary across Tornado versions; run `python adjuster.py --help` to see a full list of the ones available on your setup. They typically include `log_file_max_size`, `log_file_num_backups`, `log_file_prefix` and `log_to_stderr`.
 
-Options for Annotator Generator v3.235
+Options for Annotator Generator v3.236
 ===========================
 
 Usage: annogen.py [options]
diff --git a/adjuster.py b/adjuster.py
index 0c22e852ba0fa90d38ae20c050d1ee39ffcd9767..568d5dcf6854a02be60d3c4a2f8e31afa864df80 100755
--- a/adjuster.py
+++ b/adjuster.py
@@ -2,7 +2,7 @@
 # (can be run in either Python 2 or Python 3;
 # has been tested with Tornado versions 2 through 6)
 
-"Web Adjuster v3.17 (c) 2012-22 Silas S. Brown"
+"Web Adjuster v3.18 (c) 2012-22 Silas S. Brown"
 
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -4790,7 +4790,7 @@ backScript="""<script><!--
 document.write('<br><a href="javascript:history.go(-1)">Back to previous page</a>')
 //--></script>"""
 backScriptNoBr="""<script><!--
-document.write('<a href="javascript:history.go(-1)">Back to previous page</a>')
+document.write('<a href="javascript:history.go(-1)">Back to previous page</a> ')
 //--></script>"""
 # (HTML5 defaults type to text/javascript, as do all pre-HTML5 browsers including NN2's 'script language="javascript"' thing, so we might as well save a few bytes)
 
@@ -4799,7 +4799,18 @@ document.write('<a href="javascript:history.go(-1)">Back to previous page</a>')
 # Ruby CSS support for Chinese/Japanese annotators etc
 # --------------------------------------------------
 
-rubyCss1 = "ruby{display:inline-table;vertical-align:bottom;-webkit-border-vertical-spacing:1px;padding-top:0.5ex;}ruby *{display: inline;vertical-align:top;line-height:1.0;text-indent:0;text-align:center;white-space:nowrap;padding-left:0px !important;padding-right:0px !important /* if we space-separate words */}rb{display:table-row-group;font-size: 100%;}rt{display:table-header-group;font-size:100%;line-height:1.1;}"
+rubyCss1 = "".join([
+    "ruby{"
+    "display:inline-table;vertical-align:bottom;"
+    "-webkit-border-vertical-spacing:1px;padding-top:0.5ex;}"
+    "ruby *{"
+    "display: inline;vertical-align:top;"
+    "line-height:1.0;text-indent:0;"
+    "text-align:center;"
+    "white-space:nowrap;" # Some versions of Chrome (including under Android 9) have layout bugs in large print: if white-space:nowrap is not here then padding will be reduced.  This does make things awkward if you have a filter whose rt output exceeds a phone's screen width in large print, but we can at least work around this with Javascript below.
+    "padding-left:0px !important;padding-right:0px !important}" # if we space-separate words
+    "rb{display:table-row-group;font-size: 100%;}"
+    "rt{display:table-header-group;font-size:100%;line-height:1.1;}"])
 rubyScript = '<style>'+rubyCss1+'</style>'
 # And the following hack is to stop the styles in the 'noscript' and the variable (and any others) from being interpreted if an HTML document with this processing is accidentally referenced as a CSS source (which can mess up ruby):
 rubyScript = "<!-- { } @media(none) { -->" + rubyScript
@@ -4810,8 +4821,12 @@ rubyScript += rubyScript_fonts
 # and this goes at the END of the body:
 rubyEndScript = """
 <script><!--
-function treewalk(n) { var c=n.firstChild; while(c) { if (c.nodeType==1 && c.nodeName!="SCRIPT" && c.nodeName!="TEXTAREA" && !(c.nodeName=="A" && c.href)) { treewalk(c); if(c.nodeName=="RUBY" && c.title && !c.clkAdded) {c.addEventListener('click',Function("alert(this.title)")); c.clkAdded=1 } } c=c.nextSibling; } } function tw() { treewalk(document.body); window.setTimeout(tw,5000); } treewalk(document.body); window.setTimeout(tw,1500);
-//--></script>""" # don't use onclick= as our bookmarklets could be incompatible with sites that say unsafe-inline in their Content-Security-Policy headers
+function tw0(){if(document.getElementsByTagName){var a=document.getElementsByTagName('ruby'),i,m=document.documentElement;"""
+rubyEndScript += "for(i=0;i < a.length; i++)if(a[i].title&&!a[i].clkAdded)(function(e){e.clkAdded=1;e.addEventListener('click',(function(){alert(e.title)}))})(a[i]);" # don't use onclick= as our bookmarklets could be incompatible with sites that say unsafe-inline in their Content-Security-Policy headers
+rubyEndScript += "if(m)m=m.offsetWidth;if(m){a=document.getElementsByTagName('rt');for(i=0;i<a.length;i++)if(a[i].offsetWidth > m)a[i].style.whiteSpace='normal'}" # overriding the above nowrap (although there'll be some delay before applying this after zoom has changed; TODO: if offsetWidth takes a lot of CPU, might want to avoid recalculating ones already checked and leave the user to reload the page if necessary after changing the size)
+rubyEndScript += """}}
+function tw() { tw0(); window.setTimeout(tw,5000); } tw0(); window.setTimeout(tw,1500);
+//--></script>""" 
 
 #@file: bookmarklet.py
 # --------------------------------------------------
diff --git a/annogen.py b/annogen.py
index 1b1b58a6c59a6c4feab12df2cf1c8543f2e811b5..1ab5598d65babd38647ab33bb8698acde8b9f89f 100755
--- a/annogen.py
+++ b/annogen.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # (compatible with both Python 2.7 and Python 3)
 
-"Annotator Generator v3.235 (c) 2012-22 Silas S. Brown"
+"Annotator Generator v3.236 (c) 2012-22 Silas S. Brown"
 
 # See http://ssb22.user.srcf.net/adjuster/annogen.html
 
@@ -1622,7 +1622,7 @@ for(c=n.firstChild; c; c=c.nextSibling) {
       if glossfile: annotateFunc += b",numLines"
       annotateFunc += b")}"
     r += b"var nv="+annotateFunc+br"""(cnv); if(nv!=cnv) { var newNode=document.createElement('span'); newNode.className='_adjust0'; if(inLink) newNode.inLink=1; n.replaceChild(newNode, c); try { newNode.innerHTML=nv } catch(err) { alert(err.message) }"""
-    if for_android: r += br"""if(!inLink){var a=newNode.getElementsByTagName('ruby'),i; for(i=0; i < a.length; i++) a[i].addEventListener('click',annotPopAll)}"""
+    if for_android: r += br"""var a,i,m=document.documentElement;if(!inLink){a=newNode.getElementsByTagName('ruby');for(i=0; i < a.length; i++) a[i].addEventListener('click',annotPopAll)} if(m)m=m.offsetWidth;if(m){a=newNode.getElementsByTagName('rt');for(i=0;i < a.length;i++)if(a[i].offsetWidth > m)a[i].style.setProperty('white-space','normal','important')}""" # (offsetWidth part not currently done on browser extension; low priority as browser extensions are currently desktop-only)
     r += b"}" # if nv != cnv
   r += b"}}" # case 3, switch
   if not for_async: r += b"cP=c;"
@@ -1648,7 +1648,7 @@ for(c=n.firstChild; c; c=c.nextSibling) {
     r += br"""
         nReal.innerHTML='<span class=_adjust0>'+n.innerHTML.replace(/<ruby[^>]*>((?:<[^>]*>)*?)<span class=.?_adjust0.?>((?:<span><[/]span>)?[^<]*)(<ruby[^>]*><rb>.*?)<[/]span>((?:<[^>]*>)*?)<rt>(.*?)<[/]rt><[/]ruby>/ig,function(m,open,lrm,rb,close,rt){var a=rb.match(/<ruby[^>]*/g),i;for(i=1;i < a.length;i++){var b=a[i].match(/title=[\"]([^\"]*)/i);if(b)a[i]=' || '+b[1]; else a[i]=''}var attrs=a[0].slice(5).replace(/title=[\"][^\"]*/,'$&'+a.slice(1).join('')); return lrm+'<ruby'+attrs+'><rb>'+open.replace(/<rb>/ig,'')+rb.replace(/<ruby[^>]*><rb>/g,'').replace(/<[/]rb>.*?<[/]ruby> */g,'')+close.replace(/<[/]rb>/ig,'')+'</rb><rt>'+rt+'</rt></ruby>'}).replace(/<[/]ruby>((<[^>]*>|\\u200e)*?<ruby)/ig,'</ruby> $1').replace(/<[/]ruby> ((<[/][^>]*>)+)/ig,'</ruby>$1 ')+'</span>'"""
     if for_android: r += br""";
-        if(!inLink) {var a=function(n){n=n.firstChild;while(n){if(n.nodeType==1){if(n.nodeName=='RUBY')n.addEventListener('click',annotPopAll);else if(n.nodeName!='A')a(n)}n=n.nextSibling}};a(nReal)}"""
+        var a=function(n,i){for(n=n.firstChild;n;n=n.nextSibling){if(n.nodeType==1){if(n.nodeName=='RUBY'){if(!i)n.addEventListener('click',annotPopAll);var t;for(t=n.firstChild;t;t=t.nextSibling)if(t.nodeType==1&&t.nodeName=='RT'&&t.offsetWidth > document.documentElement.offsetWidth)t.style.setProperty('white-space','normal','important')}else a(n,i||n.nodeName=='A')}}};a(nReal,inLink)"""
     if delete_existing_ruby: r += b"""} else nReal.parentNode.replaceChild(n,nReal)"""
     r += b"}" # if nf
   r += b"}" # function annotWalk
@@ -1734,7 +1734,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, CMD_LINE_T cm
     outFile=fopen(fname,"w");
     if (!outFile) errorExit("Cannot write c.html");
   }
-  OutWriteStr("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"><meta name=\"mobileoptimized\" content=\"0\"><meta name=\"viewport\" content=\"width=device-width\"></head><body><style id=\"ruby\">ruby { display: inline-table; vertical-align: bottom; -webkit-border-vertical-spacing: 1px; padding-top: 0.5ex; } ruby * { display: inline; vertical-align: top; line-height:1.0; text-indent:0; text-align:center; white-space: nowrap; } rb { display: table-row-group; font-size: 100%; } rt { display: table-header-group; font-size: 100%; line-height: 1.1; }</style>\n<!--[if lt IE 8]><style>ruby, ruby *, ruby rb, ruby rt { display: inline !important; vertical-align: baseline !important; padding-top: 0pt !important; } ruby { border: thin grey solid; } </style><![endif]-->\n<!--[if !IE]>-->\n<style>rt { font-family: FreeSerif, Lucida Sans Unicode, Times New Roman, serif !important; }</style>\n<!--<![endif]-->\n<script><!--\nif(navigator.userAgent.match('Edge/'))document.write('<table><tr><td>')\n//--></script><h3>Clipboard</h3>");
+  OutWriteStr("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"><meta name=\"mobileoptimized\" content=\"0\"><meta name=\"viewport\" content=\"width=device-width\"></head><body><style>ruby { display: inline-table; vertical-align: bottom; -webkit-border-vertical-spacing: 1px; padding-top: 0.5ex; } ruby * { display: inline; vertical-align: top; line-height:1.0; text-indent:0; text-align:center; white-space: nowrap; } rb { display: table-row-group; font-size: 100%; } rt { display: table-header-group; font-size: 100%; line-height: 1.1; }</style>\n<!--[if lt IE 8]><style>ruby, ruby *, ruby rb, ruby rt { display: inline !important; vertical-align: baseline !important; padding-top: 0pt !important; } ruby { border: thin grey solid; } </style><![endif]-->\n<!--[if !IE]>-->\n<style>rt { font-family: FreeSerif, Lucida Sans Unicode, Times New Roman, serif !important; }</style>\n<!--<![endif]-->\n<script><!--\nif(navigator.userAgent.match('Edge/'))document.write('<table><tr><td>')\n//--></script><h3>Clipboard</h3>");
   p=pOrig; copyP=p;
   matchAll();
   free(pOrig);
@@ -1852,6 +1852,7 @@ android_url_box += br"""
 <form style="clear:both;margin:0em;padding-top:0.5ex" onSubmit="var v=this.url.value;if(typeof annotUrlTrans!='undefined'){var u=annotUrlTrans(v);if(typeof u!='undefined')v=u}if(v.slice(0,4)!='http')v='http://'+v;if(v.indexOf('.')==-1)ssb_local_annotator.alert('','','The text you entered is not a Web address. Please enter a Web address like www.example.org');else{this.t.parentNode.style.width='50%';this.t.value='LOADING: PLEASE WAIT';window.location.href=v}return false"><table style="width: 100%"><tr><td style="width:1em;margin:0em;padding:0em;display:none" id=displayMe align=left><button style="width:100%;background:#ededed;color:inherit" onclick="document.forms[document.forms.length-1].url.value='';document.getElementById('displayMe').style.display='none';return false">X</button></td><td style="margin: 0em; padding: 0em"><input type=text style="width:100%;background:inherit;color:inherit" placeholder="http://"; name=url></td><td style="width:1em;margin:0em;padding:0em" align=right><input type=submit name=t value=Go style="width:100%;background:#ededed;color:inherit"></td></tr></table></form>
 <script>
 function viewZoomCtrls() {
+   var s=document.body.getElementsByTagName("style")[0]; s.innerText=s.innerText.replace(/nowrap/,'normal');
    window.setTimeout(function(){
    var t=document.getElementById("zI");
    var r=t.getBoundingClientRect();