/* PropertyLane. 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. */
.figs { display: flex; flex-wrap: wrap; gap: 0.15rem 1.2rem; margin-top: 0.45rem; }
.figs .f { display: flex; align-items: baseline; gap: 0.4rem; }
.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.75rem; color: var(--text-mute); }
.figs i.absent { font-size: 0.8125rem; }
/* 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; 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. PropertyLane 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; }
  .census-strip .stat { min-height: 2.9rem; padding: 0.6rem 0.7rem; }
  .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; }
.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; }

.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%);
                  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);
                  backdrop-filter: blur(20px) saturate(1.4); box-shadow: var(--shadow); }
.pl-explore .pl-layer-chips { left: 1.125rem; top: 1.125rem; transform: none; }
.pl-chip { 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 { color: var(--bg); font-weight: 620; background: var(--text); }
.pl-chip:not(.active):hover { color: var(--text); }
.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 { display: flex; gap: 0.25rem; padding: 0 1.25rem; border-bottom: 1px solid var(--hairline);
           overflow-x: auto; background: var(--chrome-soft); }
.pl-tabs a { padding: 0.7rem 0.7rem; font-size: 0.8125rem; color: var(--text-mute);
             text-decoration: none; border-bottom: 2px solid transparent; white-space: nowrap; }
.pl-tabs a[aria-current="page"] { color: var(--text); border-bottom-color: var(--accent); }
.pl-tabs a:hover { color: var(--text); }
.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-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; }

.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-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); }
