/* Property Intel. Implements DESIGN.md - dark architecture under cool glass.
   Glass carries enough tint for contrast over the photographic ground, and
   one sheet per section rather than one panel per row: a list is a single
   compositing layer, which is what keeps it smooth on a phone. */

:root {
  --bg:        oklch(0.970 0.000 0);
  --page-bg:   var(--bg);
  --surface:   oklch(0.995 0.000 0);
  --text:      oklch(0.250 0.000 0);
  --text-mute: oklch(0.500 0.000 0);
  --border:    oklch(0.880 0.000 0);
  --accent:    oklch(0.520 0.110 195);
  --accent-dim:oklch(0.520 0.110 195 / 0.10);

  /* Two colours: the neutral scale and the teal. Nothing else has a hue.
     The verdict states used to carry green, red and amber; they now separate
     by weight in the neutral scale - affirmative takes the accent, attention
     sits near the text, and a rejection recedes. The word on the row says
     which it is, as it always did; the colour never carried that alone. */
  --state-pass:       var(--accent);
  --state-fail:       oklch(0.620 0.000 0);
  --state-no-reserve: var(--accent);
  --state-review:     oklch(0.420 0.000 0);

  --glass-tint: 55%;
  --glass-blur: 32px;

  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", "Roboto Mono", Menlo, monospace;
  --ease: cubic-bezier(0.25, 1, 0.5, 1);
  --metal: oklch(0.500 0.000 0);
  --shadow: 0 1px 2px oklch(0.250 0.000 0 / 0.05), 0 14px 34px oklch(0.250 0.000 0 / 0.07);
  /* Report chart identities, validated against this mode's surface
     (dataviz six checks, 2026-08-02). Gold carries the bid; teal carries
     the market. Status colors stay reserved for verdicts. */
  --chart-1: #636363;
  --chart-2: #007c7c;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg:        oklch(0.178 0.000 0);
    --page-bg:   linear-gradient(oklch(0.080 0.000 0 / 0.10), oklch(0.055 0.000 0 / 0.26)),
                 var(--page-photo);
    --surface:   oklch(0.222 0.000 0);
    --text:      oklch(0.955 0.000 0);
    --text-mute: oklch(0.683 0.000 0);
    --border:    oklch(0.500 0.000 0);
    --accent:    oklch(0.618 0.106 195);
    --accent-dim:oklch(0.618 0.106 195 / 0.12);
    --state-pass:   var(--accent);
    --state-fail:   oklch(0.560 0.000 0);
    --state-review: oklch(0.800 0.000 0);
    --glass-tint: 18%;
    --glass-blur: 20px;
    --metal: oklch(0.683 0.000 0);
    --chart-1: #999999;
    --chart-2: #009999;
    --shadow: 0 1px 1px oklch(0.040 0.000 0 / 0.40),
              0 18px 42px oklch(0.040 0.000 0 / 0.44);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --bg:        oklch(0.178 0.000 0);
  --page-bg:   linear-gradient(oklch(0.080 0.000 0 / 0.10), oklch(0.055 0.000 0 / 0.26)),
               var(--page-photo);
  --surface:   oklch(0.222 0.000 0);
  --text:      oklch(0.955 0.000 0);
  --text-mute: oklch(0.683 0.000 0);
  --border:    oklch(0.500 0.000 0);
  --accent:    oklch(0.618 0.106 195);
  --accent-dim:oklch(0.618 0.106 195 / 0.12);
  --state-pass:   var(--accent);
  --state-fail:   oklch(0.560 0.000 0);
  --state-review: oklch(0.800 0.000 0);
  --glass-tint: 18%;
  --glass-blur: 20px;
  --metal: oklch(0.683 0.000 0);
  --chart-1: #999999;
  --chart-2: #009999;
  --shadow: 0 1px 1px oklch(0.040 0.000 0 / 0.40),
            0 18px 42px oklch(0.040 0.000 0 / 0.44);
}

:root[data-theme="light"] {
  color-scheme: light;
  --bg:        oklch(0.970 0.000 0);
  --page-bg:   linear-gradient(oklch(0.970 0.000 0 / 0.86), oklch(0.945 0.000 0 / 0.90)),
               var(--page-photo);
  --surface:   oklch(0.995 0.000 0);
  --text:      oklch(0.250 0.000 0);
  --text-mute: oklch(0.500 0.000 0);
  --border:    oklch(0.880 0.000 0);
  --accent:    oklch(0.520 0.110 195);
  --accent-dim:oklch(0.520 0.110 195 / 0.10);
  --state-pass:   var(--accent);
  --state-fail:   oklch(0.620 0.000 0);
  --state-review: oklch(0.420 0.000 0);
  --glass-tint: 55%;
}

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0; min-height: 100vh; min-height: 100dvh;
  background-color: var(--bg);
  background-image: var(--page-bg);
  background-attachment: fixed;
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
  color: var(--text); font-family: var(--sans);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  /* Measured by app.js, because both bars are fixed and both grow with the OS
     text size. The literals are the fallback for a first paint and for no-JS. */
  padding-bottom: calc(var(--nav-h, 4.6rem) + 0.9rem);
}

.num { font-family: var(--mono); font-variant-numeric: tabular-nums; }
a { color: inherit; text-decoration: none; }

/* Announced, not shown. */
.sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
      overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }

/* ---- glass ------------------------------------------------------------- */
.panel {
  background: color-mix(in oklch, var(--surface) var(--glass-tint), transparent);
  backdrop-filter: blur(var(--glass-blur)) saturate(1.5);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.5);
  border: 1px solid color-mix(in oklch, var(--border) 58%, transparent);
  border-radius: 10px;
  box-shadow: var(--shadow);
}
@media (prefers-reduced-transparency: reduce) {
  .panel, .bar { background: var(--surface); backdrop-filter: none;
                 -webkit-backdrop-filter: none; }
}

/* ---- chrome ------------------------------------------------------------ */
.bar {
  position: fixed; left: 0; right: 0; z-index: 10;
  background: color-mix(in oklch, var(--surface) var(--glass-tint), transparent);
  backdrop-filter: blur(var(--glass-blur)) saturate(1.4);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.4);
}
header.bar {
  top: 0.75rem; left: 0.75rem; right: 0.75rem;
  display: flex; align-items: center; gap: 0.5rem 0.75rem; flex-wrap: wrap;
  padding: 0.7rem clamp(0.9rem, 3vw, 1.6rem);
  border: 1px solid color-mix(in oklch, var(--border) 58%, transparent);
  border-radius: 10px; box-shadow: var(--shadow);
}
.wordmark { font-family: var(--serif); font-weight: 500; letter-spacing: 0.01em;
            font-size: 1.0625rem; flex: 0 0 auto;
            display: inline-flex; align-items: center; gap: 0.45rem; }
.wordmark .mark { width: 19px; height: 19px; display: block; color: var(--metal); }
/* The version telemetry that used to sit here moved to the assumptions page,
   where data freshness is read. The header keeps only the mark and the acts. */
#themer { margin-left: auto; }
.iconbtn {
  border: 1px solid color-mix(in oklch, var(--border) 75%, transparent);
  background: color-mix(in oklch, var(--surface) 42%, transparent); color: var(--text-mute);
  border-radius: 6px; padding: 0.32rem 0.55rem; font: inherit; font-size: 0.75rem;
  cursor: pointer; min-height: 32px;
}
.iconbtn:hover { color: var(--text); background: color-mix(in oklch, var(--surface) 72%, transparent); }
.iconbtn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* auto-fit, not repeat(4): at large OS text sizes four fixed columns are
   narrower than the word "Assumptions" and the bar overflowed the viewport by
   8px. Fewer, wider columns and a second row instead. */
nav.bar {
  /* Read by app.js, so the breakpoint below is the only place the two shapes
     are decided. Measuring the element instead would have the rail's 900px of
     height reserved as foot padding. */
  --nav-mode: bar;
  bottom: 0.6rem; left: 0.6rem; right: 0.6rem;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(4.5rem, 1fr));
  padding: 0.35rem 0.3rem calc(0.35rem + env(safe-area-inset-bottom));
  border: 1px solid color-mix(in oklch, var(--border) 58%, transparent);
  border-radius: 10px; box-shadow: var(--shadow);
}
nav.bar a {
  font-size: 0.78125rem; color: var(--text-mute); padding: 0.6rem 0.2rem;
  min-height: 44px; border-radius: 10px; text-align: center; white-space: nowrap;
  display: flex; align-items: center; justify-content: center; gap: 0.3rem;
  transition: color 180ms var(--ease), background 180ms var(--ease);
}
nav.bar a[aria-current="page"] { color: var(--accent); background: var(--accent-dim);
                                 font-weight: 550; }
nav.bar a:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
nav.bar .n { font-family: var(--mono); font-variant-numeric: tabular-nums;
             font-size: 0.75rem; opacity: 0.8; }
.nav-short { display: none; }

main { padding: calc(var(--header-h, 4.5rem) + 1.75rem) clamp(0.75rem, 3vw, 1.6rem) 0;
       max-width: 1300px; margin: 0 auto; }

/* ---- the census strip ---------------------------------------------------
   Four counts across the top of the working surface, each a link to the list
   it describes. No rates and no deltas: one snapshot cannot carry a direction. */
.census-strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
  gap: 1px; margin: 0.25rem 0 0.4rem;
  border-radius: 10px; overflow: hidden;
  background: color-mix(in oklch, var(--border) 40%, transparent);
  border: 1px solid color-mix(in oklch, var(--border) 40%, transparent);
}
.census-strip .stat {
  background: color-mix(in oklch, var(--surface) 42%, transparent);
  padding: 0.7rem 0.9rem 0.75rem;
  display: flex; flex-direction: column; gap: 0.1rem;
  transition: background 180ms var(--ease);
}
.census-strip .stat:hover { background: var(--surface); }
.census-strip .stat:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.census-strip .n { font-family: var(--serif); font-size: 1.5rem; font-weight: 500;
                   letter-spacing: 0; line-height: 1.05; }
.census-strip .l { font-size: 0.6875rem; text-transform: uppercase;
                   letter-spacing: 0.13em; color: var(--text-mute); font-weight: 540; }
/* Two by two on a phone. `auto-fit` gets three across a 390px screen and leaves
   the fourth alone beside an empty cell, which reads as a missing figure. */
@media (max-width: 560px) {
  body { background-position: 22% center; }
  .census-strip { grid-template-columns: repeat(2, 1fr); }
  .census-strip .stat:nth-child(3) { border-left: 0; }
  .census-strip .stat:nth-child(n+3) { border-top: 1px solid var(--hairline); }
  /* This was one column per link, on the rule that a wrapped last item reads
     as a broken bar. Eleven links no longer fit one row at 390px - nine were
     already tight, and Model health and Bank sale insights joined them - so
     the choice became a deliberate two rows or targets under 35px wide. Six
     across keeps every tap target near 60px and fills both rows almost
     evenly; app.js measures the bar and reserves its real height at the foot
     of the page, so a taller nav costs layout nothing. */
  /* Five doors fit one row again. The two-row, six-column bar above was the
     honest answer to eleven links; with the second rank hidden here there are
     five, each near 74px at 390px, which is the phone shape the redesign
     specifies and a wider target than the old bar ever managed. */
  nav.bar { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  nav.bar a { font-size: 0.71875rem; padding: 0.6rem 0.1rem; }
  nav.bar .nav-long { display: none; }
  nav.bar .nav-short { display: inline; }
}

/* Two ranks below the five doors, and they do not get the same treatment.

   `.nav-peer` is demand, rent and bank-sale insights: peer decision routes by
   D66, D36 and D54, kept at that status on the owner's instruction. They
   appear from tab width up, beside the workspace doors rather than under
   Model, because Model is where the system reports on itself and these are
   not that.

   `.nav-secondary` is Model's own internals. Rail only - at tab width seven
   more tabs is the crowding the five-door IA exists to remove, and the Model
   page indexes them anyway.

   Neither is in the phone bar. Five thumb targets is the point of the phone
   shape; the peer routes reach the phone through the row on Ranked instead,
   which is one tap from the surface a phone actually opens on. */
nav.bar .nav-secondary,
nav.bar .nav-peer { display: none; }

/* ---- furniture --------------------------------------------------------- */
.eyebrow {
  font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.13em;
  color: var(--text-mute); font-weight: 540; margin: 2.5rem 0 0.5rem;
  display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap;
}
/* The colophon. Census date and set versions, once, at the foot of the
   assumptions page - the header bar is the brand zone, not the telemetry's. */
.ledger { font-size: 0.6875rem; color: var(--text-mute); font-family: var(--mono);
          text-align: center; line-height: 1.5; margin: 2.5rem 0 0.25rem; }
.eyebrow .count { font-family: var(--mono); letter-spacing: 0; }
.eyebrow .switch { margin-left: auto; display: flex; gap: 0.3rem; letter-spacing: 0; }
.eyebrow .switch a { font-size: 0.6875rem; padding: 0.15rem 0.5rem; border-radius: 6px;
                     border: 1px solid color-mix(in oklch, var(--border) 70%, transparent);
                     text-transform: none; }
.eyebrow .switch a[aria-current="true"] { color: var(--accent); border-color: var(--accent);
                                          background: var(--accent-dim); }
/* A basis the data cannot support. Present, named and not clickable - removing
   it would hide that yield is the ranking rule at all. F4. */
.eyebrow .switch .off {
  font-size: 0.6875rem; padding: 0.15rem 0.5rem; border-radius: 6px;
  border: 1px dashed color-mix(in oklch, var(--border) 70%, transparent);
  color: color-mix(in oklch, var(--text-mute) 75%, transparent);
  text-transform: none; cursor: not-allowed;
}
.eyebrow .switch .chip-part { font-family: var(--mono); font-size: 0.625rem; opacity: 0.85; }
.avail { font-size: 0.75rem; color: var(--text-mute); margin: -0.15rem 0 0.5rem; }

/* ---- opportunity stage ------------------------------------------------ */
.stage-head { padding: 0.35rem 0 0.55rem; max-width: 62ch; }
.stage-head .eyebrow { margin: 0.35rem 0 0.35rem; }
.stage-head h1 { margin: 0; font-family: var(--serif); font-size: 1.55rem;
                 font-weight: 500; letter-spacing: 0; line-height: 1.2; }
.stage-head > p:not(.eyebrow) { margin: 0.45rem 0 0; color: var(--text-mute);
                                font-size: 0.875rem; line-height: 1.55; }
.stage-method { color: var(--text-mute); font-size: 0.75rem; }
.stage-method summary { width: max-content; cursor: pointer; font-weight: 600; }
.stage-method summary:hover { color: var(--text); }
.stage-method summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.stage-method p { margin: 0.5rem 0 0; line-height: 1.55; }
@media (min-width: 900px) {
  .insights-page > .stage-head {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(20rem, 0.72fr);
    column-gap: clamp(2rem, 5vw, 5rem);
    row-gap: 0.5rem;
    align-items: start;
    max-width: none;
  }
  .insights-page > .stage-head > .eyebrow { grid-column: 1 / -1; }
  .insights-page > .stage-head > h1 { grid-column: 1; grid-row: 2; }
  .insights-page > .stage-head > :not(.eyebrow):not(h1) { grid-column: 2; }
  .insights-page > .stage-head > p:not(.eyebrow) { margin-top: 0; }
}
.opportunity-filters { margin-top: 0.2rem; }
.opportunity-sheet { margin-top: 0.75rem; }
.opportunity-row .rowmain { align-items: flex-start; }
.decision-mark { display: block; color: var(--accent); font-size: 0.6875rem;
                 font-weight: 620; text-transform: uppercase; letter-spacing: 0; }
.opportunity-row .addr { margin-top: 0.08rem; line-height: 1.35; }
.decision-line { display: flex; flex-wrap: wrap; gap: 0.12rem 0.75rem;
                 align-items: baseline; margin-top: 0.42rem;
                 font-size: 0.75rem; color: var(--text-mute); }
.decision-line b { color: var(--text); font-weight: 600; }
.rent-line { display: block; margin-top: 0.18rem; font-size: 0.875rem;
             color: var(--text-mute); }
.rent-line b { color: var(--accent); font-size: 1rem; font-weight: 620; }
/* The exit read where a row carries no figure line to join - attend and the
   review queue. Same label-then-figure vocabulary as .decision-line, so the
   field reads the same on every surface; its own line because run into the
   meta text it read as one more provenance token, and at 390px the chip form
   tore across two lines with the border broken in half. */
.demand-line { display: block; margin-top: 0.15rem; font-size: 0.75rem;
               color: var(--text-mute); }
.demand-line b { color: var(--text); font-weight: 600; }
.property-tags { display: flex; flex-wrap: wrap; gap: 0.25rem;
                 margin-top: 0.3rem; }
.property-tag { display: inline-flex; align-items: center; min-height: 1.35rem;
                padding: 0.12rem 0.4rem; border-radius: 4px;
                border: 1px solid color-mix(in oklch, var(--border) 52%, transparent);
                background: color-mix(in oklch, var(--surface) 28%, transparent);
                color: var(--text-mute); font-size: 0.625rem; font-weight: 580;
                line-height: 1.2; }
.property-tag.auction { color: var(--metal); }
.property-tag.source { color: var(--accent); }
.property-tag.source-sheriffhq { color: var(--metal); }
.property-tag.reject { color: var(--state-fail);
                       border-color: color-mix(in oklch, var(--state-fail) 52%, transparent);
                       background: color-mix(in oklch, var(--state-fail) 10%, transparent); }

.decision-callout { display: grid; gap: 0.2rem; margin: 1rem 0 0;
                    padding: 0.85rem 0; border-top: 1px solid color-mix(in oklch, var(--accent) 35%, transparent);
                    border-bottom: 1px solid color-mix(in oklch, var(--accent) 24%, transparent); }
.decision-callout .lbl { color: var(--accent); font-size: 0.6875rem;
                         font-weight: 620; text-transform: uppercase; letter-spacing: 0; }
.decision-callout strong { font-family: var(--serif); font-size: 1.35rem;
                           font-weight: 500; letter-spacing: 0; }
.decision-callout > span:last-child { color: var(--text-mute); font-size: 0.75rem;
                                      line-height: 1.5; max-width: 62ch; }

/* ---- deal insights ----------------------------------------------------- */
.insights-page { width: min(100%, 68rem); }
.insight-tabs { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
                gap: 0.25rem; padding: 0.3rem; margin-top: 0.35rem; }
.insight-tabs a { min-width: 0; min-height: 3.25rem; padding: 0.45rem 0.35rem;
                  display: flex; flex-direction: column; align-items: center;
                  justify-content: center; gap: 0.15rem; border-radius: 6px;
                  color: var(--text-mute); font-size: 0.75rem; line-height: 1.25;
                  text-align: center; }
.insight-tabs a b { color: inherit; font-size: 0.6875rem; font-weight: 540; }
.insight-tabs a:hover { color: var(--text); background: color-mix(in oklch, var(--text) 5%, transparent); }
.insight-tabs a:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.insight-tabs a[aria-current="page"] { color: var(--accent);
                                        background: var(--accent-dim); }
.insight-sheet { margin-top: 0.75rem; }
.insights-page[data-insight-page="high"] .insight-sheet {
  border-color: color-mix(in oklch, var(--state-pass) 48%, var(--border));
}
.insights-page[data-insight-page="late"] .insight-sheet {
  border-color: color-mix(in oklch, var(--state-review) 48%, var(--border));
}
.insight-tabs + .opportunity-filters { margin-top: 0.75rem; }
.factor-row .rowmain { align-items: flex-start; }
.factor-action { display: block; font-size: 0.6875rem; font-weight: 620;
                 text-transform: uppercase; letter-spacing: 0; color: var(--text-mute); }
.factor-row.candidate .factor-action { color: var(--state-pass); }
.factor-row.high .factor-action { color: var(--state-pass); }
.factor-row.late .factor-action { color: var(--state-review); }
.factor-row.township .factor-action,
.factor-row.land .factor-action { color: var(--metal); }
.factor-row.reject .factor-action { color: var(--state-fail); }
.factor-row.evidence .factor-action { color: var(--state-review); }
.factor-row .addr { margin-top: 0.08rem; }
.factor-verdict { display: block; margin-top: 0.3rem; color: var(--text-mute);
                  font-size: 0.8125rem; line-height: 1.45; }

/* ---- source register --------------------------------------------------- */
.source-summary { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
                  gap: 0.55rem; margin-top: 0.8rem; }
.source-stat { display: grid; grid-template-columns: auto 1fr; align-items: baseline;
               gap: 0.1rem 0.65rem; padding: 0.75rem 0.85rem; }
.source-stat b { grid-row: 1 / 3; color: var(--accent); font-family: var(--serif);
                 font-size: 1.65rem; font-weight: 500; }
.source-stat > span { color: var(--text); font-size: 0.8125rem; font-weight: 600; }
.source-stat small { color: var(--text-mute); font-size: 0.6875rem; }
.source-stat .failed { color: var(--state-fail); }
.source-filters, .demand-filters { margin-top: 0.75rem; }
.source-sheet { margin-top: 0; }
.source-value { min-width: 8.75rem; }
.source-value i { display: block; color: var(--text-mute); font-size: 0.6875rem;
                  font-style: normal; }
.source-pages { display: flex; align-items: center; justify-content: center;
                gap: 0.75rem; margin: 0.9rem 0 1.5rem; }
.source-pages .btn { min-width: 7rem; }

@media (max-width: 560px) {
  .source-summary { grid-template-columns: 1fr; }
  .source-value { min-width: 0; }
}
.factor-verdict b { color: var(--text); font-weight: 600; }
.factor-metrics { display: flex; flex-wrap: wrap; gap: 0.15rem 0.9rem;
                  margin-top: 0.25rem; color: var(--text-mute); font-size: 0.75rem; }
.factor-metrics b { color: var(--text); font-weight: 540; }

@media (max-width: 560px) {
  .factor-row .rowmain { gap: 0.45rem; }
  .factor-metrics { display: grid; grid-template-columns: 1fr; gap: 0.05rem; }
}

@media (min-width: 1100px) {
  .insights-page .insight-tabs { grid-template-columns: repeat(8, minmax(0, 1fr)); }
}

.caveat {
  font-size: 0.8125rem; line-height: 1.55; color: var(--text-mute);
  padding: 0.85rem 1rem; margin: 0.75rem 0 0; border-radius: 10px;
  background: color-mix(in oklch, var(--surface) 60%, transparent);
  border: 1px dashed color-mix(in oklch, var(--border) 85%, transparent);
}
.caveat strong { color: var(--text); font-weight: 560; }
.caveat + .caveat { margin-top: 0.5rem; }

/* ---- the shared header ------------------------------------------------- */
/* What holds for every row is a property of the set, not of any row in it, so
   it is said once here instead of 58 times below. Measured before this existed:
   the bid, its caption and the badge set were byte-identical across all 58 rows
   and took 44% of each row's area. This is the sheet's header, not a panel of
   its own: nesting a second glass surface inside the list would be a card grid
   with one card. */
.uniform {
  padding: 0.7rem 1rem 0.75rem;
  background: color-mix(in oklch, var(--text) 3.5%, transparent);
  border-bottom: 1px solid color-mix(in oklch, var(--border) 40%, transparent);
}
/* A grid, not a wrapped sentence. Separating the clauses with punctuation or a
   divider leaves an orphaned mark at the start of every wrapped line, and this
   block wraps at almost every width. Columns align instead. */
.uniform .all {
  margin: 0; font-size: 0.8125rem; line-height: 1.4; display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
  gap: 0.25rem 1.1rem;
}
.uniform .all + .all { margin-top: 0.55rem; }
.uniform .lead {
  grid-column: 1 / -1;
  font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.13em;
  font-weight: 560; color: var(--text-mute);
}
.uniform .cl { color: var(--text-mute); text-wrap: pretty; }
/* Prose, not a clause. `.lead` is a label and sets everything uppercase. */
.uniform .note { margin: 0.55rem 0 0; font-size: 0.75rem; line-height: 1.5;
                 color: var(--text-mute); max-width: 60ch; text-wrap: pretty; }
.uniform .cl b { font-weight: 560; color: var(--text); letter-spacing: 0; }
/* The badges are their own row and size to content rather than to the columns. */
.uniform .states { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; }
.uniform .states .lead { flex: 0 0 auto; }

/* ---- rows -------------------------------------------------------------- */
.sheet { overflow: hidden; }
.row {
  display: flex; align-items: stretch;
  border-top: 1px solid color-mix(in oklch, var(--border) 30%, transparent);
  transition: background 160ms var(--ease);
}
.uniform + .row, .row:first-child { border-top: 0; }
.row:hover { background: color-mix(in oklch, var(--accent) 5%, transparent); }
.row[aria-selected="true"] { background: color-mix(in oklch, var(--accent) 9%, transparent); }
.row.factor-row.preference-reject,
.row.source-row.preference-reject,
.row.factor-row.preference-reject:hover,
.row.source-row.preference-reject:hover {
  background: color-mix(in oklch, var(--state-fail) 9%, transparent);
  box-shadow: inset 3px 0 color-mix(in oklch, var(--state-fail) 86%, transparent);
}
.row.factor-row.preference-reject .factor-action { color: var(--state-fail); }
.row.factor-row.preference-reject .addr,
.row.source-row.preference-reject .addr { color: var(--state-fail); }

/* Rank, then who, then the clock. Flex rather than grid so the queue can drop
   the rank column without leaving a gutter behind. */
.rowmain {
  flex: 1 1 auto; min-width: 0; cursor: pointer;
  display: flex; align-items: baseline; gap: 0.7rem;
  padding: 0.7rem 0.4rem 0.75rem 0.85rem;
}
.rowmain:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px;
                         border-radius: 10px; }

.rank { flex: 0 0 1.5rem; text-align: right; font-size: 0.8125rem; font-weight: 500;
        color: var(--text-mute); letter-spacing: 0; }
.who { flex: 1 1 auto; min-width: 0; display: block; }

.addr { font-size: 0.9375rem; font-weight: 500; letter-spacing: 0; display: block; }
.meta { font-size: 0.8125rem; color: var(--text-mute); display: block; margin-top: 0.05rem; }
.meta .ref { font-family: var(--mono); }

/* Figures appear only where they differ across the set. A figure and its label
   are one unit so a wrap never separates them.

   Each figure is a tile with its name above it, rather than a bold number
   trailed by a clause. Read as a run, four figures and four explanations were
   one sentence the eye had to parse; named and boxed, a single figure can be
   found without reading the others. The tiles size to content so a row with
   two figures does not stretch them across the width. */
.figs { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-top: 0.5rem; }
.figs .f {
  display: flex; flex-direction: column; gap: 0.15rem; min-width: 0;
  padding: 0.4rem 0.6rem; border-radius: 8px;
  border: 1px solid color-mix(in oklch, var(--border) 50%, transparent);
  background: color-mix(in oklch, var(--surface) 26%, transparent);
}
.figs .f .k {
  font-size: 0.5625rem; font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-mute); white-space: nowrap;
}
.figs b { font-family: var(--mono); font-variant-numeric: tabular-nums;
          font-size: 1rem; font-weight: 560; letter-spacing: 0; }
.figs b.soft { font-weight: 500; color: var(--text-mute); font-size: 0.9375rem; }
.figs i { font-style: normal; font-size: 0.6875rem; color: var(--text-mute); }
.figs i.absent { font-size: 0.75rem; }
/* Contradicted by the property's own last sale. Marked, not withdrawn: absent
   and doubtful are different facts and 8.2 keeps them apart. */
.figs b.doubted { text-decoration: underline dotted
                  color-mix(in oklch, var(--state-review) 80%, transparent);
                  text-underline-offset: 4px; }

/* The clock. Always present, never coloured, never counting down: Principle 2. */
.edge { flex: 0 0 auto; text-align: right; align-self: center; }
.edge .d { display: block; font-family: var(--mono); font-variant-numeric: tabular-nums;
           font-size: 1.125rem; font-weight: 560; letter-spacing: 0; line-height: 1.1; }
.edge .u { display: block; font-size: 0.6875rem; color: var(--text-mute); line-height: 1.25;
           max-width: 6.5em; }
/* The auction date, above the count of days. Muted and unemphasised for the
   same reason the count is: it is the clock, not an alarm. */
.edge .when { display: block; font-size: 0.75rem; color: var(--text-mute);
              font-variant-numeric: tabular-nums; line-height: 1.3;
              white-space: nowrap; }

.tags { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.5rem; }

/* ---- state badges: never colour alone ---------------------------------- */
.badge {
  display: inline-flex; align-items: center; gap: 0.35rem;
  font-size: 0.6875rem; font-weight: 580; letter-spacing: 0.045em;
  text-transform: uppercase; padding: 0.2rem 0.5rem 0.2rem 0.4rem;
  border-radius: 6px; border: 1px solid currentColor; white-space: nowrap;
}
.badge .mark { font-family: var(--mono); font-size: 0.8125rem; line-height: 1; opacity: 0.9; }
.badge.pass      { color: var(--state-pass); }
.badge.fail      { color: var(--state-fail); }
.badge.noreserve { color: var(--state-no-reserve); background: var(--accent-dim); }
.badge.review    { color: var(--state-review); }

.chip {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 0.6875rem; color: var(--text-mute); letter-spacing: 0.02em;
  padding: 0.2rem 0.5rem; border-radius: 6px;
  border: 1px solid color-mix(in oklch, var(--border) 70%, transparent);
}
.chip.window { color: var(--text); border-color: color-mix(in oklch, var(--text) 35%, transparent); }

/* ---- favourite: form, not colour -------------------------------------- */
.fav {
  flex: 0 0 auto; width: 52px; min-height: 24px; display: grid; place-items: center;
  background: none; border: 0; cursor: pointer; color: var(--text-mute);
  border-radius: 8px; margin: 0.35rem 0.35rem 0.35rem 0;
  transition: color 160ms var(--ease), background 160ms var(--ease);
}
.fav:hover { color: var(--text); background: color-mix(in oklch, var(--text) 7%, transparent); }
.fav:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.fav svg { width: 21px; height: 21px; display: block; }
.fav[aria-pressed="true"] { color: var(--metal); }

/* ---- detail ------------------------------------------------------------ */
.detail { padding: 1.5rem 1.5rem 1.7rem; }
.detail h2 { margin: 0; font-family: var(--serif); font-size: 1.4rem; font-weight: 500;
             letter-spacing: 0; text-wrap: balance; }
.detail .sub { color: var(--text-mute); font-size: 0.875rem; margin: 0.15rem 0 0; }
.detail .badges { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0.85rem 0 0; }

.headline { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem 1.5rem;
            margin: 1.25rem 0 0.25rem; }
.headline .big { font-family: var(--serif); font-variant-numeric: lining-nums tabular-nums;
                 font-size: 2.4rem; font-weight: 500; letter-spacing: 0; }
.headline .big.none { font-size: 1.25rem; font-weight: 400; color: var(--text-mute); }
.headline .lbl { font-size: 0.75rem; color: var(--text-mute); text-transform: uppercase;
                 letter-spacing: 0.08em; }
.headline .beside { font-family: var(--mono); font-variant-numeric: tabular-nums;
                    font-size: 0.9375rem; color: var(--text-mute); }

table { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
th { text-align: left; font-weight: 500; color: var(--text-mute); font-size: 0.75rem;
     text-transform: uppercase; letter-spacing: 0.07em; padding: 0 0 0.4rem; }
th:last-child, td:last-child { text-align: right; }
td { padding: 0.5rem 0; border-top: 1px solid color-mix(in oklch, var(--border) 30%, transparent); }
td.v { font-family: var(--mono); font-variant-numeric: tabular-nums; white-space: nowrap; }
tr.total td { font-weight: 600;
              border-top: 1.5px solid color-mix(in oklch, var(--text) 30%, transparent); }
/* A range is two figures, not one: at large OS text sizes a nowrap range was
   289px wide in a 390px viewport and took the page 62px past the fold sideways.
   Each figure stays unbroken; the range breaks between them. */
tr.prov td.v { color: var(--text-mute); }
td.v.range, tr.prov td.v { white-space: normal; }
td.v .r { white-space: nowrap; }

/* Notice prose can be much longer than a figure. It wraps inside its evidence
   column instead of inheriting the no-wrap contract used by currency values. */
.recited { table-layout: fixed; }
.recited td:first-child { width: 40%; padding-right: 0.75rem; }
.recited td.v { white-space: normal; overflow-wrap: anywhere; }

.assumed { text-decoration: underline dotted color-mix(in oklch, var(--state-review) 75%, transparent);
           text-underline-offset: 3px; }

/* Comparables. Wide, so it scrolls in its own box rather than pushing the page
   sideways; the first column stays put because the rest is meaningless without
   knowing which sale it belongs to. */
.comps { display: block; overflow-x: auto; white-space: nowrap; font-size: 0.8125rem; }
.comps th, .comps td { padding-right: 0.7rem; }
.comps th:last-child, .comps td:last-child { padding-right: 0; text-align: right; }
.comps td.v { font-size: 0.8125rem; }
/* The rate is the column the table exists to show; the rest is corroboration. */
.comps td.strong { font-weight: 560; color: var(--text); }
/* Fenced out, kept visible. Nothing disappears for failing a test: the reader
   has to be able to see what was excluded and disagree with it. */
.comps tr.excluded td { color: var(--text-mute); text-decoration: line-through;
                        text-decoration-color: color-mix(in oklch, var(--text-mute) 50%, transparent); }
.comps tr.excluded td.strong { font-weight: 500; }
.comps .x { text-decoration: none; display: inline-block; font-size: 0.625rem;
            text-transform: uppercase; letter-spacing: 0.06em; font-weight: 580;
            color: var(--state-review); border: 1px solid currentColor;
            border-radius: 4px; padding: 0 0.25rem; vertical-align: 1px; }

/* Nearby sales as a governed decision visual. The crosshairs are derived from
   the model rate and the median distance, so the four zones keep their meaning
   from one property to the next. Exact records remain in the disclosure below. */
.comp-quadrants { margin: 1.2rem 0 0; }
.comp-chart-head { display: flex; align-items: baseline; justify-content: space-between;
                   gap: 0.25rem 1rem; margin-bottom: 0.55rem; }
.comp-chart-head strong { font-size: 0.8125rem; font-weight: 620; color: var(--state-pass); }
.comp-chart-head span { color: var(--text-mute); font-size: 0.75rem; text-align: right; }
.comp-plot {
  position: relative; height: clamp(20rem, 52vw, 27rem); overflow: hidden;
  border: 1px solid color-mix(in oklch, var(--border) 65%, transparent);
  border-radius: 8px;
  background: color-mix(in oklch, var(--surface) 26%, transparent);
}
.comp-plot::before, .comp-plot::after {
  content: ""; position: absolute; z-index: 2; pointer-events: none;
  background: color-mix(in oklch, var(--text) 34%, transparent);
}
.comp-plot::before { top: 0; bottom: 0; left: var(--x-split); width: 1px; }
.comp-plot::after { left: 0; right: 0; bottom: var(--y-split); height: 1px; }
.comp-quadrant-grid {
  position: absolute; inset: 0; z-index: 1; display: grid;
  grid-template-columns: var(--x-split) 1fr;
  grid-template-rows: calc(100% - var(--y-split)) var(--y-split);
}
.comp-quadrant { min-width: 0; padding: 0.6rem; display: flex; flex-direction: column;
                 justify-content: flex-start; pointer-events: none; }
.comp-quadrant:nth-child(2), .comp-quadrant:nth-child(4) { align-items: flex-end; text-align: right; }
.comp-quadrant:nth-child(3), .comp-quadrant:nth-child(4) { justify-content: flex-end; }
.comp-quadrant b { font-size: 0.6875rem; line-height: 1.2; font-weight: 620; }
.comp-quadrant small { margin-top: 0.1rem; color: var(--text-mute); font-size: 0.625rem;
                       line-height: 1.25; }
.comp-quadrant.near-low { background: color-mix(in oklch, var(--state-pass) 10%, transparent); }
.comp-quadrant.near-high { background: color-mix(in oklch, var(--accent) 7%, transparent); }
.comp-quadrant.far-low { background: color-mix(in oklch, var(--state-review) 7%, transparent); }
.comp-quadrant.far-high { background: color-mix(in oklch, var(--state-fail) 5%, transparent); }

.comp-point {
  appearance: none; position: absolute; z-index: 4; left: var(--x); bottom: var(--y);
  width: 26px; height: 26px; padding: 0; border: 0; border-radius: 50%;
  background: transparent; transform: translate(-50%, 50%); cursor: pointer;
}
.comp-point::before {
  content: ""; position: absolute; inset: 7px; border-radius: 50%;
  background: var(--accent); border: 1px solid color-mix(in oklch, var(--text) 68%, transparent);
  box-shadow: 0 1px 3px color-mix(in oklch, var(--bg) 70%, transparent);
}
.comp-point:hover::before, .comp-point.selected::before { inset: 5px; }
.comp-point.selected::before { outline: 2px solid var(--text); outline-offset: 2px; }
.comp-point.excluded::before { border-radius: 2px; background: var(--state-fail); }
.comp-point.context::before { background: transparent; border: 2px solid var(--state-review); }
.comp-point.excluded::after {
  content: "\00d7"; position: absolute; inset: 0; display: grid; place-items: center;
  color: var(--bg); font-size: 0.6875rem; font-weight: 760; line-height: 1;
}
.comp-point:focus-visible { outline: 2px solid var(--text); outline-offset: 1px; }
.comp-axis { position: absolute; z-index: 3; pointer-events: none; color: var(--text-mute);
             font-family: var(--mono); font-size: 0.5625rem; text-transform: uppercase; }
.comp-axis.rate { top: 50%; left: 0.25rem; transform: rotate(-90deg) translateX(-50%);
                  transform-origin: left top; }
.comp-chart-meta { margin-top: 0.45rem; color: var(--text-mute); font-size: 0.6875rem;
                   line-height: 1.45; }
.comp-selection { display: grid; gap: 0.15rem; margin: 0.65rem 0 0; padding: 0.65rem 0.75rem;
                  border: 1px solid color-mix(in oklch, var(--border) 52%, transparent);
                  border-radius: 8px; background: color-mix(in oklch, var(--surface) 22%, transparent); }
.comp-selection > span { color: var(--text-mute); font-size: 0.625rem; font-weight: 580;
                         text-transform: uppercase; letter-spacing: 0.08em; }
.comp-selection strong { font-size: 0.75rem; line-height: 1.5; font-weight: 540; }
.comp-key { display: flex; flex-wrap: wrap; gap: 0.45rem 1rem; margin: 0.45rem 0 0;
            color: var(--text-mute); font-size: 0.6875rem; }
.comp-key span { display: inline-flex; align-items: center; gap: 0.35rem; }
.comp-key i { display: inline-block; width: 0.55rem; height: 0.55rem;
              background: var(--accent); border: 1px solid currentColor; border-radius: 50%; }
.comp-key i.context { background: transparent; border: 2px solid var(--state-review); }
.comp-key i.out { background: var(--state-fail); border-radius: 2px; }
.comp-table-disclosure { margin-top: 0.75rem; border-top: 1px solid color-mix(in oklch, var(--border) 42%, transparent); }
.comp-table-disclosure > summary { min-height: 44px; display: flex; align-items: center; gap: 0.45rem;
                                   cursor: pointer; color: var(--text); font-size: 0.8125rem;
                                   font-weight: 560; list-style: none; }
.comp-table-disclosure > summary::-webkit-details-marker { display: none; }
.comp-table-disclosure > summary::after { content: "+"; margin-left: auto; color: var(--text-mute);
                                          font-family: var(--mono); font-size: 1rem; }
.comp-table-disclosure[open] > summary::after { content: "\2212"; }
.comp-table-disclosure > summary span { color: var(--text-mute); font-size: 0.6875rem; font-weight: 450; }
.comp-table-disclosure > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.comp-table-disclosure .comps { padding-bottom: 0.4rem; }

@media (max-width: 560px) {
  .comp-chart-head { display: grid; }
  .comp-chart-head span { text-align: left; }
  .comp-plot { height: 23rem; }
  .comp-quadrant { padding: 0.45rem; }
  .comp-quadrant small { display: none; }
}
tr.flagged td:first-child { font-weight: 550; }
/* Provenance was in a title attribute, which never fires on touch, and half the
   stated workload is a phone. It is rendered instead, next to the figure it
   qualifies: Principle 4, the caveat lives where the number is read. */
.why { display: block; font-size: 0.6875rem; line-height: 1.4; color: var(--state-review);
       margin-top: 0.05rem; max-width: 34ch; }

/* Normalised public GIS evidence stays in the same audit-table language as the
   sourced auction evidence. It is context, not another verdict panel. */
.open-evidence { margin-top: 1.15rem; }
.open-evidence-scope { margin: -0.25rem 0 0.55rem; max-width: 66ch;
                       color: var(--text-mute); font-size: 0.75rem; line-height: 1.5; }
.open-data-table { table-layout: fixed; }
.open-data-table td:first-child { width: 38%; padding-right: 0.8rem; }
.open-data-table td.v { white-space: normal; overflow-wrap: anywhere; }
.open-data-table .open-risk-hit td { color: var(--state-fail); }
.open-data-table .open-risk-hit .why { color: var(--state-fail); opacity: 0.82; }
.open-data-table .open-not-assessed td { color: var(--text-mute); }
.open-map-credit { margin: 0.45rem 0 0; color: var(--text-mute); font-size: 0.6875rem; }
.open-map-credit a { text-decoration: underline; text-underline-offset: 2px; }
.open-data-sources { margin-top: 0.5rem;
                     border-top: 1px solid color-mix(in oklch, var(--border) 42%, transparent); }
.open-data-sources > summary { min-height: 44px; display: flex; align-items: center;
                               cursor: pointer; list-style: none; font-size: 0.8125rem;
                               font-weight: 560; }
.open-data-sources > summary::-webkit-details-marker { display: none; }
.open-data-sources > summary::after { content: "+"; margin-left: auto;
                                      color: var(--text-mute); font-family: var(--mono); }
.open-data-sources[open] > summary::after { content: "\2212"; }
.open-data-sources td:first-child { width: 38%; }
.open-data-sources td.v { white-space: normal; }
.open-data-sources .open-state { text-transform: capitalize; }
.open-data-sources .open-state.parsed,
.open-data-sources .open-state.held,
.open-data-sources .open-state.empty-at-source { color: var(--state-pass); }
.open-data-sources .open-state.failed { color: var(--state-fail); }
.open-data-sources .open-state.not-run { color: var(--text-mute); }
.open-data-sources a { text-decoration: underline; text-underline-offset: 2px; }

@media (max-width: 560px) {
  .open-data-table td:first-child, .open-data-sources td:first-child { width: 42%; }
}

.warn { display: flex; gap: 0.5rem; font-size: 0.8125rem; color: var(--text-mute);
        padding: 0.3rem 0; align-items: baseline; }
.warn .m { font-family: var(--mono); color: var(--state-review); flex: 0 0 auto; }

/* The corroboration line. Shown whether it passes or fails, because a check the
   reader only meets on failure is one they cannot calibrate. */
.check { display: flex; gap: 0.55rem; align-items: baseline; margin: 0.55rem 0 0;
         font-size: 0.8125rem; line-height: 1.5; color: var(--text-mute);
         max-width: 62ch; }
.check .m { font-family: var(--mono); flex: 0 0 auto; color: var(--state-pass); }
.check b { font-weight: 560; color: var(--text); }
.check.disputed { color: var(--text); }
.check.disputed .m { color: var(--state-review); }

.actions { display: flex; gap: 0.5rem; margin-top: 1.25rem; }
.btn {
  flex: 1 1 auto; min-height: 44px; border-radius: 8px; font: inherit; font-size: 0.875rem;
  font-weight: 520; cursor: pointer; padding: 0.6rem 1rem;
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
  border: 1px solid var(--border); background: transparent; color: var(--text);
  transition: background 160ms var(--ease), border-color 160ms var(--ease);
}
.btn:hover { background: color-mix(in oklch, var(--text) 6%, transparent); }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--bg); }
.btn svg { width: 18px; height: 18px; }

/* ---- assumptions ------------------------------------------------------- */
.field { display: grid; gap: 0.15rem; padding: 0.8rem 1rem;
         border-top: 1px solid color-mix(in oklch, var(--border) 30%, transparent); }
.field:first-child { border-top: 0; }
.field .top { display: flex; align-items: center; gap: 0.6rem; }
.field .name { font-size: 0.875rem; font-weight: 500; }
.field .val { margin-left: auto; font-family: var(--mono);
              font-variant-numeric: tabular-nums; font-size: 0.875rem; }
.field .src { font-size: 0.75rem; color: var(--text-mute); }
.field .src .flag { color: var(--state-review); font-weight: 550; }
/* The official page a statutory figure was read from. Underlined rather than
   accented: it is provenance, not an action being offered. */
.field .src .src-link { text-decoration: underline; text-underline-offset: 2px;
                        text-decoration-color: color-mix(in oklch, var(--text-mute) 55%, transparent);
                        white-space: nowrap; }
.field .src .src-link:hover { color: var(--text); }
.caveat .flag { color: var(--state-review); font-weight: 550; }

/* ---- empty state ------------------------------------------------------- */
.empty { padding: 2.6rem 1.5rem; text-align: center; }
.empty svg { width: 26px; height: 26px; color: var(--text-mute); opacity: 0.7; }
.empty p { margin: 0.85rem auto 0; max-width: 40ch; font-size: 0.875rem;
           color: var(--text-mute); line-height: 1.6; }
/* An empty state that names the likely cause should also undo it. */
.empty .out { display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: center;
              margin-top: 1.15rem; }
.empty .out .btn { flex: 0 1 auto; }

/* ---- sign in ----------------------------------------------------------- */
.gate { min-height: 100vh; display: grid; place-items: center; padding: 1.5rem; }
.gate form { width: min(24rem, 100%); padding: 2rem 1.8rem 1.6rem; display: grid;
             gap: 0.85rem; text-align: center; }
.gate .mark { width: 34px; height: 34px; margin: 0 auto 0.2rem; display: block;
              color: var(--metal); }
.gate h1 { margin: 0; font-family: var(--serif); font-size: 1.5625rem;
           font-weight: 500; letter-spacing: 0.01em; }
.gate .strap { margin: 0; font-size: 0.6875rem; text-transform: uppercase;
               letter-spacing: 0.13em; color: var(--text-mute); font-weight: 540; }
.gate p { margin: 0; font-size: 0.8125rem; color: var(--text-mute); }
.gate .census { margin-top: 0.5rem; font-family: var(--mono); font-size: 0.6875rem; }
.gate input {
  min-height: 44px; padding: 0.55rem 0.7rem; border-radius: 8px; font: inherit;
  text-align: center;
  color: var(--text); border: 1px solid var(--border);
  background: color-mix(in oklch, var(--surface) 55%, transparent);
}
.gate input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.gate .bad { color: var(--state-fail); }
.gate .pw { position: relative; display: grid; }
.gate .pw input { padding-right: 2.6rem; }
.gate .pw-eye {
  position: absolute; right: 0.35rem; top: 50%; transform: translateY(-50%);
  width: 36px; height: 36px; display: grid; place-items: center;
  background: none; border: 0; border-radius: 7px; cursor: pointer;
  color: var(--text-mute); transition: color 160ms var(--ease);
}
.gate .pw-eye:hover { color: var(--text); }
.gate .pw-eye:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.gate .pw-eye svg { width: 19px; height: 19px; display: block; }
.gate .pw-eye .strike { display: none; }
.gate .pw-eye[aria-pressed="true"] .strike { display: block; }
.gate .pw-match { min-height: 1.1em; font-size: 0.8125rem; margin: -0.3rem 0 0; }
.gate .pw-match.ok { color: var(--state-pass); }
.gate .pw-match.no { color: var(--state-fail); }

/* ---- desk layout ------------------------------------------------------- */
.rent-stage > .col-detail { display: none; }
@media (min-width: 900px) {
  body { padding-bottom: 1.5rem; }
  .split { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
           gap: 1.1rem; align-items: start; }
  /* The panel is taller than the viewport, so pinning its top alone put the only
     action on it 327px below the fold, first reachable after 12 000px of list
     scroll. It scrolls itself instead. */
  .split .col-detail {
    display: block;
    position: sticky; top: calc(var(--header-h, 4.5rem) + 0.4rem);
    /* The nav sits in the flow above this panel, so before the page is scrolled
       the panel starts below it. Sizing against the header alone left the last
       17px of the panel under the fold at rest. */
    max-height: calc(100dvh - var(--header-h, 4.5rem) - var(--nav-flow-h, 2.5rem) - 1.6rem);
    overflow-y: auto; overscroll-behavior: contain;
  }
  nav.bar { position: static; width: max-content;
            background: color-mix(in oklch, var(--surface) 20%, transparent);
            backdrop-filter: blur(var(--glass-blur)) saturate(1.5);
            -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.5);
            border: 1px solid color-mix(in oklch, var(--border) 52%, transparent);
            grid-template-columns: repeat(6, max-content); gap: 0.3rem;
            padding: 0.3rem; margin-bottom: 0.55rem; }
  nav.bar a { padding: 0.5rem 0.85rem; }
  /* The peer routes join the tab row; Model's internals do not. */
  nav.bar a.nav-peer { display: flex; }
  nav.bar span.nav-peer { display: none; }
  .desk-hide { display: none; }
}

/* ---- the rail -----------------------------------------------------------
   The reference's left navigation, taken at the width where it pays for
   itself rather than at the width where the two-column split starts: a 13.5rem
   rail out of 900px would leave the detail pane about 330px, which is narrower
   than the figures it carries.

   It must re-assert what the block above clears - that rule turns the nav into
   a static row of tabs, and being later in the file it wins on source order
   whatever this one asks for otherwise. Below 900px the bar stays across the
   foot, where a thumb reaches it. */
@media (min-width: 1100px) {
  nav.bar {
    --nav-mode: rail;
    position: fixed; top: calc(var(--header-h, 4.5rem) + 1.5rem);
    bottom: 0.75rem; left: 0.75rem; right: auto;
    width: 13.25rem; display: flex; flex-direction: column; gap: 0.15rem;
    padding: 1.1rem 0.75rem;
    background: color-mix(in oklch, var(--surface) 22%, transparent);
    backdrop-filter: blur(var(--glass-blur)) saturate(1.5);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.5);
    border: 1px solid color-mix(in oklch, var(--border) 58%, transparent);
    border-radius: 10px; box-shadow: var(--shadow);
  }
  nav.bar a { justify-content: flex-start; text-align: left;
              padding: 0.55rem 0.7rem; min-height: 40px; font-size: 0.8125rem; }
  /* Only the rail has room for the second rank. In the tab shape between 900
     and 1100px nine tabs is the crowding this redesign removed, so there the
     four are reached from the Model page, which lists them. */
  nav.bar .nav-secondary,
  nav.bar .nav-peer { display: flex; }
  nav.bar span.nav-secondary,
  nav.bar span.nav-peer { display: block; }
  nav.bar a.nav-secondary { font-size: 0.78125rem; min-height: 34px;
                            padding-top: 0.4rem; padding-bottom: 0.4rem;
                            color: color-mix(in oklch, var(--text-mute) 88%, transparent); }
  nav.bar a.nav-secondary[aria-current="page"] { color: var(--accent); }
  /* Peer routes read at full strength - they are not a lesser rank, only a
     later one. */
  nav.bar a.nav-peer { font-size: 0.8125rem; min-height: 40px; }
  /* The counts sit at the rail's far edge, where a column of them lines up and
     can be read down rather than hunted for. */
  nav.bar .n { margin-left: auto; }
  main { padding-left: calc(14rem + clamp(0.75rem, 3vw, 1.6rem));
         max-width: calc(1300px + 14rem); }
}
@media (min-width: 1100px) and (prefers-reduced-transparency: reduce) {
  nav.bar { background: var(--surface); backdrop-filter: none;
            -webkit-backdrop-filter: none; }
}

@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }

/* ---- filters ------------------------------------------------------------ */
.filters { margin-top: 0.4rem; }
.filters > summary {
  list-style: none; cursor: pointer; padding: 0.75rem 1rem;
  display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap;
  font-size: 0.875rem; font-weight: 550; min-height: 44px;
}
.filters > summary::-webkit-details-marker { display: none; }
.filters > summary::after {
  content: "▾"; color: var(--text-mute); font-size: 0.8125rem;
  transition: transform 180ms var(--ease);
}
.filters[open] > summary::after { transform: rotate(180deg); }
.filters > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px;
                                   border-radius: 10px; }
.filters .on { font-size: 0.6875rem; font-weight: 580; letter-spacing: 0.04em;
               text-transform: uppercase; color: var(--accent);
               background: var(--accent-dim); padding: 0.15rem 0.45rem; border-radius: 6px; }
.filters .off { font-size: 0.75rem; font-weight: 400; color: var(--text-mute); }
.filters .hits { margin-left: auto; font-family: var(--mono);
                 font-variant-numeric: tabular-nums; font-size: 0.8125rem;
                 font-weight: 400; color: var(--text-mute); }

.filters form {
  display: grid; gap: 0.7rem 0.9rem; padding: 0.2rem 1rem 1.1rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  border-top: 1px solid color-mix(in oklch, var(--border) 30%, transparent);
  padding-top: 0.9rem;
}
.filters label, .filters fieldset { display: grid; gap: 0.25rem; margin: 0; padding: 0; border: 0; }
.filters .wide { grid-column: 1 / -1; }
.filters label > span, .filters legend {
  font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--text-mute); font-weight: 560; padding: 0;
}
.filters fieldset { grid-template-columns: 1fr auto 1fr; align-items: center; gap: 0.25rem 0.4rem; }
.filters fieldset legend { grid-column: 1 / -1; }
.filters .to { font-size: 0.75rem; color: var(--text-mute); }

.filters input, .filters select {
  min-height: 42px; padding: 0.4rem 0.6rem; border-radius: 8px; font: inherit;
  font-size: 0.875rem; color: var(--text); width: 100%;
  border: 1px solid var(--border);
  background: color-mix(in oklch, var(--surface) 60%, transparent);
}
.filters input[type="number"] { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.filters input:focus-visible, .filters select:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent);
}
.filters .buttons { grid-column: 1 / -1; display: flex; gap: 0.5rem; flex-wrap: wrap;
                    margin-top: 0.2rem; }
.filters .buttons .btn { flex: 1 1 8rem; text-decoration: none; }

/* The walk-away price. The one number that answers "what is the most I should
   bid", so it is set apart from the tables rather than filed inside one. */
.walkaway { margin: 1.1rem 0 0; padding: 1rem 1.15rem; border-radius: 10px;
            background: color-mix(in oklch, var(--accent) 8%, transparent);
            border: 1px solid color-mix(in oklch, var(--accent) 30%, transparent); }
.walkaway .lbl { display: block; font-size: 0.6875rem; text-transform: uppercase;
                 letter-spacing: 0.13em; font-weight: 540; color: var(--text-mute); }
.walkaway b { display: block; font-family: var(--serif);
              font-variant-numeric: lining-nums tabular-nums;
              font-size: 2.4rem; font-weight: 500; letter-spacing: 0;
              margin-top: 0.15rem; }
.walkaway .why { display: block; margin-top: 0.35rem; font-size: 0.75rem;
                 line-height: 1.5; color: var(--text-mute); max-width: 56ch; }

/* Nearby auctions. Deliberately quieter than a ranked row and never laid out
   like one: these carry no modelled figure, so a reader must not be able to
   mistake one for a listing that does. */
.filters .check { grid-template-columns: auto 1fr; align-items: center; gap: 0.5rem; }
.filters .check input { width: auto; min-height: 0; }
.filters .check > span { text-transform: none; letter-spacing: 0; font-size: 0.8125rem; }

.nearby { margin-top: 1rem; }
.nearby .group {
  font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--text-mute); font-weight: 560;
  padding: 0.7rem 0.9rem 0.2rem;
}
.near-row { padding: 0.35rem 0.9rem 0.55rem; border-top: 1px solid color-mix(in oklch, var(--border) 40%, transparent); }
.near-row a { font-size: 0.875rem; }
.near-row .d { display: block; font-size: 0.8125rem; color: var(--text-mute); }
.near-row .num { font-family: var(--mono); font-size: 0.75rem; color: var(--text-mute); }

/* The second look, on the shortlist only. Quieter than a ranked row: it is
   corroboration for a figure already on the page, not a figure of its own. */
.deep .deep-row { padding: 0.6rem 0.9rem 0.7rem; border-top: 1px solid color-mix(in oklch, var(--border) 40%, transparent); }
.deep .deep-ref { font-size: 0.875rem; font-weight: 560; margin-bottom: 0.2rem; }
.deep .d { font-size: 0.8125rem; color: var(--text-mute); line-height: 1.5; }
.deep .d b { color: var(--text); font-weight: 560; }
.deep .d i { font-style: italic; }

/* ---- E5 hygiene ---------------------------------------------------------- */
/* One property, more than one notice. Stated on the row rather than resolved
   silently, because the other notice still exists and is still reachable. */
.meta .chip-dup { font-family: var(--mono); font-size: 0.6875rem;
                  padding: 0.05rem 0.35rem; border-radius: 4px;
                  border: 1px solid color-mix(in oklch, var(--border) 80%, transparent); }
/* Quarantine and Band C share this one bucket. Review-coloured, never alarm:
   a figure we cannot stand behind is an ordinary outcome, not an error. */
.needs { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.35rem;
         margin-top: 0.45rem; font-size: 0.75rem; }
.needs b { color: var(--state-review); font-weight: 560; }
.needs i { font-style: normal; color: var(--text-mute); }

/* E4. A control that cannot answer yet says so rather than pretending. */
.check.off { opacity: 0.55; }
.check.off input { cursor: not-allowed; }

/* E3. Keep / dismiss on an insight card, and how a verdict reads afterwards.
   The controls sit beside the star and stay quiet: the judgment is the
   operator's, the page only records it. A dismissed row dims rather than
   disappears - hiding it would un-measure the very precision the verdict
   exists to feed. */
.review { display: flex; flex-direction: column; align-items: flex-end;
          justify-content: center; gap: 0.3rem; padding: 0.55rem 0.5rem 0.55rem 0; }
.review .review-btn { font-size: 0.6875rem; padding: 0.18rem 0.55rem;
                      line-height: 1.2; cursor: pointer; }
.chip-review { font-family: var(--mono); font-size: 0.6875rem;
               padding: 0.05rem 0.35rem; border-radius: 4px;
               border: 1px solid color-mix(in oklch, var(--border) 80%, transparent);
               white-space: nowrap; }
.chip-review.keep { color: var(--state-pass);
                    border-color: color-mix(in oklch, var(--state-pass) 45%, transparent); }
.chip-review.dismiss { color: var(--text-mute); }
.review-dismiss { position: relative; }
.review-dismiss summary { list-style: none; display: inline-block; }
.review-dismiss summary::-webkit-details-marker { display: none; }
.review-dismiss[open] form { display: flex; gap: 0.3rem; margin-top: 0.3rem;
                             align-items: center; }
.review-dismiss input[type="text"] { font-size: 0.75rem; padding: 0.2rem 0.4rem;
                                     width: 13rem; max-width: 40vw; }
.row.reviewed-dismissed { opacity: 0.55; }
.row.reviewed-dismissed:hover { opacity: 0.9; }

/* A listing created long before the census around it, by the source's own id
   sequence. Metal-toned, not alarm-toned: staleness is a fact to weigh, not a
   defect - fatigue and adverse selection wear the same chip. */
/* Not scoped to `.meta` any more. These chips also sit in the Attend page's
   session lines and in the report's header row, where the descendant selector
   never reached them - so "late high", "3 bonds" and the demand read have
   been rendering there as bare text run together with the listing ref. The
   rule carries its own font and size, so it does not depend on the container
   it lost. */
.chip-longlist, .chip-fact {
  font-family: var(--mono); font-size: 0.6875rem;
  padding: 0.05rem 0.35rem; border-radius: 4px;
  color: var(--metal);
  border: 1px solid color-mix(in oklch, var(--metal) 55%, transparent); }

/* D61 demand. The bottom tier reads at full strength and the rest sit back:
   a suburb with standing stock and no sales is the strongest evidence this
   model holds, and it should not look identical to one that sells in a
   quarter. Definiteness, not colour - demand introduces no red state
   (DEMAND_MODEL_SPEC section 5) and this workspace uses no urgency colour,
   so the distinction is border weight and letter-spacing, which survives
   both themes and colour-blind vision without borrowing the reject token. */
.chip-fact[data-demand="no-exit"] {
  color: color-mix(in oklch, var(--metal) 80%, var(--ink));
  border-color: color-mix(in oklch, var(--metal) 90%, transparent);
  letter-spacing: 0.01em; }
.chip-fact[data-demand="absorbing"],
.chip-fact[data-demand="steady"] {
  border-color: color-mix(in oklch, var(--metal) 35%, transparent); }
/* Every other form the read takes - the labelled figure on the rows, the
   detail page's block - carries the same distinction. Scoped to the attribute
   rather than to each container, because the labelled form was introduced on
   three surfaces at once and inherited none of it: no-exit and steady set the
   same figure in the same weight, which is the one pair this model exists to
   tell apart. */
[data-demand="no-exit"] { letter-spacing: 0.01em; }

/* The archived page's outcome form. It carried no layout rule of its own: as
   three fields it happened to sit on one line, and when D63 added price kind
   and source it began wrapping mid-label - "Price kind &middot;" on one line
   and "required with a price" on the next, reading as two broken sentences
   rather than one instruction. A grid fixes it at both sizes this product is
   used at: one column on the phone, where an outcome gets written down
   standing outside a courthouse, two from 40rem at the desk. The button
   takes its own row so it is never mistaken for another field. */
form.outcome { display: grid; grid-template-columns: 1fr; gap: 0.7rem 1rem; }
form.outcome label { display: flex; flex-direction: column; gap: 0.25rem;
  min-width: 0; }
form.outcome label > span {
  font-size: 0.75rem; line-height: 1.35; color: var(--text-mute);
  text-wrap: pretty; }
form.outcome input, form.outcome select { width: 100%; min-width: 0; }
form.outcome button { justify-self: start; }
@media (min-width: 40rem) {
  form.outcome { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  form.outcome button { grid-column: 1 / -1; } }

/* ---- 2026 workspace redesign ------------------------------------------
   The supplied dashboard reference contributes its compact rail, strong data
   hierarchy and precise dark surfaces. Property Intel keeps its own evidence
   semantics: no decorative trends, no invented deltas and no urgency colour. */
:root {
  --chrome: color-mix(in oklch, var(--surface) 86%, var(--bg));
  --chrome-soft: color-mix(in oklch, var(--surface) 68%, transparent);
  --surface-strong: color-mix(in oklch, var(--surface) 32%, transparent);
  --hairline: color-mix(in oklch, var(--border) 62%, transparent);
  --rail-w: 13.75rem;
  --radius-sm: 7px;
  --radius-md: 11px;
}

/* The palette follows thecraftedpersona.com: pure-neutral greys and one teal.
   Its neutrals carry no chroma at all - #1B1B1B, #111111, #f0f0f0, #999 - where
   this theme had been cool-tinted at hue 220, and its accent #009999 sits a
   long way below the teal that was here (L 0.618 against 0.750). Both blocks
   above carry the same values; this is the one that renders, being the later
   of the two definitions. */
:root[data-theme="dark"] {
  --bg: oklch(0.178 0.000 0);
  --surface: oklch(0.222 0.000 0);
  --text: oklch(0.955 0.000 0);
  --text-mute: oklch(0.683 0.000 0);
  --border: oklch(0.440 0.000 0);
  /* The scrim was 0.90/0.77/0.89 over a photograph whose median luminance is
     1 of 255 - it was not dimming the picture, it was deleting it.
     The photograph now carries its own tone curve instead, lifted and capped
     at 110 of 255 - one below the value at which white body text stops
     passing AA against it - so contrast is guaranteed by the asset rather
     than bought back with an opaque veil. What is left here is a directional
     wash for depth, not a scrim. */
  --page-bg:
    linear-gradient(105deg, oklch(0.055 0.000 0 / 0.12), oklch(0.075 0.000 0 / 0.04) 48%, oklch(0.055 0.000 0 / 0.10)),
    var(--page-photo);
  --shadow: 0 1px 1px oklch(0.035 0.000 0 / 0.55),
            0 18px 46px oklch(0.035 0.000 0 / 0.28);
}

:root[data-theme="light"] {
  --page-bg:
    linear-gradient(105deg, oklch(0.965 0.000 0 / 0.94), oklch(0.955 0.000 0 / 0.90)),
    var(--page-photo);
  --shadow: 0 1px 2px oklch(0.250 0.000 0 / 0.06),
            0 16px 38px oklch(0.250 0.000 0 / 0.08);
}

body {
  background-position: center;
  line-height: 1.45;
}

/* A 1536x1024 photograph cropped to a 390-wide portrait viewport shows about
   a third of its width, and centred that third is the unlit gap between the
   figure and the desk - which is why the background read as absent on a phone
   while being visible on a desktop. Biased left so the crop lands on the
   shoulder and collar, the one part of the picture that carries light. */
@media (max-width: 720px) {
  body { background-position: 30% center; }
}

/* Frosting removed. `backdrop-filter` is what "frosted" means here, and the
   82% fill under it meant a card was very nearly opaque - so the picture was
   being pushed brighter underneath surfaces that were never going to let it
   through. The brightness lever is given back to the photograph (its ceiling
   drops 110 -> 95, because text now sits on it across most of the page rather
   than only in the gutters) and the cards open instead: no blur, and a fill
   low enough to read through while still giving a card an edge and a body.
   Dropping the blur also drops one compositing layer per card, which is the
   part of this that cost most on a phone. */
.panel {
  background: var(--surface-strong);
  border-color: var(--hairline);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* Compact command bar. The context is useful on desk widths, while the
   mobile bar keeps only brand and actions. */
header.app-header {
  top: 0.625rem;
  left: 0.625rem;
  right: 0.625rem;
  min-height: 3.625rem;
  padding: 0.55rem 0.75rem 0.55rem 1rem;
  gap: 0.75rem;
  flex-wrap: nowrap;
  border-radius: var(--radius-md);
  background: color-mix(in oklch, var(--chrome) 94%, transparent);
  border-color: var(--hairline);
}

.header-context {
  display: none;
  min-width: 0;
  line-height: 1.15;
}

.header-context > span { display: block; }
.context-kicker {
  color: var(--text-mute);
  font-size: 0.625rem;
  font-weight: 650;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.context-title { margin-top: 0.2rem; font-size: 0.8125rem; font-weight: 580; }

.header-status {
  display: none;
  align-items: center;
  gap: 0.45rem;
  margin-left: auto;
  color: var(--text-mute);
  font-family: var(--mono);
  font-size: 0.6875rem;
  white-space: nowrap;
}

.status-dot {
  width: 0.42rem;
  height: 0.42rem;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--state-pass);
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--state-pass) 14%, transparent);
}

#themer { margin-left: auto; }
.iconbtn {
  min-height: 36px;
  padding: 0.4rem 0.7rem;
  border-radius: var(--radius-sm);
  background: color-mix(in oklch, var(--surface) 72%, transparent);
  border-color: var(--hairline);
  color: var(--text-mute);
  font-size: 0.6875rem;
  font-weight: 560;
}
.iconbtn:hover {
  background: color-mix(in oklch, var(--surface) 94%, transparent);
  color: var(--text);
}

.rail-brand, .nav-section, .rail-meta { display: none; }
.nav-icon {
  width: 1.05rem;
  height: 1.05rem;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  font-family: var(--mono);
  font-size: 0.95rem;
  font-weight: 500;
  line-height: 1;
}
.icon-ranked::before { content: "≡"; }
.icon-insights::before { content: "⌁"; }
.icon-rent::before { content: "⌂"; }
.icon-favourites::before { content: "☆"; }
.icon-queue::before { content: "□"; }
.icon-report::before { content: "▤"; }
.icon-sources::before { content: "⌕"; }
.icon-bank::before { content: "▨"; }
/* Demand: the way out. Every other glyph here names a thing, this one names
   a direction, which is what the route is about. */
.icon-demand::before { content: "⇄"; }
.icon-archive::before { content: "▣"; }
.icon-assumptions::before { content: "⌘"; }
/* Today is the only door that names a time rather than a thing, so it takes
   the only glyph here that is a clock. Model is the section mark; health is
   the trace, because what that page shows is a signal over time. */
.icon-today::before { content: "◷"; }
.icon-model::before { content: "⊞"; }
.icon-health::before { content: "∿"; }

nav.bar {
  border-radius: var(--radius-md);
  background: color-mix(in oklch, var(--chrome) 94%, transparent);
  border-color: var(--hairline);
}

nav.bar a { position: relative; }
nav.bar a[aria-current="page"] {
  color: var(--accent);
  background: color-mix(in oklch, var(--accent) 12%, transparent);
}

main {
  max-width: 1470px;
  padding-top: calc(var(--header-h, 4.5rem) + 1.25rem);
}

/* One compact ledger on the ranked workspace. Each number remains a link into
   the exact set it counts without becoming a row of dashboard hero cards. */
.census-strip {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0;
  margin: 0.15rem 0 0.7rem;
  background: var(--surface-strong);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
}

.census-strip .stat {
  min-height: 2.9rem;
  flex-direction: row;
  justify-content: flex-start;
  align-items: baseline;
  gap: 0.45rem;
  padding: 0.62rem 0.75rem;
  background: transparent;
  border-left: 1px solid var(--hairline);
  transition: background 180ms var(--ease);
}
.census-strip .stat:first-child { border-left: 0; }

.census-strip .stat:hover {
  background: color-mix(in oklch, var(--accent) 6%, transparent);
}

.census-strip .n {
  font-size: 1.05rem;
  font-weight: 620;
  line-height: 1;
}
.census-strip .l {
  margin-top: 0;
  font-size: 0.6875rem;
  letter-spacing: 0;
  text-transform: none;
}

.workspace-intro {
  padding: 0.55rem 0 0.75rem;
  max-width: 60ch;
}
.workspace-intro .workspace-kicker {
  margin: 0 0 0.35rem;
  color: var(--accent);
  font-size: 0.6875rem;
  font-weight: 650;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}
.workspace-intro h1 {
  margin: 0;
  font-family: var(--serif);
  font-size: 1.72rem;
  font-weight: 500;
  letter-spacing: -0.012em;
  line-height: 1.15;
}
.workspace-intro > p:last-child {
  margin: 0.4rem 0 0;
  color: var(--text-mute);
  font-size: 0.8125rem;
  line-height: 1.5;
}

.filters { margin-top: 0.15rem; box-shadow: none; }
.filters > summary { padding: 0.7rem 0.9rem; }
.sheet { background: var(--surface-strong); }
.uniform { background: color-mix(in oklch, var(--text) 3%, transparent); }
.row { border-color: color-mix(in oklch, var(--border) 40%, transparent); }
.row:hover { background: color-mix(in oklch, var(--accent) 5%, transparent); }
.row[aria-selected="true"] {
  background: color-mix(in oklch, var(--accent) 8%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in oklch, var(--accent) 28%, transparent);
}
.row.factor-row.preference-reject,
.row.source-row.preference-reject,
.row.factor-row.preference-reject:hover,
.row.source-row.preference-reject:hover {
  box-shadow: inset 0 0 0 1px color-mix(in oklch, var(--state-fail) 34%, transparent);
}
.rowmain { padding-top: 0.78rem; padding-bottom: 0.82rem; }
.addr { font-weight: 590; }
.rank { font-size: 0.75rem; }
.detail { background: transparent; }
.detail h2 { font-size: 1.48rem; }
.col-detail > .detail { border-color: color-mix(in oklch, var(--border) 70%, transparent); }
.caveat { background: color-mix(in oklch, var(--surface) 76%, transparent); }

.btn {
  border-radius: var(--radius-sm);
  font-weight: 570;
}

.badge, .chip { border-radius: 5px; }
.insight-tabs { background: var(--surface-strong); border-radius: var(--radius-md); }

/* On a phone the listing opens its own detail route. Leaving the desk inspector
   after hundreds of rows duplicates the entire decision surface off-screen. */
@media (max-width: 899px) {
  .split > .col-detail { display: none; }
}

@media (min-width: 700px) {
  .header-context { display: block; }
  .header-status { display: inline-flex; }
  #themer { margin-left: 0; }
}

@media (min-width: 900px) and (max-width: 1099px) {
  nav.bar {
    width: 100%;
    grid-template-columns: repeat(9, minmax(0, 1fr));
  }
  nav.bar a { justify-content: center; }
  .split { gap: 0.8rem; }
}

@media (min-width: 1100px) {
  header.app-header {
    left: calc(var(--rail-w) + 1.25rem);
    padding-left: 1.1rem;
  }
  .header-wordmark { display: none; }
  .header-context { display: block; }
  header.pl-header { display: none; }
  .pl-platform main { padding-top: 1.75rem; }

  nav.bar {
    top: 0.625rem;
    bottom: 0.625rem;
    left: 0.625rem;
    width: var(--rail-w);
    padding: 0.7rem;
    gap: 0.15rem;
    background: color-mix(in oklch, var(--chrome) 96%, transparent);
  }

  .rail-brand {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    padding: 0.45rem 0.55rem 1.15rem;
    color: var(--metal);
  }
  .rail-brand .mark { width: 1.45rem; height: 1.45rem; flex: 0 0 auto; }
  .rail-brand > span { min-width: 0; }
  .rail-brand b {
    display: block;
    color: var(--text);
    font-family: var(--serif);
    font-size: 1rem;
    font-weight: 500;
    line-height: 1.15;
  }
  .rail-brand small {
    display: block;
    margin-top: 0.2rem;
    color: var(--text-mute);
    font-size: 0.6rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
  }

  .nav-section {
    display: block;
    padding: 0.65rem 0.65rem 0.28rem;
    color: color-mix(in oklch, var(--text-mute) 78%, transparent);
    font-size: 0.59rem;
    font-weight: 650;
    letter-spacing: 0.13em;
    text-transform: uppercase;
  }
  .nav-section-model { margin-top: 0.5rem; }

  nav.bar a {
    justify-content: flex-start;
    min-height: 40px;
    padding: 0.58rem 0.65rem;
    gap: 0.65rem;
    border-radius: var(--radius-sm);
    font-size: 0.78125rem;
    font-weight: 520;
  }
  nav.bar a[aria-current="page"] { font-weight: 620; }
  nav.bar .n {
    margin-left: auto;
    min-width: 1.3rem;
    padding: 0.05rem 0.28rem;
    text-align: center;
    border-radius: 999px;
    background: color-mix(in oklch, var(--text) 7%, transparent);
  }

  .rail-meta {
    display: grid;
    gap: 0.25rem;
    margin-top: auto;
    padding: 0.75rem 0.65rem 0.35rem;
    border-top: 1px solid var(--hairline);
    color: var(--text-mute);
    font-size: 0.65rem;
    line-height: 1.35;
  }
  .rail-meta > span { display: flex; align-items: center; gap: 0.45rem; }
  .rail-meta .status-dot { width: 0.34rem; height: 0.34rem; }
  .rail-meta small { font-family: var(--mono); font-size: 0.625rem; }

  main {
    width: auto;
    max-width: none;
    margin: 0;
    padding-left: calc(var(--rail-w) + 1.25rem);
    padding-right: 0.8rem;
  }
  .split { grid-template-columns: minmax(28rem, 0.92fr) minmax(29rem, 1.08fr); gap: 0.8rem; }
  .split .col-detail { top: calc(var(--header-h, 4.5rem) + 0.65rem); }
  .insights-page { width: min(100%, 82rem); }
}

@media (max-width: 699px) {
  body { background-attachment: scroll; }
  header.app-header { min-height: 3.55rem; }
  .header-wordmark { font-size: 1rem; }
  .header-wordmark .mark { width: 18px; height: 18px; }
  main { padding-top: calc(var(--header-h, 4.5rem) + 1rem); }
  .census-strip { gap: 0; margin-bottom: 0.7rem;
                  grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .census-strip .stat { min-height: 2.9rem; padding: 0.6rem 0.7rem; }
  .census-strip .stat:nth-child(odd) { border-left: 0; }
  .census-strip .stat:nth-child(n+3) { border-top: 1px solid var(--hairline); }
  .census-strip .n { font-size: 1rem; }
  .workspace-intro { padding-top: 0.45rem; }
  .workspace-intro h1 { font-size: 1.5rem; }

  nav.bar {
    padding-top: 0.3rem;
    padding-bottom: calc(0.3rem + env(safe-area-inset-bottom));
  }
  nav.bar a {
    min-height: 50px;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.35rem 0.05rem;
    line-height: 1;
  }
  nav.bar .nav-icon { width: 1rem; height: 1rem; }
  nav.bar .n {
    position: absolute;
    top: 0.12rem;
    right: 0.18rem;
    min-width: 1rem;
    padding: 0.08rem 0.2rem;
    border-radius: 999px;
    background: var(--accent-dim);
    font-size: 0.58rem;
  }
}

@media (max-width: 390px) {
  nav.bar a { font-size: 0.64rem; }
  .census-strip .l { letter-spacing: 0; font-size: 0.625rem; }
}

/* ---- one-property report (D45) ------------------------------------------ */
/* Infographic-first: marks carry the data, tables carry the numbers, text
   tokens carry every label. Chart identities come from --chart-1 (gold, the
   bid) and --chart-2 (teal, the market), validated per mode; status colors
   stay reserved for verdicts. */
.report { display: grid; gap: 1rem; max-width: 62rem; margin: 0 auto; }
.report .stage-head { margin-bottom: 0; }
.report-sub { margin: 0.1rem 0 0; color: var(--text-mute); }
.report-logistics { margin: 0.6rem 0 0; font-family: var(--mono);
                    font-size: 0.8125rem; color: var(--text-mute); }
.report-block { padding: 1.1rem 1.25rem 1.2rem; }
.report-grid { display: grid; gap: 1rem; }
@media (min-width: 800px) { .report-grid { grid-template-columns: 1fr 1fr; } }

.kpis { display: grid; gap: 0.7rem; grid-template-columns: repeat(2, 1fr); }
@media (min-width: 800px) { .kpis { grid-template-columns: repeat(4, 1fr); } }
.kpi { padding: 0.85rem 1rem 0.9rem; display: grid; gap: 0.15rem; }
.kpi-label { font-size: 0.6875rem; text-transform: uppercase;
             letter-spacing: 0.1em; color: var(--text-mute); }
.kpi-value { font-family: var(--mono); font-size: 1.375rem; }
.kpi-foot { font-size: 0.75rem; color: var(--text-mute); }

.ladder { margin: 0.9rem 0 0.4rem; }
.ladder-track { position: relative; height: 26px; border-radius: 7px;
                background: color-mix(in oklch, var(--text) 6%, transparent); }
.ladder-band { position: absolute; top: 4px; bottom: 4px; min-width: 4px;
               background: var(--chart-1); border-radius: 0 4px 4px 0; }
.ladder-tick { position: absolute; top: -4px; bottom: -4px; width: 2px;
               background: var(--text); }
.ladder-tick.walk { background: var(--text); }
.ladder-tick.allin { background: var(--text-mute); opacity: 0.7; }
.ladder-dot { position: absolute; top: 50%; width: 12px; height: 12px;
              transform: translate(-50%, -50%); border-radius: 50%;
              background: var(--chart-2); box-shadow: 0 0 0 2px var(--surface); }

.report-table { width: 100%; border-collapse: collapse; margin-top: 0.55rem;
                font-size: 0.8125rem; }
.report-table td { padding: 0.28rem 0; border-top: 1px solid
                   color-mix(in oklch, var(--border) 45%, transparent); }
.report-table td.num { text-align: right; font-family: var(--mono); }
.report-table tr.total td { border-top-width: 2px; }
.swatch { display: inline-block; width: 10px; height: 10px; margin-right: 0.5rem;
          border-radius: 3px; background: var(--text-mute); vertical-align: -1px; }
.swatch.c1 { background: var(--chart-1); }
.swatch.c2 { background: var(--chart-2); }
.swatch.round { border-radius: 50%; }
.swatch.tick { width: 3px; height: 12px; border-radius: 1px; background: var(--text); }
.swatch.tick.walkline { background: var(--text); }

.stackbar { display: flex; gap: 2px; height: 18px; margin-top: 0.8rem;
            border-radius: 5px; overflow: hidden; background: var(--surface); }
.stackbar .seg { min-width: 4px; }
.stackbar .seg.c1 { background: var(--chart-1); }
.stackbar .seg.c2 { background: var(--chart-2); }

.minibars { display: grid; gap: 0.4rem; margin-top: 0.8rem; }
.minibar-row { display: grid; grid-template-columns: 9.5rem 1fr auto;
               gap: 0.6rem; align-items: center; font-size: 0.78125rem; }
.minibar-name { color: var(--text-mute); }
.minibar-track { position: relative; height: 12px; border-radius: 4px;
                 background: color-mix(in oklch, var(--text) 6%, transparent); }
.minibar { position: absolute; inset: 2px auto 2px 0; min-width: 3px;
           border-radius: 0 3px 3px 0; }
.minibar.c2 { background: var(--chart-2); }
.minibar-val { font-family: var(--mono); color: var(--text-mute); }

.dumbbell-row { display: grid; grid-template-columns: 9.5rem 1fr auto;
                gap: 0.6rem; align-items: center; font-size: 0.78125rem;
                margin-top: 0.5rem; }
.dumbbell-name { color: var(--text-mute); }
.dumbbell-track { position: relative; height: 12px; border-radius: 4px;
                  background: color-mix(in oklch, var(--text) 6%, transparent); }
.dumbbell { position: absolute; top: 2px; bottom: 2px; min-width: 4px;
            border-radius: 0 3px 3px 0; }
.dumbbell.c2 { background: var(--chart-2); }
.dumbbell-base { position: absolute; top: -3px; bottom: -3px; width: 2px;
                 background: var(--chart-1); }
.dumbbell-val { font-family: var(--mono); color: var(--text-mute); }

.verdicts { display: flex; flex-wrap: wrap; gap: 0.45rem; margin-top: 0.5rem; }

.report-plot { width: 100%; height: auto; margin-top: 0.6rem; }
.plot-axis { stroke: color-mix(in oklch, var(--text) 22%, transparent);
             stroke-width: 1; }
.plot-valueline { stroke: var(--chart-1); stroke-width: 2;
                  stroke-linecap: round; }
.plot-line { stroke: var(--chart-2); stroke-width: 2; fill: none;
             stroke-linecap: round; stroke-linejoin: round; }
.plot-dot { fill: var(--chart-2); stroke: var(--surface); stroke-width: 2; }
.plot-label { fill: var(--text-mute); font-family: var(--mono);
              font-size: 11.5px; }

.area-tiles { display: grid; gap: 0.7rem; grid-template-columns: repeat(3, 1fr);
              margin-top: 0.6rem; }
.area-tile { display: grid; gap: 0.1rem; }
.area-tile b { font-family: var(--mono); font-size: 1.125rem; font-weight: 500; }
.area-tile span { font-size: 0.71875rem; color: var(--text-mute); }

.report-note { margin: 0.7rem 0 0; font-size: 0.75rem; color: var(--text-mute); }
.report-warnings { margin: 0.4rem 0 0; padding-left: 1.1rem;
                   font-size: 0.75rem; color: var(--text-mute); }
.report-warnings li { margin-top: 0.25rem; }
.report-actions { margin: 0.9rem 0 0; display: flex; gap: 0.6rem; }

@media print {
  :root, :root[data-theme="dark"] {
    color-scheme: light;
    --bg: #fff; --page-bg: #fff; --surface: #fff;
    --text: oklch(0.250 0.000 0); --text-mute: oklch(0.500 0.000 0);
    --border: oklch(0.880 0.000 0);
    --chart-1: #636363; --chart-2: #007c7c;
    --state-pass: oklch(0.520 0.110 195); --state-fail: oklch(0.620 0.000 0);
    --state-review: oklch(0.420 0.000 0);
    --glass-tint: 100%; --glass-blur: 0px; --shadow: none;
  }
  body { background: #fff; }
  header.bar, nav.bar, .report-actions, #themer { display: none !important; }
  .panel { border: 1px solid var(--border); box-shadow: none;
           backdrop-filter: none; break-inside: avoid; }
  .report { max-width: none; }
  * { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
}
.detail-nav { display: flex; justify-content: space-between; gap: 1rem; }
.report-pack { display: grid; gap: 1.4rem; max-width: 62rem; margin: 0 auto; }
.report-pack-item { border-top: 1px solid var(--border); padding-top: 1.4rem; }
@media print {
  .report-pack-item { border-top: 0; padding-top: 0; break-before: page; }
  .report-pack .stage-head { break-after: avoid; }
}
.auction-block { border-left: 3px solid var(--metal); }
.auction-tiles { display: grid; gap: 0.9rem; margin-top: 0.5rem; }
@media (min-width: 700px) { .auction-tiles { grid-template-columns: 1fr 1.1fr 1.4fr; } }
.auction-tile { display: grid; gap: 0.15rem; align-content: start; }
.auction-office { font-size: 1.0625rem; font-family: var(--sans); }
.mail-ok { color: var(--state-pass); }
.mail-bad { color: var(--state-fail); }
.mail-signup { display: inline-flex; gap: 0.5rem; }
.mail-signup input[type="email"] { min-height: 40px; padding: 0.4rem 0.65rem;
  border-radius: 7px; font: inherit; color: var(--text);
  border: 1px solid var(--border);
  background: color-mix(in oklch, var(--surface) 55%, transparent); }
@media print { .mail-signup { display: none; } }
.opps-scroll { overflow-x: auto; }
.opps-table { font-size: 0.78125rem; min-width: 46rem; }
.opps-table .opps-head td { color: var(--text-mute); text-transform: uppercase;
  font-size: 0.65625rem; letter-spacing: 0.09em; border-top: 0; }
.opps-table td { vertical-align: top; padding-right: 0.6rem; }
.opps-table .src { display: block; font-size: 0.71875rem; }

/* Demand insights open with the two decisions; methodology stays available
   without occupying the working viewport. */
.demand-intro {
  display: grid;
  gap: 0.8rem;
  padding: 0.35rem 0 0.55rem;
}
.demand-intro-copy { max-width: 62ch; }
.demand-intro .eyebrow { margin: 0.35rem 0; }
.demand-intro h1 {
  margin: 0;
  font-family: var(--serif);
  font-size: 1.55rem;
  font-weight: 500;
  line-height: 1.2;
}
.demand-intro-copy > p:last-child {
  margin: 0.65rem 0 0;
  color: var(--text-mute);
  font-size: 0.9rem;
  line-height: 1.55;
}
.demand-summary { border-top: 1px solid var(--hairline); }
.demand-summary a {
  display: grid;
  grid-template-columns: 2.6rem minmax(0, 1fr) auto;
  gap: 0.75rem;
  align-items: center;
  min-height: 3.8rem;
  border-bottom: 1px solid var(--hairline);
}
.demand-summary a:hover strong,
.demand-summary a:focus-visible strong { color: var(--accent); }
.demand-summary a:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.demand-summary-count {
  color: var(--text);
  font-family: var(--serif);
  font-size: 1.45rem;
  line-height: 1;
}
.demand-summary strong,
.demand-summary small { display: block; }
.demand-summary strong { color: var(--text); font-size: 0.875rem; font-weight: 600; }
.demand-summary small { margin-top: 0.1rem; color: var(--text-mute); font-size: 0.6875rem; }
.demand-summary-action { color: var(--accent); font-size: 0.6875rem; font-weight: 600; }
.demand-summary > p {
  margin: 0.55rem 0 0;
  color: var(--text-mute);
  font-size: 0.75rem;
  line-height: 1.45;
}
.demand-method { max-width: 62ch; color: var(--text-mute); font-size: 0.75rem; }
.demand-method summary {
  width: max-content;
  cursor: pointer;
  color: var(--text-mute);
  font-weight: 600;
}
.demand-method summary:hover { color: var(--text); }
.demand-method summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.demand-method p { margin: 0.5rem 0 0; line-height: 1.55; }

@media (min-width: 900px) {
  .demand-intro {
    grid-template-columns: minmax(0, 1fr) minmax(20rem, 0.72fr);
    column-gap: clamp(2rem, 5vw, 5rem);
    align-items: end;
  }
  .demand-method { grid-column: 1 / -1; }
}

/* D66 demand insights. The suburb is the row, so the row is a disclosure:
   the summary carries the exit read and the one listing worth naming, and
   what stands in the suburb opens underneath. `details` rather than a JS
   toggle because 131 of these render at once and the page must work with the
   script blocked - the same reason the filters use it. */
.demand-band + .demand-band, .demand-page .demand-foot { margin-top: 1rem; }
.demand-band h2, .demand-foot h2 { margin: 0.1rem 0 0.25rem;
  font-family: var(--serif); font-size: 1.15rem; font-weight: 560;
  letter-spacing: -0.01em; }
.band-standfirst { margin: 0 0 0.7rem; max-width: 62ch;
  font-size: 0.875rem; color: var(--text-mute); }
.demand-sheet { border-radius: 10px; overflow: hidden; }
.demand-suburb {
  border-top: 1px solid color-mix(in oklch, var(--border) 30%, transparent); }
.demand-suburb:first-child { border-top: 0; }
.demand-suburb > summary {
  display: flex; align-items: baseline; gap: 0.7rem; cursor: pointer;
  padding: 0.7rem 0.85rem 0.75rem;
  transition: background 160ms var(--ease); }
.demand-suburb > summary::-webkit-details-marker { display: none; }
.demand-suburb > summary::marker { content: ""; }
.demand-suburb > summary:hover {
  background: color-mix(in oklch, var(--accent) 5%, transparent); }
.demand-suburb > summary:focus-visible { outline: 2px solid var(--accent);
  outline-offset: -2px; border-radius: 10px; }
.demand-suburb .who { flex: 1 1 auto; min-width: 0; }
/* A suburb holding an auction listing is a decision this week; one holding
   only bank stock is background. The sort already puts them first - this is
   what makes that visible without a chip saying so. */
.demand-suburb[data-biddable] > summary {
  box-shadow: inset 3px 0 color-mix(in oklch, var(--accent) 70%, transparent); }
/* The opportunity line. The verdict clause is deliberately not styled as a
   warning colour: no-exit introduces no red state (DEMAND_MODEL_SPEC 5), and
   the sentence does the work. */
.demand-best { display: block; margin-top: 0.15rem; font-size: 0.8125rem;
  color: var(--text-mute); }
.demand-best b { color: var(--text); font-weight: 600; }
.demand-best i { font-style: normal; opacity: 0.85; }
.demand-best .ref, .demand-list .ref { font-family: var(--mono); }
.demand-suburb .place { color: var(--text-mute); font-weight: 400; }
.demand-held { padding: 0.1rem 0.85rem 0.9rem;
  background: color-mix(in oklch, var(--surface) 30%, transparent); }
.demand-held .eyebrow { margin: 0.55rem 0 0.25rem; }
.demand-list { margin: 0; padding-left: 1.05rem; display: grid; gap: 0.22rem;
  font-size: 0.8125rem; color: var(--text-mute); }
.demand-list b { color: var(--text); font-weight: 600; }
.demand-list .verdict { font-size: 0.6875rem; text-transform: uppercase;
  letter-spacing: 0.07em; }
.demand-foot p { max-width: 62ch; font-size: 0.875rem; color: var(--text-mute); }

/* D68. The exit read's absence, named. Deliberately quieter than the figure
   it stands in for: it is the reason there is no number, not a number. */
.demand-unread { color: var(--text-mute); }
.demand-unread i { font-style: normal; opacity: 0.85; }

/* ---- Today: day triage (2026-08-06 redesign) ---------------------------
   One decision per row. The figure is the only bold thing in the row, the
   verdict buttons are the only interactive ones, and a passed row dims
   rather than disappearing - it is still true, and a material event revives
   it. Nothing counts down: lead time is a fact, stated once, in words. */
.triage { list-style: none; margin: 1.1rem 0 0; padding: 0; display: grid; gap: 0.7rem; }
.triage-row {
  border: 1px solid color-mix(in oklch, var(--border) 52%, transparent);
  border-radius: var(--radius-md, 14px);
  background: color-mix(in oklch, var(--surface) 42%, transparent);
  backdrop-filter: blur(var(--glass-blur)) saturate(1.4);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.4);
  padding: 0.95rem 1.05rem;
}
.triage-row.is-passed { opacity: 0.52; }
.triage-head { display: flex; justify-content: space-between; align-items: baseline;
               gap: 1rem; }
.triage-name { font-weight: 600; font-size: 1rem; text-decoration: none;
               color: var(--text); }
.triage-name:hover { text-decoration: underline; }
.triage-lead { font-family: var(--mono); font-size: 0.8125rem; color: var(--text-mute);
               white-space: nowrap; font-variant-numeric: tabular-nums; }
.triage-moved { margin: 0.3rem 0 0; font-size: 0.78125rem; letter-spacing: 0.06em;
                text-transform: uppercase; color: var(--accent); }
.triage-moved:empty { display: none; }
.triage-moved .mute { color: var(--text-mute); text-transform: none;
                      letter-spacing: normal; }
.triage-figure { margin-top: 0.55rem; display: flex; align-items: baseline;
                 gap: 0.5rem; flex-wrap: wrap; }
.triage-pct { font-size: 2rem; font-weight: 600; line-height: 1.05;
              font-variant-numeric: tabular-nums; }
/* An absent estimate is stated at the same place and never styled as a figure,
   so it cannot be skim-read as one. */
.triage-pct-absent { font-size: 1.05rem; font-weight: 500; color: var(--text-mute); }
.triage-basis { color: var(--text-mute); font-size: 0.875rem; }
.triage-bid { margin-left: auto; font-family: var(--mono); font-size: 0.875rem;
              color: var(--text-mute); }
.triage-verdicts { margin-top: 0.8rem; display: flex; gap: 0.5rem; flex-wrap: wrap; }
.triage-verdicts form { margin: 0; }
.verdict-btn {
  font: inherit; font-size: 0.875rem; min-height: 44px; padding: 0.5rem 1.15rem;
  border-radius: 10px; cursor: pointer;
  border: 1px solid color-mix(in oklch, var(--border) 62%, transparent);
  background: transparent; color: var(--text);
  transition: border-color 160ms var(--ease), color 160ms var(--ease);
}
.verdict-btn:hover { border-color: var(--accent); }
.verdict-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* The chosen verdict carries colour and a weight change, so it survives
   greyscale and does not rely on hue alone. */
.verdict-btn.is-on { color: var(--accent); border-color: var(--accent);
                     background: var(--accent-dim); font-weight: 600; }
.triage-signin { margin: 0.7rem 0 0; font-size: 0.875rem; color: var(--text-mute); }
.triage-carried { margin-top: 1.6rem; }
.triage-carried summary { cursor: pointer; color: var(--text-mute);
                          font-size: 0.875rem; padding: 0.4rem 0; }
.triage-dim .triage-row { padding: 0.6rem 0.9rem; opacity: 0.62; }
.triage-where { color: var(--text-mute); font-size: 0.875rem; margin-right: auto; }

/* The Model section index. Present because Model became a door with four
   routes under it, and on a phone or at tab width the second rank is not
   rendered - without this those routes would be unreachable by navigation. */
.section-index { display: grid; gap: 0.55rem; margin: 0 0 1.4rem;
                 grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }
.section-index a {
  display: grid; gap: 0.15rem; padding: 0.75rem 0.9rem; border-radius: 12px;
  text-decoration: none; color: var(--text);
  border: 1px solid color-mix(in oklch, var(--border) 50%, transparent);
  background: color-mix(in oklch, var(--surface) 34%, transparent);
  transition: border-color 160ms var(--ease);
}
.section-index a:hover { border-color: var(--accent); }
.section-index a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.section-index b { font-weight: 600; font-size: 0.9375rem; }
.section-index span { color: var(--text-mute); font-size: 0.8125rem; }
.workspace-actions { margin: 0.5rem 0 0; }
.workspace-actions a { font-size: 0.875rem; color: var(--accent);
                       text-decoration: none; }
.workspace-actions a:hover { text-decoration: underline; }

/* ---- lenses over Ranked (2026-08-06 redesign) --------------------------
   Eight destinations became eight readings of one list. Chips rather than
   tabs because there are nine including All and they must wrap honestly at
   390px instead of scrolling out of sight. */
.lenses { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0.9rem 0 0.2rem; }
.lenses a {
  display: inline-flex; align-items: baseline; gap: 0.4rem;
  padding: 0.4rem 0.75rem; border-radius: 999px; text-decoration: none;
  font-size: 0.8125rem; color: var(--text-mute);
  border: 1px solid color-mix(in oklch, var(--border) 52%, transparent);
  transition: border-color 160ms var(--ease), color 160ms var(--ease);
}
.lenses a:hover { border-color: var(--accent); color: var(--text); }
.lenses a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Colour and weight both carry the active lens, so it survives greyscale. */
.lenses a[aria-current="page"] { color: var(--accent); border-color: var(--accent);
                                 background: var(--accent-dim); font-weight: 600; }
.lenses .num { font-family: var(--mono); font-variant-numeric: tabular-nums;
               font-size: 0.75rem; opacity: 0.85; }
.lens-note { margin: 0.5rem 0 0; font-size: 0.875rem; color: var(--text-mute);
             max-width: 62ch; }
.lens-note a { color: var(--accent); text-decoration: none; white-space: nowrap; }
.lens-note a:hover { text-decoration: underline; }
.lens-why { margin-left: 0.4rem; }

/* ---- the decide layer (2026-08-06 redesign) ----------------------------
   One anchor figure, three cost lines, and the flags. Sized so the whole
   block clears the fold at 390px: the measured failure it replaces was a
   reader scrolling a 578-line page to re-check a number they had already
   read once. */
.decide { margin: 1rem 0 1.25rem; display: grid; gap: 0.85rem; }
.decide-anchor {
  border: 1px solid color-mix(in oklch, var(--accent) 45%, transparent);
  border-radius: 14px; padding: 1rem 1.1rem;
  background: color-mix(in oklch, var(--accent) 7%, transparent);
}
.decide-label { margin: 0; font-size: 0.6875rem; text-transform: uppercase;
                letter-spacing: 0.13em; color: var(--text-mute); }
.decide-figure { margin: 0.15rem 0 0; font-family: var(--serif);
                 font-size: clamp(2rem, 6vw, 2.75rem); line-height: 1.05;
                 font-variant-numeric: tabular-nums; }
.decide-pair { margin: 0.75rem 0 0; display: grid; gap: 0.3rem 1rem;
               grid-template-columns: 1fr max-content; font-size: 0.8125rem; }
.decide-pair dt { color: var(--text-mute); }
.decide-pair dd { margin: 0; font-family: var(--mono); text-align: right;
                  font-variant-numeric: tabular-nums; }
.decide-stack { margin: 0; display: grid; gap: 0.45rem; font-size: 0.875rem; }
.decide-stack > div { display: flex; justify-content: space-between;
                      align-items: baseline; gap: 1rem; }
.decide-stack dt { color: var(--text); }
.decide-stack dd { margin: 0; font-family: var(--mono);
                   font-variant-numeric: tabular-nums; }
/* The provisioned range never takes the same treatment as a firm total, so it
   cannot be skim-read as one and cannot be added to one. */
.decide-stack .range { color: var(--text-mute); }
.decide-stack .why { color: var(--text-mute); font-size: 0.75rem; }
.decide-flags { margin: 0; padding: 0.7rem 0.9rem 0.7rem 2rem; border-radius: 12px;
                border: 1px solid color-mix(in oklch, var(--state-review) 45%, transparent);
                background: color-mix(in oklch, var(--state-review) 8%, transparent);
                font-size: 0.8125rem; display: grid; gap: 0.25rem; }
/* An absent walk-away is stated, never drawn as a figure: same position,
   same weight as prose, so it cannot be skim-read as a number. */
.decide-anchor.is-absent { border-color: color-mix(in oklch, var(--border) 60%, transparent);
                           background: color-mix(in oklch, var(--surface) 30%, transparent); }
.decide-absent { margin: 0.3rem 0 0; font-size: 0.875rem; color: var(--text-mute);
                 max-width: 52ch; }

/* Peer reads on Ranked: the three routes D66, D36 and D54 argued for, carried
   to the phone where the bar holds five doors and will not hold eight.
   Deliberately not styled as lenses - a lens narrows this list, these ask a
   different question, and looking alike would say they were the same kind of
   thing. */
.peer-reads { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.75rem;
              margin: 0.7rem 0 0; font-size: 0.8125rem; }
.peer-reads > span { color: var(--text-mute); text-transform: uppercase;
                     letter-spacing: 0.11em; font-size: 0.6875rem; }
.peer-reads a { color: var(--text); text-decoration: none;
                border-bottom: 1px solid color-mix(in oklch, var(--accent) 45%, transparent);
                padding-bottom: 1px; min-height: 24px; display: inline-flex;
                align-items: center; }
.peer-reads a:hover { border-bottom-color: var(--accent); color: var(--accent); }
.peer-reads a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Why the page is ordered by lead time and not by what changed. Stated once,
   at the top, because "no movement flagged" silently reads as "nothing moved"
   - which is the false calm this surface shipped with on 2026-08-06. */
.today-coverage { margin: 0.9rem 0 0; padding: 0.7rem 0.9rem; border-radius: 12px;
                  font-size: 0.8125rem; color: var(--text-mute); max-width: 68ch;
                  border: 1px solid color-mix(in oklch, var(--border) 48%, transparent);
                  background: color-mix(in oklch, var(--surface) 26%, transparent); }

/* ===== Platform subdomain (platform.propertyinvestmentintel.com) =====
   Appended, never inserted between existing blocks - app.css already has one
   landmine (two :root[data-theme="dark"] blocks where the later one wins) and
   this section must not become a second one. Every value below is a token
   already defined above; nothing here is a new literal colour. */

.pl-platform { --rail-w: 11.7rem; }
@media (min-width: 1100px) {
  .pl-platform main { padding-top: 0.175rem; }
}

@keyframes plScreenIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes plPanelIn  { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  [data-anim] { animation: none !important; }
}

.pl-screen { animation: plScreenIn 220ms var(--ease) both; }
.pl-panel { animation: plPanelIn 190ms var(--ease) both; }

/* Nav items with no screen behind them yet (Saved searches, Watchlists,
   Exports, Assumptions, API access) - visibly present, per the brief's own
   IA, but not a broken link: same row shape as a live nav item, muted and
   inert rather than styled as a disabled form control. */
.pl-rail-soon { display: flex; align-items: center; gap: 0.56rem; min-height: 2.375rem;
                padding: 0 0.625rem; border-radius: var(--radius-sm);
                font-size: 0.844rem; color: var(--text-mute); opacity: 0.55;
                cursor: default; }
@media (max-width: 560px) {
  .pl-platform nav.bar { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .pl-platform nav.bar .pl-rail-soon:not(.nav-secondary) {
    min-width: 0; min-height: 44px; padding: 0 0.1rem; justify-content: center;
    font-size: 0.64rem; text-align: center;
  }
  .pl-platform nav.bar .pl-rail-soon .nav-long { display: none; }
  .pl-platform nav.bar .pl-rail-soon .nav-short { display: inline; }
}

.pl-home-map-grid { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: stretch; }
.pl-report-band { display: flex; flex-wrap: wrap; gap: 0.75rem; min-height: 26.38rem;
                  margin: 0.125rem 0 0 1.25rem; }
.pl-opportunities-head { color: var(--text-mute); font-size: 0.7rem; font-weight: 650;
                          letter-spacing: 0.11em; text-transform: uppercase; padding: 0 0.1rem; }
.pl-opportunities { box-sizing: border-box; flex: 0 0 clamp(10.4rem, 12%, 14.4rem); max-width: 100%;
                     min-width: 0; height: 26.38rem; display: flex; flex-direction: column; gap: 0.5rem;
                     padding: 0.6rem 0.2rem; overflow: hidden; border-radius: var(--radius-md);
                     border: 1px solid var(--hairline); box-shadow: var(--shadow);
                     background: color-mix(in oklch, var(--chrome) 92%, transparent);
                     backdrop-filter: blur(20px) saturate(1.4); }
.pl-opportunities-list { flex: 1; min-height: 0; min-width: 0; display: flex; flex-direction: column; gap: 0.5rem;
                          overflow-y: auto; overflow-x: hidden; padding-right: 0.2rem; }
@media (max-width: 899px) {
  .pl-report-band > .pl-opportunities,
  .pl-home-map-grid > .pl-opportunities { flex: 1 1 100%; }
}
.pl-opportunities-list p { margin: 0; }
button.pl-property-row { font: inherit; text-align: left; width: 100%; cursor: pointer; appearance: none; }
.pl-property-row.selected { border-color: var(--accent);
                             background: color-mix(in oklch, var(--accent) 13%, var(--surface-strong)); }

/* Opportunities panel rows: one line each - place, then price - not the
   richer thumbnail card .pl-property-row renders for Market Insights. */
.pl-opportunities-list .pl-property-row { padding: 0.5rem 0.4rem; margin-bottom: 0; border-radius: var(--radius-sm); }
.pl-opportunities-list .pl-property-row:hover { border-color: var(--accent); background: var(--surface-strong); }
.pl-opportunities-list .pl-property-row.selected { border-color: var(--accent);
                                                     background: color-mix(in oklch, var(--accent) 7%, var(--surface-strong)); }
.pl-opportunities-list .pl-body { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.pl-opportunities-list .pl-specs { min-width: 0; font-size: 0.78rem; color: var(--text-mute); margin: 0;
                                    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pl-opportunities-list .pl-price { flex: 0 0 auto; font-family: var(--mono); font-size: 0.78rem; font-weight: 600; }
.pl-opportunities-list .pl-property-row.selected .pl-specs { color: var(--text); }

.pl-map-band { position: relative; flex: 1 1 26rem; height: 26.38rem; min-width: 0; overflow: hidden;
               border-radius: var(--radius-md); border: 1px solid var(--hairline);
               box-shadow: var(--shadow); }
.pl-map-band iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block; }
.pl-layer-chips { position: absolute; z-index: 2; left: 50%; top: 0.75rem; transform: translateX(-50%);
                  backdrop-filter: blur(20px) saturate(1.4); }
.pl-layer-chips,
.pl-tabs { display: flex; align-items: center; gap: 0.2rem; padding: 0.3rem;
           border-radius: 9px; background: color-mix(in oklch, var(--chrome) 94%, transparent);
           border: 1px solid var(--hairline); box-shadow: var(--shadow); }
.pl-explore .pl-layer-chips { left: 1.125rem; top: 1.125rem; transform: none; }

/* Precinct crime gauge over the report map (D96): needle = national
   percentile of the precinct's official serious-crime rate. Display-only. */
/* Bottom-right corner by owner directive (2026-08-10), superseding the
   5.6rem lift that kept the embed's corner control clickable — the gauge
   sits over that control's hit area again. */
.pl-crime-gauge { position: absolute; z-index: 2; right: 0.75rem; bottom: 0.75rem;
                  width: min(22rem, calc(100% - 1.5rem)); padding: 0.55rem 0.8rem 0.5rem;
                  border-radius: 9px; background: rgba(0,0,0,0.5); backdrop-filter: blur(6px); }
.pl-crime-gauge-head { display: block; font-size: 0.68rem; font-weight: 520; letter-spacing: 0.02em;
                       color: #fff; text-shadow: 0 1px 3px rgba(0,0,0,0.65); margin-bottom: 0.5rem; }
.pl-crime-gauge-track { position: relative; height: 0.45rem; border-radius: 999px;
                        background: linear-gradient(90deg, #35d0a5, #a8d84d, #ecc94b, #f6a04d, #f97b5f); }
.pl-crime-gauge-track i { position: absolute; top: -0.4rem; width: 4px; height: 0.8rem; border-radius: 999px;
                          background: #fff; border: 1px solid rgba(0,0,0,0.45);
                          transform: translateX(-50%); }
.pl-crime-gauge-labels { display: flex; justify-content: space-between; margin-top: 0.4rem;
                         font-size: 0.62rem; color: #fff; text-shadow: 0 1px 3px rgba(0,0,0,0.65); }

/* Vertical market gauge on the map's left edge: needle = this property's
   bid floor vs modelled market value. Deep discount reads green (the
   below-market pin convention); above market reads coral. Display-only. */
.pl-market-gauge { position: absolute; z-index: 2; left: 0.75rem; top: 50%; transform: translateY(-50%);
                   padding: 0.55rem 0.7rem 0.6rem; border-radius: 9px; background: rgba(0,0,0,0.5);
                   backdrop-filter: blur(6px); }
.pl-market-gauge-head { display: block; font-size: 0.81rem; font-weight: 520; letter-spacing: 0.02em;
                        color: var(--accent); margin-bottom: 0.55rem; text-align: center; }
.pl-market-gauge-head b { display: block; font-weight: 640; margin-top: 0.15rem; color: #fff; }
.pl-market-gauge-body { display: flex; gap: 0.5rem; padding: 0.3rem 0; }
.pl-market-gauge-track { position: relative; width: 0.45rem; height: 10.5rem; border-radius: 999px;
                         background: linear-gradient(180deg, #f97b5f, #f6a04d, #ecc94b, #a8d84d, #35d0a5); }
.pl-market-gauge-track i { position: absolute; left: -0.2rem; width: 0.85rem; height: 4px; border-radius: 999px;
                           background: #fff; border: 1px solid rgba(0,0,0,0.45); transform: translateY(-50%); }
.pl-market-gauge-ticks { position: relative; height: 10.5rem; min-width: 3.4rem; font-size: 0.58rem;
                         color: #fff; }
.pl-market-gauge-ticks span { position: absolute; transform: translateY(-50%); white-space: nowrap;
                              text-shadow: 0 1px 3px rgba(0,0,0,0.65); }
.pl-chip,
.pl-tabs a { flex: 0 0 auto; font-size: 0.8rem; font-weight: 520; padding: 0.42rem 0.9rem;
               border-radius: 6px; background: transparent; border: 0; color: var(--text-mute);
               text-decoration: none; display: inline-flex; align-items: center;
               transition: color 160ms var(--ease), background 160ms var(--ease); }
.pl-chip.active,
.pl-tabs a[aria-current="page"] { color: var(--accent); font-weight: 620;
                                  background: color-mix(in oklch, var(--accent) 12%, transparent); }
.pl-chip:not(.active):hover,
.pl-tabs a:not([aria-current="page"]):hover { color: var(--text); }
.pl-chip:focus-visible,
.pl-tabs a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.pl-chip[title] { opacity: 0.5; cursor: default; }

.pl-start-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
                  gap: 0.875rem; margin-top: 0.875rem; }
.pl-start-card { display: flex; flex-direction: column; gap: 0.56rem; text-align: left;
                 padding: 1.25rem 1.25rem 1.375rem; border-radius: var(--radius-md);
                 background: var(--surface-strong); border: 1px solid var(--hairline);
                 box-shadow: var(--shadow); color: inherit; text-decoration: none;
                 transition: background 180ms var(--ease), border-color 180ms var(--ease); }
.pl-start-card svg { width: 1.5rem; height: 1.5rem; color: var(--accent); }
.pl-start-card b { font-family: var(--serif); font-size: 1.0625rem; font-weight: 500; }
.pl-start-card p { font-size: 0.78rem; line-height: 1.6; color: var(--text-mute); margin: 0; }
.pl-start-card .go { font-size: 0.75rem; color: var(--accent); margin-top: 0.125rem; }
a.pl-start-card:hover, .pl-start-card.is-link:hover { border-color: color-mix(in oklch, var(--accent) 75%, transparent);
                             background: color-mix(in oklch, var(--surface) 70%, transparent); }
.pl-start-card.is-soon { opacity: 0.6; }

.pl-caveat { max-width: 70ch; margin: 1.25rem 0 0; padding: 0.875rem 1rem;
             border: 1px dashed color-mix(in oklch, var(--border) 70%, transparent);
             border-radius: var(--radius-md); background: var(--surface-strong);
             font-size: 0.78rem; line-height: 1.65; color: var(--text-mute); }
.pl-caveat strong { color: var(--text); font-weight: 560; }

/* Property Explorer */
.pl-tabs { width: max-content; max-width: calc(100% - 2.5rem); box-sizing: border-box;
           margin: 0.75rem 1.25rem 0; overflow-x: auto; }
.pl-tabs a { white-space: nowrap; }
.pl-tab-body { padding: 1.25rem; max-width: 74rem; }

.pl-value-range { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 1px;
                   border-radius: var(--radius-md); overflow: hidden;
                   border: 1px solid var(--hairline); background: var(--hairline); }
.pl-value-range > div { background: var(--surface-strong); padding: 1rem 1.125rem; }
.pl-value-range > div.pl-mid { background: color-mix(in oklch, var(--accent) 13%, var(--surface-strong));
                                box-shadow: inset 0 1px 0 color-mix(in oklch, var(--accent) 35%, transparent); }
.pl-value-range .pl-figure { font-family: var(--mono); font-size: 1.1rem; font-variant-numeric: tabular-nums; }
.pl-value-range .pl-label { font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.13em;
                             color: var(--text-mute); }

.pl-cost-table { width: 100%; border-collapse: collapse; font-size: 0.83rem; }
.pl-cost-table th, .pl-cost-table td { padding: 0.5rem 0.7rem; border-bottom: 1px solid var(--hairline);
                                        text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums; }
.pl-cost-table th:first-child, .pl-cost-table td:first-child { text-align: left; font-family: var(--sans); }
.pl-cost-table .pl-provision { border-bottom: 1px dotted var(--border); color: var(--text-mute); }
.pl-cost-table tfoot td { font-weight: 600; border-top: 1px solid var(--border); border-bottom: none; }

.pl-hood-lenses { display: flex; gap: 0.375rem; margin-bottom: 1rem; flex-wrap: wrap; }
.pl-hood-lenses a { padding: 0.44rem 0.8rem; border-radius: 9999px; font-size: 0.78rem;
                     text-decoration: none; color: var(--text-mute);
                     border: 1px solid color-mix(in oklch, var(--border) 55%, transparent); }
.pl-hood-lenses a[aria-current="page"] { color: var(--accent); border-color: color-mix(in oklch, var(--accent) 70%, transparent); }

.pl-dist-list { display: flex; flex-direction: column; gap: 0.875rem; max-width: 34rem; }
.pl-dist-head { display: flex; justify-content: space-between; gap: 0.75rem; align-items: baseline;
                 font-size: 0.8rem; margin-bottom: 0.375rem; }
.pl-dist-head .num { font-family: var(--mono); font-size: 0.72rem; color: var(--text-mute);
                      font-variant-numeric: tabular-nums; }
.pl-dist-bar { position: relative; height: 8px; border-radius: 4px;
                background: color-mix(in oklch, var(--border) 45%, transparent); }
.pl-dist-bar i { position: absolute; top: -2px; bottom: -2px; width: 2px; margin-left: -1px;
                  background: var(--text-mute); }
.pl-dist-bar b { position: absolute; top: 50%; width: 12px; height: 12px; margin: -6px 0 0 -6px;
                  border-radius: 50%; background: var(--accent);
                  box-shadow: 0 0 0 2px color-mix(in oklch, var(--bg) 80%, transparent); }
.pl-dist-subject { font-size: 0.72rem; color: var(--accent); font-family: var(--mono);
                    font-variant-numeric: tabular-nums; margin-top: 0.3rem; }

.pl-def-table { display: grid; grid-template-columns: 1fr 1fr; gap: 0 1.5rem; font-size: 0.83rem; }
.pl-def-table .row { display: flex; justify-content: space-between; gap: 0.75rem;
                      padding: 0.44rem 0; border-bottom: 1px solid var(--hairline); }
.pl-def-table .row dt { color: var(--text-mute); }
.pl-def-table .row dd { margin: 0; font-family: var(--mono); font-variant-numeric: tabular-nums; text-align: right; }

@media (max-width: 699px) {
  .pl-value-range,
  .pl-def-table { grid-template-columns: minmax(0, 1fr); }
  .pl-cost-table { display: block; max-width: 100%; overflow-x: auto;
                   -webkit-overflow-scrolling: touch; }
}

.pl-report-map-absent { position: absolute; inset: 0; display: grid; place-items: center;
                         padding: 0 1rem; font-size: 0.8rem; text-align: center; }

.pl-subtabs { display: flex; align-items: center; justify-content: space-between;
              border-bottom: 1px solid var(--hairline); margin-bottom: 1rem;
              padding-bottom: 0.6rem; }
.pl-subtab-action { font-size: 0.8125rem; color: var(--accent); }
.pl-subtab-soon { opacity: 0.5; cursor: default; pointer-events: none; }

.pl-comparable-excluded { text-decoration: line-through; opacity: 0.55; }

/* Market Insights */
.pl-explore-grid { display: grid; grid-template-columns: minmax(0, 1fr) 26.25rem; min-height: 0; }
@media (max-width: 899px) {
  .pl-explore-grid { grid-template-columns: minmax(0, 1fr); }
}
.pl-explore-map { position: relative; min-height: 26rem; }
.pl-explore-map iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block; }
.pl-legend { position: absolute; left: 1.125rem; bottom: 1.125rem; width: 15.6rem;
             padding: 0.75rem 0.875rem; border-radius: var(--radius-md);
             background: color-mix(in oklch, var(--surface) 90%, var(--bg));
             border: 1px solid color-mix(in oklch, var(--border) 50%, transparent);
             backdrop-filter: blur(16px); display: flex; flex-direction: column; gap: 0.5rem; }
.pl-legend b { font-size: 0.75rem; }
.pl-legend-ramp { display: flex; height: 0.5rem; border-radius: 4px; overflow: hidden; }
.pl-legend-ramp i { flex: 1; display: block; }
.pl-legend-dots { display: flex; flex-direction: column; gap: 0.3rem; }
.pl-legend-dots span { display: flex; align-items: center; gap: 0.4rem; font-size: 0.72rem; color: var(--text-mute); }
.pl-legend-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.pl-legend p { margin: 0; font-size: 0.72rem; color: var(--text-mute); line-height: 1.5; }

.pl-pane-tabs { display: flex; gap: 0.25rem; padding: 0.75rem 1rem 0; border-bottom: 1px solid var(--hairline); }
.pl-pane-tabs a { padding: 0.5rem 0.75rem; font-size: 0.8125rem; color: var(--text-mute);
                   text-decoration: none; border-bottom: 2px solid transparent; }
.pl-pane-tabs a[aria-current="page"] { color: var(--text); border-bottom-color: var(--accent); }
.pl-explore-pane { padding: 1rem; overflow-y: auto; }

.pl-property-row { display: flex; gap: 0.75rem; padding: 0.7rem; border-radius: var(--radius-md);
                    background: var(--surface-strong); border: 1px solid var(--hairline);
                    margin-bottom: 0.5rem; text-decoration: none; color: inherit; }
.pl-property-row:hover { border-color: color-mix(in oklch, var(--accent) 70%, transparent);
                          background: color-mix(in oklch, var(--surface) 75%, transparent); }
.pl-property-row.pl-no-value { border-style: dashed; }
.pl-property-row .pl-thumb { width: 5.5rem; height: 4.75rem; flex: 0 0 auto; border-radius: var(--radius-sm);
                              display: grid; place-items: center; background: color-mix(in oklch, var(--surface) 60%, transparent);
                              font-size: 0.66rem; color: var(--text-mute); text-align: center; padding: 0.25rem; }
.pl-property-row .pl-body { flex: 1; min-width: 0; }
.pl-property-row .pl-price { font-family: var(--mono); font-size: 0.9375rem; font-variant-numeric: tabular-nums; }
.pl-property-row .pl-specs { font-size: 0.78rem; color: var(--text-mute); margin: 0.2rem 0; }
.pl-property-row .pl-metrics { display: flex; gap: 0.75rem; font-family: var(--mono); font-size: 0.78rem;
                                font-variant-numeric: tabular-nums; color: var(--text-mute); }
.pl-property-row .pl-discount { color: var(--accent); }
.pl-property-row .pl-discount.pl-bank-reject { color: var(--state-fail); }

.pl-market-headline { font-family: var(--serif); font-size: 1.375rem; font-weight: 500; margin: 0 0 0.25rem; }
.pl-market-provenance { font-family: var(--mono); font-size: 0.72rem; color: var(--text-mute); margin: 0 0 0.75rem; }
.pl-basis-toggle { display: inline-flex; border-radius: 9999px; border: 1px solid var(--hairline); overflow: hidden;
                    margin-bottom: 0.875rem; }
.pl-basis-toggle a { padding: 0.375rem 0.875rem; font-size: 0.75rem; text-decoration: none; color: var(--text-mute); }
.pl-basis-toggle a[aria-current="page"] { background: var(--accent); color: var(--bg); }

/* ---- sale calendar (D105) ---------------------------------------------- */
/* A month grid over the same sessions the planner lists. One sheet, one
   compositing layer, same as every other list here. Colour is carried by the
   accent alone: a marked entry holds a lot you are tracking, and the word on
   the row says which - the tint never says it by itself. */
.cal-month {
  font-size: 0.6875rem; padding: 0.15rem 0.5rem; border-radius: 6px;
  border: 1px solid transparent; color: var(--text-mute); text-decoration: none;
  letter-spacing: 0;
}
.cal-month.on { color: var(--accent); border-color: var(--accent);
                background: var(--accent-dim); }
.cal-month:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.cal { padding: 0.35rem; }
/* Separate, not collapsed: collapsed borders put a day's right-hand lot count
   flush against the next day's text, so Tuesday's "3" read as part of
   Wednesday's first office. The gap is what keeps a column a column - and
   rounded day cells need it too. */
.cal-grid { width: 100%; border-collapse: separate; border-spacing: 3px;
            table-layout: fixed; }
.cal-grid th {
  font-family: var(--sans); font-size: 0.625rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-mute);
  padding: 0.4rem 0.3rem; text-align: left;
}
.cal-grid th abbr { text-decoration: none; }
.cal-day {
  vertical-align: top; height: 5.5rem; padding: 0.3rem; overflow: hidden;
  border: 1px solid color-mix(in oklch, var(--border) 45%, transparent);
  border-radius: 8px;
}
/* A day from the neighbouring month keeps its number so the week reads whole,
   but not its sessions: 31 July carries thirteen and was setting the height of
   August's first row for a day that is not in August. It is one tab away. */
.cal-day.out { opacity: 0.32; }
.cal-day.out .cal-list { display: none; }
.cal-day.today { border-color: var(--accent);
                 background: color-mix(in oklch, var(--accent) 7%, transparent); }
.cal-day .dom { display: block; font-family: var(--mono); font-size: 0.75rem;
                font-variant-numeric: tabular-nums; color: var(--text-mute);
                margin-bottom: 0.15rem; }
.cal-day.has .dom { color: var(--text); font-weight: 600; }
.cal-day.today .dom { color: var(--accent); }

.cal-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.12rem; }
/* A grid item's min-width is `auto`, so the row would not shrink below its
   longest office name and the lot count escaped the cell into the next day's
   column - Monday's "3" reading as part of Tuesday. The cell clips as a
   backstop, since a table cell does not by default. */
.cal-item {
  min-width: 0;
  display: flex; align-items: baseline; gap: 0.25rem;
  font-size: 0.6875rem; line-height: 1.25; padding: 0.1rem 0.25rem;
  border-radius: 4px; border-left: 2px solid var(--border);
  background: color-mix(in oklch, var(--surface) 40%, transparent);
  color: var(--text-mute);
}
.cal-item.mine { border-left-color: var(--accent); color: var(--text);
                 background: var(--accent-dim); }
.cal-item .t { font-family: var(--mono); font-size: 0.625rem; font-weight: 600;
               flex: 0 0 auto; }
.cal-item .w { flex: 1 1 auto; min-width: 0; overflow: hidden;
               text-overflow: ellipsis; white-space: nowrap; }
.cal-item .n { flex: 0 0 auto; font-family: var(--mono); font-size: 0.625rem;
               font-variant-numeric: tabular-nums; }
.cal-item .n i { font-style: normal; color: var(--accent); }

.cal-key { font-size: 0.75rem; color: var(--text-mute); margin: 0.6rem 0 0;
           display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
.cal-key .cal-item { flex: 0 0 auto; }
.cal-key .count { font-family: var(--mono); }

/* On a phone a seven-column grid of stacked lists is unreadable, so the week
   becomes rows and empty days drop out entirely - the month's shape is not
   worth a screen of blank cells on a 390px viewport. */
@media (max-width: 720px) {
  .cal-grid, .cal-grid tbody, .cal-grid tr { display: block; }
  .cal-grid thead { display: none; }
  .cal-grid tr { display: grid; gap: 0.3rem; margin-bottom: 0.3rem; }
  .cal-day { height: auto; }
  .cal-day:not(.has) { display: none; }
  .cal-day .dom::after { content: " " attr(data-weekday); font-family: var(--sans); }
}

/* A real switch, not a chip that happens to be highlighted. The state is in
   the URL and the control is a link, so it works with scripting off; the
   sliding knob is the only thing CSS is doing here. */
.toggle {
  margin-left: auto; display: inline-flex; align-items: center; gap: 0.5rem;
  text-decoration: none; color: var(--text-mute); font-size: 0.6875rem;
  letter-spacing: 0;
}
.toggle .lbl { white-space: nowrap; }
.toggle .track {
  position: relative; flex: 0 0 auto; width: 2.15rem; height: 1.2rem;
  border-radius: 9999px; border: 1px solid var(--border);
  background: color-mix(in oklch, var(--text-mute) 22%, transparent);
  transition: background 160ms var(--ease), border-color 160ms var(--ease);
}
.toggle .knob {
  position: absolute; top: 50%; left: 2px; transform: translateY(-50%);
  width: 0.85rem; height: 0.85rem; border-radius: 50%;
  background: var(--text-mute);
  transition: left 160ms var(--ease), background 160ms var(--ease);
}
.toggle.on { color: var(--text); }
.toggle.on .track { background: var(--accent); border-color: var(--accent); }
.toggle.on .knob { left: calc(100% - 0.85rem - 3px); background: var(--surface); }
.toggle:hover .track { border-color: var(--accent); }
.toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px;
                        border-radius: 6px; }
@media (prefers-reduced-motion: reduce) {
  .toggle .track, .toggle .knob { transition: none; }
}

/* ---- property identity + fact tiles ------------------------------------ */
/* The card structure: where it is, what it is, where exactly, the specifics,
   then the facts as labelled tiles. Borrowed layout; the palette, the serif
   heading and the absent-value discipline are this project's own. */
/* No top margin: it now opens the tab body, whose 1.25rem padding is the gap.
   The 1.1rem it used to carry was the breathing room between the map band and
   itself, and there is nothing above it any more. */
.pl-ident { margin: 0 0 1.1rem; }
.pl-ident-where {
  margin: 0; font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--text-mute);
}
.pl-ident-title {
  margin: 0.3rem 0 0; font-family: var(--serif); font-weight: 500;
  font-size: clamp(1.35rem, 2.4vw, 1.75rem); line-height: 1.2;
}
.pl-ident-addr { margin: 0.25rem 0 0; font-size: 0.875rem; color: var(--text); }
.pl-ident-specs {
  margin: 0.3rem 0 0; font-size: 0.75rem; color: var(--text-mute);
  display: flex; align-items: center; gap: 0.35rem; flex-wrap: wrap;
}

.pl-facts {
  display: grid; gap: 0.5rem; margin: 0.25rem 0 1rem;
  grid-template-columns: repeat(auto-fill, minmax(12.5rem, 1fr));
}
.pl-fact {
  display: flex; flex-direction: column; gap: 0.3rem;
  padding: 0.6rem 0.7rem; border-radius: 8px;
  border: 1px solid color-mix(in oklch, var(--border) 55%, transparent);
  background: color-mix(in oklch, var(--surface) 30%, transparent);
}
.pl-fact.wide { grid-column: 1 / -1; }
.pl-fact .k {
  font-size: 0.625rem; font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-mute);
}
.pl-fact .v {
  font-family: var(--mono); font-size: 0.9375rem; line-height: 1.25;
  font-variant-numeric: tabular-nums; color: var(--text);
}
/* The qualifier under a figure - the market comparison, the grain, the time -
   is not the figure, and must not be read as one. */
.pl-fact .v small {
  display: block; margin-top: 0.15rem; font-family: var(--sans);
  font-size: 0.6875rem; color: var(--text-mute); letter-spacing: 0;
}
/* An absent value keeps its tile and says why. Never a dash, never "N/A". */
.pl-fact .v .absent {
  font-family: var(--sans); font-size: 0.75rem; font-style: normal;
  color: var(--text-mute);
}
@media (max-width: 560px) {
  .pl-facts { grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr)); }
}

/* ---- the triage row, second pass --------------------------------------- */
/* The first pass boxed the figures and stopped, which made a busy row into a
   busy row with borders. What was actually wrong: tiles sized to their content
   so nothing lined up between rows, padding under half what it needed, three
   box languages stacked, and no single element loud enough to be the way in.
   Fixed here in that order. */

/* Band 1. Office, province and source as plain text above the place - they
   were three pills, which is three boxes spent on provenance. */
.r-where {
  display: block; font-size: 0.625rem; font-weight: 600; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--text-mute); margin-bottom: 0.2rem;
}
.addr { font-size: 1.0625rem; line-height: 1.25; }
.r-reject { color: var(--state-fail); font-weight: 580; }

/* Band 2. The triage question, and the only thing on the row at this size. */
.r-lead { display: block; margin-top: 0.6rem; }
.r-lead b {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: clamp(1.6rem, 3.4vw, 2.05rem); font-weight: 560;
  line-height: 1.05; letter-spacing: -0.01em; display: block;
}
.r-lead b.over { color: var(--text-mute); }
.r-lead i {
  display: block; font-style: normal; font-size: 0.75rem;
  color: var(--text-mute); margin-top: 0.15rem;
}
.r-lead .absent { font-size: 0.8125rem; }
.r-lead b.doubted { text-decoration: underline dotted
                  color-mix(in oklch, var(--state-review) 80%, transparent);
                  text-underline-offset: 6px; }

/* Band 3. Sized columns, not fitted ones: every row is the same width, so
   auto-fill gives every row the same column count and a tile lands in the same
   place down the whole list. That alignment is most of what "clean" was. */
.figs {
  display: grid; gap: 0.5rem; margin-top: 0.75rem;
  grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
}
.figs .f {
  display: flex; flex-direction: column; gap: 0.2rem; min-width: 0;
  padding: 0.7rem 0.8rem; border-radius: 9px;
  border: 1px solid color-mix(in oklch, var(--border) 42%, transparent);
  background: color-mix(in oklch, var(--surface) 22%, transparent);
}
.figs .f .k {
  font-size: 0.5625rem; font-weight: 600; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--text-mute); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.figs b { font-size: 0.9375rem; font-weight: 560; }
.figs b.soft { font-size: 0.875rem; }
.figs i { font-size: 0.6875rem; line-height: 1.3; }

/* Band 4. The states were bordered boxes competing with the tiles above them;
   they are a sentence now. The mark keeps its job - never colour alone. */
.tags { gap: 0.75rem; margin-top: 0.7rem; }
.badge {
  border: 0; padding: 0; border-radius: 0; background: none;
  font-size: 0.6875rem; letter-spacing: 0.04em;
  /* The bug this fixes: as an inline-flex in a narrow column the badge was
     squeezed until the mark and its label broke onto separate lines, which
     read as an empty box with a stray "?" floating in it. */
  flex: 0 0 auto; white-space: nowrap;
}
.badge.noreserve { background: none; }
.needs { margin-top: 0.55rem; }

@media (max-width: 560px) {
  .figs { grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr)); }
  .r-lead b { font-size: 1.5rem; }
}

/* The states read as a sentence, so they are laid out as one. As flex items in
   a squeezed container they were being narrowed until the mark and its label
   landed on separate lines - an empty box with a stray "?" in it, which is
   what the row's worst element actually was. Inline text cannot do that. */
.tags { display: block; margin-top: 0.65rem; }
.badge {
  display: inline; font-size: 0.6875rem; font-weight: 580;
  letter-spacing: 0.04em; text-transform: uppercase; white-space: nowrap;
  border: 0; padding: 0; background: none; border-radius: 0;
}
 /* Trailing the badge before it, not leading the one after: as a ::before the
    separator could start a wrapped line, leaving "· REVIEW, MARKET" hanging
    under the row with an orphan dot. */
.badge:not(:last-child)::after {
  content: "·"; margin: 0 0.45rem; color: var(--text-mute); font-weight: 400;
}
.badge .mark { display: inline; margin-right: 0.28rem; }
.badge.noreserve { background: none; }

/* Compactness pass: the bands were right and the row was 400px tall, which is
   not a list any more. Same structure, less air per element. */
.figs { gap: 0.4rem; margin-top: 0.6rem; }
.figs .f { padding: 0.5rem 0.6rem; gap: 0.12rem; }
.r-lead { margin-top: 0.5rem; }
.r-lead b { font-size: clamp(1.4rem, 2.8vw, 1.7rem); }
.needs { margin-top: 0.5rem; }

/* The star sat vertically centred, which in a tall row put it adrift in the
   middle of the figures. It belongs beside the name it marks. */
.row > .fav { align-self: flex-start; margin-top: 0.7rem; }

/* ---- report identity + facts, second pass ------------------------------ */
/* Same three corrections the triage row got: more air in the tiles, one box
   language on the page, and a single figure loud enough to be the way in. */
.pl-fact { padding: 0.75rem 0.85rem; gap: 0.25rem; }
.pl-facts { gap: 0.55rem; }

/* The source keeps its data-tag markup for the deploy check and loses its
   pill, so the identity block is text and nothing else. */
.pl-ident-specs .property-tag {
  border: 0; background: none; padding: 0; min-height: 0;
  font-size: inherit; font-weight: inherit; letter-spacing: inherit;
  text-transform: none; color: var(--text-mute);
}
.pl-ident-lead { margin: 0.7rem 0 0; }
.pl-ident-lead b { font-size: clamp(1.8rem, 3.6vw, 2.4rem); }

/* The screening states, as a sentence with its name beside it. */
.pl-screening {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.6rem;
  margin: 1rem 0 0; padding-top: 0.8rem;
  border-top: 1px solid color-mix(in oklch, var(--border) 40%, transparent);
}
.pl-screening .k {
  font-size: 0.625rem; font-weight: 600; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--text-mute);
}
.pl-screening .v { font-family: var(--mono); font-size: 0.8125rem; }

/* ---- the recommendation tab -------------------------------------------- */
/* The verdict is a sentence, not a badge: "Strong candidate" means nothing
   without the reason beside it, and a coloured pill would carry the claim on
   colour alone. */
.pl-verdict {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem 0.75rem;
  margin: 0 0 1rem;
}
.pl-verdict .k {
  font-size: 0.625rem; font-weight: 600; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--text-mute);
}
.pl-verdict .v { font-family: var(--serif); font-size: 1.5rem; font-weight: 500; }
.pl-verdict i {
  font-style: normal; font-size: 0.8125rem; color: var(--text-mute);
  flex: 1 1 14rem; min-width: 0;
}
/* The three numbers that are the action, one step louder than a fact tile. */
.pl-action .pl-fact .v { font-size: 1.125rem; }
.pl-subhead {
  margin: 1.2rem 0 0.4rem; font-size: 0.75rem; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-mute);
}
.pl-caveats { margin: 0; padding-left: 1.1rem; font-size: 0.8125rem; }
.pl-caveats li { margin-bottom: 0.35rem; }
.pl-caveats.quiet { color: var(--text-mute); font-size: 0.75rem; margin-top: 0.7rem; }

/* ---- administration (identity and access, phase 9) --------------------- */
/* Ported wholesale from the CommandVoice operator dashboard, palette
   included, on the owner's explicit instruction (2026-08-12). This replaces
   the original position that an admin surface should look like the product
   it administers. The counter-argument the owner chose: a surface that is
   visibly NOT the product is one nobody mistakes for it, and this one is on
   its own hostname with its own sign-in already.

   Everything here is scoped under `body.admin`, which only the admin
   sub-app renders, so the public site is untouched. Stone/green/indigo
   below are literal Tailwind values from the source, not our tokens - the
   point of a wholesale copy is that they do not drift toward ours. */
body.admin {
  --ops-bg: #0c0a09;          /* stone-950 */
  --ops-line: rgb(255 255 255 / 0.10);
  --ops-dim: #78716c;         /* stone-500 */
  --ops-mute: #a8a29e;        /* stone-400 */
  --ops-text: #d6d3d1;        /* stone-300 */
  --ops-bright: #fafaf9;      /* stone-50  */
  --ops-brand: #22c55e;       /* green-500 */
  --ops-active-line: rgb(129 140 248 / 0.40);   /* indigo-400/40 */
  --ops-active-fill: rgb(99 102 241 / 0.10);    /* indigo-500/10 */
  --ops-bar-h: 52px;
  --ops-rail-w: 200px;
  background: var(--ops-bg);
  color: var(--ops-text);
  min-height: 100vh;
}

/* Fixed top bar. Holds the mobile nav trigger, the mark, and which operator
   is signed in - the gate already proved they may be here, so this answers
   "who am I right now", which matters when two people share a screen. */
.ops-bar {
  position: fixed; inset-inline: 0; top: 0; z-index: 50;
  display: flex; align-items: center; gap: 0.5rem;
  height: var(--ops-bar-h); padding-inline: 0.75rem;
  border-bottom: 1px solid var(--ops-line);
  background: rgb(12 10 9 / 0.80);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
}
@media (min-width: 640px) { .ops-bar { padding-inline: 1.25rem; } }
.ops-burger {
  display: inline-flex; align-items: center; justify-content: center;
  height: 2.5rem; width: 2.5rem; margin-left: -0.25rem;
  border: 0; background: none; color: var(--ops-text);
  border-radius: 0.5rem; cursor: pointer; transition: background 150ms ease;
}
.ops-burger:hover { background: rgb(255 255 255 / 0.05); color: var(--ops-bright); }
@media (min-width: 1024px) { .ops-burger { display: none; } }
.ops-brand { display: flex; align-items: center; gap: 0.75rem; min-width: 0; }
.ops-mark {
  display: flex; align-items: center; justify-content: center; flex: 0 0 auto;
  height: 1.75rem; width: 1.75rem; border-radius: 0.5rem;
  background: var(--ops-brand); color: #fff;
  font-family: var(--mono); font-size: 11px; font-weight: 700;
}
.ops-title { min-width: 0; line-height: 1.2; }
.ops-title b {
  display: block; font-size: 13px; font-weight: 600; color: var(--ops-bright);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ops-title b .lead { color: #4ade80; }             /* green-400 */
.ops-title b .tail {
  margin-left: 0.1em; padding: 0.04em 0.18em; border-radius: 0.12em;
  background: var(--ops-brand); color: #0B0B0C; font-weight: 700;
}
/* Direct child only: the wordmark's own two spans live inside the <b> and
   must stay inline - matching them here turned the lockup into a stacked,
   uppercase, full-width green bar. */
.ops-title > span {
  display: block; font-size: 10px; text-transform: uppercase;
  letter-spacing: 0.18em; color: var(--ops-dim);
}
.ops-who { margin-left: auto; padding-left: 0.75rem; text-align: right;
           min-width: 0; display: none; }
@media (min-width: 640px) { .ops-who { display: block; } }
.ops-who b { display: block; font-weight: 400; font-size: 11px;
             color: var(--ops-text); white-space: nowrap;
             overflow: hidden; text-overflow: ellipsis; }
.ops-who span { display: block; font-size: 9px; text-transform: uppercase;
                letter-spacing: 0.18em; color: var(--ops-dim); }

/* Navigation: a persistent rail from 1024px, a drawer below it. One markup
   block serves both - the drawer is the same list in a different box - so a
   link added once appears in both. */
.ops-rail {
  position: fixed; top: var(--ops-bar-h); bottom: 0; left: 0; z-index: 40;
  width: var(--ops-rail-w); padding: 0.75rem; overflow-y: auto;
  border-right: 1px solid var(--ops-line);
  background: rgb(12 10 9 / 0.60);
  display: none;
}
@media (min-width: 1024px) { .ops-rail { display: block; } }
.ops-group { margin-bottom: 1rem; }
.ops-group:last-child { margin-bottom: 0; }
.ops-group > p {
  margin: 0; padding: 0.25rem 0.75rem 0.375rem;
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.18em;
  color: var(--ops-dim);
}
.ops-group nav { display: flex; flex-direction: column; gap: 0.25rem; }
.ops-group a {
  padding: 0.625rem 0.75rem; border-radius: 0.5rem; font-size: 13px;
  border: 1px solid transparent; color: var(--ops-text);
  text-decoration: none; transition: background 150ms ease,
                                     border-color 150ms ease, color 150ms ease;
}
.ops-group a:hover {
  border-color: rgb(255 255 255 / 0.15);
  background: rgb(255 255 255 / 0.05); color: var(--ops-bright);
}
.ops-group a[aria-current="page"] {
  border-color: var(--ops-active-line); background: var(--ops-active-fill);
  color: var(--ops-bright);
}

/* The drawer. `hidden` on the container is the closed state, so with no
   JavaScript the nav is simply absent on a phone rather than stuck open -
   and the rail still serves every wide screen. */
.ops-drawer { position: fixed; inset: 0; z-index: 60; }
.ops-drawer[hidden] { display: none; }
@media (min-width: 1024px) { .ops-drawer { display: none; } }
.ops-scrim { position: absolute; inset: 0; height: 100%; width: 100%;
             border: 0; background: rgb(0 0 0 / 0.60); cursor: pointer; }
.ops-sheet {
  position: absolute; inset-block: 0; left: 0;
  display: flex; flex-direction: column; width: 82%; max-width: 300px;
  padding: 0.75rem; overflow-y: auto;
  border-right: 1px solid var(--ops-line); background: var(--ops-bg);
}
.ops-sheet-top { display: flex; align-items: center; justify-content: space-between;
                 padding-inline: 0.25rem; margin-bottom: 0.5rem; }
.ops-sheet-top span { font-size: 11px; text-transform: uppercase;
                      letter-spacing: 0.18em; color: var(--ops-dim); }

.ops-main { padding-top: var(--ops-bar-h); }
@media (min-width: 1024px) { .ops-main { padding-left: var(--ops-rail-w); } }
.ops-main > div { padding: 1.5rem 1rem; }
@media (min-width: 640px) { .ops-main > div { padding: 2rem 1.5rem; } }
@media (min-width: 1024px) { .ops-main > div { padding-inline: 2.5rem; } }

/* Page furniture. The eyebrow/heading/standfirst trio is the source's, and
   the 2.5rem rhythm between sections is what stops the tiles and the tables
   reading as one undifferentiated column. */
.ops-stack > * + * { margin-top: 2.5rem; }
.ops-head p.eyebrow { margin: 0; font-size: 11px; text-transform: uppercase;
                      letter-spacing: 0.2em; color: var(--ops-dim); }
.ops-head h1 { margin: 0.5rem 0 0; font-size: 1.5rem; font-weight: 600;
               letter-spacing: -0.01em; color: var(--ops-bright); }
.ops-head p.stand { margin: 0.5rem 0 0; font-size: 0.875rem;
                    color: var(--ops-mute); max-width: 62ch; }
.ops-sec > h2 { margin: 0; font-size: 11px; text-transform: uppercase;
                letter-spacing: 0.18em; color: var(--ops-dim); font-weight: 400; }
.ops-sec > p.stand { margin: 0.25rem 0 0; font-size: 0.75rem; color: var(--ops-mute); }
.ops-sec > .ops-card, .ops-sec > .ops-sheet-scroll { margin-top: 0.75rem; }
.ops-note { font-size: 0.75rem; color: var(--ops-mute); margin: 0.5rem 0 0;
            max-width: 62ch; }
.ops-note a { color: var(--ops-text); }

/* The source's card surface: a dark glass panel with a green rim glow and a
   single diagonal glare. Ported rather than approximated - it is most of
   what makes the dashboard look like the dashboard. */
.ops-card {
  --glow: 74 222 128;
  position: relative; isolation: isolate; overflow: hidden;
  border-radius: 14px;
  background:
    radial-gradient(58% 3% at 56% 0%, rgb(var(--glow) / 0.42), transparent 72%),
    radial-gradient(120% 92% at 0% 100%, rgb(var(--glow) / 0.08), transparent 54%),
    linear-gradient(150deg, rgb(5 13 10 / 0.86) 0%, rgb(0 3 3 / 0.94) 100%);
  border: 1px solid rgb(245 245 244 / 0.10);
  box-shadow:
    inset 0 1px 0 0 rgb(255 255 255 / 0.10),
    0 0 28px -18px rgb(var(--glow) / 0.55),
    0 34px 90px -48px rgb(0 0 0 / 0.94);
}
.ops-card::after {
  content: ""; position: absolute; top: 0; right: -2%;
  width: 46%; height: 100%; pointer-events: none;
  clip-path: polygon(26% 0, 100% 0, 68% 100%, 0 100%);
  background: linear-gradient(105deg, rgb(255 255 255 / 0.015) 0%,
    rgb(255 255 255 / 0.055) 18%, rgb(255 255 255 / 0.12) 50%,
    rgb(255 255 255 / 0.06) 74%, rgb(255 255 255 / 0.02) 100%);
  opacity: 0.6; mix-blend-mode: screen; z-index: 0;
}
.ops-card > * { position: relative; z-index: 1; }
.ops-card.pad { padding: 1rem; }

/* Stat tiles: two columns on a phone, four from 640px. Sized by the grid,
   not by their content, so every tile lands in the same place down the row. */
.ops-tiles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
             gap: 1rem; }
@media (min-width: 640px) {
  .ops-tiles { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.ops-tile .k { display: block; font-size: 10px; text-transform: uppercase;
               letter-spacing: 0.18em; color: var(--ops-dim); }
.ops-tile .v { display: block; margin-top: 0.25rem; font-family: var(--mono);
               font-size: 1.5rem; font-weight: 700;
               font-variant-numeric: tabular-nums; color: var(--ops-bright); }
.ops-tile .v.accent { color: #6ee7b7; }               /* emerald-300 */
.ops-tile .v.warn { color: #fcd34d; }                 /* amber-300 */

/* Controls. */
.ops-form { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center;
            padding: 0.75rem; }
.ops-form input, .ops-form select {
  font: inherit; font-size: 13px; padding: 0.5rem 0.625rem;
  border-radius: 0.5rem; color: var(--ops-bright);
  border: 1px solid rgb(255 255 255 / 0.15);
  background: rgb(255 255 255 / 0.04);
}
.ops-form input { flex: 1 1 12rem; min-width: 0; }
.ops-form input::placeholder { color: var(--ops-dim); }
.ops-form button, .ops-form .ops-btn { flex: 0 0 auto; }
.ops-btn {
  display: inline-flex; align-items: center; gap: 0.35rem;
  font: inherit; font-size: 13px; padding: 0.5rem 0.75rem; cursor: pointer;
  border-radius: 0.5rem; text-decoration: none;
  border: 1px solid rgb(255 255 255 / 0.15);
  background: rgb(255 255 255 / 0.05); color: var(--ops-text);
  transition: background 150ms ease, color 150ms ease, border-color 150ms ease;
}
.ops-btn:hover { background: rgb(255 255 255 / 0.10); color: var(--ops-bright); }
.ops-btn.primary { border-color: var(--ops-active-line);
                   background: var(--ops-active-fill); color: var(--ops-bright); }
.ops-btn.danger { border-color: rgb(248 113 113 / 0.35); color: #fca5a5; }
.ops-btn.danger:hover { background: rgb(248 113 113 / 0.10); color: #fecaca; }
.ops-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.ops-actions form { display: flex; gap: 0.35rem; align-items: center; }

/* A wide table on a phone scrolls inside its own card rather than pushing
   the page sideways. */
.ops-sheet-scroll { overflow-x: auto; }
.ops-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.ops-table th {
  text-align: left; font-size: 10px; font-weight: 400;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--ops-dim);
  padding: 0.75rem 1rem; white-space: nowrap;
}
.ops-table td { padding: 0.75rem 1rem; vertical-align: top;
                border-top: 1px solid rgb(255 255 255 / 0.05);
                color: var(--ops-text); }
.ops-table td a { color: var(--ops-bright); }
.ops-table td.num { font-family: var(--mono); font-size: 12px;
                    font-variant-numeric: tabular-nums; white-space: nowrap;
                    color: var(--ops-mute); }
.ops-table code { font-family: var(--mono); font-size: 12px; color: var(--ops-text); }
.ops-table .absent { display: block; font-size: 11px; font-style: normal;
                     color: var(--ops-dim); }
/* An empty-state row spans the table, so it must be told where to start -
   without this it drifts to the right edge and reads as a stray value. */
.ops-table td[colspan] { color: var(--ops-dim); text-align: left; }
/* The table already scrolls sideways inside its card, so the detail column
   gets a floor as well as a ceiling: without one it collapsed on a phone and
   drove every row three times taller than the text in it. */
.ops-detail { color: var(--ops-dim); min-width: 24ch; max-width: 34ch; }

/* Status and role read as pills, which is how the source distinguishes a
   state from a value. */
.ops-pill {
  display: inline-flex; align-items: center; border-radius: 999px;
  padding: 0.05rem 0.4rem; font-size: 9px; text-transform: uppercase;
  letter-spacing: 0.1em; border: 1px solid rgb(255 255 255 / 0.15);
  color: var(--ops-mute); white-space: nowrap;
}
.ops-pill.ok { border-color: rgb(74 222 128 / 0.30); color: #86efac;
               background: rgb(74 222 128 / 0.10); }
.ops-pill.off { border-color: rgb(255 255 255 / 0.12); color: var(--ops-dim); }
.ops-pill.warn { border-color: rgb(251 191 36 / 0.30); color: #fcd34d;
                 background: rgb(251 191 36 / 0.10); }
.ops-pill.owner { border-color: var(--ops-active-line); color: #a5b4fc;
                  background: var(--ops-active-fill); }

.ops-empty { padding: 1.5rem 1.25rem; font-size: 0.875rem; color: var(--ops-dim); }

/* The operator surface (ADMIN_OPERATOR_SPEC phase 1). */

/* An unreachable probe. Styled as a statement rather than an error, because
   "we could not ask" is information, not a fault. */
.ops-unavailable { margin: 0.5rem 0 0; font-size: 0.8125rem;
                   color: var(--ops-dim); font-style: italic; }
.ops-dim { color: var(--ops-dim); }
.ops-table b.ok, .ops-drift b.ok { color: #86efac; }
.ops-table b.bad, .ops-drift b.bad { color: #fca5a5; }

/* The attention queue. Severity is a 6px dot rather than a coloured row: the
   row still has to be readable, and three background tints down a list is the
   box-language sprawl the redesign lesson warns about.

   Every class here is `ops-` prefixed, including the ones that read fine
   unprefixed. A first pass used `.detail`, which the public site already
   defines at 1.5rem padding - so a one-line note rendered 69px tall inside a
   card that had nothing to do with it. Generic names in a shared stylesheet
   collide silently and the symptom appears nowhere near the cause. */
.ops-queue { list-style: none; margin: 0; padding: 0; }
.ops-queue li { display: flex; gap: 0.75rem; align-items: flex-start;
                padding: 0.875rem 1rem;
                border-top: 1px solid rgb(255 255 255 / 0.05); }
.ops-queue li:first-child { border-top: 0; }
.ops-queue .dot { flex: 0 0 auto; width: 6px; height: 6px; margin-top: 0.45rem;
                  border-radius: 999px; background: var(--ops-dim); }
.ops-queue li.high .dot { background: #f87171; box-shadow: 0 0 10px #f8717188; }
.ops-queue li.medium .dot { background: #fbbf24; }
.ops-queue li.low .dot { background: #78716c; }
.ops-queue b { display: block; font-size: 0.875rem; font-weight: 600;
               color: var(--ops-bright); }
.ops-queue .ops-rule { display: block; margin-top: 0.15rem; font-family: var(--mono);
                   font-size: 11px; color: var(--ops-dim); }
.ops-queue .ops-why { display: block; margin-top: 0.15rem; font-size: 0.75rem;
                     color: var(--ops-mute); }

.ops-drift { margin: 0; font-size: 0.9375rem; color: var(--ops-text); }
.ops-drift b { font-family: var(--mono); font-size: 1.25rem; }
.ops-identity { margin: 0; font-size: 0.875rem; color: var(--ops-text); }
.ops-identity a { color: var(--ops-bright); }

/* The sign-in has no bar and no rail: one card, centred on the same ground. */
.ops-gate { display: grid; place-items: center; min-height: 100vh;
            padding: 1.5rem 1rem; }
.ops-gate form { width: 100%; max-width: 22rem; display: flex;
                 flex-direction: column; gap: 0.75rem; }
.ops-gate .ops-brand { margin-bottom: 0.5rem; }
.ops-gate input {
  font: inherit; font-size: 0.875rem; padding: 0.625rem 0.75rem;
  border-radius: 0.5rem; color: var(--ops-bright);
  border: 1px solid rgb(255 255 255 / 0.15);
  background: rgb(255 255 255 / 0.04);
}
.ops-gate input::placeholder { color: var(--ops-dim); }
.ops-gate .ops-btn { justify-content: center; padding-block: 0.625rem; }
.ops-failed { margin: 0; font-size: 0.8125rem; color: #fca5a5; }
