/* Auction House 24 design system.
   Five brand colours only: Porcelain, Slate Ink, Vivid Tangerine, Azure Blue, Neon Pink.
   Everything else here is a neutral derived from them. Type is the system sans; if a
   geometric face is ever licensed, swap --font once and the whole site follows. */
  :root {
    /* brand */
    --porcelain: #FDFFFC;
    --char: #23282F;
    --tang: #FF7F11;
    --azure: #007FFF;
    --pink: #F40076;
    /* derived surfaces */
    --bg: #EFF3F8;
    --panel: #FDFFFC;
    --sunk: #F5F7F9;
    --line: #E3E7EC;
    --ink: #23282F;
    --muted: #6B7280;
    --faint: #9AA2AE;
    --tang-soft: #FFF2E4;
    --azure-soft: #E8F2FF;
    --pink-soft: #FFE7F1;
    /* shape */
    --r-xl: 22px;
    --r-lg: 16px;
    --r-md: 11px;
    --r-sm: 8px;
    --shadow-sm: 0 1px 2px rgba(35,40,47,.05), 0 2px 8px rgba(35,40,47,.05);
    --shadow-md: 0 2px 6px rgba(35,40,47,.06), 0 12px 28px rgba(35,40,47,.08);
    --font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    /* One content column width for the whole site, plus the padding a full-bleed band needs
       to line its content up with that column. */
    --site-max: 94vw;
    --band-pad: calc(3vw + 24px);
    /* legacy aliases, kept so older rules and inline styles keep working */
    --accent: #FF7F11;
    --accent-soft: #FFF2E4;
    --green: #007FFF;
    --green-soft: #E8F2FF;
  }
  * { margin: 0; padding: 0; box-sizing: border-box; }
  html { -webkit-text-size-adjust: 100%; }
  body { font-family: var(--font); background: var(--bg); color: var(--ink);
    line-height: 1.55; -webkit-font-smoothing: antialiased; overflow-x: hidden; }
  .wrap { max-width: var(--site-max); margin: 0 auto; padding: 26px 24px 0; position: relative; z-index: 1;
    min-height: 100vh; display: flex; flex-direction: column; }
  /* Full-bleed bands: break out of .wrap to the viewport edges, then pad the content back to
     the site column so the hero, the community strip and the footer read as page background
     rather than floating cards. Only property cards and the small tiles stay boxed. */
  .hero, .strip, .sitefoot { margin-left: calc(-50vw + 50%); margin-right: calc(-50vw + 50%); }
  a { color: var(--azure); }

  /* ---------- brand lockup ----------
     The mark is drawn in CSS so every page gets it from the existing <h1> markup,
     with no per-page edit. Same artwork as /mark.svg. */
  header { display: flex; justify-content: space-between; align-items: center; gap: 16px;
    flex-wrap: wrap; padding: 4px 0 18px; }
  h1 { font-size: 27px; font-weight: 500; letter-spacing: -0.025em; line-height: 1; }
  /* the "Auction House" word and the "24" mark are each flex items; the lockup
     gap keeps them apart, so no gap is needed on the wordmark itself. */
  /* The mark is 24 on a tangerine tile, set in the site's own face, so there is
     no image to ship and it matches the favicon. */
  .lockup { display: inline-flex; align-items: baseline; gap: 9px; color: var(--ink); text-decoration: none; }
  .lockup .mark { background: var(--tang); color: var(--porcelain); border-radius: 10px;
    padding: 2px 12px 4px; font-weight: 700; letter-spacing: -0.025em; }
  .lockup .word { font-weight: 500; letter-spacing: -0.02em; }
  .tag { font-size: 13px; color: var(--muted); }
  /* A real header bar on the public pages: full-bleed, a warm tint, logo left, nav and a
     Contact call-to-action on the right. */
  .site-header { margin-top: -26px; margin-left: calc(-50vw + 50%); margin-right: calc(-50vw + 50%);
    margin-bottom: 0; padding: 14px var(--band-pad); background: #FDF3E7;
    border-bottom: 1px solid #F2DBC1; flex-wrap: nowrap; gap: 20px; }
  .site-header .brandmark { font-size: 24px; flex: 0 0 auto; }
  .site-header #nav { margin: 0 0 0 auto; flex: 0 0 auto; }
  .hdr-cta { flex: none; background: var(--tang); color: var(--porcelain); border: 0;
    border-radius: 999px; padding: 9px 22px; font-weight: 700; font-size: 14px; cursor: pointer;
    transition: background .15s, transform .12s; }
  .hdr-cta:hover { background: #E67200; transform: translateY(-1px); }
  @media (max-width: 640px) {
    .site-header { flex-wrap: wrap; gap: 10px 12px; padding: 12px var(--band-pad); }
    .site-header #nav { margin-left: 0; order: 3; width: 100%; }
    .hdr-cta { margin-left: auto; } }
  /* Contact modal */
  .modal-overlay { position: fixed; inset: 0; z-index: 100; background: rgba(20,24,29,.55);
    display: flex; align-items: center; justify-content: center; padding: 20px; }
  .modal-overlay[hidden] { display: none; }
  .modal { background: var(--panel); border-radius: var(--r-lg); padding: 28px 28px 26px;
    width: 100%; max-width: 440px; position: relative; box-shadow: var(--shadow-md); }
  .modal h2 { font-size: 22px; font-weight: 700; letter-spacing: -0.02em; color: var(--ink); }
  .modal-sub { color: var(--muted); font-size: 14px; margin: 6px 0 8px; line-height: 1.5; }
  .modal label { display: block; font-size: 11px; font-weight: 700; text-transform: uppercase;
    letter-spacing: .06em; color: var(--muted); margin: 14px 0 6px; }
  .modal textarea { resize: vertical; min-height: 92px; font-family: inherit; }
  .modal-x { position: absolute; top: 12px; right: 14px; background: none; border: 0;
    font-size: 26px; line-height: 1; color: var(--faint); cursor: pointer; }
  .modal-x:hover { color: var(--ink); }
  .modal-err { color: #D93636; font-size: 13px; margin-top: 8px; }
  .modal-actions { margin-top: 20px; }
  .wa-send { display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    background: #128C4A; color: #FFFFFF; border: 0; border-radius: 999px; font-weight: 700;
    cursor: pointer; transition: background .15s; }
  .wa-send:hover { background: #0F7A40; }
  .wa-send-lg { width: 100%; padding: 12px; font-size: 14.5px; }

  h2 { font-size: 12px; text-transform: uppercase; letter-spacing: 0.1em; font-weight: 800;
    color: var(--muted); margin-bottom: 14px; }
  h3 { font-size: 19px; font-weight: 650; letter-spacing: -0.015em; line-height: 1.3; }

  /* ---------- hero ---------- */
  .hero { position: relative; overflow: hidden; background: var(--char); color: var(--porcelain);
    padding: 52px var(--band-pad) 50px; margin-bottom: 34px;
    display: flex; gap: 40px; align-items: center; }
  .hero::before, .hero::after { content: ""; position: absolute; }
  .hero::before { width: 330px; height: 330px; right: -86px; top: -108px; border-radius: 50%; background: var(--azure); }
  /* the mark again, oversized and tilted: decoration that is still the brand */
  .hero::after { right: 34px; top: 120px; transform: rotate(-7deg);
    background: var(--tang); border-radius: 26px; padding: 10px 34px 18px;
    content: "24"; display: flex; align-items: center; justify-content: center;
    color: var(--porcelain); font-size: 62px; font-weight: 700; letter-spacing: -0.04em; }
  /* on a phone the disc stays fully saturated and tucks into the corner: dropping its
     opacity over the charcoal turned it muddy and put text on an unreadable ground */
  @media (max-width: 860px) { .hero::after { display: none; }
    .hero::before { width: 190px; height: 190px; right: -74px; top: -74px; }
    .hero .stats { gap: 16px 26px; }
    .hero p.lead { font-size: 32px; }
    .hero-bg::after { background: linear-gradient(180deg, rgba(35,40,47,.82) 0%, rgba(35,40,47,.55) 58%, rgba(35,40,47,.3) 100%); } }
  .hero > * { position: relative; z-index: 1; }
  /* A per-page background scene (skyline on the landing page, a blueprint on the directory)
     replaces the generic disc + oversized wordmark on any hero that carries its own art. */
  .hero:has(.hero-bg)::before, .hero:has(.hero-bg)::after { display: none; }
  .hero-bg { position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none;
    border-radius: var(--r-xl); }
  .hero-bg svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
  .hero-bg::after { content: ""; position: absolute; inset: 0;
    background: linear-gradient(102deg, rgba(35,40,47,.95) 0%, rgba(35,40,47,.62) 46%, rgba(35,40,47,.12) 100%); }
  .hero h2 { color: var(--tang); margin-bottom: 12px; }
  .hero p.lead { font-size: 42px; font-weight: 750; letter-spacing: -0.03em; line-height: 1.08;
    max-width: 20ch; margin-bottom: 14px; color: var(--porcelain); }
  .hero p.sub { font-size: 16px; color: rgba(253,255,252,.74); max-width: 46ch; }
  /* Landing hero is two columns: copy on the left, the trust markers as a stat card on the
     right, so the content spans the band instead of piling up on the left. */
  .hero-copy { flex: 1 1 auto; min-width: 0; }
  .hero-aside { flex: 0 0 auto; }
  .stats.vstats { flex-direction: column; gap: 0; margin-top: 0; align-items: stretch; text-align: left;
    background: rgba(22,26,32,.5); border: 1px solid rgba(253,255,252,.1); border-radius: 16px; padding: 2px 26px; }
  .stats.vstats .stat { padding: 15px 0; }
  .stats.vstats .stat + .stat { border-top: 1px solid rgba(253,255,252,.09); }
  .stats.vstats .stat b { font-size: 30px; }
  .stats.vstats .stat span { margin-top: 2px; }
  @media (max-width: 860px) {
    .hero { flex-direction: column; gap: 0; align-items: stretch; }
    .stats.vstats { flex-direction: row; gap: 16px 26px; margin-top: 24px; align-items: flex-start;
      background: none; border: 0; padding: 0; }
    .stats.vstats .stat { padding: 0; }
    .stats.vstats .stat + .stat { border-top: 0; } }
  /* Base (light-background) trust-marker stats, used as-is on the property page; the hero
     overrides below restore its dark-background treatment. Same markup, two contexts. */
  .stats { display: flex; gap: 28px; flex-wrap: wrap; margin-top: 26px; }
  .stat b { display: block; font-size: 24px; font-weight: 700; letter-spacing: -0.02em; color: var(--ink); }
  .stat span { font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.07em;
    color: var(--muted); font-weight: 600; }
  .hero .stat b { color: inherit; }
  .hero .stat span { color: rgba(253,255,252,.6); }
  /* Trust markers on a light panel (property page): coloured cards so the block reads as
     finished, and horizontal rather than a bare vertical stack. */
  .stats.trust { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-top: 0; }
  .stats.trust .stat { background: var(--sunk); border: 1px solid var(--line);
    border-radius: var(--r-md); padding: 15px 18px; }
  .stats.trust .stat b { font-size: 26px; }
  .stats.trust .stat:nth-child(1) b { color: var(--tang); }
  .stats.trust .stat:nth-child(2) b { color: var(--azure); }
  .stats.trust .stat:nth-child(3) b { color: var(--pink); }
  @media (max-width: 560px) { .stats.trust { grid-template-columns: 1fr; } }
  @media (max-width: 620px) { .hero { padding: 30px 22px; } .hero p.lead { font-size: 24px; } }

  /* ---------- surfaces ---------- */
  .panel { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg);
    padding: 22px; margin-bottom: 20px; box-shadow: var(--shadow-sm); }
  /* A content section that is part of the page, not a floating card. The only boxed things
     on the page are the property cards and the small tiles inside these sections. */
  .panel.flat { background: transparent; border: 0; box-shadow: none; padding: 0; margin-bottom: 30px; }
  /* Section titles (Closing soonest, FAQs) read as real headings, not the tiny hero eyebrow. */
  .panel.flat > h2, .panelhead h2 { font-size: 23px; font-weight: 700; letter-spacing: -0.02em;
    text-transform: none; color: var(--ink); }
  .panel.flat > h2 { margin-bottom: 16px; }
  .row { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 14px; }

  /* ---------- forms ---------- */
  label { display: block; font-size: 11px; text-transform: uppercase; letter-spacing: 0.07em;
    color: var(--muted); font-weight: 700; margin-bottom: 5px; }
  input, select, textarea { width: 100%; padding: 10px 13px; border: 1px solid var(--line);
    border-radius: var(--r-md); font-size: 14.5px; font-family: var(--font);
    background: var(--sunk); color: var(--ink); transition: border-color .15s, background .15s, box-shadow .15s; }
  input:hover, select:hover, textarea:hover { border-color: #cfd6de; }
  input:focus, select:focus, textarea:focus { outline: none; background: var(--panel);
    border-color: var(--azure); box-shadow: 0 0 0 3px rgba(0,127,255,.15); }
  textarea { resize: vertical; }
  .field-full { grid-column: 1 / -1; }
  .hint { font-size: 12.5px; color: var(--muted); margin-top: 9px; }

  /* ---------- buttons ---------- */
  button { font-family: var(--font); font-size: 13.5px; font-weight: 650; padding: 10px 20px;
    border-radius: 999px; border: 1px solid var(--char); background: var(--char);
    color: var(--porcelain); cursor: pointer; transition: transform .12s, box-shadow .15s, background .15s; }
  button:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); }
  button:active { transform: none; box-shadow: none; }
  button.ghost { background: transparent; color: var(--ink); border-color: var(--line); }
  button.ghost:hover { border-color: var(--char); }
  button.warm { background: var(--tang); border-color: var(--tang); color: #fff; }
  button.blue { background: var(--azure); border-color: var(--azure); color: #fff; }
  button.small { padding: 6px 14px; font-size: 12.5px; }
  button[disabled] { opacity: 0.5; cursor: default; transform: none; box-shadow: none; }
  .btnrow { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 16px; align-items: center; }
  .linklike { background: none; border: none; padding: 0; font: inherit; color: var(--azure);
    text-decoration: underline; cursor: pointer; border-radius: 0; }
  .linklike:hover { box-shadow: none; transform: none; }

  /* ---------- property cards ---------- */
  .card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg);
    padding: 22px; margin-bottom: 18px; box-shadow: var(--shadow-sm); }
  /* The directory lists cards in a responsive grid on wider screens rather than one long
     column of full-width rows. */
  /* One property-card grid, shared by the directory (#cards) and the landing gallery
     (#gallery). Cards stretch to equal height per row; the head stacks so the price sits
     under the address; the footer pins to the bottom. */
  .prop-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); gap: 18px; }
  .prop-grid .card { margin-bottom: 0; display: flex; flex-direction: column; }
  .prop-grid .card .cardfoot { margin-top: auto; }
  .prop-grid .card-head { flex-direction: column; gap: 8px; }
  .prop-grid .card-headtext { flex: 0 0 auto; }
  .prop-grid .card-head .price { margin-top: 2px; }
  @media (max-width: 560px) { .prop-grid { grid-template-columns: 1fr; } }
  /* "See all" as a matching card tile. */
  .seeall-card { align-items: center; justify-content: center; text-align: center; gap: 4px;
    text-decoration: none; background: var(--tang-soft); border-color: #FFD3A6; }
  .seeall-card .seeall-arrow { display: inline-flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; border-radius: 50%; background: var(--tang); color: var(--porcelain);
    font-size: 22px; font-weight: 700; margin-bottom: 8px; }
  .seeall-card b { font-size: 16.5px; color: var(--ink); }
  .seeall-card > span { font-size: 13px; color: var(--muted); max-width: 22ch; }
  .seeall-card:hover { background: #FFE7CE; border-color: #FFC489; box-shadow: var(--shadow-md); transform: translateY(-2px); }
  .card-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
  .card-headtext { flex: 1 1 260px; min-width: 0; }

  /* Property video poster. Only some listings have one, so it sits inside the head row
     and simply is not there for the rest, rather than reserving an empty band. */
  .vthumb { position: relative; display: block; flex: none; width: 168px; aspect-ratio: 16 / 10;
    border-radius: var(--r-md); overflow: hidden; background: var(--sunk);
    border: 1px solid var(--line); text-decoration: none; }
  .vthumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
  .vplay { position: absolute; inset: 0; margin: auto; width: 38px; height: 38px;
    border-radius: 50%; background: rgba(35,40,47,.72); }
  /* the triangle, drawn with borders so there is no second asset to ship */
  .vplay::after { content: ""; position: absolute; top: 50%; left: 52%; transform: translate(-50%,-50%);
    border-style: solid; border-width: 8px 0 8px 13px; border-color: transparent transparent transparent var(--porcelain); }
  .vthumb:hover .vplay { background: var(--tang); }
  @media (max-width: 560px) { .vthumb { width: 100%; aspect-ratio: 16 / 9; } }
  .card h3 { font-size: 20px; }
  .card .loc { color: var(--muted); font-size: 14px; }
  /* The address, when the notice gave one: a size step up from the plain .loc lines around
     it, since it is the one piece of "from the notice" detail worth its own emphasis now
     that it no longer gets a separate boxed section. */
  .card .loc-addr { color: var(--ink); font-size: 15px; margin: 4px 0; line-height: 1.45; }
  .price { font-size: 25px; font-weight: 750; letter-spacing: -0.03em; color: var(--tang); white-space: nowrap; }
  .price small { display: block; font-size: 10.5px; font-weight: 700; color: var(--muted);
    text-transform: uppercase; letter-spacing: 0.07em; }
  .facts { display: grid; grid-template-columns: repeat(auto-fill, minmax(155px, 1fr)); gap: 14px 20px;
    margin: 0; padding: 16px 18px; background: var(--azure-soft); border-radius: var(--r-md); }
  .fact b { display: block; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.07em;
    color: #5c7d9e; font-weight: 700; margin-bottom: 2px; }
  .fact span { font-size: 14.5px; font-weight: 550; }
  .fact.field-full { grid-column: 1 / -1; }

  /* ---------- section label above each of the card's three fact boxes ---------- */
  .factshead { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em;
    font-weight: 800; color: var(--muted); margin: 18px 0 8px; }
  .links { font-size: 13.5px; margin-bottom: 8px; }
  .links a { color: var(--azure); margin-right: 16px; font-weight: 600; }
  /* The card holds two links (the listing and the WhatsApp share), so the card itself is a
     div and the big clickable area is the anchor inside it. Nesting them would be invalid.
     The anchor then stretches over the whole card with an overlay, which is what makes the
     footer area clickable too; the share button and the video thumb sit above it. */
  .cardlink { position: relative; transition: box-shadow .18s, border-color .18s, transform .18s; }
  .cardlink:hover { border-color: #cfd6de; box-shadow: var(--shadow-md); transform: translateY(-2px); }
  a.cardbody { display: block; text-decoration: none; color: inherit; }
  a.cardbody::after { content: ""; position: absolute; inset: 0; border-radius: var(--r-lg); }
  a.cardbody:focus-visible { outline: 2px solid var(--azure); outline-offset: 4px; border-radius: var(--r-md); }
  .cardlink .vthumb, .cardlink .wa-share, .cardlink .cardfoot .links a { position: relative; z-index: 2; }
  .cardfoot { display: flex; align-items: center; justify-content: space-between;
    gap: 12px; flex-wrap: wrap; margin-top: 14px; }
  .viewmore { font-size: 13px; color: var(--azure); font-weight: 700; text-decoration: none; }
  .viewmore:hover { text-decoration: underline; }
  .cardfoot .links { margin-bottom: 0; }

  /* WhatsApp share. Its own green is deliberate: people recognise the badge, and a
     tangerine or azure button here would read as another Auction House 24 action. */
  .wa-share { display: inline-flex; align-items: center; gap: 7px; text-decoration: none;
    font-size: 12.5px; font-weight: 700; color: #128C4A; background: #E7F6EC;
    border: 1px solid #C4E7D1; border-radius: 999px; padding: 7px 14px;
    transition: background .15s, border-color .15s; }
  .wa-share:hover { background: #D8F0E1; border-color: #A9DCBC; }
  .wa-share svg { flex: none; }
  .msgbox { background: var(--azure-soft); border: 1px solid #cfe3fb; border-radius: var(--r-md);
    padding: 14px 16px; font-size: 13.5px; white-space: pre-wrap; margin-top: 12px; }

  /* ---------- tables ---------- */
  table { width: 100%; border-collapse: collapse; font-size: 13.5px; margin-top: 14px; }
  th { text-align: left; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.07em;
    color: var(--muted); font-weight: 700; border-bottom: 1px solid var(--line); padding: 8px 10px; }
  td { padding: 10px; border-bottom: 1px solid var(--line); vertical-align: top; }
  tbody tr:hover td { background: var(--sunk); }
  td a { color: var(--azure); }
  th.sortable { cursor: pointer; user-select: none; }
  th.sortable:hover { color: var(--ink); }
  tr.worked td { opacity: 0.55; }
  td select, td input { padding: 6px 10px; font-size: 12.5px; }
  .stars { color: var(--tang); white-space: nowrap; }

  /* ---------- status ---------- */
  .status { font-size: 13.5px; color: var(--azure); font-weight: 600; margin-top: 10px; }
  .status.err { color: var(--pink); }
  .empty { text-align: center; color: var(--muted); padding: 44px 0; }
  .toast { position: fixed; bottom: 26px; left: 50%; transform: translateX(-50%); background: var(--char);
    color: var(--porcelain); padding: 12px 24px; border-radius: 999px; font-size: 13.5px;
    box-shadow: var(--shadow-md); opacity: 0; transition: opacity .3s; pointer-events: none; z-index: 200; }
  .toast.show { opacity: 1; }

  /* ---------- pills ---------- */
  .pill { display: inline-block; font-size: 11px; font-weight: 700; letter-spacing: 0.01em;
    background: var(--azure-soft); color: var(--azure); border-radius: 999px;
    padding: 3px 11px; margin-left: 8px; vertical-align: 2px; }
  .pill.green { background: #E4F5EA; color: #157A45; }
  .pill.amber { background: var(--tang-soft); color: #b8560a; }
  .pill.grey  { background: #EDEFF2; color: var(--muted); }
  .pill.red   { background: var(--pink-soft); color: var(--pink); }
  /* Urgency-scaled deadline pill, stepped by urgencyPercent() through the same red-to-green
     spectrum a progress bar would (green calm, tangerine soon, red hot) -- there is no bar
     any more, but the colour logic that would have driven one still drives this. */
  .pill.urgcalm { background: #E4F5EA; color: #157A45; }
  .pill.urgwarm { background: var(--tang-soft); color: var(--tang); }
  .pill.urghot  { background: #FCE8E8; color: #DC2626; }

  /* ---------- fact sub-value ---------- */
  .fact .sub { display: block; font-size: 11.5px; font-weight: 600; color: var(--muted); margin-top: 1px; }

  /* ---------- copy link ---------- */
  .copylink { display: inline-flex; align-items: center; gap: 6px; }

  /* ---------- loading skeletons ----------
     Shape of the thing that is about to appear, not a spinner: a property card and its
     facts grid, so the layout does not jump once the real data lands. */
  @keyframes skel-shine { 0% { background-position: -180px 0; } 100% { background-position: 180px 0; } }
  .skel { background-color: var(--sunk); border-radius: var(--r-sm);
    background-image: linear-gradient(90deg, var(--sunk) 0px, var(--line) 45px, var(--sunk) 90px);
    background-size: 180px 100%; background-repeat: no-repeat; animation: skel-shine 1.2s ease-in-out infinite; }
  .skel-card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg);
    padding: 22px; margin-bottom: 18px; }
  .skel-line { height: 14px; margin-bottom: 12px; }
  .skel-line.w30 { width: 30%; } .skel-line.w40 { width: 40%; }
  .skel-line.w60 { width: 60%; } .skel-line.w80 { width: 80%; }
  .skel-block { height: 130px; margin-bottom: 16px; }

  /* ---------- nav ---------- */
  nav { display: flex; justify-content: space-between; align-items: center; gap: 12px;
    flex-wrap: wrap; margin-bottom: 24px; }
  nav .tabs { display: flex; gap: 4px; flex-wrap: wrap; background: var(--panel);
    border: 1px solid var(--line); border-radius: 999px; padding: 4px; box-shadow: var(--shadow-sm); }
  nav .tabs a { font-size: 13px; font-weight: 650; text-decoration: none; color: var(--muted);
    padding: 8px 16px; border-radius: 999px; transition: color .15s, background .15s; }
  nav .tabs a:hover { color: var(--ink); background: var(--sunk); }
  nav .tabs a[aria-current="page"] { color: var(--porcelain); background: var(--char); }
  nav .count { font-size: 11px; opacity: .7; font-weight: 500; }
  .whoami { font-size: 12.5px; color: var(--muted); }
  .whoami a, .whoami .linklike { color: var(--azure); }

  /* ---------- open / passed switch on the directory ---------- */
  .segtabs { display: inline-flex; gap: 4px; background: var(--panel); border: 1px solid var(--line);
    border-radius: 999px; padding: 4px; margin-bottom: 18px; box-shadow: var(--shadow-sm); }
  .segtabs button { background: transparent; border: none; color: var(--muted);
    padding: 8px 18px; border-radius: 999px; font-size: 13px; font-weight: 650; }
  .segtabs button:hover { box-shadow: none; transform: none; color: var(--ink); }
  .segtabs button[aria-pressed="true"] { background: var(--char); color: var(--porcelain); }
  .segtabs .n { opacity: .65; font-weight: 500; }

  /* ---------- search and filters ---------- */
  .searchbar { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr auto; gap: 12px; align-items: end; }
  @media (max-width: 980px) { .searchbar { grid-template-columns: 1fr 1fr; } }
  @media (max-width: 560px) { .searchbar { grid-template-columns: 1fr; } }
  /* Two filter rows on the directory: search+state+town, then sort+type+band+reset. Scoped
     above the existing 980px breakpoint so mobile keeps the plain .searchbar collapse above. */
  @media (min-width: 981px) {
    .searchbar.filters-row1 { grid-template-columns: 2fr 1fr 1fr; }
    .searchbar.filters-row2 { grid-template-columns: 1fr 1fr auto; }
  }
  .resultcount { font-size: 12.5px; color: var(--muted); margin-top: 14px; font-weight: 600; }

  /* ---------- notice source: a file or a link ---------- */
  .srcrow { display: grid; grid-template-columns: auto auto 1fr; gap: 16px; align-items: end; margin-top: 16px; }
  @media (max-width: 640px) { .srcrow { grid-template-columns: 1fr; } .srcor { text-align: left; } }
  .srcname { font-size: 12px; color: var(--muted); margin-top: 7px; }
  .srcor { font-size: 12.5px; color: var(--faint); padding-bottom: 11px; }
  details.settings summary { cursor: pointer; font-size: 13px; font-weight: 650; color: var(--muted); }

  /* ---------- admin card overflow menu ---------- */
  details.more { display: inline-block; vertical-align: top; }
  details.more summary { cursor: pointer; font-size: 13.5px; font-weight: 650; color: var(--azure);
    list-style: none; padding: 10px 16px; }
  details.more summary::-webkit-details-marker { display: none; }
  details.more[open] summary { color: var(--ink); }

  /* ---------- who to contact, on the property card ---------- */
  .brokerpanel { margin-top: 16px; padding: 14px 16px; background: var(--sunk);
    border: 1px solid var(--line); border-radius: var(--r-md); }
  .bp-head { font-size: 11px; text-transform: uppercase; letter-spacing: 0.07em;
    color: var(--muted); font-weight: 700; }
  .bp-head a { color: var(--azure); text-transform: none; letter-spacing: 0; margin-left: 10px; font-weight: 600; }
  /* A remark and its delete control. The delete stays quiet until hover, so a wall of
     remarks does not read as a wall of red buttons. */
  .rm-row { margin-top: 8px; display: flex; gap: 12px; justify-content: space-between; align-items: flex-start; }
  .rm-del { flex: none; background: none; border: 0; padding: 2px 6px; cursor: pointer;
    font-size: 12px; font-weight: 600; color: var(--faint); border-radius: var(--r-sm); }
  .rm-del:hover { color: #D93636; background: #FDECEC; }
  .bp-table { margin-top: 6px; }
  .bp-table td { border-bottom: 1px solid var(--line); padding: 8px 8px 8px 0; vertical-align: middle; }
  .bp-table tr:last-child td { border-bottom: none; }
  .bp-table tr:hover td { background: transparent; }
  .bp-table tr.done td { opacity: 0.5; }
  .bp-meta { font-size: 11.5px; color: var(--muted); margin-left: 8px; }
  .bp-actions { white-space: nowrap; text-align: right; }
  .bp-actions a, .bp-actions button { margin-left: 10px; font-size: 12px; color: var(--azure); }
  .rowlinks { margin-top: 4px; }
  .rowlinks a { font-size: 11.5px; color: var(--azure); margin-right: 12px; font-weight: 600; }
  #editorPanel textarea { min-height: 110px; }
  ol { line-height: 1.8; padding-left: 20px; }

  /* ---------- photos ---------- */
  .thumbrow { display: flex; gap: 10px; flex-wrap: wrap; margin: 12px 0; }
  .thumbrow img { width: 96px; height: 72px; object-fit: cover; border-radius: var(--r-sm); border: 1px solid var(--line); }
  .thumbwrap { position: relative; display: inline-block; }
  .thumbwrap.pending img { opacity: 0.6; border-style: dashed; }
  .thumb-x { position: absolute; top: -7px; right: -7px; width: 21px; height: 21px; padding: 0;
    border-radius: 50%; background: var(--char); color: var(--porcelain); border: none;
    font-size: 13px; line-height: 1; cursor: pointer; }
  .thumb-x:hover { transform: none; box-shadow: none; background: var(--pink); }
  .gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 12px; margin-bottom: 18px; }
  .gallery img { width: 100%; height: 158px; object-fit: cover; border-radius: var(--r-md); border: 1px solid var(--line); }

  /* ---------- contacts modal ---------- */
  .modal-backdrop[hidden] { display: none; }
  .modal-backdrop { position: fixed; inset: 0; background: rgba(35,40,47,.5); backdrop-filter: blur(2px);
    display: flex; align-items: flex-start; justify-content: center; padding: 6vh 16px; z-index: 100; }
  .modal-box { background: var(--panel); border-radius: var(--r-xl); max-width: 800px; width: 100%;
    max-height: 86vh; overflow-y: auto; padding: 26px 28px; box-shadow: 0 24px 60px rgba(35,40,47,.3); }
  .modal-head { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-bottom: 16px; }
  .modal-body table { margin-top: 0; }

  /* ---------- area map and nearby ---------- */
  .areamap { width: 100%; height: 340px; border: 1px solid var(--line); border-radius: var(--r-md);
    display: block; background: var(--sunk); overflow: hidden; z-index: 0; }
  /* Leaflet ships its own font stack and link colours; keep the map furniture in ours. */
  .leaflet-container { font-family: var(--font); background: var(--sunk); }
  .leaflet-control-attribution { font-size: 10.5px; }
  .leaflet-control-attribution a { color: var(--azure); }
  @media (max-width: 560px) { .areamap { height: 240px; } }
  /* Each category is its own card. Ragged columns of underlined lines read as a broken
     table; a card per category makes the grouping the obvious thing about the block. */
  .amens { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px;
    margin-top: 16px; align-items: start; }
  .amen { background: var(--sunk); border: 1px solid var(--line); border-radius: var(--r-md);
    padding: 14px 16px 12px; }
  .amen b { display: block; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.08em;
    color: var(--muted); font-weight: 700; margin-bottom: 9px; }
  .amen ul { list-style: none; padding: 0; margin: 0; }
  .amen li { font-size: 13.5px; padding: 4px 0; line-height: 1.4;
    display: flex; justify-content: space-between; gap: 10px; align-items: baseline; }
  .amen-r { color: var(--tang); font-weight: 700; font-size: 12px; white-space: nowrap; }

  /* ---------- landing page ---------- */
  .hero .cta { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 26px; }
  .hero .cta a { text-decoration: none; }
  /* inline-block, not inline-flex: flexbox trims the trailing space in the text node
     right before the <b>, which welded "charge" to "any" with no gap between them. */
  .hero .nocom { display: inline-block; margin-top: 22px;
    background: rgba(253,255,252,.12); border: 1px solid rgba(253,255,252,.22);
    border-radius: 999px; padding: 7px 16px; font-size: 13px; font-weight: 650;
    color: var(--porcelain); }
  .hero .nocom b { color: var(--tang); }
  /* Same pill component as the share button, sized up to sit next to .nocom. */
  .hero .wa-share { margin: 22px 0 0 10px; font-size: 13px; padding: 7px 16px; }

  .sell { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 16px;
    margin-bottom: 20px; }
  /* A secondary section under the listings: its own heading, and lighter tiles (sunk, no
     shadow) so the white property cards above stay the dominant grid. */
  .sell-title { font-size: 23px; font-weight: 700; letter-spacing: -0.02em; text-transform: none;
    color: var(--ink); margin: 6px 0 16px; }
  .sell .item { background: var(--sunk); border: 1px solid var(--line); border-radius: var(--r-lg);
    padding: 20px 22px; }
  .sell .item b { display: block; font-size: 16px; font-weight: 700; letter-spacing: -0.015em;
    margin-bottom: 6px; }
  .sell .item span { font-size: 13.5px; color: var(--muted); }
  .sell .item-icon { display: flex; align-items: center; justify-content: center;
    width: 34px; height: 34px; border-radius: 50%; background: var(--tang-soft); color: var(--tang);
    margin-bottom: 14px; }
  .sell .item-icon-text { font-size: 11px; font-weight: 800; }
  .sell .item:nth-child(2n) .item-icon { background: var(--azure-soft); color: var(--azure); }

  .panelhead { display: flex; justify-content: space-between; align-items: baseline;
    gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
  .panelhead h2 { margin-bottom: 0; }
  .panelhead a { font-size: 13px; font-weight: 700; text-decoration: none; }

  /* Gallery cards on the landing page: smaller than a directory row, same information order. */
  .gallery-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(272px, 1fr)); gap: 16px; align-items: start; }
  .gcard { position: relative; background: var(--panel); border: 1px solid var(--line);
    border-radius: var(--r-lg); padding: 18px; color: inherit;
    box-shadow: var(--shadow-sm); transition: box-shadow .18s, border-color .18s, transform .18s; }
  .gcard:hover { border-color: #cfd6de; box-shadow: var(--shadow-md); transform: translateY(-2px); }
  .gcard { display: flex; flex-direction: column; }
  .gcard .vthumb { width: 100%; aspect-ratio: 16 / 10; margin-bottom: 14px; z-index: 2; }
  /* Only some listings have a video, so the cards in a row differ in height. Pushing the
     deadline line to the bottom lines them up instead of leaving one card half empty. */
  a.gcardbody { display: flex; flex-direction: column; flex: 1; text-decoration: none; color: inherit; }
  .gcard .when { margin-top: auto; padding-top: 8px; }
  a.gcardbody::after { content: ""; position: absolute; inset: 0; border-radius: var(--r-lg); }
  a.gcardbody:focus-visible { outline: 2px solid var(--azure); outline-offset: 4px; border-radius: var(--r-md); }
  .gcard h3 { font-size: 16.5px; margin-bottom: 2px; }
  .gcard .loc { font-size: 13px; color: var(--muted); }
  .gcard .price { font-size: 21px; margin-top: 12px; }
  .gcard .when { font-size: 12.5px; color: var(--muted); margin-top: 8px; }
  .gcard .when b { color: var(--ink); font-weight: 650; }
  /* "See all" as a full tile beside the property cards, not a small side link. */
  .gcard-cta { align-items: center; justify-content: center; text-align: center; text-decoration: none;
    background: var(--tang-soft); border-color: #FFD3A6; gap: 4px; min-height: 156px; }
  .gcard-cta .gcard-cta-arrow { display: inline-flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; border-radius: 50%; background: var(--tang); color: var(--porcelain);
    font-size: 22px; font-weight: 700; margin-bottom: 8px; }
  .gcard-cta b { font-size: 16.5px; color: var(--ink); }
  .gcard-cta > span { font-size: 13px; color: var(--muted); max-width: 22ch; }
  .gcard-cta:hover { background: #FFE7CE; border-color: #FFC489; box-shadow: var(--shadow-md); transform: translateY(-2px); }

  .strip { background: var(--char); color: var(--porcelain);
    padding: 44px var(--band-pad); margin-top: 34px; margin-bottom: 34px; display: flex; gap: 20px;
    flex-wrap: wrap; align-items: center; justify-content: space-between; }
  .strip h2 { color: var(--tang); margin-bottom: 8px; }
  .strip p { font-size: 20px; font-weight: 550; letter-spacing: -0.02em; max-width: 34ch; }
  .strip p span { color: var(--tang); }
  /* WhatsApp community strip: fill the empty right side with the mark in WhatsApp green,
     and lead the heading in the same green so the block reads as a WhatsApp invite. */
  .wa-strip { gap: 40px; align-items: center; justify-content: center; }
  .wa-strip-body { flex: 0 1 440px; }
  .wa-strip-body p { max-width: none; }
  .wa-strip h2 { display: inline-flex; align-items: center; gap: 9px; color: #25D366; }
  .wa-strip h2 svg { width: 22px; height: 22px; }
  /* A little chat preview instead of a lone logo: shows what the community actually
     sends, reads unmistakably as WhatsApp, and stacks cleanly under the text on mobile. */
  .wa-chat { flex: 0 0 300px; max-width: 100%; display: flex; flex-direction: column; gap: 8px;
    background: rgba(37,211,102,.08); border: 1px solid rgba(37,211,102,.2);
    border-radius: var(--r-lg); padding: 14px; }
  .wa-bubble { align-self: flex-start; max-width: 90%; background: #EFF3F4; color: #23282F;
    font-size: 12.5px; font-weight: 500; line-height: 1.4; padding: 8px 12px;
    border-radius: 4px 12px 12px 12px; box-shadow: 0 1px 1px rgba(0,0,0,.15); }
  .wa-bubble.wa-me { align-self: flex-end; background: #DCF8C6; color: #0B3D1E;
    border-radius: 12px 4px 12px 12px; }
  @media (max-width: 700px) { .wa-strip { justify-content: flex-start; }
    .wa-strip-body { flex-basis: auto; } .wa-chat { flex-basis: auto; width: 100%; } }
  .wa-strip-cta { margin-top: 18px; }
  .wa-strip-cta:empty { display: none; }
  .wa-join { display: inline-flex; align-items: center; gap: 8px; text-decoration: none;
    background: #25D366; color: #0A2417; font-weight: 700; font-size: 14px;
    border-radius: 999px; padding: 11px 20px; transition: background .15s; }
  .wa-join:hover { background: #1FBE5A; }
  .wa-join svg { width: 18px; height: 18px; }
  @media (max-width: 620px) { .wa-strip-logo { display: none; } }

  .faq { display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: 14px; margin-top: 18px; }
  .faq-item { background: var(--sunk); border: 1px solid var(--line); border-radius: 14px; padding: 18px 20px; }
  .faq-item h3 { font-size: 15.5px; font-weight: 700; color: var(--ink); line-height: 1.35; }
  .faq-item h3 .qmark { display: inline-flex; align-items: center; justify-content: center; width: 24px;
    height: 24px; border-radius: 7px; background: var(--tang-soft); color: var(--tang); font-weight: 800;
    font-size: 13px; margin-right: 10px; vertical-align: -5px; }
  .faq-item p { color: var(--muted); font-size: 14px; margin-top: 10px; line-height: 1.55; }

  /* ---------- footer ----------
     Charcoal, so the page ends on the brand rather than fading out, and so the bank's
     number and the address are somewhere a buyer can find on any page. Markup comes from
     renderSiteFooter() in app-shell.js: one copy of this copy, not one per page. */
  .sitefoot { margin-top: auto; background: var(--char); color: var(--porcelain);
    padding: 48px var(--band-pad) 30px; font-size: 13.5px; }
  .foot-in { display: grid; grid-template-columns: 2fr 1.2fr 1fr; gap: 28px 40px; }
  @media (max-width: 760px) { .foot-in { grid-template-columns: 1fr; gap: 24px; }
    .sitefoot { padding: 34px var(--band-pad) 20px; } }
  .foot-brand .lockup { color: var(--porcelain); font-size: 23px; }
  .foot-brand p { margin-top: 12px; color: rgba(253,255,252,.66); max-width: 54ch; line-height: 1.6; }
  .foot-brand .foot-wa { display: flex; align-items: center; gap: 7px; color: rgba(253,255,252,.5); font-size: 12.5px; }
  .foot-col b { display: block; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.09em;
    color: var(--tang); margin-bottom: 10px; }
  .foot-col a, .foot-col span { display: block; color: rgba(253,255,252,.8); text-decoration: none;
    margin-bottom: 7px; line-height: 1.5; }
  .foot-col a:hover { color: var(--tang); }
  .foot-base { margin-top: 26px; padding-top: 16px; border-top: 1px solid rgba(253,255,252,.14);
    display: flex; gap: 14px; flex-wrap: wrap; justify-content: space-between; align-items: center;
    font-size: 12px; color: rgba(253,255,252,.5); }
  /* Operator sign in lives here rather than in the nav: on-ground staff are told to look
     at the bottom of any page, and a buyer arriving from WhatsApp never trips over it. */
  .foot-op { color: rgba(253,255,252,.6); text-decoration: none;
    border: 1px solid rgba(253,255,252,.22); border-radius: 999px; padding: 5px 14px; font-weight: 600; }
  .foot-op:hover { color: var(--char); background: var(--porcelain); border-color: var(--porcelain); }
  /* Legal positioning line, fine print above the base row. */
  .foot-legal { margin-top: 22px; color: rgba(253,255,252,.42); font-size: 11.5px;
    line-height: 1.65; max-width: 96ch; }
  /* WhatsApp community links (brand column + base row) in WhatsApp green on the charcoal. */
  .foot-brand .foot-wa { margin-top: 14px; color: #25D366; font-weight: 600; text-decoration: none; }
  a.foot-wa:hover, .foot-base-wa:hover { color: #4BE585; }
  .foot-base-wa { display: inline-flex; align-items: center; gap: 7px; color: #25D366;
    font-weight: 600; text-decoration: none; }
  .foot-base-wa svg { width: 14px; height: 14px; flex: none; }
  .foot-legal + .foot-base { margin-top: 16px; }
  .made-in { display: inline-flex; align-items: center; gap: 6px; }
  .in-flag { border-radius: 2px; box-shadow: 0 0 0 1px rgba(255,255,255,.15); }
