:root {
  --ink: var(--text);
  --panel: color-mix(in srgb, var(--text) 6%, var(--bg));
  --line: color-mix(in srgb, var(--text) 16%, transparent);
  --accent: #3e5a8e;
}

* { box-sizing: border-box; }
/* Anything this page hides stays hidden. .toolset sets display: flex, which
   is an author class rule and outranks the UA stylesheet's
   [hidden] { display: none }, so #headtools showed its Row/All/Seed buttons
   in mask and sheet mode however many times the shell set .hidden on it.
   !important is what hands the attribute the win back, for every hidden this
   page sets now and every one it sets later. */
[hidden] { display: none !important; }
body {
  margin: 0; font: 14px/1.4 system-ui, sans-serif;
  background: var(--bg, #14151a); color: var(--ink, #e6e8ec);
  /* A column rather than a height guess. #shell used to take
     calc(100vh - 45px) against a header that measures 48px, which is where
     the page's three pixels of scroll came from -- and the guess had no term
     for #notice at all, so a notice pushed the stage off the bottom. */
  height: 100vh; display: flex; flex-direction: column;
}
#bar { display: flex; align-items: center; gap: 12px; padding: 8px 12px; background: var(--panel, #1c1e26); border-bottom: 1px solid var(--line, #2a2e39); flex: none; }
#bar .brand { font-weight: 600; display: flex; align-items: center; gap: 6px; }
#bar .actions { display: flex; gap: 6px; margin-left: auto; align-items: center; }
#celllabel { opacity: .7; font-variant-numeric: tabular-nums; }
button, select { font: inherit; color: inherit; background: var(--panel, #1c1e26); border: 1px solid var(--line, #2a2e39); border-radius: 6px; padding: 4px 10px; cursor: pointer; }
button.primary { background: var(--accent, #3e5a8e); border-color: transparent; }
button:disabled { opacity: .4; cursor: default; }
#dirty { color: #e0a030; font-size: .85rem; }
#notice { margin: 0; padding: 6px 12px; background: #3a2a2a; flex: none; }
/* The New dialog. A native <dialog>, so the modal backdrop, the focus trap and
   Escape all come from the browser rather than from this file. */
#newdlg { color: inherit; background: var(--panel, #1c1e26); border: 1px solid var(--line, #2a2e39); border-radius: 8px; padding: 16px; min-width: 300px; }
#newdlg::backdrop { background: rgb(0 0 0 / .5); }
#newdlg .lab { margin-top: 0; }
#newdlg .hint { margin: 0 0 10px; opacity: .7; font-size: .85rem; max-width: 34ch; }
/* Wider than the rail's 62px: these labels sit beside a text field rather than
   a slider, and a field that starts a third of the way across reads as an
   afterthought. */
#newdlg .field span { flex: 0 0 44px; }
#newdlg .field input[type=text] { flex: 1 1 0; min-width: 0; font: inherit; color: inherit; background: var(--bg, #14151a); border: 1px solid var(--line, #2a2e39); border-radius: 6px; padding: 4px 8px; }
#newdlg .bases { display: flex; gap: 12px; margin-bottom: 10px; }
#newdlg .bases label { display: flex; align-items: center; gap: 4px; cursor: pointer; }
#newdlg .row { display: flex; gap: 8px; justify-content: flex-end; margin-top: 14px; }
/* Empty until there is something to say, and it must take no space when empty:
   a reserved line under the fields reads as a missing message. */
#newproblem { margin: 8px 0 0; color: #e0a030; font-size: .85rem; }
#newproblem:empty { display: none; }
#shell { display: grid; grid-template-columns: 210px 1fr 260px; flex: 1; min-height: 0; }
#rail, #preview { background: var(--panel, #1c1e26); padding: 10px; overflow-y: auto; border-right: 1px solid var(--line, #2a2e39); }
#preview { border-right: 0; border-left: 1px solid var(--line, #2a2e39); }
.lab { font-size: .72rem; text-transform: uppercase; letter-spacing: .08em; opacity: .6; margin: 12px 0 6px; }
.field { display: flex; align-items: center; gap: 8px; margin: 6px 0; }
.field span { flex: 0 0 62px; opacity: .8; }
/* flex: 1 alone leaves min-width at auto, which is what lets a range input
   refuse to shrink to its share and hang a pixel past the rail. */
.field input[type=range] { flex: 1 1 0; min-width: 0; margin: 0; }
.field.checkbox span { flex: 1; }
.toolset { display: flex; flex-wrap: wrap; gap: 4px; }
/* Fixed-size buttons rather than a grid, because the three toolsets hold
   four, four and one. Four at 40px with 4px gaps is 172, inside the rail's
   189, so no toolset wraps. */
/* Scoped to the three icon strips, not to every .toolset. The cell clipboard
   shares the class with word-labelled buttons, and a 40px box clips "Paste
   flipped" to "Paste flipp" -- inside the rail, so neither the overflow guard
   nor the squeeze sweep sees it. A rule that sizes a button for a glyph has
   to name the strips that hold glyphs. */
#modes button, #tools button, #headtools button {
  width: 40px; height: 30px; padding: 0;
  display: flex; align-items: center; justify-content: center;
}
/* Selection is a filled state rather than an outline. outline drew outside
   the button's box, which is part of what crowded the rail.
   map-editor.css uses a 14% wash plus color: var(--accent) on the glyph, but
   its --accent is a bright #ffb000 against a similarly light panel; this
   editor's --accent is a much darker #3e5a8e over a darker panel, and tried
   at 14% the pressed state read as barely distinguishable from unpressed --
   worse, tinting the glyph itself lost the contrast the plain white icon had
   against the dark panel. 45% is heavier than map-editor.css's 14% on
   purpose, to stay legible on this panel; the glyph stays white rather than
   accent-tinted for the same reason. */
#modes button[aria-pressed="true"], #tools button[aria-pressed="true"] {
  border-color: var(--accent, #3e5a8e);
  background: color-mix(in srgb, var(--accent) 45%, transparent);
}
button .ic { width: 15px; height: 15px; }
/* Two lines. Seven controls do not fit one 181px line, which is the rail's
   209 less its 10px padding each side and the row's own 4px each side --
   the measure button and the coverage readout used to sit past the rail's
   right edge with no way to scroll to them. */
#parts .part {
  display: grid; grid-template-columns: 14px 1fr auto;
  align-items: center; column-gap: 6px; row-gap: 3px;
  padding: 4px 4px 6px; border-radius: 6px; cursor: pointer;
}
#parts .part .swatch { grid-column: 1; grid-row: 1; }
#parts .part .name { grid-column: 2; grid-row: 1; }
#parts .part .cov { grid-column: 3; grid-row: 1; }
/* Line two spans the name and coverage columns: three 22px buttons and a
   68px anchor is 146 inside the 161 they have. */
#parts .part .ctl { grid-column: 2 / 4; grid-row: 2; display: flex; align-items: center; gap: 4px; }
#parts .part .ctl .anchor { margin-left: auto; width: 68px; }
#parts .part .ctl button { width: 22px; height: 20px; padding: 0; display: flex; align-items: center; justify-content: center; }
#parts .part .ctl button .ic { width: 13px; height: 13px; }
/* Same 45% wash and the same reasoning as .toolset button[aria-pressed] above:
   this panel is darker than map-editor.css's and this --accent is muted, so
   its 14% read as barely-pressed here. */
#parts .part .ctl button[aria-pressed="true"] { border-color: var(--accent, #3e5a8e); background: color-mix(in srgb, var(--accent) 45%, transparent); }
#parts .part.active { background: rgba(255,255,255,.08); }
#parts .part.hidden { opacity: .35; }
#parts .swatch { width: 14px; height: 14px; border-radius: 3px; }
#parts .cov { font-size: .72rem; opacity: .55; font-variant-numeric: tabular-nums; }
#tones { display: flex; flex-wrap: wrap; gap: 3px; }
#tones .tone { width: 20px; height: 20px; border-radius: 3px; border: 1px solid rgba(0,0,0,.45); cursor: pointer; position: relative; }
#tones .tone:hover { outline: 2px solid #fff; }
#tones .tone .owner { position: absolute; right: -1px; bottom: -1px; width: 7px; height: 7px; border-radius: 2px; }
#stage { position: relative; overflow: hidden; background: #0c0d11; }
#grid { display: block; width: 100%; height: 100%; image-rendering: pixelated; cursor: crosshair; touch-action: none; }
#zoombar { position: absolute; right: 10px; bottom: 10px; display: flex; gap: 4px; align-items: center; background: var(--panel,#1c1e26); border: 1px solid var(--line,#2a2e39); border-radius: 8px; padding: 4px; }
/* Text mode's surface. It fills the same #stage the canvas does rather than
   sitting beside it -- one editing surface on screen at a time, the way mask
   and sheet mode already share the one canvas between them. */
#textpanel { position: absolute; inset: 0; overflow-y: auto; padding: 12px; background: var(--panel, #1c1e26); }
#textpanel fieldset { border: 1px solid var(--line, #2a2e39); border-radius: 6px; margin: 0 0 12px; padding: 6px 10px 10px; }
#textpanel legend { padding: 0 4px; font-size: .78rem; text-transform: uppercase; letter-spacing: .08em; opacity: .7; }
/* .field is the rail's own label+control row (assets/css/character-editor.css
   above); reused here rather than a second layout rule for the identity and
   casting-brief fields, which are the same shape. */
#textpanel .field span { flex: 0 0 90px; }
#textpanel .field input[type=text], #textpanel .field select { flex: 1 1 0; min-width: 0; }
/* A story or voice row: the sentence, a Remove/Play button and a Move/Import
   button, all three sized to the row rather than to their own text -- the
   buttons are word-labelled, unlike the icon rail, since there is no icon set
   for "remove a sentence" and inventing one for two buttons is not worth it. */
.story-row, .voice-row { display: flex; align-items: center; gap: 6px; margin: 5px 0; }
.story-row input, .voice-row input { flex: 1 1 0; min-width: 0; }
.story-row button, .voice-row button { flex: none; font-size: .78rem; padding: 3px 8px; }
/* The reason a value would be refused on export (refuseReason) is the input's
   title; this is the only visual sign of it besides hovering for the tooltip. */
#textpanel input[aria-invalid="true"] { outline: 1px solid #c04040; outline-offset: -1px; }
/* A reading replaced from an imported clip, so the line on screen and the
   audio on disk are known to disagree until the text catches up (Task 11). */
#textpanel input[data-imported="true"] { border-color: #e0a030; }
#pv { width: 100%; image-rendering: pixelated; background: #0c0d11; border-radius: 8px; }
#swatches .prow { display: flex; align-items: center; gap: 3px; margin: 4px 0; flex-wrap: wrap; }
#swatches .prow .name { flex: 0 0 54px; opacity: .8; font-size: .8rem; }
#swatches .sw { width: 16px; height: 16px; border-radius: 3px; cursor: pointer; border: 1px solid rgba(0,0,0,.4); }
#swatches .sw.sel { outline: 2px solid #fff; }
#shortcuts { position: fixed; right: 16px; bottom: 16px; z-index: 5; background: var(--panel); border: 1px solid var(--line); border-radius: 8px; padding: 10px 14px; font-size: .85rem; }
#shortcuts ul { margin: 0; padding-left: 0; list-style: none; }
#shortcuts li { margin: 3px 0; opacity: .85; }
#shortcuts b { display: inline-block; min-width: 8.5em; opacity: 1; }
.lab button { float: right; font-size: .8rem; line-height: 1; padding: 1px 6px; }
#tones .tone.sel { outline: 2px solid #fff; }
/* A tone no pixel carries any more keeps its slot: the strip must not reflow
   under the pointer. It greys out to say so. */
#tones .tone.empty { opacity: .3; }
#strength[disabled] { opacity: .35; }
.cellsize { display: flex; align-items: center; gap: 4px; font-size: .78rem; opacity: .8; }
.cellsize input { width: 52px; }
#preview .none { font-size: .78rem; opacity: .55; margin: 6px 0; }
#fringestat { font-size: .72rem; opacity: .6; margin: 4px 0; }
#cliptarget, #clipstat { font-size: .72rem; opacity: .6; margin: 4px 0; }
/* --- the rail's icons ----------------------------------------------------
   The same idiom as assets/css/map-editor.css: a 12x12 crispEdges SVG in a
   data URI, applied as a mask over currentColor, so one definition serves
   light, dark and the pressed state with no image asset and no second colour.

   .ic itself is duplicated from map-editor.css rather than shared. A common
   file would mean editing a working editor for no gain to it.

   Every glyph below was checked at 44px and at 15px, which is the size a
   rail button actually wears. Four earlier drafts failed that second look
   and the comments say what they failed at. */
.ic {
  display: inline-block; width: 1.5em; height: 1.5em; flex: none;
  background: currentColor;
  -webkit-mask: var(--m) center / contain no-repeat; mask: var(--m) center / contain no-repeat;
}
/* The masthead's mark: a front-facing sprite, the same glyph the landing
   page's Tools card wears for this editor. Kept identical to the .ic-figure
   in scripts/releasenotes.js so the card and the page it opens agree. */
.ic-figure { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='4' y='0' width='4' height='3'/%3E%3Crect x='0' y='3' width='12' height='1'/%3E%3Crect x='0' y='4' width='2' height='3'/%3E%3Crect x='4' y='4' width='4' height='3'/%3E%3Crect x='10' y='4' width='2' height='3'/%3E%3Crect x='3' y='7' width='6' height='2'/%3E%3Crect x='3' y='9' width='2' height='3'/%3E%3Crect x='7' y='9' width='2' height='3'/%3E%3C/svg%3E"); }
/* A filled plate with a hole knocked through it: what a mask is. */
.ic-mask { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='1' y='1' width='10' height='3'/%3E%3Crect x='1' y='4' width='3' height='4'/%3E%3Crect x='8' y='4' width='3' height='4'/%3E%3Crect x='1' y='8' width='10' height='3'/%3E%3C/svg%3E"); }
/* The sprite sheet: a framed 3x2 grid of cells. */
.ic-sheet { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='0' y='1' width='12' height='1'/%3E%3Crect x='0' y='10' width='12' height='1'/%3E%3Crect x='0' y='1' width='1' height='10'/%3E%3Crect x='11' y='1' width='1' height='10'/%3E%3Crect x='4' y='1' width='1' height='10'/%3E%3Crect x='8' y='1' width='1' height='10'/%3E%3Crect x='0' y='5' width='12' height='1'/%3E%3C/svg%3E"); }
/* A bust rather than a circle. The circle itself is what the place tool
   draws, and .ic-place has it. */
.ic-head { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='4' y='1' width='4' height='1'/%3E%3Crect x='3' y='2' width='6' height='3'/%3E%3Crect x='4' y='5' width='4' height='1'/%3E%3Crect x='2' y='8' width='8' height='1'/%3E%3Crect x='1' y='9' width='10' height='3'/%3E%3C/svg%3E"); }
/* Three lines of text, the last one short: a page of prose, not a list --
   .ic-row/.ic-all already own the grid-of-cells look, so this stays lines. */
.ic-text { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='1' y='1' width='10' height='2'/%3E%3Crect x='1' y='5' width='10' height='2'/%3E%3Crect x='1' y='9' width='6' height='2'/%3E%3C/svg%3E"); }
/* Upright: narrow handle, ferrule band, blunt bristles. Drawn as a diagonal
   it was indistinguishable from .ic-pencil at 15px, which is the size that
   matters -- mask-paint and sheet-pencil are the pair a hand confuses. */
.ic-brush { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='5' y='0' width='2' height='4'/%3E%3Crect x='3' y='4' width='6' height='2'/%3E%3Crect x='3' y='6' width='6' height='4'/%3E%3Crect x='4' y='10' width='4' height='2'/%3E%3C/svg%3E"); }
/* map-editor.css's .ic-pen geometry verbatim: a proven diagonal. */
.ic-pencil { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='0' y='11' width='1' height='1'/%3E%3Crect x='1' y='10' width='2' height='1'/%3E%3Crect x='2' y='9' width='2' height='1'/%3E%3Crect x='3' y='8' width='2' height='1'/%3E%3Crect x='4' y='7' width='2' height='1'/%3E%3Crect x='5' y='6' width='2' height='1'/%3E%3Crect x='6' y='5' width='2' height='1'/%3E%3Crect x='7' y='4' width='2' height='1'/%3E%3Crect x='8' y='3' width='2' height='1'/%3E%3Crect x='9' y='2' width='2' height='1'/%3E%3Crect x='9' y='1' width='2' height='1'/%3E%3C/svg%3E"); }
/* Axis-aligned, not slanted: an outlined block with the rubber/ferrule split
   across it, resting on the surface it clears. Slanted, it read as one more
   diagonal smear beside the brush and the pencil. */
.ic-erase { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='2' y='2' width='8' height='1'/%3E%3Crect x='2' y='8' width='8' height='1'/%3E%3Crect x='2' y='2' width='1' height='7'/%3E%3Crect x='9' y='2' width='1' height='7'/%3E%3Crect x='2' y='5' width='8' height='1'/%3E%3Crect x='0' y='11' width='12' height='1'/%3E%3C/svg%3E"); }
/* A ramp of rising bars: how much, not what. */
.ic-strength { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='0' y='8' width='2' height='4'/%3E%3Crect x='3' y='5' width='2' height='7'/%3E%3Crect x='6' y='2' width='2' height='10'/%3E%3Crect x='9' y='0' width='2' height='12'/%3E%3C/svg%3E"); }
/* A drop falling into a solid pool: the flood, not the vessel. A pail with a
   handle arc turned to porridge at 15px, and the handle was what did it.
   Shared by the mask's bucket and the sheet's fill -- one gesture, and the
   mode says which surface it lands on. */
.ic-bucket { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='5' y='1' width='2' height='1'/%3E%3Crect x='4' y='2' width='4' height='2'/%3E%3Crect x='5' y='4' width='2' height='1'/%3E%3Crect x='0' y='7' width='12' height='4'/%3E%3C/svg%3E"); }
/* A pipette: a wide hollow bulb, not a solid tip, over a diagonal shaft. The
   first draft's bulb was a small solid 4x3 block whose silhouette read as
   just one more diagonal beside .ic-pencil at 15px -- the two share a strip
   three buttons apart. This bulb is a 6x5 ring, wider and squarer than the
   shaft it sits on, so the outline itself reads as "bulb" before the eye
   ever reaches the diagonal. */
.ic-dropper { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='6' y='0' width='6' height='1'/%3E%3Crect x='6' y='1' width='1' height='3'/%3E%3Crect x='11' y='1' width='1' height='3'/%3E%3Crect x='6' y='4' width='6' height='1'/%3E%3Crect x='5' y='5' width='2' height='1'/%3E%3Crect x='4' y='6' width='2' height='1'/%3E%3Crect x='3' y='7' width='2' height='1'/%3E%3Crect x='2' y='8' width='2' height='1'/%3E%3Crect x='1' y='9' width='2' height='1'/%3E%3Crect x='0' y='10' width='2' height='2'/%3E%3C/svg%3E"); }
/* The ring the tool places, with its centre marked. */
.ic-place { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='4' y='1' width='4' height='1'/%3E%3Crect x='2' y='2' width='2' height='1'/%3E%3Crect x='8' y='2' width='2' height='1'/%3E%3Crect x='2' y='3' width='1' height='1'/%3E%3Crect x='9' y='3' width='1' height='1'/%3E%3Crect x='1' y='4' width='1' height='4'/%3E%3Crect x='10' y='4' width='1' height='4'/%3E%3Crect x='2' y='8' width='1' height='1'/%3E%3Crect x='9' y='8' width='1' height='1'/%3E%3Crect x='2' y='9' width='2' height='1'/%3E%3Crect x='8' y='9' width='2' height='1'/%3E%3Crect x='4' y='10' width='4' height='1'/%3E%3Crect x='5' y='5' width='2' height='2'/%3E%3C/svg%3E"); }
/* One family, three states of the same 3x3 grid: a filled block is a cell
   that carries a circle, a lone dot is a cell that does not. */
.ic-row { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='0' y='0' width='3' height='3'/%3E%3Crect x='4' y='0' width='3' height='3'/%3E%3Crect x='8' y='0' width='3' height='3'/%3E%3Crect x='1' y='5' width='1' height='1'/%3E%3Crect x='5' y='5' width='1' height='1'/%3E%3Crect x='9' y='5' width='1' height='1'/%3E%3Crect x='1' y='9' width='1' height='1'/%3E%3Crect x='5' y='9' width='1' height='1'/%3E%3Crect x='9' y='9' width='1' height='1'/%3E%3C/svg%3E"); }
.ic-all { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='0' y='0' width='3' height='3'/%3E%3Crect x='4' y='0' width='3' height='3'/%3E%3Crect x='8' y='0' width='3' height='3'/%3E%3Crect x='0' y='4' width='3' height='3'/%3E%3Crect x='4' y='4' width='3' height='3'/%3E%3Crect x='8' y='4' width='3' height='3'/%3E%3Crect x='0' y='8' width='3' height='3'/%3E%3Crect x='4' y='8' width='3' height='3'/%3E%3Crect x='8' y='8' width='3' height='3'/%3E%3C/svg%3E"); }
.ic-seed { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='0' y='0' width='3' height='3'/%3E%3Crect x='5' y='1' width='1' height='1'/%3E%3Crect x='9' y='1' width='1' height='1'/%3E%3Crect x='1' y='5' width='1' height='1'/%3E%3Crect x='4' y='4' width='3' height='3'/%3E%3Crect x='9' y='5' width='1' height='1'/%3E%3Crect x='1' y='9' width='1' height='1'/%3E%3Crect x='5' y='9' width='1' height='1'/%3E%3Crect x='8' y='8' width='3' height='3'/%3E%3C/svg%3E"); }
/* One channel raised over its neighbours. */
.ic-solo { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='0' y='7' width='3' height='4'/%3E%3Crect x='4' y='1' width='4' height='10'/%3E%3Crect x='9' y='7' width='3' height='4'/%3E%3C/svg%3E"); }
/* An almond eight rows tall, so the 4x4 pupil fills half of it rather than
   two thirds. At six rows the outline read as a dumbbell. */
.ic-eye { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='4' y='2' width='4' height='1'/%3E%3Crect x='2' y='3' width='2' height='1'/%3E%3Crect x='8' y='3' width='2' height='1'/%3E%3Crect x='1' y='4' width='1' height='1'/%3E%3Crect x='10' y='4' width='1' height='1'/%3E%3Crect x='0' y='5' width='1' height='2'/%3E%3Crect x='11' y='5' width='1' height='2'/%3E%3Crect x='1' y='7' width='1' height='1'/%3E%3Crect x='10' y='7' width='1' height='1'/%3E%3Crect x='2' y='8' width='2' height='1'/%3E%3Crect x='8' y='8' width='2' height='1'/%3E%3Crect x='4' y='9' width='4' height='1'/%3E%3Crect x='4' y='4' width='4' height='4'/%3E%3C/svg%3E"); }
/* A rule with its ticks: measure. */
.ic-ruler { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='0' y='3' width='12' height='1'/%3E%3Crect x='0' y='8' width='12' height='1'/%3E%3Crect x='0' y='3' width='1' height='6'/%3E%3Crect x='11' y='3' width='1' height='6'/%3E%3Crect x='2' y='4' width='1' height='2'/%3E%3Crect x='4' y='4' width='1' height='3'/%3E%3Crect x='6' y='4' width='1' height='2'/%3E%3Crect x='8' y='4' width='1' height='3'/%3E%3C/svg%3E"); }
/* The same eye with a slash, and the one definition here that leaves
   crispEdges off, exactly as map-editor.css's .ic-dead does: the slash runs
   diagonally and crisp edges would stair-step it. The rects keep their hard
   edges anyway, being integer aligned. */
.ic-eyeoff { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Crect x='4' y='2' width='4' height='1'/%3E%3Crect x='2' y='3' width='2' height='1'/%3E%3Crect x='8' y='3' width='2' height='1'/%3E%3Crect x='1' y='4' width='1' height='1'/%3E%3Crect x='10' y='4' width='1' height='1'/%3E%3Crect x='0' y='5' width='1' height='2'/%3E%3Crect x='11' y='5' width='1' height='2'/%3E%3Crect x='1' y='7' width='1' height='1'/%3E%3Crect x='10' y='7' width='1' height='1'/%3E%3Crect x='2' y='8' width='2' height='1'/%3E%3Crect x='8' y='8' width='2' height='1'/%3E%3Crect x='4' y='9' width='4' height='1'/%3E%3Crect x='4' y='4' width='4' height='4'/%3E%3Cpath d='M1 10.2l9.2-9.2 .8 .8-9.2 9.2z'/%3E%3C/svg%3E"); }
