/* ==========================================================================
   Tenant onboarding portal — design tokens and components

   Everything visual is driven by the custom properties in :root. To rebrand,
   change the token values; do not edit the component rules below.
   ========================================================================== */

:root {
  /* Brand ----------------------------------------------------------------
     Taken from the RDK Real Estate site: deep navy, warm paper, and a muted
     blue for accents. Warm neutrals throughout — a cool grey next to this
     cream reads as dirty rather than neutral. */
  --brand:            #1b2f52;
  --brand-strong:     #101f39;
  --brand-tint:       #eef1f6;
  --brand-contrast:   #ffffff;
  --accent:           #4a6c9b;

  /* Ink and surfaces ----------------------------------------------------- */
  --ink:              #1a1c1f;
  --ink-soft:         #4a4f57;
  --ink-muted:        #7b7c85;
  --surface:          #ffffff;
  --canvas:           #f7f4ee;
  --line:             #e2dcd1;
  --line-soft:        #efeae1;

  /* Chrome --------------------------------------------------------------- */
  /* The brand navy, the same one the public site's masthead and footer carry.
     Staff and visitors should look at one system rather than two. */
  --header:           #001B3A;
  --header-ink:       #f3efe8;
  --subnav:           #f2ece1;

  /* Status --------------------------------------------------------------- */
  --ok:               #3f6b4c;
  --ok-tint:          #e9f0ea;
  --warn:             #8a6100;
  --warn-tint:        #fdf5e4;
  --error:            #9c2b30;
  --error-tint:       #f9ecec;

  /* Type ----------------------------------------------------------------- */
  --font-display: "Cormorant Garamond", Georgia, "Times New Roman", serif;
  --font: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Table content. Separate from the body face on purpose: this is the type
     somebody scans forty rows of looking for one name, and it is chosen for
     legibility at 14px rather than for how it reads in a paragraph. */
  --font-data: "Source Sans 3", system-ui, -apple-system, "Segoe UI", sans-serif;

  --fs-xs:   0.8125rem;
  --fs-sm:   0.875rem;
  --fs-base: 1rem;
  --fs-lg:   1.125rem;
  --fs-h4:   1.0625rem;
  --fs-h3:   1.375rem;
  --fs-h2:   2rem;
  --fs-h1:   2.5rem;

  /* The letterspaced small caps used for labels and table headings. */
  --track-wide: .14em;

  /* Space ---------------------------------------------------------------- */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;
  --sp-7: 3rem;

  /* Shape ---------------------------------------------------------------- */
  --radius:    4px;
  --radius-sm: 3px;
  --shadow:    0 1px 2px rgba(26, 28, 31, .04), 0 8px 28px rgba(26, 28, 31, .05);
  --focus:     0 0 0 3px rgba(74, 108, 155, .30);

  --wrap: 78rem;
}

/* ==========================================================================
   Base
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--fs-base);
  line-height: 1.55;
  color: var(--ink);
  background: var(--canvas);
}

.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--sp-4); }

main.wrap { flex: 1; padding-block: var(--sp-6) var(--sp-7); }

/* The signed-out pages stack; the shell handles its own height. */
body:not(.app) { display: flex; flex-direction: column; min-height: 100vh; }

h1, h2, h3, h4 { margin: 0; line-height: 1.25; font-weight: 650; letter-spacing: -0.01em; }

.h1 { font-size: var(--fs-h1); }
.h2 { font-size: var(--fs-h2); }
.h3 { font-size: var(--fs-h3); }
.h4 { font-size: var(--fs-h4); font-weight: 650; }

p { margin: 0 0 var(--sp-3); }

a { color: var(--brand); }

.muted { color: var(--ink-muted); }
.muted-inline { color: var(--ink-muted); font-weight: 400; }
.small { font-size: var(--fs-sm); }
.mt { margin-top: var(--sp-4); }
.mt-sm { margin-top: var(--sp-2); }

code {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  background: var(--line-soft);
  padding: 0.1em 0.35em;
  border-radius: 4px;
  font-size: 0.9em;
}

.code-lg { font-size: 1.25rem; letter-spacing: .18em; font-weight: 700; }

.skip {
  position: absolute; left: -9999px;
  background: var(--brand); color: var(--brand-contrast);
  padding: var(--sp-2) var(--sp-4);
}
.skip:focus { left: var(--sp-4); top: var(--sp-2); z-index: 10; }

/* ==========================================================================
   App shell — a rail down the side, the page's own name across the top
   ========================================================================== */

/* Only when signed in. The tenant journey keeps the plain stacked page below.

   The rail is fixed, so the page is held off it by padding rather than by a
   column — which is what keeps the top bar sticky and the footer full width.
   Opening the rail widens that padding, or the wider rail would simply cover
   what it is meant to sit beside. */
.app {
  display: block;
  padding-left: var(--rail);
  transition: padding-left .16s ease;
}

.app.rail-is-open { padding-left: var(--rail-open); }

:root { --rail: 3.5rem; --rail-open: 15rem; }

.rail {
  position: fixed; inset: 0 auto 0 0; z-index: 20;
  width: var(--rail);
  display: flex; flex-direction: column;
  background: var(--header);
  color: #fff;
  overflow: hidden;
  transition: width .16s ease;
}

/* Widened by the button at the top, and remembered between pages. The names are
   in the markup either way — the collapsed rail hides them rather than omitting
   them, so a screen reader always has them. */
.rail-open { width: var(--rail-open); }

.rail-word {
  white-space: nowrap;
  opacity: 0; width: 0; overflow: hidden;
  transition: opacity .12s ease;
}

.rail-open .rail-word { opacity: 1; width: auto; }

/* Collapsed, the mark gets nearly the whole width of the rail. A wordmark held
   inside a 1rem gutter on each side has 1.5rem left to live in, which is not
   enough of it to read. The gutter comes back when the rail opens and there is
   room for it. */
.rail-brand {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-3);
  height: var(--rail); flex: none;
  padding-inline: .375rem;
  color: #fff; text-decoration: none;
  font-weight: 650; font-size: var(--fs-sm);
  background: rgb(255 255 255 / .06);
}

.rail-open .rail-brand { justify-content: flex-start; padding-inline: 1rem; }

/* The logo is a wordmark — nearly three times as wide as it is tall. Sized by
   its height it came out three times wider than the collapsed rail, and the
   rail's own overflow:hidden cut the end off it. In a 3.5rem column the width
   is the constraint, so the width is what is set and the height follows. */
.rail-brand img {
  flex: none;
  max-width: 100%;
  width: auto; height: auto;
  max-height: 2rem;
}

.rail-initials {
  display: grid; place-items: center;
  width: 1.5rem; height: 1.5rem; flex: none;
  font-size: .6875rem; font-weight: 700; letter-spacing: .04em;
}

.rail-toggle,
.rail-item {
  display: flex; align-items: center; gap: var(--sp-3);
  height: 2.75rem; flex: none;
  padding-inline: 1rem;
  border: 0; background: transparent;
  color: rgb(255 255 255 / .72);
  font: inherit; font-size: var(--fs-sm);
  text-decoration: none; text-align: left;
  cursor: pointer;
  white-space: nowrap;
}

.rail-toggle svg,
.rail-item svg { flex: none; }

.rail-toggle:hover,
.rail-item:hover { background: rgb(255 255 255 / .08); color: #fff; }

.rail-toggle:focus-visible,
.rail-item:focus-visible { outline: 2px solid #fff; outline-offset: -2px; }

.rail-nav { display: flex; flex-direction: column; }

/* The section you are in, marked by a bar on the edge as well as by colour —
   a tint alone is not enough to find at a glance in a column of eight. */
.rail-on {
  background: rgb(255 255 255 / .12);
  color: #fff;
  box-shadow: inset 3px 0 0 #fff;
}

.shell { display: flex; flex-direction: column; min-height: 100vh; }

/* White, so the page's name sits on its own surface rather than on the canvas. */
.topbar {
  position: sticky; top: 0; z-index: 10;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-5);
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

.topbar-title {
  font-size: var(--fs-h4); font-weight: 650;
  letter-spacing: -0.01em;
  margin: 0;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.topbar-right { display: flex; align-items: center; gap: var(--sp-4); }

.shell-main { flex: 1; padding-block: var(--sp-5) var(--sp-7); }

/* On a phone the rail lies flat across the top: a fixed column would take a
   third of the width, and the page is what somebody came for. */
@media (max-width: 48rem) {
  .app, .app.rail-is-open { padding-left: 0; }

  .rail {
    position: static;
    width: auto;
    flex-direction: row; flex-wrap: wrap; align-items: center;
  }

  .rail-toggle { display: none; }
  .rail-nav { flex-direction: row; flex-wrap: wrap; }
  .rail-brand { padding-inline: var(--sp-4); }
  .rail-on { box-shadow: inset 0 -3px 0 #fff; }

  /* The name of the page gets its own line rather than an ellipsis. "T…" is not
     a title, and on a phone there is no width to share with the sign-out. */
  .topbar {
    flex-direction: column; align-items: flex-start;
    gap: var(--sp-2);
    padding-inline: var(--sp-4);
    position: static;
  }

  .topbar-title { white-space: normal; overflow: visible; }
  .topbar-right { width: 100%; justify-content: space-between; }
}

/* ==========================================================================
   Masthead and footer
   ========================================================================== */

.masthead { background: var(--surface); border-bottom: 1px solid var(--line); }

.masthead-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4); padding-block: var(--sp-3);
}

.brand { display: flex; align-items: center; gap: var(--sp-3); }

.brand-mark {
  width: 2.25rem; height: 2.25rem; flex: none;
  display: grid; place-items: center;
  background: var(--brand); color: var(--brand-contrast);
  border-radius: var(--radius-sm);
  font-weight: 700; font-size: var(--fs-sm); letter-spacing: .04em;
}

/* The logo where one has been provided; the lettering mark where it has not.
   Height is fixed and width follows, so any sensible logo sits correctly without
   anyone having to crop it to a particular shape first. */
.brand-logo {
  height: 2.25rem; width: auto; flex: none;
  max-width: 10rem; object-fit: contain;
}

.brand-text { display: flex; flex-direction: column; line-height: 1.2; }
.brand-name { font-weight: 650; font-size: var(--fs-sm); }
.brand-sub  { color: var(--ink-muted); font-size: var(--fs-xs); }

.env-flag {
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--warn); background: var(--warn-tint);
  border: 1px solid rgba(138, 97, 0, .25);
  padding: var(--sp-1) var(--sp-2); border-radius: 999px;
}

.footer {
  border-top: 1px solid var(--line); background: var(--surface);
  padding-block: var(--sp-4);
  color: var(--ink-muted); font-size: var(--fs-sm);
}
.footer p { margin: 0; }

/* ==========================================================================
   Journey header and stepper
   ========================================================================== */

.journey-head { margin-bottom: var(--sp-5); }

.journey-head .meta { color: var(--ink-soft); font-size: var(--fs-sm); margin: var(--sp-2) 0 0; }
.journey-head .dot  { color: var(--line); margin-inline: var(--sp-2); }

.stepper {
  list-style: none; margin: 0 0 var(--sp-5); padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-5);
}

.step { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); }

.step-num {
  width: 1.65rem; height: 1.65rem; flex: none;
  display: grid; place-items: center;
  border-radius: 50%; font-size: var(--fs-xs); font-weight: 700;
  border: 1.5px solid var(--line); color: var(--ink-muted); background: var(--surface);
}

.step-label { color: var(--ink-muted); }

.step-done .step-num    { background: var(--brand); border-color: var(--brand); color: var(--brand-contrast); }
.step-done .step-label  { color: var(--ink-soft); }

.step-current .step-num   { border-color: var(--brand); color: var(--brand); background: var(--brand-tint); }
.step-current .step-label { color: var(--ink); font-weight: 650; }

/* ==========================================================================
   Card
   ========================================================================== */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: var(--sp-5);
}

.card > .h3 + .muted { margin-top: var(--sp-2); }

.card-centre { text-align: center; max-width: 34rem; margin-inline: auto; }
.card-centre .lead { font-size: var(--fs-lg); color: var(--ink-soft); }

.stack > * + * { margin-top: var(--sp-4); }

.card h3.h4 {
  margin-top: var(--sp-5);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--line-soft);
}

/* ==========================================================================
   Forms
   ========================================================================== */

.grid { display: grid; gap: var(--sp-4); }
.grid-2 { grid-template-columns: 1fr; }
.grid-3 { grid-template-columns: 1fr; }

@media (min-width: 40rem) {
  .grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 60rem) {
  .grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.field { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.field-narrow { max-width: 14rem; }

/* A field that takes the whole row of a grid — a URL, where a half-width box
   hides the end of what was pasted into it. */
.field-wide { grid-column: 1 / -1; }

.label { font-size: var(--fs-sm); font-weight: 650; color: var(--ink-soft); }

.input {
  font: inherit; color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.6rem 0.7rem;
  width: 100%;
  transition: border-color .12s, box-shadow .12s;
}

.input:hover { border-color: #c6cdd6; }

.input:focus-visible {
  outline: none;
  border-color: var(--brand);
  box-shadow: var(--focus);
}

.input[readonly] { background: var(--line-soft); color: var(--ink-muted); }

select.input {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%236b7583' d='M1.4 0 6 4.6 10.6 0 12 1.4 6 7.4 0 1.4z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  padding-right: 2.25rem;
}

.input-code {
  font-size: 1.5rem; letter-spacing: .5em; text-align: center;
  font-variant-numeric: tabular-nums;
}

.file {
  font: inherit; font-size: var(--fs-sm);
  border: 1px dashed var(--line); border-radius: var(--radius-sm);
  padding: var(--sp-3); width: 100%; background: var(--surface);
}
.file::file-selector-button {
  font: inherit; font-size: var(--fs-sm); font-weight: 600;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink-soft);
  padding: 0.3rem 0.6rem; margin-right: var(--sp-3); cursor: pointer;
}

.hint  { font-size: var(--fs-xs); color: var(--ink-muted); }

/*
  Two things on one line: a value and a quiet note beside it.

  A flex gap rather than a space in the markup, because there is no space in the
  markup to rely on. Razor drops whitespace that contains a newline between two
  tags, so

      <strong>@unit</strong>
      <span class="hint">Annual rent changed</span>

  renders as "1203Annual rent changed". Putting the two in a flex row makes the
  separation a layout rule instead of a typing accident, and it works the same
  where the first item is a bare @expression with no tag of its own.
*/
.beside { display: flex; align-items: baseline; gap: var(--sp-2); }
.error { font-size: var(--fs-xs); color: var(--error); font-weight: 600; }
.error:empty { display: none; }

.confirm {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  font-size: var(--fs-sm); line-height: 1.5;
  padding: var(--sp-3) 0;
}
.confirm + .confirm { border-top: 1px solid var(--line-soft); }
.confirm input { margin-top: 0.25rem; width: 1rem; height: 1rem; flex: none; accent-color: var(--brand); }

.confirm-consent {
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: var(--sp-3) var(--sp-4); background: var(--canvas);
}

/* ==========================================================================
   Buttons
   ========================================================================== */

.actions { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.actions-end { justify-content: flex-end; margin-top: var(--sp-5); }

.btn {
  font: inherit; font-weight: 650; font-size: var(--fs-sm);
  border-radius: var(--radius-sm);
  padding: 0.6rem 1.1rem;
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background-color .12s, border-color .12s, color .12s;
}

.btn:focus-visible { outline: none; box-shadow: var(--focus); }

.btn-primary { background: var(--brand); color: var(--brand-contrast); }
.btn-primary:hover { background: var(--brand-strong); }

.btn-secondary {
  background: var(--surface); color: var(--ink); border-color: var(--line);
}
.btn-secondary:hover { border-color: #c6cdd6; background: var(--canvas); }

.btn-link {
  background: none; color: var(--brand); padding-inline: var(--sp-2);
}
.btn-link:hover { text-decoration: underline; }

.btn-sm { font-size: var(--fs-xs); padding: 0.4rem 0.75rem; }

/* ==========================================================================
   Chips, alerts, notices
   ========================================================================== */

.chip {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: var(--fs-xs); font-weight: 650;
  padding: 0.15rem 0.55rem; border-radius: 999px;
  border: 1px solid transparent; white-space: nowrap;
}
.chip-sm { font-size: 0.75rem; padding: 0.1rem 0.45rem; }

.chip-ok    { background: var(--ok-tint);   color: var(--ok);    border-color: rgba(23,104,63,.2); }
.chip-warn  { background: var(--warn-tint); color: var(--warn);  border-color: rgba(138,97,0,.25); }
.chip-todo  { background: var(--brand-tint);color: var(--brand); border-color: rgba(30,77,140,.2); }
.chip-quiet { background: var(--line-soft); color: var(--ink-muted); }

.alert {
  border-radius: var(--radius-sm);
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-sm);
  border: 1px solid transparent;
}
.alert p:last-child { margin-bottom: 0; }
.alert-error { background: var(--error-tint); color: var(--error); border-color: rgba(164,35,42,.22); }
.alert-warn  { background: var(--warn-tint);  color: #5c4100;      border-color: rgba(138,97,0,.25); }
.alert-error:empty { display: none; }

/* A plain .alert had padding, a transparent border and no colour of its own —
   which rendered a success as bare text sitting in space, looking like a fault
   rather than a confirmation. Pages that still show one now show something
   deliberate. */
.alert-ok { background: var(--ok-tint); color: var(--ok); border-color: rgba(23,104,63,.2); }

/* A confirmation that follows you down the page.
   Sticky rather than fixed: it takes part in the layout, so it pushes the table
   down by its own height once instead of covering the first rows of it, and it
   stops being pinned when the page it belongs to scrolls away. The shadow is
   what stops it reading as part of the row it happens to be over. */
.alert-live {
  position: sticky;
  top: var(--sp-3);
  z-index: 5;
  box-shadow: 0 2px 10px rgb(16 24 40 / .10);
}

/* The row that was just changed. Paired with the fragment the handlers redirect
   to, so the browser scrolls to it and it says which one it was - the rent and
   the switch are small controls on a wide row, and "which of these eighty did I
   just press" is a real question a second afterwards. */
.table tbody tr:target > td {
  background: var(--ok-tint);
  box-shadow: inset 0 1px 0 rgba(23,104,63,.22), inset 0 -1px 0 rgba(23,104,63,.22);
}

.table tbody tr:target > td:first-child { box-shadow: inset 1px 1px 0 rgba(23,104,63,.22), inset 0 -1px 0 rgba(23,104,63,.22); }
.table tbody tr:target > td:last-child  { box-shadow: inset -1px 1px 0 rgba(23,104,63,.22), inset 0 -1px 0 rgba(23,104,63,.22); }

/* Scrolled to by the browser, so it should not land flush against the pinned
   confirmation above it. */
.table tbody tr[id] { scroll-margin-top: 5rem; }

.notice {
  border-left: 3px solid var(--line);
  background: var(--canvas);
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-sm);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  margin-top: var(--sp-4);
}
.notice-dev { border-left-color: var(--warn); background: var(--warn-tint); }

/* ==========================================================================
   Document checklist
   ========================================================================== */

.doc-list { display: flex; flex-direction: column; gap: var(--sp-3); margin-top: var(--sp-4); }

.doc {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: var(--sp-4);
  background: var(--surface);
}
.doc-done { border-color: rgba(23,104,63,.3); background: linear-gradient(0deg, var(--ok-tint) 0%, var(--surface) 60%); }

.doc-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap;
}

.doc-name { font-weight: 650; }

.doc-upload { display: flex; align-items: center; gap: var(--sp-3); margin-top: var(--sp-3); flex-wrap: wrap; }
.doc-upload .file { flex: 1 1 16rem; }

.doc-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); margin-top: var(--sp-3);
  padding-top: var(--sp-2); border-top: 1px solid var(--line-soft);
}

.extracted { margin: var(--sp-3) 0 0; display: flex; flex-direction: column; gap: var(--sp-1); }

.extracted-row {
  display: grid; grid-template-columns: 1fr; gap: 0;
  padding: var(--sp-1) 0;
  font-size: var(--fs-sm);
}

@media (min-width: 34rem) {
  .extracted-row { grid-template-columns: 11rem 1fr; align-items: baseline; gap: var(--sp-3); }
}

.extracted-row dt { color: var(--ink-muted); font-size: var(--fs-xs); }
.extracted-row dd { margin: 0; display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }

/* ==========================================================================
   Review summary
   ========================================================================== */

.summary { margin: var(--sp-4) 0 0; border-top: 1px solid var(--line-soft); }

.summary-row {
  display: grid; grid-template-columns: 1fr; gap: 0;
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--line-soft);
  font-size: var(--fs-sm);
}

@media (min-width: 34rem) {
  .summary-row { grid-template-columns: 13rem 1fr; align-items: baseline; gap: var(--sp-4); }
}

.summary-row dt { color: var(--ink-muted); }
.summary-row dd { margin: 0; display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }

.value { font-weight: 650; }

/* ==========================================================================
   Confirmation
   ========================================================================== */

.tick {
  width: 3rem; height: 3rem; margin: 0 auto var(--sp-4);
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--ok-tint); color: var(--ok);
  font-size: 1.5rem; font-weight: 700;
}
.tick-warn { background: var(--warn-tint); color: var(--warn); }

.next { text-align: left; margin-top: var(--sp-5); }

.steps-list { margin: var(--sp-3) 0 0; padding-left: 1.25rem; font-size: var(--fs-sm); color: var(--ink-soft); }
.steps-list li + li { margin-top: var(--sp-2); }

/* ==========================================================================
   Table (development launcher only)
   ========================================================================== */

.table { width: 100%; border-collapse: collapse; margin: var(--sp-4) 0; font-size: var(--fs-sm); }
.table th {
  text-align: left; font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink-muted); border-bottom: 1px solid var(--line); padding: var(--sp-2);
}
.table td { padding: var(--sp-3) var(--sp-2); border-bottom: 1px solid var(--line-soft); vertical-align: middle; }

/* ==========================================================================
   Motion
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; }
}

/* ==========================================================================
   Agent screens
   ========================================================================== */

.agent-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--sp-4); flex-wrap: wrap; margin-bottom: var(--sp-5);
}
.agent-head p { margin: var(--sp-1) 0 0; }

.nowrap { white-space: nowrap; }

.bar {
  width: 6rem; height: 6px; border-radius: 999px;
  background: var(--line-soft); overflow: hidden;
}
.bar span { display: block; height: 100%; background: var(--brand); border-radius: 999px; }

.linkbox { text-align: left; }
.link-raw {
  display: block; margin-top: var(--sp-3);
  word-break: break-all; font-size: var(--fs-xs); line-height: 1.5;
  background: var(--surface); border: 1px solid var(--line);
  padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-sm);
}

/* ==========================================================================
   Authentication
   ========================================================================== */

.masthead-right { display: flex; align-items: center; gap: var(--sp-3); }

.whoami { display: flex; flex-direction: column; line-height: 1.2; text-align: right; }
.whoami-name { font-size: var(--fs-sm); font-weight: 650; }
.whoami-role { font-size: var(--fs-xs); color: var(--ink-muted); }

.signout { margin: 0; }

.card-signin { max-width: 26rem; margin-inline: auto; }
.card-signin .muted { margin-bottom: var(--sp-4); }

.btn-block { width: 100%; }

/* ==========================================================================
   Back office — review queue and review screen
   ========================================================================== */

.staffnav {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.staffnav-inner { display: flex; gap: var(--sp-5); }
.staffnav a {
  display: inline-block; padding: var(--sp-3) 0;
  font-size: var(--fs-sm); font-weight: 600; color: var(--ink-soft);
  text-decoration: none; border-bottom: 2px solid transparent;
}
.staffnav a:hover { color: var(--brand); border-bottom-color: var(--line); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* The way back, as a button, with whatever trail follows it as quiet text. The
   button is the thing you press; the crumbs after it are context, and turning
   those into buttons too would give a reader four things to press and one place
   they actually meant to go. */
.backlink {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--sp-2);
  margin-bottom: var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--ink-muted);
}

/* Filters ---------------------------------------------------------------- */

.filters { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-4); }
.filter {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3); border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface);
  font-size: var(--fs-sm); color: var(--ink-soft); text-decoration: none;
}
.filter:hover { border-color: var(--brand); color: var(--brand); }
.filter-on {
  background: var(--brand); border-color: var(--brand); color: var(--brand-contrast);
}
.filter-count {
  font-variant-numeric: tabular-nums; font-weight: 650;
  background: rgba(0, 0, 0, .08); border-radius: 999px; padding: 0 var(--sp-2);
}
.filter-on .filter-count { background: rgba(255, 255, 255, .22); }

/* Review header and approval -------------------------------------------- */

.review-head {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: var(--sp-4); margin-bottom: var(--sp-4);
}
.review-head p { margin: var(--sp-1) 0 0; }
.review-head-status { display: flex; flex-wrap: wrap; gap: var(--sp-2); justify-content: flex-end; }

.approve-bar { margin-bottom: var(--sp-4); }
.approve-form {
  display: flex; justify-content: space-between; align-items: center;
  gap: var(--sp-4); flex-wrap: wrap; margin: 0;
}
.approve-controls { display: flex; gap: var(--sp-2); align-items: center; }
.approve-controls .input { min-width: 18rem; }

/* Two-column review ------------------------------------------------------ */

.review-split {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--sp-4); align-items: start;
}
.review-flags { display: flex; flex-direction: column; gap: var(--sp-4); }

/* The viewer follows the reviewer down a long exception list, because the
   whole point is to compare the document against the value. */
.review-viewer { position: sticky; top: var(--sp-4); }

@media (max-width: 60rem) {
  .review-split { grid-template-columns: minmax(0, 1fr); }
  .review-viewer { position: static; }
}

/* Exception cards -------------------------------------------------------- */

.flag { border-left: 4px solid var(--line); }
.flag-block  { border-left-color: var(--error); }
.flag-advice { border-left-color: var(--warn); }
.flag-done   { border-left-color: var(--ok); background: var(--canvas); }
.flag-inview { box-shadow: 0 0 0 2px var(--brand-tint); }

.flag-head { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.flag-head h2 { margin: 0; }
.flag-head .hint { margin-left: auto; font-variant-numeric: tabular-nums; }

.flag-detail { margin: var(--sp-3) 0 0; color: var(--ink-soft); }
.flag-source { margin: var(--sp-2) 0 0; font-size: var(--fs-sm); }

.flag-form { margin-top: var(--sp-4); }
.flag-form .field { margin-bottom: var(--sp-3); }
.flag-form textarea.input { resize: vertical; }
.flag-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }

/* A recorded decision ---------------------------------------------------- */

.decision {
  margin-top: var(--sp-3); padding: var(--sp-3);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-sm); font-size: var(--fs-sm);
}
.decision-change { margin-top: var(--sp-2); display: flex; gap: var(--sp-2); align-items: center; }
.decision-note { margin: var(--sp-2) 0 0; color: var(--ink-soft); font-style: italic; }

.was { text-decoration: line-through; color: var(--ink-muted); }
.now { font-weight: 650; }

/* Document viewer -------------------------------------------------------- */

.viewer-tabs { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin-bottom: var(--sp-3); }
.viewer-tab {
  padding: var(--sp-1) var(--sp-3); border-radius: var(--radius-sm);
  border: 1px solid var(--line); background: var(--surface);
  font-size: var(--fs-xs); font-variant-numeric: tabular-nums;
  color: var(--ink-soft); text-decoration: none;
}
.viewer-tab:hover { border-color: var(--brand); color: var(--brand); }
.viewer-tab-on { background: var(--brand-tint); border-color: var(--brand); color: var(--brand-strong); }

.viewer-title { margin: 0 0 var(--sp-3); }

.viewer-frame {
  width: 100%; height: 26rem; border: 1px solid var(--line);
  border-radius: var(--radius-sm); background: var(--canvas);
}

/* ==========================================================================
   Returned for correction (BL-11)
   ========================================================================== */

.returned {
  background: var(--warn-tint); border: 1px solid var(--warn);
  border-radius: var(--radius); padding: var(--sp-4) var(--sp-5);
  margin-bottom: var(--sp-4);
}
.returned-title { margin: 0 0 var(--sp-2); color: var(--warn); }
.returned-lead { margin: 0 0 var(--sp-3); }

.returned-list { margin: 0; padding-left: var(--sp-5); display: grid; gap: var(--sp-3); }
.returned-item-head { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.returned-what { font-weight: 650; }
.returned-note { margin: var(--sp-1) 0 0; color: var(--ink-soft); font-style: italic; }
.returned-done .returned-what { color: var(--ink-muted); }

/* A slot the tenant has been asked to replace, and one they may not touch. */
.doc-returned { border-color: var(--warn); box-shadow: inset 3px 0 0 var(--warn); }
.doc-locked { opacity: .72; }
.doc-returned-note {
  margin: var(--sp-3) 0 0; padding: var(--sp-2) var(--sp-3);
  background: var(--warn-tint); border-radius: var(--radius-sm); font-size: var(--fs-sm);
}

/* A fieldset used only to lock a form; it should not look like a fieldset. */
fieldset.plain { border: 0; margin: 0; padding: 0; min-inline-size: 0; }
fieldset.plain[disabled] .input { background: var(--line-soft); color: var(--ink-muted); }

/* Reviewer's view of what is out with the tenant. */
.waiting-bar { margin-bottom: var(--sp-4); border-left: 4px solid var(--warn); }
.waiting-list { margin: var(--sp-3) 0 0; padding: 0; list-style: none; display: grid; gap: var(--sp-2); }
.waiting-list li { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; font-size: var(--fs-sm); }

/* Notification log ------------------------------------------------------- */

.outbox-body td { padding-top: 0; border-top: 0; }
.outbox-subject { font-weight: 650; font-size: var(--fs-sm); margin-bottom: var(--sp-1); }
.outbox-text {
  margin: 0; padding: var(--sp-3);
  background: var(--canvas); border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
  font-family: inherit; font-size: var(--fs-sm); color: var(--ink-soft);
  white-space: pre-wrap; word-break: break-word;
}

/* Row actions on the tracker ---------------------------------------------- */

.rowmenu { position: relative; display: inline-block; }
.rowmenu > summary { list-style: none; cursor: pointer; }
.rowmenu > summary::-webkit-details-marker { display: none; }

.rowmenu-body {
  position: absolute; right: 0; z-index: 20; width: 22rem;
  margin-top: var(--sp-2); padding: var(--sp-4);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: 0 12px 28px rgba(22, 25, 29, .14);
  text-align: left;
}
.rowmenu-form { margin: 0 0 var(--sp-4); }
.rowmenu-form:last-child { margin-bottom: 0; }
.rowmenu-row { display: flex; gap: var(--sp-2); align-items: center; }
.rowmenu-row .input { flex: 1 1 auto; }

/* ==========================================================================
   Dashboard — SCR-11
   ========================================================================== */

.filterbar {
  display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: flex-end;
  margin-bottom: var(--sp-4);
}
.filterbar .field { margin: 0; }
.filterbar .actions { margin-left: auto; }

/* Header tiles. A figure with no plot needs no chart — the number is the point. */
.tiles {
  display: grid; gap: var(--sp-3); margin-bottom: var(--sp-3);
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}
.tile {
  display: flex; flex-direction: column; gap: var(--sp-1);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: var(--sp-4);
}
.tile-label { font-size: var(--fs-sm); color: var(--ink-soft); font-weight: 600; }
.tile-figure {
  font-size: 2rem; font-weight: 700; line-height: 1.1;
  font-variant-numeric: tabular-nums; color: var(--ink); text-decoration: none;
}
a.tile-figure:hover { color: var(--brand); text-decoration: underline; }
.tile-absent { color: var(--ink-muted); }

.dash-scope { margin: 0 0 var(--sp-4); font-size: var(--fs-sm); }

.views { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fit, minmax(24rem, 1fr)); }
.view { margin: 0; }
.view-wide { grid-column: 1 / -1; }

/* Secondary figures within a view. */
.figures { display: flex; flex-wrap: wrap; gap: var(--sp-4); margin: var(--sp-4) 0; }
.figure {
  display: flex; flex-direction: column; gap: var(--sp-1);
  text-decoration: none; color: inherit; min-width: 7rem;
}
a.figure:hover .figure-value { color: var(--brand); text-decoration: underline; }
.figure-value { font-size: var(--fs-h3); font-weight: 700; font-variant-numeric: tabular-nums; }
.figure-label { font-size: var(--fs-xs); color: var(--ink-muted); }
.figure-alert .figure-value { color: var(--error); }
.figure-flat { cursor: default; }

/* Single-series bars. One hue, direct-labelled, so no legend and no palette to
   get wrong; the value sits beside every bar, which is also the table view. */
.meters { display: grid; gap: var(--sp-2); }
.meter {
  display: grid; grid-template-columns: minmax(7rem, 12rem) 1fr auto;
  align-items: center; gap: var(--sp-3);
  text-decoration: none; color: inherit; padding: 2px 0;
}
.meter:hover .meter-fill { background: var(--brand-strong); }
.meter:hover .meter-label { color: var(--brand); }
.meter-label {
  font-size: var(--fs-sm); color: var(--ink-soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.meter-track { height: 10px; background: var(--line-soft); border-radius: 999px; overflow: hidden; }
.meter-fill { display: block; height: 100%; background: var(--brand); border-radius: 999px; }
.meter-value {
  display: flex; align-items: baseline; justify-content: flex-end; gap: var(--sp-2);
  font-size: var(--fs-sm); font-weight: 650; font-variant-numeric: tabular-nums;
  min-width: 3.5rem; text-align: right;
}

.profile-grid { display: grid; gap: var(--sp-5); grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); }
.profile-group h3 { margin: 0 0 var(--sp-3); }

@media (max-width: 48rem) {
  .views { grid-template-columns: minmax(0, 1fr); }
  .meter { grid-template-columns: minmax(5rem, 8rem) 1fr auto; }
}

/* Property administration */
.permit-form { display: flex; align-items: center; gap: var(--sp-2); margin: 0; }
.input-tiny { width: 5rem; padding: var(--sp-1) var(--sp-2); }

.layout {
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: var(--sp-4); margin-top: var(--sp-4);
}
.layout-head { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--sp-4); flex-wrap: wrap; }
.layout-head h3 { margin: 0; }
.layout-head p { margin: var(--sp-1) 0 0; }
.layout-controls { display: flex; align-items: flex-end; gap: var(--sp-4); flex-wrap: wrap; }
.layout-controls .label { display: block; margin-bottom: var(--sp-1); }

/* Configuration sub-navigation */
.submenu { display: flex; gap: var(--sp-1); margin-bottom: var(--sp-4); flex-wrap: wrap; }
.submenu-item {
  padding: var(--sp-2) var(--sp-4); border-radius: var(--radius-sm);
  border: 1px solid var(--line); background: var(--surface);
  font-size: var(--fs-sm); font-weight: 600; color: var(--ink-soft); text-decoration: none;
}
a.submenu-item:hover { border-color: var(--brand); color: var(--brand); }
.submenu-on { background: var(--brand-tint); border-color: var(--brand); color: var(--brand-strong); }

/* Card pages */
.card-actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center; }
.btn-danger { background: var(--surface); border: 1px solid var(--error); color: var(--error); }
.btn-danger:hover { background: var(--error-tint); }
.blocked-reason { font-size: var(--fs-xs); color: var(--ink-muted); max-width: 26rem; }

/* ==========================================================================
   Staff administration
   ========================================================================== */

/* A label that sits beside its own control rather than above it. */
.checkbox {
  display: flex; align-items: baseline; gap: var(--sp-2);
  font-weight: 400; cursor: pointer;
}

.checkbox input { margin: 0; }

/* Property assignment: a column at narrow widths, two or three where there is
   room, so a long portfolio does not become a long scroll. */
.checklist {
  display: grid; gap: var(--sp-2); margin-top: var(--sp-3);
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}

.checklist .checkbox {
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface);
}

/* A row that has become a form. Tinted, so it is obvious which of twelve rows
   is the one being edited — and padded, because a form crammed to a cell's
   default padding reads as a rendering fault rather than as an editor. */
.row-editing > td {
  background: var(--brand-tint);
  padding: var(--sp-4) var(--sp-3);
}

/* Amenities -----------------------------------------------------------------
   The icon the public site will draw, beside the name, so what is being ticked
   is the thing a visitor will actually see rather than a word standing in for
   it. Centred rather than on the baseline, because a 20px mark and a line of
   text share a centre and not a baseline. */

.amenitypick { align-items: center; gap: var(--sp-2); }

.amenitypick .amenity-icon { flex: none; color: var(--brand); }

.amenitypick-name { flex: 1; min-width: 0; }

/* Withdrawn from the master, and still ticked here. Shown quietly rather than
   hidden: a tick should never disappear without somebody having untucked it. */
.amenitypick-off { color: var(--ink-muted); }
.amenitypick-off .amenity-icon { color: var(--ink-muted); }

/* The icon on its own in a table cell, and inline beside its name on a card. */
.iconcell { width: 1px; color: var(--brand); }

/* dd.iconline, not .iconline: inside a summary row the dd already aligns on the
   baseline, and a mark and a line of text share a centre rather than a baseline. */
dd.iconline, .iconline {
  display: flex; align-items: center; gap: var(--sp-2);
  color: var(--brand);
}

.amenity-icon { display: block; }

/* ==========================================================================
   Duplicate detection (BL-07 / EX-05)
   ========================================================================== */

/* Warm rather than red: a match is a question for a reviewer, not a failure. */
.duplicate-bar { border-left: 3px solid var(--warn); }

.decided {
  margin-top: var(--sp-3); padding: var(--sp-2) var(--sp-3);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}

/* A file refused before it was sent. Spoken by the browser, in the same voice
   the server uses for MSG-402. */
.upload-refusal:empty { display: none; }

.upload-refusal {
  margin: var(--sp-2) 0 0;
  font-size: var(--fs-xs); line-height: 1.5;
  color: var(--error); font-weight: 600;
}

/* ---------------------------------------------------------------------------
   Searching and paging a list
   --------------------------------------------------------------------------- */

.listfilter { padding-bottom: var(--sp-4); }

/* Wraps rather than scrolls: on a phone the search box takes the width and the
   page size drops beneath it, which is the order somebody uses them in. */
.listfilter-row {
  display: flex; flex-wrap: wrap; align-items: flex-end;
  gap: var(--sp-3);
}
.listfilter-row .field { flex: 1 1 18rem; margin: 0; }
.listfilter-row .field-narrow { flex: 0 1 12rem; }
.listfilter-row .actions { margin: 0; }

.pager {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--sp-3); margin-top: var(--sp-4);
  padding-top: var(--sp-3); border-top: 1px solid var(--line-soft);
}
.pager p { margin: 0; }
.pager-controls { display: flex; align-items: center; gap: var(--sp-3); }

/* Label and value pairs on a detail page. Two columns where there is room for
   them, stacked where there is not. */
.detail { display: grid; grid-template-columns: 12rem 1fr; gap: var(--sp-2) var(--sp-4); margin: 0; }
.detail dt { color: var(--ink-muted); font-size: var(--fs-sm); }
.detail dd { margin: 0; }

@media (max-width: 40rem) {
  .detail { grid-template-columns: 1fr; gap: 0 0; }
  .detail dd { margin-bottom: var(--sp-3); }
}


/* ==========================================================================
   Brand skin

   The RDK look, applied over the components above rather than through them:
   a near-black masthead, a paper sub-navigation, serif display type and
   letterspaced small caps for anything that labels something else.

   Deliberately last in the file. Every rule here has the same specificity as
   the one it replaces and wins by position, so the components above stay
   readable as components and this stays readable as a skin.
   ========================================================================== */

/* Display type. Serif for headings only — a working screen read all day wants
   a sans for its content, whatever the marketing site does. */
.h1, .h2, .h3 {
  font-family: var(--font-display);
  font-weight: 500;
  letter-spacing: 0;
  line-height: 1.15;
}
.h1 { font-size: var(--fs-h1); }
.h2 { font-size: var(--fs-h2); }

/* Anything that names something else: table headings, field labels, the
   sub-navigation. Small, wide, and quiet. */
.table th,
.label,
.staffnav a,
.pager .muted {
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: var(--track-wide);
  font-size: 0.6875rem;
  font-weight: 500;
}

.label { color: var(--ink-muted); }

.table th {
  color: var(--ink-muted);
  border-bottom: 1px solid var(--ink);
  padding-block: var(--sp-3);
}

/* Row content. Slightly narrower than the body sans, which is why long email
   addresses stop wrapping and a row of six columns still fits. */
.table td {
  font-family: var(--font-data);
  font-size: 0.9375rem;
  padding-block: var(--sp-4);
}

/* Figures line up when they are compared down a column, which on this screen
   they always are — references, unit numbers, dates, ages. */
.table td.nowrap,
.link-raw,
.code-lg,
.input-code {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* Masthead ---------------------------------------------------------------- */

.masthead {
  background: var(--header);
  border-bottom: none;
  color: var(--header-ink);
}
.masthead-inner { padding-block: var(--sp-4); }
.masthead a { color: var(--header-ink); }

.brand-name {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: .01em;
}
.brand-sub {
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: var(--track-wide);
  font-size: 0.625rem;
  color: rgba(243, 239, 232, .62);
}

/* The logo is a grey mark on a dark bar, so it needs no inversion — but it
   does need room to breathe against the lettering beside it. */
.brand { gap: var(--sp-4); }
.brand-logo { height: 1.75rem; }
.brand-mark { background: var(--accent); }

/* The name and role used to sit on the dark masthead and were coloured for it.
   They live on the white top bar now, so the base rules above — dark ink on a
   light surface — are the right ones and this override is gone. Only the role's
   lettering is worth keeping. */
.whoami-role {
  font-family: var(--font-mono);
  text-transform: uppercase; letter-spacing: var(--track-wide);
  font-size: 0.625rem;
}
.masthead .btn-link { color: var(--header-ink); }

/* Sub-navigation ---------------------------------------------------------- */

.staffnav {
  background: var(--subnav);
  border-bottom: 1px solid var(--line);
}
.staffnav-inner { gap: var(--sp-6); }
.staffnav a {
  color: var(--ink-soft);
  padding-block: var(--sp-4);
  border-bottom-width: 1px;
}
.staffnav a:hover {
  color: var(--brand);
  border-bottom-color: var(--brand);
}

/* Page furniture ---------------------------------------------------------- */

.agent-head {
  align-items: flex-end;
  padding-bottom: var(--sp-5);
  margin-bottom: var(--sp-5);
  border-bottom: 1px solid var(--line);
}

.card {
  border-radius: var(--radius);
  border: 1px solid var(--line);
  box-shadow: none;
}

.input {
  border-radius: var(--radius-sm);
  border-color: var(--line);
  background: var(--surface);
}
.input:hover { border-color: #cfc7b8; }

.btn {
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: .1em;
  font-size: 0.6875rem;
  font-weight: 500;
}
.btn-secondary { border-color: var(--brand); color: var(--brand); background: transparent; }
.btn-secondary:hover { background: var(--brand-tint); border-color: var(--brand); }
.btn-link { text-transform: none; letter-spacing: 0; font-family: var(--font); font-size: var(--fs-sm); }

.chip {
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: .08em;
  font-size: 0.625rem;
}

/* The filter band, as a band across the page rather than a floating card. */
.listfilter {
  background: var(--subnav);
  border-inline: none;
  border-radius: 0;
  margin-inline: calc(-1 * var(--sp-4));
  padding-inline: var(--sp-4);
}

/* Paging sits at the foot of the list, centred, as the last thing on the page. */
.pager {
  justify-content: center;
  flex-direction: column;
  gap: var(--sp-2);
  padding-top: var(--sp-5);
  margin-top: var(--sp-5);
  border-top: 1px solid var(--line);
}
.pager-controls { gap: var(--sp-5); }

/* Footer ------------------------------------------------------------------ */

.footer {
  background: var(--brand-strong);
  border-top: none;
  color: rgba(243, 239, 232, .72);
  padding-block: var(--sp-6);
}
.footer p { max-width: 60rem; }

/* ==========================================================================
   Excel import — the column picker
   ========================================================================== */

.columnpick {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--sp-4);
  margin: 0;
}

.columnpick legend {
  padding-inline: var(--sp-2);
  margin-left: calc(var(--sp-2) * -1);
}

/* Two or three across where there is room. A portfolio has eleven unit columns
   and a single list of them reads as a wall. */
.columnpick-grid {
  display: grid; gap: var(--sp-3);
  grid-template-columns: repeat(auto-fill, minmax(310px, 1fr));
}

/* Each option is a label, a state and an explanation stacked together, so the
   hint belongs to its own checkbox rather than floating between two. */
.columnpick .checkbox > span {
  display: flex; flex-direction: column; gap: 2px;
}

.checkbox-label { font-weight: 500; }

/* The label and the sentence under it, stacked. A column rather than two spans
   in a row: Razor drops the newline between them, so without this the
   explanation runs straight on from the label. */
.checkbox-text { display: flex; flex-direction: column; gap: 2px; }

.columnpick .hint { margin: 0; }

/* A required column is shown ticked and disabled. Greyed enough to read as
   "decided", not so grey it reads as "unavailable". */
.checkbox-fixed { opacity: .8; cursor: default; }
.checkbox-fixed input { cursor: default; }

/* ==========================================================================
   Layout photographs
   ========================================================================== */

.gallery {
  display: grid; gap: var(--sp-4);
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  margin-block: var(--sp-4);
}

/* One picture rather than a row of them: the same tile, held to a tile's width
   instead of stretching across the card. */
.gallery-one { grid-template-columns: minmax(0, 20rem); }

/* A column, so the caption can be pushed to the bottom. The tiles in a row are
   the same height because the grid stretches them; without this the caption of a
   tile that also carries an "Also used by" line sits lower than its neighbours',
   and a row of four reads as four different components. */
.shot {
  margin: 0;
  display: flex; flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
}

/* Fixed aspect and cover, so eight photographs from eight different phones make
   one tidy grid rather than a ragged column. */
.shot img {
  display: block; width: 100%;
  aspect-ratio: 4 / 3; object-fit: cover;
  background: var(--brand-tint);
}

/* The frame the controls sit over. Positioned so they can, and clipped so a
   button in a corner follows the tile's own rounding. */
.shot-frame { position: relative; }

/* The actions, over the photograph rather than listed under it. Three of them in
   words took more room than the picture they belonged to.

   Always visible rather than revealed on hover: hover does not exist on a phone,
   and a control nobody can find is not a control. */
.shot-tools {
  position: absolute; top: var(--sp-2); right: var(--sp-2);
  display: flex; gap: var(--sp-1);
}

/* Which photograph carries the card, said on the photograph itself. */
.shot-lead {
  position: absolute; left: var(--sp-2); bottom: var(--sp-2);
  padding: .25rem .5rem;
  border-radius: var(--radius-sm);
  background: rgb(14 14 15 / .62);
  color: #fff;
  font-size: .625rem; font-weight: 650;
  letter-spacing: .1em; text-transform: uppercase;
  backdrop-filter: blur(3px);
}

.shot figcaption {
  display: flex; flex-direction: column; gap: var(--sp-1);
  margin-top: auto;
  padding: var(--sp-2);
  border-top: 1px solid var(--line-soft);
}

/* The caption and the button that saves it, in one control. */
.shot-caption { display: flex; gap: var(--sp-2); align-items: center; }
.shot-caption .input { font-size: var(--fs-sm); min-width: 0; }

/* The file box and the button that sends it, likewise. Two boxes a row apart made
   it look as though choosing a file had already done the job. */
.uploadbar { display: flex; gap: var(--sp-2); align-items: center; }
.uploadbar .input { min-width: 0; }

/* ==========================================================================
   Row actions — a horizontal set of icon buttons
   ========================================================================== */

/* Each action posts something different, so each is its own form. Forms are
   block-level and stack; this puts them back on one line. */
.rowactions { display: flex; align-items: center; gap: var(--sp-2); }

.rowactions form { display: contents; }

.iconbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem;
  padding: 0;
  background: var(--surface);
  color: var(--brand);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  cursor: pointer;
}

.iconbtn:hover {
  background: var(--brand); border-color: var(--brand); color: var(--brand-contrast);
}

.iconbtn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* The primary action of the three, filled so it reads first. */
.iconbtn-solid {
  background: var(--brand); border-color: var(--brand); color: var(--brand-contrast);
}

.iconbtn-solid:hover { background: var(--brand-strong); border-color: var(--brand-strong); }

/* On an image, so the chrome has to carry itself rather than borrow the page's
   white. Dark and slightly blurred, which reads on a bright façade and on a
   night shot alike. */
.iconbtn-over {
  background: rgb(14 14 15 / .55);
  border-color: rgb(255 255 255 / .28);
  color: #fff;
  backdrop-filter: blur(3px);
}

.iconbtn-over:hover {
  background: var(--brand); border-color: var(--brand); color: var(--brand-contrast);
}

/* Removing is the one that cannot be undone, so it is the one that is red — but
   only once you are on it. Red at rest in a row of three trains people to ignore
   the colour. */
/* Marked at rest, not only on hover.
   
   These three buttons are now pictures with no words beside them, and the
   destructive one had exactly the same weight and colour as the other two until
   the pointer touched it. The glyph is a bin, so it is not unreadable — but
   asking the eye to tell a bin from a pencil at 18 pixels before it commits is
   work it should not have to do. Colour only, no fill: the row stays quiet. */
.iconbtn-danger {
  color: var(--error);
  border-color: rgb(156 43 48 / .28);
}

.iconbtn-danger:hover {
  background: var(--error); border-color: var(--error); color: #fff;
}

/* ==========================================================================
   Editing inside a table row

   A field and its save button on one line inside a cell, for the columns that
   are edited in a sweep rather than one at a time — forty rents down a tower.
   Each row is its own form, so one save never carries another row's value.
   ========================================================================== */

.cellform { display: flex; align-items: center; gap: var(--sp-2); }

/* Shorter than a field on a form. A table row is 2.25rem of chrome already and
   a full-height input in every row turns the table into a stack of boxes. */
.input-sm { padding: .35rem .5rem; font-size: var(--fs-sm); }

/* Wide enough for an annual rent in dirhams — seven figures and a separator —
   and no wider, or the column pushes everything after it off the screen. */
.cellnum { width: 7.5rem; text-align: right; }

/* The rent's own hint sits under the field rather than beside it: the column is
   already as wide as it should be. */
.cellform + .hint { display: block; margin-top: .25rem; }

/* ==========================================================================
   A switch

   For a thing that is on or off right now, rather than a thing you are about to
   do — "listed" is a state, and a button labelled "List" would be describing
   the action and leaving the state to be inferred from which label is showing.

   It is a submit button, so it works with scripting off; the form posts and the
   row comes back in its new state.
   ========================================================================== */

.switch {
  position: relative;
  display: inline-block;
  width: 2.5rem; height: 1.375rem;
  padding: 0; border: 1px solid var(--line);
  border-radius: 999px;
  background: #e8e9ec;
  cursor: pointer;
  transition: background .14s ease, border-color .14s ease;
}

.switch-knob {
  position: absolute; top: 50%; left: .1875rem;
  transform: translateY(-50%);
  width: .9375rem; height: .9375rem;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: 0 1px 2px rgb(16 31 57 / .3);
  transition: left .14s ease;
}

.switch-on { background: var(--ok); border-color: var(--ok); }

.switch-on .switch-knob { left: calc(100% - 1.125rem); }

.switch:hover { border-color: var(--brand); }

.switch:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* ==========================================================================
   The application timeline

   One list out of four logs. A list rather than a table because the rows are
   not comparable — a status change, a reminder and somebody opening a passport
   have nothing in common to line up in columns, and a table with three empty
   cells in every row reads worse than a sentence.

   The rule down the left is what makes it a timeline rather than a list, and the
   marker's colour is the only thing that says which log a line came from. It is
   deliberately quiet: which table a fact was stored in is the reader's last
   question, not their first.
   ========================================================================== */

.timeline { list-style: none; margin: var(--sp-4) 0 0; padding: 0 0 0 var(--sp-5); position: relative; }

.timeline::before {
  content: ""; position: absolute; left: 0.32rem; top: 0.6rem; bottom: 0.6rem;
  width: 1px; background: var(--line);
}

.timeline-day {
  font-size: var(--fs-xs); font-weight: 650; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-muted);
  margin: var(--sp-4) 0 var(--sp-2); position: relative;
}
.timeline-day:first-child { margin-top: 0; }

.timeline-item {
  display: grid;
  grid-template-columns: 3.25rem minmax(0, 1fr) auto;
  align-items: baseline;
  gap: var(--sp-2) var(--sp-3);
  padding: 0.3rem 0;
  position: relative;
  font-size: var(--fs-sm);
}

/* The marker, centred on the rule. */
.timeline-item::before {
  content: ""; position: absolute; left: calc(-1 * var(--sp-5) + 0.08rem); top: 0.62rem;
  width: 0.5rem; height: 0.5rem; border-radius: 999px;
  background: var(--surface); border: 1.5px solid var(--ink-muted);
}

.timeline-change::before   { border-color: var(--brand); }
.timeline-decision::before { border-color: var(--ok); }
.timeline-message::before  { border-color: var(--ink-muted); }
.timeline-access::before   { border-color: var(--warn); }

.timeline-at { font-variant-numeric: tabular-nums; color: var(--ink-muted); font-size: var(--fs-xs); }

.timeline-what { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.timeline-said { color: var(--ink); }
.timeline-detail { font-size: var(--fs-xs); color: var(--ink-muted); overflow-wrap: anywhere; }

.timeline-who { font-size: var(--fs-xs); color: var(--ink-muted); text-align: right; white-space: nowrap; }

/* On a phone the actor moves under the event rather than off the edge. */
@media (max-width: 40rem) {
  .timeline-item { grid-template-columns: 3.25rem minmax(0, 1fr); }
  .timeline-who { grid-column: 2; text-align: left; }
}

/* ==========================================================================
   The portfolio change log

   A stripe down the left of each row, and nothing else. The two kinds somebody
   comes here for — a price, and whether a unit is on the public site — are
   worth finding at a glance in five hundred rows, and a colour on the edge does
   that without turning an audit log into a chart.
   ========================================================================== */

.change-rent    > td:first-child { box-shadow: inset 3px 0 0 var(--brand); }
.change-listing > td:first-child { box-shadow: inset 3px 0 0 var(--ok); }
.change-gone    > td:first-child { box-shadow: inset 3px 0 0 var(--error); }
