/* ── ACT Development Screen: a slim, monochrome layer on Bootstrap 5 ───────
   Black and greys only, no accent hues. State is shown by contrast, not
   colour: darker = stronger signal. A tool that says "walk away" in red
   and "proceed" in green is making the decision for you; this one puts
   the numbers in a fixed-width face and lets them argue.

   Bootstrap's semantic utilities are remapped to greyscale here so the
   components keep working without per-template edits. */

:root{
  --ink:#1b1b1b; --g1:#3d3d3d; --g2:#6c6c6c; --g3:#9a9a9a;
  --g4:#cfcfcf; --g5:#e6e6e6; --g6:#f3f3f3;
  --bs-body-font-family:"Hanken Grotesk", system-ui, sans-serif;
  --bs-body-color:var(--ink);
  /* Both halves of the pair. `--bs-link-color` and
     `--bs-link-color-rgb` are separate variables in Bootstrap 5.3 --
     the -rgb one only feeds rgba() composition -- so setting the second
     alone left `--bs-link-color` at the stock #0d6efd. Plain anchors
     were caught anyway by the `a{}` rule below, but `.nav-link` is a
     class selector and outranks a bare element one, which is how the
     user-area tab strip ended up the only blue thing on the site. */
  --bs-link-color:var(--ink);
  --bs-link-hover-color:#000;
  --bs-link-color-rgb:27,27,27;
  --bs-link-hover-color-rgb:0,0,0;
}
.mono, .figure-val, table.data td.num, table.data th.num, .grid-cell, input.form-control, .form-select{
  font-family:"Spline Sans Mono", ui-monospace, monospace;
  font-variant-numeric:tabular-nums;
}
[x-cloak]{display:none!important}
body{font-size:15px}
a{color:var(--ink)} a:hover{color:#000}
.fa-solid,.fa-regular{line-height:1; vertical-align:-.05em}

/* ── HTMX swap containers ─────────────────────────────────────────────
   Every keystroke in the calculators re-renders the whole container, and
   the answer changing adds or removes a panel, so the page gets taller or
   shorter mid-edit. Chrome's scroll anchoring then tries to hold whatever
   it had anchored on — but that node was just destroyed by the swap, so
   the correction it computes is garbage and the viewport lands at the very
   bottom of the document. The symptom is the input you are typing in
   apparently diving to the foot of the page.

   Anchoring has nothing to hold onto in a container that is replaced
   wholesale, so opt these out of it. Scroll position then simply stays
   where the user left it, which is what typing into a field should do. */
#model, #screen, #activity-stream, #results, #nav-results, #add-results{
  overflow-anchor:none;
}
/* The swap wrapper is not a panel, so `.panel + .panel` cannot reach
   across it and the panel after `#screen` sat flush against the Gate 2
   buttons. Give the container the page's own 1rem rhythm rather than
   putting a utility class on the div, so the rule travels with the
   reason for it. */
#screen{margin-bottom:1rem}

/* ── Primary / action = black ──────────────────────────────────────────*/
.btn-primary{
  --bs-btn-bg:var(--ink); --bs-btn-border-color:var(--ink);
  --bs-btn-hover-bg:#000; --bs-btn-hover-border-color:#000;
  --bs-btn-active-bg:#000; --bs-btn-active-border-color:#000;
  --bs-btn-disabled-bg:var(--g3); --bs-btn-disabled-border-color:var(--g3);
}
.btn-outline-primary,.btn-outline-warning{
  --bs-btn-color:var(--ink); --bs-btn-border-color:var(--g4);
  --bs-btn-hover-bg:var(--ink); --bs-btn-hover-color:#fff; --bs-btn-hover-border-color:var(--ink);
}
.btn-outline-secondary{
  --bs-btn-color:var(--g1); --bs-btn-border-color:var(--g4);
  --bs-btn-hover-bg:var(--g6); --bs-btn-hover-color:var(--ink); --bs-btn-hover-border-color:var(--g3);
}
.text-brand,.text-success,.text-primary{color:var(--ink)!important}
.text-danger{color:var(--g2)!important}
.brand-logo{width:30px; height:30px; border-radius:7px; background:var(--ink);
  color:#fff; display:grid; place-items:center; font-weight:700; flex:none;
  font-size:.85rem; letter-spacing:-.02em}

/* ── Badges / alerts → greyscale ───────────────────────────────────────*/
.text-bg-success,.text-bg-danger{background-color:var(--ink)!important; color:#fff!important}
.text-bg-warning{background-color:var(--g5)!important; color:var(--ink)!important}
.text-bg-secondary,.text-bg-light{background-color:var(--g6)!important; color:var(--g2)!important;
  border:1px solid var(--g5)}
.alert-primary,.alert-success,.alert-warning,.alert-secondary,.alert-info,.alert-danger{
  --bs-alert-color:var(--ink); --bs-alert-bg:var(--g6); --bs-alert-border-color:var(--g5);
}
.form-control:focus,.form-select:focus{border-color:var(--g2); box-shadow:0 0 0 .18rem rgba(0,0,0,.08)}
.form-check-input:checked{background-color:var(--ink); border-color:var(--ink)}

/* ── Search ───────────────────────────────────────────────────────────*/
.search-shell{max-width:640px}
.search-input{font-size:1.15rem; padding:.85rem 1rem; border:1.5px solid var(--g4); border-radius:.6rem}
.search-input:focus{border-color:var(--ink)}
.results{border:1px solid var(--g5); border-radius:.6rem; overflow:hidden; background:#fff}
.results a{display:block; padding:.6rem .85rem; text-decoration:none; border-bottom:1px solid var(--g6)}
.results a:last-child{border-bottom:0}
.results a:hover,.results a:focus{background:var(--g6)}
.results .addr{font-weight:600}
.results .meta{font-size:.8rem; color:var(--g2)}
/* The suburb row in the dropdown. Tinted rather than bordered so it
   reads as a different kind of answer to the addresses under it — a
   destination, not a result. */
.results a.result-suburb{background:var(--g6); border-bottom:1px solid var(--g4)}
.results a.result-suburb:hover,.results a.result-suburb:focus{background:var(--g5)}
.results a.result-suburb .addr{display:flex; justify-content:space-between; gap:1rem}
.results .suburb-count{font-weight:400; font-size:.8rem; color:var(--g2);
  font-family:"Spline Sans Mono", ui-monospace, monospace; white-space:nowrap}
.htmx-request .spinner-hint{opacity:1}
.spinner-hint{opacity:0; transition:.15s; font-size:.8rem; color:var(--g3)}

/* ── Figures — the numbers are the product, so give them room ─────────*/
.figure-grid{display:grid; gap:.75rem; grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}
.figure{border:1px solid var(--g5); border-radius:.5rem; padding:.7rem .85rem; background:#fff}
.figure-label{font-size:.72rem; text-transform:uppercase; letter-spacing:.06em; color:var(--g2)}
.figure-val{font-size:1.35rem; font-weight:600; line-height:1.25; margin-top:.15rem}
.figure-val.sm{font-size:1.05rem}
.figure-note{font-size:.76rem; color:var(--g2); margin-top:.15rem}
.figure.strong{border-color:var(--ink); border-width:1.5px}

/* ── Verdict panels: contrast, not colour ─────────────────────────────*/
.verdict{border:1.5px solid var(--g4); border-radius:.6rem; padding:1rem 1.15rem; background:#fff}
.verdict .label{font-size:.72rem; text-transform:uppercase; letter-spacing:.08em; color:var(--g2)}
.verdict .call{font-size:1.5rem; font-weight:700; letter-spacing:-.01em; margin:.15rem 0 .4rem}
.verdict p{margin:0; color:var(--g1); font-size:.9rem}
.verdict-stop{background:var(--ink); border-color:var(--ink); color:#fff}
.verdict-stop .label,.verdict-stop p{color:var(--g4)}
.verdict-warn{background:var(--g6); border-color:var(--g3)}
.verdict-go{background:#fff; border-color:var(--ink)}

/* ── Data tables ──────────────────────────────────────────────────────*/
table.data{width:100%; font-size:.88rem; border-collapse:collapse}
table.data th{font-size:.72rem; text-transform:uppercase; letter-spacing:.05em;
  color:var(--g2); font-weight:600; padding:.4rem .5rem; border-bottom:1px solid var(--g4);
  text-align:left; white-space:nowrap}
table.data td{padding:.4rem .5rem; border-bottom:1px solid var(--g6)}
table.data td.num,table.data th.num{text-align:right}
table.data tr.best td{background:var(--g6); font-weight:600}
table.data tr.best td:first-child{box-shadow:inset 3px 0 0 var(--ink)}
table.data tbody tr:hover td{background:var(--g6)}
table.data caption{caption-side:top; padding:0 0 .4rem; font-size:.8rem; color:var(--g2)}

/* Below Bootstrap's `sm` breakpoint these stop fitting: the widest is
   seven columns and 660px of content in a 310px panel, and with nothing
   to contain it the whole document went 320px wider than the phone. Every
   page then scrolled sideways, including the parts that were never too
   wide.

   Making the table a block gives it the same containment `.table-scroll`
   gives the radar — it scrolls inside the panel it belongs to instead of
   dragging the document with it — without that rule's sticky header and
   capped height, which these don't need. The scrollbar sits under the
   last row and is the affordance; a column clipped mid-figure at the
   panel edge says the rest is there.

   Desktop and iPad are the primary targets and they are untouched: the
   query stops at 575.98px, well below an iPad's 768. */
@media (max-width:575.98px){
  table.data:not(.radar-table){display:block; width:100%; overflow-x:auto}
  /* A block table lays out at min-content, so any header that is not
     allowed to wrap sets its column's width on its own. Letting them wrap
     took the worst table from 660px to 560 — a third less to scroll
     through. Figures are the exception: a broken number reads as two. */
  table.data:not(.radar-table) th{white-space:normal}
  table.data:not(.radar-table) td.num{white-space:nowrap}
  /* A caption belongs to the table, so it takes the table's width — which
     is now the scrolled width, not the visible one, and the sentence ran
     off the side of a panel you had to scroll sideways to finish reading.
     As a block it takes the width of the box instead and wraps inside it. */
  table.data:not(.radar-table) caption{display:block}
}

/* ── Sensitivity grid — darker cell = more land you can pay for ───────*/
.grid-cell{text-align:right; padding:.35rem .5rem; font-size:.82rem; border:1px solid #fff}
.grid-cell.q0{background:#fff}
.grid-cell.q1{background:var(--g6)}
.grid-cell.q2{background:var(--g5)}
.grid-cell.q3{background:var(--g4)}
.grid-cell.q4{background:var(--g3); color:#fff}
.grid-cell.here{outline:2px solid var(--ink); outline-offset:-2px; font-weight:700}

/* ── Panels and section headings ──────────────────────────────────────*/
.panel{border:1px solid var(--g5); border-radius:.6rem; background:#fff; padding:1.1rem 1.25rem}
.panel + .panel{margin-top:1rem}
.panel-head{display:flex; align-items:baseline; justify-content:space-between; gap:1rem;
  margin:0 0 .85rem}
.panel-head h2{font-size:1rem; font-weight:700; margin:0; letter-spacing:-.01em}
.panel-head .hint{font-size:.8rem; color:var(--g2)}
.rule{border:0; border-top:1px solid var(--g5); margin:1rem 0}

/* ── Assumption fields ────────────────────────────────────────────────*/
.assump{display:grid; grid-template-columns:1fr 130px; gap:.5rem 1rem; align-items:center;
  padding:.3rem 0; border-bottom:1px solid var(--g6)}
.assump:last-child{border-bottom:0}
.assump label{font-size:.85rem; color:var(--g1); margin:0}
.assump .form-control{text-align:right; font-size:.85rem; padding:.25rem .5rem}
.assump .unit{font-size:.75rem; color:var(--g3)}

/* ── Flags: Mr Fluffy, missing schedule, deadline warnings ────────────
   A plain box, weighted by its border. There was a 4px ink rule down the
   left edge; it is gone. A heavy bar is the one piece of chrome this
   design does not otherwise use, and three of them stacked down a
   results page read as decoration applied to the page rather than as
   anything about the block.

   Emphasis is carried the way it is everywhere else here -- by contrast.
   A flag that matters has a darker border than a quiet one, and the
   quiet one also drops its text to `--g1`. `.signal` keeps ITS left rule
   deliberately: there the rule's colour is the state, so removing it
   would remove the meaning rather than the ornament. */
.flag{display:flex; gap:.6rem; align-items:flex-start; border:1px solid var(--g3);
  border-radius:.4rem;
  padding:.6rem .8rem; background:#fff; font-size:.86rem}
.flag + .flag{margin-top:.5rem}
.flag.quiet{border-color:var(--g5); color:var(--g1)}
.flag .fa-solid{color:var(--g2); margin-top:.15rem}

/* ── Block overview: the signal grid ──────────────────────────────────
   Two columns of short rows rather than a table, because the reader is
   scanning for the one line that matters, not comparing a column.

   State is the left rule and the marker glyph, both greyscale: a
   constraint gets the full-contrast rule, something to check gets a
   mid-grey one, a clear result gets almost nothing. The alternative —
   red for bad, green for clear — would be the tool making the call, and
   a mapped bushfire band is a cost, not a verdict. */
.signal-grid{display:grid; gap:.4rem .9rem; grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}
.signal{display:flex; gap:.55rem; align-items:baseline; font-size:.86rem;
  padding:.35rem .6rem; border-left:3px solid var(--g5); background:var(--g6);
  border-radius:.25rem}
.signal-state{font-family:"Spline Sans Mono", ui-monospace, monospace; font-weight:700;
  color:var(--g3); width:.9rem; flex:none; text-align:center}
.signal-detail{color:var(--g1)}
.signal-note{font-size:.75rem; color:var(--g2); margin-top:.1rem}
.signal.constraint{border-left-color:var(--ink); background:#fff}
.signal.constraint .signal-state{color:var(--ink)}
.signal.investigate{border-left-color:var(--g2); background:#fff}
.signal.investigate .signal-state{color:var(--g1)}
.signal.opportunity{border-left-color:var(--g3); background:#fff}
.signal.clear .signal-state{color:var(--g2)}
.signal.clear strong{font-weight:600}
.signal.informational{border-left-color:var(--g4)}
.signal.unknown{background:transparent; border-left-color:var(--g4)}
/* The unassessed list stays one line until asked for. It must be
   present — omitting it is the misreading this whole product guards
   against — but it is the least decision-relevant thing on the panel. */
.signal-unknown{font-size:.84rem; color:var(--g1)}
.signal-unknown summary{cursor:pointer; color:var(--g1); padding:.3rem 0}
.signal-unknown summary:hover{color:var(--ink)}
.signal-unknown[open] .signal{margin-top:.3rem}

/* ── Explainers ───────────────────────────────────────────────────────*/
.prose{max-width:44rem; font-size:.98rem; line-height:1.65}
.prose h2{font-size:1.15rem; font-weight:700; margin:1.8rem 0 .6rem}
.prose h3{font-size:1rem; font-weight:600; margin:1.4rem 0 .5rem}
.prose table{width:100%; font-size:.88rem; margin:1rem 0; border-collapse:collapse}
.prose th,.prose td{padding:.35rem .5rem; border-bottom:1px solid var(--g5); text-align:left}
.prose blockquote{border-left:3px solid var(--g4); padding-left:1rem; margin:1.2rem 0;
  color:var(--g1); font-style:normal}
.prose code{background:var(--g6); padding:.1rem .3rem; border-radius:.2rem; color:var(--ink)}
.prose .worked{background:var(--g6); border-radius:.5rem; padding:.9rem 1.1rem; margin:1.2rem 0;
  font-size:.9rem}

/* ── Disclaimer, footer ───────────────────────────────────────────────*/
.disclaimer{font-size:.78rem; color:var(--g2); border-top:1px solid var(--g5);
  padding-top:.85rem; margin-top:1.5rem}
.disclaimer p{margin:0 0 .4rem}
footer.site{border-top:1px solid var(--g5); margin-top:2.5rem; padding:1.25rem 0 2rem;
  font-size:.8rem; color:var(--g2)}
footer.site a{color:var(--g1)}

/* ── Landing ──────────────────────────────────────────────────────────*/
.hero h1{font-size:2rem; font-weight:700; letter-spacing:-.02em}
.hero .lede{font-size:1.05rem; color:var(--g1); max-width:34rem}
.pill{display:inline-block; border:1px solid var(--g4); border-radius:99px;
  padding:.15rem .6rem; font-size:.75rem; color:var(--g1)}
.step-num{width:26px; height:26px; border-radius:50%; background:var(--ink); color:#fff;
  display:grid; place-items:center; font-size:.75rem; font-weight:600; flex:none}

/* ── Activity strip ───────────────────────────────────────────────────
   A scrollable month-by-month bar chart. Two overlaid bars rather than a
   stack: the light bar is all applications, the dark one the subset that
   is development-related, so the ratio is readable at a glance without a
   legend lookup. */
.monthstrip{display:flex; gap:3px; overflow-x:auto; padding:.25rem 0 .5rem;
  scrollbar-width:thin; align-items:flex-end}
.monthstrip .month{flex:none; width:38px; text-decoration:none; text-align:center;
  padding:.2rem .1rem; border-radius:.3rem}
.monthstrip .month:hover{background:var(--g6)}
.monthstrip .bar-wrap{position:relative; height:86px; display:flex; align-items:flex-end;
  justify-content:center}
.monthstrip .bar{position:absolute; bottom:0; width:20px; background:var(--g4);
  border-radius:2px 2px 0 0; min-height:1px}
.monthstrip .bar.dev{width:20px; background:var(--ink)}
.monthstrip .mcount{font-size:.68rem; color:var(--g2); margin-top:.15rem}
.monthstrip .mlabel{font-size:.62rem; color:var(--g3); line-height:1.15; margin-top:.1rem}
.monthstrip .mlabel .yr{color:var(--g4)}
.swatch{display:inline-block; width:9px; height:9px; border-radius:2px; vertical-align:baseline}
.swatch.light{background:var(--g4)}
.swatch.dark{background:var(--ink)}

/* ── Optimism panel ───────────────────────────────────────────────────
   Deliberately not red. Nothing here is an error -- these are choices,
   and the panel exists to price them, not to forbid them. */
.panel.optimism{border-color:var(--g3); border-width:1.5px}

/* An input whose value has been flagged. A left edge, not a red ring:
   the field is still perfectly valid. */
.assump.flagged .form-control{border-color:var(--g2); box-shadow:inset 3px 0 0 var(--ink)}
.assump .flagnote{grid-column:1 / -1; font-size:.74rem; color:var(--g2); margin-top:-.1rem}

/* The current month is always incomplete, so its bar is not comparable
   to the others. Hatched rather than hidden -- dropping it would make
   the strip look stale. */
.monthstrip .month.partial .bar{background:repeating-linear-gradient(
  135deg, var(--g4) 0 3px, #fff 3px 6px)}
.monthstrip .month.partial .bar.dev{background:repeating-linear-gradient(
  135deg, var(--ink) 0 3px, var(--g4) 3px 6px)}
.swatch.partial{background:repeating-linear-gradient(135deg, var(--ink) 0 2px, #fff 2px 4px)}

/* ── DA activity markers in search results ────────────────────────────
   A live application on the block is the one thing a searcher most needs
   to see before clicking, so it gets full contrast and everything else
   recedes. Still monochrome: urgency is weight, not hue. */
.da-strip{display:flex; flex-wrap:wrap; gap:.3rem; margin-top:.3rem}
.da-tag{font-size:.71rem; line-height:1.5; padding:.05rem .4rem; border-radius:.25rem;
  border:1px solid var(--g5); background:var(--g6); color:var(--g2); white-space:nowrap}
.da-tag.live{background:var(--ink); border-color:var(--ink); color:#fff; font-weight:600}
.da-tag.quiet{background:#fff; color:var(--g3)}

/* ── Neighbouring blocks ──────────────────────────────────────────────*/
.neighbour-dist{font-size:.72rem; color:var(--g3); white-space:nowrap}

/* ── Filter bars ──────────────────────────────────────────────────────*/
.filters{display:flex; flex-wrap:wrap; gap:.75rem; align-items:flex-end}
.filters .filter{flex:1 1 180px; min-width:150px}
.filters .form-select{font-size:.85rem}

/* ── Navigation ───────────────────────────────────────────────────────
   The dots button has to be indistinguishable from a nav link until you
   reach for it: it is a peer of the three destinations beside it, not a
   control. */
.nav-more{background:none; border:0; line-height:1}
.nav-more::after{display:none}          /* no Bootstrap caret next to the dots */
.nav-more[aria-expanded="true"]{color:var(--ink)}

/* Where the menu opens — four declarations that used to arrive at
   runtime from Popper.

   Every top/right/left rule for a dropdown menu in bootstrap.min.css is
   written as `.dropdown-menu[data-bs-popper]{...}`, and that attribute is
   set by Bootstrap's JavaScript. With the bundle removed for the 24 KB
   (see the note in base.html) the menu keeps `position:absolute` and
   every bit of its border, padding and shadow, and loses its position
   entirely: it opens left-aligned to the button, which is the last item
   in the navbar, and hangs off the right-hand edge of the screen.

   That failure is worth naming because it is the quiet kind. The menu
   still opens, still closes, still looks like itself, and the styling
   gives no hint that a whole category of rule silently stopped matching.

   So this is our dropdown now and it states its own position. Keyed on
   the data attribute the behaviour uses, not on `.dropdown-menu`, so it
   cannot reach a menu that app.js is not driving. */
[data-dropdown-menu]{top:100%; right:0; left:auto; margin-top:.125rem}

/* Where you are. The same inset underline the comparison tables use to
   mark the best cell — weight and a rule, never colour, so it survives
   the monochrome palette and a black-and-white print.

   Unscoped, so it reaches every nav rather than only the top bar. It was
   `.navbar .nav-link.active`, and the user-area tab strip is not inside
   a navbar, so it fell through to stock Bootstrap and marked the current
   tab with a blue fill — the one active state on the site that said it
   in colour, in a palette whose whole premise is that it does not. */
.nav-link.active{color:var(--ink); font-weight:600;
  box-shadow:inset 0 -2px 0 var(--ink)}

/* Pills carry a background by default and this palette marks state with
   the rule above instead, so there is nothing left for the fill to do.

   The padding and the radius go with it. A pill is 1rem of horizontal
   padding against the top bar's .5rem, so the same 2px rule underneath
   came out half again as wide and read as a different mark rather than
   the same one lower down the page — and a corner radius is shape left
   over from a fill that is no longer drawn. Matching both makes "where
   you are" one thing on this site instead of two.

   Set here rather than per-template so a second pill strip inherits it. */
.nav-pills{
  --bs-nav-pills-link-active-bg:transparent;
  --bs-nav-pills-link-active-color:var(--ink);
  --bs-nav-pills-border-radius:0;
  --bs-nav-link-padding-x:.5rem;
  --bs-nav-link-color:var(--g2);
  --bs-nav-link-hover-color:var(--ink);
}
.navbar .dropdown-item.active{background:var(--g6); color:var(--ink); font-weight:600;
  box-shadow:inset 3px 0 0 var(--ink)}
.navbar .dropdown-menu{border-color:var(--g5); border-radius:.5rem; font-size:.9rem;
  box-shadow:0 6px 20px rgba(0,0,0,.08)}
.navbar .dropdown-item:active{background:var(--ink)}

/* `navbar-expand` never collapses, so the brand plus the links ran to
   1.8× the width of a 375px screen and the whole page scrolled
   sideways. Moving three items behind the dots fixed most of it; the
   nav still drops to its own row on a phone so the brand keeps its
   line. No overflow scrolling here — it would clip the dropdown.

   Dropping to its own row was not enough on its own. At 375px the five
   items plus the dots measured 405px against a 351px content box, so
   the row still ran off the right-hand edge -- and the item it ran off
   with was "Sign in", which is the one action every emailed link is
   asking for. `space-between` cannot save that: it distributes SPARE
   space and there was none, so the overflow was invisible to it.

   Three declarations, in the order they earn their place:

     the gutter    `gap-1` on the markup is 4px between six items, and
                   `space-between` is already doing that job on this
                   row. 20px back for nothing.
     the padding   `.px-2` is 8px a side per item. Halved, which is
                   another 48px and still leaves every label a 38px-tall
                   target -- the height comes from the vertical padding
                   and is untouched.
     the wrap      belt and braces for 320px, where even the tightened
                   row does not fit. "Sign in" drops to a line of its
                   own instead of off the screen. Nothing clips at any
                   width, which is the property worth having. */
@media (max-width:575.98px){
  .navbar > .container-xl{flex-wrap:wrap; row-gap:.35rem}
  .navbar .navbar-nav{width:100%; margin-left:0!important;
    justify-content:space-between; flex-wrap:wrap;
    column-gap:0; row-gap:.15rem}
  /* `!important` because `.px-2` in the markup is a Bootstrap spacing
     utility, and every one of those is declared `!important` by
     construction. Specificity cannot beat it; only the same weapon
     can. The alternative is deleting `px-2` from eight nav links and
     restating desktop padding here, which moves the risk to the width
     nobody was complaining about. */
  .navbar .nav-link{white-space:nowrap; font-size:.9rem;
    padding-left:.25rem!important; padding-right:.25rem!important}
}

/* ── Acquisition radar ────────────────────────────────────────────────
   A denser filter bar than the activity page: there are ten inputs and
   they have to sit above the fold, or the page reads as a form to fill
   in rather than a dial to turn. */
.radar-filters{display:grid; gap:1rem; align-items:start;
  grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}
/* Two of the ten inputs need the room: the suburb list, and the row of
   constraint exclusions that would otherwise wrap one word per line. */
.radar-filters .rf-wide{grid-column:span 2}
.radar-filters .rf-actions{grid-column:1/-1; display:flex; align-items:center;
  gap:1rem; padding-top:.25rem; border-top:1px solid var(--g6); margin-top:.25rem}
.radar-filters .rf-pair{display:flex; gap:.5rem}
.radar-filters .form-select,.radar-filters .form-control{font-size:.85rem}
@media (max-width:640px){.radar-filters .rf-wide{grid-column:1/-1}}
.radar-filters select[multiple]{padding:.2rem}
.radar-filters select[multiple] option{padding:.15rem .35rem; border-radius:.2rem}
.rf-checks{display:flex; flex-wrap:wrap; gap:.15rem .85rem; padding-top:.15rem}
.rf-check{display:inline-flex; align-items:center; gap:.35rem; font-size:.85rem;
  color:var(--g1); cursor:pointer; white-space:nowrap}
.rf-check input{margin:0}

/* 250 rows and eight columns. The table scrolls inside its panel rather
   than pushing the page sideways. */
.table-scroll{overflow-x:auto; max-height:70vh; overflow-y:auto;
  border:1px solid var(--g6); border-radius:.4rem}
table.radar-table{margin:0}
table.radar-table thead th{position:sticky; top:0; background:#fff; z-index:1;
  box-shadow:inset 0 -1px 0 var(--g4)}
table.radar-table td{vertical-align:top}
table.radar-table .radar-sub{font-size:.72rem; color:var(--g3); margin-top:.1rem}
table.radar-table .shortlist-col{width:2.2rem; text-align:center}
table.radar-table .shortlist-col input{margin-top:.15rem; cursor:pointer}
table.radar-table .shortlist-col input:disabled{cursor:not-allowed; opacity:.35}

/* ── Shortlist bar ────────────────────────────────────────────────────
   Docked rather than floating: it is a working tray, and it should not
   cover the last row of the table it is filled from. */
.shortlist-bar{position:sticky; bottom:0; z-index:1020; background:#fff;
  border-top:1.5px solid var(--ink); box-shadow:0 -2px 12px rgba(0,0,0,.07)}
.shortlist-head{display:flex; flex-wrap:wrap; gap:.75rem; align-items:center;
  justify-content:space-between; padding:.6rem 0}
.shortlist-toggle{background:none; border:0; padding:0; font-size:.88rem;
  color:var(--ink); display:inline-flex; align-items:center; gap:.4rem}
.shortlist-toggle:hover{text-decoration:underline}
.shortlist-cap{font-size:.78rem; color:var(--g2)}
.shortlist-items{display:flex; flex-wrap:wrap; gap:.4rem; padding:0 0 .75rem}
.shortlist-chip{display:inline-flex; align-items:center; gap:.35rem; font-size:.8rem;
  border:1px solid var(--g4); border-radius:99px; padding:.1rem .3rem .1rem .7rem}
.shortlist-chip a{color:var(--g1); text-decoration:none}
.shortlist-chip a:hover{text-decoration:underline}
.shortlist-chip button{background:none; border:0; color:var(--g3); font-size:1rem;
  line-height:1; padding:0 .3rem}
.shortlist-chip button:hover{color:var(--ink)}
.shortlist-note{flex:1 1 100%; margin:.35rem 0 0; font-size:.74rem; color:var(--g3)}

/* ── Comparison tables ────────────────────────────────────────────────
   Rows are metrics and columns are subjects, which is the opposite of
   the usual orientation but the right one here: you read across a single
   metric to compare, and there are more metrics than subjects. */
table.compare{width:100%; font-size:.88rem; border-collapse:collapse}
table.compare th, table.compare td{padding:.45rem .6rem; border-bottom:1px solid var(--g6)}
table.compare thead th{border-bottom:1px solid var(--g4); font-size:.8rem; vertical-align:bottom}
table.compare tbody th{font-weight:400; color:var(--g1); text-align:left; width:26%}
table.compare tbody th .note{display:block; font-size:.73rem; color:var(--g3)}
table.compare td{text-align:right; font-family:"Spline Sans Mono", ui-monospace, monospace;
  font-variant-numeric:tabular-nums; white-space:nowrap}
table.compare td.best{font-weight:700; box-shadow:inset 0 -2px 0 var(--ink)}
table.compare tr.divider td, table.compare tr.divider th{border-bottom-color:var(--g4);
  padding-top:1rem; font-weight:600; color:var(--ink)}
table.compare tbody tr:hover td, table.compare tbody tr:hover th{background:var(--g6)}
.compare-head{font-weight:700}
.compare-head a{text-decoration:none}
.compare-sub{font-size:.74rem; color:var(--g2); font-weight:400}

/* ── Suburb index ─────────────────────────────────────────────────────
   Fifty-odd links, which is a lot of rows and very little in each one.
   Columns rather than a list, so it reads as a directory to scan rather
   than a wall to scroll — and `auto-fill` rather than a fixed count so
   it collapses to one column on a phone without a media query.

   The count beside each name is multi-dwelling applications since 1999.
   It is what the list is ordered by, and without it the order looks
   arbitrary. */
.suburb-index{list-style:none; margin:0; padding:0;
  display:grid; gap:.15rem .9rem;
  grid-template-columns:repeat(auto-fill, minmax(13rem, 1fr))}
.suburb-index li{display:flex; justify-content:space-between; gap:.5rem;
  align-items:baseline; padding:.22rem 0; border-bottom:1px solid var(--g6);
  font-size:.86rem}
.suburb-index a{text-decoration:none}
.suburb-index a:hover{text-decoration:underline}
.suburb-index .mono{font-size:.76rem; color:var(--g3);
  font-variant-numeric:tabular-nums}
