diff --git a/pd/nw/css/solarized.css b/pd/nw/css/solarized.css
index ef23c18fc1d1058f350b16b3d04175031704cd4e..c3314dfed0b52521cf34320f4f0e34c641d21566 100644
--- a/pd/nw/css/solarized.css
+++ b/pd/nw/css/solarized.css
@@ -311,7 +311,7 @@ text {
 
 /* text inside selected objects */
 :not(.gop).selected text {
-    fill: blue;
+    fill: #268bd2;
 }
 
 /* for an object that didn't create */
diff --git a/pd/nw/css/solarized_inverted.css b/pd/nw/css/solarized_inverted.css
new file mode 100644
index 0000000000000000000000000000000000000000..b97a55f493552cdb1a91d84eb411d69f05def37c
--- /dev/null
+++ b/pd/nw/css/solarized_inverted.css
@@ -0,0 +1,625 @@
+/* Global CSS */
+
+/*
+@font-face {
+    font-family: "DejaVu Sans Mono";
+    src: url("../DejaVuSansMono.ttf");
+}
+*/
+
+body {
+    margin: 0px;
+    font-family: "DejaVu Sans Mono";
+}
+
+.noselect {
+    -webkit-touch-callout: none;
+    -webkit-user-select: none;
+    -khtml-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+}
+
+::selection {
+    background: #073642;
+    color: #839496;
+}
+
+/* The main Pd Window */
+
+#console_controls {
+    color: #657b83;
+    background-color: #073642;
+    height: 50px; 
+} 
+
+#control_frame {
+    padding: 12px;
+}
+
+#printout {
+    margin: 8px;
+}
+
+#console_bottom {
+    position: absolute;
+    top: 50px;
+    left: 0px;
+    right: 0px;
+    bottom: 0px;
+    overflow-y: scroll;    
+    background-color: #002b36;
+    color: #839496;
+}
+
+/* The console API allows classes for different types of messages to print.
+   Currently the only class is "error". More may be added, especially once 
+   we port the "loglevel" functionality that was available in Pd Extended. */
+#console_bottom .error {
+    color: #93a1a1;
+}
+
+#console_bottom .error a {
+    color: #b58900;
+    font-weight: 600;
+}
+
+/* Find bar */
+
+#console_find label, #canvas_find label {
+    font-family: "DejaVu Sans", sans-serif;
+    font-size: 10pt;
+}
+
+/* marks for matches to console_find */
+mark {
+    background: #eee8d5;
+}
+
+mark.console_find_current.console_find_highlighted,
+mark.console_find_current {
+    background: #b58900;
+}
+
+mark.console_find_highlighted {
+    background: red;
+}
+
+#console_find {
+    width: 100%;
+    height: 1em;
+    padding: 0.2em;
+    background: #073642;
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    color: #586e75;
+}
+
+/* Pure Data Patch Window (aka canvas) */
+
+/* patch font and background color. (Note: margin needs to stay at zero.) */
+.patch_body {
+    background-color: #002b36;
+}
+
+#selection_rectangle {
+    stroke: #b58900;
+}
+
+/* The outline to show the visible area for a Graph-On-Parent canvas,
+   i.e., the "red rectangle" */
+.gop_rect {
+    fill: none;
+    stroke: #dc322f;
+    stroke-opacity: 0.4;
+}
+
+.cord.signal {
+    stroke-width: 2;
+    stroke: #586e75;
+}
+
+.cord.control {
+    stroke-width: 1;
+    stroke: #586e75;
+}
+
+/* selected connection between objects */
+.cord.signal.selected_line,
+.cord.control.selected_line {
+    stroke: #b58900;
+}
+
+#cord_inspector_rect {
+    fill: #93a1a1;
+    stroke: #93a1a1;
+}
+
+#cord_inspector_text {
+    fill: white;
+}
+
+#cord_inspector_text.flash {
+    fill: #e87216;
+}
+
+/* text inside boxes: message boxes, object boxes, graphs, comments, etc. */
+.box_text {
+    fill: #839496;
+}
+
+/* hyperlinks: for now, just pddplink and helplink */
+.pd_link text {
+    fill: blue;
+}
+
+.pd_link text:hover {
+    fill: red;
+}
+
+.pd_link.selected text {
+    fill: white;
+}
+
+#new_object_textentry {
+    /* max-width: 10ch; */
+    min-width: 3ch;
+    position: absolute;
+    display: table-cell;
+    padding: 3px 2px 3px 2px;
+    /* box-shadow: inset 1px 0px 0px 1px #000; */
+    background-color: transparent;
+    white-space: pre-wrap;
+    overflow-wrap: break-word;
+    -webkit-margin-before: 0px;
+    color: #93a1a1;
+}
+
+#new_object_textentry.obj {
+    outline: 1px solid #b58900;
+}
+
+#new_object_textentry.msg {
+    outline: 0px solid #b58900;
+    background-image: url(../msg-box.svg);
+}
+
+p.msg::after {
+    content: "";
+    height: 100%;
+    width: 5px;
+    background-image: url(../msg-box-flag.svg);
+    position: absolute;
+    top: 0%;
+    left: 100%;
+}
+
+/* not sure what this is doing here... */
+text {
+    // fill: red;
+    //cursor: default;
+}
+
+/* not sure if this is still needed */
+.selected_border {
+    stroke: blue;
+    stroke-dasharray: none;
+    stroke-width: 1;
+}
+
+.msg .border {
+    stroke: #586e75;
+    fill: #002b36;
+}
+
+/* state of msg box when clicking it */
+.msg.flashed .border {
+    stroke-width: 4;
+}
+
+/* atom box */
+.atom .border {
+    stroke: #586e75;
+    fill: #002b36;
+}
+
+/* for dropdown box we want to visually distinguish boxes that output
+   the index from boxes that output the value. For now we do that by
+   stroking the arrow for boxes that output an index. For boxes that
+   output the value we don't need a CSS rule, as the arrow will be filled
+   black by default */
+.atom .index_arrow {
+    stroke: #586e75;
+    stroke-width: 1;
+    fill: none;
+}
+
+.atom .value_arrow {
+    stroke: #586e75;
+    fill: #586e75;
+}
+
+/* gatom "activated" text (i.e., when it has the keyboard focus) */
+.atom.activated text {
+    fill: #dc322f;
+}
+
+#dropdown_list {
+    position: absolute;
+    border-width: 1px;
+    border-style: solid;
+    border-color: #586e75;
+    cursor: pointer;
+    color: #93a1a1;
+
+}
+
+#dropdown_list ol {
+    list-style-position: inside;
+    margin: 0;
+    padding: 0;
+    background: #002b36;
+}
+
+#dropdown_list li {
+    list-style-type: none;
+    padding: 5px;
+}
+
+#dropdown_list li.highlighted {
+    background: #073642;
+}
+
+.obj .border {
+    fill: #002b36;
+    stroke: #586e75;
+}
+
+/* A little hack for special canvas of [cnv].
+   All other iemguis have a black border, but
+   [cnv] sets its selection rectangle to the
+   user-supplied fill color when the object
+   isn't selected */
+.iemgui .border:not(.mycanvas_border) {
+    stroke: #93a1a1;
+}
+
+.graph .border {
+    stroke: #586e75;
+    fill: none;
+}
+
+/* Graph (or subpatch) that has been opened to inspect its contents */
+.graph.has_window .border {
+    stroke: #93a1a1;
+    fill: #eee8d5;
+}
+
+/* border color for selected objects
+      * an element with the class "border"
+      * the element is contained within a parent element of class "selected"
+      * that parent element is not in class "gop"
+   in plain English:
+      This lets us highlight an object's border, unless it is inside a gop
+      canvas.
+*/
+:not(.gop).selected .border {
+    stroke: #b58900;
+    display: inline;
+}
+
+/* text inside selected objects */
+:not(.gop).selected text {
+    fill: #b58900;
+}
+
+/* for an object that didn't create */
+.obj .border.broken_border {
+    fill: transparent;
+    stroke: #dc322f;
+    stroke-dasharray: 3 2;
+}
+
+/* control inlet */
+.xlet_control {
+    stroke: #586e75;
+    fill: #002b36;
+}
+
+/* signal inlet */
+.xlet_signal {
+    stroke: #586e75;
+    fill: #002b36;
+    stroke-width: 1;
+}
+
+/* iemgui inlet or outlet */
+.xlet_iemgui {
+    stroke: #586e75;
+    fill: #002b36;
+    stroke-width: 1;
+}
+
+/* text label for an iemgui */
+.iemgui_label_selected {
+    fill: #268bd2;
+}
+
+/* test of xlet hover animation... this should 
+   probably use the web animation API instead. That
+   way the animation won't get cut off when you
+   move off the object */
+@-webkit-keyframes fizzle {
+    0% {
+        stroke-width: 1;
+        stroke-opacity: 1;
+        rx: 1;
+        ry: 1;
+    }
+    100% {
+        stroke-width: 20;
+        stroke-opacity: 0.2;
+        rx: 50;
+        ry: 50;
+    }
+}
+
+/* can't remember why this was tagged !important */
+.xlet_selected {
+    stroke: gray !important;
+    fill: gray;
+    -webkit-animation: fizzle 0.5s linear 1;
+}
+
+#canvas_find {
+    width: 100%;
+    height: 1em;
+    padding: 3px;
+    background: #073642;
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    color: #586e75;
+}
+
+/* Dialog to ask to save the patch before quitting */
+#save_before_quit {
+    background-color: #fdf6e3;
+    border:1px solid #eee8d5;
+    padding: 12px;
+    margin: 12px;
+    box-shadow: 7px 7px 5px grey;
+}
+
+/* Search dialog */
+
+.search_body {
+    font-family: "DejaVu Sans", sans-serif;
+    font-size: 10pt;
+    padding: 8px;
+    background: #fdf6e3;
+    color: #657b83;
+}
+
+.search_body a {
+    color: #268bd2;
+}
+
+/* Common to all dialogs */
+
+.dialog_body {
+    font-family: "DejaVu Sans", sans-serif;
+    font-size: 10pt;
+    background: #fdf6e3;
+}
+
+.submit_buttons {
+    text-align: center;
+    padding: 8px;
+}
+
+fieldset {
+    border-radius:3px;
+    border:2px solid #eee8d5;
+    margin-left:auto;
+    margin-right:auto;
+    padding: 10px;
+}
+
+.hidden {
+    display: none;
+}
+
+.container{
+    display: none;
+}
+
+/* Iemgui dialog */
+
+input[type="text"]{
+    width:3em;
+}
+
+input[type="number"]{
+    width:3em;
+}
+
+label {
+    text-align: right;
+}
+
+/* Pair of properties that are related */
+.pair {
+    width: 75%;
+    text-align: left;
+    align: left;
+}
+
+.item1 {
+    width: 50%;
+}
+
+.item2 {
+    width: 50%;
+}
+
+input[name="x_offset"] {
+    width: 2em;
+}
+
+input[name="y_offset"] {
+    width: 2em;
+}
+
+input[name="send_symbol"] {
+    width: 8em;
+}
+
+input[name="receive_symbol"] {
+    width: 8em;
+}
+
+input[name="label"] {
+    width: 8em;
+}
+
+input[name="font_size"] {
+    width: 3em;
+}
+
+input[name="startup_flags"] {
+    width: 16em;
+}
+
+/* Canvas dialog */
+
+div.x-scale {
+    padding: 3px;
+    text-align: center;
+}
+
+div.gop-range {
+}
+
+div.y1 {
+    text-align: center;
+    padding: 3px;
+}
+
+div.x1 {
+    text-align: center;
+    padding: 3px;
+}
+
+div.y2 {
+    text-align: center;
+    padding: 3px;
+}
+
+.disabled {
+    color: #aaa;
+}
+
+/* Preferences dialog */
+
+#prefs_html_element {
+/*    height: 100%; */
+    margin: 0px;
+    padding: 0px;
+    height: 100vh;
+}
+
+.prefs_body {
+    padding: 0px;
+}
+
+#prefs_container {
+    display: table;
+}
+
+/* Main tab widget */
+
+/* All the display, width, and height settings below are a house of cards.
+   I don't have the schooling to actually predict how all these CSS elements
+   work together to create the whole. I just fudged around until I found a
+   way to get the buttons anchored at the bottom of the dialog without
+   triggering scrollbars to appear. If someone knows a way to do it "right"
+   without becoming an order of magnitude more complex, do feel free... */
+.prefs_tab_group {
+    display: table;
+    width: 90%;
+}
+
+/* Configure the radio buttons to hide off-screen */
+.prefs_tab {
+    position: absolute;
+    left:-100px;
+    top:-100px;
+}
+
+/* Configure labels to look like tabs */
+.prefs_tab + label {
+    /* inline-block such that the label can be given dimensions */
+    display: inline-block;
+    /* A nice curved border around the tab */
+    border: 1px solid #bbb;
+    border-top-left-radius: 5px;
+    border-top-right-radius: 5px;
+    /* the bottom border is handled by the tab content div */
+    border-bottom: 0;
+    /* Padding around tab text */
+    padding: 5px 10px;
+    /* put a small margin to the left to make the first tab clear */
+    margin-left: 4px;
+    margin-top: 8px;
+    margin-bottom: 0px;
+    /* Set the background color to default gray (non-selected tab) */
+    background-color:#ececec;
+}
+
+/* Focused tabs */
+.prefs_tab:focus + label {
+    border: 1px dashed #bbb;
+}
+
+/* Checked tabs must be white with the bottom border removed */
+.prefs_tab:checked + label {
+    background-color: #f3f3f3;
+    text-shadow: 1px 0px 0px; /* substitute for "bold" to retain div width */
+    border-bottom: 1px solid #f3f3f3;
+    margin-bottom: -1px;
+}
+
+/* The tab content must fill the widgets size and have a nice border */
+.prefs_tab_group > div {
+    display: none;
+    border-top: 1px solid #ddd;
+    padding: 0px;
+    margin: 0px;
+    height: 100%;
+}
+
+/* This matches tabs displaying to their associated radio inputs */
+.tab1:checked ~ .tab1, .tab2:checked ~ .tab2, .tab3:checked ~ .tab3, .tab4:checked ~ .tab4 {
+    display: table;
+    padding: 8px;
+    line-height: 20px;
+    width: 100%;
+    height: 78vh;
+}
+
+.tab_settings {
+    padding-top: 8px;
+}
+
+#prefs_buttons {
+    display: table;
+    height: 10vh;
+    padding: 0px;
+    margin: 0px;
+    margin-top: -10px;
+    margin-bottom: -10px;
+    padding: 30px;
+}
diff --git a/pd/nw/dialog_prefs.html b/pd/nw/dialog_prefs.html
index 8b9a2d38f5e27a1e5a65f1a0a18aa31e1190b3c5..e5b7d77533c670e2ae667a99b1aa02a73a7e29ad 100644
--- a/pd/nw/dialog_prefs.html
+++ b/pd/nw/dialog_prefs.html
@@ -293,6 +293,9 @@
               </option>
               <option data-i18n="prefs.gui.presets.solarized" value="solarized">
               </option>
+              <option data-i18n="prefs.gui.presets.solarized_inverted"
+                      value="solarized_inverted">
+              </option>
             </select>
             <br/>
             <label data-i18n="[title]prefs.gui.zoom.save_zoom_tt">
diff --git a/pd/nw/locales/de/translation.json b/pd/nw/locales/de/translation.json
index db6dad8d5cc7fee29df6092c40e4675b97e0f2a9..d092082070d2cf252e463ca3df58f9f5c4607ee2 100644
--- a/pd/nw/locales/de/translation.json
+++ b/pd/nw/locales/de/translation.json
@@ -398,6 +398,7 @@
         "subdued": "Dezent",
         "strongbad": "Strongbad",
         "solarized": "Solarized",
+        "solarized_inverted": "Solarized (Inverted)",
         "extended": "Extended",
         "c64": "C64"
       },
diff --git a/pd/nw/locales/en/translation.json b/pd/nw/locales/en/translation.json
index 267c5d18bdb8f6a94ab31e9fc4e860cb2624866e..62814d604e999a6cd6b29ab3bbeee948bd2d7e42 100644
--- a/pd/nw/locales/en/translation.json
+++ b/pd/nw/locales/en/translation.json
@@ -398,6 +398,7 @@
         "subdued": "Subdued",
         "strongbad": "Strongbad",
         "solarized": "Solarized",
+        "solarized_inverted": "Solarized (Inverted)",
         "extended": "Extended",
         "c64": "C64"
       },