Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
<!--}}}-->
When getting started, you may want to:
* Set your username for signing your edits: <<option txtUserName>>
* Change the page [[title|SiteTitle]] (now "<<tiddler SiteTitle>>") and [[subtitle|SiteSubtitle]] (now "<<tiddler SiteSubtitle>>"); they also set the browser tab title
* Create a tiddler where your content "starts"
** Use the button on the sidebar or [[link|My first tiddler]] it here, follow the link, edit, and click "done"
** It will be shown in the Timeline (usually on the right), but you may want to link it in the MainMenu (usually on the left)
** and/or make it open when the ~TiddlyWiki is opened by editing the list of [[DefaultTiddlers]] (separate links with spaces or linebreaks)
* Save your ~TiddlyWiki
** Although "download saving" works in any browser, it may be not that convenient, so you'll probably want to use [[a dedicated saver|https://classic.tiddlywiki.com/#%5B%5BSetting up saving%5D%5D]]
<<importTiddlers>>
<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
These [[InterfaceOptions]] for customising [[TiddlyWiki]] are saved in your browser

Your username for signing your edits. Write it as a [[WikiWord]] (eg [[JoeBloggs]])

<<option txtUserName>>
<<option chkSaveBackups>> [[SaveBackups]]
<<option chkAutoSave>> [[AutoSave]]
<<option chkRegExpSearch>> [[RegExpSearch]]
<<option chkCaseSensitiveSearch>> [[CaseSensitiveSearch]]
<<option chkAnimate>> [[EnableAnimations]]

----
Also see [[AdvancedOptions]]
<!--{{{-->
<div class='header' role='banner'>
  <div class='headerShadow'>
    <span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
    <span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
  </div>
  <div class='headerForeground'>
    <span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
    <span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
  </div>
</div>
<div id='mainMenu' role='navigation' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
  <div id='sidebarOptions' role='navigation' refresh='content' tiddler='SideBarOptions'></div>
  <div id='sidebarTabs' role='complementary' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea' role='main'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

a {color:[[ColorPalette::PrimaryMid]];}
a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a img {border:0;}

h1, h2, h3, h4, h5, h6 { color: [[ColorPalette::SecondaryDark]]; }
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

.txtOptionInput {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

.button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
.button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
.button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}

.header {
	background: -moz-linear-gradient(to bottom, [[ColorPalette::PrimaryLight]], [[ColorPalette::PrimaryMid]]);
	background: linear-gradient(to bottom, [[ColorPalette::PrimaryLight]], [[ColorPalette::PrimaryMid]]);
}
.header a:hover {background:transparent;}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

.tabSelected {
	color:[[ColorPalette::Foreground]];
	background:[[ColorPalette::Background]];
	border-left:1px solid [[ColorPalette::TertiaryLight]];
	border-top:1px solid [[ColorPalette::TertiaryLight]];
	border-right:1px solid [[ColorPalette::TertiaryLight]];
}
.tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
.tabContents {border:1px solid [[ColorPalette::TertiaryLight]];}
.tabContents .button {border:0;}

#sidebar {}
#sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
#sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}

.wizard { background:[[ColorPalette::PrimaryPale]]; }
.wizard__title    { color:[[ColorPalette::PrimaryDark]]; border:none; }
.wizard__subtitle { color:[[ColorPalette::Foreground]]; border:none; }
.wizardStep { background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]]; }
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizardFooter .status a { color: [[ColorPalette::PrimaryPale]]; }
.wizard .button {
	color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryDark]];
}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {
	color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];
}

.wizard .notChanged {background:transparent;}
.wizard .changedLocally {background:#80ff80;}
.wizard .changedServer {background:#8080ff;}
.wizard .changedBoth {background:#ff8080;}
.wizard .notFound {background:#ffff80;}
.wizard .putToServer {background:#ff80ff;}
.wizard .gotFromServer {background:#80ffff;}

#messageArea { background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; box-shadow: 1px 2px 5px [[ColorPalette::TertiaryMid]]; }
.messageToolbar__button { color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none; }
.messageToolbar__button_withIcon { background:inherit; }
.messageToolbar__button_withIcon:active { background:inherit; border:none; }
.tw-icon line { stroke: [[ColorPalette::TertiaryDark]]; }
.messageToolbar__button:hover .tw-icon line { stroke: [[ColorPalette::Foreground]]; }

.popup {
	background: [[ColorPalette::Background]];
	color: [[ColorPalette::TertiaryDark]];
	box-shadow: 1px 2px 5px [[ColorPalette::TertiaryMid]];
}
.popup li a, .popup li a:visited, .popup li a:hover, .popup li a:active {
	color:[[ColorPalette::Foreground]]; border: none;
}
.popup li a:hover { background:[[ColorPalette::SecondaryLight]]; }
.popup li a:active { background:[[ColorPalette::SecondaryPale]]; }
.popup li.disabled { color:[[ColorPalette::TertiaryMid]]; }
.popupHighlight {color:[[ColorPalette::Foreground]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}

.tiddler .defaultCommand {font-weight:bold;}

.shadow .title {color:[[ColorPalette::TertiaryDark]];}

.title {color:[[ColorPalette::SecondaryDark]];}
.subtitle {color:[[ColorPalette::TertiaryDark]];}

.toolbar {color:[[ColorPalette::PrimaryMid]];}
.toolbar a {color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
.selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}

.tagging, .tagged { background: [[ColorPalette::Background]]; border: 2px solid [[ColorPalette::TertiaryPale]]; }
.selected .tagging, .selected .tagged { border: 2px solid [[ColorPalette::TertiaryLight]]; }
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button { border:none; }

.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}

.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}

.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}

.imageLink, #displayArea .imageLink {background:transparent;}

.annotation { background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }

.viewer .listTitle {list-style-type:none; margin-left:-2em;}
.viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
.viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}

.twtable { background: [[ColorPalette::Background]]; }
.viewer th, .viewer thead td, .twtable th, .twtable thead td { background: [[ColorPalette::SecondaryMid]]; color: [[ColorPalette::Background]]; }
.viewer td, .viewer tr, .twtable td, .twtable tr { border: 1px solid [[ColorPalette::TertiaryLight]]; }
.twtable caption { color: [[ColorPalette::TertiaryMid]]; }

.viewer pre {background:[[ColorPalette::SecondaryPale]];}
.viewer code {color:[[ColorPalette::SecondaryDark]];}
.viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

.highlight, .marked {background:[[ColorPalette::SecondaryLight]];}

.editor input {border:1px solid [[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%; background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}
.readOnly {background:[[ColorPalette::TertiaryPale]];}

#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:alpha(opacity=60);}
/*}}}*/
/*{{{*/
body { font-size:.75em; font-family:arial,helvetica,sans-serif; margin:0; padding:0; }

* html .tiddler {height:1%;}

h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}

hr {height:1px;}

dt {font-weight:bold;}

ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}

.txtOptionInput {width:11em; border-width: 1px; }

#contentWrapper .chkOptionInput {border:0;}

.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}


a {text-decoration:none;}

.externalLink {text-decoration:underline;}

.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}

/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}

#mainMenu .tiddlyLinkExisting,
#mainMenu .tiddlyLinkNonExisting,
#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}


.header {position:relative;}
.headerShadow {position:relative; padding:3em 0 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:3em 0 1em 1em; left:0; top:0;}

.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}

#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}

#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 0.3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}
#sidebarTabs li:not(:last-child) { margin-bottom: 0.3em; }
#sidebarTabs ul:not(:last-child) { margin-bottom: 0.5em; }

.wizard { padding:0.1em 2em 0; }
.wizard__title    { font-size:2em; }
.wizard__subtitle { font-size:1.2em; }
.wizard__title, .wizard__subtitle { font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em; }
.wizardStep { padding:1em; }
.wizardFooter { padding: 0.8em 0; }
.wizardFooter .status { display: inline-block; line-height: 1.5; padding: 0.3em 1em; }
.wizardFooter .button { margin:0.5em 0 0; font-size:1.2em; padding:0.2em 0.5em; }

#messageArea { position:fixed; top:2em; right:0; margin:0.5em; padding:0.7em 1em; z-index:2000; }
.messageToolbar { text-align:right; padding:0.2em 0; }
.messageToolbar__button { text-decoration:underline; }
.messageToolbar__button_withIcon { display: inline-block; }
.tw-icon { height: 1em; width: 1em; } /* width for IE */
.tw-icon line { stroke-width: 1; stroke-linecap: round; }
.messageArea__text:not(:last-child) { margin-bottom: 0.3em; }
.messageArea__text a { text-decoration:underline; }

.popup {position:absolute; z-index:300; font-size:.9em; padding:0.3em 0; list-style:none; margin:0;}
.popup .popupMessage, .popup li.disabled, .popup li a { padding: 0.3em 0.7em; }
.popup li a {display:block; font-weight:normal; cursor:pointer;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}

.tiddlerPopupButton {padding:0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em; margin:0;}

.tabset {padding:1em 0 0 0.5em;}
.tab {display: inline-block; white-space: nowrap; position: relative; bottom: -0.7px; margin: 0 0.25em 0 0; padding:0.2em;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}

#contentWrapper {display:block;}
#splashScreen {display:none;}

#displayArea {margin:1em 17em 0 14em;}

.toolbar {text-align:right; font-size:.9em;}

.tiddler { padding: 1em; }

.title { font-size: 1.6em; font-weight: bold; }
.subtitle { font-size: 1.1em; }

.missing .viewer, .missing .title { font-style: italic; }
.missing .subtitle { display: none; }

.tiddler .button {padding:0.2em 0.4em;}

.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagged li, .tagging li { margin: 0.3em 0; }
.tagClear {clear:both;}

.footer {font-size:.9em;}
.footer li {display:inline;}

.annotation { padding: 0.5em 0.8em; margin: 0.5em 1px; }

.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0 0.25em; padding:0 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}

.viewer table, table.twtable { border-collapse: collapse; margin: 0.8em 0; }
.viewer th, .viewer td, .viewer tr, .viewer caption, .twtable th, .twtable td, .twtable tr, .twtable caption { padding: 0.2em 0.4em; }
.twtable caption { font-size: 0.9em; }
table.listView { margin: 0.8em 1.0em; }
table.listView th, table.listView td, table.listView tr { text-align: left; }
.listView > thead { position: sticky; top: 0; }

* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer pre {padding:0.5em; overflow:auto;}
pre, code { font-family: monospace, monospace; font-size: 1em; }
.viewer pre, .viewer code { line-height: 1.4em; }

.editor {font-size:1.1em; line-height:1.4em;}
.editor input, .editor textarea { display: block; width: 100%; box-sizing: border-box; font: inherit; padding: 0.1em 0.4em; }
.editorFooter {padding:0.25em 0; font-size:.9em;}
.editorFooter .button {padding-top:0; padding-bottom:0;}

.fieldsetFix {border:0; padding:0; margin:1px 0;}

.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}

* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0; right:0;}
#backstageButton a {padding: 0.3em 0.5em; display: inline-block;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel { display:none; z-index:100; position:absolute; width:90%; margin:0 5%; }
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
  #mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea { display: none !important; }
  #displayArea { margin: 1em 1em 0em; }
}
/*}}}*/
<!--{{{-->
<div class='toolbar' role='navigation' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
/***
|Name       |DarkModePlugin|
|Description|This plugin introduces "dark mode" (changes styles) and switching it by the {{{darkMode}}} macro and operating system settings|
|Documentation|https://yakovl.github.io/TiddlyWiki_DarkModePlugin/|
|Version    |1.3.3|
|Author     |Yakov Litvin|
|Source     |https://github.com/YakovL/TiddlyWiki_DarkModePlugin/blob/master/DarkModePlugin.js|
|License    |[[MIT|https://github.com/YakovL/TiddlyWiki_YL_ExtensionsCollection/blob/master/Common%20License%20(MIT)]]|
!!!Demo
<<darkMode>>
<<darkMode label:"☀️/🌘">>
!!!Syntax
{{{
<<darkMode>> (<<switchNightMode>> also works, for backward compatibility)
<<darkMode label:"☀️/🌘">>
}}}
!!!Installation
Is as usual: import or copy the plugin with the {{{systemConfig}}} tag, reload. Note: for the plugin to work correctly, you should keep its name (DarkModePlugin).

!!!Optional configuration
When the dark mode is applied, the {{{darkMode}}} class is added to the {{{html}}} element. This allows to add ''styles for dark mode'' only, like this:
{{{
.darkMode code { color:red }
code { color: green }
}}}
Ordinary styles are applied to both modes, but {{{.darkMode}}} ones have higher precedence and "overwrite" the oridinary ones.

The palette applied for the dark mode can be ''customized'' by editing ColorPaletteDark (removing it restores the default values).

!!!Additional notes
Styles of some browser interface bits (like <html><button class="button" onclick='alert("this is known as an alert")'>alert</button</html>) are only affected by OS/browser's "dark mode"/theme, so for good UI it is recommended to switch OS dark mode (DarkModePlugin will follow). For Windows users, [[switching by hotkey|https://superuser.com/a/1724237/576393]] may be useful.

The plugin ''adds extra styles'' (see ~FollowDarkMode and ~FewerColors sections) which are not yet configurable.

The option {{{chkDarkMode}}} is now ''deprecated'': later it will be either removed or re-implemented.
!!!Code
***/
//{{{
config.macros.switchNightMode = // backward compatibility
config.macros.darkMode = {
	pluginName: "DarkModePlugin",
	optionName: "chkDarkMode",
	getDarkPaletteText: function() {
		return store.getTiddlerText(this.darkPaletteTitle)
	},
	// this helper may become more complex for custom themes
	getMainPaletteTitle: function() {
		return "ColorPalette"
	},
	lightPaletteTitle: "ColorPaletteLight",
	darkPaletteTitle: "ColorPaletteDark",

	// setDark, setLight, and applyAdjustments are "governed outside": they don't check or change the cookie-parameter
	setDark: function() {
		var paletteTitle = this.getMainPaletteTitle()

		var lightPaletteTiddler = new Tiddler(this.lightPaletteTitle)
		lightPaletteTiddler.text = store.getTiddlerText(paletteTitle) || "shadow"
		store.saveTiddler(lightPaletteTiddler)

		var darkPaletteTiddler = new Tiddler(paletteTitle)
		darkPaletteTiddler.text = this.getDarkPaletteText()
		// attach the tiddler, recalc slices, invoke notifiers
		store.saveTiddler(darkPaletteTiddler)

		this.applyAdjustments(true)
	},
	setLight: function() {
		var paletteTitle = this.getMainPaletteTitle()

		var lightPaletteText = store.getTiddlerText(this.lightPaletteTitle)
		if(!lightPaletteText || lightPaletteText === "shadow")
			store.removeTiddler(paletteTitle) // to recalc slices of ColorPalette
		else
			store.saveTiddler(paletteTitle, paletteTitle, lightPaletteText)

		store.deleteTiddler(this.lightPaletteTitle)

		this.applyAdjustments(false)
	},
	applySectionCSS: function(sectionName) {
		var sectionText = store.getRecursiveTiddlerText(this.pluginName + "##" + sectionName, "", 1)
		var css = sectionText.replace(/^\s*{{{((?:.|\n)*?)}}}\s*$/, "$1")
		return setStylesheet(css, sectionName)
	},
	applyAdjustments: function(isDarkMode) {
		if(isDarkMode) {
			jQuery('html').addClass('darkMode')
			this.applySectionCSS("FollowDarkMode")
			this.applySectionCSS("~FewerColors")
		} else {
			jQuery('html').removeClass('darkMode')
			removeStyleSheet("FollowDarkMode")
			removeStyleSheet("~FewerColors")
		}
	},

	// "governance" methods
	isDarkMode: function() {
		return !!store.fetchTiddler(this.lightPaletteTitle)
	},
	switchMode: function() {
		var me = config.macros.darkMode
		config.options[me.optionName] = !config.options[me.optionName]

		config.options[me.optionName] ? me.setDark() : me.setLight()

// "baking" doesn't work yet..
		if(saveOption)
			saveOption(me.optionName)
		else
			saveOptionCookie(me.optionName)

		refreshColorPalette()
	},
	followOsMode: function(followLight) {
		// old browsers may fail to detect
		var isOsDarkModeDetected = window.matchMedia &&
			window.matchMedia('(prefers-color-scheme: dark)').matches

		if(isOsDarkModeDetected && !this.isDarkMode()) {
			config.options[this.optionName] = false
			this.switchMode()
		}

		if(!isOsDarkModeDetected && this.isDarkMode() && followLight) {
			config.options[this.optionName] = true
			this.switchMode()
		}
	},
	restoreSavedMode: function() {
		if(!this.isDarkMode()) return

		// TODO: check if styles are really missing (avoid applying twice)
		this.applyAdjustments(true)
		config.options[this.optionName] = true
	},
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		var pParams = paramString.parseParams("anon", null, true, false, true)
		var label = getParam(pParams, "label", "switch")
		var tooltip = ""

		createTiddlyButton(place, label, tooltip, this.switchMode, 'button darkModeSwitcher')
	}
}

// We avoid using .init to support installation via SharedTiddlersPlugin, TiddlerInFilePlugin, and reinstalling via CookTiddlerPlugin.
// This also helps to avoid extra refreshing.
;(function(macro) {
	// Save the palette as shadow so that one can cusomize it
	config.shadowTiddlers[macro.darkPaletteTitle] =
		store.getTiddlerText(macro.pluginName + "##DarkModeColorPalette")

	// Set dark mode on start if OS dark mode is set or dark mode was saved previously
	macro.followOsMode(false)
	macro.restoreSavedMode()

	// install only once
	if(!config.extensions.DarkModePlugin) {
		// prevent sites to ask about unsaved changes after switching mode
		config.extensions.DarkModePlugin = {
			orig_confirmExit: confirmExit
		}
		window.confirmExit = function() {
			if(readOnly) return
			return config.extensions.DarkModePlugin.orig_confirmExit ?
				config.extensions.DarkModePlugin.orig_confirmExit() : undefined
		}

		// Detect OS mode change, apply
		if(window.matchMedia) window.matchMedia('(prefers-color-scheme: dark)')
			.addEventListener('change', function(event) { macro.followOsMode(true) })
	}
})(config.macros.darkMode)
//}}}
/***
!!!FollowDarkMode
{{{
input, select, textarea {
	color:[[ColorPalette::Foreground]];
	background-color:[[ColorPalette::Background]];
}

.darkMode {
	color-scheme: dark;
}
}}}
!!!~FewerColors
{{{
.title, h1, h2, h3, h4, h5, h6 {
	color: [[ColorPalette::PrimaryDark]];
}
::selection {
	background: [[ColorPalette::TertiaryMid]];
}
}}}
!!!DarkModeColorPalette
Background: #000
Foreground: #ddd
~PrimaryPale: #730
~PrimaryLight: #e70
~PrimaryMid: #fb4
~PrimaryDark: #feb
~SecondaryPale: #003
~SecondaryLight: #017
~SecondaryMid: #24b
~SecondaryDark: #7be
~TertiaryPale: #111
~TertiaryLight: #333
~TertiaryMid: #666
~TertiaryDark: #999
Error: #f44
!!!
***/
[[Intro]]
Sjcl@{"iv":"57rhQuMkmc8yi08NOUEFCA==","v":1,"iter":10000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"W9klfKsl9X0=","ct":"98v6rff+kcc5QaKjz53vNyzyxe6KsKMpLO6mNKBwfVwtLPYj5i4UJ+ZC+08EW0ljlv7UrEpCJQvkH8MfO+xmz+PbASiCe7Xgt21J35sOBS/Zt+48dXvRBOwiycOpeCBZWnHPhmkLr4mhJaChKet5C4WCHm71YOgeDDW484AO0IlgfJ5HKjaGkwFmN9ZtOzIqggTXfFLcABqZWldzwY1gkLiWMQ=="}
/***
|Name        |EncryptionPlugin|
|Description |Allows to encrypt (password protect) selected content with AES and adapt the interface with additional macros|
|Demo        |Open the [[demo page|https://yakovl.github.io/TiddlyWiki_EncryptionPlugin/demo.html]] to try the look & feel|
|Version     |2.0.3|
|Source      |https://github.com/YakovL/TiddlyWiki_EncryptionPlugin/blob/master/EncryptionPlugin.js|
|Author      |Yakov Litvin|
|Forked from |[[EncryptedVaultPlugin|http://visualtw.ouvaton.org/VisualTW.html#EncryptedVaultPlugin]] by Pascal Collin (now available at [[GitHub|https://yakovl.github.io/VisualTW2/VisualTW2.html#EncryptedVaultPlugin]] or [[in web archive|https://web.archive.org/web/20160130130224/http://visualtw.ouvaton.org/VisualTW.html#EncryptedVaultPlugin]]); versions up to 1.7.1 were pre-released as ~NewEncryptedVaultPlugin|
|License|[[BSD open source license|License]]|
!Installation
While this plugin is supposed to work in any modern browser and with any TW saver, it is __recommended to create a backup__ of your TW before installing the plugin.

Other than that (and unlike v1.x), the plugin is __installed as usual__ (import/copy the plugin with the {{{systemConfig}}} tag, save and reload).
With [[ExtensionsExplorerPlugin|https://github.com/YakovL/TiddlyWiki_ExtensionsExplorerPlugin]], this one can be found and installed from the ~ExtensionsCollection → ~YLExtensionsCollection.

For details about upgrading from 1.x or migrating from ~EncryptedVaultPlugin, see sections below.
!Usage
* Use <<unlock>><<setPassword>> button (available by default in SideBarOptions)
** {{{<<unlock ButtonTitle ButtonTooltip OpenTiddlersWhenUnlock CloseTiddlersWhenUnlock>>}}} creates a button to unlock the encrypted vault (all parameters are optional)
** {{{<<setPassword ButtonTitle ButtonTooltip>>}}} if unlocked, creates a button to set the current password (all parameters are optional)
* Use a blank password to save unencrypted (disable vault usage)
* By default, only the system tiddlers (shadow ones and those tagged {{{systemConfig}}}) aren't encrypted. Also, if you create [[ListUnencrypted]] and put a [[filter|classic.tiddlywiki.com#Filters]] there, the filtered tiddlers won't be encrypted, too.
** Use {{{unencrypted}}} tag to avoid encryption for some tiddler
** Use {{{forceEncryption}}} tag to force some shadow tiddler to be encrypted
** Even shadow tiddlers (MainMenu, SiteTitle, PageTemplate, StyleSheet, ...) ''can be encrypted''. The shadow version is used until unlocking.
* Additionally, you can use the following macros:
** {{{<<purge ButtonTitle ButtonTooltip>>}}} if locked, creates a button to purge a locked vault, useful for lost password (encrypted content is the deleted)
** {{{<<ifLocked tiddlyText>>}}} displays tiddlyText (wikified) if the vault is locked
** {{{<<ifUnlocked tiddlyText>>}}} displays tiddlyText (wikified) if the vault is unlocked
!Understand your attack model
Security is a state, not a result, because it depends on actions of others. To understand if your security model is good enough, you should understnad the attack model.

A typical model is that you don't want somebody to have your data accidentally or with minimal efforts – for this case you have to just make sure the password you're using is strong enough (i.e. one can't quickly guess it or crack with simple dictionary techniques).

However, you should mind the data sensitivity: for instance, using encrypted TW to store credentials of financial accounts that hold big funds, or to store other information that "costs" much is not recommended as TW doesn't provide means to prevent brute force attacks, and can be theoretically attacked with other means, like malware plugins or phishing.

In other words, you should be mindful about what you are trying to protect, from whom, and if just encrypting with AES is good enough in your case.
!Upgrading from 1.x
Although it works smoothly, it is recommended to create a backup before upgrading from 1.x.
After upgrading, manual removal of the old vault is recommended: open TW with a text editor, find {{{<!--POST-SHADOWAREA-->}}}, and remove the 2 lines after  it (one starting with {{{<div id="vaultArea">}}} and the other being {{{<!--POST-VAULTAREA-->}}}).
!Migration from ~EncryptedVaultPlugin
The recommended way to migrate is to
# Backup your TW
# Decrypt it (unset the password, save)
# Remove the ~EncryptedVaultPlugin, add ~EncryptionPlugin, save, reload
# Encrypt again (set the password, save, reload), check if it works fine
	{{PoG{test thoroughly (including, DefaultTiddlers, first run of the plugin, macros appearence and usage, data format compatibility, including unencrypted, ...; .oO MVP for ...) and update metadata}}}
!Changes since ~EncryptedVaultPlugin
Compared to ~EncryptedVaultPlugin, this plugin:
* Uses a stonger encryption (AES);
* Fixes various major issues, uses decorators instead of overridings of several core functions;
* Uses a customizable StyleSheetVault shadow for styles;
* Improves the UI for password (doesn't show the typed value, adds autofocus, supports pressing enter to apply).
Additionally, versions 2.x use a tiddler to store encrypted content and hence:
* Are not restricted by which saver to use;
* Don't interfere with core upgrading (although in some cases one has to unencrypt TW before doing it);
* Encrypted content can be imported, [[inlcuded|https://yakovl.github.io/TiddlyWiki_SharedTiddlersPlugin/]], [[saved to a file|https://github.com/YakovL/TiddlyWiki_TiddlerInFilePlugin]], etc.
***/
/***
Stanford Javascript Crypto Library {{DDnc{v.1.0.6 ([[63eed5|https://github.com/bitwiseshiftleft/sjcl/commit/63eed58b9dc395afb3c03df8d70d7e7bf4c88b1b]]), update!}}}, source: https://github.com/bitwiseshiftleft/sjcl
+ one line to make `sjcl` globally accessible
***/
//{{{
"use strict";var sjcl={cipher:{},hash:{},keyexchange:{},mode:{},misc:{},codec:{},exception:{corrupt:function(a){this.toString=function(){return"CORRUPT: "+this.message};this.message=a},invalid:function(a){this.toString=function(){return"INVALID: "+this.message};this.message=a},bug:function(a){this.toString=function(){return"BUG: "+this.message};this.message=a},notReady:function(a){this.toString=function(){return"NOT READY: "+this.message};this.message=a}}};
sjcl.cipher.aes=function(a){this.s[0][0][0]||this.O();var b,c,d,e,f=this.s[0][4],g=this.s[1];b=a.length;var h=1;if(4!==b&&6!==b&&8!==b)throw new sjcl.exception.invalid("invalid aes key size");this.b=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(0===a%b||8===b&&4===a%b)c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255],0===a%b&&(c=c<<8^c>>>24^h<<24,h=h<<1^283*(h>>7));d[a]=d[a-b]^c}for(b=0;a;b++,a--)c=d[b&3?a:a-4],e[b]=4>=a||4>b?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^g[3][f[c&
255]]};
sjcl.cipher.aes.prototype={encrypt:function(a){return t(this,a,0)},decrypt:function(a){return t(this,a,1)},s:[[[],[],[],[],[]],[[],[],[],[],[]]],O:function(){var a=this.s[0],b=this.s[1],c=a[4],d=b[4],e,f,g,h=[],k=[],l,n,m,p;for(e=0;0x100>e;e++)k[(h[e]=e<<1^283*(e>>7))^e]=e;for(f=g=0;!c[f];f^=l||1,g=k[g]||1)for(m=g^g<<1^g<<2^g<<3^g<<4,m=m>>8^m&255^99,c[f]=m,d[m]=f,n=h[e=h[l=h[f]]],p=0x1010101*n^0x10001*e^0x101*l^0x1010100*f,n=0x101*h[m]^0x1010100*m,e=0;4>e;e++)a[e][f]=n=n<<24^n>>>8,b[e][m]=p=p<<24^p>>>8;for(e=
0;5>e;e++)a[e]=a[e].slice(0),b[e]=b[e].slice(0)}};
function t(a,b,c){if(4!==b.length)throw new sjcl.exception.invalid("invalid aes block size");var d=a.b[c],e=b[0]^d[0],f=b[c?3:1]^d[1],g=b[2]^d[2];b=b[c?1:3]^d[3];var h,k,l,n=d.length/4-2,m,p=4,r=[0,0,0,0];h=a.s[c];a=h[0];var q=h[1],v=h[2],w=h[3],x=h[4];for(m=0;m<n;m++)h=a[e>>>24]^q[f>>16&255]^v[g>>8&255]^w[b&255]^d[p],k=a[f>>>24]^q[g>>16&255]^v[b>>8&255]^w[e&255]^d[p+1],l=a[g>>>24]^q[b>>16&255]^v[e>>8&255]^w[f&255]^d[p+2],b=a[b>>>24]^q[e>>16&255]^v[f>>8&255]^w[g&255]^d[p+3],p+=4,e=h,f=k,g=l;for(m=
0;4>m;m++)r[c?3&-m:m]=x[e>>>24]<<24^x[f>>16&255]<<16^x[g>>8&255]<<8^x[b&255]^d[p++],h=e,e=f,f=g,g=b,b=h;return r}
sjcl.bitArray={bitSlice:function(a,b,c){a=sjcl.bitArray.$(a.slice(b/32),32-(b&31)).slice(1);return void 0===c?a:sjcl.bitArray.clamp(a,c-b)},extract:function(a,b,c){var d=Math.floor(-b-c&31);return((b+c-1^b)&-32?a[b/32|0]<<32-d^a[b/32+1|0]>>>d:a[b/32|0]>>>d)&(1<<c)-1},concat:function(a,b){if(0===a.length||0===b.length)return a.concat(b);var c=a[a.length-1],d=sjcl.bitArray.getPartial(c);return 32===d?a.concat(b):sjcl.bitArray.$(b,d,c|0,a.slice(0,a.length-1))},bitLength:function(a){var b=a.length;return 0===
b?0:32*(b-1)+sjcl.bitArray.getPartial(a[b-1])},clamp:function(a,b){if(32*a.length<b)return a;a=a.slice(0,Math.ceil(b/32));var c=a.length;b=b&31;0<c&&b&&(a[c-1]=sjcl.bitArray.partial(b,a[c-1]&2147483648>>b-1,1));return a},partial:function(a,b,c){return 32===a?b:(c?b|0:b<<32-a)+0x10000000000*a},getPartial:function(a){return Math.round(a/0x10000000000)||32},equal:function(a,b){if(sjcl.bitArray.bitLength(a)!==sjcl.bitArray.bitLength(b))return!1;var c=0,d;for(d=0;d<a.length;d++)c|=a[d]^b[d];return 0===
c},$:function(a,b,c,d){var e;e=0;for(void 0===d&&(d=[]);32<=b;b-=32)d.push(c),c=0;if(0===b)return d.concat(a);for(e=0;e<a.length;e++)d.push(c|a[e]>>>b),c=a[e]<<32-b;e=a.length?a[a.length-1]:0;a=sjcl.bitArray.getPartial(e);d.push(sjcl.bitArray.partial(b+a&31,32<b+a?c:d.pop(),1));return d},i:function(a,b){return[a[0]^b[0],a[1]^b[1],a[2]^b[2],a[3]^b[3]]},byteswapM:function(a){var b,c;for(b=0;b<a.length;++b)c=a[b],a[b]=c>>>24|c>>>8&0xff00|(c&0xff00)<<8|c<<24;return a}};
sjcl.codec.utf8String={fromBits:function(a){var b="",c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d<c/8;d++)0===(d&3)&&(e=a[d/4]),b+=String.fromCharCode(e>>>24),e<<=8;return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],c,d=0;for(c=0;c<a.length;c++)d=d<<8|a.charCodeAt(c),3===(c&3)&&(b.push(d),d=0);c&3&&b.push(sjcl.bitArray.partial(8*(c&3),d));return b}};
sjcl.codec.hex={fromBits:function(a){var b="",c;for(c=0;c<a.length;c++)b+=((a[c]|0)+0xf00000000000).toString(16).substr(4);return b.substr(0,sjcl.bitArray.bitLength(a)/4)},toBits:function(a){var b,c=[],d;a=a.replace(/\s|0x/g,"");d=a.length;a=a+"00000000";for(b=0;b<a.length;b+=8)c.push(parseInt(a.substr(b,8),16)^0);return sjcl.bitArray.clamp(c,4*d)}};
sjcl.codec.base32={B:"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",X:"0123456789ABCDEFGHIJKLMNOPQRSTUV",BITS:32,BASE:5,REMAINING:27,fromBits:function(a,b,c){var d=sjcl.codec.base32.BASE,e=sjcl.codec.base32.REMAINING,f="",g=0,h=sjcl.codec.base32.B,k=0,l=sjcl.bitArray.bitLength(a);c&&(h=sjcl.codec.base32.X);for(c=0;f.length*d<l;)f+=h.charAt((k^a[c]>>>g)>>>e),g<d?(k=a[c]<<d-g,g+=e,c++):(k<<=d,g-=d);for(;f.length&7&&!b;)f+="=";return f},toBits:function(a,b){a=a.replace(/\s|=/g,"").toUpperCase();var c=sjcl.codec.base32.BITS,
d=sjcl.codec.base32.BASE,e=sjcl.codec.base32.REMAINING,f=[],g,h=0,k=sjcl.codec.base32.B,l=0,n,m="base32";b&&(k=sjcl.codec.base32.X,m="base32hex");for(g=0;g<a.length;g++){n=k.indexOf(a.charAt(g));if(0>n){if(!b)try{return sjcl.codec.base32hex.toBits(a)}catch(p){}throw new sjcl.exception.invalid("this isn't "+m+"!");}h>e?(h-=e,f.push(l^n>>>h),l=n<<c-h):(h+=d,l^=n<<c-h)}h&56&&f.push(sjcl.bitArray.partial(h&56,l,1));return f}};
sjcl.codec.base32hex={fromBits:function(a,b){return sjcl.codec.base32.fromBits(a,b,1)},toBits:function(a){return sjcl.codec.base32.toBits(a,1)}};
sjcl.codec.base64={B:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",fromBits:function(a,b,c){var d="",e=0,f=sjcl.codec.base64.B,g=0,h=sjcl.bitArray.bitLength(a);c&&(f=f.substr(0,62)+"-_");for(c=0;6*d.length<h;)d+=f.charAt((g^a[c]>>>e)>>>26),6>e?(g=a[c]<<6-e,e+=26,c++):(g<<=6,e-=6);for(;d.length&3&&!b;)d+="=";return d},toBits:function(a,b){a=a.replace(/\s|=/g,"");var c=[],d,e=0,f=sjcl.codec.base64.B,g=0,h;b&&(f=f.substr(0,62)+"-_");for(d=0;d<a.length;d++){h=f.indexOf(a.charAt(d));
if(0>h)throw new sjcl.exception.invalid("this isn't base64!");26<e?(e-=26,c.push(g^h>>>e),g=h<<32-e):(e+=6,g^=h<<32-e)}e&56&&c.push(sjcl.bitArray.partial(e&56,g,1));return c}};sjcl.codec.base64url={fromBits:function(a){return sjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){return sjcl.codec.base64.toBits(a,1)}};sjcl.hash.sha256=function(a){this.b[0]||this.O();a?(this.F=a.F.slice(0),this.A=a.A.slice(0),this.l=a.l):this.reset()};sjcl.hash.sha256.hash=function(a){return(new sjcl.hash.sha256).update(a).finalize()};
sjcl.hash.sha256.prototype={blockSize:512,reset:function(){this.F=this.Y.slice(0);this.A=[];this.l=0;return this},update:function(a){"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));var b,c=this.A=sjcl.bitArray.concat(this.A,a);b=this.l;a=this.l=b+sjcl.bitArray.bitLength(a);if(0x1fffffffffffff<a)throw new sjcl.exception.invalid("Cannot hash more than 2^53 - 1 bits");if("undefined"!==typeof Uint32Array){var d=new Uint32Array(c),e=0;for(b=512+b-(512+b&0x1ff);b<=a;b+=512)u(this,d.subarray(16*e,
16*(e+1))),e+=1;c.splice(0,16*e)}else for(b=512+b-(512+b&0x1ff);b<=a;b+=512)u(this,c.splice(0,16));return this},finalize:function(){var a,b=this.A,c=this.F,b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);b.push(Math.floor(this.l/0x100000000));for(b.push(this.l|0);b.length;)u(this,b.splice(0,16));this.reset();return c},Y:[],b:[],O:function(){function a(a){return 0x100000000*(a-Math.floor(a))|0}for(var b=0,c=2,d,e;64>b;c++){e=!0;for(d=2;d*d<=c;d++)if(0===c%d){e=
!1;break}e&&(8>b&&(this.Y[b]=a(Math.pow(c,.5))),this.b[b]=a(Math.pow(c,1/3)),b++)}}};
function u(a,b){var c,d,e,f=a.F,g=a.b,h=f[0],k=f[1],l=f[2],n=f[3],m=f[4],p=f[5],r=f[6],q=f[7];for(c=0;64>c;c++)16>c?d=b[c]:(d=b[c+1&15],e=b[c+14&15],d=b[c&15]=(d>>>7^d>>>18^d>>>3^d<<25^d<<14)+(e>>>17^e>>>19^e>>>10^e<<15^e<<13)+b[c&15]+b[c+9&15]|0),d=d+q+(m>>>6^m>>>11^m>>>25^m<<26^m<<21^m<<7)+(r^m&(p^r))+g[c],q=r,r=p,p=m,m=n+d|0,n=l,l=k,k=h,h=d+(k&l^n&(k^l))+(k>>>2^k>>>13^k>>>22^k<<30^k<<19^k<<10)|0;f[0]=f[0]+h|0;f[1]=f[1]+k|0;f[2]=f[2]+l|0;f[3]=f[3]+n|0;f[4]=f[4]+m|0;f[5]=f[5]+p|0;f[6]=f[6]+r|0;f[7]=
f[7]+q|0}
sjcl.mode.ccm={name:"ccm",G:[],listenProgress:function(a){sjcl.mode.ccm.G.push(a)},unListenProgress:function(a){a=sjcl.mode.ccm.G.indexOf(a);-1<a&&sjcl.mode.ccm.G.splice(a,1)},fa:function(a){var b=sjcl.mode.ccm.G.slice(),c;for(c=0;c<b.length;c+=1)b[c](a)},encrypt:function(a,b,c,d,e){var f,g=b.slice(0),h=sjcl.bitArray,k=h.bitLength(c)/8,l=h.bitLength(g)/8;e=e||64;d=d||[];if(7>k)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(f=2;4>f&&l>>>8*f;f++);f<15-k&&(f=15-k);c=h.clamp(c,
8*(15-f));b=sjcl.mode.ccm.V(a,b,c,d,e,f);g=sjcl.mode.ccm.C(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),k=f.clamp(b,h-e),l=f.bitSlice(b,h-e),h=(h-e)/8;if(7>g)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(b=2;4>b&&h>>>8*b;b++);b<15-g&&(b=15-g);c=f.clamp(c,8*(15-b));k=sjcl.mode.ccm.C(a,k,c,l,e,b);a=sjcl.mode.ccm.V(a,k.data,c,d,e,b);if(!f.equal(k.tag,a))throw new sjcl.exception.corrupt("ccm: tag doesn't match");
return k.data},na:function(a,b,c,d,e,f){var g=[],h=sjcl.bitArray,k=h.i;d=[h.partial(8,(b.length?64:0)|d-2<<2|f-1)];d=h.concat(d,c);d[3]|=e;d=a.encrypt(d);if(b.length)for(c=h.bitLength(b)/8,65279>=c?g=[h.partial(16,c)]:0xffffffff>=c&&(g=h.concat([h.partial(16,65534)],[c])),g=h.concat(g,b),b=0;b<g.length;b+=4)d=a.encrypt(k(d,g.slice(b,b+4).concat([0,0,0])));return d},V:function(a,b,c,d,e,f){var g=sjcl.bitArray,h=g.i;e/=8;if(e%2||4>e||16<e)throw new sjcl.exception.invalid("ccm: invalid tag length");
if(0xffffffff<d.length||0xffffffff<b.length)throw new sjcl.exception.bug("ccm: can't deal with 4GiB or more data");c=sjcl.mode.ccm.na(a,d,c,e,g.bitLength(b)/8,f);for(d=0;d<b.length;d+=4)c=a.encrypt(h(c,b.slice(d,d+4).concat([0,0,0])));return g.clamp(c,8*e)},C:function(a,b,c,d,e,f){var g,h=sjcl.bitArray;g=h.i;var k=b.length,l=h.bitLength(b),n=k/50,m=n;c=h.concat([h.partial(8,f-1)],c).concat([0,0,0]).slice(0,4);d=h.bitSlice(g(d,a.encrypt(c)),0,e);if(!k)return{tag:d,data:[]};for(g=0;g<k;g+=4)g>n&&(sjcl.mode.ccm.fa(g/
k),n+=m),c[3]++,e=a.encrypt(c),b[g]^=e[0],b[g+1]^=e[1],b[g+2]^=e[2],b[g+3]^=e[3];return{tag:d,data:h.clamp(b,l)}}};
sjcl.mode.ocb2={name:"ocb2",encrypt:function(a,b,c,d,e,f){if(128!==sjcl.bitArray.bitLength(c))throw new sjcl.exception.invalid("ocb iv must be 128 bits");var g,h=sjcl.mode.ocb2.S,k=sjcl.bitArray,l=k.i,n=[0,0,0,0];c=h(a.encrypt(c));var m,p=[];d=d||[];e=e||64;for(g=0;g+4<b.length;g+=4)m=b.slice(g,g+4),n=l(n,m),p=p.concat(l(c,a.encrypt(l(c,m)))),c=h(c);m=b.slice(g);b=k.bitLength(m);g=a.encrypt(l(c,[0,0,0,b]));m=k.clamp(l(m.concat([0,0,0]),g),b);n=l(n,l(m.concat([0,0,0]),g));n=a.encrypt(l(n,l(c,h(c))));
d.length&&(n=l(n,f?d:sjcl.mode.ocb2.pmac(a,d)));return p.concat(k.concat(m,k.clamp(n,e)))},decrypt:function(a,b,c,d,e,f){if(128!==sjcl.bitArray.bitLength(c))throw new sjcl.exception.invalid("ocb iv must be 128 bits");e=e||64;var g=sjcl.mode.ocb2.S,h=sjcl.bitArray,k=h.i,l=[0,0,0,0],n=g(a.encrypt(c)),m,p,r=sjcl.bitArray.bitLength(b)-e,q=[];d=d||[];for(c=0;c+4<r/32;c+=4)m=k(n,a.decrypt(k(n,b.slice(c,c+4)))),l=k(l,m),q=q.concat(m),n=g(n);p=r-32*c;m=a.encrypt(k(n,[0,0,0,p]));m=k(m,h.clamp(b.slice(c),p).concat([0,
0,0]));l=k(l,m);l=a.encrypt(k(l,k(n,g(n))));d.length&&(l=k(l,f?d:sjcl.mode.ocb2.pmac(a,d)));if(!h.equal(h.clamp(l,e),h.bitSlice(b,r)))throw new sjcl.exception.corrupt("ocb: tag doesn't match");return q.concat(h.clamp(m,p))},pmac:function(a,b){var c,d=sjcl.mode.ocb2.S,e=sjcl.bitArray,f=e.i,g=[0,0,0,0],h=a.encrypt([0,0,0,0]),h=f(h,d(d(h)));for(c=0;c+4<b.length;c+=4)h=d(h),g=f(g,a.encrypt(f(h,b.slice(c,c+4))));c=b.slice(c);128>e.bitLength(c)&&(h=f(h,d(h)),c=e.concat(c,[-2147483648,0,0,0]));g=f(g,c);
return a.encrypt(f(d(f(h,d(h))),g))},S:function(a){return[a[0]<<1^a[1]>>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^135*(a[0]>>>31)]}};
sjcl.mode.gcm={name:"gcm",encrypt:function(a,b,c,d,e){var f=b.slice(0);b=sjcl.bitArray;d=d||[];a=sjcl.mode.gcm.C(!0,a,f,d,c,e||128);return b.concat(a.data,a.tag)},decrypt:function(a,b,c,d,e){var f=b.slice(0),g=sjcl.bitArray,h=g.bitLength(f);e=e||128;d=d||[];e<=h?(b=g.bitSlice(f,h-e),f=g.bitSlice(f,0,h-e)):(b=f,f=[]);a=sjcl.mode.gcm.C(!1,a,f,d,c,e);if(!g.equal(a.tag,b))throw new sjcl.exception.corrupt("gcm: tag doesn't match");return a.data},ka:function(a,b){var c,d,e,f,g,h=sjcl.bitArray.i;e=[0,0,
0,0];f=b.slice(0);for(c=0;128>c;c++){(d=0!==(a[Math.floor(c/32)]&1<<31-c%32))&&(e=h(e,f));g=0!==(f[3]&1);for(d=3;0<d;d--)f[d]=f[d]>>>1|(f[d-1]&1)<<31;f[0]>>>=1;g&&(f[0]^=-0x1f000000)}return e},j:function(a,b,c){var d,e=c.length;b=b.slice(0);for(d=0;d<e;d+=4)b[0]^=0xffffffff&c[d],b[1]^=0xffffffff&c[d+1],b[2]^=0xffffffff&c[d+2],b[3]^=0xffffffff&c[d+3],b=sjcl.mode.gcm.ka(b,a);return b},C:function(a,b,c,d,e,f){var g,h,k,l,n,m,p,r,q=sjcl.bitArray;m=c.length;p=q.bitLength(c);r=q.bitLength(d);h=q.bitLength(e);
g=b.encrypt([0,0,0,0]);96===h?(e=e.slice(0),e=q.concat(e,[1])):(e=sjcl.mode.gcm.j(g,[0,0,0,0],e),e=sjcl.mode.gcm.j(g,e,[0,0,Math.floor(h/0x100000000),h&0xffffffff]));h=sjcl.mode.gcm.j(g,[0,0,0,0],d);n=e.slice(0);d=h.slice(0);a||(d=sjcl.mode.gcm.j(g,h,c));for(l=0;l<m;l+=4)n[3]++,k=b.encrypt(n),c[l]^=k[0],c[l+1]^=k[1],c[l+2]^=k[2],c[l+3]^=k[3];c=q.clamp(c,p);a&&(d=sjcl.mode.gcm.j(g,h,c));a=[Math.floor(r/0x100000000),r&0xffffffff,Math.floor(p/0x100000000),p&0xffffffff];d=sjcl.mode.gcm.j(g,d,a);k=b.encrypt(e);
d[0]^=k[0];d[1]^=k[1];d[2]^=k[2];d[3]^=k[3];return{tag:q.bitSlice(d,0,f),data:c}}};sjcl.misc.hmac=function(a,b){this.W=b=b||sjcl.hash.sha256;var c=[[],[]],d,e=b.prototype.blockSize/32;this.w=[new b,new b];a.length>e&&(a=b.hash(a));for(d=0;d<e;d++)c[0][d]=a[d]^909522486,c[1][d]=a[d]^1549556828;this.w[0].update(c[0]);this.w[1].update(c[1]);this.R=new b(this.w[0])};
sjcl.misc.hmac.prototype.encrypt=sjcl.misc.hmac.prototype.mac=function(a){if(this.aa)throw new sjcl.exception.invalid("encrypt on already updated hmac called!");this.update(a);return this.digest(a)};sjcl.misc.hmac.prototype.reset=function(){this.R=new this.W(this.w[0]);this.aa=!1};sjcl.misc.hmac.prototype.update=function(a){this.aa=!0;this.R.update(a)};sjcl.misc.hmac.prototype.digest=function(){var a=this.R.finalize(),a=(new this.W(this.w[1])).update(a).finalize();this.reset();return a};
sjcl.misc.pbkdf2=function(a,b,c,d,e){c=c||1E4;if(0>d||0>c)throw new sjcl.exception.invalid("invalid params to pbkdf2");"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,k,l=[],n=sjcl.bitArray;for(k=1;32*l.length<(d||1);k++){e=f=a.encrypt(n.concat(b,[k]));for(g=1;g<c;g++)for(f=a.encrypt(f),h=0;h<f.length;h++)e[h]^=f[h];l=l.concat(e)}d&&(l=n.clamp(l,d));return l};
sjcl.prng=function(a){this.c=[new sjcl.hash.sha256];this.m=[0];this.P=0;this.H={};this.N=0;this.U={};this.Z=this.f=this.o=this.ha=0;this.b=[0,0,0,0,0,0,0,0];this.h=[0,0,0,0];this.L=void 0;this.M=a;this.D=!1;this.K={progress:{},seeded:{}};this.u=this.ga=0;this.I=1;this.J=2;this.ca=0x10000;this.T=[0,48,64,96,128,192,0x100,384,512,768,1024];this.da=3E4;this.ba=80};
sjcl.prng.prototype={randomWords:function(a,b){var c=[],d;d=this.isReady(b);var e;if(d===this.u)throw new sjcl.exception.notReady("generator isn't seeded");if(d&this.J){d=!(d&this.I);e=[];var f=0,g;this.Z=e[0]=(new Date).valueOf()+this.da;for(g=0;16>g;g++)e.push(0x100000000*Math.random()|0);for(g=0;g<this.c.length&&(e=e.concat(this.c[g].finalize()),f+=this.m[g],this.m[g]=0,d||!(this.P&1<<g));g++);this.P>=1<<this.c.length&&(this.c.push(new sjcl.hash.sha256),this.m.push(0));this.f-=f;f>this.o&&(this.o=
f);this.P++;this.b=sjcl.hash.sha256.hash(this.b.concat(e));this.L=new sjcl.cipher.aes(this.b);for(d=0;4>d&&(this.h[d]=this.h[d]+1|0,!this.h[d]);d++);}for(d=0;d<a;d+=4)0===(d+1)%this.ca&&y(this),e=z(this),c.push(e[0],e[1],e[2],e[3]);y(this);return c.slice(0,a)},setDefaultParanoia:function(a,b){if(0===a&&"Setting paranoia=0 will ruin your security; use it only for testing"!==b)throw new sjcl.exception.invalid("Setting paranoia=0 will ruin your security; use it only for testing");this.M=a},addEntropy:function(a,
b,c){c=c||"user";var d,e,f=(new Date).valueOf(),g=this.H[c],h=this.isReady(),k=0;d=this.U[c];void 0===d&&(d=this.U[c]=this.ha++);void 0===g&&(g=this.H[c]=0);this.H[c]=(this.H[c]+1)%this.c.length;switch(typeof a){case "number":void 0===b&&(b=1);this.c[g].update([d,this.N++,1,b,f,1,a|0]);break;case "object":c=Object.prototype.toString.call(a);if("[object Uint32Array]"===c){e=[];for(c=0;c<a.length;c++)e.push(a[c]);a=e}else for("[object Array]"!==c&&(k=1),c=0;c<a.length&&!k;c++)"number"!==typeof a[c]&&
(k=1);if(!k){if(void 0===b)for(c=b=0;c<a.length;c++)for(e=a[c];0<e;)b++,e=e>>>1;this.c[g].update([d,this.N++,2,b,f,a.length].concat(a))}break;case "string":void 0===b&&(b=a.length);this.c[g].update([d,this.N++,3,b,f,a.length]);this.c[g].update(a);break;default:k=1}if(k)throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string");this.m[g]+=b;this.f+=b;h===this.u&&(this.isReady()!==this.u&&A("seeded",Math.max(this.o,this.f)),A("progress",this.getProgress()))},
isReady:function(a){a=this.T[void 0!==a?a:this.M];return this.o&&this.o>=a?this.m[0]>this.ba&&(new Date).valueOf()>this.Z?this.J|this.I:this.I:this.f>=a?this.J|this.u:this.u},getProgress:function(a){a=this.T[a?a:this.M];return this.o>=a?1:this.f>a?1:this.f/a},startCollectors:function(){if(!this.D){this.a={loadTimeCollector:B(this,this.ma),mouseCollector:B(this,this.oa),keyboardCollector:B(this,this.la),accelerometerCollector:B(this,this.ea),touchCollector:B(this,this.qa)};if(window.addEventListener)window.addEventListener("load",
this.a.loadTimeCollector,!1),window.addEventListener("mousemove",this.a.mouseCollector,!1),window.addEventListener("keypress",this.a.keyboardCollector,!1),window.addEventListener("devicemotion",this.a.accelerometerCollector,!1),window.addEventListener("touchmove",this.a.touchCollector,!1);else if(document.attachEvent)document.attachEvent("onload",this.a.loadTimeCollector),document.attachEvent("onmousemove",this.a.mouseCollector),document.attachEvent("keypress",this.a.keyboardCollector);else throw new sjcl.exception.bug("can't attach event");
this.D=!0}},stopCollectors:function(){this.D&&(window.removeEventListener?(window.removeEventListener("load",this.a.loadTimeCollector,!1),window.removeEventListener("mousemove",this.a.mouseCollector,!1),window.removeEventListener("keypress",this.a.keyboardCollector,!1),window.removeEventListener("devicemotion",this.a.accelerometerCollector,!1),window.removeEventListener("touchmove",this.a.touchCollector,!1)):document.detachEvent&&(document.detachEvent("onload",this.a.loadTimeCollector),document.detachEvent("onmousemove",
this.a.mouseCollector),document.detachEvent("keypress",this.a.keyboardCollector)),this.D=!1)},addEventListener:function(a,b){this.K[a][this.ga++]=b},removeEventListener:function(a,b){var c,d,e=this.K[a],f=[];for(d in e)e.hasOwnProperty(d)&&e[d]===b&&f.push(d);for(c=0;c<f.length;c++)d=f[c],delete e[d]},la:function(){C(this,1)},oa:function(a){var b,c;try{b=a.x||a.clientX||a.offsetX||0,c=a.y||a.clientY||a.offsetY||0}catch(d){c=b=0}0!=b&&0!=c&&this.addEntropy([b,c],2,"mouse");C(this,0)},qa:function(a){a=
a.touches[0]||a.changedTouches[0];this.addEntropy([a.pageX||a.clientX,a.pageY||a.clientY],1,"touch");C(this,0)},ma:function(){C(this,2)},ea:function(a){a=a.accelerationIncludingGravity.x||a.accelerationIncludingGravity.y||a.accelerationIncludingGravity.z;if(window.orientation){var b=window.orientation;"number"===typeof b&&this.addEntropy(b,1,"accelerometer")}a&&this.addEntropy(a,2,"accelerometer");C(this,0)}};
function A(a,b){var c,d=sjcl.random.K[a],e=[];for(c in d)d.hasOwnProperty(c)&&e.push(d[c]);for(c=0;c<e.length;c++)e[c](b)}function C(a,b){"undefined"!==typeof window&&window.performance&&"function"===typeof window.performance.now?a.addEntropy(window.performance.now(),b,"loadtime"):a.addEntropy((new Date).valueOf(),b,"loadtime")}function y(a){a.b=z(a).concat(z(a));a.L=new sjcl.cipher.aes(a.b)}function z(a){for(var b=0;4>b&&(a.h[b]=a.h[b]+1|0,!a.h[b]);b++);return a.L.encrypt(a.h)}
function B(a,b){return function(){b.apply(a,arguments)}}sjcl.random=new sjcl.prng(6);
a:try{var D,E,F,G;if(G="undefined"!==typeof module&&module.exports){var H;try{H=require("crypto")}catch(a){H=null}G=E=H}if(G&&E.randomBytes)D=E.randomBytes(128),D=new Uint32Array((new Uint8Array(D)).buffer),sjcl.random.addEntropy(D,1024,"crypto['randomBytes']");else if("undefined"!==typeof window&&"undefined"!==typeof Uint32Array){F=new Uint32Array(32);if(window.crypto&&window.crypto.getRandomValues)window.crypto.getRandomValues(F);else if(window.msCrypto&&window.msCrypto.getRandomValues)window.msCrypto.getRandomValues(F);
else break a;sjcl.random.addEntropy(F,1024,"crypto['getRandomValues']")}}catch(a){"undefined"!==typeof window&&window.console&&(console.log("There was an error collecting entropy from the browser:"),console.log(a))}
sjcl.json={defaults:{v:1,iter:1E4,ks:128,ts:64,mode:"ccm",adata:"",cipher:"aes"},ja:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json,f=e.g({iv:sjcl.random.randomWords(4,0)},e.defaults),g;e.g(f,c);c=f.adata;"string"===typeof f.salt&&(f.salt=sjcl.codec.base64.toBits(f.salt));"string"===typeof f.iv&&(f.iv=sjcl.codec.base64.toBits(f.iv));if(!sjcl.mode[f.mode]||!sjcl.cipher[f.cipher]||"string"===typeof a&&100>=f.iter||64!==f.ts&&96!==f.ts&&128!==f.ts||128!==f.ks&&192!==f.ks&&0x100!==f.ks||2>f.iv.length||
4<f.iv.length)throw new sjcl.exception.invalid("json encrypt: invalid parameters");"string"===typeof a?(g=sjcl.misc.cachedPbkdf2(a,f),a=g.key.slice(0,f.ks/32),f.salt=g.salt):sjcl.ecc&&a instanceof sjcl.ecc.elGamal.publicKey&&(g=a.kem(),f.kemtag=g.tag,a=g.key.slice(0,f.ks/32));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));"string"===typeof c&&(f.adata=c=sjcl.codec.utf8String.toBits(c));g=new sjcl.cipher[f.cipher](a);e.g(d,f);d.key=a;f.ct="ccm"===f.mode&&sjcl.arrayBuffer&&sjcl.arrayBuffer.ccm&&
b instanceof ArrayBuffer?sjcl.arrayBuffer.ccm.encrypt(g,b,f.iv,c,f.ts):sjcl.mode[f.mode].encrypt(g,b,f.iv,c,f.ts);return f},encrypt:function(a,b,c,d){var e=sjcl.json,f=e.ja.apply(e,arguments);return e.encode(f)},ia:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json;b=e.g(e.g(e.g({},e.defaults),b),c,!0);var f,g;f=b.adata;"string"===typeof b.salt&&(b.salt=sjcl.codec.base64.toBits(b.salt));"string"===typeof b.iv&&(b.iv=sjcl.codec.base64.toBits(b.iv));if(!sjcl.mode[b.mode]||!sjcl.cipher[b.cipher]||"string"===
typeof a&&100>=b.iter||64!==b.ts&&96!==b.ts&&128!==b.ts||128!==b.ks&&192!==b.ks&&0x100!==b.ks||!b.iv||2>b.iv.length||4<b.iv.length)throw new sjcl.exception.invalid("json decrypt: invalid parameters");"string"===typeof a?(g=sjcl.misc.cachedPbkdf2(a,b),a=g.key.slice(0,b.ks/32),b.salt=g.salt):sjcl.ecc&&a instanceof sjcl.ecc.elGamal.secretKey&&(a=a.unkem(sjcl.codec.base64.toBits(b.kemtag)).slice(0,b.ks/32));"string"===typeof f&&(f=sjcl.codec.utf8String.toBits(f));g=new sjcl.cipher[b.cipher](a);f="ccm"===
b.mode&&sjcl.arrayBuffer&&sjcl.arrayBuffer.ccm&&b.ct instanceof ArrayBuffer?sjcl.arrayBuffer.ccm.decrypt(g,b.ct,b.iv,b.tag,f,b.ts):sjcl.mode[b.mode].decrypt(g,b.ct,b.iv,f,b.ts);e.g(d,b);d.key=a;return 1===c.raw?f:sjcl.codec.utf8String.fromBits(f)},decrypt:function(a,b,c,d){var e=sjcl.json;return e.ia(a,e.decode(b),c,d)},encode:function(a){var b,c="{",d="";for(b in a)if(a.hasOwnProperty(b)){if(!b.match(/^[a-z0-9]+$/i))throw new sjcl.exception.invalid("json encode: invalid property name");c+=d+'"'+
b+'":';d=",";switch(typeof a[b]){case "number":case "boolean":c+=a[b];break;case "string":c+='"'+escape(a[b])+'"';break;case "object":c+='"'+sjcl.codec.base64.fromBits(a[b],0)+'"';break;default:throw new sjcl.exception.bug("json encode: unsupported type");}}return c+"}"},decode:function(a){a=a.replace(/\s/g,"");if(!a.match(/^\{.*\}$/))throw new sjcl.exception.invalid("json decode: this isn't json!");a=a.replace(/^\{|\}$/g,"").split(/,/);var b={},c,d;for(c=0;c<a.length;c++){if(!(d=a[c].match(/^\s*(?:(["']?)([a-z][a-z0-9]*)\1)\s*:\s*(?:(-?\d+)|"([a-z0-9+\/%*_.@=\-]*)"|(true|false))$/i)))throw new sjcl.exception.invalid("json decode: this isn't json!");
null!=d[3]?b[d[2]]=parseInt(d[3],10):null!=d[4]?b[d[2]]=d[2].match(/^(ct|adata|salt|iv)$/)?sjcl.codec.base64.toBits(d[4]):unescape(d[4]):null!=d[5]&&(b[d[2]]="true"===d[5])}return b},g:function(a,b,c){void 0===a&&(a={});if(void 0===b)return a;for(var d in b)if(b.hasOwnProperty(d)){if(c&&void 0!==a[d]&&a[d]!==b[d])throw new sjcl.exception.invalid("required parameter overridden");a[d]=b[d]}return a},sa:function(a,b){var c={},d;for(d in a)a.hasOwnProperty(d)&&a[d]!==b[d]&&(c[d]=a[d]);return c},ra:function(a,
b){var c={},d;for(d=0;d<b.length;d++)void 0!==a[b[d]]&&(c[b[d]]=a[b[d]]);return c}};sjcl.encrypt=sjcl.json.encrypt;sjcl.decrypt=sjcl.json.decrypt;sjcl.misc.pa={};sjcl.misc.cachedPbkdf2=function(a,b){var c=sjcl.misc.pa,d;b=b||{};d=b.iter||1E3;c=c[a]=c[a]||{};d=c[d]=c[d]||{firstSalt:b.salt&&b.salt.length?b.salt.slice(0):sjcl.random.randomWords(2,0)};c=void 0===b.salt?d.firstSalt:b.salt;d[c]=d[c]||sjcl.misc.pbkdf2(a,c,b.iter);return{key:d[c].slice(0),salt:c.slice(0)}};
"undefined"!==typeof module&&module.exports&&(module.exports=sjcl);"function"===typeof define&&define([],function(){return sjcl});

window.sjcl = sjcl;
//}}}
//{{{
// make plugin work with MainTiddlyServer and TW 2.8.1+
config.options.chkAvoidGranulatedSaving = true;

config.shadowTiddlers.SideBarOptions = config.shadowTiddlers.SideBarOptions.replace(
	/<<saveChanges>>/, "<<unlock>><<setPassword>><<saveChanges>>");
config.shadowTiddlers.GettingStarted +=
	"\n\n<<ifLocked 'This ~TiddlyWiki uses EncryptionPlugin. " +
	"To load protected content click on'>><<unlock>>" +
	"<<ifUnlocked 'This ~TiddlyWiki uses EncryptionPlugin. " +
	"To set or change password click on'>><<setPassword>>";

merge(config.messages, {
	vaultCreationInfo: "The encrypted vault has been created",
	passwordSet: "🔒 Successfully set password",
	passwordUnset: "🔓 Successfully unset password",
	purgeConfirm: "Purge the encrypted vault ?\n\nAll unlocked content will be lost.",
	vaultPurgedInfo: "All contents have been purged from encrypted vault.\nPassword has been blanked.\nYou must save once to apply this changes.",
	vaultEncryptedInfo: "Saving with encryption",
	vaultUnchangedInfo: "No changes in Encrypted vault",
	noLockedVaultNoPurge: "No locked encrypted vault, nothing to purge.",
	emptyVaultInfo: "Saving without encryption",
	saveWithLockedVaultConfirm: "Encrypted vault is locked. No changes will apply inside.\n\nAre you sure ?",
	confirmOverload: "This following tiddler already exists in system store. Overload ?\nOK : the encrypted version will replace the system store version\nCancel : the system store version will replace the encrypted version"
});

config.extensions = config.extensions || {}
config.extensions.vault = {
	// TODO: encapsulate sjcl from global context?
	callSjcl: function(method, inputText, password) {
		if(!password) return

		try {
			var outputText = window.sjcl[method](password, inputText)
		} catch(ex) {
			console.log("Crypto error: " + ex)
			return null
		}
		return outputText
	},
	// this constant string allows to distinguish whether some content
	// is encrypted with the algorithm used here
	// TODO: for updating the plugin in some TWs, detect old prefix (Cryptomx@) and warn
	prefix: "Sjcl@",
	encrypt: function(src, password) {
		if(!password) return src
		return this.prefix + this.callSjcl("encrypt", src, password)
	},
	// if a wrong password is used, returns src as is
	decrypt: function(src, password) {
		var res = this.callSjcl("decrypt", src.substr(this.prefix.length), password)
		return res === null ? src : res
	},
	isEncrypted: function(src) {
		return src.substr(0, this.prefix.length) == this.prefix
	},

	// these should not be found by indexOf() of this source;
	// as < is encoded as &lt;, this won't happen anyway
	vaultAreaId: 'vaultArea',
	startSaveVaultArea: '<div id="vaultArea">',
	endSaveVaultArea: '</div>',
	postVaultAreaMarker: '<!--POST-VAULTAREA-->',

	// adapted from locateStoreArea
	locateVaultArea: function(original) {
		if(!original) return null

		// the vaultArea div should be just before the storeArea div
		var posOpeningDiv = original.indexOf(this.startSaveVaultArea)
		var limitClosingDiv = original.indexOf(this.postVaultAreaMarker)
		// startSaveArea is globally available (should be deprecated though)
		if(limitClosingDiv == -1)
			limitClosingDiv = original.indexOf(startSaveArea)
		var posClosingDiv = original.lastIndexOf(this.endSaveVaultArea, limitClosingDiv)

		return (posOpeningDiv == -1 || posClosingDiv == -1) ? null :
			[posOpeningDiv, posClosingDiv];
	},

	// implementing in-tiddler vault
	singleVaultTiddlerName: "EncryptedVault",
	updateVaultTiddler: function(encryptedContentOrNull) {
		if(encryptedContentOrNull === null) {
			// TODO: ask for confirmation? make undo-able?
			store.deleteTiddler(this.singleVaultTiddlerName)
			return
		}

		var encryptedContent = encryptedContentOrNull
		var vaultTiddler = store.fetchTiddler(this.singleVaultTiddlerName) // fetch existing or create
		if(!vaultTiddler) {
			vaultTiddler = new Tiddler(this.singleVaultTiddlerName)
			vaultTiddler.tags.push(this.tagDontEncrypt)
			store.addTiddler(vaultTiddler) // doesn't setDirty, unlike createTiddler
		}
		vaultTiddler.text = encryptedContent
		vaultTiddler.modified = new Date()
		// TODO: update modifier? (see core methods that update the fields) something else?
	},
	getVaultTiddlerContent: function() {
		var vaultTiddler = store.fetchTiddler(this.singleVaultTiddlerName)
		return vaultTiddler ? vaultTiddler.text : null
		// same, but returning null is implicit: return store.getTiddlerText(this.singleVaultTiddlerName)
	},

	tagDontEncrypt: "unencrypted",
	tagForceEncrypt: "forceEncryption",
	getUnencryptedArray: function() {
		var unencryptedList = store.fetchTiddler("ListUnencrypted")
		return !unencryptedList ? [] :
			store.filterTiddlers(unencryptedList.text)
	},
	// this is used to avoid quadratic complexity (filtering N tiddlers per each N tiddlers)
	unencryptedCacheMap: null,
	populateUnencryptedCacheMap: function() {
		var unencryptedArray = this.getUnencryptedArray()
		this.unencryptedCacheMap = {}
		for(var i = 0; i < unencryptedArray.length; i++) {
			var title = unencryptedArray[i].title
			this.unencryptedCacheMap[title] = true
		}
	},
	clearnUnencryptedCacheMap: function() {
		this.unencryptedCacheMap = null
	},
	shouldEncryptTiddler: function(tiddler) {
		if(tiddler.isTagged(this.tagForceEncrypt)) return true

		if(store.isShadowTiddler([tiddler.title])
		   || tiddler.title === "ListUnencrypted"
		   || tiddler.isTagged("systemConfig")
		   || tiddler.isTagged(this.tagDontEncrypt)
		) return false

		if(this.unencryptedCacheMap) {
			return !this.unencryptedCacheMap[tiddler.title]
		} else {
			var unencryptedArray = this.getUnencryptedArray()
			if(unencryptedArray.indexOf(tiddler) !== -1) return false
			/*var unencryptedList = store.fetchTiddler("ListUnencrypted")
			if(unencryptedList) {
				var filter = unencryptedList.text
				var tids = store.filterTiddlers(filter)
				if(tids.indexOf(tiddler) !== -1) return false
			}*/
		}

		return true
	},

	// TODO: review terms (locked, loaded, ..) – should be consistent
	getVaultContent: function() {
		var inTiddlerContent = this.getVaultTiddlerContent()
		if(inTiddlerContent) return inTiddlerContent

		// backward compatibility with 1.x
		var el = document.getElementById(this.vaultAreaId)
		return el ? el.innerHTML : null
	},
	// TODO: remove state; may be move some sections above to ~submodules instead
	// loaded: falsy by default (we don't set it so that installing twice won't hurt)
	isLocked: function() {
		if(this.loaded) return false
		var vaultContent = this.getVaultContent()
		return vaultContent === null || this.isEncrypted(vaultContent)
	},
	existsAndIsLocked: function() {
		return this.getVaultContent() !== null &&
			this.isLocked()
	},
	// TODO: fix lingo (missing, prompt); review
	// returns a boolean indicating success
	load: function() {
		if (!this.existsAndIsLocked()) {
			// vaultAlreadyUnlockedWarning is missing even in the original plugin!
			alert(config.messages.vaultAlreadyUnlockedWarning);
			return false;
		}

		var vaultContent = this.getVaultContent()
		if(vaultContent === null) return false

		var pwd = this.password || "";
		while(this.isEncrypted(vaultContent) && (pwd != null)) {
			if(pwd) vaultContent = this.decrypt(vaultContent, pwd);
			if(this.isEncrypted(vaultContent))
				pwd = prompt("Enter a password", pwd);
		}
		if(pwd != null) this.password = pwd;
		if(this.isEncrypted(vaultContent)) return false;

		var wasDirty = store.isDirty();
		if(vaultContent) {
			var e = document.createElement("div");
			e.innerHTML = vaultContent;
			store.getLoader().loadTiddlers(store, e.childNodes);
		}
		this.loaded = true;
		refreshAll();
		story.refreshAllTiddlers();
		store.setDirty(wasDirty);
		return true
	},

	// TODO: expose password setter, but hide direct access to password, if possible
	// password: falsy by default

	// TODO: can we implement a method "purge" instead? review current logic:
	// seems to have multiple flaws (one is: it's never restored to false!)
	// Make sure installing twice won't hurt
	shouldPurge: false,

	// save for decorating; avoid problems if this is installed twice
	originals: config.extensions.vault ? config.extensions.vault.originals : {
		updateOriginal: updateOriginal,
		LoaderBase_loadTiddler: LoaderBase.prototype.loadTiddler,
		saveChanges: saveChanges,
		Tiddler_doNotSave: Tiddler.prototype.doNotSave
	},
	doNotSaveMode: 'encrypted'
}

// decorate
Tiddler.prototype.doNotSave = function() {
	var shouldEncrypt = config.extensions.vault.shouldEncryptTiddler(this)
	var mode = config.extensions.vault.doNotSaveMode
	if((shouldEncrypt && mode == "encrypted" || !shouldEncrypt && mode == "unencrypted") &&
	   config.extensions.vault.password) return true
	return config.extensions.vault.originals.Tiddler_doNotSave.apply(this, arguments)
}

TiddlyWiki.prototype.allEncryptedTiddlersAsHtml = function() {
	var prevMode = config.extensions.vault.doNotSaveMode
	config.extensions.vault.doNotSaveMode = "unencrypted"

	var result = this.allTiddlersAsHtml()

	config.extensions.vault.doNotSaveMode = prevMode
	return result
}

// TODO: review all decorations; may be move (encapsulate) some bits to ceVault methods
// decorate
window.updateOriginal = function(original, posDiv) {
	var ceVault = config.extensions.vault
	var vaultIsUpdatable = !ceVault.locateVaultArea(original) ||
		!ceVault.existsAndIsLocked(true) || ceVault.shouldPurge

	ceVault.populateUnencryptedCacheMap()

	var password = ceVault.password
	ceVault.updateVaultTiddler(!password ? null : ceVault.encrypt(store.allEncryptedTiddlersAsHtml(), password))

	var revised = ceVault.originals.updateOriginal.apply(this, arguments)
	//# move reporting results outside updateOriginal?
	if(vaultIsUpdatable) {
		displayMessage(config.messages[password ? 'vaultEncryptedInfo' : 'emptyVaultInfo'])
	} else
		displayMessage(config.messages.vaultUnchangedInfo)

	ceVault.clearnUnencryptedCacheMap()

	return revised
}

// decorate
LoaderBase.prototype.loadTiddler = function(store, node, tiddlers) {
	var title = this.getTitle(store, node);
	if(store.getTiddler(title) && !confirm(config.messages.confirmOverload +"\n\n"+ title))
		return;
	return config.extensions.vault.originals.LoaderBase_loadTiddler.apply(this, arguments)
}

// decorate
window.saveChanges = function(onlyIfDirty, tiddlers) {
	var ceVault = config.extensions.vault
	if(ceVault.shouldPurge || !ceVault.existsAndIsLocked() ||
	   confirm(config.messages.saveWithLockedVaultConfirm))
		ceVault.originals.saveChanges.apply(this, arguments);
}

var shadowName = "StyleSheetVault"
if(!config.shadowTiddlers[shadowName]) {
	config.shadowTiddlers[shadowName] = 'input { max-width: 100%; }'
	store.addNotification(shadowName, refreshStyles)
	store.addNotification("ColorPalette", function(smth, doc) { refreshStyles(shadowName, doc) })
}

// TODO: move defaults to lingo
config.macros.unlock = {
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		var form = createTiddlyElement(place, 'form')
		jQuery(form).attr({ refresh: "macro", macroName: macroName }).data({
			label:  	params[0] || "unlock vault",
			tooltip:	params[1] || "unlock encrypted vault",
			openTiddlers:	params[2] || "",
			closeTiddlers:	params[3] || "",
		})
		this.refresh(form)
	},
	refresh: function(form) {
		var params = jQuery(form).data()
		jQuery(form).empty()
		var macro = this
		var ceVault = config.extensions.vault

		//# or may be show something more helpful
		if(!ceVault.existsAndIsLocked()) return;

		var input = createTiddlyElement(form, 'input', null, null, null, {
			type: 'password'
		})
		input.focus()

		jQuery(input).on('keydown', function(event) {
			if(event.key !== 'Enter') return
			macro.unlockAndOpen(input.value,
				params.openTiddlers, params.closeTiddlers)
			return false
		})
		// TODO: explain they can type and press "enter"

		createTiddlyButton(form, params.label, params.tooltip, function() {
			macro.unlockAndOpen(input.value,
				params.openTiddlers, params.closeTiddlers)
			return false
		})
	},
	unlockAndOpen: function(newPassword, openTiddlersFilter, closeTiddlersFilter) {
		var ceVault = config.extensions.vault
		if(newPassword) ceVault.password = newPassword

		if(ceVault.load()) {
			if(closeTiddlersFilter) {
				var tiddlers = store.filterTiddlers(closeTiddlersFilter)
				for(var i = 0; i < tiddlers.length; i++) {
					if(!story.isDirty(tiddlers[i].title))
						story.closeTiddler(tiddlers[i].title)
				}
			}
			if(openTiddlersFilter) {
				var tiddlers = store.filterTiddlers(openTiddlersFilter)
				for(var i = 0; i < tiddlers.length; i++)
					story.displayTiddler("bottom", tiddlers[i].title)
			}
		}
	}
}

// TODO: move defaults to lingo
config.macros.setPassword = {
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		var form = createTiddlyElement(place, 'form')
		jQuery(form).attr({ refresh: "macro", macroName: macroName }).data({
			label:   params[0] || "set password",
			tooltip: params[1] || "Set password for encrypted vault"
		})
		this.refresh(form)
	},
	refresh: function(form) {
		var params = jQuery(form).data()
		jQuery(form).empty()

		if(config.extensions.vault.existsAndIsLocked()) return
		createTiddlyButton(form, params.label, params.tooltip, this.onClick)
	},
	onClick: function(event) {
		var form = event.target.parentElement
		jQuery(form).empty()
		var refreshForm = function() { config.macros.setPassword.refresh(form) }

		var input = createTiddlyElement(form, 'input', null, null, null, {
			type: 'password'
		})
		input.focus()

		var ceVault = config.extensions.vault
		jQuery(input).on('keydown', function(event) {
			if(event.key === 'Escape') return refreshForm()

			if(event.key !== 'Enter') return
			ceVault.password = input.value

			refreshForm()
			displayMessage(ceVault.password ?
				config.messages.passwordSet :
				config.messages.passwordUnset)
			return false
		})
		.on('blur', refreshForm)
		// TODO: explain they have to type and press "enter" and/or add a button for that
		// TODO: add also way to cancel (→ refresh form)

		return false;
	}
}

config.macros.purge = {
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		var label   = params[0] || "purge vault";
		var tooltip = params[1] || "Delete locked vault";
		var ceVault = config.extensions.vault
		if (ceVault.existsAndIsLocked())
			createTiddlyButton(place, label, tooltip, this.onClick);
	},
	onClick: function() {
		var ceVault = config.extensions.vault
		if (!ceVault.existsAndIsLocked())
			alert(config.messages.noLockedVaultNoPurge);
		else
			if(confirm(config.messages.purgeConfirm)) {
				ceVault.shouldPurge = true;
				alert(config.messages.vaultPurgedInfo);
			}
		return false;
	}
}

config.macros.ifLocked = {
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		if(config.extensions.vault.existsAndIsLocked())
			wikify(params[0], place, null, tiddler);
	}
}

config.macros.ifUnlocked = {
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		if(!config.extensions.vault.existsAndIsLocked())
			wikify(params[0], place, null, tiddler);
	}
}
//}}}
The password in this demo is {{{123}}}. By default, browser will focus password input, so just type {{{123}}} and hit enter. After that, you'll see encrypted tiddlers, like [[An ecrypted tiddler]].

If you're using a device with a smaller screen, open the sidebar by clicking the three dots (this [[responsive|ResponsiveThemePlugin]] TW hides them by default). Sometimes, you'll want to put the macro that decrypts the content somewhere else, like on top of the page or above the "tiddlerDisplay" column (container of all the tiddlers).
<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!--}}}-->
/***
|Name        |ResponsiveThemePlugin|
|Description |A plugin + theme to make TW responsive (desktop/mobile)|
|Version     |0.6.3|
|Author      |Yakov Litvin|
|Source      |https://responsive.tiddlyhost.com#ResponsiveThemePlugin (won't work for checking/updating via EEP, will be changed)|
|License     |[[MIT|https://github.com/YakovL/TiddlyWiki_YL_ExtensionsCollection/blob/master/Common%20License%20(MIT)]]|
|PageTemplate|ResponsiveThemePlugin##Page Template|
|StyleSheet  |ResponsiveStyleSheet|
|Other config|[[TopLineMenuMiddle]] TopLineMenu|
!Installation & configuration
Install this as a usual plugin: copy, tag with {{{systemConfig}}}, save, reload. The only difference is that after the first reload, MarkupPreHead will be adjusted automatically, and to apply it, you have to save and reload again.

These parts can be edited to customize the theme:
* ResponsiveStyleSheet, StyleSheet are both applied, customizing the latter is preferrable
* TopLineMenu, TopLineMenuMiddle define the content in the top menu, customizing the latter (empty by default) is preferrable
As this is both a plugin and a theme, it's currently not possible to combine this with another theme.
!Page Template
<!--{{{-->
<header class='header' role='banner'>
  <div class='headerForeground'>
    <span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
    <span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
  </div>
</header>
<div id='topLineMenu' refresh='content' tiddler='TopLineMenu'></div>
<div class="body">
  <nav id='mainMenu' class='body__nav' role='navigation' refresh='content' tiddler='MainMenu'></nav>
  <main id='displayArea' class='body__main' role='main'>
    <div id='messageArea' class="messageArea"></div>
    <div id='tiddlerDisplay'></div>
  </main>
  <aside id='sidebar' class='body__sidebar'>
    <div id='sidebarOptions' role='navigation' refresh='content' tiddler='SideBarOptions'></div>
    <div id='sidebarTabs' role='complementary' refresh='content' force='true' tiddler='SideBarTabs'></div>
  </aside>
</div>
<!--}}}-->

!Code
***/
//{{{
config.options.txtTheme = 'ResponsiveThemePlugin'

// a fix: when name is set to TiddlerTitle##SectionName, should still find it
// TODO: move this to the core, add version check here
TiddlyWiki.prototype.notify = function(title, doBlanket)
{
	if(!this.notificationLevel) {
		for(var i = 0; i < this.namedNotifications.length; i++) {
			var n = this.namedNotifications[i];

			var nTitle = n.name
			if(nTitle) {
				var separatorIndex = nTitle.indexOf(config.textPrimitives.sectionSeparator)
				if(separatorIndex > -1) nTitle = nTitle.substring(0, separatorIndex)
			}

			if((n.name == null && doBlanket) || (nTitle == title))
				n.notify(n.name || title);
		}
	}
};

var isInstalled = !!document.getElementById('fullContentWrapper')

if(!isInstalled) {
	// Wrap backstage elements into a single element #backstageWrapper,
	// wrap #backstageWrapper and #contentWrapper into #fullContentWrapper
	// (as contentWrapper's innerHTML is defined in refreshPageTemplate, we can't just move backstageWrapper inside contentWrapper, so we create a common wrapper instead)
	const commonWrapper = createTiddlyElement(null, 'div', 'fullContentWrapper')
	const backstageWrapper = createTiddlyElement(commonWrapper, 'div', 'backstageWrapper')
	const contentWrapper = document.getElementById('contentWrapper')

	contentWrapper.parentNode.insertBefore(commonWrapper, contentWrapper)
	commonWrapper.appendChild(contentWrapper)

	for(let id of ['backstageButton', 'backstageArea', 'backstage', 'backstageCloak']) {
		// move inside wrapper
		backstageWrapper.appendChild(document.getElementById(id))
	}


	// make sure editing StyleSheet for custom styles causes updating css at once
	store.addNotification("StyleSheet", function(title, doc) {
		refreshStyles("ResponsiveStyleSheet", doc)
	})
}

const viewportHtml = '<meta name="viewport" content="width=device-width, initial-scale=1" />'
const preHeadMarkup = store.getTiddlerText('MarkupPreHead')
if(preHeadMarkup.indexOf(viewportHtml) == -1) {
	const preHeadTiddler = store.fetchTiddler('MarkupPreHead') || new Tiddler('MarkupPreHead')
	const closeMarkerPosition = preHeadMarkup.indexOf('<!--}}}-->')
	// TODO: test
	preHeadTiddler.text = closeMarkerPosition == -1 ? preHeadMarkup + '\n' + viewportHtml
		: preHeadMarkup.substring(0, closeMarkerPosition) + viewportHtml + '\n'
		+ preHeadMarkup.substring(closeMarkerPosition)
	store.saveTiddler(preHeadTiddler)
}

// close menus on click elsewhere
jQuery('body').on('click', function(event) {
	// except on mobile
	if(!window.matchMedia || !window.matchMedia("(max-width: 768px)").matches) return

	const $mainMenu = jQuery('#mainMenu')
	const $sidebar = jQuery('#sidebar')
	if(!isDescendant(event.target, $mainMenu[0])) $mainMenu.hide()
	if(!isDescendant(event.target, $sidebar[0])) $sidebar.hide()
})
//}}}

// /%
/***
!ResponsiveStyleSheet
***/
///*{{{*/
//body {
//	/* prevent scroll on backstage clock, right? ..better set width by JS instead
//	overflow-x: hidden; */
//	/* increased compared to core; should be increased further */
//	font-size: .8em;
//}
//
//#fullContentWrapper {
//	box-shadow: 0px 1px 4px [[ColorPalette::TertiaryMid]];
//	position: relative;
//	/* to position #messageArea, see https://stackoverflow.com/a/67776640/3995261
//	contain: content; */
//
//	max-width: 80em;
//	margin-inline-start: auto;
//	margin-inline-end: auto;
//}
//
//#backstageWrapper {
//	position: absolute;
//	top: 0;
//	left: 0;
//	right: 0;
//}
//#contentWrapper {
//	min-height: 100vh;
//	background: [[ColorPalette::Background]];
//}
//#backstageCloak {
//	/* from https://css-tricks.com/full-bleed/ */
//	width: 100vw;
//	left: 50%;
//	right: 50%;
//	margin-left: -50vw;
//	margin-right: -50vw;
//	top: 0;
//}
//
//#backstagePanel {
//	width: unset;
//	/* 0 auto  doesn't work here */
//	margin: 0;
//}
//
//.header {
//	background: -moz-linear-gradient(to bottom, [[ColorPalette::PrimaryLight]], [[ColorPalette::PrimaryMid]]);
//	background: linear-gradient(to bottom, [[ColorPalette::PrimaryLight]], [[ColorPalette::PrimaryMid]]);
//}
//.headerForeground {
//	padding: 3em 1em 1em;
//	position: relative;
//	text-shadow: -1px -1px [[ColorPalette::Foreground]];
//}
//.siteTitle {
//	/* decreased compared to the core; may be decreased more */
//	font-size: 2.5em;
//}
//@media (max-width: 768px) {
//	.siteTitle { font-size: 1.8em; }
//}
//
//#topLineMenu {
//	position: sticky;
//	top: 0;
//	z-index: 1;
//	box-shadow: 0px 1px 4px [[ColorPalette::TertiaryMid]];
//	background: [[ColorPalette::Background]];
//	padding: .5em;
///*padding-block-start: .5em;
//padding-inline-start: .5em;
//inline-size: max-content;*/
//}
//.topLineMenu__wrapper {
//	display: flex;
//	align-items: center;
//}
//.topLineMenu__center {
//	flex: 1;
//	text-align: center;
//	padding: 0 1em;
//}
//#topLineMenu a.button {
//	padding: 0.3em 0.5em;
//}
//
///* remake columns using flex */
//.body {
//	display: flex;
//	/* to allow MainMenu hover */
//	position: relative;
//}
///* undoing styles for body__nav, body__sidebar; body__main */
//#mainMenu, #sidebar {
//	position: relative;
//}
//#mainMenu {
//	padding: 1em;
//}
//#sidebar {
//	margin-inline-start: 1em;
//	padding-block-start: 1em;
//	font-size: 1em;
//}
//#sidebarOptions {
//	/* overwriting defaults */
//	padding-top: 0;
//}
//#displayArea {
//	/* prevent stretching the body horizontally (by code blocks etc), idea from:
//	   https://chaiyihein.medium.com/fixing-flexbox-child-element-overflows-the-power-of-min-width-1c7af87314da */
//	min-width: 0;
//	margin: 0;
//}
//.body__main {
//	flex: 1;
//}
//
//@media (max-width: 768px) {
//	#mainMenu, #sidebar {
//		display: none;
//		position: absolute;
//		top: 0;
//		bottom: 0;
//		background: [[ColorPalette::Background]];
//		box-shadow: 1px 2px 5px [[ColorPalette::TertiaryMid]];
//		/* height: ?? (full?) stick to the top? */
//	}
//	#mainMenu {
//		left: 0;
//	}
//	#sidebar {
//		right: 0;
//	}
//}
//
//.button_button {
//	background: [[ColorPalette::Background]];
//	border: 1px solid [[ColorPalette::SecondaryMid]];
//	padding: 0;
//	line-height: 1;
//	border-radius: 5px;
//}
//.button_button svg {
//	vertical-align: middle;
//	/* accessability */
//	min-width: 24px;
//	min-height: 24px;
//}
//.button__shape {
//	fill: none;
//	stroke: [[ColorPalette::Foreground]];
//	stroke-width: 3;
//}
//
//[[StyleSheet]]
///*}}}*/
/***
!end of ResponsiveStyleSheet
***/
// %/ //
//{{{
;(function() {
var cssName = "ResponsiveStyleSheet",
    css = store.getTiddlerText("ResponsiveThemePlugin" + "##" + cssName).replace(/^\/\//gm, "");
css = css.substring(5, css.length - 5); // cut leading \n***/ and trailing /***\n of the section
config.shadowTiddlers[cssName] = css;
})();
//}}}
// /%
/***
!TopLineMenu
***/
//{{topLineMenu__wrapper{
//<html>
//    <button class="button button_button" title="toggle main menu" onclick='
//	const $nav = jQuery(".body__nav")
//	$nav.is(":hidden") ? $nav.show() : $nav.hide()
//	if(event && event.stopPropagation) event.stopPropagation()
//    '>
//      <svg xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" viewBox="0 0 100 100">
//	<rect x="20" width="60" y="20" height="10" rx="5" ry="5" class="button__shape" />
//	<rect x="20" width="60" y="45" height="10" rx="5" ry="5" class="button__shape" />
//	<rect x="20" width="60" y="70" height="10" rx="5" ry="5" class="button__shape" />
//      </svg>
//    </button>
//</html>
//{{topLineMenu__center{
//<<tiddler [[TopLineMenuMiddle]]>>}}}
//<html>
//    <button class="button button_button" title="toggle sidebar" onclick='
//	const $nav = jQuery(".body__sidebar")
//	$nav.is(":hidden") ? $nav.show() : $nav.hide()
//	if(event && event.stopPropagation) event.stopPropagation()
//    '>
//      <svg xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" viewBox="0 0 100 100">
//	<circle cx="50" cy="25" r="7" class="button__shape" />
//	<circle cx="50" cy="50" r="7" class="button__shape" />
//	<circle cx="50" cy="75" r="7" class="button__shape" />
//      </svg>
//    </button>
//</html>
//}}}
/***
!end of TopLineMenu
***/
// %/ //
//{{{
;(function() {
var cssName = "TopLineMenu",
    css = store.getTiddlerText("ResponsiveThemePlugin" + "##" + cssName).replace(/^\/\//gm, "");
css = css.substring(5, css.length - 5); // cut leading \n***/ and trailing /***\n of the section
config.shadowTiddlers[cssName] = css;
})();
//}}}
demo
~EncryptionPlugin