/* ── PROPERTY-CONTEXT SIDEBAR ───────────────────────────────────────────────
 *
 * Dom 2026-08-29: "they would see the progress, edits, clients requests, SPW
 * status and MC too, Media, download page, and all that needs to be to make the
 * work ultra easy and flowless / fun", and "The selector can extend to the
 * right. Make it look and work like Silicon Valley gurus would do it."
 *
 * Two pieces, both in the agent rail's lower half:
 *   · the SELECTOR — the property in play, as a compact card;
 *   · the SCOPED GROUP — the tools for THAT property, and nothing else.
 * Clicking the selector opens a flyout to the RIGHT of the rail.
 *
 * OWN SHEET, by the same rule the composer sheet follows: main.css and
 * agent-dash.css belong to other lanes right now, so nothing here edits them.
 * Everything is scoped to `.pr-*` so it cannot leak onto another surface.
 *
 * WHY THE FLYOUT IS NOT A CHILD OF THE RAIL
 * `.ag-rail` is `overflow-y: auto; overflow-x: hidden` (main.css:7490). A panel
 * that extends to the right from inside it would be CLIPPED at 238px — the one
 * thing the brief asks for is the one thing that container cannot do. So the
 * flyout is rendered as a sibling, `position: fixed`, anchored at the rail's
 * right edge. It is 320px wide starting at 238px, so it ends around 558px and
 * cannot reach the co-op dock pill (fixed, right: 22px, z-index 9000).
 *
 * TOKENS ONLY: the shared ground/line/ink/radius/spacing/motion scales, plus
 * --lcx-green (the Composer's identity green, defined in listing-composer.css)
 * for the one entry that carries it.
 */

/* ── The block inside the rail ────────────────────────────────────────────
 * Sits after the global nav and before `.ag-rail-display`, whose `margin-top:
 * auto` keeps the theme control and the identity block pinned to the bottom —
 * so this lands in the rail's lower half exactly as asked, without moving
 * anything that was already there. */
.pr-ctx {
  padding: var(--sp-3) var(--sp-4) 0;
  border-top: 1px solid var(--line);
  margin-top: var(--sp-3);
}
.pr-ctx-label {
  display: block;
  margin: var(--sp-2) 0 var(--sp-2) 12px;
  font-size: calc(12px * var(--text-scale, 1));
  font-weight: 600;
  color: var(--ink-3);
}

/* ── The current-property card ────────────────────────────────────────────
 * A control, so it reads as one: full width, hairline, hover, focus ring. */
.pr-current {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  padding: var(--sp-2);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--bg);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.pr-current:hover { background: var(--bg-hover); border-color: var(--line-strong, var(--line)); }
.pr-current:focus-visible { outline: 2px solid var(--focus-ring-c); outline-offset: -2px; }
.pr-current[aria-expanded="true"] { border-color: var(--line-strong, var(--line)); background: var(--bg-hover); }

/* The thumbnail. A fixed box with a ground and an aspect ratio, so the row is
   its final height BEFORE the image arrives — no layout shift, ever. */
.pr-thumb {
  flex: none;
  width: 36px;
  aspect-ratio: 4 / 3;
  border-radius: var(--r-1);
  overflow: hidden;
  background: var(--bg-sunken);
  display: block;
}
.pr-thumb img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  opacity: 0;
  transition: opacity var(--t-base) var(--ease);
}
.pr-thumb img.is-in { opacity: 1; }

/* NO COVER PHOTO YET. Freshly ingested listings have none, and an empty dark
   box is both uninformative and identical between properties — which is most
   of why switching between two of them read as "nothing happened". The address
   initial is a real mark, needs no network, and cannot fail to load. */
.pr-thumb.is-blank {
  display: grid;
  place-items: center;
  background: var(--bg-sunken);
  color: var(--ink-3);
  font-size: calc(15px * var(--text-scale, 1));
  font-weight: 700;
  line-height: 1;
  user-select: none;
}

/* "THIS CHANGED." One ring, drawn on and faded out, when a property is picked
   on a page that has nowhere to navigate to. Same vocabulary as the composer's
   remote-edit ring: no bounce, no scale, and nothing at all under
   prefers-reduced-motion, where the ring simply appears and goes. */
@keyframes pr-flash {
  0%   { box-shadow: 0 0 0 0   color-mix(in srgb, var(--brand) 45%, transparent); }
  18%  { box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 45%, transparent); }
  100% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand)  0%, transparent); }
}
.pr-ctx.is-flash {
  border-radius: var(--r-2);
  animation: pr-flash 1200ms var(--ease) forwards;
}
@media (prefers-reduced-motion: reduce) {
  .pr-ctx.is-flash { animation: none; box-shadow: var(--shadow-focus); }
}

.pr-cur-txt { min-width: 0; flex: 1 1 auto; }
.pr-cur-addr {
  display: block;
  font-size: calc(13px * var(--text-scale, 1));
  font-weight: 600;
  letter-spacing: -.01em;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pr-cur-caret { flex: none; width: 14px; height: 14px; color: var(--ink-3); }

/* ── The scoped group ─────────────────────────────────────────────────────
 * Everything under the selector belongs to the selected property. Same row
 * anatomy as the global rail above it, deliberately: this is still the rail,
 * it is just narrowed to one listing. */
.pr-scoped {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: var(--sp-2);
  padding-bottom: var(--sp-3);
}
.pr-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 9px 12px;
  border-radius: var(--r-btn);
  color: var(--ink-2);
  text-decoration: none;
  font-size: calc(13.5px * var(--text-scale, 1));
  font-weight: 500;
  letter-spacing: -.01em;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.pr-item:hover { background: var(--bg-hover); color: var(--ink); }
.pr-item.is-active { background: var(--bg-hover); color: var(--ink); font-weight: 600; }
/* The SAME 3px marker every rail item uses, in the same place. One vocabulary
   for "you are here" across the whole rail. */
.pr-item.is-active::before {
  content: "";
  position: absolute; left: -16px; top: 50%;
  transform: translateY(-50%);
  width: 3px; height: 20px;
  border-radius: 0 3px 3px 0;
  background: var(--brand);
}
.pr-item:focus-visible { outline: 2px solid var(--focus-ring-c); outline-offset: -2px; }
.pr-item svg { width: 15px; height: 15px; flex: none; color: var(--ink-3); }
.pr-item:hover svg, .pr-item.is-active svg { color: var(--ink); }
.pr-item-txt { min-width: 0; flex: 1 1 auto; }
.pr-item-name { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The status line under an entry. It carries INFORMATION, so it sits on the
   secondary ink rung, never the muted one — and it only renders when there is
   a real fact to put in it. */
.pr-item-fact {
  display: block;
  margin-top: 1px;
  font-size: calc(11.5px * var(--text-scale, 1));
  font-weight: 500;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* THE COMPOSER ENTRY — green identity, never a resting fill.
 * Dom 2026-08-29: "Listing composer when is green is confusing... I'm on a
 * different page and I think I'm on the listing composer when I look at the
 * sidebar." A filled row IS the rail's word for "you are here", so the tool's
 * colour is carried by the icon and the label instead, and the ACTIVE state is
 * the standard one every other row uses. Identity and location stay separate
 * signals. */
.pr-item.is-compose { color: var(--lcx-green); font-weight: 600; }
.pr-item.is-compose svg { color: var(--lcx-green); }
.pr-item.is-compose:hover { background: var(--bg-hover); color: var(--lcx-green); }
.pr-item.is-compose:hover svg { color: var(--lcx-green); }
.pr-item.is-compose.is-active { background: var(--bg-hover); color: var(--lcx-green); }
.pr-item.is-compose.is-active svg { color: var(--lcx-green); }
/* The identity survives into the active state through the marker only — same
   shape, same position, same meaning as every other item's. */
.pr-item.is-compose.is-active::before { background: var(--lcx-green); }
.pr-item.is-compose:focus-visible { outline-color: var(--lcx-green); }

/* A count worth noticing (client requests). Never a bare colour: it is a
   number in a chip, and the chip is only drawn when the number is real. */
.pr-badge {
  flex: none;
  min-width: 18px;
  padding: 1px 6px 2px;
  border-radius: var(--r-btn);
  background: var(--bg-sunken);
  color: var(--ink-2);
  font-size: calc(11.5px * var(--text-scale, 1));
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: center;
}

/* ── The flyout ───────────────────────────────────────────────────────────
 * Anchored to the rail's right edge, never inside it. z-index sits above the
 * rail (60) and the topbar (55), and far below the co-op dock (9000), which it
 * cannot reach anyway: this panel ends around x=558. */
.pr-flyout {
  position: fixed;
  left: 238px;
  z-index: 61;
  width: 320px;
  max-width: calc(100vw - 250px);
  display: flex;
  flex-direction: column;
  max-height: min(560px, calc(100dvh - 32px));
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-2, var(--shadow-1));
  overflow: hidden;
  animation: pr-fly-in 170ms var(--ease-out);
}
.pr-flyout[hidden] { display: none; }
/* A short rise and fade — the portal's quiet vocabulary. Nothing springs. */
@keyframes pr-fly-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .pr-flyout { animation: none; }
  .pr-thumb img { transition: none; }
}

.pr-fly-head {
  flex: none;
  padding: var(--sp-3);
  border-bottom: 1px solid var(--line);
}
.pr-filter {
  width: 100%;
  padding: 8px 12px 9px;          /* 1px deeper at the bottom: optical centring */
  border: 1px solid var(--line);
  border-radius: var(--r-btn);
  background: var(--bg);
  color: var(--ink);
  font: inherit;
  font-size: calc(13px * var(--text-scale, 1));
  outline: none;
}
.pr-filter::placeholder { color: var(--ink-3); }
.pr-filter:focus-visible { box-shadow: var(--shadow-focus); }

/* The list. Scrolls inside its own box — the page behind is never touched, and
   nothing here changes scroll behaviour. */
.pr-fly-list {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: var(--sp-2);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.pr-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  padding: var(--sp-2);
  border: 0;
  border-radius: var(--r-2);
  background: none;
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
/* Hover and keyboard cursor are the SAME visual: the arrow keys move a real
   highlight, not an invisible one. */
.pr-row:hover, .pr-row.is-cursor { background: var(--bg-hover); }
.pr-row:focus-visible { outline: 2px solid var(--focus-ring-c); outline-offset: -2px; }
.pr-row.is-current { background: var(--bg-hover); }
.pr-row-txt { min-width: 0; flex: 1 1 auto; }
.pr-row-addr {
  display: block;
  font-size: calc(13px * var(--text-scale, 1));
  font-weight: 600;
  letter-spacing: -.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pr-row-sub {
  display: block;
  margin-top: 1px;
  font-size: calc(11.5px * var(--text-scale, 1));
  color: var(--ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* The tick on the row you are already on. */
.pr-row-on { flex: none; width: 14px; height: 14px; color: var(--ink-2); }

/* Empty and no-match states. Honest sentences, never a padded blank. */
.pr-empty {
  padding: var(--sp-6) var(--sp-4);
  text-align: center;
}
.pr-empty h4 {
  margin: 0 0 var(--sp-2);
  font-size: calc(14px * var(--text-scale, 1));
  font-weight: 600;
  color: var(--ink);
}
.pr-empty p {
  margin: 0 0 var(--sp-4);
  font-size: calc(13px * var(--text-scale, 1));
  color: var(--ink-2);
  line-height: 1.5;
}
.pr-empty p:last-child { margin-bottom: 0; }

/* THE SCOPE-PIN CAPTION (Dom 2026-08-29, admin only). While the "GV only" pin
 * is on, the selector lists Grapevine properties only — and it says so, right
 * above the list, because a roster that is quietly short is indistinguishable
 * from a roster that is broken. It is a caption, not an option: no hover, no
 * hit area, and `paintCursor` walks `.pr-row` so the arrow keys skip it. */
.pr-scope-note {
  padding: var(--sp-2) var(--sp-2) var(--sp-1);
  font-size: calc(11px * var(--text-scale, 1));
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* ── The collapsed rail ──────────────────────────────────────────────────
 * At <=900px main.css:7648-7661 narrows the rail to 58px and hides every
 * label (`.ag-rail-item span`), the theme block and the identity block. This
 * block has to collapse WITH it or it would be the one thing still shouting
 * text in a 58px column — the rule lives here because main.css belongs to
 * another lane right now.
 *
 * What survives the collapse is what still works at that width: the
 * thumbnail (which IS the property, and is still a button that opens the
 * flyout) and the scoped icons. */
@media (max-width: 900px) {
  .pr-ctx { padding: var(--sp-3) 6px 0; }
  .pr-ctx-label { display: none; }
  .pr-current { padding: 4px; justify-content: center; }
  .pr-cur-txt, .pr-cur-caret { display: none; }
  .pr-thumb { width: 34px; }
  .pr-item { padding: 11px 0; justify-content: center; }
  .pr-item-txt, .pr-badge { display: none; }
  .pr-item.is-active::before { left: -6px; }

  /* The flyout anchors to the collapsed rail's edge, not to a 238px one that
     is no longer there, and takes the width it can actually have. */
  .pr-flyout {
    left: 64px;
    right: var(--sp-3);
    width: auto;
    max-width: none;
  }
}

/* ── THE SELLER'S RAIL ─────────────────────────────────────────────────────
 *
 * Dom 2026-08-29: the share view "is missing the sidebar - not good." Then, on
 * the first attempt at one: "This is BS sidebar revert our look and just make
 * the sidebar hide so we can see only icons not texts."
 *
 * SO THERE IS NO SELLER RAIL LOOK. components/seller-rail.js renders the AGENT
 * rail's markup — `.ag-rail`, `.ag-rail-brand`, `.ag-rail-nav`,
 * `.ag-rail-item`, `.ag-rail-mini-btn`, and the property block's `.pr-ctx` /
 * `.pr-current` / `.pr-thumb` — so every pixel of its look comes from the rules
 * that already paint the agent side (main.css:7500-7558 and the top of this
 * file). Nothing below restyles any of it.
 *
 * What IS left for this block, and only this:
 *   1. the PAGE INSET while the rail is mounted. The share view has no
 *      `body:has(#app-nav.ag-chrome)` chrome, so main.css:7493 never fires and
 *      the inset has to be keyed off `html.has-seller-rail` instead. 238px, and
 *      NO 54px top pad — there is no topbar on a share view, and reserving room
 *      for one is exactly the dead strip this lane is measuring against.
 *   2. the two seller-only rows inside the rail's property card (the brokerage
 *      line and the read-only status chip).
 *   3. the ON-PURPOSE collapse, restating the agent rail's own 900px rules at
 *      any width — the same route `html.has-agent-rail-mini` takes further down
 *      this file, so nobody meets two different narrow rails.
 *
 * The GV purple skin flows through `--brand` exactly as it does everywhere
 * else, and both themes come free because nothing here paints a raw colour.
 */
html.has-seller-rail body { padding-left: 238px; }

/* The card is a CARD on this side: a seller has no second property to switch
   to, so the control affordances come off and nothing else changes. */
.sr-rail .pr-current.is-static { cursor: default; }
.sr-rail .pr-current.is-static:hover {
  background: var(--bg);
  border-color: var(--line);
}
/* First block under the brand — its divider is the brand's, so the card's own
   top rule would double it. */
.sr-rail .pr-ctx { border-top: 0; margin-top: 0; }

/* Only ever the brokerage the LISTING carries. Absent when the record has none. */
.sr-brand {
  display: block;
  margin-top: 2px;
  font-size: calc(12px * var(--text-scale, 1));
  font-weight: 500;
  color: var(--ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A brokerage's own mark is not our logo file and has no light/dark twin, so it
   is shown as supplied and simply fitted to the brand slot's height. */
.sr-rail-logo-brand { display: block; height: 30px !important; width: auto !important; max-width: 100%; }

/* THE TOGGLE SITS AT THE FOOT, as it does on the agent rail. There, the foot
   anchoring comes from `.ag-rail-display { margin-top: auto }` (main.css:7564)
   pushing the identity block and the toggle down; this rail has no theme block
   and no identity block to do the pushing, so the toggle carries the same
   `margin-top: auto` itself. Same mechanism, same result — the control that
   undoes the collapse is at the bottom of the rail on both sides. */
.sr-rail .ag-rail-mini-btn { margin-top: auto; }

/* The rail's WIDTH has to travel with the inset, the same easing the agent
   chrome already uses (see `#app-nav.ag-chrome .ag-rail` further down). */
#seller-nav .ag-rail { transition: width var(--t-base) var(--ease); }
@media (prefers-reduced-motion: reduce) {
  #seller-nav .ag-rail { transition: none; }
}

/* ── THE SAME COLLAPSE, ON PURPOSE RATHER THAN ON WIDTH ────────────────────
 * Dom 2026-08-29: "just make the sidebar hide so we can see only icons not
 * texts", with the chevron at the rail's foot and the choice remembered per
 * viewer (components/seller-rail.js, `cs.seller.rail.mini`).
 *
 * DELIBERATELY THE SAME COLLAPSE THE RAIL ALREADY HAS. main.css:7662-7669
 * narrows `.ag-rail` to 58px under 900px and hides every label, and the 900px
 * block at the top of THIS file does the same for the property card; the rules
 * below re-state exactly those declarations under `.sr-rail.is-mini` so they
 * apply at ANY width. Not a second small-rail design — no new width, no new
 * padding, no new type.
 *
 * Each entry keeps its name through aria-label + title on the anchor
 * (components/seller-rail.js), so an icon-only rail is still labelled on hover
 * and to a screen reader. */
.sr-rail.is-mini { width: 58px; }
html.has-seller-rail-mini body { padding-left: 58px; }
.sr-rail.is-mini .ag-rail-brand { padding: 0 10px; justify-content: center; }
/* CS letters on the mini rail (Dom 2026-08-29) — the full lockup squeezed to
   an unreadable smear at 56px; the monogram is the mark that survives it. */
/* Dom 2026-08-29: "CS Din bold" — the monogram is set in the logo's own face.
   1KB woff2, subset to exactly the two letters it will ever draw. */
@font-face {
  font-family: 'DIN Pro CS';
  src: url('/assets/fonts/DINPro-Bold-CS.woff2') format('woff2');
  font-weight: 700;
  font-display: swap;
}
.ag-rail-mark {
  display: none;
  font-family: 'DIN Pro CS', 'DIN Alternate', var(--font-sans, sans-serif);
  font-weight: 700;
  font-size: 17px;
  letter-spacing: .02em;
  color: var(--ink);
  line-height: 1;
}
.sr-rail.is-mini .ag-rail-mark, .ag-rail.is-mini .ag-rail-mark { display: block; }
.sr-rail.is-mini .ag-rail-logo, .ag-rail.is-mini .ag-rail-logo { display: none !important; }

/* ── CS STUDIO | RE — the systems brand (Dom 2026-08-29) ─────────────────── */
.ag-rail-lockup {
  font-family: 'DIN Pro CS', 'DIN Alternate', var(--font-sans, sans-serif);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: .06em;
  color: var(--ink);
  line-height: 1;
  white-space: nowrap;
}
.ag-rail-lockup-pipe { color: var(--ink-4); font-weight: 400; }
/* GV skin: their logo, not our systems brand. Mini rail: the monogram. */
html.is-gv .ag-rail-lockup { display: none; }
.sr-rail.is-mini .ag-rail-lockup, .ag-rail.is-mini .ag-rail-lockup { display: none; }

.ag-rail-credit {
  margin: var(--sp-2) 0 0;
  padding: 0 14px 10px;
  font-size: 10.5px;
  letter-spacing: .02em;
  color: var(--ink-4);
  white-space: nowrap;
}
.sr-rail.is-mini .ag-rail-credit, .ag-rail.is-mini .ag-rail-credit { display: none; }
.sr-rail.is-mini .ag-rail-item span { display: none; }
.sr-rail.is-mini .ag-rail-nav { padding: var(--sp-3) 6px; }
.sr-rail.is-mini .ag-rail-item { padding: 11px 0; justify-content: center; }
.sr-rail.is-mini .ag-rail-item.is-active::before { left: -6px; }
.sr-rail.is-mini .pr-ctx { padding: var(--sp-3) 6px 0; }
.sr-rail.is-mini .pr-ctx-label { display: none; }
.sr-rail.is-mini .pr-current { padding: 4px; justify-content: center; }
.sr-rail.is-mini .pr-cur-txt { display: none; }
.sr-rail.is-mini .pr-thumb { width: 34px; }
.sr-rail.is-mini .sr-status { display: none; }
/* The toggle takes over the bottom anchoring, exactly as it does on the agent
   rail when the two elements that were providing it go to display:none. */
.sr-rail.is-mini .ag-rail-mini-btn { margin-top: auto; padding: 9px 6px 10px; justify-content: center; }

/* WIDTH-DRIVEN, at the rail's own breakpoint. main.css already narrows
   `.ag-rail` and hides `.ag-rail-item span` there, and the 900px block at the
   top of this file already collapses the property card — so the ONLY thing
   missing is the page inset this file owns, plus the two seller-only rows. */
@media (max-width: 900px) {
  html.has-seller-rail body { padding-left: 58px; }
  .sr-rail .ag-rail-brand { padding: 0 10px; justify-content: center; }
  .sr-rail .ag-rail-mini-btn { margin-top: auto; }
}

/* ── THE MARKET STATUS ─────────────────────────────────────────────────────
 * Dom 2026-08-29: "Statuses need to be real — Live on MLS, In progress,
 * Cancelled, Sold, Re-posted, On Hold."
 *
 * ONE rule per palette colour, keyed off `data-cat`, so the six statuses cost
 * six lines rather than six blocks — and a seventh status later costs none.
 * The colours are the portal's own --cat-* family, which is what that family
 * exists for, and which the Grapevine skin does not remap: "Sold" should read
 * identically on both tenants, because it is not a brand statement.
 *
 * Every chip is a coloured GROUND with its readable twin as ink, the pattern
 * the palette already maintains per theme — so no chip needs a white-on-bright
 * exception and all six clear AA in light and dark.
 */
.pr-status { margin-top: var(--sp-2); position: relative; }
.pr-status[hidden] { display: none; }
.pr-status-btn {
  display: block;
  padding: 2px;
  border: 0;
  border-radius: var(--r-1);
  background: none;
  cursor: pointer;
}
.pr-status-btn:focus-visible { outline: 2px solid var(--focus-ring-c); outline-offset: 0; }

.lc-chip {
  display: inline-block;
  padding: 3px 9px 4px;            /* 1px deeper at the bottom: optical centring */
  border-radius: var(--r-btn);
  font-size: calc(12px * var(--text-scale, 1));
  font-weight: 600;
  letter-spacing: -.01em;
  white-space: nowrap;
}
.lc-chip.is-sm { padding: 2px 8px 3px; font-size: calc(11.5px * var(--text-scale, 1)); }
.lc-chip[data-cat="green"]    { background: var(--cat-green-soft);    color: var(--cat-green); }
.lc-chip[data-cat="lime"]     { background: var(--cat-lime-soft);     color: var(--cat-lime); }
.lc-chip[data-cat="tan"]      { background: var(--cat-tan-soft);      color: var(--cat-tan); }
.lc-chip[data-cat="purple"]   { background: var(--cat-purple-soft);   color: var(--cat-purple); }
.lc-chip[data-cat="red"]      { background: var(--cat-red-soft);      color: var(--cat-red); }
.lc-chip[data-cat="lavender"] { background: var(--cat-lavender-soft); color: var(--cat-lavender); }

.pr-status-menu {
  position: absolute;
  left: 0;
  top: calc(100% + 4px);
  z-index: 62;
  min-width: 240px;
  display: flex;
  flex-direction: column;
  padding: var(--sp-1, 4px);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-2, var(--shadow-1));
}
.pr-status-menu[hidden] { display: none; }
.pr-status-menu button {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  padding: 7px 8px 8px;
  border: 0;
  border-radius: var(--r-1);
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.pr-status-menu button:hover, .pr-status-menu button.is-on { background: var(--bg-hover); }
.pr-status-menu button:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
/* The one-line explanation of what the status MEANS. It carries information, so
   it sits on the secondary rung, not the muted one. */
.pr-status-hint {
  font-size: calc(11.5px * var(--text-scale, 1));
  color: var(--ink-2);
  white-space: normal;
}
@media (max-width: 900px) {
  /* Collapsed rail: the chip alone still fits and still opens the menu. */
  .pr-status { display: flex; justify-content: center; }
  .pr-status-menu { left: 0; min-width: 220px; }
}

/* The seller's read-only status chip. Same chip as everywhere else — it is the
   same fact — just with no control around it. */
.sr-status { display: block; margin-top: var(--sp-2); }
@media (max-width: 900px) { .sr-status { display: none; } }

/* ── THE STATUS CONTROL ON THE LISTING HUB ─────────────────────────────────
 * Same chip, same menu, same vocabulary as the property sidebar — one status
 * system in the portal, not two implementations that drift. It sits in the
 * herobar beside the website pill, which is exactly where the two facts have
 * to be readable side by side without being confused for each other.
 */
.ld-phase { position: relative; display: inline-flex; }
.ld-phase-btn {
  padding: 2px;
  border: 0;
  border-radius: var(--r-1);
  background: none;
  cursor: pointer;
}
.ld-phase-btn:focus-visible { outline: 2px solid var(--focus-ring-c); outline-offset: 0; }
.ld-phase-menu {
  position: absolute;
  left: 0;
  top: calc(100% + 6px);
  z-index: 40;
  min-width: 250px;
  display: flex;
  flex-direction: column;
  padding: var(--sp-1, 4px);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-2, var(--shadow-1));
}
.ld-phase-menu[hidden] { display: none; }
.ld-phase-menu button {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  padding: 7px 8px 8px;
  border: 0;
  border-radius: var(--r-1);
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.ld-phase-menu button:hover, .ld-phase-menu button.is-on { background: var(--bg-hover); }
.ld-phase-menu button:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
.ld-phase-hint { font-size: calc(11.5px * var(--text-scale, 1)); color: var(--ink-2); white-space: normal; }

/* ── THE AGENT RAIL, MINIMISED ─────────────────────────────────────────────
 * Dom 2026-08-29: an icon-only left-edge strip for the AGENT rail, on demand
 * rather than on width, with the toggle at the rail's foot and the choice
 * remembered per viewer (components/nav.js, `cs.agent.rail.mini`).
 *
 * DELIBERATELY THE SAME COLLAPSE THE RAIL ALREADY HAS. main.css:7648-7661
 * narrows this rail to 58px under 900px and hides every label; the block below
 * re-states those declarations under `html.has-agent-rail-mini` so they apply
 * at ANY width. Not a second small-rail design — the seller rail took exactly
 * this route above (.sr-rail.is-mini), and an agent should not meet two
 * different narrow rails depending on why the rail narrowed.
 *
 * The rules are keyed off <html> rather than off the aside because the PAGE
 * INSET is owned there: `.app-shell` padding-left and `.ag-topbar` left are
 * both a function of the rail's width, and the property block inside the rail
 * has to collapse with it. `html.x .y` (0,2,0) outranks the plain `.y` (0,1,0)
 * originals with no !important anywhere, and at <=900px both blocks agree.
 *
 * It lives in THIS file because main.css belongs to another lane right now, and
 * this file already owns the property block's collapse and the seller rail's
 * is-mini. Everything is painted from tokens, so both themes and the GV skin
 * come along for free.
 *
 * Each entry keeps its name through aria-label + title on the anchor
 * (components/nav.js), so an icon-only rail is still labelled on hover and to
 * a screen reader. */
html.has-agent-rail-mini body:has(#app-nav.ag-chrome) .app-shell { padding-left: 58px; }
html.has-agent-rail-mini .ag-rail { width: 58px; }
html.has-agent-rail-mini .ag-topbar { left: 58px; }
html.has-agent-rail-mini .ag-rail-brand { padding: 0 10px; justify-content: center; }
html.has-agent-rail-mini .ag-rail-wm { display: none; }
/* `.ag-rail-portal` ("Agent portal") is NOT in the 900px block — an omission
   there, but this lane does not edit that file. At 58px it is four wrapped
   characters of grey, so it goes here. */
html.has-agent-rail-mini .ag-rail-portal { display: none; }
html.has-agent-rail-mini .ag-rail-item span,
html.has-agent-rail-mini .ag-rail-foot,
html.has-agent-rail-mini .ag-rail-display,
html.has-agent-rail-mini .ag-imp-t { display: none; }
html.has-agent-rail-mini .ag-rail-nav { padding: var(--sp-3) 6px; }
html.has-agent-rail-mini .ag-rail-item { padding: 11px 0; justify-content: center; }
html.has-agent-rail-mini .ag-rail-item.is-active::before { left: -6px; }
html.has-agent-rail-mini .ag-imp { margin: var(--sp-2) 6px 0; padding: var(--sp-2) 4px; justify-content: center; }
html.has-agent-rail-mini .ag-imp-x { margin-left: 0; }
html.has-agent-rail-mini .ag-user-name { display: none; }

/* THE PROPERTY BLOCK COLLAPSES WITH IT — the same declarations the 900px block
   at the top of this file uses, for the same reason: at 58px the card is its
   THUMBNAIL, which is still the button that opens the flyout. */
html.has-agent-rail-mini .pr-ctx { padding: var(--sp-3) 6px 0; }
html.has-agent-rail-mini .pr-ctx-label { display: none; }
html.has-agent-rail-mini .pr-current { padding: 4px; justify-content: center; }
html.has-agent-rail-mini .pr-cur-txt,
html.has-agent-rail-mini .pr-cur-caret { display: none; }
html.has-agent-rail-mini .pr-thumb { width: 34px; }
html.has-agent-rail-mini .pr-item { padding: 11px 0; justify-content: center; }
html.has-agent-rail-mini .pr-item-txt,
html.has-agent-rail-mini .pr-badge { display: none; }
html.has-agent-rail-mini .pr-item.is-active::before { left: -6px; }
html.has-agent-rail-mini .pr-flyout { left: 64px; right: var(--sp-3); width: auto; max-width: none; }

/* ── THE TOGGLE ────────────────────────────────────────────────────────────
 * The one control in the rail's foot that survives the collapse — it is how you
 * get back out. Same quiet row vocabulary as `.ag-rail-item`: no new colour, no
 * new radius, no new motion, and the chevron sits on the same 16px icon gutter
 * the rail items use, so it reads as one more row rather than as an appendage.
 *
 * A CHEVRON AND NO WORD. Measured 2026-08-29 at a 980x800 viewport: the rail
 * with the property block in it ended 12px short of the fold, so a labelled
 * 37px row pushed the rail into overflow and put the collapse control BELOW it.
 * The name lives on aria-label + title instead (components/nav.js), exactly as
 * it does on every other icon-only control in this rail.
 *
 * STICKY, for the same reason. The rail is `overflow-y: auto`; a short window,
 * a large text-scale or an impersonation block still scrolls it, and the one
 * control that undoes the narrow state must never be the thing you have to
 * scroll to find. It keeps the rail's own ground so scrolled rows pass behind
 * it rather than through it. */
.ag-rail-mini-btn {
  position: sticky; bottom: 0; z-index: 1;
  flex: none;
  display: flex; align-items: center; gap: var(--sp-3);
  margin: 0; padding: 6px var(--sp-4) 8px;
  border: 0; border-top: 1px solid var(--line);
  background: var(--bg-elevated); color: var(--ink-3);
  font: inherit; line-height: 1; cursor: pointer;
  transition: color .12s ease;
}
.ag-rail-mini-btn:hover { color: var(--ink); }
/* The identity block's bottom margin WAS the rail's last gutter. The toggle
   now provides it, so keeping both spent 16px the rail does not have. */
.ag-rail-foot:has(+ .ag-rail-mini-btn) { margin-bottom: 0; }
.ag-rail-mini-btn:focus-visible { outline: 2px solid var(--focus-ring-c); outline-offset: -2px; }
.ag-rail-mini-chev {
  width: 16px; flex: none; text-align: center;
  font-size: calc(15px * var(--text-scale, 1)); line-height: 1;
}

/* Collapsed: the chevron centres, and the button takes over the bottom
   anchoring that `.ag-rail-display` (margin-top: auto) was providing — that
   element is display:none here, so it no longer pushes anything down. */
html.has-agent-rail-mini .ag-rail-mini-btn {
  margin-top: auto;
  padding: 9px 6px 10px;
  justify-content: center;
}

/* The width-driven collapse hides the same two neighbours, so the button needs
   the same bottom anchoring there. Nothing else is restated: the html-class
   block above already covers a mini rail at any width. */
@media (max-width: 900px) {
  .ag-rail-mini-btn { margin-top: auto; padding: 9px 6px 10px; justify-content: center; }
}

/* The rail's WIDTH has to travel with the inset. assets/css/listing-composer.css
 * already puts a transition on the agent chrome (transform / left /
 * padding-left) for the composer's focus mode, so `.app-shell` padding and
 * `.ag-topbar` left already slide — without this the rail's own edge would snap
 * while everything around it eased, which reads as a glitch rather than as a
 * collapse. `transform` is restated so the focus-mode slide that sheet owns is
 * not dropped by this declaration replacing its shorthand. */
#app-nav.ag-chrome .ag-rail {
  transition: transform var(--t-base) var(--ease), width var(--t-base) var(--ease);
}
@media (prefers-reduced-motion: reduce) {
  #app-nav.ag-chrome .ag-rail { transition: none; }
}
