/* Austin Home Search - a scanning surface, not a document.
 *
 * Palette is taken from the thing being searched for rather than from
 * dashboard convention: limestone paper, cedar green, and a sage-biased
 * neutral so the greys read as chosen rather than inherited. Copper is
 * reserved for one job - the "Needs research" flag - and is never used as
 * an accent, so a warning cannot be confused with emphasis.
 *
 * Every colour is a token on :root. The dark palette redefines only the
 * tokens, never the components, and is declared three times over: the OS
 * preference via prefers-color-scheme, plus explicit data-theme rules so a
 * viewer's own toggle wins in BOTH directions.
 */

:root {
  --paper:  #fbfaf8;
  --raised: #f2f1ec;
  --ink:    #16232a;
  --muted:  #5a6764;
  --accent: #2f5d4c;
  --accent-soft: #dbe6df;
  --line:   #e2e4de;
  --warn:   #9c5a24;
  --warn-bg:#f6ead9;
  --meter:  #a8c4b4;

  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, ui-serif, serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --step-0: 0.95rem;
  --step-1: 1.05rem;
  --step-2: 1.35rem;
  --step-3: 1.7rem;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper:  #0f1619;
    --raised: #172126;
    --ink:    #e7ece9;
    --muted:  #94a5a1;
    --accent: #8fc0aa;
    --accent-soft: #1e2f2a;
    --line:   #26343a;
    --warn:   #e0a869;
    --warn-bg:#2c2116;
    --meter:  #3f6656;
  }
}
:root[data-theme="dark"] {
  --paper:  #0f1619;
  --raised: #172126;
  --ink:    #e7ece9;
  --muted:  #94a5a1;
  --accent: #8fc0aa;
  --accent-soft: #1e2f2a;
  --line:   #26343a;
  --warn:   #e0a869;
  --warn-bg:#2c2116;
  --meter:  #3f6656;
}
:root[data-theme="light"] {
  --paper:  #fbfaf8;
  --raised: #f2f1ec;
  --ink:    #16232a;
  --muted:  #5a6764;
  --accent: #2f5d4c;
  --accent-soft: #dbe6df;
  --line:   #e2e4de;
  --warn:   #9c5a24;
  --warn-bg:#f6ead9;
  --meter:  #a8c4b4;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--sans);
  font-size: var(--step-0);
  line-height: 1.55;
  color: var(--ink);
  background: var(--paper);
  -webkit-text-size-adjust: 100%;
}

header {
  padding: 1.4rem 1.5rem 1rem;
  background: var(--raised);
}
header h1 {
  margin: 0;
  font-family: var(--serif);
  font-size: var(--step-3);
  font-weight: 600;
  letter-spacing: -.01em;
  color: var(--ink);
  text-wrap: balance;
}

/* The nav sits outside the header so it can stick to the viewport rather
   than only within the header's own box - a sticky child stops sticking the
   moment its parent scrolls away, which is the usual reason a "sticky" nav
   quietly isn't. --nav-h is what the sticky column headers below offset
   themselves by, so the two never overlap. */
:root { --nav-h: 2.9rem; }
nav {
  position: sticky; top: 0; z-index: 5;
  display: flex; flex-wrap: wrap; gap: .15rem;
  padding: 0 1.5rem;
  background: var(--raised);
  border-bottom: 1px solid var(--line);
}
nav a {
  padding: .55rem .9rem;
  text-decoration: none;
  color: var(--muted);
  font-size: .85rem;
  font-weight: 600;
  letter-spacing: .01em;
  border-bottom: 2px solid transparent;
}
nav a:hover { color: var(--ink); }
nav a.on { color: var(--accent); border-bottom-color: var(--accent); }

main { padding: 1.75rem 1.5rem; max-width: 68rem; margin: 0 auto; }

/* Two levels, deliberately far apart. A section title is the serif voice;
   a subhead inside it is a small sans label. When every section shares one
   page, headings that look alike make the page read as one long list. */
h2 {
  font-family: var(--sans);
  font-size: .74rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .09em;
  color: var(--muted);
  margin: 2.5rem 0 .6rem;
}
/* Scoped to a direct child of main - i.e. the standalone pages, where h2 is
   the first thing under the blurb. Left unscoped, `h2:first-of-type` (0,1,1)
   outranks `.page-title` (0,1,0) and would quietly re-add a top margin to
   every section title in the bundle. */
main > h2:first-of-type { margin-top: 1.75rem; }
/* A heading that introduces a second table on the same page needs to clear
   the table above it, not crowd its bottom border. */
.scroll + h2 { margin-top: 3rem; padding-top: 1.5rem; border-top: 1px solid var(--line); }
.blurb { margin: 0 0 1.4rem; color: var(--muted); max-width: 62ch; }
.subblurb { margin: 0 0 1rem; color: var(--muted); font-size: .84rem; max-width: 62ch; }

/* The italic-address key. Sits directly above the table it explains, not in
   the footer, so the mark and its meaning are visible at the same time. */
.legend {
  margin: 0 0 .8rem;
  padding: .55rem .75rem;
  border-left: 3px solid var(--accent);
  background: var(--raised);
  color: var(--muted);
  font-size: .8rem;
  max-width: 70ch;
  border-radius: 0 3px 3px 0;
}
.legend em { color: var(--ink); font-weight: 600; }

/* An italic address carries meaning, so it needs to look deliberate rather
   than like a rendering accident. */
table.listings td:first-child em {
  font-style: italic;
  color: var(--ink);
  border-bottom: 1px dotted var(--accent);
  cursor: help;
}

/* --- controls ------------------------------------------------------- */
.controls {
  display: flex; flex-wrap: wrap; gap: .85rem; align-items: center;
  padding: .85rem 1rem;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: 4px;
  margin-bottom: 1.1rem;
  font-size: .82rem;
}
.controls label {
  display: flex; gap: .4rem; align-items: center;
  color: var(--muted); text-transform: uppercase;
  letter-spacing: .06em; font-size: .7rem; font-weight: 600;
}
.controls input, .controls button, .controls select {
  font-family: var(--sans); font-size: .85rem;
  padding: .4rem .55rem;
  border: 1px solid var(--line); border-radius: 3px;
  background: var(--paper); color: var(--ink);
}
/* The sort column and its direction stay adjacent when the bar wraps -
   split across a line break they read as two unrelated controls. */
.sortbar { display: flex; gap: .5rem; align-items: center; flex-wrap: nowrap; }
.sort-dir { white-space: nowrap; }
.controls input[type="search"] { min-width: 15rem; }
.controls input[type="number"] { width: 6.5rem; font-family: var(--mono); font-variant-numeric: tabular-nums; }
.controls button { cursor: pointer; font-weight: 600; }
.controls button:hover { border-color: var(--accent); color: var(--accent); }
.count {
  margin-left: auto; color: var(--muted);
  font-family: var(--mono); font-size: .78rem; font-variant-numeric: tabular-nums;
}

/* The gap note belongs to the phone card layout, where a hidden empty cell
   would otherwise vanish without trace. In the desktop table an empty cell
   is a visible blank in a grid and needs no explaining, so this never
   renders there - it would be a spurious eleventh column. */
table.listings td.gaps { display: none; }

:where(a, button, input, th):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* --- table ---------------------------------------------------------- */
.scroll { overflow-x: auto; border: 1px solid var(--line); border-radius: 4px; }
table.listings { width: 100%; border-collapse: collapse; font-size: .88rem; }
table.listings th {
  text-align: left; white-space: nowrap; cursor: pointer;
  padding: .6rem .7rem;
  background: var(--raised); color: var(--muted);
  font-size: .7rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .07em;
  border-bottom: 1px solid var(--line);
}
/* The column header used to be `position: sticky; top: var(--nav-h)`. It sits
   inside .scroll, and `overflow-x: auto` makes overflow-y compute to auto as
   well - so .scroll is a scroll container on both axes and the header stuck
   to IT rather than to the viewport, ending up laid over adjacent content
   instead of scrolling with it. Two tables on More Options made it worse.
   The page nav is what stays put; the column header scrolls. */
table.listings th:hover { color: var(--accent); }
table.listings th.num, table.listings td.num { text-align: right; }
table.listings th[aria-sort="ascending"]::after  { content: " \2191"; color: var(--accent); }
table.listings th[aria-sort="descending"]::after { content: " \2193"; color: var(--accent); }
table.listings td {
  padding: .55rem .7rem;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}
table.listings tbody tr:last-child td { border-bottom: 0; }
table.listings tbody tr:hover { background: var(--accent-soft); }
table.listings td.num {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: .84rem;
}
table.listings td:first-child { font-weight: 600; min-width: 15rem; }
table.listings a { color: var(--accent); font-weight: 600; text-decoration: none; }
table.listings a:hover { text-decoration: underline; }

/* Score reads as a shape first, a number second. */
.score { display: inline-flex; flex-direction: column; align-items: flex-end; gap: .2rem; }
.score .fig { font-weight: 600; }
.meter { display: block; width: 3.5rem; height: 3px; background: var(--line); border-radius: 2px; overflow: hidden; }
.meter > span { display: block; height: 100%; background: var(--meter); }

.flag {
  display: inline-block;
  background: var(--warn-bg); color: var(--warn);
  padding: .12rem .45rem; border-radius: 3px;
  font-family: var(--sans); font-size: .72rem; font-weight: 600;
  letter-spacing: .02em; white-space: nowrap;
}

/* --- cards ---------------------------------------------------------- */
.cards { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }
.card {
  border: 1px solid var(--line); border-left: 3px solid var(--accent);
  border-radius: 4px; padding: 1rem; background: var(--raised);
  display: flex; flex-direction: column; gap: .4rem;
}
.card h3 {
  margin: 0; font-family: var(--sans); font-size: .68rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em; color: var(--muted);
}
.card .addr { margin: 0; font-family: var(--serif); font-size: var(--step-1); font-weight: 600; }
.card .why { margin: 0; color: var(--muted); font-size: .84rem; }
.card .meta {
  margin: 0; color: var(--muted); font-family: var(--mono);
  font-size: .76rem; font-variant-numeric: tabular-nums;
}
.card a { color: var(--accent); font-weight: 600; font-size: .84rem; text-decoration: none; margin-top: auto; }
.card a:hover { text-decoration: underline; }

footer {
  padding: 2rem 1.5rem 3.5rem; max-width: 68rem; margin: 0 auto;
  color: var(--muted); font-size: .8rem;
}
footer p { max-width: 62ch; margin: 0; }

/* Single-file bundle: one section at a time. With no JS every section
   shows - a long page, but a complete one. */
body.bundled .page { display: none; }
body.bundled .page.on { display: block; }

/* Section separation. With four sections stacked on one page, the boundary
   has to be unmistakable: a rule, real air on both sides of it, and a title
   in the serif voice with an accent bar - so a reader scrolling past knows
   they have crossed into a different list rather than a new heading in the
   same one. Class beats the `h2` element selector above, so these win
   without !important. */
.page + .page {
  margin-top: 4rem;
  padding-top: 2.75rem;
  border-top: 1px solid var(--line);
}
.page-title {
  position: relative;
  font-family: var(--serif);
  font-size: var(--step-3);
  font-weight: 600;
  text-transform: none;
  letter-spacing: -.01em;
  color: var(--ink);
  margin: 0 0 .5rem;
  padding-top: .95rem;
  text-wrap: balance;
}
.page-title::before {
  content: "";
  position: absolute; top: 0; left: 0;
  width: 2.75rem; height: 3px;
  background: var(--accent);
  border-radius: 2px;
}

/* When every section is on the page at once, the nav links are jump links.
   Without this the sticky bar covers the heading you just jumped to. */
.page { scroll-margin-top: calc(var(--nav-h) + .5rem); }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* --- phone ---------------------------------------------------------- */
@media (max-width: 760px) {
  /* Five links wrap to two rows on a phone, so anything offsetting itself
     from the sticky nav has to clear a taller bar. Measured in a browser,
     not estimated: 91px at 360-414px wide, with the 44px tap targets below.
     The narrower case is handled after this block. */
  :root { --nav-h: 5.75rem; }
  main, header, footer, nav { padding-left: 1rem; padding-right: 1rem; }
  header { padding-top: 1.1rem; padding-bottom: .8rem; }
  header h1 { font-size: var(--step-2); }
  .scroll { border: 0; overflow-x: visible; }
  table.listings thead { display: none; }
  table.listings, table.listings tbody, table.listings tr, table.listings td { display: block; width: 100%; }
  table.listings tr {
    border: 1px solid var(--line); border-radius: 4px;
    margin-bottom: .8rem; padding: .5rem .75rem; background: var(--raised);
  }
  table.listings tbody tr:hover { background: var(--raised); }
  table.listings td {
    border: 0; padding: .3rem 0;
    display: flex; justify-content: space-between; align-items: center; gap: 1rem;
  }
  table.listings td::before {
    content: attr(data-label);
    color: var(--muted); font-size: .68rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: .06em;
  }
  table.listings td:first-child {
    display: block; min-width: 0;
    font-family: var(--serif); font-size: var(--step-1);
    border-bottom: 1px solid var(--line);
    padding-bottom: .45rem; margin-bottom: .3rem;
  }
  table.listings td:first-child::before { content: ""; }
  /* An empty cell is a quiet blank in a desktop grid. Here it becomes a
     full-width row with a bold uppercase label and nothing beside it, so a
     discovery lead rendered as a stack of MATCH SCORE / ACRES / SQ FT with
     no values and read as broken data - though every one of those blanks is
     correct. They collapse, and .gaps below says which ones did. */
  table.listings td[data-empty] { display: none; }
  /* Sentence case, unlike the cell labels above it. This is a note to the
     reader, not another field name, and setting it in the same uppercase
     letter-spaced treatment made it read as a column that had lost its
     value - the exact confusion it exists to clear up. */
  table.listings td.gaps {
    display: block; border: 0;
    padding: .45rem 0 .1rem; margin-top: .25rem;
    border-top: 1px solid var(--line);
    color: var(--muted); font-size: .72rem; font-style: italic;
  }
  table.listings td.gaps::before { content: ""; }
  .score { flex-direction: row; align-items: center; gap: .5rem; }
  /* Wrapping flex put one filter per line, so the control bar ran nearly the
     full height of the screen and the first house was below the fold on
     every page. A three-column grid with the label stacked over its input
     fits the same controls in a third of the space. */
  .controls {
    display: grid; grid-template-columns: repeat(3, 1fr);
    gap: .6rem .5rem; align-items: end;
  }
  .controls > input[type="search"], .controls > .sortbar { grid-column: 1 / -1; }
  .controls > label { flex-direction: column; align-items: stretch; gap: .25rem; }
  .controls > label input[type="number"] { width: 100%; }
  .controls input[type="search"] { min-width: 0; }
  .controls > .reset { grid-column: 1 / 2; }
  .count {
    grid-column: 2 / -1; margin-left: 0;
    text-align: right; align-self: center;
  }
  .sortbar label { flex: 1; }
  .controls select { flex: 1; min-width: 0; }
}

/* Below about 360px the five nav links need a third row. Kept as its own
   block after the phone rules so it overrides them on source order, and set
   from a measurement at 320px rather than a guess - too small a value lands
   an in-page jump behind the sticky bar, hiding the heading it jumped to. */
@media (max-width: 359px) {
  :root { --nav-h: 8.75rem; }   /* measured 138px at 320px wide */
}

/* --- tap targets ----------------------------------------------------- */
/* Keyed to the pointer, not the viewport width. These were written into the
   760px phone block at first, which meant a touch tablet at 768px - wide
   enough for the real table, still driven entirely by a fingertip - got
   mouse-sized targets: 41px nav links and 22px row links. How big a target
   needs to be is a fact about the input device, not about how much room
   there is. 44px is the documented minimum. */
@media (pointer: coarse) {
  nav a { display: flex; align-items: center; min-height: 44px; }
  .controls input, .controls button, .controls select { min-height: 44px; }
  /* The two links are the whole point of a row - they are what the reader
     taps to go and look at the house. */
  table.listings td.link a {
    display: inline-flex; align-items: center; justify-content: flex-end;
    min-height: 44px; min-width: 44px; padding-left: .5rem;
  }
}

/* The drive-time basis note. Same key treatment, muted, because it explains
   a column rather than a mark. */
.legend.note {
  border-left-color: var(--muted);
  font-size: .78rem;
}
