/* 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 {
  /* The CommunityScale web design system's colors (src/communityscale/shared/brand_colors.py
     in the app; app.communityscale.io/internal/design shows them). render/test_design.py
     keeps these equal to the tokens. The site is grayscale: a town's own colors are its seal
     and its zoning map, not the page around them. */
  --neutral-50: #fafafa; --neutral-100: #f5f5f5; --neutral-200: #e5e5e5; --neutral-300: #d4d4d4;
  --neutral-400: #a3a3a3; --neutral-500: #737373; --neutral-600: #525252; --neutral-700: #404040;
  --neutral-800: #262626; --neutral-900: #171717; --neutral-950: #0a0a0a;
  --brand-200: #c2d8ff; --brand-300: #adbfff; --brand-700: #3445b0; --brand-900: #192f5e;
  --success-50: #f3fae8; --success-300: #b6d57f; --success-700: #4e6704;
  --error-50: #fff4f2; --error-300: #feb1a0; --error-400: #fc866c; --error-600: var(--error-600); --error-700: #a5270b;
  --warning-50: #fbf8e1; --warning-100: #f5efc1; --warning-200: #eadf8e; --warning-300: #ecd731; --warning-700: #685d06;
  --dark-page: #111214; --dark-surface: #17181b; --dark-raised: #1d1f22;
  --dark-text: #e9e7e2; --dark-body: #c9c8c4; --dark-muted: #8d9096;

  /* What the rules below use. Each has a dark twin under [data-theme="dark"]. */
  --paper: #ffffff;                   /* the page */
  --paper-2: var(--neutral-50);       /* the contents rail, the bars, quiet panels */
  --surface: #ffffff;                 /* cards, inputs, tables */
  --raised: #ffffff;                  /* menus and popovers */
  --ink: var(--neutral-950);          /* headings, names, the strongest text */
  --body: var(--neutral-800);         /* the law itself */
  --ink-2: var(--neutral-600);        /* secondary text */
  --ink-3: var(--neutral-500);        /* numbers and notes: 4.74:1 on the page, 4.54:1 on the rail */
  --rule: var(--neutral-200);
  --rule-strong: var(--neutral-300);
  --link: var(--brand-700);
  --link-hover: var(--brand-900);
  --focus: var(--brand-900);
  /* The primary button's gray, which also marks whatever is chosen: a selected reading, the
     current tab, the active district. Never a block of black. */
  --fill: var(--neutral-200);
  --fill-hover: var(--neutral-300);
  --fill-ink: var(--neutral-950);
  --wash: var(--neutral-100);         /* hover and the row being commented on */
  --current: #ffffff;                 /* the contents entry being read, on the rail's gray */
  --seg-track: var(--neutral-100);    /* a segmented control's track and its chosen side */
  --seg-on: #ffffff;
  --mark: var(--warning-100);         /* a search hit, the section followed to */
  --ins: var(--success-700);
  --ins-bg: var(--success-50);
  --del: var(--error-700);
  --del-bg: var(--error-50);
  --warn-ink: var(--warning-700);
  --warn-bg: var(--warning-50);
  --warn-rule: var(--warning-200);
  --info-bg: var(--neutral-50);
  --info-rule: var(--neutral-300);
  --danger: var(--error-700);
  --on-strong: #ffffff;               /* text on a green or red fill */
  --shadow: rgba(10, 10, 10, 0.12);

  /* The names the rest of this sheet was written with. A town's palette used to land here;
     now the strong color is ink and the accent a mid gray. */
  --primary: var(--ink);
  --primary-soft: var(--ink-2);
  --secondary: var(--neutral-500);
  --pill-active: var(--fill);

  --measure: 64ch;
  --rail: 21rem;
  --margin: 20rem;
  --font: 'Roboto', system-ui, sans-serif;
  --cond: 'Roboto Condensed', 'Arial Narrow', sans-serif;
  color-scheme: light;
}

/* Dark: the design system's dark palette, true grays rather than black. ds-theme.js sets
   data-theme before the first paint from the system's setting or the masthead's toggle. */
:root[data-theme="dark"] {
  --paper: var(--dark-page);
  --paper-2: var(--dark-surface);
  --surface: var(--dark-surface);
  --raised: var(--dark-raised);
  --ink: var(--dark-text);
  --body: var(--dark-body);
  --ink-2: var(--dark-muted);
  --ink-3: var(--dark-muted);
  --rule: rgba(255, 255, 255, 0.1);
  --rule-strong: rgba(255, 255, 255, 0.2);
  --link: var(--brand-300);
  --link-hover: var(--brand-200);
  --focus: var(--brand-300);
  --fill: rgba(255, 255, 255, 0.15);
  --fill-hover: rgba(255, 255, 255, 0.2);
  --fill-ink: #ffffff;
  --wash: rgba(255, 255, 255, 0.06);
  --current: rgba(255, 255, 255, 0.1);
  --seg-track: rgba(255, 255, 255, 0.1);
  --seg-on: var(--neutral-700);
  --mark: rgba(236, 215, 49, 0.22);
  --ins: var(--success-300);
  --ins-bg: rgba(153, 187, 84, 0.14);
  --del: var(--error-300);
  --del-bg: rgba(252, 134, 108, 0.14);
  --warn-ink: var(--warning-300);
  --warn-bg: rgba(193, 174, 12, 0.1);
  --warn-rule: rgba(193, 174, 12, 0.35);
  --info-bg: rgba(255, 255, 255, 0.04);
  --info-rule: rgba(255, 255, 255, 0.12);
  --danger: var(--error-400);
  --on-strong: var(--dark-page);
  --shadow: rgba(0, 0, 0, 0.5);
  --secondary: var(--dark-muted);
  color-scheme: dark;
}

/* 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(--body);
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

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

/* Material Icons Outlined, in the box a 20px icon uses, centered on the line it belongs to. */
.mi {
  font-family: 'Material Icons Outlined'; font-weight: normal; font-style: normal;
  font-size: 20px; line-height: 1; width: 1em; height: 1em; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  vertical-align: middle; white-space: nowrap; direction: ltr;
  font-feature-settings: 'liga'; -webkit-font-smoothing: antialiased; user-select: none;
}

/* ── buttons ──────────────────────────────────────────────────────────────── */

/* The design system's two buttons: the primary a gray fill with black text, the secondary a
   black outline with no fill. One text size for both. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.375rem;
  padding: 0.5rem 0.75rem; border: 0; border-radius: 0.375rem;
  font: inherit; font-size: 0.875rem; font-weight: 600; line-height: 1.25rem;
  text-decoration: none; cursor: pointer; max-width: 100%; text-align: center;
  color: var(--ink); background: transparent; box-shadow: inset 0 0 0 1px var(--ink);
}
.btn:hover { color: var(--ink); background: var(--wash); }
.btn-primary { background: var(--fill); color: var(--fill-ink); box-shadow: none; }
.btn-primary:hover { background: var(--fill-hover); color: var(--fill-ink); }
.btn .mi { font-size: 18px; }
.btn-sm { padding: 0.375rem 0.625rem; }
/* An icon on its own, in a 36px target: the light and dark toggle. */
.iconbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.25rem; height: 2.25rem; padding: 0; border: 0; border-radius: 0.375rem;
  color: var(--ink-2); background: none; cursor: pointer;
}
.iconbtn:hover { color: var(--ink); background: var(--wash); }
.mi-dark { display: none; }
:root[data-theme="dark"] .mi-light { display: none; }
:root[data-theme="dark"] .mi-dark { display: inline-flex; }

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

/* The town's seal and name at the left, the instruments it publishes as tabs, and the
   downloads, the light and dark toggle and the account at the right, as the design system's
   code page sets them. In the page's own color, solid: the town is named by its seal, not
   by a band of its color. */
.masthead {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: stretch; gap: 0 1.5rem;
  min-height: 3.5rem; padding: 0 clamp(1rem, 3vw, 2rem);
  background: var(--paper); color: var(--ink);
  border-bottom: 1px solid var(--rule);
}
.brand {
  display: flex; align-items: center; gap: 0.75rem; min-width: 0;
  color: var(--ink); text-decoration: none; white-space: nowrap;
  font-family: var(--cond); font-size: 1.125rem; font-weight: 700;
}
.brand:hover { color: var(--ink); }
.brand-what { font-weight: 300; }
/* CommunityScale's own pages carry the product lockup: the symbol, CommunityScale in
   semibold, then the product in regular weight, 0.5em apart. */
.brand-product { align-items: baseline; align-self: center; gap: 0.5em; font-family: var(--font); font-size: 1rem; font-weight: 600; }
.brand-product .brand-what { font-weight: 400; }
.topnav { display: flex; align-items: stretch; gap: 1.5rem; font-size: 0.875rem; }
.topnav a {
  display: inline-flex; align-items: center; padding-top: 2px;
  color: var(--ink-2); text-decoration: none; border-bottom: 2px solid transparent;
}
.topnav a:hover { color: var(--ink); border-bottom-color: var(--rule-strong); }
.topnav a[aria-current="page"], .topnav a.is-on {
  color: var(--ink); font-weight: 500; border-bottom-color: var(--ink);
}
.mast-tools { display: flex; align-items: center; gap: 0.5rem; margin-left: auto; }

/* The Download menu: a <details>, so it opens without a script (menus.js closes it). */
.menu { position: relative; }
.menu > summary { list-style: none; white-space: nowrap; }
.menu > summary::-webkit-details-marker { display: none; }
.menu .mi-caret { margin-right: -0.25rem; transition: transform 0.15s; }
.menu[open] .mi-caret { transform: rotate(180deg); }
.menu-panel {
  position: absolute; right: 0; top: calc(100% + 0.25rem); z-index: 50;
  min-width: 17rem; padding: 0.25rem;
  background: var(--raised); border-radius: 0.375rem;
  box-shadow: 0 10px 25px -5px var(--shadow), 0 0 0 1px var(--rule);
}
.menu-panel a {
  display: flex; align-items: center; gap: 0.625rem;
  padding: 0.5rem 0.625rem; border-radius: 0.25rem;
  color: var(--ink); font-size: 0.875rem; text-decoration: none; white-space: nowrap;
}
.menu-panel a .mi { color: var(--ink-3); font-size: 18px; }
.menu-panel a:hover, .menu-panel a:focus-visible { background: var(--wash); color: var(--ink); }

/* ── 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: var(--warn-bg); border-bottom-color: var(--warn-rule); }
/* Adopted and not yet in effect, or in effect with an adoption pending: a fact about the
   law's status, so it reads as neither a draft (amber) nor a defect. */
.banner-stage { background: var(--info-bg); border-bottom-color: var(--info-rule); }
.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); }
}

/* The rail never scrolls itself: the Contents toggle sits on top and the list below it is
   the one scrolling box. With the list at the rail's full height under the toggle, the rail
   overflowed by the toggle's height and showed a second scrollbar beside the list's. */
.rail {
  position: sticky; top: 3.6rem; align-self: start;
  height: calc(100vh - 3.6rem); overflow: hidden;
  display: flex; flex-direction: column;
  background: var(--paper-2); border-right: 1px solid var(--rule);
}
.rail-inner { flex: 1 1 auto; min-height: 0; 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.45rem 1.85rem 0.45rem 0.65rem; font: inherit; font-size: 0.875rem; color: var(--ink);
  background: var(--surface); border: 1px solid var(--rule-strong); border-radius: 0.375rem;
  -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(--ink); background: var(--wash); }
.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: var(--surface); }
/* The result the reader followed, marked because the list stays up behind them. */
.result.is-current { background: var(--surface); 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: var(--mark); color: inherit; border-radius: 2px; }
.toc-art {
  padding: 1rem 1.25rem 0.35rem; font-family: var(--cond); font-size: 0.9rem; font-weight: 500;
  color: var(--ink); 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: 4rem 1fr; gap: 0.4rem;
  margin: 0 0.75rem; padding: 0.35rem 0.5rem; border-radius: 0.375rem;
  font-size: 0.875rem; line-height: 1.35; color: var(--body); text-decoration: none;
}
.toc-sec a:hover { background: var(--current); color: var(--ink); }
.toc-sec.is-target a {
  background: var(--current); color: var(--ink); font-weight: 500;
  box-shadow: 0 0 0 1px var(--rule), 0 1px 2px var(--shadow);
}
.toc-num { font-family: var(--font); font-variant-numeric: tabular-nums; font-size: 0.75rem; font-weight: 400; 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);
}
.doc-title .doc-num { font-weight: 700; margin-right: 0.3em; }
/* Where the page belongs (the town, the state, the body of law), under its title rather
   than over it: the design system puts no label above a heading. */
.place { margin: -0.5rem 0 1.5rem; font-size: 1.1rem; color: var(--ink-2); }
.doc-title + .place { margin: -2rem 0 2.5rem; font-size: 1rem; }

/* ── 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.125rem; font-weight: 600; line-height: 1.35;
}
.sec-num { font-family: var(--font); font-variant-numeric: tabular-nums; font-size: 1em; font-weight: 500; color: var(--ink-3); }
.sec-title { font-size: 1em; color: var(--ink); }
.sec:target .sec-num { background: var(--mark); color: var(--ink); padding: 0 0.25rem; border-radius: 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 color-mix(in srgb, var(--ins) 35%, var(--surface)); border-radius: 2px; padding: 0.05rem 0.35rem;
}

.history {
  font-size: 0.75rem; color: var(--ink-3);
  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%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--chip) 55%, var(--surface));
}
.chip:hover { background: color-mix(in srgb, var(--chip) 40%, var(--surface)); }

/* ── 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.875rem; color: var(--ink-3);
  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);
 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: var(--surface); 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-radius: 0.375rem; -webkit-overflow-scrolling: touch; }
.code-table td > p, .code-table th > p { margin: 0.15rem 0; }
.code-table { border-collapse: collapse; font-size: 0.875rem; min-width: 100%; color: var(--body); }
/* 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); padding: 0.5rem 0.75rem 0.5rem 0; vertical-align: top;
}
.code-table tr:first-child td { color: var(--ink); font-weight: 600; border-bottom-color: var(--rule-strong); }
/* 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; }
.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: var(--surface); 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: var(--surface); 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 ─────────────────────────────────────────────────────────── */

/* The map's own controls sit on the design system's surface: a card with a hairline ring,
   solid rather than frosted, in the page's light or dark. */
.mapctl {
  position: absolute; left: 0.75rem; top: 0.75rem; z-index: 5;
  display: flex; flex-direction: column; gap: 0.5rem;
  width: max-content; max-width: calc(100% - 1.5rem); padding: 0.5rem;
  background: var(--raised); border-radius: 0.5rem;
  box-shadow: 0 1px 3px var(--shadow), 0 0 0 1px var(--rule);
}
.mapctl-row {
  display: flex; align-items: center; gap: 0.5rem; padding: 0 0.125rem;
  font-size: 0.8125rem; color: var(--ink); cursor: pointer;
}
.mapctl-row input { accent-color: var(--ink); width: 1rem; height: 1rem; margin: 0; }
.mapctl-seg { display: flex; }
/* Adopted against proposed: the design system's segmented control, the same as the
   Map | Satellite switch the shared map runtime draws across the map. */
.mapctl-pills {
  display: inline-flex; padding: 2px; border-radius: 6px; background: var(--seg-track);
}
.mapctl-pills button {
  font: inherit; font-size: 0.8125rem; font-weight: 500; line-height: 1.25rem; white-space: nowrap;
  padding: 0.25rem 0.75rem; border: 0; border-radius: 5px; cursor: pointer;
  color: var(--ink-2); background: transparent;
}
.mapctl-pills button:hover { color: var(--ink); }
.mapctl-pills button.is-on { color: var(--ink); background: var(--seg-on); box-shadow: 0 1px 2px var(--shadow); }
/* "Comment on a place" starts something rather than choosing a reading, so it is the
   primary button: the gray fill. While a place is being chosen it holds the darker gray. */
.mapctl-pin {
  display: inline-flex; align-items: center; justify-content: center; width: 100%;
  font: inherit; font-size: 0.8125rem; font-weight: 600; line-height: 1.25rem; cursor: pointer;
  padding: 0.375rem 0.625rem; color: var(--fill-ink); background: var(--fill);
  border: 0; border-radius: 0.375rem;
}
.mapctl-pin:hover, .mapctl-pin.is-on { background: var(--fill-hover); }

/* ── 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. The design system's search box: a
   magnifier at the left, a hairline ring, the surface behind. */
.mapsearch {
  position: absolute; top: 0.75rem; left: 50%; transform: translateX(-50%); z-index: 5;
  width: min(21rem, calc(100% - 7.5rem));
}
.mapsearch::before {
  content: 'search'; position: absolute; left: 0.625rem; top: 0.5rem; z-index: 1;
  font-family: 'Material Icons Outlined'; font-size: 18px; line-height: 1; color: var(--ink-3);
  font-feature-settings: 'liga'; pointer-events: none;
}
.mapsearch-input {
  width: 100%; box-sizing: border-box; font: inherit; font-size: 0.875rem; line-height: 1.25rem;
  padding: 0.4375rem 0.75rem 0.4375rem 2.125rem; color: var(--ink);
  background: var(--raised); border: 0; border-radius: 0.375rem;
  box-shadow: 0 1px 3px var(--shadow), inset 0 0 0 1px var(--rule-strong);
}
.mapsearch-input::placeholder { color: var(--ink-3); }
.mapsearch-input:focus { outline: 2px solid var(--focus); outline-offset: 0; }
.mapsearch-results {
  margin-top: 0.25rem; max-height: 60vh; overflow-y: auto; padding: 0.25rem;
  background: var(--raised); border-radius: 0.375rem;
  box-shadow: 0 10px 25px -5px var(--shadow), 0 0 0 1px var(--rule);
}
.mapsearch-result {
  display: block; width: 100%; text-align: left; font: inherit; font-size: 0.875rem;
  padding: 0.5rem 0.625rem; color: var(--ink); background: none;
  border: 0; border-radius: 0.25rem; cursor: pointer;
}
.mapsearch-result:hover, .mapsearch-result:focus-visible { background: var(--wash); }
.mapsearch-none { margin: 0; padding: 0.5rem 0.625rem; font-size: 0.875rem; color: var(--ink-2); }

/* ── 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(--fill); border: 2px solid var(--surface);
  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(--fill-hover); }
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;
 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: var(--surface); }
.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: dotted;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--neutral-400);
  text-underline-offset: 4px;
}
.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: var(--surface); }
.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: var(--surface); }
.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.75rem; bottom: 0.75rem; z-index: 5; max-width: min(18rem, calc(100% - 1.5rem));
  background: var(--raised); border-radius: 0.5rem;
  box-shadow: 0 1px 3px var(--shadow), 0 0 0 1px var(--rule);
  overflow: hidden;
}
.maplegend-toggle {
  display: flex; align-items: center; gap: 0.25rem; width: 100%;
  font: inherit; font-size: 0.875rem; font-weight: 600; cursor: pointer;
  padding: 0.5rem 0.625rem; color: var(--ink); background: none; border: 0;
}
.maplegend-toggle::before {
  content: 'chevron_right'; font-family: 'Material Icons Outlined'; font-size: 18px; font-weight: 400;
  line-height: 1; color: var(--ink-3); font-feature-settings: 'liga'; transition: transform 0.15s;
}
.maplegend.is-open .maplegend-toggle::before { transform: rotate(90deg); }
.maplegend-toggle span { font-weight: 400; font-variant-numeric: tabular-nums; color: var(--ink-3); }
.maplegend-items { display: none; max-height: 42vh; overflow-y: auto; padding: 0 0.375rem 0.5rem; }
.maplegend.is-open .maplegend-items { display: block; }
/* The groups are named in the text's own color, a weight lighter than the panel's title. */
.maplegend-group {
  margin: 0.625rem 0 0.25rem; padding: 0 0.25rem;
  font-size: 0.8125rem; font-weight: 500; color: var(--ink);
}
.maplegend-group:first-child { margin-top: 0; }
.maplegend-item {
  display: flex; align-items: center; gap: 0.5rem; width: 100%;
  font: inherit; font-size: 0.8125rem; text-align: left; cursor: pointer;
  padding: 0.25rem; color: var(--body); background: none;
  border: 0; border-radius: 0.25rem;
}
.maplegend-item:hover { background: var(--wash); color: var(--ink); }
.maplegend-item.is-active { background: var(--fill); color: var(--fill-ink); }
.maplegend-item i {
  width: 0.75rem; height: 0.75rem; 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.25rem 1rem;
  padding: 0.125rem 0.25rem 0.5rem;
  border-bottom: 1px solid var(--rule); margin-bottom: 0.5rem;
}
.maplegend-switch {
  display: flex; align-items: center; gap: 0.5rem;
  font-size: 0.8125rem; color: var(--ink); cursor: pointer;
}
.maplegend-switch input { accent-color: var(--ink); width: 1rem; height: 1rem; margin: 0; }

/* ── 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; 
 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, the tabs and the tools without truncating all of them,
     so the tabs get a row of their own under the name, scrolling sideways if they must. */
  .masthead { flex-wrap: wrap; padding: 0 0.85rem; gap: 0 0.75rem; }
  .brand { min-height: 3.5rem; font-size: 1.05rem; gap: 0.5rem; }
  .brand-town { display: none; }
  .brand-town-short { display: inline; }
  .topnav {
    order: 3; flex: 1 0 100%; gap: 1.25rem; margin: 0 -0.85rem; padding: 0 0.85rem;
    overflow-x: auto; scrollbar-width: none; border-top: 1px solid var(--rule);
  }
  .topnav::-webkit-scrollbar { display: none; }
  .topnav a { white-space: nowrap; padding: 0.5rem 0 0.4rem; }
  .menu-label, .menu .mi-caret { display: none; }
  .menu > summary { padding: 0.375rem; }
  .menu-panel { position: fixed; left: 0.85rem; right: 0.85rem; top: 3.25rem; min-width: 0; }
  /* The label leaves the screen but not the button's name: the icon is hidden from assistive
     technology, so the label is what a screen reader announces. */
  .authbtn > span:not(.mi), .portal-admin > span:not(.mi) {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip: rect(0 0 0 0); white-space: nowrap;
  }
  .authbtn, .portal-admin { padding: 0.375rem; }

  .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; }

  /* No number column on a phone. A gutter per level compounds: five levels of Lowell's
     signs provisions left the text a few words wide, one word per line in places. The
     marker runs in ahead of the first line instead, and each level steps in a little, so
     depth still reads (with the change bar) without spending the width on it. The line
     height is the body's 1.6 at 16px, set on the smaller marker so both baselines match. */
  .prov, .prov .prov, .prov .prov .prov { display: block; }
  .prov { padding-left: 0.55rem; }
  .prov-num { float: left; font-size: 0.75rem; line-height: 2.1333; padding-right: 0.4rem; }
  .prov-body { max-width: none; }
  /* The why-marker sits past the provision's right edge on a wide screen, which on a phone
     is off the screen. Keep it inside, in room the provision leaves for it. */
  body .prov:has(> .anote-mark), body .definition:has(> .anote-mark) { padding-right: 1.7rem; }
  body .prov > .anote-mark, body .definition > .anote-mark { left: auto; right: 0; margin: 0; }
  body .sec > .sec-head .anote-mark { position: static; margin-left: 0.3rem; }
  .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: var(--surface); 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: var(--warn-bg); border-bottom-color: var(--warn-rule); }
.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: var(--warn-bg); border-left: 3px solid var(--warn-ink); font-size: 0.88rem; line-height: 1.5;
}
.review-notice strong { color: var(--warn-ink); }

/* ── 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: var(--surface); 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: var(--warn-ink); background: var(--warn-bg);
  border: 1px solid var(--warn-rule); 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: var(--fill-ink); background: var(--fill); border: 1px solid var(--fill); border-radius: 2px;
}
.comment-form button:hover { background: var(--fill-hover); }
.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: var(--surface); 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(--fill); color: var(--fill-ink); border-color: var(--fill); }
.mod-tab.is-on span { color: var(--ink-2); }

.mod-card { background: var(--surface); border: 1px solid var(--rule); padding: 0.9rem 1rem; margin-bottom: 0.7rem; }
.mod-card.is-pending { border-left: 3px solid var(--warn-ink); }
.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: var(--surface); color: var(--primary); border: 1px solid var(--primary); border-radius: 2px;
}
.mod-actions button:hover { background: var(--fill); color: var(--fill-ink); }
.mod-actions button:disabled { opacity: 0.5; cursor: default; }

.mod-gate { background: var(--surface); 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(--fill); color: var(--fill-ink); border: 1px solid var(--fill); 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; }
.authwho { font-size: 0.75rem; color: var(--ink-2); max-width: 12rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Sign in is the secondary button with a person icon, as in the design system's code page. */
.authbtn {
  display: inline-flex; align-items: center; gap: 0.375rem;
  padding: 0.375rem 0.625rem; border: 0; border-radius: 0.375rem; cursor: pointer;
  font: inherit; font-size: 0.875rem; font-weight: 600; line-height: 1.25rem; white-space: nowrap;
  color: var(--ink); background: transparent; box-shadow: inset 0 0 0 1px var(--ink);
}
.authbtn .mi { font-size: 18px; }
.authbtn:hover { background: var(--wash); }

@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, 3vw, 2rem);
  background: var(--paper-2); border-bottom: 1px solid var(--rule);
  font-size: 0.875rem; color: var(--ink-2);
}
.switch { display: inline-flex; align-items: center; gap: 0.4rem; cursor: pointer; }
.switch input { accent-color: var(--ink); width: 1rem; height: 1rem; }
.controls-label {
  color: var(--ink-2); font-size: 0.875rem; 
  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(--font); font-size: 0.875rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.controls-crumb:empty { display: none; }
.controls-crumb .crumb-sec { color: var(--ink); font-weight: 600; }
/* 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; }
/* Except the banner's legend, which names both marks whatever the view: hidden, it read
   "inserted and . 24 of 52 sections". */
body.view-proposed .banner del { display: inline; }
/* 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; background: var(--seg-track);
  border: 0; border-radius: 0.375rem; padding: 0.125rem; }
.viewpick label { cursor: pointer; padding: 0.2rem 0.75rem; border-radius: 5px; font-weight: 500; color: var(--ink-2); white-space: nowrap; }
.viewpick label:hover { color: var(--ink); }
.viewpick label:has(input:focus-visible) { outline: 2px solid var(--focus); }
.viewpick input { position: absolute; opacity: 0; pointer-events: none; }
.viewpick label:has(input:checked) { background: var(--seg-on); color: var(--ink); box-shadow: 0 1px 2px var(--shadow); }
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: var(--on-strong); 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: var(--on-strong); }
  .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;
  /* Notes may overlap (see site.js): each sits level with its change, so an opaque card
     with a shadow reads as lying over the one above, whose heading still shows. */
  background: color-mix(in srgb, var(--ins) 7%, var(--paper));
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.margin > .anote:hover, .margin > .anote:focus-within, .margin > .anote.is-linked {
  z-index: 5;
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--ins) 45%, transparent), 0 6px 22px rgba(0, 0, 0, 0.16);
}
/* A note whose change is not shown in the current view (site.js). */
.margin > .anote.is-offstage { display: none; }
/* The change a note is about, while the reader is on the note. */
.note-target {
  outline: 2px solid color-mix(in srgb, var(--ins) 45%, transparent);
  outline-offset: 3px; border-radius: 2px;
}
.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: 500; font-size: 0.8125rem; color: var(--ink);
  border-bottom: 1px solid var(--rule-strong); text-align: center;
}
.matrix thead .corner { border: 0; background: none; }
.matrix .unit {
  display: block; font-family: var(--font); font-weight: 400;
  font-size: 0.72rem; color: var(--ink-3);
}
.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: var(--surface); }

.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%; flex-shrink: 0;
  font: inherit; font-size: 0.875rem; text-align: left; cursor: pointer;
  padding: 0.45rem 1rem; color: var(--ink-2);
  background: var(--paper-2); border: 0; border-bottom: 1px solid var(--rule);
}
.rail-toggle::before { content: 'chevron_left'; font-family: 'Material Icons Outlined'; font-size: 18px; vertical-align: -0.3em; margin-right: 0.15rem; color: var(--ink-3); font-feature-settings: 'liga'; }
.rail-toggle:hover { color: var(--ink); }
body.rail-collapsed .rail-inner { display: none; }
body.rail-collapsed .rail-toggle::before { content: 'chevron_right'; }
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.875rem; background: var(--surface); min-width: 100%; color: var(--body); }
/* The design system's table: rules between rows only, the header in bold over a stronger
   rule, no fill and no stripes, and the row under the pointer washed. */
.matrix th, .matrix td {
  border: 0; border-bottom: 1px solid var(--rule); padding: 0.5rem 0.625rem; 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(--surface); color: var(--ink); font-weight: 600; font-family: var(--font);
  white-space: nowrap; vertical-align: bottom; border-bottom-color: var(--rule-strong);
}
/* 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(--font); font-variant-numeric: tabular-nums; font-size: 0.75rem; font-weight: 400; color: var(--ink-3);
}
/* 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: var(--surface);
  box-shadow: 1px 0 0 var(--rule); }
.matrix tbody tr:hover th { background: color-mix(in srgb, var(--ink) 4%, var(--surface)); }
.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.8125rem; text-align: center; white-space: nowrap; }
.matrix tbody tr:hover { background: var(--wash); }
.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: none; color: var(--ink); font-weight: 600; text-align: left;
  border-bottom: 1px solid var(--rule-strong); padding: 0.5rem 0.75rem 0.5rem 0;
}

/* 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; }
  /* One row under the search: Labels, the segmented control, then the button. */
  .mapctl {
    left: 0.5rem; top: 3.25rem; max-width: calc(100% - 1rem);
    flex-direction: row; flex-wrap: wrap; align-items: center; gap: 0.5rem; padding: 0.375rem;
  }
  .mapctl-pin { width: auto; }
}

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

/* The town's seal, at the height of its name. A seal is drawn for white, so in dark mode it
   sits on a white plate rather than being recolored. */
.brand-logo { height: 2rem; width: auto; flex: 0 0 auto; }
:root[data-theme="dark"] .brand-logo {
  box-sizing: content-box; padding: 0.15rem 0.3rem; border-radius: 0.375rem; background: #fff;
}
.brand-town-short { display: none; }

/* ── about this code, then the CommunityScale footer ──────────────────────── */

/* Who to reach and where the text comes from, then the footer every CommunityScale product
   carries, which links back to us: the town publishes the code and we build the site. */
.about {
  padding: 2.5rem clamp(1rem, 3vw, 2rem); font-size: 0.875rem; color: var(--ink-2);
  background: var(--paper-2); border-top: 1px solid var(--rule);
}
.about-inner { max-width: 48rem; }
.about p { margin: 0.5rem 0; }
.about a { color: var(--ink-2); text-decoration: underline; text-underline-offset: 4px; }
.about a:hover { color: var(--ink); }
.about-pub { color: var(--body); padding-top: 0.5rem; }
.vintage { display: flex; align-items: flex-start; gap: 0.375rem; font-size: 0.75rem; color: var(--ink-2); }
.vintage .mi { font-size: 14px; height: 1rem; }
.foot {
  padding: 2rem clamp(1rem, 3vw, 2rem); font-size: 0.875rem; color: var(--ink-2);
  background: var(--paper); border-top: 1px solid var(--rule);
}
.foot-inner { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1.5rem; }
.social { display: flex; flex-wrap: wrap; align-items: center; gap: 1.5rem; margin: 0; padding: 0; list-style: none; }
.social a { display: flex; margin: -0.5rem; padding: 0.5rem; border-radius: 0.375rem; color: var(--ink-3); }
.social a:hover { color: var(--ink); }
.social svg { width: 1.25rem; height: 1.25rem; fill: currentColor; }
.foot-row { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem 1rem; margin: 0; }
.foot-row a { color: var(--ink-2); text-decoration: none; }
.foot-row a:hover { color: var(--ink); }
a.foot-brand { display: inline-flex; align-items: baseline; gap: 0.5em; color: var(--ink); font-weight: 600; }
a.foot-brand:hover { color: var(--ink-2); }
/* The free-floating symbol, 1em tall, standing on the baseline and dropped 0.09em. */
.symbol { height: 1em; width: auto; aspect-ratio: 153 / 124; fill: currentColor; transform: translateY(0.09em); }
.foot-contact, .foot-links { font-size: 0.875rem; }
.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.5rem; height: 2.5rem; border-radius: 50%;
  text-decoration: none; color: var(--fill-ink); background: var(--fill);
  box-shadow: 0 2px 8px var(--shadow);
}
.totop:hover { color: var(--fill-ink); background: var(--fill-hover); }
body.scrolled .totop { display: flex; }

@media (max-width: 40rem) {
  .brand-logo { height: 1.6rem; }
  .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 nothing. */
@media (max-width: 40rem) {
  .brand-town { display: none; }
  .brand-town-short { display: inline; }
}

/* 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: var(--surface);
  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 {
  color: inherit; text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--chip) 80%, #444); text-decoration-thickness: 1.5px;
  text-underline-offset: 2px;
  padding: 0 0.2rem; border-radius: 2px;
  background: color-mix(in srgb, var(--chip) 10%, transparent);
}
.pill:hover { background: color-mix(in srgb, var(--chip) 30%, transparent); color: inherit; }

/* A defined term keeps the case the bylaw drafted it in: the design system sets nothing in
   capitals, and the bold condensed face above is what marks it as a definition. */

/* 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; 
  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: var(--surface); color: var(--ink);
  border: 0; border-radius: 0.5rem;
  box-shadow: 0 10px 25px -5px var(--shadow), 0 0 0 1px var(--rule);
  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 { }
.term-card-head {
  margin: 0 0 0.4rem;
  font-family: var(--cond); font-size: 0.76rem; 
  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(--ink); font-weight: 600; }
.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: var(--surface); 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; 
  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: var(--surface); }
.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; 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; 
  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 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. */

.portal { display: inline-flex; align-items: center; gap: 0.5rem; }
.portal:empty { display: none; }

/* The comment queue, where a moderation action can lose a race. A conflict is news, not
   an error: somebody else already acted on the same row, so it reads in amber "the base
   moved" language. A stale page is a different problem: nothing on it can be trusted enough to act on,
   so the reload banner offers only the one control that is still safe to press. */
.cs-conflict {
  font-size: 0.8rem; color: var(--warn-ink); background: var(--warn-bg); padding: 0.4rem 0.6rem;
  margin: 0 0 0.7rem;
}
.cs-reload {
  display: flex; gap: 1rem; align-items: center; justify-content: space-between;
  background: var(--del-bg); color: var(--del); border: 1px solid var(--del);
  padding: 0.7rem 1rem; margin-bottom: 1rem; font-size: 0.86rem;
}
.cs-reload button {
  font: inherit; font-size: 0.82rem; padding: 0.3rem 0.9rem; cursor: pointer;
  border: 1px solid currentColor; background: none; color: inherit; flex-shrink: 0;
}

/* ── members ──────────────────────────────────────────────────────────────── */
.mb-tiers { display: grid; grid-template-columns: max-content 1fr; gap: 0.2rem 1rem; font-size: 0.82rem;
  color: var(--ink-2); margin: 0 0 1.25rem; }
.mb-tiers dt { font-weight: 600; color: var(--ink); }
.mb-tiers dd { margin: 0; }
.mb-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; margin-bottom: 1rem; }
.mb-table th { text-align: left; font-size: 0.72rem; 
  color: var(--ink-3); border-bottom: 1px solid var(--rule); padding: 0.3rem 0.4rem; }
.mb-table td { border-bottom: 1px solid var(--rule); padding: 0.45rem 0.4rem; vertical-align: middle; }
.mb-table select { font: inherit; font-size: 0.82rem; padding: 0.15rem 0.3rem; }
.mb-face { width: 1.6rem; height: 1.6rem; border-radius: 50%; vertical-align: middle; margin-right: 0.5rem; }
.mb-name { font-weight: 600; }
.mb-email { display: block; color: var(--ink-3); font-size: 0.78rem; }
.mb-fixed { color: var(--ink-2); font-size: 0.82rem; }
.mb-invites { font-size: 0.85rem; padding-left: 1.1rem; }

/* ── adoption: where a chapter is in its life ───────────────────────────────── */
.lc-steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.5rem; list-style: none;
  padding: 0; margin: 0 0 1.5rem; counter-reset: lc; }
.lc-steps li { border: 1px solid var(--rule); border-top: 4px solid var(--rule); background: var(--surface);
  padding: 0.6rem 0.7rem; font-size: 0.8rem; color: var(--ink-3); }
.lc-steps li.is-past { border-top-color: var(--secondary); }
.lc-steps li.is-here { border-top-color: var(--primary); color: var(--ink); box-shadow: 0 2px 10px rgba(0,0,0,0.06); }
.lc-step-name { display: block; font-weight: 600; font-size: 0.9rem; margin-bottom: 0.2rem; }
.lc-now h2 { font-size: 1.05rem; margin: 0 0 0.4rem; }
.lc-act { border-top: 1px solid var(--rule); padding: 1rem 0; }
.lc-act h3 { font-size: 0.95rem; margin: 0 0 0.4rem; }
.lc-act form { display: grid; gap: 0.6rem; max-width: 32rem; }
.lc-act label { display: grid; gap: 0.2rem; font-size: 0.82rem; color: var(--ink-2); }
.lc-act label.lc-check { display: flex; gap: 0.4rem; align-items: center; }
.lc-act input[type="text"], .lc-act input[type="date"] { font: inherit; padding: 0.3rem 0.4rem;
  border: 1px solid var(--rule-strong); border-radius: 0.2rem; }
.lc-act .ed-btn { justify-self: start; }
.lc-sub { border-top: 0; padding-left: 1rem; border-left: 2px solid var(--rule); margin-top: 0.8rem; }
.lc-note { font-size: 0.78rem; color: var(--ink-3); }
.lc-refused { font-size: 0.85rem; background: var(--del-bg); color: var(--del); padding: 0.5rem 0.7rem; }
.lc-status { min-height: 1.2em; font-size: 0.85rem; }
.lc-status.is-ok { color: var(--secondary); }
.lc-status.is-error { color: var(--danger); }
.lc-history ol { font-size: 0.8rem; color: var(--ink-2); padding-left: 1.1rem; }
@media (max-width: 45rem) { .lc-steps { grid-template-columns: 1fr 1fr; } }

/* ── 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; 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); padding: .4rem .6rem .4rem 0;
  font-size: .76rem; 
}
.rev-table td { padding: .45rem .6rem .45rem 0; border-bottom: 1px solid var(--rule); vertical-align: top; }
/* Four columns of revision ids and dates do not fit a phone; the table scrolls in its own box
   rather than widening the page. */
@media (max-width: 40rem) { .rev-table { display: block; overflow-x: auto; } }
.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: var(--ins); }
.d-del { color: var(--del); }
.d-chg { color: var(--warn-ink); }
.d-ren { color: var(--link); }
.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; text-transform: none; color: var(--ink-3); margin: .5rem 0 0; }
.d-warn { color: var(--del); 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); border-radius: 3px;
  padding: 1.1rem 1.25rem 1.25rem; margin: 1.5rem 0 2rem;
  background: color-mix(in srgb, var(--primary) 3%, var(--surface));
}
.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; grid-template-columns: minmax(0, 1fr); 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], .up-form input[type=file] {
  width: 100%; min-width: 0; max-width: 100%; box-sizing: border-box;
  font: inherit; font-size: .86rem; padding: .4rem .5rem;
  border: 1px solid var(--rule); border-radius: 2px; background: var(--surface);
}
.up-form button {
  justify-self: start; font: inherit; font-size: .86rem; padding: .45rem 1.1rem;
  border: 1px solid var(--fill); background: var(--fill); color: var(--fill-ink);
  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: var(--wash);
}
.up-ok  { border-left-color: var(--ins); }
.up-err { border-left-color: var(--del); }
.up-warn{ border-left-color: var(--warn-ink); }
.up-result ul { margin: .35rem 0 0 1.1rem; padding: 0; }
.up-warn-inline { color: var(--warn-ink); }


/* 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(--ink-3); }
.rev-count {
  display: inline-block; min-width: 1.35em; padding: 0 0.35em; border-radius: 0.7em;
  background: var(--rule); 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);
}
.rev-id { font-variant-numeric: tabular-nums; font-weight: 600; }
.rev-view, .rev-size { color: var(--ink-3); }
.rev-when { font-variant-numeric: tabular-nums; }
.rev-note { flex: 1 1 100%; color: var(--ink-2); }
.rev-forked { border-left: 3px solid var(--del); padding-left: 0.5rem; }
.rev-fork-tag { color: var(--del); }

/* 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);
  border-radius: 4px; text-decoration: none; background: var(--paper);
}
.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(--ink-2); }

/* The administrators' catalogue at /admin/. */
.catalog-total { color: var(--ink-2); margin: 0 0 1.5rem; }
.catalog-group { margin: 0 0 2.5rem; }
.catalog-group h2 { font-family: var(--cond); font-weight: 300; font-size: 1.7rem; margin: 0 0 0.2rem; color: var(--primary); }
.catalog-count { font-size: 1rem; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.catalog-blurb { color: var(--ink-2); margin: 0 0 0.9rem; }
.catalog-table { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
.catalog-table th, .catalog-table td { text-align: left; vertical-align: top; padding: 0.55rem 0.6rem; border-bottom: 1px solid var(--rule); }
.catalog-table th { font-family: var(--cond); font-weight: 400; color: var(--ink-3); font-size: 0.8rem; }
.catalog-name { display: block; font-weight: 500; }
.catalog-slug { display: block; font-family: var(--cond); color: var(--ink-3); font-size: 0.8rem; }
.catalog-note { display: block; color: var(--ink-2); font-size: 0.82rem; margin-top: 0.2rem; max-width: 34rem; }
.catalog-links a { margin-right: 0.6rem; white-space: nowrap; }
.catalog-warn { color: var(--del); }
.catalog-muted { color: var(--ink-3); }
@media (max-width: 720px) {
  .catalog-table thead { display: none; }
  .catalog-table tr { display: block; padding: 0.6rem 0; border-bottom: 1px solid var(--rule); }
  .catalog-table td { display: block; border: 0; padding: 0.15rem 0; }
}
.admin-none { margin-top: 1.2rem; color: var(--ink-2); }

.mine-count { margin-top: 1.2rem; color: var(--ink-3); }
.mine-list { list-style: none; margin: 0.5rem 0 0; padding: 0; }
.mine-item { padding: 0.9rem 0; border-top: 1px solid var(--rule); }
.mine-head { display: flex; flex-wrap: wrap; gap: 0.4rem 0.9rem; align-items: baseline; }
.mine-when { color: var(--ink-3); 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); color: var(--ins); }
.st-done { background: var(--rule); color: var(--ink-2); }
.mine-body {
  margin: 0.5rem 0 0; padding-left: 0.9rem; border-left: 3px solid var(--rule);
  color: var(--ink-2);
}

/* ── 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: var(--surface); 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;
 color: var(--ink-3);
}

.panel-audit .btn { margin-top: 0.25rem; }
/* The landing page's summary of an audit's most significant findings: one sentence each,
   each a link to its card. Only an audit that marks findings as significant has it. */
.audit-highlights { max-width: 46rem; margin: 0 0 1.5rem; padding-left: 1.4rem; }
.audit-highlights li { margin: 0 0 0.6rem; padding-left: 0.2rem; }
.audit-highlights a { color: var(--ink); text-decoration-color: var(--rule); text-underline-offset: 0.18em; }
.audit-highlights a:hover { color: var(--primary); text-decoration-color: var(--primary); }

@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: var(--surface); border-bottom: 1px solid var(--rule);
}
.ed-views { display: flex; }
.ed-view {
  border: 1px solid var(--rule); background: var(--surface); 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(--fill); border-color: var(--fill); color: var(--fill-ink); }
.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: var(--surface); 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(--fill); border-color: var(--fill); color: var(--fill-ink); }
.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: var(--danger); }

.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: var(--paper-2); }
.eb.is-changed { border-left-color: var(--secondary); }
.eb.is-new { border-left-color: var(--secondary); background: color-mix(in srgb, var(--secondary) 6%, var(--surface)); }
.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); }
.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: var(--paper-2); }
.ed-doc.is-marked .eb-body.is-relaid { outline: 2px dashed var(--warn-ink); outline-offset: 2px; }
.ed-doc.is-marked .eb-body.is-relaid::before { content: "Paragraphs moved around a table, list or illustration"; display: block; font-size: 0.8em; color: var(--warn-ink); margin-bottom: 0.25em; }

.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: var(--surface); 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-icon { font-size: 1rem; line-height: 1; padding-left: 0.55rem; padding-right: 0.55rem; }
.ed-link { font: inherit; font-size: 0.78rem; border: 0; background: none; color: var(--primary);
  cursor: pointer; text-decoration: underline; padding: 0; }
.ed-picked { font-size: 0.78rem; color: var(--ink-2); display: inline-flex; gap: 0.5rem;
  align-items: baseline; padding-left: 0.5rem; border-left: 1px solid var(--rule); }
.ed-picked[hidden] { display: none; }
.ed-btn-danger { background: var(--danger); border-color: var(--danger); color: var(--on-strong); }
.ed-btn-danger:hover { background: color-mix(in srgb, var(--danger) 85%, var(--ink)); border-color: color-mix(in srgb, var(--danger) 85%, var(--ink)); }

/* The tick box on each provision. Faint until the provision is hovered, ticked, or
   something is already selected, so the page reads as a document and not a form. */
.eb-pick { margin: 0 0.15rem 0 0; width: 0.8rem; height: 0.8rem; cursor: pointer;
  opacity: 0; accent-color: var(--primary); align-self: center; }
.eb:hover > .eb-head > .eb-pick, .eb-pick:checked, .eb-pick:focus-visible,
.ed-doc:has(.eb.is-picked) .eb-pick { opacity: 1; }
.eb.is-picked { background: color-mix(in srgb, var(--primary) 6%, var(--surface)); border-left-color: var(--primary); }

.ed-confirm { border: 1px solid var(--rule-strong); border-radius: 0.4rem; padding: 1.25rem 1.4rem;
  max-width: 30rem; box-shadow: 0 10px 40px rgba(0,0,0,0.18); }
.ed-confirm::backdrop { background: rgba(20, 24, 40, 0.35); }
.ed-confirm h2 { font-size: 1.05rem; margin: 0 0 0.6rem; }
.ed-confirm p { font-size: 0.88rem; margin: 0.4rem 0; color: var(--ink-2); }
.ed-confirm-note { color: var(--ink-3); font-size: 0.8rem; }
.ed-confirm-list { font-size: 0.85rem; margin: 0.3rem 0 0.6rem; padding-left: 1.1rem; }
.ed-confirm-actions { display: flex; gap: 0.5rem; justify-content: flex-end; margin-top: 1rem; }

/* Spelling and grammar, painted over the text with the Custom Highlight API. */
::highlight(cs-spelling) { text-decoration: underline wavy var(--error-600); text-decoration-thickness: 1.5px;
  text-underline-offset: 3px; }
::highlight(cs-grammar) { text-decoration: underline wavy var(--link); text-decoration-thickness: 1.5px;
  text-underline-offset: 3px; }
.ed-fix { position: absolute; z-index: 60; background: var(--surface); border: 1px solid var(--rule-strong);
  border-radius: 0.35rem; box-shadow: 0 6px 24px rgba(0,0,0,0.14); padding: 0.6rem 0.75rem;
  max-width: 22rem; font-size: 0.82rem; }
.ed-fix p { margin: 0 0 0.35rem; }
.ed-fix-kind { font-size: 0.68rem; font-weight: 600; }
.ed-fix-kind.is-spelling, .ed-problems .is-spelling { color: var(--error-600); }
.ed-fix-kind.is-grammar, .ed-problems .is-grammar { color: var(--link); }
.ed-fix-msg { color: var(--ink-2); }
.ed-fix-opts { color: var(--ink-2); }

/* Tables, lists and illustrations inside a provision, edited as what they are. */
.eb-grid { margin: 0.5rem 0; border: 1px solid var(--rule); background: var(--surface); }
.eb-grid-bar { display: flex; gap: 0.3rem; align-items: center; padding: 0.25rem 0.4rem;
  border-bottom: 1px solid var(--rule); background: var(--paper-2); font-size: 0.72rem; color: var(--ink-3); }
.eb-grid-bar span { margin-right: auto; }
.eb-grid-bar button { font: inherit; font-size: 0.72rem; padding: 0.1rem 0.45rem; cursor: pointer;
  border: 1px solid var(--rule); background: var(--surface); color: var(--ink-2); border-radius: 0.2rem; }
.eb-grid-bar button:hover { border-color: var(--primary); color: var(--primary); }
.eb-grid-scroll { overflow-x: auto; max-height: 32rem; }
.eb-grid table { border-collapse: collapse; font-size: 0.8rem; width: max-content; min-width: 100%; }
.eb-grid td, .eb-grid th { border: 1px solid var(--rule); padding: 0.2rem 0.4rem; vertical-align: top;
  min-width: 3rem; }
.eb-grid th { background: var(--paper-2); font-weight: 600; }
.eb-grid td p, .eb-grid th p { margin: 0; }
.eb-grid td:focus, .eb-grid th:focus { outline: 2px solid var(--primary); outline-offset: -2px; }
.eb-grid tr.is-ins td { background: var(--ins-bg); }
.eb-grid tr.is-del td { background: var(--del-bg); }
.eb-list { margin: 0.4rem 0 0.4rem 1.2rem; padding: 0; font-size: 0.9rem; }
.eb-list li { padding: 0.1rem 0.2rem; }
.eb-list li:focus { outline: 2px solid var(--primary); outline-offset: 1px; }
.eb-figure { margin: 0.6rem 0; padding: 0.5rem; border: 1px solid var(--rule); background: var(--surface); max-width: 34rem; }
.eb-figure img { display: block; max-width: 100%; max-height: 20rem; }
.eb-figure figcaption { font-size: 0.85rem; font-weight: 600; margin-top: 0.4rem; }
.eb-figure figcaption:empty::before { content: attr(data-placeholder); color: var(--ink-3); font-weight: 400; }
.eb-figure-alt { font-size: 0.78rem; color: var(--ink-3); margin: 0.3rem 0; }
.eb-figure-alt span { color: var(--ink-2); }
.eb-figure-replace { display: inline-block; font-size: 0.75rem; cursor: pointer; }
.eb-figure.is-new-image { outline: 2px solid var(--ins); }

.eb-grid td.is-option { cursor: pointer; text-align: center; font-weight: 600; color: var(--primary); }
.eb-grid td.is-option:hover, .eb-grid td.is-option:focus { background: color-mix(in srgb, var(--primary) 8%, var(--surface)); outline: none; }
.ed-picker { position: absolute; z-index: 60; background: var(--surface); border: 1px solid var(--rule-strong);
  border-radius: 0.35rem; box-shadow: 0 6px 24px rgba(0,0,0,0.14); padding: 0.35rem; max-width: 26rem;
  max-height: 22rem; overflow-y: auto; }
.ed-picker-head { font-size: 0.68rem; color: var(--ink-3);
  margin: 0.15rem 0.35rem 0.3rem; }
.ed-picker button { display: flex; gap: 0.6rem; width: 100%; text-align: left; border: 0; background: none;
  padding: 0.3rem 0.4rem; font: inherit; font-size: 0.82rem; cursor: pointer; border-radius: 0.2rem; }
.ed-picker button strong { min-width: 2.2rem; color: var(--primary); }
.ed-picker button span { color: var(--ink-2); }
.ed-picker button:hover, .ed-picker button:focus { background: var(--paper-2); outline: none; }
.ed-picker button.is-on { background: color-mix(in srgb, var(--primary) 10%, var(--surface)); }

/* A viewer reads the draft: no tools, no grips, no tick boxes. */
body.is-readonly .ed-tools, body.is-readonly .eb-grip, body.is-readonly .eb-pick,
body.is-readonly .eb-grid-bar button, body.is-readonly .eb-figure-replace, body.is-readonly #ed-review { display: none; }
/* The marked view is a redline to read, not a value to change (editor-embeds.js refuses too). */
.ed-doc.is-marked .eb-grid-bar button, .ed-doc.is-marked .eb-figure-replace, .ed-doc.is-marked .eb-pick { display: none; }
/* Struck in this round: nothing is placed beside it or typed into it. */
.eb.is-struck .eb-grip, .eb.is-struck .eb-pick, .eb.is-struck .eb-grid-bar button, .eb.is-struck .eb-figure-replace { display: none; }

/* The contents as a drag surface. */
.ed-outlist a { cursor: grab; user-select: none; }
.ed-outlist a.is-dragging { opacity: 0.5; }
.ed-outlist a.is-drop-before { box-shadow: 0 -2px 0 0 var(--primary); }
.ed-outlist a.is-drop-after { box-shadow: 0 2px 0 0 var(--primary); }
.ed-outlist .is-struck > a { text-decoration: line-through; opacity: 0.55; }
.ed-btn.is-armed { background: var(--danger); border-color: var(--danger); color: var(--on-strong); }
.ed-btn:disabled { opacity: 0.45; cursor: default; border-color: var(--rule);
  background: var(--surface); 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%, var(--surface));
  border-bottom: 1px solid var(--rule); font-size: 0.86rem;
}
.ed-banner p { margin: 0; }
/* A stale draft or a reload notice carries its own buttons in this slot, in place of the
   lone Dismiss a status banner otherwise gets. */
.ed-banner-actions { display: flex; gap: 0.5rem; flex-shrink: 0; }
/* Changes the page cannot place: a list, each with its Remove, until none is left. */
.ed-unplaced { display: block; background: color-mix(in srgb, var(--warn-ink) 10%, var(--surface)); }
.ed-unplaced ul { margin: 0.4rem 0 0; padding-left: 1.2rem; }
.ed-unplaced li { margin: 0.2rem 0; }
.ed-unplaced li .ed-btn { margin-left: 0.5rem; }

/* The grip is the drag target, so it is always in the same place and never in the text.
   Up and down reorders; sideways as well chooses the rung it takes there, 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; 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; 
}
/* Followed here from the Changes panel. */
.eb.is-found { background: color-mix(in srgb, var(--secondary) 14%, var(--surface)); }
/* 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(--fill); 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: var(--surface);
  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(--fill); color: var(--fill-ink); }
.eb-ins-add:active { cursor: grabbing; }
.eb-ins-rung {
  font-size: 0.66rem; color: var(--primary);
  background: var(--surface); padding: 0 0.2rem 0 0; flex: none;
}


/* 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;
}

/* The keyboard's way into commenting. Clicking a provision opens the box, but a provision
   is text, not a control, so this button carries the same action for a keyboard, a switch
   or a voice. It sits in the gutter, invisible until the provision is hovered or the button
   itself is focused, and is announced with the provision's label. */
.doc [data-eid] { position: relative; }
.cbtn {
  position: absolute; left: -1.9rem; top: 0.05rem;
  width: 1.5rem; height: 1.5rem; padding: 0; border: 1px solid var(--rule-strong);
  border-radius: 50%; background: var(--paper); color: var(--ink-2);
  font: inherit; font-size: 0.8rem; line-height: 1; cursor: pointer;
  opacity: 0; transition: opacity 0.12s ease;
}
.doc [data-eid]:hover > .cbtn, .cbtn:focus-visible, .doc [data-eid].is-commenting > .cbtn { opacity: 1; }
.cbtn:hover, .cbtn:focus-visible { color: var(--primary); border-color: var(--primary); }
body.hide-comments .cbtn { display: none; }
.cbtn-row { position: static; float: none; display: inline-block; margin: 0 0.3rem 0 0; vertical-align: middle; }
.doc tr[data-eid]:hover .cbtn-row, tr[data-eid].is-commenting .cbtn-row { opacity: 1; }
@media (max-width: 1179px) {
  .cbtn { position: static; opacity: 1; margin: 0 0.4rem 0 0; vertical-align: middle; float: right; }
}

/* Straight to the text, past the masthead and the contents rail. Visible only on focus. */
.skiplink {
  position: absolute; left: 0.5rem; top: -3rem; z-index: 100;
  padding: 0.5rem 0.8rem; background: var(--fill); color: var(--fill-ink); border-radius: 0.375rem;
  font: 600 0.9rem/1.5 var(--font); text-decoration: none; min-height: 24px;
}
.skiplink:focus { top: 0.5rem; outline: 2px solid var(--focus); outline-offset: 2px; }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
