/* ============================================================================
   FGR admin dashboard — styles

   Layered ON TOP of /assets/tokens.css, which is the single source of truth for
   the brand. Nothing here redefines a brand colour or the font; those are
   inherited so the admin cannot drift from the site. --fg-radius and
   --fg-shadow-card themselves are likewise never redefined -- deviation 4
   below introduces admin-only --a-radius/--a-shadow-soft tokens instead of
   changing what those shared tokens mean everywhere else.

   Remember: tokens.css sets html{font-size:62.5%}, so 1rem = 10px here.

   THREE DELIBERATE DEVIATIONS from the public site, each with a reason:

   1. TEXT COLOUR. The site ships --fg-body #767676, which tokens.css itself
      records as 4.24:1 on --fg-page — under the 4.5:1 AA floor. The site keeps
      it because its brief is to match the live WordPress colours. The admin has
      no such brief: it is new internal tooling where staff read dense data for
      long stretches. Measured 2026-09-02:
          #3a3a3a on #f7f7f7 = 10.62:1
          #5f5f5f on #f7f7f7 =  5.96:1   (secondary text)
          #5f5f5f on #ffffff =  6.39:1

   2. CONTROL BORDERS. --fg-border #e0e0e0 measures 1.32:1 on white. That is
      fine for a decorative divider and it is still used as one, but WCAG 1.4.11
      wants 3:1 for the visible boundary of an input. --a-border-control is
      #8a8a8a (3.22:1 on the page) — the same value tokens.css already vetted
      against the 1.4.11 floor for --fg-meta-icon.

   3. DENSITY. Tighter than the public site. An 86-row table and a 30-field form
      are not marketing pages.

   4. SHAPE. Cards, controls, pills and the property thumbnail carry their own
      8px radius and a two-layer shadow instead of the public site's flat
      --fg-radius:0 / --fg-shadow-card. --fg-radius and --fg-shadow-card
      themselves are untouched -- this only changes what the admin's own
      components consume, chosen 2026-09-06 to match the shipped real-estate
      CRM dashboards (RealtyHub, AIRES) staff will recognise from other tools.

   5. ROW SIZE. The reference design (a CRM-style properties table) reads
      noticeably roomier than deviation 3's original "tighter than the public
      site" call. Table text moved 1.35rem -> 1.5rem, --a-row-pad grew from
      1.0/1.2rem to 1.3/1.5rem, and the thumbnail from 6.4x4.8rem to
      7.4x5.4rem. This is a real trade-off, not a free win: at ~15px row
      height instead of ~13px, roughly 15% fewer of the 86 properties fit
      per screen. Chosen deliberately 2026-09-06 anyway, because the roomier
      read was the whole point of the picked direction -- pushing further to
      literally match the reference's ~19px rows would cost closer to 40%
      of visible rows, which is why this stops short of that.
   ========================================================================= */

/* Every element, one box-sizing. Without this, `width`/`min-height` plus
   padding/border compute differently depending on the ELEMENT TYPE, not
   just per author rule -- Chromium's own UA stylesheet already defaults
   <button>, <select> and type="search" to border-box, but a plain
   type="text" input or an <a> defaults to content-box. That mismatch is
   what caused two separate real bugs this same file already had to fix
   piecemeal (text inputs rendering 14px taller than a <select> sharing the
   identical min-height rule; "Save changes" rendering 26px narrower than
   "Back to list" sharing the identical width:100% rule) -- both were the
   same root cause showing up on different elements. One reset here closes
   the whole class of it, instead of the next one surfacing on the next
   element type nobody happened to test yet. */
*, *::before, *::after { box-sizing: border-box; }

:root {
    /* text — see deviation 1 above */
    --a-text:            #3a3a3a;
    --a-text-muted:      #5f5f5f;
    --a-heading:         var(--fg-heading);

    /* surfaces */
    --a-page:            var(--fg-page);
    --a-surface:         var(--fg-surface);
    --a-rail:            #242a30;          /* sidebar; darker than --fg-header-bg
                                              so the admin is never mistaken for
                                              the public site at a glance */
    --a-rail-text:       #c9d1d9;
    --a-rail-active:     var(--fg-primary);

    /* lines */
    --a-border:          var(--fg-border);        /* dividers only */
    --a-border-control:  #8a8a8a;                 /* inputs — see deviation 2 */

    /* state */
    --a-danger:          var(--fg-accent-red);    /* white on it = 5.02:1 */
    --a-ok:              #17847a;                 /* --fg-accent-teal-text */
    --a-focus:           var(--fg-primary);

    /* density */
    --a-gap:             1.6rem;
    --a-rail-w:          23rem;
    --a-row-pad:         1.3rem 1.5rem;   /* see deviation 5 */

    /* shape — see deviation 4 above */
    --a-radius:          8px;
    --a-shadow-soft:     0 1px 2px rgba(15, 23, 42, .04), 0 6px 20px rgba(15, 23, 42, .05);

    /* Buttons carry their own, tighter elevation than --a-shadow-soft above.
       A card is a resting surface; a button is a thing you are about to
       press, so it sits closer to the page and lifts as you approach it.
       The filled buttons' shadows are tinted with their OWN hue rather than
       neutral grey -- a blue button casting a grey shadow reads as pasted
       on. Their border also drops from --a-border-control (#8a8a8a, which
       exists for text inputs, see deviation 2) to a hairline: outlining
       navigation as heavily as data entry is what made the toolbar shout. */
    --a-border-btn:              #e6e8eb;
    --a-shadow-btn:              0 1px 2px rgba(15, 23, 42, .06);
    --a-shadow-btn-hover:        0 3px 8px rgba(15, 23, 42, .10);
    --a-shadow-cta:              0 1px 2px rgba(0, 121, 184, .30), 0 4px 12px rgba(0, 121, 184, .22);
    --a-shadow-cta-hover:        0 4px 14px rgba(0, 121, 184, .34);
    --a-shadow-danger:           0 1px 2px rgba(210, 45, 62, .30), 0 4px 12px rgba(210, 45, 62, .22);
    --a-shadow-danger-hover:     0 4px 14px rgba(210, 45, 62, .34);
    /* Filled/tonal text inputs/selects/textareas: no border, no shadow --
       the tint itself is what marks the box against the white card. A
       DIFFERENT tint from --fg-tint (used for :disabled/[readonly] below),
       or an enabled field and a disabled one would look identical. Focus
       darkens to the same tint one step further -- see the :focus rule --
       instead of a ring, so nothing reads as a line even on click. */
    --a-field-fill:              #eef2f5;
    --a-field-fill-focus:        #e4ebf1;

    /* motion — one place, so everything shares a rhythm */
    --a-fast:            140ms;
    --a-ease:            cubic-bezier(.2, .0, .2, 1);
}

/* Motion is opt-in, not opt-out: anything that animates below names this
   variable, so a single query disables the lot. */
@media (prefers-reduced-motion: reduce) {
    :root { --a-fast: 0ms; }
    *, *::before, *::after { animation-duration: .01ms !important;
                             animation-iteration-count: 1 !important;
                             transition-duration: .01ms !important;
                             scroll-behavior: auto !important; }
}

/* Any class that sets `display` beats the UA's `[hidden] { display: none }`,
   because a class rule outranks a bare attribute selector. `.field__err` is
   `display: flex`, so every hidden error marker rendered anyway -- four red "!"
   badges sat under the filter bar with no error to report. The public site
   carries this same guard for the same reason. Attribute-hidden wins here. */
[hidden] { display: none !important; }

body.admin {
    background: var(--a-page);
    color: var(--a-text);
    font-size: 1.4rem;
    -webkit-font-smoothing: antialiased;
}

/* Prices, sizes and counts sit in columns. Proportional digits make them jitter
   between rows and shift width as values change. */
.num { font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------------ a11y -- */
.skip-link {
    position: absolute; left: -9999px; top: 0; z-index: 100;
    background: var(--fg-primary); color: #fff;
    padding: 1rem 1.6rem; font-weight: var(--fg-font-weight-medium);
}
.skip-link:focus { left: 0; color: #fff; }

/* One focus treatment for most of the app. :focus-visible only, so a mouse
   click does not leave a ring behind, but every keyboard user gets one --
   true for a, button, summary and [tabindex], but NOT for input/select/
   textarea: browsers treat focusing a text-entry element as always
   "visible" (typing is expected next), so a plain mouse click into a field
   matched :focus-visible here too, same as a keyboard user. Fields get
   their own override below instead of relying on this one. */
:where(a, button, summary, [tabindex]):focus-visible {
    outline: 3px solid var(--a-focus);
    outline-offset: 2px;
}
/* No line at all on click -- not an outline, not a ring-shaped shadow.
   The fill itself darkens one step, same idea as a button's own hover/
   active state (admin.css's .btn:hover), just expressed as color instead
   of elevation since these fields have neither a border nor a shadow to
   deepen. Plain :focus (not :focus-visible): the two aren't meaningfully
   different for a text field per the note above, so this is what both a
   mouse click AND keyboard focus get -- a keyboard user still sees
   something change, just never a border/ring shape. */
.input:focus, .select:focus, .textarea:focus {
    outline: none;
    background: var(--a-field-fill-focus);
}

.visually-hidden {
    position: absolute !important; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ----------------------------------------------------------------- shell -- */
.app {
    display: grid;
    grid-template-columns: var(--a-rail-w) minmax(0, 1fr);
    min-height: 100vh;
    min-height: 100dvh;
}
.app[hidden] { display: none; }

/* --- sidebar --- */
.rail {
    background: var(--a-rail);
    color: var(--a-rail-text);
    display: flex; flex-direction: column;
    position: sticky; top: 0; align-self: start;
    height: 100vh; height: 100dvh;
}
.rail__brand {
    display: flex; align-items: center; gap: 1rem;
    padding: 2rem 1.8rem;
    border-bottom: 1px solid rgba(255, 255, 255, .08);
}
.rail__brand strong { color: #fff; font-size: 1.6rem; font-weight: 500; line-height: 1.2; }
.rail__brand span { display: block; font-size: 1.1rem; color: #8b949e; }

.rail__nav { flex: 1; overflow-y: auto; padding: 1.2rem 0; }
.rail__group {
    padding: 1.6rem 1.8rem .6rem;
    font-size: 1.1rem; letter-spacing: .08em; text-transform: uppercase;
    color: #7d8590;
}
.rail__link {
    display: flex; align-items: center; gap: 1.2rem;
    padding: 1.1rem 1.8rem;
    color: var(--a-rail-text);
    border-left: 3px solid transparent;
    transition: background var(--a-fast) var(--a-ease),
                color      var(--a-fast) var(--a-ease);
}
.rail__link:hover { background: rgba(255, 255, 255, .06); color: #fff; }
/* Active state carries a colour AND a bar, so it does not depend on colour
   alone (WCAG 1.4.1). aria-current is the accessible half. */
.rail__link[aria-current="page"] {
    background: rgba(255, 255, 255, .09);
    border-left-color: var(--a-rail-active);
    color: #fff; font-weight: 500;
}
.rail__link svg { width: 1.8rem; height: 1.8rem; flex: none; }

.rail__foot {
    border-top: 1px solid rgba(255, 255, 255, .08);
    padding: 1.4rem 1.8rem;
    font-size: 1.2rem;
}
.rail__who { color: #fff; }
.rail__signout { margin-top: 1rem; white-space: nowrap; padding-left: 0; color: var(--a-rail-text); }
.rail__signout:hover:not(:disabled) { background: rgba(255, 255, 255, .06); color: #fff; }

.rail__role {
    display: inline-block; margin-top: .4rem;
    background: rgba(255, 255, 255, .12); color: #fff;
    padding: .2rem .8rem; font-size: 1.1rem; text-transform: capitalize;
}

/* --- main --- */
.main { min-width: 0; display: flex; flex-direction: column; }

.topbar {
    display: flex; align-items: center; gap: var(--a-gap);
    padding: 1.6rem 2.4rem;
    background: var(--a-surface);
    border-bottom: 1px solid var(--a-border);
    position: sticky; top: 0; z-index: 20;
}
.topbar h1 { margin: 0; font-size: 2rem; }
.topbar__spacer { flex: 1; }

.content { padding: 2.4rem; }
.content > * + * { margin-top: var(--a-gap); }

/* ----------------------------------------------------------------- cards -- */
.card {
    background: var(--a-surface);
    box-shadow: var(--a-shadow-soft);
    border-radius: var(--a-radius);
}
.card__head {
    display: flex; align-items: center; gap: 1.2rem;
    padding: 1.6rem 2rem;
    border-bottom: 1px solid var(--a-border);
}
.card__head h2 { margin: 0; font-size: 1.6rem; }
.card__body { padding: 2rem; }

.stat-grid {
    display: grid; gap: var(--a-gap);
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
}
.stat { padding: 2rem; }
.stat__n { font-size: 3.2rem; line-height: 1.1; color: var(--a-heading); }
.stat__k { font-size: 1.3rem; color: var(--a-text-muted); margin-top: .4rem; }

/* --------------------------------------------------------------- buttons -- */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: .8rem;
    /* 3.6rem = 36px, compact -- was 4rem/40px. Still a pointer-first desktop
       tool, not the 44px touch floor; the touch-sized controls are the row
       links, which are full-width. */
    min-height: 3.6rem;
    padding: 0 1.2rem;
    font: inherit; font-size: 1.3rem; font-weight: 500;
    border: 1px solid transparent; border-radius: var(--a-radius);
    background: var(--fg-surface); color: var(--a-text);
    border-color: var(--a-border-btn);
    box-shadow: var(--a-shadow-btn);
    cursor: pointer;
    transition: background var(--a-fast) var(--a-ease),
                border-color var(--a-fast) var(--a-ease),
                box-shadow var(--a-fast) var(--a-ease),
                transform var(--a-fast) var(--a-ease);
}
/* icon() (ui.js) never sets width/height on the <svg> it builds, and nothing
   here sized one either -- each icon was rendering at whatever size the
   browser happened to fall back to with no intrinsic dimensions, which
   turned out to NOT even be consistent (measured 32.6px for the plus icon,
   25.9px for the upload icon, on the same toolbar). That oversized, uneven
   icon was what pushed "New property" onto two lines in the first place.
   Fixing the sizing here, not in the toolbar's own markup, so every button
   everywhere in the admin gets one consistent icon size for free. */
.btn svg { width: 1.5rem; height: 1.5rem; flex: none; }
/* Approach lifts the button a single pixel and deepens its shadow. One
   pixel is deliberate: enough to read as "this responds", small enough that
   a toolbar of them doesn't ripple as the pointer crosses it. */
.btn:hover:not(:disabled) { transform: translateY(-1px); box-shadow: var(--a-shadow-btn-hover); }
.btn:active:not(:disabled) { transform: translateY(0); box-shadow: var(--a-shadow-btn); }
/* Several of these buttons are rendered as <a> (the toolbar's are), and the
   global `a:hover { color: var(--fg-link-hover) }` is (0,1,1) -- which
   outranks `.btn--primary`'s (0,1,0) and repaints a white label brand-blue
   on a brand-blue fill. It was always wrong; it only became invisible once
   the filled hover moved from navy to a lighter blue. Every variant states
   its own hover colour at (0,3,0) so the anchor rule cannot reach it. */
.btn:hover:not(:disabled) { color: var(--a-text); }

.btn--primary { background: var(--fg-primary); border-color: var(--fg-primary); color: #fff;
                box-shadow: var(--a-shadow-cta); }
/* The filled buttons keep DARKENING on hover, as the rest of the product
   does. A lighter fill would sit better with a lifting shadow, and the
   picked design showed one -- but it cannot be had at this text size.
   Measured 2026-09-06, white on each fill:
       #0079b8 (rest)            4.74:1   passes AA
       #0086cc (lighter hover)   3.98:1   FAILS -- 14px/500 needs 4.5:1
       #00419e (--fg-primary-dark) 9.33:1 passes comfortably
   Brightening a blue this saturated cannot reach 4.5:1 against white at
   all (the ceiling is around #0080c4 at 4.30:1), so the lift and the
   deeper shadow carry the "raised" reading instead, and the fill goes the
   safe direction. */
.btn--primary:hover:not(:disabled) { background: var(--fg-primary-dark);
                                     border-color: var(--fg-primary-dark);
                                     box-shadow: var(--a-shadow-cta-hover);
                                     color: #fff; }
.btn--danger  { background: var(--a-danger); border-color: var(--a-danger); color: #fff;
                box-shadow: var(--a-shadow-danger); }
/* Same reasoning: --a-danger is 5.02:1 with white and brightening it eats
   that margin, so this darkens as it always did. */
.btn--danger:hover:not(:disabled) { filter: brightness(.9);
                                    box-shadow: var(--a-shadow-danger-hover);
                                    color: #fff; }
/* Ghost stays flat and stays put. It is the quiet inline action -- giving it
   the same lift as a real button would promote it past what it is. */
.btn--ghost   { background: transparent; border-color: transparent; color: var(--fg-primary);
                box-shadow: none; }
.btn--ghost:hover:not(:disabled) { background: var(--fg-tint); transform: none; box-shadow: none;
                                   color: var(--fg-primary); }
.btn--sm { min-height: 3.2rem; padding: 0 1.1rem; font-size: 1.3rem; }

/* The Save/Back(/Delete) stack in an edit form's sidebar rail -- .btn is
   inline-flex, sized to its own content, which is right for a toolbar row
   but left "Save changes" sitting narrow while "Back to list" filled the
   whole card next to it. Three different view files (property-edit.js,
   simple-edit.js, terms.js) had each given the BACK link its own one-off
   `display:block` to reach full width, but never gave the SAVE button the
   same treatment -- this replaces all three with one shared class that
   sizes every button in the stack the same way. */
.rail-actions { display: grid; gap: .8rem; }
.rail-actions .btn { width: 100%; }

/* Disabled must be obvious AND non-interactive; opacity alone reads as "still
   clickable" to a lot of people. Elevation says "pressable", so a disabled
   button gives it up entirely and sits flat on the page. */
.btn:disabled { opacity: .45; cursor: not-allowed; box-shadow: none; transform: none; }
.btn[aria-busy="true"] { cursor: progress; }

/* The lift is the primary hover cue, and it is motion. Anyone who asked for
   less of it still needs to know the pointer is on a button, so the cue
   falls back to the tint the buttons used before this style -- the shadow
   still deepens, it just no longer moves. */
@media (prefers-reduced-motion: reduce) {
    .btn:hover:not(:disabled),
    .btn:active:not(:disabled) { transform: none; }
    .btn:hover:not(:disabled) { background: var(--fg-tint); }
    .btn--primary:hover:not(:disabled) { background: var(--fg-primary-dark); }
    .btn--danger:hover:not(:disabled)  { background: var(--a-danger); }
}

/* ---------------------------------------------------------------- fields -- */
.field { display: block; }
.field + .field { margin-top: 1.6rem; }
.field > label,
.fieldset > legend {
    display: block; margin-bottom: .6rem;
    font-size: 1.2rem; font-weight: 500; color: var(--a-heading);
}
.field__req { color: var(--a-danger); margin-left: .3rem; }
/* Persistent helper text, not a placeholder that vanishes the moment you type */
.field__hint { display: block; margin-top: .5rem; font-size: 1.2rem; color: var(--a-text-muted); }

/* Compact pass, same reasoning as .btn's own: 3.6rem/13px instead of
   4rem/14px, matching the toolbar buttons beside these fields rather than
   sitting a size apart from them.

   Filled/tonal: no border, no shadow, just --a-field-fill's tint marking
   the box against the white card -- back to the shared --a-radius (8px,
   same as buttons/cards) now that shape isn't doing the defining work a
   border or a shadow would. */
.input, .select, .textarea {
    display: block; width: 100%;
    min-height: 3.6rem; padding: .6rem .9rem;
    font: inherit; font-size: 1.3rem; color: var(--a-text);
    background: var(--a-field-fill);
    border: 1px solid transparent;
    border-radius: var(--a-radius);
}
.textarea { min-height: 12rem; resize: vertical; line-height: 1.6; }
.input:disabled, .select:disabled, .textarea:disabled {
    background: var(--fg-tint); color: var(--a-text-muted); cursor: not-allowed;
}
/* Read-only is NOT disabled: the value still matters and is still selectable. */
.input[readonly] { background: var(--fg-tint); }

.field--bad .input, .field--bad .select, .field--bad .textarea { border-color: var(--a-danger); border-width: 2px; }
.field__err {
    display: flex; align-items: center; gap: .6rem;
    margin-top: .6rem; font-size: 1.25rem; color: var(--a-danger);
}
.field__err::before {
    content: "!"; flex: none;
    width: 1.6rem; height: 1.6rem; line-height: 1.6rem; text-align: center;
    background: var(--a-danger); color: #fff; font-size: 1.1rem; font-weight: 700;
}

.row { display: grid; gap: 1.2rem; }
.row--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.row--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.row .field + .field { margin-top: 0; }

.fieldset { border: 0; padding: 0; margin: 0; }
.check-grid {
    display: grid; gap: .6rem 1.6rem;
    grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
    margin-top: .4rem;
}
.check { display: flex; align-items: center; gap: .8rem; font-size: 1.35rem; cursor: pointer; }
.check input { width: 1.7rem; height: 1.7rem; accent-color: var(--fg-primary); cursor: pointer; }

/* ----------------------------------------------------------------- table -- */
/* The wrapper is what scrolls, so a wide table never widens the document. */
.table-wrap { overflow-x: auto; }
.table { width: 100%; border-collapse: collapse; font-size: 1.5rem; }
.table th, .table td { padding: var(--a-row-pad); text-align: left; vertical-align: middle; }
.table thead th {
    position: sticky; top: 0; z-index: 1;
    background: var(--fg-tint);
    font-size: 1.3rem; letter-spacing: .04em; text-transform: uppercase;   /* see deviation 5 */
    color: var(--a-text-muted); font-weight: 500;
    border-bottom: 1px solid var(--a-border);
    white-space: nowrap;
}
.table tbody tr { border-bottom: 1px solid var(--a-border); }
.table tbody tr:hover { background: var(--fg-tint); }
.table td.num, .table th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* Sort buttons live inside the th so the whole header is not a click target by
   accident, and aria-sort on the th is what a screen reader announces. */
.th-sort {
    display: inline-flex; align-items: center; gap: .5rem;
    background: none; border: 0; padding: 0; margin: 0;
    font: inherit; color: inherit; text-transform: inherit; letter-spacing: inherit;
    cursor: pointer;
}
.th-sort::after { content: "\2195"; opacity: .45; font-size: 1.1rem; }
[aria-sort="ascending"]  .th-sort::after { content: "\2191"; opacity: 1; }
[aria-sort="descending"] .th-sort::after { content: "\2193"; opacity: 1; }

.thumb {
    width: 7.4rem; height: 5.4rem; object-fit: cover;   /* see deviation 5 */
    background: var(--fg-tint); display: block;
    border-radius: var(--a-radius);
}
.thumb--none {
    display: flex; align-items: center; justify-content: center;
    font-size: 1.1rem; color: var(--a-text-muted);
}

.t-title { display: block; font-weight: 500; color: var(--a-heading); }
.t-title:hover { color: var(--fg-primary); }
.t-sub { display: block; font-size: 1.2rem; color: var(--a-text-muted); margin-top: .2rem; }

/* ------------------------------------------------------------------ pill -- */
.pill {
    display: inline-block; padding: .4rem 1.1rem;   /* see deviation 5 */
    font-size: 1.25rem; font-weight: 500; line-height: 1.5;
    border: 1px solid transparent; border-radius: 999px;
    white-space: nowrap;
}
/* Every pill carries a word, never colour alone. */
.pill--live   { background: #e6f4ea; color: #14622c; border-color: #b7ddc2; }
.pill--draft  { background: var(--fg-tint); color: #5a4a00; border-color: #ded2a0; }
.pill--gone   { background: #f2f2f2; color: #4d4d4d; border-color: var(--a-border); }
.pill--star   { background: #e7f2f9; color: #005b8c; border-color: #b7d8ea; }

/* ------------------------------------------------------------- toolbar ---- */
.toolbar {
    display: flex; flex-wrap: wrap; align-items: flex-end; gap: 1.3rem;
    padding: 2rem 2.2rem; border-bottom: 1px solid var(--a-border);   /* see deviation 5 */
}
.toolbar .field { margin: 0; }
.toolbar__spacer { flex: 1 1 2rem; }
.toolbar__count { font-size: 1.3rem; color: var(--a-text-muted); }

.pager { display: flex; align-items: center; gap: .6rem; padding: 1.4rem 2rem; flex-wrap: wrap; }
.pager__spacer { flex: 1; }

/* ------------------------------------------------------------ empty/load -- */
.empty { padding: 6rem 2rem; text-align: center; }
.empty h3 { margin: 0 0 .8rem; font-size: 1.7rem; }
.empty p { margin: 0 auto 2rem; max-width: 46rem; color: var(--a-text-muted); }

/* Reserves the row height so the table does not jump when data lands. */
.skel { background: var(--fg-tint); height: 1.2rem; animation: pulse 1.2s var(--a-ease) infinite; }
@keyframes pulse { 50% { opacity: .45; } }

/* ----------------------------------------------------------------- login -- */
.login-page {
    min-height: 100vh; min-height: 100dvh;
    display: grid; place-items: center; padding: 2.4rem;
    background: var(--a-page);
}
.login { width: 100%; max-width: 40rem; }
.login .card__body { padding: 2.8rem; }
.login h1 { margin: 0 0 .4rem; font-size: 2.2rem; }
.login__sub { margin: 0 0 2.4rem; color: var(--a-text-muted); font-size: 1.35rem; }
.login .btn { width: 100%; }

/* Not a toast: an error you must be able to read, re-read and act on. */
.notice {
    display: flex; gap: 1rem; padding: 1.2rem 1.4rem; margin-bottom: 1.6rem;
    font-size: 1.3rem; border-left: 4px solid;
}
.notice--bad  { background: #fdecee; color: #8a1420; border-color: var(--a-danger); }
.notice--info { background: #eaf3f9; color: #114a68; border-color: var(--fg-primary); }
.notice--warn { background: #fdf6e3; color: #6b5300; border-color: #c9a227; }

/* ---------------------------------------------------------------- toasts -- */
.toasts {
    position: fixed; right: 2rem; bottom: 2rem; z-index: 60;
    display: flex; flex-direction: column; gap: .8rem;
    max-width: 38rem;
}
.toast {
    background: #242a30; color: #fff; padding: 1.2rem 1.6rem;
    font-size: 1.35rem; box-shadow: var(--fg-shadow-raised);
    animation: toast-in var(--a-fast) var(--a-ease);
}
.toast--bad { background: var(--a-danger); }
.toast--ok  { background: var(--a-ok); }
@keyframes toast-in { from { opacity: 0; transform: translateY(.8rem); } }

/* ------------------------------------------------------------ responsive -- */
/* Desktop-first is correct for this tool, but it must not break on a laptop or
   a tablet an agent actually carries. */
/* ------------------------------------------------------- property form -- */
/* This layout used to be set with inline styles from property-edit.js, which
   meant the responsive rule below needed two !important declarations just to
   beat them. Owning it here removes the need for either. */
.prop-edit-grid {
    display: grid;
    gap: 2rem;
    grid-template-columns: minmax(0, 1fr) 32rem;
    align-items: start;
}
.prop-rail {
    position: sticky;
    /* clears the sticky topbar */
    top: 8rem;
    align-self: start;
}

/* The form's two columns collapse before the sidebar does, so the rail never
   squeezes the form into an unusable width on a laptop. */
@media (max-width: 1240px) {
    .prop-edit-grid { grid-template-columns: minmax(0, 1fr); }
    .prop-rail { position: static; }
}

@media (max-width: 1000px) {
    .app { grid-template-columns: 1fr; }
    .rail { position: static; height: auto; }
    .rail__nav { display: flex; flex-wrap: wrap; padding: .6rem; }
    .rail__group { display: none; }
    .rail__link { padding: 1rem 1.4rem; border-left: 0; border-bottom: 3px solid transparent; }
    .rail__link[aria-current="page"] { border-left: 0; border-bottom-color: var(--a-rail-active); }
    .content { padding: 1.6rem; }
    .topbar { padding: 1.4rem 1.6rem; }
}
@media (max-width: 640px) {
    .row--2, .row--3 { grid-template-columns: 1fr; }
    .row .field + .field { margin-top: 1.6rem; }
    .toasts { left: 1rem; right: 1rem; max-width: none; }
}
