/* Sherborn Zoning — set like a statute book.
   Citation numbers hang in the gutter, body runs at a reading measure, and the only
   decoration is a hairline rule system. Long legal text is the whole job. */

:root {
  /* Overridden per community by the build; these are the fallbacks. */
  --primary: #192f5e;
  --secondary: #507060;
  --primary-soft: color-mix(in srgb, var(--primary) 72%, #fff);
  /* The wash behind a chosen segment of a pill control. Derived from the community's own
     primary rather than fixed, so a town whose colour is not navy gets its own tint. */
  --pill-active: color-mix(in srgb, var(--primary) 8%, #fff);
  --ink: #14161a;
  --ink-2: #4a5160;
  --ink-3: #7c8395;
  --paper: #faf8f4;
  --paper-2: #f2efe8;
  --rule: #ddd8cd;
  --rule-strong: #c6bfaf;
  --ins: #2f6b3a;
  --ins-bg: #e6f2e6;
  --del: #a32b2b;
  --del-bg: #f7e8e6;
  --measure: 64ch;
  --rail: 21rem;
  --margin: 20rem;
  --font: 'Roboto', system-ui, sans-serif;
  --cond: 'Roboto Condensed', 'Arial Narrow', sans-serif;
}

/* There was a third face here, monospaced, carrying everything on the site that is not
   prose: section numbers, schedule figures, and the small labels that name them. It made a
   page of law look like a page of code. The two jobs it was actually doing come apart
   cleanly, and neither of them needs a monospaced face to do it: figures need their digits
   to line up, which is `font-variant-numeric: tabular-nums` in any face carrying a tabular
   set — Roboto does — and labels need to look unlike the sentence beside them, which is
   what the condensed face was already for. Nothing on this site is set in mono. */

*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; scroll-padding-top: 5.5rem; }

body {
  margin: 0;
  /* A single long token — a URL in a citation, a wide table — must never widen the page
     and set every line of prose scrolling sideways. */
  overflow-x: clip;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--primary); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--primary-soft); }
:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* ── masthead ─────────────────────────────────────────────────────────────── */

.masthead {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: 1.25rem;
  padding: 0.6rem clamp(1rem, 4vw, 2.5rem);
  background: var(--primary); color: #fff;
  border-bottom: 3px solid var(--secondary);
}
.masthead-main { display: flex; align-items: center; gap: 0.75rem; min-width: 0; }
.brand { display: flex; align-items: center; gap: 0.45rem; color: #fff; text-decoration: none; min-width: 0; }
.brand-town { font-family: var(--cond); font-weight: 700; font-size: 1.05rem; letter-spacing: 0.01em; }
.brand-sep { color: #ffffff66; }
.brand-what { font-family: var(--cond); font-weight: 300; font-size: 1.05rem; }
.topnav { display: flex; align-items: center; gap: 1.25rem; margin-left: auto; }
.topnav a {
  color: #dfe6f2; text-decoration: none; font-size: 0.85rem;
  padding-bottom: 2px; border-bottom: 2px solid transparent;
}
.topnav a:hover, .topnav a.is-on { color: #fff; border-bottom-color: var(--secondary); }

/* ── banner ───────────────────────────────────────────────────────────────── */

.banner {
  padding: 0.85rem clamp(1rem, 4vw, 2.5rem);
  font-size: 0.92rem; line-height: 1.5;
  border-bottom: 1px solid var(--rule);
}
.banner-proposed { background: #fdf6d9; border-bottom-color: #e6d89a; }
.banner a { margin-left: 0.35rem; white-space: nowrap; }

/* ── layout ───────────────────────────────────────────────────────────────── */

.layout { display: grid; grid-template-columns: var(--rail) minmax(0, 1fr); align-items: start; }
@media (min-width: 1180px) {
  .layout { grid-template-columns: var(--rail) minmax(0, 1fr) var(--margin); }
}

.rail {
  position: sticky; top: 3.6rem; align-self: start;
  height: calc(100vh - 3.6rem); overflow: hidden;
  background: var(--paper-2); border-right: 1px solid var(--rule);
}
.rail-inner { height: 100%; overflow-y: auto; padding: 1.25rem 0 4rem; }
.rail-head {
  padding: 0 1.25rem 0.75rem; font-family: var(--cond); font-weight: 700;
  font-size: 1rem; color: var(--primary);
}
.rail-head span { display: block; font-weight: 300; color: var(--ink-2); }
.filterbox { position: relative; margin: 0 1.25rem 0.75rem; }
.filter {
  width: 100%; max-width: 100%; margin: 0;
  padding: 0.4rem 1.85rem 0.4rem 0.6rem; font: inherit; font-size: 0.85rem;
  background: #fff; border: 1px solid var(--rule-strong); border-radius: 2px;
  -webkit-appearance: none; appearance: none;
}
/* Safari and Chrome put their own cross in a type=search box, but only while it has
   focus, and it clears the box without dismissing the results — ours holds the gesture. */
.filter::-webkit-search-cancel-button { display: none; }
.filter-clear {
  position: absolute; top: 50%; right: 0.3rem; transform: translateY(-50%);
  display: flex; align-items: center; justify-content: center;
  width: 1.3rem; height: 1.3rem; padding: 0;
  font: inherit; font-size: 1.05rem; line-height: 1; color: var(--ink-3);
  background: none; border: 0; border-radius: 2px; cursor: pointer;
}
.filter-clear:hover { color: var(--primary); background: var(--paper-2); }
.filter-clear[hidden] { display: none; }

.toc { list-style: none; margin: 0; padding: 0; }

/* Search results, in the rail where the contents were. A result has to show enough of
   the provision to be judged without opening it — the citation alone is no better than
   the table of contents this replaces. */
.results { padding: 0 0 2rem; }
.results-count, .results-none {
  margin: 0 1.25rem 0.5rem; font-size: 0.76rem; color: var(--ink-3);
}
.result {
  display: block; padding: 0.5rem 1.25rem; text-decoration: none; color: var(--ink-2);
  border-top: 1px solid var(--rule);
}
.result:hover { background: #fff; }
/* The result the reader followed, marked because the list stays up behind them. */
.result.is-current { background: #fff; box-shadow: inset 3px 0 0 var(--primary); }
.result.is-current .result-cite { font-weight: 700; }
.result-cite {
  display: block; font-family: var(--font); font-variant-numeric: tabular-nums; font-size: 0.74rem; color: var(--primary);
  margin-bottom: 0.15rem;
}
.result[data-kind="definition"] .result-cite { font-family: var(--cond); font-weight: 700; }
.result-text { display: block; font-size: 0.78rem; line-height: 1.45; }
.result mark { background: color-mix(in srgb, var(--secondary) 28%, #fff); color: inherit; }
.toc-art {
  padding: 1rem 1.25rem 0.3rem; font-family: var(--cond); font-size: 0.78rem;
  color: var(--ink-3); border-top: 1px solid var(--rule); margin-top: 0.5rem;
}
.toc-art span { color: var(--primary); font-weight: 700; }
.toc-sec a {
  display: grid; grid-template-columns: 4.3rem 1fr; gap: 0.4rem;
  padding: 0.28rem 1.25rem; font-size: 0.85rem; line-height: 1.35;
  color: var(--ink-2); text-decoration: none;
}
.toc-sec a:hover { background: #fff; color: var(--primary); }
.toc-sec.is-target a { background: #fff; color: var(--primary); box-shadow: inset 3px 0 0 var(--primary); }
.toc-num { font-family: var(--font); font-variant-numeric: tabular-nums; font-size: 0.76rem; color: var(--ink-3); }
.toc-sec.is-changed .toc-num::after { content: '●'; margin-left: 0.3rem; color: var(--ins); font-size: 0.6rem; }
.toc-sec[hidden] { display: none; }

.doc { padding: 2.5rem clamp(1rem, 5vw, 4rem) 6rem; max-width: 62rem; min-width: 0; }
.doc-title {
  font-family: var(--cond); font-weight: 300; font-size: clamp(2rem, 5vw, 3.1rem);
  line-height: 1.08; margin: 0 0 2.5rem; color: var(--primary);
}
.eyebrow {
  display: block; font-family: var(--cond); font-variant-numeric: tabular-nums; font-size: 0.72rem; font-weight: 500;
  letter-spacing: 0.08em; color: var(--ink-3); margin-bottom: 0.6rem;
}

/* ── article + section ────────────────────────────────────────────────────── */

.art {
  display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap;
  margin: 3.5rem 0 1.5rem; padding-top: 1rem;
  border-top: 2px solid var(--primary);
  font-family: var(--cond); font-weight: 300; font-size: 1.5rem; color: var(--primary);
}
/* Number and title share the heading's size; only weight and case distinguish them. */
.art-num { font-family: var(--cond); font-size: 1em; font-weight: 700; color: var(--primary); }
.art-title { font-size: 1em; font-weight: 300; }
.art:first-of-type { margin-top: 0; }

.sec { margin: 0 0 2.75rem; scroll-margin-top: 5.5rem; }
.sec-head {
  display: flex; align-items: baseline; gap: 0.65rem; flex-wrap: wrap;
  margin: 0 0 0.6rem; font-size: 1.12rem; font-weight: 700; line-height: 1.35;
}
.sec-num { font-family: var(--font); font-variant-numeric: tabular-nums; font-size: 1em; font-weight: 500; color: var(--primary); }
.sec-title { font-size: 1em; color: var(--ink); }
.sec:target .sec-num {
  background: color-mix(in srgb, var(--secondary) 22%, #fff);
  box-shadow: inset 0 -2px 0 var(--secondary); padding: 0 0.25rem;
}
.sec-body > .prov:first-child { margin-top: 0; }

.badge {
  font-family: var(--font); font-variant-numeric: tabular-nums; font-size: 0.68rem; text-decoration: none;
  color: var(--ins); background: var(--ins-bg);
  border: 1px solid #bcd8bc; border-radius: 2px; padding: 0.05rem 0.35rem;
}

.history {
  font-size: 0.8rem; color: var(--ink-3); font-style: italic;
  margin: 0.15rem 0 0.75rem;
}

/* The classes of district, and lists like it: the source marks them up as one-cell tables.
   Set as a list, with room for each entry's history to appear under it. */
.blocklist { list-style: none; margin: 0.6rem 0 1rem; padding: 0; }
.blocklist > li {
  padding: 0.18rem 0 0.18rem 1rem; position: relative;
}
.blocklist > li::before {
  content: ""; position: absolute; left: 0.15rem; top: 0.78em;
  width: 4px; height: 4px; border-radius: 50%; background: var(--rule-strong);
}
body.show-history .blocklist > li { padding-bottom: 0.1rem; }
body.show-history .blocklist .hist { margin: 0.1rem 0 0.5rem; }
/* A category heading inside the list — "Overlay Districts" over the overlays it groups.
   No bullet, and set apart from the entries above and below it. */
.blocklist > li.blocklist-head {
  padding-left: 0; margin-top: 0.7rem; font-weight: 600; color: var(--primary);
}
.blocklist > li.blocklist-head::before { content: none; }
.blocklist > li.blocklist-head:first-child { margin-top: 0; }

.chips { display: flex; flex-wrap: wrap; gap: 0.35rem; margin: 0 0 0.9rem; }
.chip {
  font-size: 0.74rem; text-decoration: none; color: var(--ink);
  padding: 0.1rem 0.5rem 0.1rem 0.45rem; border-radius: 999px;
  background: color-mix(in srgb, var(--chip) 22%, #fff);
  border: 1px solid color-mix(in srgb, var(--chip) 55%, #fff);
}
.chip:hover { background: color-mix(in srgb, var(--chip) 40%, #fff); }

/* ── provisions: the number hangs in the gutter ───────────────────────────── */

/* The gutter is sized from the document's own longest marker, measured at build time and
   set as --num-w. It was a fixed 3.1rem, which fits `240-4.5` and clips `11.4.16`; every
   code numbers differently and several run deeper than three levels. */
/* The gaps compound. A top-level provision, three subsections, four paragraphs under one of
   them: at 0.85/0.6rem apiece the deepest rung sat further from the sentence it qualifies
   than from the next provision along, and a screen of § 6.1 held about a third as much text
   as the page it came from. Each level is tighter than the one above it now, so depth reads
   as belonging rather than as distance. */
/* The marker sits on the same baseline as the first line of the provision it numbers. It is
   set smaller than the body, so its line box is shorter; aligned to the top of the row its
   baseline landed several pixels high and `a.` read as a superscript over `historically part
   of a mill complex`. `baseline` aligns the two by their first baselines instead, so the pair
   stays locked whatever the marker's size — including the smaller one the narrow breakpoint
   sets. The old `padding-top` nudge was an approximation of this and is gone. */
.prov { display: grid; grid-template-columns: var(--num-w, 3.1rem) minmax(0, 1fr);
        align-items: baseline; margin: 0.6rem 0; }
.prov-num {
  font-family: var(--font); font-variant-numeric: tabular-nums; font-size: 0.8rem; color: var(--primary);
  padding-right: 0.5rem; user-select: none;
  /* A marker is one token and must never break across lines — "(11)" split to "(11" over ")"
     when the gutter was too narrow. The gutter is sized to the longest marker instead. */
  white-space: nowrap;
}
.prov-body { max-width: min(var(--measure), 100%); min-width: 0; }
.prov .prov-body > p { margin: 0.4rem 0; }
/* The first paragraph opens flush with its marker and the last one closes flush with the
   provision, so the gap between provisions is the provision's own margin and not that plus a
   paragraph's. These have to out-specify `.prov .prov-body > p` above: written as a bare
   `.prov-body > p:first-child` they tie it on specificity, lose on source order, and every
   nested provision — nearly all of them — got 0.4rem of margin above its first line that the
   marker beside it did not, which is what pushed the two apart. */
.prov-body > p:first-child,
.prov .prov-body > p:first-child { margin-top: 0; }
.prov-body > p:last-child,
.prov .prov-body > p:last-child { margin-bottom: 0; }
/* A nested provision's marker is short — `1.`, `A.`, `(a)` — so it gets a fraction of the
   top-level gutter. Giving every level the width the longest top-level number needs
   compounds: three levels of a 4.8rem gutter left the text in a ten-character column. */
.prov .prov { margin: 0.34rem 0; grid-template-columns: var(--num-w-nested, 2.2rem) minmax(0, 1fr); }
/* And it stops growing after that, whatever the source nests — but still wide enough for a
   two-digit marker so it never wraps. */
.prov .prov .prov { margin: 0.22rem 0; grid-template-columns: 2.2rem minmax(0, 1fr); }
/* The change bar runs the full height of the provision, so it has to be drawn against the
   provision box rather than the marker. As an inset shadow on the marker it was as tall as
   the marker only because the marker stretched to fill the row; baseline alignment sizes the
   marker to its own text, which would have left a two-character stub of a bar. Drawn here it
   also composes with the commenting fill, which is a box-shadow on this same element. */
.prov.is-changed { position: relative; }
.prov.is-changed > .prov-num::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 2px; background: var(--ins);
}

/* A section title the draft rewrites. There is no <ins> to mark inside it — the heading is
   title-cased out of shouted source, so no run of it survives to carry one — and the redline
   would otherwise show the new wording with nothing to say it is new. The same rule the
   contents list uses for an amended section, applied to the title itself. */
.sec-title.is-changed { text-decoration: underline; text-decoration-color: var(--ins);
                        text-decoration-thickness: 2px; text-underline-offset: 4px; }

/* A repealed provision. The number is kept so a citation to it still lands somewhere,
   but what remains is a note about a repeal, not law in force — so it is set as
   apparatus, the way the amendment history is. */
/* A list of one keeps its place in the tree but publishes no marker, so the gutter that
   would hold the marker collapses rather than leaving a blank column of it.

   One column, not a zero-width one beside a full one: the marker is `display: none`, so it
   leaves the grid entirely and the body becomes the *first* item — against two columns it
   landed in the narrow one and set the wording a character wide. And the selector has to
   answer `.prov .prov`, which is more specific than a lone class and was overriding this
   for every nested one, which is nearly all of them. */
.prov--unnumbered,
.prov .prov--unnumbered,
.prov .prov .prov--unnumbered { grid-template-columns: minmax(0, 1fr); }
.prov--unnumbered > .prov-num { display: none; }
.prov.is-removed > .prov-num { color: var(--ink-3); }
.prov.is-removed > .prov-body { color: var(--ink-3); font-size: 0.92rem; }
.prov.is-removed > .prov-body > p { font-style: italic; }
.prov.is-removed > .prov-body .xref { font-style: normal; }

p { margin: 0.7rem 0; overflow-wrap: anywhere; }
.sec-body > p, .sec-body > .definition p { max-width: min(var(--measure), 100%); }

dfn {
  font-style: normal; font-weight: 700; font-family: var(--cond);
  letter-spacing: 0.01em; color: var(--primary);
}
.definition {
  margin: 0.55rem 0; padding-left: 0.9rem;
  border-left: 2px solid var(--rule-strong);
}
.definition p { margin: 0.35rem 0; }
/* A run of entries reads as one block, so it is spaced tightly inside — and it was spaced
   the same on the way out, which left § 2.2's hundred and thirteen entries and § 4.8.7.C's
   nine running straight into the provision after them with nothing to say the glossary had
   ended. The gap belongs after the run rather than after every entry, so it goes on
   whatever follows the last one. */
.definition + :not(.definition) { margin-top: 1.9rem; }

/* An illustration. Line diagrams, drawn small: shown at their own size and no larger,
   because scaling them up to the column width only softens the lines. */
figure.illus { margin: 0.9rem 0; max-width: 100%; }
figure.illus img {
  display: block; max-width: 100%; height: auto;
  background: #fff; border: 1px solid var(--rule); padding: 0.6rem;
}
figure.illus figcaption {
  margin-top: 0.35rem; font-family: var(--cond); font-size: 0.78rem; color: var(--ink-3);
}
.definition figure.illus { margin-left: 0; }

.xref { text-decoration-style: dotted; }
.statref::after { content: '↗'; font-size: 0.7em; vertical-align: super; margin-left: 0.1em; opacity: 0.6; }

ins { background: var(--ins-bg); color: var(--ins); text-decoration: none; border-bottom: 1px solid var(--ins); }
del { background: var(--del-bg); color: var(--del); }

/* ── tables ───────────────────────────────────────────────────────────────── */

.table-scroll { overflow-x: auto; max-width: 100%; margin: 1rem 0; border: 1px solid var(--rule); background: #fff; -webkit-overflow-scrolling: touch; }
.code-table td > p, .code-table th > p { margin: 0.15rem 0; }
.code-table { border-collapse: collapse; font-size: 0.85rem; min-width: 100%; }
/* A table is its own division now, so it carries an anchor and a comment station. The
   figure adds nothing visually -- the scroller inside keeps doing that work -- so it must
   not add margins of its own on top of the paragraph spacing around it. */
.codetable { margin: 0; scroll-margin-top: 1.5rem; }
.codetable:target > .table-scroll { outline: 2px solid var(--primary); outline-offset: 3px; }
.code-table td {
  border-bottom: 1px solid var(--rule); border-right: 1px solid var(--rule);
  padding: 0.35rem 0.6rem; vertical-align: top;
}
.code-table tr:first-child td { background: var(--paper-2); font-weight: 700; }
/* A table is its own division now, so it carries an anchor and a comment station. The
   figure adds nothing visually -- the scroller inside keeps doing that work -- so it must
   not add margins of its own on top of the paragraph spacing around it. */
.codetable { margin: 0; scroll-margin-top: 1.5rem; }
.codetable:target > .table-scroll { outline: 2px solid var(--primary); outline-offset: 3px; }
.code-table td { overflow-wrap: anywhere; }
.code-table p { margin: 0; }

/* The Code Comparative Table: three columns, of which two are citations and one is prose.
   The citations set the width of their own columns and never wrap — a former section
   number broken across two lines is unreadable as a number — and the topic takes what is
   left. Its row headers are the former numbers, so they are not given the shaded header
   treatment that `.code-table th` carries: shading a whole column reads as a header for
   the rows to its right, which it is not. */
.comparative { font-size: 0.82rem; }
.comparative thead th { white-space: nowrap; }
.comparative tbody th {
  background: none; font-weight: 500; white-space: nowrap;
  font-variant-numeric: tabular-nums; color: var(--ink-2);
}
.comparative td:last-child { white-space: nowrap; font-variant-numeric: tabular-nums; }
.comparative td:nth-child(2) { width: 100%; overflow-wrap: normal; }
.comparative tbody tr:nth-child(even) { background: var(--paper); }
.backmatter-note { margin-top: 1rem; font-size: 0.82rem; color: var(--ink-2); }

/* ── home ─────────────────────────────────────────────────────────────────── */

.home { max-width: 68rem; margin: 0 auto; padding: 0 clamp(1rem, 5vw, 2.5rem) 6rem; }
.hero { padding: clamp(3rem, 9vw, 6rem) 0 3rem; border-bottom: 1px solid var(--rule); }
.hero h1 {
  font-family: var(--cond); font-weight: 300; font-size: clamp(2.4rem, 7vw, 4.5rem);
  line-height: 1.03; margin: 0 0 1.25rem; color: var(--primary);
}
.lede { font-size: 1.1rem; color: var(--ink-2); max-width: 42rem; margin: 0 0 2rem; }
.cta { display: flex; gap: 0.6rem; flex-wrap: wrap; }
.btn {
  display: inline-block; padding: 0.55rem 1.1rem; text-decoration: none;
  border: 1px solid var(--primary); color: var(--primary); background: transparent;
  font-size: 0.92rem; border-radius: 2px;
}
.btn:hover { background: #fff; }
.btn-primary { background: var(--primary); color: #fff; }
.btn-primary:hover { background: var(--primary-soft); color: #fff; }
.stamp { font-family: var(--cond); font-variant-numeric: tabular-nums; font-size: 0.75rem; color: var(--ink-3); margin-top: 1.75rem; }

.panel { padding: 3rem 0; border-bottom: 1px solid var(--rule); }
.panel h2 { font-family: var(--cond); font-weight: 300; font-size: 1.9rem; margin: 0 0 0.4rem; color: var(--primary); }
.panel-note { color: var(--ink-2); max-width: 42rem; margin: 0 0 1.5rem; }

.dcards { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: 0.6rem; }
.dcard {
  display: grid; grid-template-columns: 0.5rem 1fr; gap: 0 0.75rem;
  padding: 0.75rem 0.9rem; text-decoration: none; color: var(--ink);
  background: #fff; border: 1px solid var(--rule);
}
.dcard:hover { border-color: var(--primary); }
.dcard-swatch { grid-row: span 2; background: var(--chip); border-radius: 1px; }
.dcard-name { font-weight: 500; }
.dcard-meta { font-family: var(--cond); font-variant-numeric: tabular-nums; font-size: 0.72rem; color: var(--ink-3); }
.caveat { margin-top: 1rem; padding-left: 1.1rem; color: var(--ink-3); font-size: 0.85rem; }

.changed { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.changed a {
  font-family: var(--font); font-variant-numeric: tabular-nums; font-size: 0.8rem; text-decoration: none;
  padding: 0.25rem 0.55rem; background: #fff; border: 1px solid var(--rule); color: var(--primary);
}
.changed a:hover { border-color: var(--primary); }

/* ── map ──────────────────────────────────────────────────────────────────── */

/* The label faces the CommunityScale basemap asks MapLibre for.
 *
 * The style carries no `glyphs` URL on purpose: MapLibre draws its type from the page's own
 * web fonts instead of a glyph server, which is what keeps the label stack identical across
 * the atlas, the dashboards and this site. The families are named separately from the page's
 * own Roboto because MapLibre selects a face by family name, not by weight. Served from the
 * atlas, which answers with `access-control-allow-origin: *`.
 * Roboto is licensed under Apache-2.0. */
@font-face {
  font-family: 'Roboto Regular';
  src: url('https://maps.communityscale.io/assets/fonts/Roboto-Regular.ttf') format('truetype');
  font-style: normal; font-weight: 400; font-display: block;
}
@font-face {
  font-family: 'Roboto Medium';
  src: url('https://maps.communityscale.io/assets/fonts/Roboto-Medium.ttf') format('truetype');
  font-style: normal; font-weight: 500; font-display: block;
}
@font-face {
  font-family: 'Roboto Bold';
  src: url('https://maps.communityscale.io/assets/fonts/Roboto-Bold.ttf') format('truetype');
  font-style: normal; font-weight: 700; font-display: block;
}

.maplayout { display: grid; grid-template-columns: minmax(0, 1fr) 25rem; height: calc(100vh - 3.6rem); }
#map { height: 100%; position: relative; }
.map-down { padding: 3rem 1.5rem; color: var(--ink-2); font-size: 0.95rem; max-width: 32rem; }

/* ── map controls ─────────────────────────────────────────────────────────── */

.mapctl {
  position: absolute; left: 0.6rem; top: 0.6rem; z-index: 5;
  width: max-content; max-width: calc(100% - 1.2rem);
  background: #fffffff2; backdrop-filter: blur(3px);
  border: 1px solid var(--rule); border-radius: 3px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.12);
  padding: 0.4rem 0.55rem;
}
.mapctl-row {
  display: flex; align-items: center; gap: 0.4rem;
  font-size: 0.74rem; color: var(--ink); cursor: pointer; padding: 0.12rem 0;
}
.mapctl-row input { accent-color: var(--primary); margin: 0; }
.mapctl-head {
  margin: 0.5rem 0 0.25rem; font-family: var(--cond); font-size: 0.66rem;
  letter-spacing: 0.04em; color: var(--ink-3);
}
.mapctl-seg { display: flex; flex-direction: column; align-items: stretch; }
/* Adopted against proposed is a choice between two readings of one map, and it is set the
   way the app sets the same kind of choice on the affordability chart: one outlined group,
   the current segment washed and lettered in the brand colour rather than reversed out of
   it. The rule between the segments belongs to the group, so the shape holds whether the
   pair stacks or sits side by side. */
.mapctl-pills {
  display: flex; flex-direction: column;
  border: 1px solid var(--rule); border-radius: 8px; overflow: hidden;
}
.mapctl-pills button {
  font: inherit; font-size: 0.72rem; font-weight: 500; text-align: center; cursor: pointer;
  padding: 0.28rem 0.8rem; color: var(--ink-2); background: transparent; border: 0;
}
.mapctl-pills button + button { border-top: 1px solid var(--rule); }
.mapctl-pills button:hover { background: var(--paper-2); }
.mapctl-pills button.is-on {
  background: var(--pill-active); color: var(--primary); font-weight: 700;
  /* The border is recoloured rather than thickened, so the group does not shift by a pixel
     as the choice moves. */
  box-shadow: inset 0 0 0 1px var(--primary);
}
/* "Comment on a place" is not one of a set of readings — it starts something, and the map
   changes under the reader when it does. A filled button against the outlined pair above
   it, so the difference between choosing and doing is visible before either is used. */
.mapctl-pin {
  display: block; width: 100%; margin-top: 0.55rem;
  font: inherit; font-size: 0.74rem; font-weight: 600; cursor: pointer;
  padding: 0.36rem 0.5rem; color: #fff; background: var(--primary);
  border: 1px solid var(--primary); border-radius: 3px;
}
.mapctl-pin:hover { filter: brightness(1.12); }
.mapctl-pin.is-on {
  background: var(--secondary); border-color: var(--secondary); color: #fff;
}

/* ── address search ───────────────────────────────────────────────────────── */

/* Top center, clear of the toolbar (top left) and the zoom/basemap controls (top
   right) — the one open edge of the map at every width. */
.mapsearch {
  position: absolute; top: 0.6rem; left: 50%; transform: translateX(-50%); z-index: 5;
  width: min(21rem, calc(100% - 7.5rem));
}
.mapsearch-input {
  width: 100%; box-sizing: border-box; font: inherit; font-size: 0.82rem;
  padding: 0.45rem 0.7rem; color: var(--ink);
  background: #fffffff2; backdrop-filter: blur(3px);
  border: 1px solid var(--rule); border-radius: 3px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.12);
}
.mapsearch-input::placeholder { color: var(--ink-3); }
.mapsearch-input:focus { outline: 2px solid var(--primary); outline-offset: 1px; }
.mapsearch-results {
  margin-top: 0.3rem; max-height: 60vh; overflow-y: auto;
  background: #fffffff2; backdrop-filter: blur(3px);
  border: 1px solid var(--rule); border-radius: 3px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.12);
}
.mapsearch-result {
  display: block; width: 100%; text-align: left; font: inherit; font-size: 0.8rem;
  padding: 0.4rem 0.7rem; color: var(--ink); background: none;
  border: 0; border-bottom: 1px solid var(--rule); cursor: pointer;
}
.mapsearch-result:last-child { border-bottom: 0; }
.mapsearch-result:hover { background: var(--paper-2); }
.mapsearch-none { margin: 0; padding: 0.5rem 0.7rem; font-size: 0.78rem; color: var(--ink-3); }

/* ── comment pins ─────────────────────────────────────────────────────────── */

/* A teardrop rather than a dot: on a map already full of colored areas a circle reads as
   another piece of data, and this is the reader's own mark on it.

   The shape is on an inner element on purpose. MapLibre writes its own `transform` onto the
   marker element on every frame to position it, so a `rotate()` set here is overwritten and
   the teardrop comes out a circle. */
.mappin { display: block; width: 1.1rem; height: 1.35rem; cursor: pointer; }
.mappin i {
  display: block; width: 1.1rem; height: 1.1rem;
  background: var(--primary); border: 2px solid #fff;
  border-radius: 50% 50% 50% 0; transform: rotate(-45deg);
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.5);
}
.mappin-new i { background: var(--secondary); }
body.is-pinning .maplibregl-canvas { cursor: crosshair; }
.mappanel { overflow-y: auto; background: var(--paper-2); border-left: 1px solid var(--rule); padding: 1.5rem; }
.panel-empty h2 { font-family: var(--cond); font-weight: 300; font-size: 1.6rem; color: var(--primary); margin: 0 0 0.5rem; }
.panel-empty p { color: var(--ink-2); font-size: 0.92rem; }
.pd-title { font-family: var(--cond); font-weight: 700; font-size: 1.4rem; color: var(--primary); margin: 0 0 0.15rem; }
.pd-sub { font-family: var(--cond); font-variant-numeric: tabular-nums; font-size: 0.75rem; color: var(--ink-3); margin: 0 0 1.25rem; }
.pd-h { font-family: var(--cond); font-size: 0.95rem; font-weight: 700; margin: 1.5rem 0 0.5rem; color: var(--ink); }
/* The citation sits in the same left gutter the list of governing sections uses, so the
   panel cites a heading the one way rather than two. Under the table it read as a footnote
   to the last row of figures. */
.pd-h .n { font-variant-numeric: tabular-nums; font-size: 0.75rem; font-weight: 400;
  color: var(--ink-3); margin-right: 0.5rem; }
/* The district's code, at the weight of a name. It is the identifier a reader carries
   between the map, the legend and the schedule, and it was set as a footnote. */
.pd-code { font-family: var(--cond); font-weight: 700; font-size: 1rem;
  letter-spacing: 0.04em; color: var(--primary); margin: 0 0 1.25rem; }
.pd-code .pd-aka { font-weight: 400; letter-spacing: 0; font-size: 0.8rem;
  color: var(--ink-3); }
.pd-dim { width: 100%; border-collapse: collapse; font-size: 0.82rem; background: #fff; }
.pd-dim th, .pd-dim td { text-align: left; padding: 0.3rem 0.5rem; border-bottom: 1px solid var(--rule); }
.pd-dim th { font-weight: 400; color: var(--ink-2); }
.pd-dim td { font-family: var(--font); font-variant-numeric: tabular-nums; font-size: 0.78rem; text-align: right; }
/* A district that regulates one use differently from another is answering the same question
   twice, and the reader's question is what the difference is. That is a comparison across
   the row, so the use categories are columns of one table rather than a stack of separate
   ones. Ten of Lowell's eighteen districts carry more than one. */
.pd-dim-multi thead th {
  text-align: right; vertical-align: bottom; font-weight: 500; font-size: 0.71rem;
  line-height: 1.25; color: var(--ink-3); padding-bottom: 0.3rem;
}
/* The row-heading column is the widest thing in the table and the figures are what the eye
   is tracking, so the headings take a fixed share and the use columns divide what is left
   equally. `fixed` rather than auto: under auto the last column got only the width its own
   content needed, so "All other uses" broke onto three lines beside two columns that had
   room to spare. Checked against the widest value in any multi-use district, Side Yard's
   "10 SUM 25", which fits with room at this share. */
.pd-dim-multi { table-layout: fixed; }
.pd-dim-multi tbody th { width: 38%; }
.pd-dim-multi td { white-space: nowrap; }
/* A defined term in a panel heading, linked to the glossary on the chapter page. Marked like
   `.tref` so the underline means the same thing everywhere, but it navigates rather than
   summoning a card: the definition is on another page, and the pointer says so. */
.dref {
  color: inherit;
  text-decoration-line: underline;
  text-decoration-style: solid;
  text-decoration-thickness: 1px;
  text-decoration-color: color-mix(in srgb, var(--secondary) 50%, transparent);
  text-underline-offset: 0.16em;
}
.dref:hover, .dref:focus-visible {
  color: inherit;
  text-decoration-color: var(--secondary);
  background: color-mix(in srgb, var(--secondary) 12%, transparent);
}
.pd-list { list-style: none; margin: 0; padding: 0; }
.pd-list a { display: block; padding: 0.3rem 0; font-size: 0.86rem; text-decoration: none; border-bottom: 1px solid var(--rule); }
.pd-list a:hover { background: #fff; }
.pd-list .n { font-family: var(--font); font-variant-numeric: tabular-nums; font-size: 0.75rem; color: var(--ink-3); margin-right: 0.5rem; }
/* What the district does with each use. A table rather than a run of lines, set like the
   dimensional standards above it, because the reader's question is which of these they may
   do here and that is a question about the column, not about any one row. */
.pd-uses { width: 100%; border-collapse: collapse; font-size: 0.8rem; background: #fff; }
.pd-uses th, .pd-uses td {
  text-align: left; padding: 0.3rem 0.5rem; vertical-align: middle;
  border-bottom: 1px solid var(--rule);
}
.pd-uses th { font-weight: 400; color: var(--ink-2); }
/* Narrow, right-aligned and never wrapped, so the values line up as a column a reader can
   run their eye down. "SP" broken over two lines is not a value. */
.pd-uses td.v {
  width: 3.4rem; text-align: right; white-space: nowrap;
  font-weight: 700; color: var(--primary);
}
.pd-uses tr:hover th, .pd-uses tr:hover td { background: var(--paper-2); }
.maplegend {
  position: absolute; left: 0.6rem; bottom: 0.6rem; z-index: 5; max-width: min(17rem, calc(100% - 1.2rem));
  background: #fffffff2; backdrop-filter: blur(3px);
  border: 1px solid var(--rule); border-radius: 3px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.12);
  overflow: hidden;
}
.maplegend-toggle {
  display: flex; align-items: center; gap: 0.35rem; width: 100%;
  font: inherit; font-size: 0.74rem; font-weight: 500; cursor: pointer;
  padding: 0.35rem 0.6rem; color: var(--primary); background: none; border: 0;
}
.maplegend-toggle::before { content: '▸'; font-size: 0.7em; color: var(--ink-3); }
.maplegend.is-open .maplegend-toggle::before { content: '▾'; }
.maplegend-toggle span {
  font-family: var(--cond); font-variant-numeric: tabular-nums; font-size: 0.68rem; color: var(--ink-3);
}
.maplegend-items { display: none; max-height: 42vh; overflow-y: auto; padding: 0 0.35rem 0.35rem; }
.maplegend.is-open .maplegend-items { display: block; }
.maplegend-group {
  margin: 0.45rem 0 0.15rem; padding: 0 0.15rem;
  font-family: var(--cond); font-size: 0.66rem; letter-spacing: 0.04em;
  color: var(--ink-3);
}
.maplegend-group:first-child { margin-top: 0; }
.maplegend-item {
  display: flex; align-items: center; gap: 0.4rem; width: 100%;
  font: inherit; font-size: 0.72rem; text-align: left; cursor: pointer;
  padding: 0.16rem 0.25rem; color: var(--ink); background: none;
  border: 0; border-radius: 2px;
}
.maplegend-item:hover { background: var(--paper-2); }
.maplegend-item.is-active { background: var(--primary); color: #fff; }
.maplegend-item i {
  width: 0.7rem; height: 0.7rem; border-radius: 2px; flex: 0 0 auto;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.18);
}
.maplegend-item span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The layer switches sit together above the key, on one line where there is room for it.
   The rule under them belongs to the group rather than to either switch, so adding a second
   one does not add a second divider. */
.maplegend-switches {
  display: flex; flex-wrap: wrap; gap: 0.1rem 0.9rem;
  padding: 0.16rem 0.25rem 0.4rem;
  border-bottom: 1px solid var(--rule); margin-bottom: 0.3rem;
}
.maplegend-switch {
  display: flex; align-items: center; gap: 0.4rem;
  font-size: 0.72rem; color: var(--ink); cursor: pointer;
}

/* ── parcel popup ─────────────────────────────────────────────────────────── */

.parcel-popup { font-family: inherit; }
.parcel-popup-address {
  font-family: var(--cond); font-weight: 700; font-size: 0.86rem; color: var(--primary);
  margin: 0 0 0.5rem; line-height: 1.25;
}
.parcel-popup-row {
  display: flex; align-items: center; justify-content: space-between; gap: 0.6rem;
  font-size: 0.78rem; padding: 0.2rem 0; border-bottom: 1px solid var(--rule);
}
.parcel-popup-row:last-child { border-bottom: 0; }
.parcel-popup-label { color: var(--ink-3); }
.parcel-popup-link {
  font: inherit; font-family: var(--font); font-variant-numeric: tabular-nums; font-size: 0.76rem; color: var(--primary);
  background: none; border: 0; padding: 0; cursor: pointer; text-decoration: underline;
}
.parcel-popup-link:hover { color: var(--secondary); }
/* Same green the bylaw text itself uses for an insertion — a proposed zone is the same
   kind of thing, a change the amendment makes, so it reads as one visual language. */
.parcel-popup-row--proposed .parcel-popup-label,
.parcel-popup-row--proposed .parcel-popup-link { color: var(--ins); }
.parcel-popup-tag {
  display: inline-block; margin-left: 0.4rem; padding: 0.05rem 0.4rem; border-radius: 2px;
  font-family: var(--cond); font-variant-numeric: tabular-nums; font-size: 0.62rem; font-weight: 400; text-transform: uppercase;
  letter-spacing: 0.03em; color: var(--ins); background: var(--ins-bg); vertical-align: middle;
}

/* ── footer ───────────────────────────────────────────────────────────────── */

.foot {
  padding: 2.5rem clamp(1rem, 5vw, 4rem); border-top: 1px solid var(--rule);
  color: var(--ink-2); font-size: 0.85rem; background: var(--paper-2);
}
.foot p { margin: 0.3rem 0; max-width: 46rem; }
.foot-meta { color: var(--ink-3); font-size: 0.8rem; }

/* ── responsive ───────────────────────────────────────────────────────────── */

@media (max-width: 60rem) {
  .layout { grid-template-columns: 1fr; }
  .rail {
    position: static; height: auto; overflow: visible;
    border-right: 0; border-bottom: 1px solid var(--rule);
  }
  .rail-inner { max-height: 60vh; }
  .doc { padding-top: 1.75rem; }
  .maplayout { grid-template-columns: 1fr; height: auto; }
  #map { height: 62vh; }
  .mappanel { border-left: 0; border-top: 1px solid var(--rule); max-height: none; }
  body.rail-collapsed .layout { grid-template-columns: 1fr; }
}

/* Phones. The masthead has to stay one compact bar rather than wrapping into four
   lines, the body has to give back the width the desktop reading measure assumes, and
   the contents rail has to stop standing between the reader and the bylaw. */
@media (max-width: 40rem) {
  body { font-size: 16px; line-height: 1.6; }

  /* One row cannot hold the town, three links and an account control without
     truncating all of them, so the navigation gets its own. */
  .masthead {
    flex-direction: column; align-items: stretch; gap: 0.4rem;
    padding: 0.45rem 0.85rem 0.35rem; border-bottom-width: 2px;
  }
  .masthead-main { justify-content: space-between; gap: 0.5rem; }
  .brand { gap: 0.4rem; }
  .brand-town { display: none; }
  .brand-town-short { display: inline; }
  .brand-town-short, .brand-what { font-size: 0.95rem; white-space: nowrap; }
  .brand-logo { height: 1.5rem; }
  .topnav {
    margin-left: 0; gap: 1rem; overflow-x: auto; scrollbar-width: none;
    border-top: 1px solid color-mix(in srgb, #fff 18%, transparent); padding-top: 0.3rem;
  }
  .topnav::-webkit-scrollbar { display: none; }
  .topnav a { font-size: 0.78rem; white-space: nowrap; padding-bottom: 1px; }
  .authbtn { font-size: 0.72rem; padding: 0.2rem 0.55rem; white-space: nowrap; }

  .banner { padding: 0.7rem 0.85rem; font-size: 0.85rem; }
  .controls { padding: 0.45rem 0.85rem; gap: 0.9rem; font-size: 0.78rem; }

  .doc { padding: 1.5rem 0.85rem 4rem; }
  .doc-title { margin-bottom: 1.5rem; }
  .rail-toggle { padding: 0.5rem 0.85rem; }
  .rail-head { padding: 0 0.85rem 0.6rem; }
  .filterbox { margin: 0 0.85rem 0.6rem; }
  .toc-art { padding: 0.8rem 0.85rem 0.25rem; }
  .toc-sec a { grid-template-columns: 3.9rem 1fr; padding: 0.3rem 0.85rem; }

  /* The gutter for a provision number costs a tenth of the screen on a phone — kept tight,
     but wide enough that a two-digit marker like "(11)" stays on one line. */
  .prov { grid-template-columns: 2.3rem minmax(0, 1fr); }
  .prov .prov { grid-template-columns: 2.3rem minmax(0, 1fr); }
  .prov-num { font-size: 0.75rem; }
  .sec { margin-bottom: 2rem; }
  .sec-head { gap: 0.4rem; font-size: 1rem; }

  .art { margin: 2.5rem 0 1.1rem; font-size: 1.25rem; }

  /* Tables scroll inside their own box; they never widen the page. */
  .table-scroll { margin: 0.8rem 0; }
  .code-table, .matrix { font-size: 0.78rem; }
  .code-table td, .code-table th, .matrix th, .matrix td { padding: 0.3rem 0.4rem; }
  .matrix tbody th { min-width: 11rem; }
  /* The header stays pinned on a narrow screen too: it is where the column headings are
     needed most, since less of the table is on screen at once. */
  .table-scroll { max-height: 66vh; }

  .foot { padding: 1.75rem 0.85rem; }
}

@media print {
  .masthead, .rail, .topnav, .foot, .badge { display: none; }
  body { background: #fff; font-size: 11pt; }
  .layout { display: block; }
  .sec { break-inside: avoid; }
}

/* A proposal drafted against superseded text — flagged in place, never silently shown. */
.banner-review { background: #fbeee6; border-bottom-color: #e2c3ab; }
.banner-review a { margin-left: 0.3rem; font-family: var(--font); font-variant-numeric: tabular-nums; font-size: 0.82rem; }
/* Document-level defects are listed rather than run together: each one is a
   separate decision for whoever picks them up. */
.banner-review ul { margin: 0.5rem 0 0; padding-left: 1.1rem; }
.banner-review li { margin: 0.2rem 0; }
.review-notice {
  margin: 0 0 1rem; padding: 0.7rem 0.9rem; max-width: var(--measure);
  background: #fbeee6; border-left: 3px solid #c2703a; font-size: 0.88rem; line-height: 1.5;
}
.review-notice strong { color: #9a5525; }

/* ── public comment: a margin gutter, the way a word processor does it ────── */

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* The marker in the section heading is the affordance — a count when there are
   comments, a pencil when there are none. */




.margin { position: relative; padding: 0 1rem 6rem 0; }
.mcard {
  position: absolute; top: 0; left: 0; width: calc(100% - 1rem);
  background: #fff; border: 1px solid var(--rule); border-radius: 2px;
  padding: 0.6rem 0.7rem; font-size: 0.82rem;
  transition: transform 0.18s ease, border-color 0.18s ease;
}
.mcard.is-empty { opacity: 0; pointer-events: none; }
.mcard.is-empty.is-active, .mcard:hover { opacity: 1; pointer-events: auto; }
.mcard.is-active { border-color: var(--primary); box-shadow: 0 1px 6px rgba(25, 47, 94, 0.12); }
.mcard-cite {
  margin: 0 0 0.4rem; font-family: var(--font); font-variant-numeric: tabular-nums; font-size: 0.7rem; color: var(--ink-3);
}

.comment { margin: 0 0 0.6rem; padding-bottom: 0.5rem; border-bottom: 1px solid var(--paper-2); }
.comment:last-of-type { border-bottom: 0; }
.comment-meta { display: flex; gap: 0.4rem; align-items: baseline; flex-wrap: wrap; margin: 0 0 0.1rem; font-size: 0.72rem; }
.comment-author { font-weight: 500; }
.comment-when { color: var(--ink-3); font-family: var(--cond); font-variant-numeric: tabular-nums; font-size: 0.68rem; }
.comment-pending {
  font-size: 0.65rem; color: #9a5525; background: #fbeee6;
  border: 1px solid #e2c3ab; border-radius: 2px; padding: 0 0.25rem;
}
/* A comment the review team has settled, one way or the other. It reads as a fact about
   the comment rather than as something still wanting attention, so it drops the amber the
   waiting badge uses. */
.comment-pending.is-settled {
  color: var(--ink-3); background: var(--paper-2); border-color: var(--rule);
}
.comment-body { margin: 0; font-size: 0.82rem; line-height: 1.5; }
.comment.is-pending .comment-body { color: var(--ink-2); }

.comment-form textarea {
  width: 100%; font: inherit; font-size: 0.8rem; padding: 0.35rem 0.45rem;
  background: var(--paper); border: 1px solid var(--rule-strong); border-radius: 2px; resize: vertical;
}
.comment-actions { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.35rem; }
.comment-form button {
  font: inherit; font-size: 0.78rem; padding: 0.22rem 0.7rem; cursor: pointer;
  color: #fff; background: var(--primary); border: 1px solid var(--primary); border-radius: 2px;
}
.comment-form button:hover { background: var(--primary-soft); }
.comment-form button:disabled { opacity: 0.55; cursor: default; }
.comment-status { font-size: 0.72rem; color: var(--ink-2); }
.comment-note { margin: 0.3rem 0 0; font-size: 0.68rem; color: var(--ink-3); line-height: 1.4; }

/* Below the three-column breakpoint the gutter cannot hold its own column, so cards
   fall inline under the provision they belong to and stop being positioned. */
@media (max-width: 1179px) {
  .margin { grid-column: 1 / -1; padding: 0 clamp(1rem, 5vw, 4rem) 3rem; }
  .mcard { position: static; width: auto; transform: none !important; margin-bottom: 0.6rem; }
  .mcard.is-empty { display: none; }
  .margin { height: auto !important; }
}

/* ── moderation queue ─────────────────────────────────────────────────────── */

.mod { max-width: 56rem; margin: 0 auto; padding: 2.5rem clamp(1rem, 5vw, 2.5rem) 5rem; }
.mod h1 {
  font-family: var(--cond); font-weight: 300; font-size: clamp(1.9rem, 5vw, 2.7rem);
  color: var(--primary); margin: 0 0 0.35rem;
}
.mod-intro { color: var(--ink-2); max-width: 40rem; margin: 0 0 2rem; }

.mod-tabs { display: flex; gap: 0.4rem; flex-wrap: wrap; margin-bottom: 1.5rem; }
.mod-tab {
  font: inherit; font-size: 0.85rem; padding: 0.3rem 0.7rem; cursor: pointer;
  background: #fff; color: var(--ink-2);
  border: 1px solid var(--rule); border-radius: 2px;
}
.mod-tab span { font-family: var(--cond); font-variant-numeric: tabular-nums; font-size: 0.75rem; color: var(--ink-3); }
.mod-tab.is-on { background: var(--primary); color: #fff; border-color: var(--primary); }
.mod-tab.is-on span { color: #cbd7ea; }

.mod-card { background: #fff; border: 1px solid var(--rule); padding: 0.9rem 1rem; margin-bottom: 0.7rem; }
.mod-card.is-pending { border-left: 3px solid #c2703a; }
.mod-card.is-published { border-left: 3px solid var(--ins); }
.mod-card.is-hidden { border-left: 3px solid var(--ink-3); opacity: 0.7; }
.mod-head { display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap; margin-bottom: 0.45rem; }
.mod-cite { font-family: var(--font); font-variant-numeric: tabular-nums; font-size: 0.82rem; text-decoration: none; }
.mod-badge {
  font-size: 0.68rem; padding: 0 0.35rem; border-radius: 2px;
  background: var(--paper-2); border: 1px solid var(--rule); color: var(--ink-2);
}
.mod-when, .mod-expr { font-size: 0.72rem; color: var(--ink-3); }
/* Where a map pin landed, as the writer's browser read it off the published layers. */
.mod-place {
  margin: 0 0 0.4rem; font-family: var(--cond); font-variant-numeric: tabular-nums; font-size: 0.72rem; color: var(--ink-3);
}
.mod-body { margin: 0 0 0.6rem; font-size: 0.94rem; white-space: pre-wrap; }
.mod-foot { display: flex; align-items: center; gap: 0.7rem; flex-wrap: wrap; font-size: 0.76rem; color: var(--ink-3); }
.mod-author { font-family: var(--cond); font-variant-numeric: tabular-nums; }
.mod-by { color: var(--ins); }
.mod-actions { margin-left: auto; display: flex; gap: 0.35rem; }
.mod-actions button {
  font: inherit; font-size: 0.78rem; padding: 0.2rem 0.6rem; cursor: pointer;
  background: #fff; color: var(--primary); border: 1px solid var(--primary); border-radius: 2px;
}
.mod-actions button:hover { background: var(--primary); color: #fff; }
.mod-actions button:disabled { opacity: 0.5; cursor: default; }

.mod-gate { background: #fff; border: 1px solid var(--rule); padding: 1.5rem; }
.mod-gate h2 { font-family: var(--cond); font-weight: 300; font-size: 1.5rem; color: var(--primary); margin: 0 0 0.4rem; }
.mod-signin {
  font: inherit; font-size: 0.9rem; margin-top: 0.6rem; padding: 0.4rem 1rem; cursor: pointer;
  background: var(--primary); color: #fff; border: 1px solid var(--primary); border-radius: 2px;
}
.mod-empty, .mod-loading { color: var(--ink-3); }
.mod-error { color: var(--del); }

/* ── sign in ──────────────────────────────────────────────────────────────── */

.authbox { display: flex; align-items: center; gap: 0.5rem; margin-left: 0.5rem; }
.authwho { font-size: 0.75rem; color: #cbd7ea; max-width: 12rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.authbtn {
  font: inherit; font-size: 0.8rem; padding: 0.25rem 0.7rem; cursor: pointer;
  color: #fff; background: color-mix(in srgb, #fff 16%, transparent);
  border: 1px solid color-mix(in srgb, #fff 45%, transparent); border-radius: 2px;
}
.authbtn:hover { background: #fff; color: var(--primary); border-color: #fff; }

@media (max-width: 40rem) {
  .authwho { display: none; }
}


/* ── reading controls ─────────────────────────────────────────────────────── */

.controls {
  display: flex; gap: 1.25rem; flex-wrap: wrap; align-items: center;
  padding: 0.5rem clamp(1rem, 4vw, 2.5rem);
  background: var(--paper-2); border-bottom: 1px solid var(--rule);
  font-size: 0.82rem;
}
.switch { display: inline-flex; align-items: center; gap: 0.4rem; cursor: pointer; }
.switch input { accent-color: var(--primary); width: 0.95rem; height: 0.95rem; }
.controls-label {
  color: var(--ink-3); font-size: 0.74rem; letter-spacing: 0.02em;
  margin-right: -0.75rem;
}
/* Where you are in the code, filled in as you scroll. It leads the bar and takes all the
   width the reading controls do not, so as much of the citation shows as fits; it truncates
   with an ellipsis at the controls rather than wrapping, so the bar stays one row and the
   sticky height never shifts. `order` moves it ahead of the controls without reordering the
   markup, which keeps the tab order controls-first. */
.controls-crumb {
  order: -1; flex: 1 1 auto; min-width: 0; margin: 0;
  color: var(--ink-2); font-family: var(--cond); font-size: 0.86rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.controls-crumb:empty { display: none; }
.controls-crumb .crumb-sec { color: var(--primary); font-weight: 700; }
/* The third crumb, in a section long enough to need one. Quieter than the section it sits
   under: it says where in § 4.8 the reader is, not what they are reading. */
.controls-crumb .crumb-sub { color: var(--ink-2); }
.controls-crumb .crumb-sep { color: var(--ink-3); margin: 0 0.4rem; }
/* The reading controls hold their width; only the crumb gives way. */
.viewpick, .controls > .switch, .controls-label { flex: 0 0 auto; }

/* On a wide screen the reading controls and the reader's place in the code stay put under
   the masthead while the text scrolls. The offset is the masthead's measured height (set on
   :root by site.js), so the two bars sit flush with no sliver of text between them. On a
   narrow screen they scroll away — a pinned bar there costs more than it is worth. */
@media (min-width: 1180px) {
  .controls {
    position: sticky; top: var(--mh, 3.33rem); z-index: 30; flex-wrap: nowrap;
  }
  .rail {
    top: calc(var(--mh, 3.33rem) + var(--ch, 2.6rem));
    height: calc(100vh - var(--mh, 3.33rem) - var(--ch, 2.6rem));
  }
  html { scroll-padding-top: calc(var(--mh, 3.33rem) + var(--ch, 2.6rem) + 0.8rem); }
  .sec { scroll-margin-top: calc(var(--mh, 3.33rem) + var(--ch, 2.6rem) + 0.8rem); }
}

/* One document, three readings.
   marked   — the amendment against the text it amends
   proposed — the bylaw as it would read if adopted: insertions only, and set in the
              accent color rather than struck about with editing marks
   adopted  — the bylaw as it stands: insertions gone, deletions reading as plain text */
body.view-proposed del { display: none; }
/* A provision the amendment repeals outright. Hiding its `del` alone would leave the
   shell: a number hanging in the gutter with nothing beside it. In the text as it would
   read if adopted, a repealed provision is simply not there. */
body.view-proposed .prov.is-struck,
body.view-proposed .sec.is-struck,
body.view-proposed .definition.is-struck,
/* A definition's continuation paragraphs are <p> and <li>, not provisions, so they need
   saying separately. Without this a wholly struck list item keeps its bullet and loses its
   words: four of them under HOME OCCUPATION. */
body.view-proposed .def-list.is-struck,
body.view-proposed li.is-struck,
body.view-proposed p.is-struck,
body.view-proposed .toc-sec.is-struck,
/* A use-table row repealed outright (render_marked_use_schedule) is the same shell
   problem in a <tr>: hiding its cells' `del` content one by one still leaves an empty
   striped row with borders. */
body.view-proposed tr.is-struck { display: none; }
/* The mirror case, a row that does not exist until the redline adopts: shown in the
   marked and proposed readings, gone from the bylaw as it stands today. */
body.view-adopted tr.is-added { display: none; }
/* A district column that does not survive the restructure at all -- Sherborn's B-G/B-P
   merging into B -- the same way: every cell in it already carries a mark, but the cell
   itself, borders included, has to go too, or "as proposed" reads as five real columns
   and two hollow ones. */
body.view-proposed .sched-col-removed { display: none; }
body.view-adopted .sched-col-added { display: none; }
body.view-proposed ins {
  color: var(--secondary); background: none; border-bottom: 0; text-decoration: none;
}
body.view-adopted ins { display: none; }
body.view-adopted del { background: none; color: inherit; text-decoration: none; }
body.view-adopted .badge,
body.view-adopted .banner-proposed { display: none; }
/* The adopted view is the bylaw as it stands, so nothing marks a provision as changed:
   the green indicators — the contents dot, the section-title underline, the bar beside a
   changed provision — all belong to the redline, not to the code in force. */
body.view-adopted .toc-sec.is-changed .toc-num::after { content: none; }
body.view-adopted .sec-title.is-changed { text-decoration: none; }
body.view-adopted .prov.is-changed > .prov-num::before { content: none; }

.viewpick { display: inline-flex; gap: 0.15rem; background: #fff;
  border: 1px solid var(--rule); border-radius: 3px; padding: 0.1rem; }
.viewpick label { cursor: pointer; padding: 0.15rem 0.5rem; border-radius: 2px; }
.viewpick input { position: absolute; opacity: 0; pointer-events: none; }
.viewpick label:has(input:checked) { background: var(--primary); color: #fff; }
body.hide-comments .cbox { display: none; }

/* ── author notes: why a provision changed ──────────────────────────────────── */

/* The drafting team's rationale for an amendment. It carries the green of the inserted
   text, because that is what it explains: a reader who has just seen green in the body
   finds the same green in the margin saying why. Set apart from the law as apparatus, so
   it never reads as part of the ordinance, and open to comment like any provision. */
.anote {
  margin: 0.6rem 0 1rem; padding: 0.7rem 0 0.7rem 1rem;
  border-left: 3px solid var(--ins);
  background: color-mix(in srgb, var(--ins) 7%, transparent);
  border-radius: 0 3px 3px 0;
}
.anote-head {
  margin: 0 0 0.35rem; font-family: var(--cond); font-weight: 700;
  font-size: 0.78rem; color: var(--ins);
}
.anote-issue { margin: 0 0 0.4rem; font-size: 0.9rem; font-style: italic; color: var(--ink-2); }
.anote-body { margin: 0; font-size: 0.92rem; line-height: 1.6; color: var(--ink); }
.anote-src { margin: 0.45rem 0 0; font-size: 0.74rem; color: var(--ink-3); }
/* A list inside a definition. Set as one because it is one: the lead-in ends with a colon
   and what follows are its items, which as paragraphs read as separate sentences. */
.def-list { margin: 0.35rem 0 0.5rem; padding-left: 1.35rem; }
.def-list li { margin: 0.18rem 0; }

.anote-slot { display: none; }
body.hide-authornotes .anote,
body.hide-authornotes .anote-mark { display: none; }

/* The marker in the heading row: the note's anchor in the text. */
.anote-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.35rem; height: 1.35rem; padding: 0; margin-left: 0.15rem;
  vertical-align: middle; cursor: pointer;
  color: var(--ins); background: var(--ins-bg);
  border: 1px solid color-mix(in srgb, var(--ins) 35%, transparent);
  border-radius: 3px;
}
.anote-mark svg { width: 0.78rem; height: 0.78rem; fill: currentColor; }
/* The why-pencil belongs in the same gutter as the hover actions, at the provision's right
   edge, so everything to the side of the text sits in one column. It stays put — a persistent
   marker of a changed provision — while the copy/comment/edit bar appears below it on hover.
   :has scopes the positioning context to the provisions that actually carry a note. */
.sec:has(> .sec-head .anote-mark),
.prov:has(> .anote-mark),
.definition:has(> .anote-mark) { position: relative; }
.sec > .sec-head .anote-mark,
.prov > .anote-mark,
.definition > .anote-mark {
  position: absolute; top: 0.1rem; left: 100%; margin: 0 0 0 0.4rem; float: none; z-index: 1;
}
.anote-mark:hover, .anote-mark:focus-visible, .anote-mark[aria-expanded="true"] {
  background: var(--ins); color: #fff; border-color: var(--ins);
}
/* Hovering either end lights the other, so which note belongs to which heading is never a
   guess when several sit down the margin together. */
.anote.is-linked { box-shadow: 0 0 0 2px color-mix(in srgb, var(--ins) 45%, transparent); }

/* Step through the tracked changes. Every provision that carries a redline edit is a stop on
   the tour; a segmented up/down control in its gutter walks to the previous or next change, so
   a reviewer moves through all of them in order rather than scrolling to hunt for green.

   The control sits in the why-pencil's slot and replaces it: at rest a changed-and-noted
   provision shows its green pencil, and the moment the reader is on that change — hovering the
   pencil or the edited text — the pencil gives way to the arrows in the same spot, a single
   tall target rather than two slivers. A provision with no note has nothing at rest and the
   arrows simply appear there. Desktop with a real pointer only: below the margin breakpoint
   the gutter has no room and there is no hover to reveal them. Nothing steps through in the
   as-adopted view, so the control follows the redline out of it. */
.chg-station { position: relative; }
.chg-nav { display: none; }
@media (hover: hover) and (min-width: 1180px) {
  .chg-nav {
    position: absolute; top: 0.02rem; left: 100%; z-index: 3;
    margin-left: 0.4rem;                     /* the pencil's slot — it overlays the pencil */
    display: flex; flex-direction: column;
    background: var(--ins-bg); border: 1px solid color-mix(in srgb, var(--ins) 38%, transparent);
    border-radius: 4px; overflow: hidden;
    box-shadow: 0 1px 3px rgba(20, 22, 26, 0.12);
    opacity: 0; visibility: hidden; transition: opacity 0.09s ease;
  }
  .chg-peek > .chg-nav,
  .chg-active > .chg-nav,
  .chg-nav:hover, .chg-nav:focus-within { opacity: 1; visibility: visible; }

  /* The pencil steps aside for the arrows while the reader is on the change: same footprint,
     so it reads as the pencil turning into the control rather than a second thing appearing. */
  .anote-mark { transition: opacity 0.09s ease; }
  .chg-peek > .anote-mark, .chg-active > .anote-mark,
  .chg-peek > .sec-head .anote-mark, .chg-active > .sec-head .anote-mark {
    opacity: 0; pointer-events: none;
  }

  .chg-nav-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 1.45rem; height: 1.25rem; padding: 0; cursor: pointer;
    color: var(--ins); background: none; border: 0;
  }
  .chg-nav-btn.chg-prev { border-bottom: 1px solid color-mix(in srgb, var(--ins) 22%, transparent); }
  .chg-nav-btn svg { width: 0.95rem; height: 0.95rem; }
  .chg-nav-btn:hover:not(:disabled) { background: var(--ins); color: #fff; }
  .chg-nav-btn:disabled { color: color-mix(in srgb, var(--ins) 30%, transparent); cursor: default; }
}
body.view-adopted .chg-nav { display: none; }

/* The edited text the tour just landed on gets a ring that fades, so the eye finds the exact
   change after a jump — not just the provision it lives in. */
@keyframes chg-flash {
  from { box-shadow: 0 0 0 2px color-mix(in srgb, var(--ins) 60%, transparent); }
  to { box-shadow: 0 0 0 2px transparent; }
}
.chg-flash { border-radius: 2px; animation: chg-flash 1.1s ease-out; }

/* In the margin it is a card at its section's height, like a comment card. Absolute so a
   note never pushes the one below it down; the script sets the offset. The caret points
   back across the gutter at the marker in the heading row. */
.margin > .anote {
  position: absolute; top: 0; left: 0; width: calc(100% - 1rem);
  margin: 0; border-left-width: 3px;
}
.margin > .anote::before {
  content: ''; position: absolute; left: -11px; top: 0.6rem;
  border: 9px solid transparent; border-left: 0; border-right-color: var(--ins);
}

/* Below the margin breakpoint there is no third column, and dropping the note into the
   flow pushes the ordinance down the page to make room for commentary about it. It folds
   behind the marker instead and opens over the text, anchored under its own heading. */
@media (max-width: 1179px) {
  .sec, .prov, .definition { position: relative; }
  .sec > .anote, .prov > .anote, .definition > .anote {
    display: none;
    position: absolute; z-index: 30; top: 2.1rem; left: 0;
    width: min(32rem, 100%);
    background: var(--paper); border: 1px solid var(--ins);
    border-left-width: 3px; border-radius: 0 3px 3px 0;
    padding: 0.7rem 0.9rem 0.75rem 1rem;
    box-shadow: 0 6px 22px rgba(0, 0, 0, 0.14);
  }
  /* The caret sits under the marker that opened it, wherever that heading ends — the
     marker follows the heading's length, so a fixed offset points at nothing. */
  .sec > .anote::before, .prov > .anote::before, .definition > .anote::before {
    content: ''; position: absolute; top: -9px; left: var(--caret-x, 1.2rem);
    border: 9px solid transparent; border-top: 0; border-bottom-color: var(--ins);
  }
  .note-open > .anote,
  .note-peek > .anote { display: block; }
  body.hide-authornotes .note-open > .anote,
  body.hide-authornotes .note-peek > .anote { display: none; }
}
/* An author note off the redline (the "as adopted" view) has no place, and the view CSS
   already hides the redline; belt and suspenders so it never shows there. */
body.view-adopted .anote { display: none; }

/* ── schedules ────────────────────────────────────────────────────────────── */

/* "Minimum" and "Maximum" said once, above the columns they govern, instead of ten times
   across the widest table in the bylaw. */
.matrix thead .grp {
  font-family: var(--cond); font-weight: 400; font-size: 0.7rem;
  /* The group header sits inside `thead`, which is navy. Grey on navy is the pair that
     made "Shared Parking Chart" hard to read; it takes the same white as its siblings and
     is set apart by weight and tracking instead of by colour. */
  letter-spacing: 0.06em; color: #fff;
  border-bottom: 1px solid rgba(255, 255, 255, 0.35); text-align: center;
}
.matrix thead .corner { border: 0; background: none; }
.matrix .unit {
  display: block; font-family: var(--font); font-weight: 400;
  font-size: 0.66rem; color: var(--ink-3); letter-spacing: 0;
}
.schedule figcaption { display: flex; align-items: baseline; gap: 0.75rem; flex-wrap: wrap; }
.expand {
  font: inherit; font-size: 0.72rem; font-family: var(--cond);
  color: var(--primary); background: none; cursor: pointer;
  border: 1px solid var(--rule-strong); border-radius: 3px; padding: 0.1rem 0.45rem;
}
.expand:hover { border-color: var(--primary); background: #fff; }

.schedule-dialog {
  width: 100vw; max-width: 100vw; height: 100vh; max-height: 100vh;
  margin: 0; padding: clamp(0.75rem, 3vw, 2rem);
  border: 0; background: var(--paper); color: var(--ink);
  overflow: auto;
}
.schedule-dialog::backdrop { background: rgba(20, 22, 26, 0.55); }
/* Given the whole window, the table can use it: no reading measure, no inner scroller. */
.schedule-dialog .schedule { margin: 0; max-width: none; }
.schedule-dialog .table-scroll { max-width: none; overflow: visible; }
.schedule-dialog .matrix { width: 100%; }
.schedule-dialog .expand::after { content: ' ✕'; }

/* ── collapsible contents ─────────────────────────────────────────────────── */

.rail-toggle {
  position: sticky; top: 0; z-index: 2; width: 100%;
  font: inherit; font-size: 0.75rem; text-align: left; cursor: pointer;
  padding: 0.45rem 1.25rem; color: var(--ink-2);
  background: var(--paper-2); border: 0; border-bottom: 1px solid var(--rule);
}
.rail-toggle::before { content: '◂ '; color: var(--ink-3); }
.rail-toggle:hover { color: var(--primary); }
body.rail-collapsed .rail-inner { display: none; }
body.rail-collapsed .rail-toggle::before { content: '▸ '; }
body.rail-collapsed .rail { height: auto; }
body.rail-collapsed .layout { grid-template-columns: 8.5rem minmax(0, 1fr); }
@media (min-width: 1180px) {
  body.rail-collapsed .layout { grid-template-columns: 8.5rem minmax(0, 1fr) var(--margin); }
}

.toc-art-first { margin-top: 0; border-top: 0; }
.toc-sched .toc-num { color: var(--primary); }

/* ── schedules ────────────────────────────────────────────────────────────── */

.schedule { margin: 1.2rem 0 1.5rem; }

/* The parking schedule carries three kinds of row, and the source distinguished them by
   nothing at all. A category heads the uses under it; a use is a row; a continuation
   qualifies the use above it by zone. */
/* Ten columns of very unequal weight. Left to itself the browser gives the six identical
   percentage columns as much room as the requirement, and "2 spaces per dwelling unit"
   wraps over three lines while "60" sits in a column wide enough for a sentence. */
.matrix.matrix-parking { table-layout: fixed; min-width: 80rem; }
.matrix.matrix-parking th:nth-child(1) { width: 20rem; }
.matrix.matrix-parking th:nth-child(2) { width: 7rem; }
/* The requirement column carries the notes as well now, so it takes the width the notes
   column used to hold rather than leaving it to the six percentage columns, which need
   room for a heading and not for a sentence. */
.matrix.matrix-parking th:nth-child(3) { width: 18rem; }
.matrix.matrix-parking th:nth-child(n + 4) { width: 5.7rem; }
/* Two columns rather than ten. Without a zone column or a shared-parking band there is
   nothing to hold eighty rems of width open for, and the second column is the
   requirement itself -- a sentence -- rather than a zone code. The use names run long
   ("Trucking, freight terminal, automotive processing facility"), so the first column
   takes rather more than a code column would. */
.matrix.matrix-parking.is-plain { min-width: 0; width: 100%; }
.matrix.matrix-parking.is-plain th:nth-child(1) { width: 38%; }
.matrix.matrix-parking.is-plain th:nth-child(2) { width: 62%; }
.matrix.matrix-parking tbody th { font-weight: 400; }
/* Requirements are sentences — "2 spaces per dwelling unit" — not codes, so they read
   left-aligned in the body face rather than centered in the mono the use table wants. */
.matrix.matrix-parking tbody td { font-family: var(--font); font-size: 0.78rem;
  text-align: left; white-space: normal; }
.matrix.matrix-parking tbody td:nth-child(n + 4) { text-align: center;
  font-family: var(--font); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* The note finishes the requirement above it rather than standing beside it, so it reads as
   a second line in the same cell and in a quieter voice. */
.matrix-parking .pk-note { display: block; color: var(--ink-2); font-size: 0.74rem; }
/* One cell across the whole shared-parking block, which is how the chart states it. Centred
   over the six periods rather than sitting under the first of them. */
.matrix-parking .pk-none { text-align: center; color: var(--ink-2); font-style: italic; }
/* A use schedule's own grouping — Spencer sorts 92 uses under eight headings, and without
   them the table is 92 undifferentiated rows. Styled as the parking schedule's categories
   already are, so a reader learns one convention rather than two. */
.matrix .use-cat th {
  font-family: var(--cond); font-weight: 700; font-size: 0.76rem;
  text-align: left; color: var(--primary); background: var(--paper-2);
  border-top: 2px solid var(--rule-strong); padding-top: 0.5rem;
}

.matrix-parking .pk-cat th {
  font-family: var(--cond); font-weight: 700; font-size: 0.76rem;
  color: var(--primary); background: var(--paper-2);
  border-top: 2px solid var(--rule-strong); padding-top: 0.5rem;
}
.matrix-parking .pk-cont > th {
  padding-left: 1.9rem; color: var(--ink-2);
  border-top: 0;  /* it continues the use above it, so nothing is drawn between them */
}
.matrix-parking .pk-cont > th::before { content: '\21b3'; position: absolute;
  margin-left: -1.1rem; color: var(--ink-3); }
.matrix-parking .pk-cont > th { position: relative; }
.matrix-parking tbody tr:nth-child(even) { background: none; }
.matrix-parking .pk-use > th { border-top: 1px solid var(--rule); }
/* A schedule is a reference table, not prose. It has no reading measure to respect, and
   twenty district columns squeezed into a 62rem text column reads as a wall. Where the
   window is wide enough it takes the comment margin too, which is an overlay and empty
   until someone opens it. Left aligned with the text; only the right edge moves. */
@media (min-width: 86rem) {
  .schedule.is-wide,
  /* A wide table published inline gets the same room as one in a schedule figure. */
  .table-scroll.is-wide { max-width: none; width: calc(100% + var(--margin) - 3rem); }
}
.schedule figcaption {
  font-family: var(--cond); font-weight: 700; font-size: 0.95rem;
  color: var(--primary); margin-bottom: 0.4rem;
}
.matrix { border-collapse: collapse; font-size: 0.8rem; background: #fff; min-width: 100%; }
.matrix th, .matrix td {
  border: 1px solid var(--rule); padding: 0.3rem 0.55rem; text-align: left;
  /* Centred, not top-aligned: most cells in a use or dimensional table hold a single
     token -- Y, SP, a figure -- beside a row label that wraps to three lines, and
     top-aligning those leaves the token floating at the top of a tall row. */
  vertical-align: middle;
}
.matrix thead th {
  background: var(--primary); color: #fff; font-weight: 500; font-family: var(--cond);
  white-space: nowrap;
}
/* Sticky to the scroll box, not to the viewport. `.table-scroll` has `overflow-x: auto`,
   which makes it the containing block for sticky positioning — a header pinned to the
   masthead's height pinned itself inside the table instead and floated between body rows.
   So the box scrolls vertically too, and the header sticks to the top of it. A table shorter
   than the cap never reaches it and is unchanged; a use schedule of a hundred and thirteen
   rows keeps its district columns named all the way down, which is the whole difficulty of
   reading one. */
.table-scroll { max-height: min(72vh, 44rem); overflow-y: auto; }
.matrix thead th { position: sticky; top: 0; z-index: 1; }
/* The band above the column heads — "Shared Parking Chart" — is a second header row, so it
   pins above them rather than scrolling away over them. */
.matrix thead tr:first-child th { top: 0; }
.matrix thead tr:nth-child(2) th { top: var(--matrix-head, 1.9rem); }
.schedule-dialog .matrix thead th { position: sticky; top: 0; z-index: 1; }
.matrix thead th .unit {
  display: block; font-family: var(--cond); font-variant-numeric: tabular-nums; font-size: 0.68em; font-weight: 400; opacity: 0.75;
}
/* The use column is pinned. Eighteen district columns scroll past it, and a Y three
   screens to the right means nothing if the use it belongs to has scrolled off. */
.matrix tbody th { font-weight: 400; min-width: 15rem;
  position: sticky; left: 0; z-index: 1; background: #fff;
  box-shadow: 1px 0 0 var(--rule); }
.matrix tbody tr:nth-child(even) th { background: var(--paper); }
.matrix thead th:first-child { position: sticky; left: 0; z-index: 3; }
.matrix thead th { z-index: 2; }
/* Its own scroll box, so pinning has something to be pinned against. */
.schedule .table-scroll { overflow: auto; max-height: min(78vh, 46rem); }
.schedule-dialog .table-scroll { max-height: none; overflow: auto; }
.matrix tbody td { font-family: var(--font); font-variant-numeric: tabular-nums; font-size: 0.76rem; text-align: center; white-space: nowrap; }
.matrix tbody tr:nth-child(even) { background: var(--paper); }
.matrix .use-num {
  font-family: var(--font); font-variant-numeric: tabular-nums; font-size: 0.72rem; color: var(--ink-3); margin-right: 0.4rem;
}
.schedule-inline tbody td { text-align: left; font-family: var(--font); font-size: 0.82rem; white-space: normal; }
.schedule-key, .schedule-src { margin: 0.4rem 0 0; font-size: 0.72rem; color: var(--ink-2); }
.schedule-notes { margin: 0.5rem 0 0; padding-left: 1rem; font-size: 0.74rem; color: var(--ink-2); }
.schedule-notes .fn { font-family: var(--font); font-variant-numeric: tabular-nums; color: var(--primary); }
.code-table th {
  background: var(--paper-2); font-weight: 700; text-align: left;
  border-bottom: 1px solid var(--rule); border-right: 1px solid var(--rule); padding: 0.35rem 0.6rem;
}

/* Media queries last: the collapsed-rail width above is a desktop rule, and being later
   in the file it was beating the small-screen override. On a phone the rail stacks full
   width, so reserving a column for it costs a third of the screen. */
@media (max-width: 60rem) {
  .layout,
  body.rail-collapsed .layout { grid-template-columns: minmax(0, 1fr); }
  body.rail-collapsed .rail { border-bottom: 1px solid var(--rule); }
}

/* ── map page on small screens ────────────────────────────────────────────── */

@media (max-width: 45rem) {
  /* The map is the page; the panel is the answer to a tap on it. Give the map enough
     height to be usable and let the panel follow underneath rather than competing. */
  #map { height: 58vh; min-height: 20rem; }
  .mappanel { padding: 1rem 0.85rem 2.5rem; }
  .pd-title { font-size: 1.15rem; }
  .pd-sub { font-size: 0.7rem; }
  .pd-code { font-size: 0.9rem; }
  .pd-h { font-size: 0.85rem; margin-top: 1.1rem; }
  .pd-dim th, .pd-dim td { padding: 0.25rem 0.35rem; font-size: 0.76rem; }
  .pd-list a { font-size: 0.82rem; }
  .panel-empty h2 { font-size: 1.25rem; }
  .maplegend { left: 0.5rem; bottom: 0.5rem; }
  .maplegend-items { max-height: 34vh; }
  /* On a phone the controls and the legend are the only things standing between the reader
     and the map, so they get out of each other's way rather than stacking down one side. */
  /* Full width above the toolbar rather than centered over it — centered was where the
     toolbar already lives at this width, so the two covered each other. */
  .mapsearch { left: 0.5rem; right: 0.5rem; width: auto; transform: none; }
  .mapctl { left: 0.5rem; top: 3.1rem; right: 0.5rem; width: auto; padding: 0.35rem 0.45rem; }
  .mapctl-seg { flex-direction: row; flex-wrap: wrap; gap: 0.2rem; }
  /* Side by side where the panel is wide and short. The group's own rule follows. */
  .mapctl-pills { flex-direction: row; }
  .mapctl-pills button + button { border-top: 0; border-left: 1px solid var(--rule); }
  .mapctl-head { width: 100%; margin: 0.35rem 0 0.1rem; }
}

/* ── town identity ────────────────────────────────────────────────────────── */

/* The seal is transparent-backed and its green reads on the primary, so it goes on
   untouched — tinting it white was what turned it into a blank rectangle, because the
   emblem's interior is opaque. */
.brand-logo { height: 1.75rem; width: auto; flex: 0 0 auto; }
.brand-town-short { display: none; }

.foot-contact { font-size: 0.85rem; }
.foot-links { font-size: 0.8rem; }
.foot-links a { margin-right: 0.15rem; }

/* ── back to top ──────────────────────────────────────────────────────────── */

.totop {
  position: fixed; right: 1rem; bottom: 1rem; z-index: 30;
  display: none; align-items: center; justify-content: center;
  width: 2.4rem; height: 2.4rem; border-radius: 50%;
  font-size: 1.1rem; line-height: 1; text-decoration: none;
  color: #fff; background: var(--primary);
  border: 1px solid color-mix(in srgb, #fff 30%, transparent);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
.totop:hover { color: #fff; background: var(--primary-soft); }
body.scrolled .totop { display: flex; }

@media (max-width: 40rem) {
  .brand-logo { height: 1.3rem; }
  .totop { right: 0.7rem; bottom: 0.7rem; width: 2.6rem; height: 2.6rem; }
}

.comment-delete {
  font: inherit; font-size: 0.66rem; cursor: pointer; margin-left: auto;
  padding: 0 0.3rem; color: var(--ink-3);
  background: none; border: 1px solid var(--rule); border-radius: 2px;
}
.comment-delete:hover { color: var(--del); border-color: var(--del); }
.comment-delete:disabled { opacity: 0.5; cursor: default; }

/* Media queries last. The brand's short-name default sits in the identity block above,
   which is later in the file than the phone breakpoint — so without this both the long
   and the short name stayed hidden and the masthead read only "/ Zoning". */
@media (max-width: 40rem) {
  .brand-town { display: none; }
  .brand-town-short { display: inline; }
  .brand-logo { height: 1.6rem; }
}

/* The hover affordance: a comment button in the margin, aligned to whatever provision
   the cursor is over — the innermost one, so hovering a sub-clause offers the sub-clause
   rather than the section containing it. */




/* A provision under the cursor gets a hairline in the gutter, so it is obvious which
   one the button would attach to. */

/* The provision number doubles as its comment handle. */
.prov-num { cursor: pointer; }
.prov-num:hover { color: var(--secondary); }
body.hide-comments .prov-num { cursor: default; }
body.hide-comments .prov-num:hover { color: var(--primary); }


/* ── commenting ───────────────────────────────────────────────────────────── */

/* The provision under the cursor is shaded so it is unambiguous what a click will
   attach a comment to. :has() keeps the fill on the innermost one — without it every
   ancestor of a hovered sub-clause would light up too. */
.doc [data-eid]:hover { background: color-mix(in srgb, var(--secondary) 9%, transparent); }
.doc [data-eid]:has([data-eid]:hover) { background: none; }
.doc [data-eid] { border-radius: 2px; transition: background 0.12s ease; }
.doc [data-eid].is-commenting,
.doc [data-eid].is-commenting:hover {
  background: color-mix(in srgb, var(--secondary) 16%, transparent);
  box-shadow: inset 2px 0 0 var(--secondary);
}
/* A provision this reader has already written about. Nobody else's activity is shown. */
.doc [data-eid].has-mine > .prov-num::after,
.doc .sec.has-mine .sec-num::after { content: ' ✎'; color: var(--secondary); font-size: 0.8em; }
body.hide-comments .doc [data-eid]:hover { background: none; }

.cbox {
  width: calc(100% - 1rem); background: #fff;
  border: 1px solid var(--secondary); border-radius: 3px;
  padding: 0.7rem 0.8rem; font-size: 0.82rem;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.margin > .cbox { position: absolute; top: 0; left: 0; }
.cbox.is-inline {
  position: static; width: auto; margin: 0.6rem 0 0.9rem;
}
.cbox .comment-note {
  margin-top: 0.5rem; padding-top: 0.45rem; border-top: 1px solid var(--rule);
  color: var(--ink-2); font-size: 0.72rem;
}
.cbox-close {
  background: none !important; color: var(--ink-3) !important;
  border-color: transparent !important;
}
.cbox-close:hover { color: var(--primary) !important; text-decoration: underline; }

/* The hover hint. Pointer-events off so it never intercepts the click it is advertising,
   and hover-capable devices only — on touch there is no hover to hint at. */
/* The provision gutter: the one place, to the right of any provision, for the actions a
   reader has on it. It appears on hover, a narrow vertical stack of icon buttons, and asks
   the comment and editor modules to open by event. */
.pgutter {
  position: absolute; z-index: 35; display: none;
  flex-direction: column; gap: 0.15rem; padding: 0.1rem;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  border: 1px solid var(--rule); border-radius: 4px;
  box-shadow: 0 1px 5px rgba(20, 22, 26, 0.12);
}
@media (hover: hover) {
  .pgutter.is-on { display: inline-flex; }
  /* Reserve the column the gutter lives in, so a narrow window still has room for it to the
     right of the text rather than over it. */
  .doc { padding-right: max(2.9rem, clamp(1rem, 5vw, 4rem)); }
}
.pg-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.75rem; height: 1.75rem; padding: 0; cursor: pointer;
  color: var(--ink-2); background: none; border: 0; border-radius: 3px;
}
.pg-btn svg { width: 1.15rem; height: 1.15rem; }
.pg-btn:hover { background: var(--paper-2); color: var(--primary); }
.pg-btn[data-act="edit"]:hover { color: var(--secondary); }
.pg-btn[hidden] { display: none; }
.pg-btn.is-done { color: var(--ins); }

/* The gutter's own tooltip: immediate (no native ~1s delay), sitting to the left of the
   bar and pointing back at the button. Reused to confirm a copy, when it turns green and
   reads "Link copied". */
.pg-tip {
  position: absolute; z-index: 40; pointer-events: none;
  transform: translate(calc(-100% - 9px), -50%);
  white-space: nowrap; opacity: 0; visibility: hidden;
  padding: 0.18rem 0.45rem; border-radius: 4px;
  font-size: 0.72rem; line-height: 1.25; font-weight: 500;
  color: var(--paper); background: var(--ink);
  box-shadow: 0 1px 4px rgba(20, 22, 26, 0.25);
  transition: opacity 0.09s ease;
}
.pg-tip.is-on { opacity: 1; visibility: visible; }
.pg-tip.is-ok { background: var(--ins); }
.pg-tip::after {
  content: ''; position: absolute; top: 50%; right: -3px;
  width: 7px; height: 7px; transform: translateY(-50%) rotate(45deg);
  background: var(--ink);
}
.pg-tip.is-ok::after { background: var(--ins); }
/* The comment action is meaningless with comments switched off, and editing with the
   redline hidden; the reader has told us they do not want them, so drop them from the bar. */
body.hide-comments .pg-btn[data-act="comment"] { display: none; }

/* A district named in the text links to itself on the map. Subtle enough to read
   through — this is a bylaw, and half its sentences name a district. */
.pill {
  text-decoration: none; color: inherit;
  padding: 0 0.2rem; border-radius: 2px;
  background: color-mix(in srgb, var(--chip) 18%, transparent);
  box-shadow: inset 0 -1px 0 color-mix(in srgb, var(--chip) 65%, transparent);
}
.pill:hover { background: color-mix(in srgb, var(--chip) 38%, transparent); color: inherit; }

/* Definitions are set in capitals, which is the bylaw's own convention for a defined
   term, whatever case the amendment happened to be drafted in. */
dfn { text-transform: uppercase; }

/* A statute's own apparatus. Three things a bylaw on this platform does not publish and
   every state statute does, so they are set here rather than borrowed from a class that
   means something else on a code page.

   The session-law credit is shown rather than hidden behind the code pages' amendment-history
   toggle. On a bylaw the history is an aside; on a statute it is the provenance of the
   provision, printed inline by the Revisor of Statutes and by the Legislature both, and a
   reference copy that dropped it would be quietly less useful than the page it copies. It is
   set as apparatus — small, grey, in the same family as a heading — so it reads as a note on
   the text rather than as part of it. */
body.statute .statute-credit {
  margin: 0.2rem 0 0.7rem;
  font-family: var(--cond); font-size: 0.78rem; color: var(--ink-3);
  max-width: min(var(--measure), 100%);
}
/* Off when the reader has said so. Only the session-law credits go: a Revisor's note is
   about what the provision *is* — a reallocation, a renumbering — and a reader who has
   dismissed the amendment history has not asked to be told less about that. */
body.statute.hide-history .statute-credit { display: none; }

/* The codifier speaking about the provision rather than in it. Boxed and labelled, because
   the one thing a reader must never do is mistake a note about a renumbering for the law. */
body.statute .statute-note {
  margin: 0.6rem 0; padding: 0.5rem 0.8rem;
  border-left: 2px solid var(--rule-strong); background: var(--paper-2);
  max-width: min(var(--measure), 100%);
}
body.statute .statute-note > span {
  display: block; font-family: var(--cond); font-size: 0.72rem; letter-spacing: 0.04em;
  color: var(--ink-3);
}
body.statute .statute-note p { margin: 0.25rem 0 0; font-size: 0.92rem; }
/* Maine gives most of its provisions a headnote — a heading one rung below the section,
   which Massachusetts has no equivalent of. It sits above the provision's own text. */
body.statute .prov-heading {
  margin: 0 0 0.25rem; font-weight: 700; color: var(--ink);
}

/* A statute is not a bylaw, and the Commonwealth drafts the other way round: it prints a
   defined term in sentence case inside quotation marks — “Accessory dwelling unit”, a
   self-contained housing unit … — and the quotation marks are part of the drafting rather
   than decoration around a name. Shouting it would misreport the statute's own typography,
   so the rule above is scoped off on the reference pages. */
body.statute dfn { text-transform: none; }

/* ── defined terms in use ─────────────────────────────────────────────────────
   A word the bylaw defines, wherever the bylaw uses it. Underlined so a reader can see
   which words in a sentence carry a fixed meaning, and in the accent rather than the link
   colour because it is an annotation on the word, not somewhere else to go: half the
   sentences in a zoning code would otherwise be a wall of blue. Hovering shows the
   definition; clicking goes to it. */
.tref {
  color: inherit;
  text-decoration-line: underline;
  text-decoration-style: solid;
  text-decoration-thickness: 1px;
  text-decoration-color: color-mix(in srgb, var(--secondary) 50%, transparent);
  text-underline-offset: 0.16em;
  cursor: help;
}
.tref:hover, .tref:focus-visible {
  color: inherit;
  text-decoration-color: var(--secondary);
  background: color-mix(in srgb, var(--secondary) 12%, transparent);
}
/* Inside the card the word is still defined and still marked, but there is nowhere for it
   to go: the reader is already reading a definition. */
.tref.is-flat { cursor: text; }
.tref.is-flat:hover { background: none; }
/* A struck or inserted term keeps the revision mark's colour: what the draft did to the
   word matters more than that the word is defined. */
ins .tref, del .tref { text-decoration-color: currentColor; }

.term-card {
  position: fixed; z-index: 60;
  width: min(30rem, calc(100vw - 1rem));
  max-height: min(22rem, 60vh); overflow-y: auto; overscroll-behavior: contain;
  padding: 0.75rem 0.9rem 0.85rem;
  background: #fff; color: var(--ink);
  border: 1px solid var(--rule-strong); border-top: 2px solid var(--secondary);
  box-shadow: 0 6px 24px rgba(20, 22, 26, 0.14);
  font-size: 0.92rem; line-height: 1.55;
  opacity: 0; transition: opacity 0.1s ease;
}
.term-card.is-on { opacity: 1; }
.term-card.is-above { border-top: 1px solid var(--rule-strong); border-bottom: 2px solid var(--secondary); }
.term-card-head {
  margin: 0 0 0.4rem;
  font-family: var(--cond); font-size: 0.76rem; letter-spacing: 0.02em;
  color: var(--ink-3);
}
.term-card-src { color: var(--ink-2); text-decoration-color: var(--rule-strong); }
.term-card-src:hover { color: var(--primary); }
/* The reach of a local definition, which is the whole reason the card names its source:
   a term defined for the floodplain does not mean that anywhere else. */
.term-card-scope { color: var(--secondary); font-weight: 700; }
.term-card-scope::before { content: ' · '; color: var(--ink-3); font-weight: 400; }
/* The entry, borrowed from further down the page: no rule down its left side, because the
   card is already a box, and no gutter, because nothing here is being cited. */
.term-card-body { border-left: 0; padding-left: 0; margin: 0; }
.term-card-body > p:first-child { margin-top: 0; }
.term-card-body > p:last-child, .term-card-body > ul:last-child { margin-bottom: 0; }
.term-card-body .prov { display: block; margin: 0.35rem 0 0; }
.term-card-body .prov-num { display: inline; margin-right: 0.3rem; font-weight: 700; }
.term-card-body .prov-body { display: inline; }
.term-card-body figure.illus { display: none; }
.term-card::after {
  content: ''; position: absolute; top: -5px; left: var(--tail, 50%);
  width: 8px; height: 8px; margin-left: -4px; transform: rotate(45deg);
  background: #fff; border-left: 1px solid var(--rule-strong); border-top: 1px solid var(--rule-strong);
}
.term-card.is-above::after {
  top: auto; bottom: -5px;
  border: 0; border-right: 1px solid var(--rule-strong); border-bottom: 1px solid var(--rule-strong);
}
@media print {
  /* The underline is still worth having on paper — it says the word is defined — but
     nothing can be hovered, so it is set lighter and the card never exists. */
  .tref { text-decoration-color: var(--rule-strong); }
  .term-card { display: none; }
}

/* Schedule rows are provisions: each is commentable like any other. */
.matrix tbody tr[data-eid]:hover { background: color-mix(in srgb, var(--secondary) 10%, transparent); }
.matrix tbody tr.is-commenting { background: color-mix(in srgb, var(--secondary) 18%, transparent); }

/* Where a link landed. Held for a moment so a reader arriving from a comment or a shared
   URL can see which provision was meant, then released so it does not read as a selection. */
.is-landed {
  animation: landed 2.4s ease-out;
  border-radius: 2px;
}
@keyframes landed {
  0%, 55% { background: color-mix(in srgb, var(--secondary) 20%, transparent); }
  100%    { background: transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .is-landed { animation: none; background: color-mix(in srgb, var(--secondary) 14%, transparent); }
}

/* ── amendment history ────────────────────────────────────────────────────── */

/* Provenance, not text. It reads as apparatus — smaller, set back behind a rule, in the
   accent rather than the ink — so an eye scanning the bylaw passes over it. Hidden until
   the reader turns it on from the controls at the top. */
.hist { display: none; }
body.show-history .hist {
  display: block;
  margin: 0.15rem 0 0.8rem;
  padding-left: 0.6rem;
  border-left: 2px solid color-mix(in srgb, var(--secondary) 45%, transparent);
  font-size: 0.78rem; line-height: 1.5; color: var(--ink-3);
}
body.show-history .sec-head + .hist,
body.show-history .chips + .hist { margin-top: 0.35rem; }
.history { display: none; }


/* ── the front door ───────────────────────────────────────────────────────────
   code.communityscale.io itself, rather than any one community's code. The same
   statute-book setting as the pages it introduces: this is a product for people who
   read legal text all day, and it should look like the thing it is selling. */

body.home { background: var(--paper); }
.home-main { max-width: 68rem; margin: 0 auto; padding: 0 clamp(1rem, 5vw, 2.5rem) 5rem; }
.home-main section { padding: 3.5rem 0 0; }
.home-main h2 {
  font-family: var(--cond); font-weight: 300; font-size: clamp(1.5rem, 3.4vw, 2.1rem);
  color: var(--primary); margin: 0 0 0.4rem; padding-top: 1rem;
  border-top: 2px solid var(--primary);
}
.section-lede { margin: 0 0 1.6rem; color: var(--ink-3); font-size: 0.92rem; max-width: 46rem; }

.hero { padding: clamp(3rem, 8vw, 5.5rem) 0 0; }
.hero-eyebrow {
  font-family: var(--cond); font-variant-numeric: tabular-nums; font-size: 0.72rem; letter-spacing: 0.1em;
  color: var(--ink-3); margin: 0 0 1rem;
}
.hero h1 {
  font-family: var(--cond); font-weight: 300; line-height: 1.05;
  font-size: clamp(2.1rem, 6.4vw, 4.2rem); color: var(--primary);
  margin: 0 0 1.5rem; max-width: 20ch;
}
.hero-lede { font-size: clamp(1rem, 1.6vw, 1.16rem); line-height: 1.6; max-width: 52rem; margin: 0; }

.home-cards { display: grid; gap: 1px; background: var(--rule); border: 1px solid var(--rule); }
@media (min-width: 52rem) { .home-cards { grid-template-columns: repeat(3, 1fr); } }
.home-card {
  display: flex; flex-direction: column; gap: 0.3rem;
  padding: 1.4rem 1.5rem 1.5rem; background: var(--paper);
  text-decoration: none; color: var(--ink);
}
.home-card.is-live:hover { background: #fff; }
.home-card.is-soon { color: var(--ink-3); }
.home-place { font-family: var(--cond); font-weight: 700; font-size: 1.2rem; color: var(--primary); }
.home-card.is-soon .home-place { color: var(--ink-3); }
.home-state { font-family: var(--cond); font-variant-numeric: tabular-nums; font-size: 0.7rem; letter-spacing: 0.06em; color: var(--ink-3); }
.home-note { font-size: 0.86rem; line-height: 1.5; margin: 0.5rem 0 1rem; flex: 1; }
.home-go {
  font-family: var(--cond); font-size: 0.8rem; letter-spacing: 0.03em;
  color: var(--primary); border-top: 1px solid var(--rule); padding-top: 0.6rem;
}
.home-card.is-live .home-go::after { content: ' →'; }
.home-card.is-soon .home-go { color: var(--ink-3); }

.points { display: grid; gap: 1.6rem 2.5rem; }
@media (min-width: 46rem) { .points { grid-template-columns: 1fr 1fr; } }
.point h3 {
  font-size: 1rem; font-weight: 700; margin: 0 0 0.35rem; line-height: 1.35;
  padding-left: 0.85rem; border-left: 3px solid var(--secondary);
}
.point-next h3 { border-left-color: var(--rule-strong); color: var(--ink-2); }
.point p { margin: 0; padding-left: 0.85rem; font-size: 0.92rem; line-height: 1.6; color: var(--ink-2); }

.home-cta p { max-width: 46rem; font-size: 0.96rem; line-height: 1.6; }
/* There used to be a second `.cta` here, a standalone button for the pre-Tailwind front
   door. That page moved to home.css and took its markup with it, but the rule stayed and
   went on matching the one thing still called `.cta`: the row of buttons under the hero,
   500 lines above. Being later in the file it won, so the row got `display:inline-block`
   and a solid `--primary` background painted across all three buttons. The white text on
   the primary button read fine; the other two were the same blue as the block behind them
   and vanished until hover. Live on both communities. Deleted rather than scoped: nothing
   in the built site uses it. */

/* ── admin portal, the inline editor, and the amendment queue ──────────────────
 *
 * The portal link rides in the topnav and shows only to a reader the server says holds a
 * role, so most visitors never render any of this. The editor box mirrors the comment box
 * it shares a surface with; the queue mirrors the comment queue. The redline reuses the
 * --ins / --del vocabulary the drafted amendments already use, so a suggested change reads
 * the same as a proposed one. */

.portal { display: inline-flex; align-items: center; gap: 0.9rem; }
.portal-tag {
  font-family: var(--cond); font-variant-numeric: tabular-nums; font-size: 0.62rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: #cbd7ea; border: 1px solid #3a4d74;
  border-radius: 999px; padding: 0.05rem 0.5rem;
}

/* An editor gets a hint on every provision; the pencil is the way in. Hidden until the
 * body is flagged an editor, so a reader never sees an affordance they cannot use. */
.edit-flag { display: none; }
.is-editor .edit-flag {
  display: inline-block; margin-left: 0.4rem; cursor: pointer;
  font-size: 0.75rem; color: var(--secondary); user-select: none;
}
.is-editor [data-eid].is-editing { background: color-mix(in srgb, var(--secondary) 8%, transparent); }

.ebox {
  background: #fff; border: 1px solid var(--rule-strong); border-left: 3px solid var(--secondary);
  padding: 0.9rem 1rem; margin: 0.6rem 0; max-width: var(--measure);
}
.ebox-head { font-size: 0.9rem; color: var(--ink-2); margin: 0 0 0.6rem; }
.ebox-edit {
  border: 1px solid var(--rule); background: var(--paper); padding: 0.6rem 0.7rem;
  min-height: 3rem; font-size: 0.95rem; line-height: 1.5;
}
.ebox-edit:focus { outline: 2px solid var(--secondary); outline-offset: 1px; }
.ebox-why { display: block; margin: 0.6rem 0 0; font-size: 0.8rem; color: var(--ink-2); }
.ebox-why textarea {
  display: block; width: 100%; margin-top: 0.25rem; padding: 0.4rem 0.5rem;
  border: 1px solid var(--rule); font: inherit; font-size: 0.9rem; resize: vertical;
}
.ebox-note { font-size: 0.74rem; color: var(--ink-3); margin: 0.6rem 0 0; }
.ebox-actions { display: flex; gap: 0.4rem; justify-content: flex-end; margin-top: 0.7rem; }
.ebox-actions button {
  font: inherit; font-size: 0.82rem; padding: 0.3rem 0.9rem; cursor: pointer;
  border: 1px solid var(--primary); background: #fff; color: var(--primary);
}
.ebox-send { background: var(--primary); color: #fff; }
.ebox-actions button:hover { background: var(--primary-soft); color: #fff; }
.ebox-status { font-size: 0.78rem; color: var(--del); margin: 0.4rem 0 0; min-height: 1em; }

/* The queue reuses the moderation layout wholesale. */
.equeue-tabs { display: flex; gap: 0.4rem; flex-wrap: wrap; margin-bottom: 1.5rem; }
.equeue-tabs button {
  font: inherit; font-size: 0.8rem; text-transform: capitalize; cursor: pointer;
  padding: 0.3rem 0.7rem; border: 1px solid var(--rule); background: #fff; color: var(--ink-2);
}
.equeue-tabs button.is-on { background: var(--primary); color: #fff; border-color: var(--primary); }
.equeue-empty { color: var(--ink-3); }

.ecard { background: #fff; border: 1px solid var(--rule); border-left: 3px solid var(--rule-strong); padding: 0.9rem 1rem; margin-bottom: 0.8rem; }
.ecard.data-id { }
.ecard-head { display: flex; align-items: baseline; gap: 0.6rem; margin-bottom: 0.3rem; }
.ecard-cite { font-family: var(--font); font-variant-numeric: tabular-nums; font-size: 0.82rem; }
.ecard-status {
  font-family: var(--cond); font-variant-numeric: tabular-nums; font-size: 0.66rem; letter-spacing: 0.05em; text-transform: uppercase;
  margin-left: auto; padding: 0.05rem 0.45rem; border-radius: 999px; background: var(--paper-2); color: var(--ink-3);
}
.ecard-status.is-accepted { background: var(--ins-bg); color: var(--ins); }
.ecard-status.is-rejected { background: var(--del-bg); color: var(--del); }
.ecard-status.is-superseded { background: #f3ead9; color: #8a5a1c; }
.ecard-by { font-size: 0.74rem; color: var(--ink-3); margin: 0 0 0.5rem; }
.ecard-why { font-size: 0.86rem; color: var(--ink-2); font-style: italic; margin: 0 0 0.5rem; }
.ecard-stale { font-size: 0.8rem; color: #8a5a1c; background: #f3ead9; padding: 0.4rem 0.6rem; margin: 0 0 0.5rem; }
.ecard-diff {
  border: 1px solid var(--rule); background: var(--paper); padding: 0.5rem 0.7rem;
  font-size: 0.9rem; line-height: 1.55; overflow-x: auto;
}
.ecard-diff ins { background: var(--ins-bg); color: var(--ins); text-decoration: none; }
.ecard-diff del { background: var(--del-bg); color: var(--del); }
.ecard-actions { display: flex; gap: 0.4rem; margin-top: 0.7rem; }
.ecard-actions button {
  font: inherit; font-size: 0.82rem; padding: 0.3rem 0.9rem; cursor: pointer;
  border: 1px solid var(--primary); background: #fff; color: var(--primary);
}
.ecard-actions button:hover { background: var(--primary); color: #fff; }
.ecard-actions button:disabled { opacity: 0.5; cursor: default; }

/* ── version archive ─────────────────────────────────────────────────────────
   The revision history and the upload control. Reuses the moderation queue's
   measure (.mod) because it is the same kind of page: a working surface for
   somebody with a role, not a reading surface for the public. */

.rev-page { max-width: 72rem; }
.rev-block { margin: 2.5rem 0 3rem; }
.rev-block h2 { font-size: 1.05rem; letter-spacing: .01em; margin: 0 0 .35rem; }
.rev-blurb { color: var(--ink-2); font-size: .86rem; margin: .2rem 0 .9rem; line-height: 1.5; }

.rev-table { width: 100%; border-collapse: collapse; font-size: .84rem; }
.rev-table th {
  text-align: left; font-weight: 500; color: var(--ink-3);
  border-bottom: 1px solid var(--rule, #d8dce4); padding: .4rem .6rem .4rem 0;
  font-size: .76rem; letter-spacing: .02em;
}
.rev-table td { padding: .45rem .6rem .45rem 0; border-bottom: 1px solid rgba(0,0,0,.055); vertical-align: top; }
.rev-id { font-family: var(--font); font-variant-numeric: tabular-nums; font-weight: 500; white-space: nowrap; }
.rev-sha { font-family: var(--font); font-variant-numeric: tabular-nums; color: var(--ink-3); font-size: .78rem; }
.rev-what { color: var(--ink-2); max-width: 26rem; }
.rev-changes { white-space: nowrap; font-family: var(--font); font-variant-numeric: tabular-nums; font-size: .78rem; }

/* The diff verbs. Colour carries meaning here, so each also differs in sign. */
.d-add { color: #1a7f45; }
.d-del { color: #a8302b; }
.d-chg { color: #8a5a00; }
.d-ren { color: #2c5aa0; }
.d-none { color: var(--ink-3); font-style: italic; }

.rev-detail td { padding-top: 0; }
.rev-detail details { margin: 0 0 .5rem; }
.rev-detail summary { cursor: pointer; color: var(--ink-3); font-size: .78rem; }
.rev-detail ul { margin: .25rem 0 .6rem 1.1rem; padding: 0; columns: 2; column-gap: 2rem; }
.rev-detail li { font-size: .8rem; color: var(--ink-2); break-inside: avoid; }
.d-h { font-size: .74rem; letter-spacing: .04em; text-transform: none; color: var(--ink-3); margin: .5rem 0 0; }
.d-warn { color: #a8302b; font-size: .8rem; margin: .5rem 0 0; }

/* Upload. Visually separated from the history because it is the only control on
   this page that writes anything. */
.up-panel {
  border: 1px solid var(--rule, #d8dce4); border-radius: 3px;
  padding: 1.1rem 1.25rem 1.25rem; margin: 1.5rem 0 2rem;
  background: color-mix(in srgb, var(--primary) 3%, #fff);
}
.up-panel h2 { font-size: 1rem; margin: 0 0 .3rem; }
.up-gate { color: var(--ink-2); font-size: .86rem; margin: .6rem 0 0; }
.up-form { display: grid; gap: .7rem; max-width: 38rem; margin-top: .6rem; }
.up-form label { display: grid; gap: .25rem; font-size: .8rem; color: var(--ink-2); }
.up-form select, .up-form input[type=text] {
  font: inherit; font-size: .86rem; padding: .4rem .5rem;
  border: 1px solid var(--rule, #d8dce4); border-radius: 2px; background: #fff;
}
.up-form button {
  justify-self: start; font: inherit; font-size: .86rem; padding: .45rem 1.1rem;
  border: 1px solid var(--primary); background: var(--primary); color: #fff;
  border-radius: 2px; cursor: pointer;
}
.up-form button[disabled] { opacity: .55; cursor: default; }
.up-head { font-size: .8rem; color: var(--ink-3); margin: 0; }
.up-result:empty { display: none; }
.up-result {
  margin-top: .9rem; padding: .7rem .85rem; border-radius: 2px;
  font-size: .84rem; line-height: 1.5; border-left: 3px solid var(--ink-3);
  background: rgba(0,0,0,.028);
}
.up-ok  { border-left-color: #1a7f45; }
.up-err { border-left-color: #a8302b; }
.up-warn{ border-left-color: #8a5a00; }
.up-result ul { margin: .35rem 0 0 1.1rem; padding: 0; }
.up-warn-inline { color: #8a5a00; }


/* XML revision history, in the footer and only for an editor of this community.
   Closed by default: it is a working record, not something a reader of the law needs
   open. The forked row is the one worth seeing at a glance — a revision that does not
   descend from the one before it is the failure the whole revision store exists to catch. */
.revhistory:empty { display: none; }
.rev-history { margin-top: 0.9rem; font-size: 0.86rem; }
.rev-history > summary { cursor: pointer; color: var(--ink3, #666); }
.rev-count {
  display: inline-block; min-width: 1.35em; padding: 0 0.35em; border-radius: 0.7em;
  background: var(--rule, #ddd); text-align: center; font-variant-numeric: tabular-nums;
}
.rev-list { list-style: none; margin: 0.6rem 0 0; padding: 0; }
.rev-item {
  display: flex; flex-wrap: wrap; gap: 0.3rem 0.9rem; align-items: baseline;
  padding: 0.32rem 0; border-top: 1px solid var(--rule, #e5e5e5);
}
.rev-id { font-variant-numeric: tabular-nums; font-weight: 600; }
.rev-view, .rev-size { color: var(--ink3, #777); }
.rev-when { font-variant-numeric: tabular-nums; }
.rev-note { flex: 1 1 100%; color: var(--ink2, #555); }
.rev-forked { border-left: 3px solid var(--del, #a8302b); padding-left: 0.5rem; }
.rev-fork-tag { color: var(--del, #a8302b); }

/* The admin landing page, and a resident's own comments.
   Both are lists of things that happened, so they read as rows rather than as cards in a
   grid: the question a reader arrives with is "what is here and what state is it in", and
   a row answers that in one line. */
.admin-cards { list-style: none; margin: 1.4rem 0 0; padding: 0; display: grid; gap: 0.9rem; }
.admin-card a {
  display: block; padding: 0.95rem 1.1rem; border: 1px solid var(--rule, #e0e0e0);
  border-radius: 4px; text-decoration: none; background: var(--paper, #fff);
}
.admin-card a:hover { border-color: var(--primary); }
.admin-card-title { display: block; font-weight: 600; color: var(--primary); }
.admin-card-blurb { display: block; margin-top: 0.3rem; color: var(--ink2, #555); }
.admin-none { margin-top: 1.2rem; color: var(--ink2, #555); }

.mine-count { margin-top: 1.2rem; color: var(--ink3, #777); }
.mine-list { list-style: none; margin: 0.5rem 0 0; padding: 0; }
.mine-item { padding: 0.9rem 0; border-top: 1px solid var(--rule, #e5e5e5); }
.mine-head { display: flex; flex-wrap: wrap; gap: 0.4rem 0.9rem; align-items: baseline; }
.mine-when { color: var(--ink3, #777); font-variant-numeric: tabular-nums; }
/* The status is the point of the page, so it is a chip rather than another grey word. */
.mine-status { padding: 0.08rem 0.5rem; border-radius: 0.8em; font-size: 0.82rem; }
.st-new { background: var(--ins-bg, #eef6ee); color: var(--ins, #2f6b34); }
.st-done { background: var(--rule, #eee); color: var(--ink2, #555); }
.mine-body {
  margin: 0.5rem 0 0; padding-left: 0.9rem; border-left: 3px solid var(--rule, #e0e0e0);
  color: var(--ink2, #444);
}

/* ── the zoning audit ─────────────────────────────────────────────────────────
   A findings page, not an error log. Each finding is a card because each one is a separate
   decision somebody has to make, and the evidence sits inside the card that makes the claim
   so a reader never has to hold two places on the page at once. */
.audit { max-width: 52rem; margin: 0 auto; padding: 0 clamp(1rem, 4vw, 2.5rem) 4rem; }
.audit-head { padding: clamp(2.5rem, 7vw, 4.5rem) 0 2rem; border-bottom: 1px solid var(--rule); }
.audit-head h1 {
  font-family: var(--cond); font-weight: 300; font-size: clamp(2.1rem, 6vw, 3.4rem);
  line-height: 1.05; margin: 0 0 1.1rem; color: var(--primary);
}
.audit-note {
  font-size: 0.92rem; color: var(--ink-2); max-width: 42rem;
  border-left: 2px solid var(--secondary); padding-left: 0.9rem; margin: 0;
}

.audit-group { padding: 2.5rem 0 0.5rem; }
.audit-group h2 {
  font-family: var(--cond); font-weight: 300; font-size: 1.7rem;
  margin: 0 0 0.35rem; color: var(--primary);
}
.audit-count {
  font-size: 0.8rem; font-weight: 500; color: var(--ink-3);
  border: 1px solid var(--rule); border-radius: 999px; padding: 0.05rem 0.5rem;
  vertical-align: 0.35em; margin-left: 0.35rem;
}
.audit-lede { color: var(--ink-2); font-size: 0.95rem; max-width: 42rem; margin: 0 0 1.5rem; }

.audit-item {
  background: #fff; border: 1px solid var(--rule); border-left: 3px solid var(--primary);
  border-radius: 2px; padding: 1.1rem 1.25rem; margin: 0 0 0.9rem;
}
.audit-item h3 {
  font-family: var(--cond); font-weight: 700; font-size: 1.05rem;
  margin: 0 0 0.5rem; color: var(--ink); line-height: 1.35;
}
/* The citation, and the link. A finding about a provision that does not exist still shows
   the number — struck through, because that is the finding. */
.audit-where {
  font-family: var(--cond); font-variant-numeric: tabular-nums; font-weight: 400;
  font-size: 0.85rem; color: var(--primary); text-decoration: none;
  border: 1px solid var(--rule); border-radius: 2px; padding: 0.05rem 0.4rem;
  margin-right: 0.5rem; white-space: nowrap;
}
a.audit-where:hover { border-color: var(--primary); background: var(--paper-2); }
.audit-where.is-absent { color: var(--ink-3); text-decoration: line-through; }
.audit-detail { margin: 0 0 0.85rem; color: var(--ink-2); font-size: 0.95rem; }
.audit-evidence {
  margin: 0 0 0.85rem; padding: 0.7rem 0.9rem 0.7rem 1.9rem;
  background: var(--paper-2); border-radius: 2px;
  font-size: 0.86rem; color: var(--ink-2);
}
.audit-evidence li { margin: 0.15rem 0; }
.audit-action {
  margin: 0; font-size: 0.9rem; color: var(--ink);
  border-left: 2px solid var(--secondary); padding-left: 0.75rem;
}
.audit-source {
  margin: 0.85rem 0 0; font-family: var(--cond); font-size: 0.72rem;
  letter-spacing: 0.04em; color: var(--ink-3);
}

.panel-audit .btn { margin-top: 0.25rem; }

@media (max-width: 40rem) {
  .audit-item { padding: 0.9rem 1rem; }
  .audit-where { display: inline-block; margin-bottom: 0.3rem; }
}

/* ── The Code editor ───────────────────────────────────────────────────────────────────
   A drafting surface, not a reading one. It borrows the code page's type and rules so the
   drafter sees what a resident will, and adds only what editing needs: block boundaries you
   can see, a rung that is a control rather than an indent, and a state marker per block. */
.ed { max-width: none; padding: 0; }
.ed-bar {
  position: sticky; top: var(--mh, 3.33rem); z-index: 30; display: flex; gap: 1rem;
  align-items: center;
  padding: 0.5rem 1rem; background: #fff; border-bottom: 1px solid var(--rule);
}
.ed-views { display: flex; }
.ed-view {
  border: 1px solid var(--rule); background: #fff; color: var(--ink-2);
  font: inherit; font-size: 0.82rem; padding: 0.3rem 0.75rem; cursor: pointer;
}
.ed-view + .ed-view { border-left: 0; }
.ed-view:first-child { border-radius: 0.3rem 0 0 0.3rem; }
.ed-view:last-child { border-radius: 0 0.3rem 0.3rem 0; }
.ed-view.is-on { background: var(--primary); border-color: var(--primary); color: #fff; }
.ed-tools { display: flex; gap: 0.5rem; align-items: center; }
.ed-rungpick { font-size: 0.78rem; color: var(--ink-3); display: flex; gap: 0.35rem;
  align-items: center; }
.ed-rungpick select { font: inherit; font-size: 0.78rem; padding: 0.2rem; }
.ed-btn {
  border: 1px solid var(--rule); background: #fff; font: inherit; font-size: 0.82rem;
  padding: 0.3rem 0.7rem; border-radius: 0.3rem; cursor: pointer;
}
.ed-btn:hover { border-color: var(--primary); }
.ed-btn-go { background: var(--primary); border-color: var(--primary); color: #fff; }
.ed-btn-go:disabled { opacity: 0.5; cursor: default; }
.ed-right { margin-left: auto; display: flex; gap: 0.75rem; align-items: center; }
/* The save state is the one thing on this bar that is always true, so it never moves. */
.ed-save { font-size: 0.78rem; color: var(--ink-3); min-width: 12rem; text-align: right; }
.ed-save.is-ok { color: var(--secondary); }
.ed-save.is-dirty { color: var(--ink-2); }
.ed-save.is-error { color: #a3341f; }

.ed-cols { display: grid; grid-template-columns: 16rem minmax(0, 1fr) 0; gap: 1.5rem;
  padding: 1rem; }
.ed-cols:has(#ed-changes:not([hidden])) { grid-template-columns: 16rem minmax(0, 1fr) 22rem; }
.ed-outline { position: sticky; align-self: start; max-height: 78vh;
  top: calc(var(--mh, 3.33rem) + var(--edbar, 3rem) + 0.75rem);
  overflow-y: auto; font-size: 0.8rem; }
.ed-outlist { list-style: none; margin: 0; padding: 0; }
.ed-outlist a { display: block; padding: 0.2rem 0; text-decoration: none; color: var(--ink-2); }
.ed-outlist a:hover { color: var(--primary); }
.ed-outlist .n { font-family: var(--font); font-variant-numeric: tabular-nums;
  color: var(--ink-3); margin-right: 0.4rem; }
.ed-out-article > a { font-weight: 600; margin-top: 0.4rem; }
.ed-out-section > a { padding-left: 0.75rem; }

/* A block boundary is visible because it is structural. The left rule is the boundary you
   cannot type through, which is the difference between this and a word processor. */
/* A hairline between blocks, because the boundary is the thing you cannot type through and
   an editor that hides its own structure is a word processor. */
.eb { border-left: 2px solid transparent; border-top: 1px solid var(--rule);
  padding: 0.2rem 0 0.2rem 0.6rem; margin: 0; position: relative; }
.eb .eb { margin-left: 0.9rem; }
.eb:first-child { border-top: 0; }
.eb:hover { border-left-color: var(--rule); }
.eb.is-cursor { border-left-color: var(--primary); background: #fcfcfd; }
.eb.is-changed { border-left-color: var(--secondary); }
.eb.is-new { border-left-color: var(--secondary); background: color-mix(in srgb, var(--secondary) 6%, #fff); }
.eb.is-struck { opacity: 0.45; text-decoration: line-through; }
.eb-head { display: flex; gap: 0.5rem; align-items: baseline; font-size: 0.7rem;
  color: var(--ink-3); }
.eb-num { font-family: var(--font); font-variant-numeric: tabular-nums; min-width: 1ch;
  display: inline-block; }
/* A provision with no number yet still has to be clickable, and has to say what belongs
   there. A definition's word is typed here and is not optional. */
.eb-num:empty::before {
  content: attr(data-placeholder); color: var(--ink-3); opacity: 0.7; font-style: italic;
}
.eb-rung { text-transform: none; color: var(--ink-3); opacity: 0.6; }
.eb-heading { font-size: 0.95rem; margin: 0.1rem 0; }
.eb-body { font-size: 0.9rem; line-height: 1.5; }
.eb-body p { margin: 0.25rem 0; }
.eb-body:focus, .eb-heading:focus { outline: 2px solid var(--primary); outline-offset: 2px; }
/* Marked is a rendering of the draft, not a place to type. */
.ed-doc.is-marked .eb-body, .ed-doc.is-marked .eb-heading { background: #fbfbfa; }

.ed-side { position: sticky; align-self: start; max-height: 78vh;
  top: calc(var(--mh, 3.33rem) + var(--edbar, 3rem) + 0.75rem);
  overflow-y: auto; font-size: 0.82rem; border-left: 1px solid var(--rule);
  padding-left: 1rem; }
.ed-side h2 { font-size: 0.95rem; margin: 0 0 0.6rem; }
.ed-ops { margin: 0; padding-left: 1.1rem; }
.ed-ops li { margin: 0.5rem 0; }
.ed-ops a { text-decoration: none; color: inherit; display: block; }
.ed-ops a:hover .ed-target { color: var(--primary); }
/* Throwing one amendment out of the round. Quiet until the change it belongs to is under
   the pointer, because a row of buttons reads as a form rather than as a list of changes. */
.ed-ops li { position: relative; padding-right: 4rem; }
.ed-drop {
  position: absolute; top: 0; right: 0; opacity: 0;
  border: 1px solid var(--rule); background: #fff; color: var(--ink-3);
  font: inherit; font-size: 0.7rem; padding: 0.1rem 0.4rem; border-radius: 0.25rem;
  cursor: pointer; transition: opacity 0.12s;
}
.ed-ops li:hover .ed-drop, .ed-drop:focus-visible { opacity: 1; }
.ed-drop:hover { border-color: var(--del); color: var(--del); }
.ed-op { color: var(--primary); font-weight: 600; }
.ed-target { color: var(--ink-2); }
.ed-author { display: block; color: var(--ink-3); font-size: 0.7rem; }
.ed-derived { font-size: 0.78rem; font-weight: 600; color: var(--ink-2);
  margin: 1rem 0 0.3rem; }
.ed-renum { margin: 0; padding-left: 1.1rem; list-style: none; }
.ed-renum li { margin: 0.2rem 0; }
.ed-renum a { font-family: var(--font); font-variant-numeric: tabular-nums;
  font-size: 0.74rem; color: var(--ink-3); text-decoration: none; }
.ed-renum a:hover { color: var(--primary); }
.ed-none { color: var(--ink-3); }

@media (max-width: 900px) {
  .ed-cols { grid-template-columns: minmax(0, 1fr); }
  .ed-outline { display: none; }
  .ed-bar { flex-wrap: wrap; }
  .ed-save { min-width: 0; }
}
.ed-btn.is-armed { background: #a3341f; border-color: #a3341f; color: #fff; }
.ed-btn:disabled { opacity: 0.45; cursor: default; border-color: var(--rule);
  background: #fff; color: var(--ink-3); }

/* Review: the same chapter, read rather than written. The bar says what the round is and
   carries the one act the page exists for. */
.ed-bar-review { gap: 1.25rem; }
.ed-back { font-size: 0.82rem; color: var(--ink-2); text-decoration: none; }
.ed-back:hover { color: var(--primary); }
.ed-round { font-size: 0.82rem; color: var(--ink-2); }
.ed.is-review .eb-grip { display: none; }
.ed.is-review .eb-num, .ed.is-review .eb-heading, .ed.is-review .eb-body { cursor: default; }
/* The changes rail is the page in review, not a third tab of it. */
.ed.is-review .ed-cols { grid-template-columns: 14rem minmax(0, 1fr) 24rem; }

/* A provision given a different rung. The compiler retags it where it stands, so nothing
   moves; the indent is the only way to see on the page what the drafter dragged. */
.eb.is-reclassified > .eb-head > .eb-rung { color: var(--secondary); opacity: 1;
  font-weight: 600; }
/* Publishing is the act that mints a Revision, so what happened stays on the page rather
   than living in a status word the next keystroke overwrites. */
.ed-banner {
  display: flex; gap: 1rem; align-items: center; justify-content: space-between;
  padding: 0.6rem 1rem; background: color-mix(in srgb, var(--secondary) 10%, #fff);
  border-bottom: 1px solid var(--rule); font-size: 0.86rem;
}
.ed-banner p { margin: 0; }

/* The grip is the drag target, so it is always in the same place and never in the text.
   Up and down reorders; sideways changes the rung, which is a different act on the same
   provision and is why one handle serves both. */
.eb-grip {
  cursor: grab; user-select: none; color: var(--ink-3); opacity: 0.35;
  font-size: 0.8rem; line-height: 1; letter-spacing: -0.1em; touch-action: none;
}
.eb:hover > .eb-head > .eb-grip { opacity: 0.9; }
.eb.is-dragging { opacity: 0.55; }
body.is-dragging-block { cursor: grabbing; user-select: none; }
/* Where it will land. A line rather than a gap, so nothing below jumps while dragging. */
.eb.is-drop-before { box-shadow: 0 -2px 0 0 var(--primary); }
.eb.is-drop-after { box-shadow: 0 2px 0 0 var(--primary); }
/* A number that changed because something else moved. Shown as the number it will be,
   because "renumbering on compile" is the editor talking about its own machinery when the
   question was what the code will read like. */
.eb.is-renumbered > .eb-head > .eb-num {
  color: var(--secondary); font-weight: 600;
}
.eb.is-renumbered > .eb-head > .eb-num::after {
  content: "renumbered"; font-weight: 400; font-size: 0.62rem; opacity: 0.75;
  margin-left: 0.35rem; letter-spacing: 0.02em;
}
/* Followed here from the Changes panel. */
.eb.is-found { background: color-mix(in srgb, var(--secondary) 14%, #fff); }
/* What a provision says after its children, which is where it is rendered. */
.eb-wrap { margin-top: 0.3rem; }

/* The "+" in the gap between two blocks: where somebody wanting to add a provision is
   already pointing. Dragging it sideways picks the rung before it is created, so where and
   what are one gesture. */
/* The insertion point is the boundary itself.
   Every block is already separated from the next by a hairline, because a block boundary is
   the thing you cannot type through. Hovering one turns it into the rule the new provision
   will sit on, indented to its rung, with the "+" on the line rather than out in the
   margin beside it. */
.eb-ins {
  position: absolute; z-index: 20; height: 0; display: flex; align-items: center;
  gap: 0.4rem; pointer-events: none;
}
.eb-ins-rule {
  flex: 1; height: 1px; background: var(--primary); opacity: 0.55;
}
.eb-ins-add {
  pointer-events: auto; cursor: grab;
  width: 1.15rem; height: 1.15rem; flex: none; margin-left: -0.575rem;
  border: 1px solid var(--primary); border-radius: 50%; background: #fff;
  color: var(--primary); font: inherit; font-size: 0.8rem; line-height: 1;
  display: flex; align-items: center; justify-content: center; padding: 0;
}
.eb-ins-add:hover { background: var(--primary); color: #fff; }
.eb-ins-add:active { cursor: grabbing; }
.eb-ins-rung {
  font-size: 0.66rem; letter-spacing: 0.02em; color: var(--primary);
  background: #fff; padding: 0 0.2rem 0 0; flex: none;
}

.eb-opaque, .eb.is-opaque .eb-head {
  color: var(--ink-3); font-size: 0.75rem; background: #f7f7f6;
  border: 1px dashed var(--rule); border-radius: 0.25rem;
  padding: 0.25rem 0.5rem; margin: 0.3rem 0; display: inline-block;
}
.eb-opaque span { opacity: 0.7; font-style: italic; margin-left: 0.4rem; }

/* A definition's number is the defined word, so it is set like one rather than like 240-1.4. */
.eb[data-rung="hcontainer"] > .eb-head > .eb-num {
  font-family: inherit; font-weight: 600; color: var(--ink-2); font-size: 0.75rem;
}
