/* =========================================================================
   LAYER 3c — PRODUCT UTILITIES
   =========================================================================

   Small classes for concepts Bootstrap has no opinion about because they
   are ours, not the framework's: an amount of money, a verification
   badge, a status pill.

   These exist so "gold means money" is a rule the codebase can enforce
   rather than a convention each view re-implements. A view that needs to
   render a rent amount reaches for .rq-money; it never reaches for a
   gold colour, and it certainly never picks one by eye.

   Everything here reads LAYER 2 roles only. No literals, no primitives.
   ========================================================================= */

/* =========================================================================
   MONEY
   =========================================================================
   The rule: gold marks *value* — an amount, a balance, a payout, a total.
   It never marks an action. If the thing is clickable it is accent blue,
   even when it is about money ("Pay rent" is a button, not an amount).

   .rq-money renders the amount itself. Tabular figures matter more than
   they look like they should: rent tables stack amounts vertically, and
   proportional digits make the decimal points wander, which reads as
   sloppiness on exactly the screens where users are most careful.
   ------------------------------------------------------------------------- */
/*
   Deliberately sets colour and figures only — NOT weight or size.

   It has to compose. Almost every amount in the app already sits in
   something with its own weight (a KPI value at 700, a table cell at
   600, a <strong> in a sentence). If this class also asserted a weight
   it would quietly flatten all of them, and the fix would be a pile of
   per-site overrides — the exact mess the token layer exists to avoid.
   A utility that only says "this is money" can be added anywhere.

   Use .rq-money-display when the amount IS the element and needs its
   own typography.
*/
.rq-money {
    color: var(--rq-money);
    font-family: var(--rq-font-mono);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    letter-spacing: -0.01em;
}

/* The headline number on a KPI card or a payment screen. */
.rq-money-display {
    color: var(--rq-money);
    font-family: var(--rq-font-mono);
    font-weight: var(--rq-weight-medium);
    font-size: var(--rq-text-3xl);
    line-height: var(--rq-leading-tight);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    letter-spacing: -0.03em;
}

/* Emphasis within an amount — a total, or the figure a page is about. */
.rq-money-strong { color: var(--rq-money-strong); }

/*
   KPI cards carry status modifiers that colour their value:

     .rq-kpi.success  green   paid, complete, settled
     .rq-kpi.alert    amber   needs attention
     .rq-kpi.danger   red     overdue, failed
     .rq-kpi.info     accent  ...nothing. Just a tint.

   The first three outrank gold on purpose — when an amount is overdue,
   "overdue" is the more urgent fact and red should win. Status beats
   identity.

   .info is different: it carries no meaning, it simply paints the number
   with the interactive accent, which is the exact confusion gold exists
   to end (the rent figure and the Pay button were the same colour).
   Those all sit at (0,3,0), so this rule needs (0,4,0) to take just the
   .info case back without disturbing the three that matter.
*/
.rq-kpi.info .rq-kpi-value.rq-money { color: var(--rq-money); }

/* An amount that is NOT the point: struck-through original price, a
   secondary line, a zero balance. Gold would over-signal here. */
.rq-money-quiet {
    color: var(--rq-sub);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/* Money on the inverted navy panel — see the .rq-inverse role remapping
   near the bottom of this file, which handles this and every other role
   at once. Nothing needed here. */

/* A framed amount — escrow held, payout pending, deposit on file. */
.rq-money-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--rq-space-2);
    padding: var(--rq-space-1) var(--rq-space-3);
    border-radius: var(--rq-radius-pill);
    background: var(--rq-money-soft);
    border: 1px solid var(--rq-money-mid);
    color: var(--rq-money);
    font-size: var(--rq-text-sm);
    font-weight: var(--rq-weight-semibold);
    font-variant-numeric: tabular-nums;
}

/* =========================================================================
   STANDING — the other half of gold's job
   =========================================================================
   Verified identity, host tier, superhost-style recognition. Standing is
   earned and rare; that is why it shares gold with money and why neither
   should appear on a screen more than a couple of times.
   ------------------------------------------------------------------------- */
.rq-badge-verified {
    display: inline-flex;
    align-items: center;
    gap: var(--rq-space-1);
    padding: 2px var(--rq-space-2);
    border-radius: var(--rq-radius-sm);
    background: var(--rq-money-soft);
    border: 1px solid var(--rq-money-mid);
    color: var(--rq-money);
    font-size: var(--rq-text-2xs);
    font-weight: var(--rq-weight-semibold);
    letter-spacing: .04em;
    text-transform: uppercase;
    white-space: nowrap;
}

/* =========================================================================
   STATUS PILLS
   =========================================================================
   Bootstrap's .badge is fine but every area invented its own variant
   (--approved-bg, --pending-color, --declined-bg …) with hardcoded
   colours. These replace all of them and read the semantic roles, so a
   theme change carries them along.

   Meaning, not decoration: pick by what the state IS.
     success  settled, paid, approved, complete
     warning  waiting on someone, pending, expiring
     danger   overdue, declined, failed
     info     informational, scheduled, in progress
     neutral  draft, archived, not started
   ------------------------------------------------------------------------- */
.rq-status {
    display: inline-flex;
    align-items: center;
    gap: var(--rq-space-1);
    padding: 2px var(--rq-space-2);
    border-radius: var(--rq-radius-pill);
    font-size: var(--rq-text-xs);
    font-weight: var(--rq-weight-semibold);
    line-height: 1.6;
    white-space: nowrap;
    border: 1px solid transparent;
}

.rq-status-success { background: var(--rq-success-soft); border-color: var(--rq-success-mid); color: var(--rq-success-hover); }
.rq-status-warning { background: var(--rq-warning-soft); border-color: var(--rq-warning-mid); color: var(--rq-warning-hover); }
.rq-status-danger  { background: var(--rq-danger-soft);  border-color: var(--rq-danger-mid);  color: var(--rq-danger-hover); }
.rq-status-info    { background: var(--rq-info-soft);    border-color: var(--rq-info-mid);    color: var(--rq-info-hover); }
.rq-status-neutral { background: var(--rq-muted);        border-color: var(--rq-border-med);  color: var(--rq-sub); }

/* In dark mode the -hover roles are darker than the fills they sit on,
   so the pill text uses the base hue instead. */
[data-bs-theme="dark"] .rq-status-success { color: var(--rq-success); }
[data-bs-theme="dark"] .rq-status-warning { color: var(--rq-warning); }
[data-bs-theme="dark"] .rq-status-danger  { color: var(--rq-danger); }
[data-bs-theme="dark"] .rq-status-info    { color: var(--rq-info); }

/* =========================================================================
   SURFACES
   =========================================================================
   The inverted panel, as a class rather than a colour each view re-picks.
   ------------------------------------------------------------------------- */
/*
   The inverted panel is always dark, even when the page around it is
   light. That makes it a THEME BOUNDARY, not just a background colour:
   every role that was tuned for a light surface is wrong inside it.

   Measured before this rule existed: --rq-money on .rq-inverse in light
   mode scored 3.87:1, because light-mode money is the dark gold-700 and
   the panel is navy. Dark gold on dark navy. The mistake is easy to make
   and almost impossible to see in a screenshot review, since dark-on-dark
   reads as "subtle" until someone actually tries to read the number.

   Rather than patch each component that might appear inside a panel, the
   panel re-points the roles once. Anything nested inherits the corrected
   set automatically — including markup written years from now that never
   heard of .rq-inverse.
*/
.rq-inverse {
    background: var(--rq-inverse);

    --rq-text:         var(--rq-on-dark-92);
    --rq-sub:          var(--rq-on-dark-72);
    --rq-faint:        var(--rq-on-dark-52);
    --rq-border:       var(--rq-on-dark-08);
    --rq-border-med:   var(--rq-on-dark-12);

    /* The pairing the identity was designed for: 10.5:1. */
    --rq-money:        var(--rq-gold-400);
    --rq-money-strong: var(--rq-gold-300);
    --rq-money-mid:    var(--rq-gold-700);
    --rq-money-soft:   var(--rq-gold-a12);

    /* Accent and status step light, same reasoning as the dark theme. */
    --rq-accent:       var(--rq-blue-400);
    --rq-accent-hover: var(--rq-blue-300);
    --rq-accent-soft:  var(--rq-blue-a14);
    --rq-success-text: var(--rq-green-500);
    --rq-warning-text: var(--rq-amber-500);
    --rq-danger-text:  var(--rq-red-500);
    --rq-info-text:    var(--rq-cyan-500);

    color: var(--rq-text);
}
.rq-inverse .text-muted,
.rq-inverse .text-body-secondary { color: var(--rq-sub) !important; }

/* =========================================================================
   TYPE
   =========================================================================
   The editorial display face, available inside the app. Reserved for page
   titles and hero numbers — set body copy in it and the product stops
   looking like software.
   ------------------------------------------------------------------------- */
.rq-display {
    font-family: var(--rq-font-display);
    font-weight: var(--rq-weight-semibold);
    letter-spacing: -0.03em;
    line-height: var(--rq-leading-tight);
}

.rq-numeric {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}


/* =========================================================================
   SECTION SUB-NAV  ·  phase 2
   =========================================================================
   The second level of navigation. The sidebar carries six destinations per
   persona; this carries the children of whichever one is open, directly
   under the page header.

   Deliberately understated. It is a "where am I inside this section"
   indicator, not a second sidebar competing with the first — so: no fills,
   no borders per tab, one 2px underline on the active item and nothing
   else. The moment this looks as heavy as the sidebar, the page has two
   things claiming to be the navigation.
   ------------------------------------------------------------------------- */
.rq-subnav {
    margin: 0 0 var(--rq-space-5);
    border-bottom: 1px solid var(--rq-border);

    /* Tabs scroll rather than wrap. A wrapped second row reads as a second
       navigation block and pushes the page content down unpredictably;
       horizontal overflow keeps the header a fixed height on every screen. */
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
}
.rq-subnav::-webkit-scrollbar { display: none; }

.rq-subnav-list {
    display: flex;
    align-items: stretch;
    gap: var(--rq-space-1);
    margin: 0;
    padding: 0;
    list-style: none;
    width: max-content;
    min-width: 100%;
}

.rq-subnav-link {
    display: inline-flex;
    align-items: center;
    gap: var(--rq-space-2);
    padding: var(--rq-space-3) var(--rq-space-3) calc(var(--rq-space-3) - 2px);
    border-bottom: 2px solid transparent;
    color: var(--rq-sub);
    font-size: var(--rq-text-sm);
    font-weight: var(--rq-weight-medium);
    text-decoration: none;
    white-space: nowrap;
    transition: color var(--rq-transition-fast),
                border-color var(--rq-transition-fast);
}
.rq-subnav-link:hover,
.rq-subnav-link:focus-visible {
    color: var(--rq-text);
    text-decoration: none;
}
.rq-subnav-link i {
    font-size: 1.05em;
    opacity: .75;
}

.rq-subnav-link.active {
    color: var(--rq-accent);
    border-bottom-color: var(--rq-accent);
    font-weight: var(--rq-weight-semibold);
}
.rq-subnav-link.active i { opacity: 1; }

.rq-subnav-badge {
    display: inline-flex;
    align-items: center;
    padding: 0 var(--rq-space-2);
    height: 18px;
    border-radius: var(--rq-radius-pill);
    background: var(--rq-accent-soft);
    color: var(--rq-accent);
    font-size: var(--rq-text-2xs);
    font-weight: var(--rq-weight-semibold);
}

/* On phones the icons carry the meaning and the labels crowd the row, but
   dropping labels entirely leaves unlabelled glyphs. Keep the label on the
   ACTIVE tab only: the user can see where they are, and the rest stay
   compact and tappable. */
@media (max-width: 575.98px) {
    .rq-subnav-link { padding-inline: var(--rq-space-3); }
    .rq-subnav-link:not(.active) span { display: none; }
    .rq-subnav-link i { font-size: 1.2em; }
}


/* =========================================================================
   LIFECYCLE STRIP  ·  phase 2
   =========================================================================
   The stages of one tenancy, shown on the lease record. This is where the
   seventeen move-in / move-out sidebar entries went.

   It is a track, not a tab row: the steps have an order, and the connecting
   line says so. But it stops short of looking like a wizard, because the
   user is not being marched through it — they are looking at a lease and
   seeing what its stages are and which one is live.
   ------------------------------------------------------------------------- */
.rq-lifecycle {
    background: var(--rq-surface);
    border: 1px solid var(--rq-border);
    border-radius: var(--rq-radius-lg);
    padding: var(--rq-space-5);
    margin-bottom: var(--rq-space-5);
}

.rq-lifecycle-head { margin-bottom: var(--rq-space-4); }

.rq-lifecycle-title {
    font-size: var(--rq-text-lg);
    font-weight: var(--rq-weight-semibold);
    color: var(--rq-text);
    margin: 0;
}

.rq-lifecycle-caption {
    margin: var(--rq-space-1) 0 0;
    font-size: var(--rq-text-sm);
    color: var(--rq-sub);
}

.rq-lifecycle-track {
    display: flex;
    align-items: flex-start;
    gap: 0;
    margin: 0;
    padding: 0;
    list-style: none;
    overflow-x: auto;
    scrollbar-width: none;
}
.rq-lifecycle-track::-webkit-scrollbar { display: none; }

.rq-lifecycle-stage {
    position: relative;
    flex: 1 1 0;
    min-width: 108px;
}

/* The connecting line. Drawn behind the markers, from the middle of one to
   the middle of the next, so it never pokes out past the first or last. */
.rq-lifecycle-stage::before {
    content: "";
    position: absolute;
    top: 17px;
    left: calc(-50% + 18px);
    width: calc(100% - 36px);
    height: 2px;
    background: var(--rq-border-med);
}
.rq-lifecycle-stage:first-child::before { display: none; }
.rq-lifecycle-stage.done::before { background: var(--rq-success); }

.rq-lifecycle-node {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--rq-space-2);
    padding: 0 var(--rq-space-2);
    text-align: center;
    text-decoration: none;
    color: var(--rq-sub);
}
a.rq-lifecycle-node:hover { text-decoration: none; color: var(--rq-text); }
a.rq-lifecycle-node:hover .rq-lifecycle-marker { border-color: var(--rq-accent); }

.rq-lifecycle-marker {
    display: grid;
    place-items: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--rq-surface);
    border: 2px solid var(--rq-border-med);
    font-size: 16px;
    transition: border-color var(--rq-transition-fast),
                background var(--rq-transition-fast);
}

.rq-lifecycle-label {
    display: flex;
    flex-direction: column;
    gap: 1px;
    font-size: var(--rq-text-sm);
    font-weight: var(--rq-weight-medium);
    line-height: 1.3;
}
.rq-lifecycle-label small {
    font-size: var(--rq-text-2xs);
    color: var(--rq-faint);
    font-weight: var(--rq-weight-normal);
}

/* ---- states ---- */

.rq-lifecycle-stage.done .rq-lifecycle-marker {
    background: var(--rq-success-soft);
    border-color: var(--rq-success);
    color: var(--rq-success);
}
.rq-lifecycle-stage.done .rq-lifecycle-node { color: var(--rq-text); }

.rq-lifecycle-stage.current .rq-lifecycle-marker {
    background: var(--rq-accent-soft);
    border-color: var(--rq-accent);
    color: var(--rq-accent);
    /* The one step that is actually the user's turn. Given a ring rather
       than just a fill so it survives being scanned at a glance. */
    box-shadow: 0 0 0 4px var(--rq-accent-soft);
}
.rq-lifecycle-stage.current .rq-lifecycle-node {
    color: var(--rq-text);
    font-weight: var(--rq-weight-semibold);
}

.rq-lifecycle-stage.upcoming .rq-lifecycle-node { color: var(--rq-faint); cursor: default; }
.rq-lifecycle-stage.upcoming .rq-lifecycle-marker { opacity: .55; }

/* On a phone the track becomes a vertical list. Six stages cannot be laid
   out horizontally at 375px without the labels turning into two-character
   stubs, and the order reads just as well down the page. */
@media (max-width: 575.98px) {
    .rq-lifecycle-track { flex-direction: column; gap: var(--rq-space-1); }
    .rq-lifecycle-stage { min-width: 0; width: 100%; }
    .rq-lifecycle-stage::before {
        top: 0; left: 17px;
        width: 2px; height: 100%;
    }
    .rq-lifecycle-node {
        flex-direction: row;
        align-items: center;
        gap: var(--rq-space-3);
        text-align: left;
        padding: var(--rq-space-2) 0;
    }
    .rq-lifecycle-label { align-items: flex-start; }
}


/* =========================================================================
   MOBILE TAB BAR  ·  phase 2
   =========================================================================
   Bottom navigation for tenants and renters on phones. Rendered by
   _MobileTabBar.cshtml, which decides who gets it.

   Bottom rather than top because the bottom third of a phone screen is the
   only part a thumb reaches without regripping, and these are the taps
   people make one-handed while doing something else.
   ------------------------------------------------------------------------- */
.rq-tabbar {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 1030;               /* above content, below offcanvas + modals */
    display: flex;
    align-items: stretch;
    background: var(--rq-surface);
    border-top: 1px solid var(--rq-border);

    /* Clear the iOS home indicator. Without this the last row of labels sits
       under the system gesture bar and the taps get swallowed. */
    padding-bottom: env(safe-area-inset-bottom, 0);
    box-shadow: var(--rq-elev-2);
}

.rq-tabbar-link {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    padding: var(--rq-space-2) var(--rq-space-1);
    min-height: 56px;            /* comfortably over the 44px touch minimum */
    color: var(--rq-sub);
    text-decoration: none;
    font-size: var(--rq-text-2xs);
    font-weight: var(--rq-weight-medium);
    line-height: 1.2;
    text-align: center;
}
.rq-tabbar-link:hover { text-decoration: none; color: var(--rq-text); }

.rq-tabbar-link i { font-size: 21px; }

.rq-tabbar-link span {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rq-tabbar-link.active {
    color: var(--rq-accent);
    font-weight: var(--rq-weight-semibold);
}

/* The bar is fixed, so the page needs to end above it or the last card sits
   underneath. Applied only where the bar actually renders. */
@media (max-width: 991.98px) {
    body:has(.rq-tabbar) .body-wrapper { padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px)); }
}


/* =========================================================================
   COMMAND PALETTE  ·  phase 2
   =========================================================================
   Ctrl/Cmd+K. Behaviour lives in rq.palette.js.
   ------------------------------------------------------------------------- */
.rq-palette[hidden] { display: none; }

.rq-palette {
    position: fixed;
    inset: 0;
    z-index: 1080;               /* above modals — it is summoned on top of them */
    display: flex;
    justify-content: center;
    /* Sits high on the screen, not centred. The list grows downward, and a
       vertically-centred panel jumps as results change. */
    padding: 12vh var(--rq-space-4) var(--rq-space-4);
}

.rq-palette-backdrop {
    position: absolute;
    inset: 0;
    background: var(--rq-ink-a55);
    backdrop-filter: blur(2px);
}

.rq-palette-panel {
    position: relative;
    width: 100%;
    max-width: 560px;
    max-height: 62vh;
    display: flex;
    flex-direction: column;
    background: var(--rq-surface-raised);
    border: 1px solid var(--rq-border-med);
    border-radius: var(--rq-radius-lg);
    box-shadow: var(--rq-elev-3);
    overflow: hidden;
}

.rq-palette-field {
    display: flex;
    align-items: center;
    gap: var(--rq-space-3);
    padding: var(--rq-space-4);
    border-bottom: 1px solid var(--rq-border);
    color: var(--rq-faint);
}

.rq-palette-input {
    flex: 1;
    border: 0;
    background: transparent;
    color: var(--rq-text);
    /* 16px minimum: anything smaller and iOS zooms the viewport on focus,
       which on a phone leaves the user looking at a magnified corner. */
    font-size: var(--rq-text-md);
    outline: none;
}
.rq-palette-input::placeholder { color: var(--rq-faint); }

.rq-palette-kbd {
    padding: 2px var(--rq-space-2);
    border: 1px solid var(--rq-border-med);
    border-radius: var(--rq-radius-sm);
    background: var(--rq-muted);
    color: var(--rq-faint);
    font-family: var(--rq-font-mono);
    font-size: var(--rq-text-2xs);
}

.rq-palette-list {
    margin: 0;
    padding: var(--rq-space-2);
    list-style: none;
    overflow-y: auto;
}

.rq-palette-item {
    display: flex;
    align-items: center;
    gap: var(--rq-space-3);
    padding: var(--rq-space-3);
    border-radius: var(--rq-radius-md);
    color: var(--rq-text);
    text-decoration: none;
}
.rq-palette-item:hover { text-decoration: none; }

/* One highlight, driven by the keyboard cursor rather than :hover, so the
   mouse and the arrow keys can never disagree about what Enter will do. */
.rq-palette-item.is-cursor {
    background: var(--rq-accent-soft);
    color: var(--rq-accent);
}

.rq-palette-item i { font-size: 18px; opacity: .8; }
.rq-palette-label { flex: 1; font-weight: var(--rq-weight-medium); }

.rq-palette-parent {
    font-size: var(--rq-text-xs);
    color: var(--rq-faint);
    white-space: nowrap;
}

.rq-palette-empty {
    padding: var(--rq-space-5);
    text-align: center;
    color: var(--rq-sub);
    font-size: var(--rq-text-sm);
}

body.rq-palette-open { overflow: hidden; }

/* The topbar trigger. Reads as a search field rather than a button so the
   shortcut is discoverable without being explained. */
.rq-palette-trigger {
    display: inline-flex;
    align-items: center;
    gap: var(--rq-space-2);
    padding: var(--rq-space-2) var(--rq-space-3);
    border: 1px solid var(--rq-border-med);
    border-radius: var(--rq-radius-md);
    background: var(--rq-muted);
    color: var(--rq-faint);
    font-size: var(--rq-text-sm);
    cursor: pointer;
    min-width: 190px;
}
.rq-palette-trigger:hover { border-color: var(--rq-border-strong); color: var(--rq-sub); }
/* Just quiet text, no box. Giving the shortcut its own border and fill
   made it read as a second input nested inside the first — two stacked
   rounded rectangles with different backgrounds, which is a control, not
   a hint. The shortcut is a label on the field; it should recede. */
.rq-palette-trigger kbd {
    margin-left: auto;
    padding: 0;
    border: 0;
    background: none;
    color: var(--rq-faint);
    font-family: var(--rq-font-mono);
    font-size: var(--rq-text-2xs);
    letter-spacing: .04em;
}
.rq-palette-trigger:hover kbd { color: var(--rq-sub); }

/* The settled-tenancy line that stands in for the lifecycle strip when
   neither moving in nor moving out applies. Quiet on purpose: it exists so
   the steps stay reachable, not to invite anyone to use them. */
.rq-lease-stages-hint {
    display: flex;
    align-items: center;
    gap: var(--rq-space-2);
    margin-bottom: var(--rq-space-5);
    padding: var(--rq-space-3) var(--rq-space-4);
    border: 1px dashed var(--rq-border-med);
    border-radius: var(--rq-radius-md);
    color: var(--rq-sub);
    font-size: var(--rq-text-sm);
}
.rq-lease-stages-hint i { color: var(--rq-faint); font-size: 1.1em; }


/* =========================================================================
   TABLE → CARDS  ·  phase 4
   =========================================================================
   Below 768px a .rq-table-cards table stops being a table and becomes a
   list of cards, one per row, each field on its own line with its column
   name beside it.

   The alternative — what these screens did before — is horizontal scroll.
   That fails in a specific and costly way: the columns pushed off the
   right are the last ones, and on a payments table the last columns are
   Amount and Status. The two things a tenant opened the page to see were
   the two guaranteed to be off screen, with only a thin scrollbar to say
   so.

   Labels come from rq.tablecards.js, which copies them out of <thead>.
   If that never runs, the rows still stack — they just lose their labels.
   Stacking is the part that must not depend on JavaScript.

   Opt-in. Operator tables stay tables: a landlord scanning forty rows of
   arrears wants to compare down a column, and forty cards is not that.
   ------------------------------------------------------------------------- */
@media (max-width: 767.98px) {

    .rq-table-cards thead {
        /* Not display:none — that removes it from the accessibility tree
           along with the column semantics. This hides it visually while
           leaving it readable by assistive tech. */
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .rq-table-cards,
    .rq-table-cards tbody,
    .rq-table-cards tfoot,
    .rq-table-cards tr,
    .rq-table-cards td {
        display: block;
        width: auto;
    }

    .rq-table-cards tr {
        position: relative;
        margin-bottom: var(--rq-space-3);
        padding: var(--rq-space-3) var(--rq-space-4);
        background: var(--rq-surface);
        border: 1px solid var(--rq-border);
        border-radius: var(--rq-radius-md);
    }
    .rq-table-cards tr:last-child { margin-bottom: 0; }

    .rq-table-cards td {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: var(--rq-space-4);
        padding: var(--rq-space-2) 0;
        border: 0;
        border-bottom: 1px solid var(--rq-border);
        text-align: left !important;   /* beats the inline text-align:right
                                          several of these tables use on
                                          their amount column */
    }
    .rq-table-cards td:last-child { border-bottom: 0; padding-bottom: 0; }
    .rq-table-cards td:first-child { padding-top: 0; }

    .rq-table-cards td::before {
        content: attr(data-label);
        flex: 0 0 auto;
        max-width: 45%;
        color: var(--rq-sub);
        font-size: var(--rq-text-xs);
        font-weight: var(--rq-weight-medium);
        text-transform: uppercase;
        letter-spacing: .04em;
    }

    /* Action and icon columns have no header to borrow, so they get the
       full width rather than an empty label and a lopsided row. */
    .rq-table-cards td.rq-cell-unlabelled {
        justify-content: flex-start;
    }
    .rq-table-cards td.rq-cell-unlabelled::before { display: none; }

    /* An empty table still needs to say so. Without this the "no rows"
       row inherits the label treatment and reads as a field.

       Scoped to .rq-table-empty rather than any [colspan]: the first
       version matched the label half of a <tfoot> total too, and centred
       "Total refundable" in the middle of its own row. */
    .rq-table-cards tr.rq-table-empty td::before { display: none; }
    .rq-table-cards tr.rq-table-empty td {
        justify-content: center;
        text-align: center !important;
    }

    /* ---- totals row ----
       Three of these tables carry a <tfoot> with the sum. It is not a
       record, so it does not become a labelled card; it stays one line —
       what it is on the left, how much on the right — and is given the
       accent edge so it reads as the conclusion of the list above it. */
    .rq-table-cards tfoot tr {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: var(--rq-space-4);
        margin-top: var(--rq-space-2);
        border-color: var(--rq-accent-mid);
        background: var(--rq-muted);
    }
    .rq-table-cards tfoot td {
        border: 0;
        padding: 0;
        font-weight: var(--rq-weight-semibold);
    }
    .rq-table-cards tfoot td::before { display: none; }
}


/* =========================================================================
   TOUCH TARGETS  ·  phase 4
   =========================================================================
   Below 768px every interactive control gets at least 44px of height.

   44 is not arbitrary: it is Apple's minimum and roughly the width of an
   adult fingertip. Measured on /tenant/browse before this existed, eleven
   controls were under it — the sidebar toggle was 28x18px, primary buttons
   31px, filter pills 36px, inputs 38px. Those all work with a mouse and
   are a coin flip with a thumb, which matters most on exactly the screens
   tenants use one-handed.

   Applied at the viewport, not per persona. An operator who opens the app
   on a phone gets the same benefit, and the rule costs desktop nothing.
   ------------------------------------------------------------------------- */
@media (max-width: 767.98px) {

    .rq-btn,
    .btn,
    .rq-pill,
    .rq-subnav-link,
    .dropdown-item,
    .page-link {
        min-height: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }

    /* Icon-only controls need width too — a 44px-tall, 18px-wide target is
       still a miss. The sidebar toggle was exactly this.

       .favorite-btn sits here rather than with the buttons above because it
       is a bare <button class="favorite-btn">, not a .btn, so the button
       rule never reached it. It measured 32x32 on every listing card:
       small, floating over a photo, and the most-tapped control on the
       browse screen. */
    .sidebartoggler,
    .nav-icon-hover-bg,
    .btn-close,
    .favorite-btn,
    .nav-link.sidebartoggler {
        min-width: 44px;
        min-height: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }

    /* Form fields. The 16px floor is not about legibility: iOS Safari zooms
       the whole viewport when a focused field is smaller, leaving the user
       looking at a magnified corner of the page with no obvious way back.
       Nothing hits that today; this keeps it that way. */
    .form-control,
    .form-select,
    .rq-field input,
    .rq-field select,
    .rq-field textarea {
        min-height: 44px;
        font-size: max(16px, var(--rq-text-md));
    }
    textarea.form-control { min-height: 88px; }

    /* Checkboxes and radios are the smallest targets in any form. Growing
       the box is half the fix; the label has to be tappable too, which it
       is by default only when it carries a `for`. */
    .form-check-input {
        width: 1.35em;
        height: 1.35em;
        margin-top: .12em;
    }
    .form-check-label { padding: var(--rq-space-1) 0; }

    /* Table rows that act as links — the property and booking lists — are
       the one place where a whole block is the target and 44px is a floor
       rather than a target size. */
    .rq-table-cards tr[role="button"],
    .rq-table-cards tr[onclick] { min-height: 44px; }
}


/* =========================================================================
   PAY RENT  ·  phase 4
   =========================================================================
   The one screen in the tenant product with a single job. Amount, method,
   button — in that order, all above the fold on a phone.
   ------------------------------------------------------------------------- */

.rq-pay-amount {
    padding: var(--rq-space-4) 0 var(--rq-space-5);
    border-bottom: 1px solid var(--rq-border);
    margin-bottom: var(--rq-space-4);
}

.rq-pay-amount-label {
    font-size: var(--rq-text-xs);
    font-weight: var(--rq-weight-semibold);
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--rq-sub);
    margin-bottom: var(--rq-space-2);
}

/* The figure itself takes .rq-money-display, so it is gold and tabular
   like every other amount in the product. It was previously a disabled
   text input showing a currency string — a value dressed as a control,
   which invites a tap that does nothing. */
.rq-pay-amount .rq-money-display { font-size: var(--rq-text-4xl); }

.rq-pay-amount-sub {
    margin-top: var(--rq-space-2);
    font-size: var(--rq-text-sm);
    color: var(--rq-sub);
}

.rq-pay-method { margin-bottom: var(--rq-space-4); }

.rq-pay-addmethod {
    display: inline-flex;
    align-items: center;
    gap: var(--rq-space-1);
    margin-top: var(--rq-space-2);
    font-size: var(--rq-text-sm);
    color: var(--rq-accent);
}

.rq-pay-fee {
    margin: calc(-1 * var(--rq-space-2)) 0 var(--rq-space-4);
    font-size: var(--rq-text-sm);
    color: var(--rq-sub);
}

/* Contractor / mover job payment (Views/Shared/_JobPayForm.cshtml) */
.rq-job-pay-fee { margin: var(--rq-space-2) 0 var(--rq-space-3); }
.rq-job-pay-msg { margin-top: var(--rq-space-2); font-size: var(--rq-text-sm); color: var(--rq-sub); }
.rq-job-pay-msg.is-error,
.rq-job-pay-error { color: var(--rq-danger-hover); }
.rq-job-pay-error { font-size: var(--rq-text-sm); margin-bottom: var(--rq-space-2); }
.rq-job-pay-empty p,
.rq-job-pay-note { font-size: var(--rq-text-sm); color: var(--rq-sub); margin: 0 0 var(--rq-space-2); }

.rq-pay-submit {
    width: 100%;
    justify-content: center;
    font-size: var(--rq-text-md);
    font-weight: var(--rq-weight-semibold);
    padding-block: var(--rq-space-3);
}

/* ---- the autopay offer ----
   Deliberately a card of its own, placed after the payment rather than
   beside it. As an outline button next to Pay it read as the lesser of two
   equivalent choices; it is neither. It is how someone stops making this
   decision twelve times a year. */
.rq-autopay-offer {
    display: flex;
    gap: var(--rq-space-4);
    align-items: flex-start;
    border-color: var(--rq-accent-mid);
    background: var(--rq-accent-soft);
}

.rq-autopay-icon {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    width: 42px;
    height: 42px;
    border-radius: 50%;
    background: var(--rq-surface);
    color: var(--rq-accent);
    font-size: 20px;
}

.rq-autopay-title {
    font-weight: var(--rq-weight-semibold);
    color: var(--rq-text);
    margin-bottom: var(--rq-space-1);
}

.rq-autopay-copy {
    margin: 0 0 var(--rq-space-3);
    font-size: var(--rq-text-sm);
    color: var(--rq-sub);
    max-width: 52ch;
}

@media (max-width: 767.98px) {
    /* One column, and the amount grows rather than shrinks — it is the
       thing being confirmed before money moves. */
    .rq-pay-amount .rq-money-display { font-size: var(--rq-text-4xl); }
    .rq-autopay-offer { flex-direction: column; gap: var(--rq-space-3); }
    .rq-autopay-offer .rq-btn { width: 100%; }
}


/* =========================================================================
   EMPTY STATES  ·  phase 4
   =========================================================================
   For the tables that previously rendered nothing when they had no rows.

   Worth being clear about why these appeared now: before the card layout,
   an empty table still showed its column headers, which looked enough like
   content that nobody noticed the state was missing. Hiding the header on
   mobile removed that disguise and left a titled card with blank space
   underneath. The header was never an empty state — it was a table
   pretending to have something in it.
   ------------------------------------------------------------------------- */
.rq-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--rq-space-1);
    padding: var(--rq-space-6) var(--rq-space-4);
    text-align: center;
}

.rq-empty > i {
    font-size: 26px;
    color: var(--rq-faint);
    margin-bottom: var(--rq-space-1);
}

.rq-empty-title {
    font-weight: var(--rq-weight-semibold);
    color: var(--rq-text);
}

.rq-empty-copy {
    font-size: var(--rq-text-sm);
    color: var(--rq-sub);
    max-width: 40ch;
}

/* The empty row must not be dressed as a card by the mobile table rules —
   it is one message, not a record. */
@media (max-width: 767.98px) {
    .rq-table-cards tr.rq-table-empty {
        padding: 0;
        background: none;
        border: 0;
    }
    .rq-table-cards tr.rq-table-empty td { padding: 0; border: 0; }
}


/* =========================================================================
   KPI TRENDS  ·  phase 5
   =========================================================================
   Sparklines and period deltas on KPI cards.

   The sparkline is inline SVG using currentColor, so it themes itself and
   costs nothing — no charting library was reinstated to draw a 92x28 line.
   Colour carries DIRECTION, never judgement: more open maintenance tickets
   is a rise and a problem, more rent roll is a rise and a win. The card
   says which way the number moved; what that means is the operator's call.
   ------------------------------------------------------------------------- */

.rq-kpi-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--rq-space-3);
}

/* NOTE: .rq-sparkline, not .rq-spark. The latter is the container of the
   overview's 12-month bar chart (with .rq-spark-bar / .rq-spark-bar-col)
   and is a different thing entirely — this class was briefly called
   .rq-spark and silently clamped that chart to 92x28, spilling its bars
   over the card above. */
.rq-sparkline {
    flex: 0 0 auto;
    /* align-self, not just the parent's align-items: KPI cards are grid
       items that stretch to the tallest in the row, and a flex child with
       no cross-axis alignment of its own stretches with them. */
    align-self: center;
    width: 92px;
    height: 28px;
    max-height: 28px;
    overflow: visible;
    opacity: .9;
}
/* Direction only. Deliberately not success/danger — see the note above. */
.rq-sparkline.up   { color: var(--rq-accent); }
.rq-sparkline.down { color: var(--rq-sub); }

.rq-kpi-delta {
    display: flex;
    align-items: center;
    gap: var(--rq-space-1);
    margin-top: var(--rq-space-2);
    font-size: var(--rq-text-xs);
    font-weight: var(--rq-weight-medium);
    color: var(--rq-sub);
}
.rq-kpi-delta i { font-size: 1.05em; }
.rq-kpi-delta.up   { color: var(--rq-text); }
.rq-kpi-delta.down { color: var(--rq-sub); }
.rq-kpi-delta.flat { color: var(--rq-faint); }

.rq-kpi-delta-pct { opacity: .85; }
.rq-kpi-delta-since {
    color: var(--rq-faint);
    font-weight: var(--rq-weight-normal);
}

.rq-kpi-sub {
    margin-top: var(--rq-space-1);
    font-size: var(--rq-text-xs);
    color: var(--rq-sub);
}

/* On a phone the card is already narrow; the sparkline drops rather than
   squeezing the number it is meant to support. */
@media (max-width: 575.98px) {
    .rq-sparkline { display: none; }
    .rq-kpi-delta-since { display: none; }
}


/* ---- Tinted icon chip -------------------------------------------------
   A soft wash of the element's OWN colour, for icon chips whose colour is
   data-driven (a calendar event type, an activity kind, a sitemap status)
   and therefore has no matching -soft role to pair with.

   This replaces a trick that only ever worked on literals: the views built
   the tint by gluing a two-digit alpha onto the hex - "#10b981" + "15" - to
   make an eight-digit colour. The moment the hex became var(--rq-...) that
   concatenation produced "var(--rq-success)15", which is not a colour, so
   the chip lost its background entirely and the icon floated on the card.

   currentColor means the tint tracks whatever colour the element was given,
   in either theme, with nothing to keep in sync. */
.rq-tint { position: relative; isolation: isolate; }
.rq-tint > * { position: relative; z-index: 1; }
.rq-tint::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: currentColor;
    opacity: .14;
    z-index: 0;
}


/* ---- "Waiting on you" band -------------------------------------------
   The few things a person must decide, above everything else on the page
   they already land on. Capped at three by TodayDecisions; anything past
   that is counted with a link, never listed, because a list that grows
   without limit is a backlog and backlogs get scrolled past. */
.rq-today {
    background: var(--rq-surface);
    border: 1px solid var(--rq-border);
    /* 18px to match .rq-card. The band sits directly above a row of them,
       and a different corner radius reads as a different kind of object. */
    border-radius: 18px;
    padding: 14px 16px;
    margin-bottom: 16px;
    /* A quiet accent edge rather than a coloured panel: the band should read
       as important without shouting over the page it sits on. */
    border-left: 3px solid var(--rq-accent);
}
.rq-today-head {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 12px; margin-bottom: 10px;
}
.rq-today-title { font-weight: 700; font-size: 15px; }
.rq-today-date { font-size: 12px; color: var(--rq-sub); }
.rq-today-items { display: flex; flex-direction: column; gap: 8px; }
.rq-today-item {
    display: flex; align-items: center; gap: 12px;
    padding: 10px 12px;
    border: 1px solid var(--rq-border);
    border-radius: 10px;
    background: var(--rq-surface-sunken);
}
.rq-today-icon {
    flex: 0 0 auto;
    width: 32px; height: 32px; border-radius: 8px;
    display: flex; align-items: center; justify-content: center;
    font-size: 16px;
}
.rq-today-body { flex: 1; min-width: 0; }
.rq-today-item-title {
    font-weight: 600; font-size: 14px;
    display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
}
.rq-today-flag {
    font-size: 11px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .04em;
}
.rq-today-detail { font-size: 13px; color: var(--rq-sub); margin-top: 2px; }

/* On a phone the action goes full width under the text rather than
   squeezing the title into two words per line. */
@media (max-width: 575.98px) {
    .rq-today-item { flex-wrap: wrap; }
    .rq-today-body { flex: 1 0 100%; order: 2; }
    .rq-today-item > .rq-btn { flex: 1 0 100%; order: 3; justify-content: center; }
}


/* ---- Booking wizard notes --------------------------------------------
   Replaces .alert-info / .alert-secondary / .card.bg-light inside the
   booking modal. Those are fixed Bootstrap colours: .bg-light in
   particular is a near-white that does not follow the theme, so in dark
   mode the property summary was a white block in the middle of a dark
   modal, mid-checkout. */
.rq-book-note {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    padding: 10px 12px;
    border-radius: 10px;
    font-size: 13px;
    line-height: 1.45;
    background: var(--rq-accent-soft);
    color: var(--rq-text);
    border: 1px solid var(--rq-accent-mid);
}
.rq-book-note i {
    font-size: 16px;
    flex-shrink: 0;
    margin-top: 1px;
    color: var(--rq-accent-text);
}
/* The reCAPTCHA line is legal boilerplate, not a message — it should be
   present and quiet, not competing with the sentence above it. */
.rq-book-note.subtle {
    background: var(--rq-surface-sunken);
    border-color: var(--rq-border);
    color: var(--rq-sub);
    font-size: 12px;
}
.rq-book-note.subtle i { color: var(--rq-sub); }
.rq-book-note a { color: var(--rq-accent-text); }

.rq-book-summary {
    background: var(--rq-surface-sunken);
    border: 1px solid var(--rq-border);
}


/* ---- Toasts -----------------------------------------------------------
   Replaces window.alert(). Anchored bottom-right so it never covers the
   thing the message is about — an alert() sat over the middle of the page
   and had to be dismissed before you could read what it referred to. */
.rq-toast-host {
    position: fixed;
    right: 16px;
    bottom: 16px;
    z-index: 1090;          /* above modals' backdrop, below the modal itself */
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-width: min(380px, calc(100vw - 32px));
    pointer-events: none;   /* the host must not swallow clicks on the page */
}
.rq-toast {
    pointer-events: auto;
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 14px;
    border-radius: 12px;
    background: var(--rq-surface-raised);
    border: 1px solid var(--rq-border);
    box-shadow: var(--rq-elev-3);
    font-size: 13px;
    line-height: 1.45;
    color: var(--rq-text);
    animation: rq-toast-in .18s ease-out;
}
.rq-toast.leaving { opacity: 0; transform: translateY(4px); transition: opacity .2s, transform .2s; }
.rq-toast > i { font-size: 17px; flex-shrink: 0; margin-top: 1px; }
.rq-toast.info    > i { color: var(--rq-accent-text); }
.rq-toast.success > i { color: var(--rq-success-text); }
.rq-toast.error   > i { color: var(--rq-danger-text); }
/* A left edge in the severity colour, so the kind survives being read at a
   glance without tinting the whole panel. */
.rq-toast.success { border-left: 3px solid var(--rq-success); }
.rq-toast.error   { border-left: 3px solid var(--rq-danger); }
.rq-toast-body { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.rq-toast-close {
    background: none;
    border: 0;
    color: var(--rq-sub);
    font-size: 18px;
    line-height: 1;
    padding: 0 2px;
    cursor: pointer;
    flex-shrink: 0;
}
.rq-toast-close:hover { color: var(--rq-text); }
.rq-toast-close:focus-visible { outline: 2px solid var(--rq-accent); outline-offset: 2px; }

@keyframes rq-toast-in {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
}

/* Respect a stated preference for less motion — a toast sliding in is
   decoration, and the message is the point. */
@media (prefers-reduced-motion: reduce) {
    .rq-toast { animation: none; }
    .rq-toast.leaving { transition: none; }
}

@media (max-width: 575.98px) {
    .rq-toast-host { left: 16px; right: 16px; max-width: none; }
}


/* ---- Native field adornments -----------------------------------------
   Replaces Kendo's NumericTextBox Format("c2") / Format("n0") display.

   A native <input type="number"> holds a NUMBER, not a formatted string —
   which is the point. Kendo rendered "$1,234.00" into the field and parsed
   it back on read; a decimal separator in the wrong locale silently turned
   1,234 into 1. The prefix here is presentation only and never enters the
   value. */
.rq-adorn {
    position: relative;
    display: flex;
    align-items: stretch;
}
.rq-adorn-prefix {
    display: inline-flex;
    align-items: center;
    padding: 0 10px;
    border: 1px solid var(--rq-border);
    border-right: 0;
    border-radius: 6px 0 0 6px;
    background: var(--rq-surface-sunken);
    color: var(--rq-sub);
    font-size: 13px;
    flex-shrink: 0;
}
.rq-adorn .form-control {
    border-radius: 0 6px 6px 0;
    min-width: 0;
}
.rq-adorn.suffixed .form-control { border-radius: 6px 0 0 6px; }
.rq-adorn-suffix {
    display: inline-flex;
    align-items: center;
    padding: 0 10px;
    border: 1px solid var(--rq-border);
    border-left: 0;
    border-radius: 0 6px 6px 0;
    background: var(--rq-surface-sunken);
    color: var(--rq-sub);
    font-size: 13px;
    flex-shrink: 0;
}

/* The browser's spinner is noise on a money field and encourages clicking
   a rent up by one cent at a time. Hidden on money only; plain counts
   (rent due day, grace days) keep theirs, where stepping is the point. */
.rq-adorn.money .form-control::-webkit-outer-spin-button,
.rq-adorn.money .form-control::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
.rq-adorn.money .form-control { -moz-appearance: textfield; appearance: textfield; }

/* A switch replacing Kendo's Switch widget. Bootstrap ships .form-switch;
   this only sizes it to sit level with the label it follows. */
/* .form-switch supplies the pill; these two lines undo the indent it
   assumes, since the label here is a sibling rather than inside it. */
.rq-switch.form-switch { padding-left: 0; }
.rq-switch.form-switch .form-check-input { margin-left: 0; }
.rq-switch { display: inline-flex; align-items: center; gap: 8px; }
.rq-switch .form-check-input { width: 2.25em; height: 1.25em; margin: 0; cursor: pointer; }
.rq-switch .form-check-input:focus-visible {
    outline: 2px solid var(--rq-focus-ring);
    outline-offset: 2px;
}

/* Checkbox group — replaces the Kendo MultiSelect for short fixed lists
   (amenities, house rules). Auto-fit columns rather than a fixed count, so a
   narrow edit panel falls to one column without needing a breakpoint, and the
   group scrolls once it outgrows its box instead of pushing the form down. */
.rq-checks {
    display: grid;
    /* 150px, not 180: in the property edit panel the group is ~380px wide and
       its own scrollbar takes ~15 of those, which was just enough to fail a
       180px minimum and collapse two columns into one very wide one. */
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 6px 16px;
    max-height: 220px;
    overflow-y: auto;
    padding: 10px 12px;
    border: 1px solid var(--rq-border);
    border-radius: 8px;
    background: var(--rq-surface);
}
.rq-check {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    font-size: 13px;
    color: var(--rq-text);
    cursor: pointer;
}
.rq-check .form-check-input { margin: 0; flex: 0 0 auto; cursor: pointer; }
.rq-check .form-check-input:focus-visible {
    outline: 2px solid var(--rq-focus-ring);
    outline-offset: 2px;
}


/* =========================================================================
   .rq-brand — the wordmark
   =========================================================================
   Type, not an image. Fraunces at optical size 144, the initial in the money
   role (gold-700 on light, gold-400 on dark — the pair the amounts already
   use), the name in the text role. One element serves every theme; the
   light/dark PNG pair it replaced is gone. In the collapsed sidebar the rail
   clips .logo-img to 40px, which leaves exactly the gold R showing.
   Sizes: default fits a 34-35px box (sidebar, topbars); .lg the 38px sign-in
   card; .xl the public hero. Keep the serif to the mark and to headings —
   never on controls or body text.
   ------------------------------------------------------------------------- */
.rq-brand {
    display: inline-block;   /* plain inline text: reads as one word, not R + entiqa */
    font-family: "Fraunces", Georgia, "Times New Roman", serif;
    font-variation-settings: "opsz" 144;
    font-weight: 500;
    font-size: 30px;
    line-height: 1;
    letter-spacing: -0.02em;
    color: var(--rq-text);
    white-space: nowrap;
    text-decoration: none;
    -webkit-font-smoothing: antialiased;
}
.rq-brand-mark { color: var(--rq-money); font-weight: 600; }
.rq-brand.lg { font-size: 34px; }
.rq-brand.xl { font-size: 56px; }
.auth-card .rq-brand { font-size: 34px; }   /* the sign-in card's 38px box */
a:hover > .rq-brand, a:focus-visible > .rq-brand { color: var(--rq-text); }
a:hover > .rq-brand .rq-brand-mark { color: var(--rq-money-strong); }


/* =========================================================================
   Brand typography — the titles the components above did not own
   =========================================================================
   Fraunces on anything that names a thing: Bootstrap card titles, the
   window and editor-modal titles, the sign-in card's heading. Never on
   controls, labels, tables or running text — those stay in Mulish, and
   figures stay in Plex Mono (.rq-kpi-value, .rq-money).
   ------------------------------------------------------------------------- */
.card-title,
.rq-window-title,
.rq-modal-title,
.auth-card h1, .auth-card h2, .auth-card h3 {
    font-family: var(--rq-font-display);
    font-variation-settings: "opsz" 144;
    font-weight: 600;
    letter-spacing: -.015em;
}
.rq-window-title, .rq-modal-title { font-size: 17px; }

/* ---- The collapsed rail: the brand keeps its gold R, the persona its word ----
   The sidebar toggle puts body[data-sidebartype=mini-sidebar] on and the
   rail stays ~87px until hovered. In that state the wordmark keeps only its
   gold R, and the persona pill drops its icon and keeps the WORD — small,
   uppercase, brand gold, centred under the R like the nav icons below it
   (Artem, 2026-09-07: "leave the word instead, centred as the rest of the
   icons"). A bare initial and an icon were both tried first: the initial
   read as a stray letter, the icon as one more nav item. Hover expands the
   rail and the normal pill returns. */
[data-sidebartype="mini-sidebar"] .left-sidebar:not(:hover) .rq-brand-word { display: none; }
[data-sidebartype="mini-sidebar"] .left-sidebar:not(:hover) .rq-persona-icon { display: none; }
[data-sidebartype="mini-sidebar"] .left-sidebar:not(:hover) .rq-persona-pill {
    justify-content: center;
    padding-left: 0 !important;
    padding-right: 0 !important;
}
[data-sidebartype="mini-sidebar"] .left-sidebar:not(:hover) .rq-persona-word {
    display: block;
    font-family: var(--rq-font-mono);
    font-size: 9px;
    font-weight: 600;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--rq-money);
    text-align: center;
    white-space: nowrap;
}

/* A card title's trailing caption or link ("Last 6 months", "All tickets →")
   is metadata, not a name: it stays in the reading face. The title itself
   is the first child. */
.rq-card-title > :not(:first-child),
.rq-card-title small {
    font-family: var(--rq-font-ui);
    font-variation-settings: normal;
    font-weight: 500;
    letter-spacing: 0;
}

/* =========================================================================
   Installed app — the install banner and the notifications bell
   ========================================================================= */
.rq-install {
    position: fixed; z-index: 1080;
    left: 16px; right: 16px; bottom: 16px;
    display: flex; align-items: center; gap: 14px;
    padding: 14px 16px;
    background: var(--rq-surface-raised); color: var(--rq-text);
    border: 1px solid var(--rq-border); border-radius: 14px;
    box-shadow: 0 18px 44px -20px var(--rq-shadow-color);
}
@media (min-width: 768px) {
    .rq-install { left: auto; right: 24px; bottom: 24px; max-width: 440px; }
}
/* On a phone the tenant/renter tab bar owns the bottom edge; sit above it. */
@media (max-width: 767.98px) {
    .rq-install { bottom: calc(16px + 64px + env(safe-area-inset-bottom, 0px)); }
}
.rq-install-mark { flex: 0 0 auto; width: 44px; height: 44px; display: grid; place-items: center; border-radius: 10px; background: var(--rq-inverse); }
.rq-install-mark .rq-brand { color: var(--rq-on-inverse); }
.rq-install-body { flex: 1 1 auto; min-width: 0; }
.rq-install-title { font-family: var(--rq-font-display); font-variation-settings: "opsz" 144; font-weight: 600; font-size: 15px; letter-spacing: -.01em; }
.rq-install-text { font-size: 12.5px; color: var(--rq-sub); margin-top: 2px; }
.rq-install-actions { display: flex; flex-direction: column; gap: 6px; flex: 0 0 auto; }
.rq-install.is-prompt .rq-install-text-ios,
.rq-install.is-ios .rq-install-text-prompt,
.rq-install.is-ios .rq-install-btn-prompt { display: none; }
@media (max-width: 480px) {
    .rq-install { flex-wrap: wrap; }
    .rq-install-actions { flex-direction: row; width: 100%; justify-content: flex-end; }
}

/* The bell: off = quiet, on = the brand gold, busy = waiting on the browser. */
.rq-push-toggle.is-on i { color: var(--rq-money); }
.rq-push-toggle.is-busy { opacity: .6; pointer-events: none; }
.rq-push-toggle.is-unavailable { opacity: .45; cursor: default; }

/* =========================================================================
   Test assistant (Development only) — the manual plan's quick-fill panel
   ========================================================================= */
.rq-testassist {
    position: fixed; z-index: 1085; left: 16px; bottom: 16px; width: 320px; max-height: 60vh;
    display: flex; flex-direction: column;
    background: var(--rq-surface-raised); color: var(--rq-text);
    border: 1px solid var(--rq-border); border-radius: 12px;
    box-shadow: 0 18px 44px -20px var(--rq-shadow-color);
    font-size: 12.5px;
}
.rq-ta-head { display: flex; align-items: center; justify-content: space-between; padding: 8px 10px 8px 12px; border-bottom: 1px solid var(--rq-border); }
.rq-ta-title { font-family: var(--rq-font-mono); font-size: 10.5px; letter-spacing: .13em; text-transform: uppercase; color: var(--rq-money); }
.rq-ta-x { border: 0; background: transparent; color: var(--rq-sub); font-size: 18px; line-height: 1; cursor: pointer; padding: 0 4px; }
.rq-ta-body { overflow: auto; padding: 8px 12px; display: flex; flex-direction: column; gap: 8px; }
.rq-ta-empty { color: var(--rq-sub); }
.rq-ta-fill { display: flex; flex-direction: column; gap: 6px; padding: 8px 0; border-bottom: 1px solid var(--rq-border); }
.rq-ta-fill:last-child { border-bottom: 0; }
.rq-ta-case b { font-family: var(--rq-font-mono); color: var(--rq-money); margin-right: 4px; }
.rq-ta-foot { padding: 8px 12px; border-top: 1px solid var(--rq-border); color: var(--rq-faint); font-size: 11px; }
.rq-ta-link { border: 0; background: transparent; color: var(--rq-accent); cursor: pointer; font-size: 11px; padding: 0; }
@media (max-width: 767.98px) { .rq-testassist { left: 8px; right: 8px; width: auto; bottom: calc(16px + 64px); } }

/* Smart home: a door code where its holder (guest, cleaner, contractor) reads it. */
.rq-door-code {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 14px; padding: 12px 14px; border-radius: 12px;
    background: var(--rq-surface-sunken); border: 1px solid var(--rq-border);
}
.rq-door-code-digits { font-family: var(--rq-font-mono, ui-monospace, Consolas, monospace); font-size: 26px; font-weight: 700; letter-spacing: .18em; color: var(--rq-text); font-variant-numeric: tabular-nums; }
.rq-door-code-meta { font-size: 12.5px; color: var(--rq-sub); }

/* Beta: one slim line on every page while Beta:ShowNotice is on (Views/Shared/_BetaBanner.cshtml). */
.rq-beta-bar {
    display: flex; align-items: center; justify-content: center; gap: 8px; flex-wrap: wrap;
    padding: 6px 16px; font-size: 12.5px; line-height: 1.4; text-align: center;
    background: var(--rq-warning-soft); color: var(--rq-warning-text);
    border-bottom: 1px solid var(--rq-warning-mid);
}
.rq-beta-bar > i { font-size: 15px; }
