/* harcourts.css build 20260917-a6b11fb3 */
/* ==========================================================================
   Harcourts Dapto | Albion Park | Shellharbour
   Brand Stylesheet — single source of truth
   --------------------------------------------------------------------------
   Every Atlas-generated page links this file.
   Never override these tokens inline. If a new pattern is needed, add it
   here as a class first, then use the class on the page.

   Brand reference: Harcourts International Brand Standards
   Primary: Harcourts Blue #001f49 | Accent: Harcourts Cyan #00aeef
   Typography: Source Sans Pro
   ========================================================================== */

/* ---------- Fonts (self-host in /assets/fonts) ----------------------------- */
/* Primary: Source Sans 3 (formerly Source Sans Pro) — self-hosted.
   Every page must link static/fonts/brand-fonts.css BEFORE this file
   (deployed estate-wide via integrations/deploy_brand_fonts.py).
   No CDN font loads — the old Google @import was removed 12/06/2026. */
/* Secondary: Harcourts Script — licensed font, self-hosted from assets/fonts/ */

@font-face {
  font-family: 'HarcourtsScript';
  /* Path resolves relative to where harcourts.css is served. Each app
     symlinks the font into its static/fonts/ dir so this works everywhere. */
  src: url('./fonts/HarcourtsScript.woff') format('woff'),
       url('./fonts/HarcourtsScript.ttf')  format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ---------- Design tokens -------------------------------------------------- */
/* COLOUR IS NOT IN THIS BLOCK. Every raw colour token lives in
   brand/palette-harcourts.css and is spliced in immediately below, between the
   PALETTE markers, by `brand/sync.sh --apply`. Edit a colour THERE, never here
   and never inside the generated block — `brand/sync.sh` fails if the two
   disagree, and fails again if a name is declared in both. What is left here is
   shape: type, space, radius, shadow geometry, motion, z-index, component knobs.
   (Phase 4, 14/09/2026 — the split moved 34 tokens and changed no value.) */
:root {

  /* Typography */
  --h-font-sans:    'Source Sans 3', 'Source Sans Pro', -apple-system, BlinkMacSystemFont, sans-serif;
  --h-font-display: 'Source Sans 3', 'Source Sans Pro', sans-serif;
  --h-font-script:  'HarcourtsScript', cursive;  /* Secondary — personality/single words only */
  --h-font-mono:    ui-monospace, 'SF Mono', Menlo, Consolas, monospace;  /* figures/code — NOT JetBrains (that's the Wealth brand) */

  --h-fs-xs:       0.75rem;   /* 12 */
  --h-fs-sm:       0.875rem;  /* 14 */
  --h-fs-base:     1rem;      /* 16 */
  --h-fs-lg:       1.125rem;  /* 18 */
  --h-fs-xl:       1.375rem;  /* 22 */
  --h-fs-2xl:      1.75rem;   /* 28 */
  --h-fs-3xl:      2.25rem;   /* 36 */
  --h-fs-4xl:      3rem;      /* 48 */
  --h-fs-5xl:      4rem;      /* 64 */

  --h-fw-extralight: 200;  /* brand weight set is 200/300/400/600/700 — 200 is the light end of the weight-extreme pairing */
  --h-fw-light:    300;
  --h-fw-regular:  400;
  --h-fw-semibold: 600;
  --h-fw-bold:     700;

  --h-lh-tight:    1.15;
  --h-lh-snug:     1.35;
  --h-lh-base:     1.6;

  --h-tracking-tight: -0.025em;  /* -25 per brand spec, used for headings */
  --h-tracking-body:  -0.01em;   /* -10 per brand spec, used for body */
  --h-tracking-wide:  0.08em;

  /* Spacing scale (4px base). Every step is an exact multiple of the base
     unit, so the scale is composed from it: change --h-space-unit and the
     whole scale moves together. Multipliers 1 2 3 4 6 8 12 16 24 32.
     (Phase 3, 14/09/2026 — values unchanged, proven by the visual baseline.) */
  --h-space-unit: 0.25rem;
  --h-s-1:  calc(var(--h-space-unit) *  1);
  --h-s-2:  calc(var(--h-space-unit) *  2);
  --h-s-3:  calc(var(--h-space-unit) *  3);
  --h-s-4:  calc(var(--h-space-unit) *  4);
  --h-s-5:  calc(var(--h-space-unit) *  6);
  --h-s-6:  calc(var(--h-space-unit) *  8);
  --h-s-8:  calc(var(--h-space-unit) * 12);
  --h-s-10: calc(var(--h-space-unit) * 16);
  --h-s-12: calc(var(--h-space-unit) * 24);
  --h-s-16: calc(var(--h-space-unit) * 32);

  /* Layout */
  --h-container:   1200px;
  --h-container-narrow: 880px;

  /* Radius — Harcourts is restrained; keep small */
  --h-radius-sm:   2px;
  --h-radius:      4px;
  --h-radius-lg:   8px;
  --h-radius-pill: 999px;    /* ONLY for circles and the toggle switch — never for badges, chips, tabs or counts (MG standard 04/09/2026) */

  /* Borders — the hairline width is its own knob; both borders compose it. */
  --h-border-w:    1px;
  --h-border:      var(--h-border-w) solid var(--h-grey-10);
  --h-border-strong: var(--h-border-w) solid var(--h-grey-30);

  /* Shadows — subtle only. Every shadow is navy at a low alpha; the three
     alphas are knobs here so "softer" or "stronger" is one edit, not three
     hand-written rgba()s. Offsets and blur stay hand-set per level. The navy
     itself (--h-shadow-rgb) is a colour and lives in palette-harcourts.css. */
  --h-shadow-a-sm: 0.06;
  --h-shadow-a:    0.08;
  --h-shadow-a-lg: 0.12;
  --h-shadow-sm:   0 1px 2px rgba(var(--h-shadow-rgb), var(--h-shadow-a-sm));
  --h-shadow:      0 2px 8px rgba(var(--h-shadow-rgb), var(--h-shadow-a));
  --h-shadow-lg:   0 12px 32px rgba(var(--h-shadow-rgb), var(--h-shadow-a-lg));

  /* Motion */
  --h-ease:        cubic-bezier(0.4, 0, 0.2, 1);
  --h-duration:    180ms;

  /* Z-index scale — always use these, never invent magic numbers.
     nav < dropdown < backdrop < modal < toast. */
  --h-z-nav:      100;
  --h-z-dropdown: 300;
  --h-z-backdrop: 800;
  --h-z-modal:    900;
  --h-z-toast:    1000;

  /* Focus — keyboard ring (cyan is reserved for focus/accent). The glow itself
     (--h-focus-glow) is raw colour and lives in palette-harcourts.css. */
  --h-focus-ring-w: 2px;
  --h-focus-glow-spread: 3px;
  --h-focus-ring: var(--h-focus-ring-w) solid var(--h-cyan);

  /* Focus glow, recoloured for a field already carrying a verdict. Use ONLY
     with a matching border-colour — the glow alone is not the signal.
     Added 14/09/2026 with the state matrix (phase 2, section A). */
  --h-focus-glow-error:   0 0 0 var(--h-focus-glow-spread) var(--h-error-soft);
  --h-focus-glow-success: 0 0 0 var(--h-focus-glow-spread) var(--h-success-soft);

  /* Component knobs (Phase 3, 14/09/2026). Each one carries the value the
     component already had — the declarations below were rewritten to read
     these instead of repeating the literal, so the rendering is unchanged and
     the styleguide's tuning panel has something to turn.
     --h-btn-min-h is the touch target: BRAND.md's button standard and the
     44px minimum both live here, so do not take it below 44.
     --h-field-min-h is `auto` on purpose: fields have never carried a minimum
     height (their height comes from padding + line-height), and `auto` is the
     initial value, so nothing moves until someone sets one. */
  --h-btn-min-h:     44px;
  --h-btn-pad-y:     var(--h-s-3);
  --h-btn-pad-x:     var(--h-s-5);
  --h-btn-fs:        var(--h-fs-base);
  --h-btn-fw:        var(--h-fw-semibold);
  --h-btn-radius:    var(--h-radius);
  --h-btn-border-w:  1px;

  --h-field-min-h:    auto;
  --h-field-pad-y:    var(--h-s-3);
  --h-field-pad-x:    var(--h-s-4);
  --h-field-fs:       var(--h-fs-base);
  --h-field-radius:   var(--h-radius);
  --h-field-border-w: var(--h-border-w);
  --h-field-border-c: var(--h-grey-30);
  --h-label-fs:       var(--h-fs-sm);
  --h-label-fw:       var(--h-fw-semibold);

  /* Breakpoints — DOCUMENTATION ONLY (added 14/09/2026, phase 2 section J).
     A custom property cannot drive an @media query, so these do not and cannot
     replace the 56 hand-written queries in this file. They exist so JS
     (matchMedia) and new code read one scale instead of inventing an 11th
     value. Which scale step each existing query rounds to is in the phase 2
     report. Use the nearest step for anything new; never add a new width. */
  --h-bp-phone:  640px;   /* 21 queries today — the dominant phone breakpoint */
  --h-bp-tablet: 768px;   /* 17 queries today, spread over 700/720/760/768 */
  --h-bp-laptop: 900px;   /* 12 queries today, over 860/900 — shell + sidebar */
  --h-bp-wide:  1100px;   /*  3 queries today, over 1000/1100 — wide tables */
}

/* === PALETTE harcourts — GENERATED from brand/palette-harcourts.css by brand/sync.sh. Edit THAT file. === */
:root {
  /* Brand colours — primary */
  --h-blue:        #001f49;   /* Harcourts Blue — dominant */
  --h-blue-90:     #0a2a55;
  --h-blue-80:     #1a3a65;
  --h-blue-20:     #cdd4de;
  --h-blue-10:     #e6e9ee;

  /* Brand colours — accent (use sparingly, never majority) */
  --h-cyan:        #00aeef;   /* Harcourts Cyan (Pantone Process Cyan C, RGB 0/174/239) — accents only */
  --h-cyan-90:     #0098d1;

  /* Neutrals */
  --h-black:       #000000;
  --h-charcoal:    #1a1a1a;
  --h-ink:         #2a2a2a;   /* body text */
  --h-grey-70:     #4a4a4a;
  --h-grey-50:     #8a8a8a;
  --h-grey-30:     #c8c8c8;   /* Harcourts Mid Grey (PDF spec: RGB 200/200/200) */
  --h-grey-10:     #ececec;
  --h-paper:       #f7f7f5;   /* off-white page bg */
  --h-white:       #ffffff;

  /* Status (used sparingly, never compete with brand) */
  --h-success:     #008752;
  --h-warning:     #fbb040;
  --h-error:       #d11242;

  /* Status — soft tint + ink pairs, for badges/alerts/row highlights.
     Tint is ~10% of the status colour on white; ink passes AA on its tint.
     Use these instead of inventing #dcfce7-style Tailwind pairs. */
  --h-success-soft: #e6f3ee;
  --h-success-ink:  #005835;
  --h-warning-soft: #fff7ec;
  --h-warning-ink:  #7a4d00;
  --h-error-soft:   #fae7ec;
  --h-error-ink:    #920d2e;
  --h-info-soft:    #e6f7fd;
  --h-info-ink:     #006a91;

  /* Dark surfaces — navy-derived set for dark-chrome dashboards (Pulse).
     Never mix with off-brand darks (#0f172a etc.). */
  --h-dark-surface: #001233;   /* page background */
  --h-dark-raise:   #002a63;   /* cards / raised panels */
  --h-dark-line:    #1a3a5c;   /* hairlines on dark */
  --h-dark-text:    #e6e9ee;   /* body text on dark */
  --h-dark-muted:   #98a8c3;   /* secondary text on dark */

  /* Shadow tint — navy as an "r, g, b" triplet, so each shadow level in
     harcourts.css can set its own alpha against it. The three alphas and the
     offsets are shape and stay there. */
  --h-shadow-rgb:  0, 31, 73;

  /* Focus glow — the one token that is raw colour AND a composed value. It
     moves whole rather than being split, so the glow follows the palette; the
     spread it reads (--h-focus-glow-spread) stays a component knob. */
  --h-focus-glow: 0 0 0 var(--h-focus-glow-spread) rgba(0, 174, 239, 0.15);
}
/* === /PALETTE === */

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

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

body {
  margin: 0;
  font-family: var(--h-font-sans);
  font-size: var(--h-fs-base);
  font-weight: var(--h-fw-regular);
  line-height: var(--h-lh-base);
  color: var(--h-ink);
  background: var(--h-white);
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }

a {
  color: var(--h-blue);
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color var(--h-duration) var(--h-ease);
}
a:hover { color: var(--h-cyan); }

/* ---------- Typography classes -------------------------------------------- */
.h-display {
  font-family: var(--h-font-display);
  font-weight: var(--h-fw-light);
  font-size: var(--h-fs-5xl);
  line-height: var(--h-lh-tight);
  letter-spacing: var(--h-tracking-tight);
  color: var(--h-blue);
  margin: 0 0 var(--h-s-5);
}

.h-h1 {
  font-weight: var(--h-fw-semibold);
  font-size: var(--h-fs-3xl);
  line-height: var(--h-lh-tight);
  color: var(--h-blue);
  margin: 0 0 var(--h-s-4);
}

.h-h2 {
  font-weight: var(--h-fw-semibold);
  font-size: var(--h-fs-2xl);
  line-height: var(--h-lh-snug);
  color: var(--h-blue);
  margin: 0 0 var(--h-s-3);
}

/* An h1 styled at the h2 size is a PAGE TITLE — house spec says page titles
   are bold (700), matching .page-title across Calls/ECR/PAR/Patch/Issues. */
h1.h-h2 {
  font-weight: var(--h-fw-bold);
}

.h-h3 {
  font-weight: var(--h-fw-semibold);
  font-size: var(--h-fs-xl);
  line-height: var(--h-lh-snug);
  color: var(--h-blue);
  margin: 0 0 var(--h-s-3);
}

.h-eyebrow {
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-semibold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  color: var(--h-cyan);
  margin: 0 0 var(--h-s-2);
}

.h-lead {
  font-size: var(--h-fs-lg);
  font-weight: var(--h-fw-light);
  line-height: var(--h-lh-snug);
  color: var(--h-grey-70);
}

.h-list {
  margin: 0 0 var(--h-s-3);
  padding-left: var(--h-s-4);
  color: var(--h-ink);
  line-height: var(--h-lh-snug);
}
.h-list li { margin-bottom: var(--h-s-2); }
.h-list--tight li { margin-bottom: 0; }

.h-muted { color: var(--h-grey-50); }
.h-meta  { font-size: var(--h-fs-sm); color: var(--h-grey-50); }
/* The same small line, in the status inks, for a note that has to be read
   rather than skimmed past — "why this row didn't work" under a table cell.
   Added 15/09/2026 for the Studio Videos row, whose Vimeo error had nowhere
   honest to go: a .h-badge is a status, a .h-notice is a block, and neither is
   a one-line footnote inside a row. */
.h-meta--error   { color: var(--h-error-ink); }
.h-meta--warning { color: var(--h-warning-ink); }

/* ---------- Signature brand patterns -------------------------------------- */

/* The Harcourts Script — secondary font for personality, single words only.
   Never use for body, headings, or buttons. Reserved for accent words like
   "Welcome", "Home", "Sold" used as personal/emotional callouts. */
.h-script {
  font-family: var(--h-font-script);
  font-weight: 400;
  font-style: italic;
}

/* The cyan underline — Harcourts' signature headline treatment.
   Apply to the LAST word of a headline (wrap that word in <span class="h-underline">).
   Height = ~50% of cap height, sits ~50% from top, cyan colour. */
.h-underline {
  position: relative;
  display: inline-block;
  white-space: nowrap;
  /* Own stacking context so the z-index:-1 bar sits behind the text but can
     never disappear behind an ancestor's background (apps that paint `html`
     AND `body` — PAR/Patch/Flow — were swallowing it otherwise). */
  isolation: isolate;
}
.h-underline::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0.08em;
  height: 0.42em;
  background: var(--h-cyan);
  z-index: -1;
}

/* The H mark — placeholder for the standalone H symbol.
   Drop the official SVG into assets/ and reference it where you'd use this class. */
.h-mark {
  display: inline-block;
  width: 1.5em;
  height: 1.5em;
  background: var(--h-blue);
  color: var(--h-white);
  font-weight: var(--h-fw-bold);
  text-align: center;
  line-height: 1.5em;
  border-radius: var(--h-radius-sm);
}

/* ---------- Layout primitives --------------------------------------------- */
.h-container {
  width: 100%;
  max-width: var(--h-container);
  margin: 0 auto;
  padding: 0 var(--h-s-5);
}

.h-container--narrow { max-width: var(--h-container-narrow); }

.h-section {
  padding: var(--h-s-10) 0;
}

.h-section--tight { padding: var(--h-s-6) 0; }

.h-grid {
  display: grid;
  gap: var(--h-s-5);
}

.h-grid--2 { grid-template-columns: repeat(2, 1fr); }
.h-grid--3 { grid-template-columns: repeat(3, 1fr); }
.h-grid--4 { grid-template-columns: repeat(4, 1fr); }

@media (max-width: 768px) {
  .h-grid--2, .h-grid--3, .h-grid--4 { grid-template-columns: 1fr; }
}

/* ---------- Brand stripe (signature texture) ------------------------------ */
/* RETIRED 04/09/2026 — MG: 'not Harcourts'. Kept only so legacy markup doesn't break. Never add to a page. */
.h-stripe {
  height: 6px;
  background: repeating-linear-gradient(
    90deg,
    var(--h-blue) 0,
    var(--h-blue) 24px,
    var(--h-white) 24px,
    var(--h-white) 48px
  );
}

.h-stripe--thin { height: 3px; }
.h-stripe--vertical {
  width: 6px;
  height: 100%;
  background: repeating-linear-gradient(
    0deg,
    var(--h-blue) 0,
    var(--h-blue) 24px,
    var(--h-white) 24px,
    var(--h-white) 48px
  );
}

/* ---------- Buttons -------------------------------------------------------- */
/* NAMING — the double-dash BEM form is canonical from 14/09/2026:
   .h-btn--primary / --secondary / --ghost / --accent / --success / --danger /
   --warning. The original single-dash form (.h-btn-primary) is an alias on the
   SAME rule, not a second implementation, and it stays forever — ~20 apps ship
   it. Write the double-dash form in new markup; never rewrite old markup for
   the sake of it, and never define a variant in only one of the two forms. */
.h-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--h-s-2);
  padding: var(--h-btn-pad-y) var(--h-btn-pad-x);
  font-family: var(--h-font-sans);
  font-size: var(--h-btn-fs);
  font-weight: var(--h-btn-fw);
  line-height: 1;
  letter-spacing: 0.02em;
  border: var(--h-btn-border-w) solid transparent;
  border-radius: var(--h-btn-radius);
  cursor: pointer;
  text-decoration: none;
  transition: all var(--h-duration) var(--h-ease);
  min-height: var(--h-btn-min-h);
}

.h-btn-primary,
.h-btn--primary {
  background: var(--h-blue);
  color: var(--h-white);
}
.h-btn-primary:hover,
.h-btn--primary:hover {
  background: var(--h-blue-90);
  color: var(--h-white);
  transform: translateY(-1px);
  box-shadow: var(--h-shadow);
}

.h-btn-secondary,
.h-btn--secondary {
  background: var(--h-white);
  color: var(--h-blue);
  border-color: var(--h-blue);
}
.h-btn-secondary:hover,
.h-btn--secondary:hover {
  background: var(--h-blue);
  color: var(--h-white);
}

.h-btn-ghost,
.h-btn--ghost {
  background: transparent;
  color: var(--h-blue);
}
.h-btn-ghost:hover,
.h-btn--ghost:hover {
  background: var(--h-blue-10);
  color: var(--h-blue);
}

.h-btn-accent,
.h-btn--accent {
  background: var(--h-cyan);
  color: var(--h-white);
}
.h-btn-accent:hover,
.h-btn--accent:hover {
  background: var(--h-cyan-90);
  color: var(--h-white);
}

/* Cyan CTA with navy text — the contrast-safe cyan button (cyan/navy is 6.6:1;
   cyan/white above is 2.5:1, so .h-btn--accent must stay small or on a dark
   surface). For the one primary action on a navy hero, where cyan is the
   brand's CTA colour and the text must still be readable. Added 15/09/2026
   for the Storage hero. */
.h-btn--accent-ink {
  background: var(--h-cyan);
  color: var(--h-blue);
}
.h-btn--accent-ink:hover {
  background: var(--h-cyan-90);
  color: var(--h-blue);
}

/* Confirm / destructive actions — use sparingly; most actions are primary. */
.h-btn-success,
.h-btn--success {
  background: var(--h-success);
  color: var(--h-white);
}
.h-btn-success:hover,
.h-btn--success:hover {
  background: var(--h-success-ink);
  color: var(--h-white);
}

.h-btn-danger,
.h-btn--danger {
  background: var(--h-error);
  color: var(--h-white);
}
.h-btn-danger:hover,
.h-btn--danger:hover {
  background: var(--h-error-ink);
  color: var(--h-white);
}

.h-btn--sm { padding: var(--h-s-2) var(--h-s-4); font-size: var(--h-fs-sm); min-height: 36px; }
.h-btn--lg { padding: var(--h-s-4) var(--h-s-6); font-size: var(--h-fs-lg); min-height: 52px; }
.h-btn--block { width: 100%; }

/* A full-width clickable ROW that is still a real button — for "here are three
   things needing you, tap one to jump to it" lists. Keeps the brand's focus ring,
   font, radius and transition; only the layout changes: left-aligned, wrapping,
   growing to its content instead of a single centred line. Use with a colour
   variant (usually .h-btn-secondary) like any other button. */
.h-btn--row {
  width: 100%;
  justify-content: flex-start;
  text-align: left;
  align-items: center;
  min-height: 0;
  font-weight: var(--h-fw-regular);
  line-height: var(--h-lh-snug);
  white-space: normal;
  gap: var(--h-s-3);
}

/* Disabled buttons read as disabled, whatever the variant. */
.h-btn:disabled, .h-btn[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }

/* ---------- Cards ---------------------------------------------------------- */
.h-card {
  background: var(--h-white);
  border: var(--h-border);
  border-radius: var(--h-radius-lg);
  overflow: hidden;
  transition: box-shadow var(--h-duration) var(--h-ease),
              transform var(--h-duration) var(--h-ease);
}

.h-card:hover { box-shadow: var(--h-shadow-lg); transform: translateY(-2px); }

/* Cancels the lift-on-hover for a .h-card that is informational, not a link
   or button (a static sidebar panel, a detail-page card). .h-form-card
   already re-derives this exact override by hand at its own definition
   below; add it here once and use it, rather than a third copy. */
.h-card--static:hover { transform: none; box-shadow: var(--h-shadow); }

/* Sign-in card variant — used on the login page of every internal app.
   Canonical look (modelled on the flow sign-in page): flat navy page, one
   compact white card — icon tile, app name, tagline, single primary button. */
.h-card--login {
  position: relative;
  width: 360px;
  max-width: 90vw;
  margin: var(--h-s-12) auto;
  padding: var(--h-s-8) var(--h-s-6);
  background: var(--h-white);
  border-radius: var(--h-radius-lg);
  box-shadow: var(--h-shadow-lg);
  text-align: center;
}
.h-card--login:hover { transform: none; box-shadow: var(--h-shadow-lg); }

/* Third-party sign-in button (Google, Microsoft…) — white, bordered, full
   width, provider logo + label. Deliberately not `.h-btn`: an OAuth button
   follows the provider's own button guidelines (white background, this
   border weight), not the brand's button system. */
.h-login-oauth-btn {
  display: flex; align-items: center; justify-content: center; gap: var(--h-s-3);
  width: 100%;
  padding: var(--h-s-3) var(--h-s-4);
  border-radius: var(--h-radius);
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-semibold);
  background: var(--h-white);
  color: var(--h-grey-70);
  border: 1.5px solid var(--h-grey-30);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--h-duration) var(--h-ease), box-shadow var(--h-duration) var(--h-ease);
}
.h-login-oauth-btn:hover { background: var(--h-paper); box-shadow: var(--h-shadow-sm); }

/* An "or" divider between a primary action and an alternative one. */
.h-login-divider {
  display: flex; align-items: center; gap: var(--h-s-3);
  margin: var(--h-s-4) 0;
  color: var(--h-grey-50);
  font-size: var(--h-fs-xs);
}
.h-login-divider::before, .h-login-divider::after { content: ''; flex: 1; height: 1px; background: var(--h-grey-10); }

/* ── Full-page login layout ────────────────────────────────────────────────
   Flat Harcourts navy with a single centred sign-in card. */
.h-login-page {
  margin: 0;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--h-s-6);
  font-family: var(--h-font-sans);
  color: var(--h-white);
  background: var(--h-blue);
}

/* Card sits centred; reset any auto-margin from .h-card--login default */
.h-login-page > .h-card--login {
  margin: 0;
}

/* App mark — small cyan tile with a navy line icon (the flow-logo pattern).
   Drop a 24×24 stroke SVG inside; it inherits currentColor. */
.h-login-card__mark {
  width: 40px;
  height: 40px;
  border-radius: var(--h-radius-lg);
  background: var(--h-cyan);
  color: var(--h-blue);
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto var(--h-s-4);
}
.h-login-card__mark svg { width: 22px; height: 22px; }

/* App name beneath the mark */
.h-login-card__title {
  font-family: var(--h-font-sans);
  font-size: var(--h-fs-2xl);
  font-weight: var(--h-fw-semibold);
  letter-spacing: var(--h-tracking-tight);
  color: var(--h-blue);
  margin: 0 0 var(--h-s-1);
}

/* Subtitle beneath the app title — full meaning of the abbreviation */
.h-login-card__subtitle {
  font-family: var(--h-font-sans);
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-regular);
  color: var(--h-grey-50);
  margin: 0 0 var(--h-s-5);
  letter-spacing: 0.01em;
}

/* Inline error notice above the sign-in button */
.h-login-card__error {
  background: var(--h-blue-10);
  color: var(--h-blue);
  border-radius: var(--h-radius-lg);
  padding: var(--h-s-3);
  font-size: var(--h-fs-sm);
  margin: 0 0 var(--h-s-4);
}

/* Cyan accent — thin bar that visually links the title to the brand mark */
.h-login-card__accent {
  display: block;
  width: 40px;
  height: 3px;
  background: var(--h-cyan);
  border: 0;
  border-radius: 2px;
  margin: 0 auto var(--h-s-4);
}

.h-card__media {
  aspect-ratio: 4 / 3;
  background: var(--h-grey-10);
  overflow: hidden;
}
.h-card__media img { width: 100%; height: 100%; object-fit: cover; }

/* ---------- Video embed (16:9) --------------------------------------------- */
/* The responsive frame for an embedded player. Added 15/09/2026 for
   video.hdas.com.au and kept general, because a webbook and a listing page want
   the same frame: put the <iframe> straight inside and it fills it. Navy
   underneath, so the moment before the player paints is brand rather than a
   white flash. aspect-ratio rather than the padding-top ratio hack — every
   browser the estate serves has it, and a seller's phone is the newest device
   in the chain. */
.h-video {
  position: relative;
  width: 100%;
  max-width: 100%;
  aspect-ratio: 16 / 9;
  background: var(--h-blue);
  border-radius: var(--h-radius-lg);
  overflow: hidden;
}
.h-video iframe,
.h-video video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

.h-card__body  { padding: var(--h-s-5); }
.h-card__title { font-weight: var(--h-fw-semibold); color: var(--h-blue); margin: 0 0 var(--h-s-2); font-size: var(--h-fs-lg); }
.h-card__meta  { font-size: var(--h-fs-sm); color: var(--h-grey-50); margin: 0; }

/* ---------- Tile (property listing standard) ------------------------------ */
.h-tile {
  display: flex;
  flex-direction: column;
  background: var(--h-white);
  border-radius: var(--h-radius-lg);
  overflow: hidden;
  border: var(--h-border);
  transition: box-shadow var(--h-duration) var(--h-ease);
}
.h-tile:hover { box-shadow: var(--h-shadow-lg); }

.h-tile__image {
  position: relative;
  aspect-ratio: 16 / 10;
  background: var(--h-grey-10);
  overflow: hidden;
}
.h-tile__image img { width: 100%; height: 100%; object-fit: cover; }

.h-tile__badge {
  position: absolute;
  top: var(--h-s-3);
  left: var(--h-s-3);
  background: var(--h-blue);
  color: var(--h-white);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-semibold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  padding: var(--h-s-1) var(--h-s-3);
  border-radius: var(--h-radius-sm);
}

.h-tile__body { padding: var(--h-s-5); flex: 1; display: flex; flex-direction: column; }

.h-tile__price {
  font-size: var(--h-fs-xl);
  font-weight: var(--h-fw-bold);
  color: var(--h-blue);
  margin: 0 0 var(--h-s-2);
}

.h-tile__address {
  font-size: var(--h-fs-base);
  color: var(--h-ink);
  margin: 0 0 var(--h-s-4);
  line-height: var(--h-lh-snug);
}

.h-tile__features {
  display: flex;
  gap: var(--h-s-4);
  padding-top: var(--h-s-3);
  border-top: var(--h-border);
  margin-top: auto;
  font-size: var(--h-fs-sm);
  color: var(--h-grey-70);
}

.h-tile__features span {
  display: inline-flex;
  align-items: center;
  gap: var(--h-s-1);
  font-weight: var(--h-fw-semibold);
}

/* ---------- Header / nav --------------------------------------------------- */
.h-header {
  background: var(--h-white);
  border-bottom: var(--h-border);
}

/* Dark variant for internal apps where the header sits on a navy band
   above a light body (hub, calls, ecr, par all use this pattern). */
.h-header--dark {
  background: var(--h-blue);
  border-bottom: 1px solid rgba(255,255,255,0.08);
  color: var(--h-white);
}
.h-header--dark .h-header__logo { color: var(--h-white); }
.h-header--dark .h-nav a        { color: rgba(255,255,255,0.85); }
.h-header--dark .h-nav a:hover  { color: var(--h-cyan); }
.h-header--dark .h-nav a.active { color: var(--h-white); border-bottom: 2px solid var(--h-cyan); }

.h-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--h-s-4) var(--h-s-6);
}

.h-header__logo {
  font-family: var(--h-font-display);
  font-weight: var(--h-fw-bold);
  font-size: var(--h-fs-xl);
  color: var(--h-blue);
  text-decoration: none;
  letter-spacing: var(--h-tracking-tight);
  display: inline-flex;
  align-items: center;
  gap: var(--h-s-2);
}
.h-header__logo-accent { color: var(--h-cyan); }
.h-header__logo-sub {
  font-style: italic;
  font-weight: var(--h-fw-regular);
  font-size: var(--h-fs-sm);
  opacity: 0.7;
  margin-left: var(--h-s-2);
}

/* Brand logo image — pair with the canonical PNGs in ~/Atlas/brand/assets/
   (logo-horizontal-{blue,white}.png, logo-stacked-{blue,white}.png).
   Use the BLUE variant on light backgrounds, WHITE on dark. */
.h-logo {
  display: block;
  height: auto;
  max-width: 100%;
  user-select: none;
}
.h-logo--sm   { height: 28px; width: auto; }
.h-logo--md   { height: 40px; width: auto; }
.h-logo--lg   { height: 64px; width: auto; }
.h-logo--login {
  /* For sign-in cards — STACKED logo (Harcourts wordmark + DAS locations).
     Native 2636×1105 PNG; 120px display height = 286px wide, fits in the
     wider 480px login card with breathing room. */
  display: block;
  height: 120px;
  width: auto;
  max-width: 320px;
  margin: 0 auto var(--h-s-5);
  object-fit: contain;
}

/* User chip — avatar + first name + sign-out, sits on the right of .h-header */
.h-user-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--h-s-3);
  font-size: var(--h-fs-sm);
}
.h-user-chip__avatar {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--h-cyan);
  color: var(--h-white);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: var(--h-fw-bold);
  font-size: var(--h-fs-xs);
}
.h-user-chip__name { font-weight: var(--h-fw-semibold); }
.h-user-chip__logout {
  color: var(--h-cyan);
  text-decoration: none;
  font-weight: var(--h-fw-semibold);
}
.h-user-chip__logout:hover { text-decoration: underline; }

.h-nav { display: flex; gap: var(--h-s-5); }
.h-nav a {
  color: var(--h-ink);
  text-decoration: none;
  font-weight: var(--h-fw-semibold);
  font-size: var(--h-fs-sm);
  letter-spacing: 0.02em;
}
.h-nav a:hover { color: var(--h-cyan); }

/* ---------- Internal-tool top bar (sticky 60px) ---------------------------
   Canonical chrome shared by every authenticated internal app (Hub, Calls,
   Issues, ECR, PAR). Place at the top of <body>. Pair with .h-app-nav__brand
   on the left, optional middle nav, and .h-user-chip on the right. */
.h-app-nav {
  display: flex;
  align-items: center;
  height: 60px;
  padding: 0 var(--h-s-6);
  background: var(--h-blue);
  color: var(--h-white);
  gap: var(--h-s-4);
  position: sticky;
  top: 0;
  z-index: var(--h-z-nav);
  flex-shrink: 0;
}
.h-app-nav__brand {
  display: inline-flex;
  align-items: baseline;
  gap: var(--h-s-3);
  text-decoration: none;
  line-height: 1;
  flex-shrink: 0;
}
.h-app-nav__brand-img {
  height: 28px;
  width: auto;
  display: block;
  position: relative;
  top: 7px;
}
.h-app-nav__brand-suffix {
  color: var(--h-cyan);
  font-family: var(--h-font-sans);
  font-weight: var(--h-fw-semibold);
  font-size: var(--h-fs-2xl);
  letter-spacing: -0.01em;
  line-height: 1;
}
.h-app-nav__spacer { flex: 1; }
.h-app-nav__right  { display: flex; align-items: center; gap: var(--h-s-3); }
.h-app-nav__links  { display: flex; align-items: center; gap: var(--h-s-2); }
.h-app-nav__links a {
  color: rgba(255,255,255,0.7);
  text-decoration: none;
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-semibold);
  padding: var(--h-s-2) var(--h-s-3);
  border-radius: var(--h-radius);
  transition: background var(--h-duration) var(--h-ease),
              color var(--h-duration) var(--h-ease);
}
.h-app-nav__links a:hover  { color: var(--h-white); background: rgba(255,255,255,0.08); }
.h-app-nav__links a.active { color: var(--h-white); background: rgba(0,174,239,0.2); }

/* Back-to-Studio in the top bar — the .h-app-nav counterpart of
   .h-sidebar__back, for apps that haven't moved to the Studio shell. Sits at
   the head of .h-app-nav__right, left of the user chip, and stays quieter than
   a nav link: it leaves the app rather than moving around inside it. */
.h-app-nav__back {
  display: inline-flex;
  align-items: center;
  gap: var(--h-s-2);
  color: rgba(255,255,255,0.6);
  font-size: var(--h-fs-sm);
  padding: var(--h-s-2) var(--h-s-3);
  border-radius: var(--h-radius);
  text-decoration: none;
  transition: background var(--h-duration) var(--h-ease),
              color var(--h-duration) var(--h-ease);
}
.h-app-nav__back:hover { background: rgba(255,255,255,0.1); color: var(--h-white); }
.h-app-nav__back svg { width: 15px; height: 15px; flex: none; }
/* Phones keep the arrow, drop the word — same trade the user-name chip makes. */
@media (max-width: 640px) { .h-app-nav__back span { display: none; } }

/* User chip used inside .h-app-nav__right — avatar + first name + sign-out */
.h-app-nav__user {
  display: flex;
  align-items: center;
  gap: var(--h-s-2);
  color: var(--h-white);
}
.h-app-nav__avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--h-cyan);
  color: var(--h-white);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-bold);
  flex-shrink: 0;
  overflow: hidden;
}
.h-app-nav__avatar img { width: 100%; height: 100%; object-fit: cover; }
.h-app-nav__user-name { font-size: var(--h-fs-sm); font-weight: var(--h-fw-semibold); }
.h-app-nav__logout {
  color: rgba(255,255,255,0.6);
  font-size: var(--h-fs-sm);
  padding: var(--h-s-2) var(--h-s-3);
  border-radius: var(--h-radius);
  text-decoration: none;
  transition: background var(--h-duration) var(--h-ease),
              color var(--h-duration) var(--h-ease);
}
.h-app-nav__logout:hover { background: rgba(255,255,255,0.1); color: var(--h-white); }

@media (max-width: 640px) {
  .h-app-nav { padding: 0 var(--h-s-4); gap: var(--h-s-2); }
  .h-app-nav__user-name { display: none; }
  /* Drop the wide horizontal logo on phones — the cyan app name carries the
     brand. Keeps Sign out on-screen even with extra nav controls. */
  .h-app-nav__brand-img { display: none; }
  .h-app-nav__brand-suffix { font-size: var(--h-fs-xl); }
  .h-app-nav__right { gap: var(--h-s-2); }
}

/* ---------- Footer --------------------------------------------------------- */
.h-footer {
  background: var(--h-blue);
  color: var(--h-white);
  padding: var(--h-s-8) 0 var(--h-s-5);
  margin-top: var(--h-s-12);
}
.h-footer a { color: var(--h-white); }
.h-footer__meta {
  border-top: 1px solid rgba(255,255,255,0.15);
  margin-top: var(--h-s-6);
  padding-top: var(--h-s-4);
  font-size: var(--h-fs-sm);
  opacity: 0.8;
}

/* ---------- Forms ---------------------------------------------------------- */
.h-label {
  display: block;
  font-size: var(--h-label-fs);
  font-weight: var(--h-label-fw);
  color: var(--h-blue);
  margin-bottom: var(--h-s-1);
}

.h-input, .h-textarea, .h-select {
  width: 100%;
  min-height: var(--h-field-min-h);
  padding: var(--h-field-pad-y) var(--h-field-pad-x);
  font-family: var(--h-font-sans);
  font-size: var(--h-field-fs);
  color: var(--h-ink);
  background: var(--h-white);
  border: var(--h-field-border-w) solid var(--h-field-border-c);
  border-radius: var(--h-field-radius);
  transition: border-color var(--h-duration) var(--h-ease);
}

.h-input:focus, .h-textarea:focus, .h-select:focus {
  outline: none;
  border-color: var(--h-cyan);
  box-shadow: var(--h-focus-glow);
}

.h-textarea { min-height: 120px; resize: vertical; }

/* Styled native <select> with consistent chevron — drop into any app for a
   uniform dropdown look (no browser-default arrow). The chevron uses the
   navy hex inline so it renders without depending on CSS-variable resolution. */
.h-select {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  padding-right: calc(var(--h-field-pad-x) + 18px);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path fill='%23001f49' d='M0 0l5 6 5-6z'/></svg>");
  background-repeat: no-repeat;
  background-position: right var(--h-s-3) center;
}
.h-select--pill {
  border: 1px solid var(--h-grey-10);
  border-radius: var(--h-radius);
  padding: var(--h-s-2) calc(var(--h-s-4) + 18px) var(--h-s-2) var(--h-s-4);
  font-weight: var(--h-fw-semibold);
  color: var(--h-blue);
  font-size: var(--h-fs-sm);
  background-color: var(--h-white);
}

/* Colour-by-value status select — a workflow status the user can change
   inline, tinted to match its current value. Compose with the base
   `.h-select` (`<select class="h-select h-select--status is-warning">`) so it
   inherits the chevron mechanics rather than redrawing them; the `is-*`
   colour states reuse .h-badge's soft-tint pairs so a status select and a
   status badge for the same value always agree. */
.h-select--status {
  border: none;
  border-radius: var(--h-radius);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-semibold);
  text-transform: uppercase;
  letter-spacing: var(--h-tracking-wide);
  padding: var(--h-s-1) calc(var(--h-s-3) + 14px) var(--h-s-1) var(--h-s-3);
  background-color: var(--h-blue-10);
  color: var(--h-blue);
  transition: opacity var(--h-duration) var(--h-ease);
}
.h-select--status:hover { opacity: .85; }
.h-select--status.is-info    { background-color: var(--h-info-soft);    color: var(--h-info-ink); }
.h-select--status.is-warning { background-color: var(--h-warning-soft); color: var(--h-warning-ink); }
.h-select--status.is-success { background-color: var(--h-success-soft); color: var(--h-success-ink); }
.h-select--status.is-error   { background-color: var(--h-error-soft);   color: var(--h-error-ink); }
.h-select--status.is-quiet   { background-color: var(--h-grey-10);      color: var(--h-grey-70); }

/* ---------- Live indicator -------------------------------------------------
   Marks a surface that keeps itself up to date, so nobody sits in front of a
   stale screen wondering whether to hit refresh. Pair the dot with a short
   plain-English note saying how often it checks — the dot alone doesn't tell
   anyone what it means.
     <span class="h-live-flag"><span class="h-live-flag__dot"></span>Live — …</span>
   Reveal it from JS once polling is actually running, and hide it if polling
   gives up: a flag that lies is worse than no flag.                           */
.h-live-flag {
  display: inline-flex;
  align-items: center;
  gap: var(--h-s-2);
  font-size: var(--h-fs-sm);
  color: var(--h-grey-50);
}
.h-live-flag__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--h-success);
  flex: none;
  animation: hLivePulse 2.4s var(--h-ease) infinite;
}
@keyframes hLivePulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }
@media (prefers-reduced-motion: reduce) {
  .h-live-flag__dot { animation: none; }
}

/* ---------- Badges / pills ------------------------------------------------- */
.h-badge {
  display: inline-block;
  padding: var(--h-s-1) var(--h-s-3);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-semibold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  border-radius: var(--h-radius-sm);
  background: var(--h-blue-10);
  color: var(--h-blue);
}
.h-badge--accent  { background: var(--h-cyan); color: var(--h-white); }
.h-badge--solid   { background: var(--h-blue); color: var(--h-white); }
.h-badge--info    { background: var(--h-info-ink); color: var(--h-white); }
.h-badge--success { background: var(--h-success); color: var(--h-white); }
.h-badge--warning { background: var(--h-warning); color: var(--h-charcoal); }
.h-badge--error   { background: var(--h-error); color: var(--h-white); }
/* Soft variants — tinted background + status ink; the default choice for
   in-table status chips where solid blocks would shout. */
.h-badge--success-soft { background: var(--h-success-soft); color: var(--h-success-ink); }
.h-badge--warning-soft { background: var(--h-warning-soft); color: var(--h-warning-ink); }
.h-badge--error-soft   { background: var(--h-error-soft);   color: var(--h-error-ink); }
.h-badge--info-soft    { background: var(--h-info-soft);    color: var(--h-info-ink); }
/* .h-badge--quiet already exists — see "Quiet + informational variants"
   further down this file (added 06/09/2026, for Calls' own queue). */

/* Larger touch/read target — a standalone status shown once and prominently
   (a detail-page header) rather than packed into a table row. */
.h-badge--lg { padding: var(--h-s-2) var(--h-s-4); font-size: var(--h-fs-sm); }

/* ---------- Notices -------------------------------------------------------- */
/* A block-level message attached to the thing it's about — distinct from
   .h-badge, which labels a status inline. Left rule carries the status colour
   so the tint can stay light enough to read a paragraph against. */
.h-notice {
  padding: var(--h-s-4) var(--h-s-5);
  border-radius: var(--h-radius-sm);
  border-left: 3px solid var(--h-blue);
  background: var(--h-blue-10);
  color: var(--h-blue);
  font-size: var(--h-fs-sm);
}
.h-notice__title {
  font-weight: var(--h-fw-semibold);
  margin: 0 0 var(--h-s-2) 0;
}
.h-notice p:last-child { margin-bottom: 0; }
.h-notice--warning {
  border-left-color: var(--h-warning);
  background: var(--h-warning-soft);
  color: var(--h-warning-ink);
}
.h-notice--error {
  border-left-color: var(--h-error);
  background: var(--h-error-soft);
  color: var(--h-error-ink);
}
.h-notice--success {
  border-left-color: var(--h-success);
  background: var(--h-success-soft);
  color: var(--h-success-ink);
}

/* Filter / status / tab pills — clickable, with hover + active states.
   Different from .h-badge (one-shot uppercase label). Use .h-pill for
   the bars of "All / On Market / Coming Soon / Sold" style controls
   that appear across hub, brochure, calls, pulse, ecr. */
.h-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--h-s-2);
  padding: var(--h-s-2) var(--h-s-4);
  font-family: var(--h-font-sans);
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-semibold);
  color: var(--h-blue);
  background: var(--h-white);
  border: 1px solid var(--h-grey-10);
  border-radius: var(--h-radius);
  cursor: pointer;
  transition: background var(--h-duration) var(--h-ease),
              border-color var(--h-duration) var(--h-ease);
  text-decoration: none;
}
.h-pill:hover {
  background: var(--h-blue-10);
  border-color: var(--h-blue-20);
}
.h-pill.is-active,
.h-pill[aria-pressed="true"],
.h-pill--active {
  background: var(--h-blue);
  color: var(--h-white);
  border-color: var(--h-blue);
}
.h-pill__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 18px;
  padding: 0 var(--h-s-2);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-bold);
  background: var(--h-blue-10);
  color: var(--h-blue);
  border-radius: var(--h-radius);
}
.h-pill.is-active .h-pill__count,
.h-pill--active .h-pill__count {
  background: rgba(255,255,255,0.2);
  color: var(--h-white);
}

/* Modal close button — the ✕ in the corner of a dialog. Tiny, square,
   icon-only. Use INSIDE a .h-card or .h-modal as the dismiss control. */
.h-modal-close {
  position: absolute;
  top: var(--h-s-3);
  right: var(--h-s-3);
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--h-grey-50);
  cursor: pointer;
  font-size: var(--h-fs-lg);
  line-height: 1;
  transition: background var(--h-duration) var(--h-ease),
              color var(--h-duration) var(--h-ease);
}
.h-modal-close:hover {
  background: var(--h-grey-10);
  color: var(--h-charcoal);
}

/* ---------- Modal ----------------------------------------------------------- */
/* Centred dialog over a navy scrim. Markup:
   <div class="h-modal-backdrop"></div>
   <div class="h-modal" role="dialog" aria-modal="true">
     <button class="h-modal-close">✕</button>
     <h3 class="h-modal__title">…</h3> … <div class="h-modal__footer">…</div>
   </div> */
.h-modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 18, 51, 0.55);
  z-index: var(--h-z-backdrop);
}
.h-modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(560px, calc(100vw - var(--h-s-6)));
  max-height: calc(100vh - var(--h-s-10));
  overflow: auto;
  padding: var(--h-s-6);
  background: var(--h-white);
  border-radius: var(--h-radius-lg);
  box-shadow: var(--h-shadow-lg);
  z-index: var(--h-z-modal);
}
.h-modal__title {
  margin: 0 0 var(--h-s-4);
  font-size: var(--h-fs-xl);
  font-weight: var(--h-fw-bold);
  color: var(--h-blue);
  letter-spacing: var(--h-tracking-tight);
}
.h-modal__lede {
  margin: 0 0 var(--h-s-4);
  color: var(--h-grey-70);
  font-size: var(--h-fs-sm);
  line-height: var(--h-lh-base);
}
.h-modal__lede strong { color: var(--h-ink); font-weight: var(--h-fw-bold); }
.h-modal__footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--h-s-2);
  margin-top: var(--h-s-6);
}

/* ---------- Toast ----------------------------------------------------------- */
/* Transient confirmation, bottom-centre. Add/remove from JS; the reduced-motion
   block already neutralises any animation you attach. */
.h-toast {
  position: fixed;
  bottom: var(--h-s-5);
  left: 50%;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  gap: var(--h-s-3);
  padding: var(--h-s-3) var(--h-s-5);
  background: var(--h-blue);
  color: var(--h-white);
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-semibold);
  border-radius: var(--h-radius);
  box-shadow: var(--h-shadow-lg);
  z-index: var(--h-z-toast);
}
.h-toast--success { background: var(--h-success); }
.h-toast--error   { background: var(--h-error); }
/* An undoable action needs its way back inside the toast itself. A ghost or
   secondary button here would be navy-on-navy, so the action states its own
   colours against the toast's fill. (07/09/2026) */
.h-toast__action.h-btn {
  background: transparent;
  color: var(--h-white);
  border-color: var(--h-white);
}
.h-toast__action.h-btn:hover,
.h-toast__action.h-btn:focus-visible {
  background: var(--h-white);
  color: var(--h-blue);
}

/* ---------- Page header ----------------------------------------------------- */
/* Standard page-top row: title (+ optional subtitle) left, actions right. */
.h-page-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--h-s-4);
  margin: var(--h-s-6) 0 var(--h-s-5);
}
/* The right-hand end of a page header: a count, a filter note, an action —
   whatever pairs with the title. .h-page-header is space-between, so without
   a wrapper a third child lands in the middle of the bar. No top margin:
   .h-actions has one, and a header is not a form footer. */
.h-page-header__aside {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--h-s-3);
}

.h-page-header__title {
  margin: 0;
  font-size: var(--h-fs-2xl);
  font-weight: var(--h-fw-bold);
  color: var(--h-blue);
  letter-spacing: var(--h-tracking-tight);
}
.h-page-header__sub {
  margin: var(--h-s-1) 0 0;
  font-size: var(--h-fs-sm);
  color: var(--h-grey-50);
}
/* The title block gives way first, so the actions stay on the title's line
   instead of wrapping under it; and if they DO wrap on a narrow screen,
   margin-left:auto keeps them on the right rather than dropping them left. */
.h-page-header > :first-child { flex: 1 1 340px; min-width: 0; }
.h-page-header__actions {
  display: flex;
  align-items: center;
  gap: var(--h-s-2);
  margin-left: auto;
}
/* Workflow steps: Back · Workflow · Next, in three fixed slots so the buttons
   land in exactly the same place on every step of the run, whatever the labels
   say and whether or not a step has a Back or a Next. An absent one is an
   empty slot, not a gap that shifts the others. */
.h-page-header__actions--steps { display: grid; grid-template-columns: repeat(3, 190px); }
.h-page-header__actions--steps .h-btn { width: 100%; }
@media (max-width: 768px) {
  .h-page-header__actions--steps { display: flex; flex-wrap: wrap; }
  .h-page-header__actions--steps .h-btn { width: auto; }
  .h-page-header__actions--steps .h-page-header__slot { display: none; }
}

/* ---------- Segmented toggle ------------------------------------------------ */
/* 2–4 mutually exclusive options in one control (Add/Subtract, Day/Week/Month).
   Works on <button> or <a>; mark the active option with .is-active or
   aria-pressed="true". */
.h-segmented {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  background: var(--h-white);
  border: 1px solid var(--h-grey-10);
  border-radius: var(--h-radius);
}
/* An author `display` beats the UA's [hidden] rule, so a switch hidden by the
   server or by JS stayed on screen — same failure as the .h-label one below
   (16/09/2026: Suburb Figures showed the house sizes AND the unit sizes at
   once, which is exactly the mix-up the two switches exist to prevent). */
.h-segmented[hidden] { display: none; }
.h-segmented__option {
  padding: var(--h-s-2) var(--h-s-4);
  font-family: var(--h-font-sans);
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-semibold);
  color: var(--h-blue);
  background: transparent;
  border: 0;
  border-radius: var(--h-radius);
  cursor: pointer;
  text-decoration: none;
  transition: background var(--h-duration) var(--h-ease);
}
.h-segmented__option:hover { background: var(--h-blue-10); }
.h-segmented__option.is-active,
.h-segmented__option[aria-pressed="true"] {
  background: var(--h-blue);
  color: var(--h-white);
}

/* ---------- Empty state ----------------------------------------------------- */
/* Friendly zero-results block — use instead of a bare "No data" row. */
.h-empty {
  padding: var(--h-s-10) var(--h-s-6);
  text-align: center;
  color: var(--h-grey-50);
}
.h-empty__icon  { font-size: var(--h-fs-3xl); margin-bottom: var(--h-s-3); }
.h-empty__title {
  margin: 0 0 var(--h-s-1);
  font-size: var(--h-fs-lg);
  font-weight: var(--h-fw-semibold);
  color: var(--h-grey-70);
}
.h-empty__hint  { margin: 0; font-size: var(--h-fs-sm); }

/* ---------- Skeleton (loading shimmer) -------------------------------------- */
/* Functional gradient (loading state), not decorative — exempt from the
   no-gradients rule. Size it with width/height utilities or inline layout. */
.h-skeleton {
  display: block;
  min-height: 1em;
  border-radius: var(--h-radius);
  background: linear-gradient(90deg, var(--h-grey-10) 25%, var(--h-paper) 50%, var(--h-grey-10) 75%);
  background-size: 200% 100%;
  animation: h-skeleton-shimmer 1.4s ease-in-out infinite;
}
@keyframes h-skeleton-shimmer {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}

/* ---------- Tables --------------------------------------------------------- */
.h-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--h-fs-sm);
}
.h-table th {
  text-align: left;
  background: var(--h-blue);
  color: var(--h-white);
  font-weight: var(--h-fw-semibold);
  padding: var(--h-s-3) var(--h-s-4);
}
.h-table td {
  padding: var(--h-s-3) var(--h-s-4);
  border-bottom: var(--h-border);
}
.h-table tr:hover td { background: var(--h-blue-10); }

/* --dense: an operational queue — many rows, scanned not read. The header
   drops to the small uppercase tracked label the rest of the system uses
   for captions (.h-eyebrow, .h-stat__label, .h-badge), so the column names
   recede and the rows carry the weight; cells tighten a step. Promoted from
   the Call Log queue on 15/09/2026, where it had been hand-built beside the
   plain .h-table for months. */
.h-table--dense th {
  padding: var(--h-s-2) var(--h-s-3);
  font-size: var(--h-fs-xs);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  white-space: nowrap;
  user-select: none;
}
.h-table--dense td { padding: var(--h-s-3); vertical-align: middle; }
.h-table--dense tbody tr:last-child td { border-bottom: 0; }

/* ---------- Utility -------------------------------------------------------- */
.h-divider { border: 0; border-top: var(--h-border); margin: var(--h-s-6) 0; }
.h-mt-0 { margin-top: 0; }
.h-text-center { text-align: center; }
.h-mono { font-family: var(--h-font-mono); font-variant-numeric: tabular-nums; }
.h-on-blue { background: var(--h-blue); color: var(--h-white); }
.h-on-blue .h-h1, .h-on-blue .h-h2, .h-on-blue .h-h3 { color: var(--h-white); }

/* ---------- Focus / motion / print ----------------------------------------- */
/* ── Keyboard focus — cyan ring (brand reserves cyan for focus states) ── */
:focus-visible {
  outline: var(--h-focus-ring);
  outline-offset: 2px;
}
/* inputs already show their own cyan border+glow on focus — no double ring */
.h-input:focus-visible, .h-textarea:focus-visible, .h-select:focus-visible { outline: none; }

/* ── Reduced motion ── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

@media print {
  body { background: var(--h-white); color: var(--h-black); }
  .h-btn, .h-nav, .h-app-nav { display: none; }
  .h-card, .h-tile { box-shadow: none; border: 1px solid var(--h-grey-30); }
  /* tables: ink-friendly — borders instead of navy fills */
  .h-table th {
    background: var(--h-white) !important;
    color: var(--h-black) !important;
    border-bottom: 2px solid var(--h-black);
  }
  .h-table td { border-bottom: 1px solid var(--h-grey-30); }
  a { color: var(--h-black); text-decoration: none; }
}

/* ---------- Studio shell (sidebar app layout) -------------------------------
   The Studio shell at studio.hdas.com.au: a full-height Harcourts Blue
   sidebar on the left, white content on the right. Sidebar carries the
   wordmark + cyan "Studio" extension, a search box, grouped nav, and the
   signed-in user card at the bottom. Added 04/09/2026. */
.h-shell {
  display: flex;
  min-height: 100vh;
  background: var(--h-paper);
}
.h-sidebar {
  width: 240px;
  flex: none;
  display: flex;
  flex-direction: column;
  background: var(--h-blue);
  color: var(--h-white);
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}
.h-sidebar__brand {
  display: flex;
  align-items: baseline;
  gap: var(--h-s-2);
  padding: var(--h-s-5) var(--h-s-5) var(--h-s-5);
  text-decoration: none;
  color: var(--h-white);
  line-height: 1;
}
.h-sidebar__brand-img { height: 22px; width: auto; display: block; position: relative; top: 4px; }
.h-sidebar__brand-ext {
  font-family: var(--h-font-sans);
  font-weight: var(--h-fw-light);
  font-size: var(--h-fs-lg);
  color: var(--h-cyan);
  letter-spacing: 0;
  border-left: 1px solid rgba(255,255,255,0.25);
  padding-left: var(--h-s-2);
}
.h-sidebar__search {
  margin: 0 var(--h-s-4) var(--h-s-4);
  display: flex;
  align-items: center;
  gap: var(--h-s-2);
  padding: var(--h-s-2) var(--h-s-3);
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: var(--h-radius);
  color: rgba(255,255,255,0.55);
  font-size: var(--h-fs-sm);
}
.h-sidebar__search input {
  background: none;
  border: 0;
  color: var(--h-white);
  font-family: var(--h-font-sans);
  font-size: var(--h-fs-sm);
  width: 100%;
  outline: none;
}
.h-sidebar__search input::placeholder { color: rgba(255,255,255,0.45); }
.h-sidebar__nav { flex: 1; padding: 0 var(--h-s-3); }
.h-sidebar__group {
  margin: var(--h-s-4) var(--h-s-2) var(--h-s-2);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-semibold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  color: rgba(255,255,255,0.45);
}
.h-sidebar__link {
  display: flex;
  align-items: center;
  gap: var(--h-s-3);
  padding: var(--h-s-2) var(--h-s-3);
  border-radius: var(--h-radius);
  color: rgba(255,255,255,0.8);
  text-decoration: none;
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-regular);
  border-left: 2px solid transparent;
  transition: background var(--h-duration) var(--h-ease), color var(--h-duration) var(--h-ease);
}
.h-sidebar__link:hover { background: rgba(255,255,255,0.08); color: var(--h-white); }
.h-sidebar__link.is-active {
  background: rgba(255,255,255,0.1);
  color: var(--h-white);
  font-weight: var(--h-fw-semibold);
  border-left-color: var(--h-cyan);
}
.h-sidebar__link svg { width: 16px; height: 16px; flex: none; opacity: 0.85; }
.h-sidebar__link--muted { color: rgba(255,255,255,0.35); cursor: default; }
.h-sidebar__link--muted:hover { background: none; color: rgba(255,255,255,0.35); }
.h-sidebar__badge {
  margin-left: auto;
  min-width: 18px;
  height: 18px;
  padding: 0 var(--h-s-2);
  border-radius: var(--h-radius);
  background: var(--h-cyan);
  color: var(--h-blue);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-bold);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
/* Back-to-Studio link — for standalone apps (Calls, Issues, …) that wear the
   Studio shell but live on their own domain. Sits at the foot of the sidebar,
   under the nav and above the signed-in user, deliberately quieter than a nav
   link: it leaves the app rather than moving around inside it. */
.h-sidebar__back {
  display: flex;
  align-items: center;
  gap: var(--h-s-3);
  margin: var(--h-s-3) var(--h-s-3) 0;
  padding: var(--h-s-2) var(--h-s-3);
  border-radius: var(--h-radius);
  color: rgba(255,255,255,0.55);
  text-decoration: none;
  font-size: var(--h-fs-sm);
  transition: background var(--h-duration) var(--h-ease), color var(--h-duration) var(--h-ease);
}
.h-sidebar__back:hover { background: rgba(255,255,255,0.08); color: var(--h-white); }
.h-sidebar__back svg { width: 16px; height: 16px; flex: none; opacity: 0.85; }

.h-sidebar__user {
  border-top: 1px solid rgba(255,255,255,0.12);
  padding: var(--h-s-4) var(--h-s-5);
  display: flex;
  align-items: center;
  gap: var(--h-s-3);
}
.h-sidebar__avatar {
  width: 34px; height: 34px;
  border-radius: 50%;
  background: var(--h-cyan);
  color: var(--h-blue);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-bold);
  display: flex; align-items: center; justify-content: center;
  overflow: hidden; flex: none;
}
.h-sidebar__avatar img { width: 100%; height: 100%; object-fit: cover; }
.h-sidebar__user-name { font-size: var(--h-fs-sm); font-weight: var(--h-fw-semibold); color: var(--h-white); line-height: 1.2; }
.h-sidebar__user-role { font-size: var(--h-fs-xs); color: rgba(255,255,255,0.55); line-height: 1.2; }
.h-sidebar__user-meta { min-width: 0; }
.h-sidebar__signout {
  display: block;
  padding: 0 var(--h-s-5) var(--h-s-4);
  font-size: var(--h-fs-xs);
  color: rgba(255,255,255,0.55);
  text-decoration: none;
}
.h-sidebar__signout:hover { color: var(--h-white); }

.h-shell__main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.h-shell__content { padding: var(--h-s-6) var(--h-s-8) var(--h-s-10); max-width: 1320px; width: 100%; }
.h-shell__topbar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--h-s-3);
  padding: var(--h-s-3) var(--h-s-8);
  background: var(--h-white);
  border-bottom: 1px solid var(--h-grey-10);
  min-height: 52px;
}

/* View-as banner across the top of the content when a leader is previewing */
.h-viewas {
  display: flex;
  align-items: center;
  gap: var(--h-s-3);
  padding: var(--h-s-2) var(--h-s-8);
  background: var(--h-info-soft);
  color: var(--h-info-ink);
  font-size: var(--h-fs-sm);
  border-bottom: 1px solid var(--h-grey-10);
}
.h-viewas form { margin-left: auto; }

/* Launcher tile — logo left, name right. For app/service launchers on Home.
   NOT the property .h-tile. */
.h-launch-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: var(--h-s-3);
}
.h-launch {
  display: flex;
  align-items: center;
  gap: var(--h-s-3);
  padding: var(--h-s-3) var(--h-s-4);
  min-height: 60px;
  background: var(--h-white);
  border: 1px solid var(--h-grey-10);
  border-radius: var(--h-radius);
  color: var(--h-ink);
  text-decoration: none;
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-semibold);
  line-height: 1.25;
  transition: box-shadow var(--h-duration) var(--h-ease), border-color var(--h-duration) var(--h-ease);
}
.h-launch:hover { box-shadow: var(--h-shadow); border-color: var(--h-blue-20); color: var(--h-blue); }
.h-launch__logo {
  width: 28px; height: 28px; flex: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--h-radius-sm);
  overflow: hidden;
  background: var(--h-white);
}
.h-launch__logo img { width: 100%; height: 100%; object-fit: contain; }
.h-launch__fallback {
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  background: var(--h-blue);
  color: var(--h-white);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-bold);
}
.h-launch--placeholder {
  border-style: dashed;
  color: var(--h-grey-50);
  font-weight: var(--h-fw-regular);
  background: transparent;
}
.h-launch--placeholder:hover { box-shadow: none; border-color: var(--h-grey-10); color: var(--h-grey-50); }

/* Section eyebrow used between launcher groups on Home */
.h-home-section { margin: 0 0 var(--h-s-6); }
.h-home-section__title {
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-bold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  color: var(--h-grey-70);
  margin: 0 0 var(--h-s-3);
}

/* Toggle switch — on/off control for access switches. It's a <button
   role="switch" aria-checked>, so it's a clickable control, not a pill. */
.h-switch {
  position: relative;
  width: 40px; height: 22px;
  border-radius: var(--h-radius-pill);
  background: var(--h-grey-30);
  border: 0;
  padding: 0;
  cursor: pointer;
  flex: none;
  transition: background var(--h-duration) var(--h-ease);
}
.h-switch::after {
  content: "";
  position: absolute;
  top: 3px; left: 3px;
  width: 16px; height: 16px;
  border-radius: 50%;
  background: var(--h-white);
  transition: transform var(--h-duration) var(--h-ease);
}
.h-switch[aria-checked="true"] { background: var(--h-cyan); }
.h-switch[aria-checked="true"]::after { transform: translateX(18px); }
.h-switch:focus-visible { outline: 2px solid var(--h-cyan); outline-offset: 2px; }
.h-switch:disabled { opacity: 0.4; cursor: not-allowed; }
.h-switch-row { display: inline-flex; align-items: center; gap: var(--h-s-2); font-size: var(--h-fs-sm); }

/* Users table extras */
.h-user-cell { display: flex; align-items: center; gap: var(--h-s-3); }
.h-user-cell__avatar {
  width: 32px; height: 32px; border-radius: 50%; overflow: hidden; flex: none;
  background: var(--h-blue); color: var(--h-white);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--h-fs-xs); font-weight: var(--h-fw-bold);
}
.h-user-cell__avatar img { width: 100%; height: 100%; object-fit: cover; }
.h-user-cell__name { font-weight: var(--h-fw-semibold); color: var(--h-blue); line-height: 1.2; }
.h-user-cell__sub { font-size: var(--h-fs-xs); color: var(--h-grey-50); line-height: 1.2; }

/* ---------- Avatar (initials circle) ---------------------------------------
   Soft-tint identity avatar for a person who isn't staff — a caller, a
   contact, a match — wherever initials stand in for a photo: a table row, a
   mobile card, a detail-page header. Distinct from .h-user-cell__avatar
   above (solid navy), which is the staff-directory avatar and is unchanged;
   apps had grown three near-identical copies of this soft-tint recipe at
   three different fixed sizes before this existed. */
.h-avatar {
  display: flex; align-items: center; justify-content: center;
  flex: none;
  width: 36px; height: 36px;
  border-radius: 50%;
  background: var(--h-blue-10);
  color: var(--h-blue);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-bold);
  text-transform: uppercase;
}
.h-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
.h-avatar--md { width: 40px; height: 40px; font-size: var(--h-fs-sm); }
/* Rounded-square, not circle — the size a detail-page hero avatar wants so it
   doesn't read as a tiny badge blown up. */
.h-avatar--lg { width: 52px; height: 52px; font-size: var(--h-fs-lg); border-radius: var(--h-radius-lg); }

/* A tel:/mailto: link shown with its icon inline — universal wherever a
   contact's phone number is clickable text, not just decoration. */
.h-phone-link {
  display: inline-flex; align-items: center; gap: var(--h-s-1);
  color: var(--h-blue); font-weight: var(--h-fw-semibold); white-space: nowrap;
}
.h-phone-link:hover { text-decoration: underline; }

/* A small dot + label chip — an owner, a tag, an assignee — plus the
   dashed-border empty-state variant of the same shape for "nobody yet".
   Named .h-dot-chip, not .h-chip: that name is already taken (the @mention
   chip further below in this file — a different shape for a different job;
   see it before ever reaching for ".h-chip" again). */
.h-dot-chip {
  display: inline-flex; align-items: center; gap: var(--h-s-1);
  padding: calc(var(--h-s-1) + 1px) var(--h-s-3);
  border-radius: var(--h-radius);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-semibold);
  background: var(--h-grey-10);
  color: var(--h-grey-70);
  white-space: nowrap;
}
.h-dot-chip__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--h-blue); flex: none; }
.h-dot-chip--empty {
  background: var(--h-white);
  color: var(--h-grey-70);
  border: 1px dashed var(--h-grey-30);
}

/* A bordered paper-toned box for an <audio> element — a voicemail, a call
   recording — with a caption below. */
.h-recording {
  background: var(--h-paper);
  border: var(--h-border);
  border-radius: var(--h-radius);
  padding: var(--h-s-4);
}
.h-recording__player { width: 100%; display: block; }
.h-recording__note { font-size: var(--h-fs-sm); line-height: var(--h-lh-base); color: var(--h-grey-70); margin: var(--h-s-3) 0 0; }

.h-stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: var(--h-s-3); margin: 0 0 var(--h-s-6); }
/* The numbers in a stat row line up. A label may run to one line or two
   ("Days on market" / "Open home attendance"), so the label reserves two
   lines and the value always starts at the same height in every tile of the
   row — Michael, 16/09/2026, off the vendor report where 14, 1, 0, 2 sat at
   three different heights. A label that needs three lines is too long; shorten
   it rather than widen the tile. */
.h-stat {
  display: flex; flex-direction: column;
  background: var(--h-white); border: 1px solid var(--h-grey-10); border-radius: var(--h-radius);
  padding: var(--h-s-3) var(--h-s-4);
}
.h-stat__label { font-size: var(--h-fs-xs); font-weight: var(--h-fw-semibold); letter-spacing: var(--h-tracking-wide); text-transform: uppercase; color: var(--h-grey-50); line-height: var(--h-lh-snug); min-height: calc(2 * var(--h-lh-snug) * 1em); margin: 0 0 var(--h-s-1); }
.h-stat__value { font-size: var(--h-fs-2xl); font-weight: var(--h-fw-bold); color: var(--h-blue); line-height: 1; margin: 0; }
.h-stat__sub { font-size: var(--h-fs-xs); color: var(--h-grey-50); margin: var(--h-s-1) 0 0; }

@media (max-width: 900px) {
  .h-shell { flex-direction: column; }
  .h-sidebar { width: 100%; height: auto; position: static; }
  .h-sidebar__nav { padding-bottom: var(--h-s-3); }
  .h-shell__content { padding: var(--h-s-4); }
  .h-shell__topbar, .h-viewas, .h-bday-banner { padding-left: var(--h-s-4); padding-right: var(--h-s-4); }
}

/* Studio shell fixes 04/09/2026 — [hidden] must beat display rules on these */
.h-toast[hidden], .h-launch__fallback[hidden], .h-form-card__actions[hidden] { display: none; }
.h-splash-backdrop[hidden] { display: none; }
.h-bday-banner[hidden] { display: none; }
/* .h-label is display:flex (stacked caption over control), which beats the UA
   stylesheet [hidden] rule -- so a JS-hidden field stayed on screen. The
   attendance form showed two date fields because of exactly this, and the one
   she filled in was the one thrown away. */
.h-label[hidden], .h-grid--2 > [hidden] { display: none !important; }
.h-sidebar__search svg { width: 16px; height: 16px; flex: none; }
.h-sidebar__brand-img { height: 18px; top: 3px; }
.h-shell__topbar label { white-space: nowrap; font-size: var(--h-fs-sm); }
.h-shell__topbar .h-select { width: auto; min-width: 200px; }
.h-launch--placeholder .h-launch__fallback { background: var(--h-grey-10); color: var(--h-grey-50); }

/* Sidebar brand: franchise-extension rule — "Studio" is Source Sans Light,
   cyan, tracking 0, CAP HEIGHT aligned to the Harcourts H (wordmark PNG has
   its cap top at row 0 and its baseline at 73.6% of its height; the cyan
   underscore below that is not part of the text). 04/09/2026 */
.h-sidebar__brand { align-items: flex-start; }
.h-sidebar__brand-img { height: 18px; top: 0; }
.h-sidebar__brand-ext { font-size: 20px; line-height: 1; margin-top: -4px; padding-left: var(--h-s-2); margin-left: var(--h-s-1); border-left-width: 1px; }

/* ---------- Studio Projects / Ideas (04/09/2026) --------------------------- */
.h-seg-count { opacity: 0.7; font-weight: var(--h-fw-regular); margin-left: var(--h-s-1); }
.h-proj-toolbar { display: flex; gap: var(--h-s-2); align-items: center; margin: 0 0 var(--h-s-4); }
.h-proj-form { padding: var(--h-s-5); margin: 0 0 var(--h-s-5); }
.h-proj-form:hover { transform: none; box-shadow: var(--h-shadow); }
.h-proj-form--idea { padding: var(--h-s-4) var(--h-s-5); }
.h-proj-form__grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--h-s-3) var(--h-s-4); }
.h-proj-form__wide { grid-column: 1 / -1; }
.h-proj-form .h-label { display: flex; flex-direction: column; gap: var(--h-s-1); }
.h-proj-form .h-textarea { min-height: 72px; }
.h-proj-form__actions { display: flex; justify-content: flex-end; gap: var(--h-s-2); margin-top: var(--h-s-4); }
.h-proj-list { display: flex; flex-direction: column; gap: var(--h-s-3); }
.h-proj, .h-idea {
  background: var(--h-white);
  border: 1px solid var(--h-grey-10);
  border-radius: var(--h-radius);
  padding: var(--h-s-4) var(--h-s-5);
}
.h-proj--done { opacity: 0.6; }
.h-proj__head, .h-idea__head { display: flex; align-items: center; gap: var(--h-s-3); }
.h-proj__title {
  flex: 1; margin: 0;
  font-size: var(--h-fs-lg); font-weight: var(--h-fw-bold); color: var(--h-blue);
  letter-spacing: var(--h-tracking-tight); outline: none; border-radius: var(--h-radius-sm);
}
.h-proj [contenteditable="true"]:hover { background: var(--h-blue-10); }
.h-proj [contenteditable="true"]:focus { background: var(--h-white); box-shadow: 0 0 0 2px var(--h-cyan); }
.h-proj [contenteditable="true"]:empty::before { content: attr(data-placeholder); color: var(--h-grey-50); }
.h-proj__summary { margin: var(--h-s-2) 0 0; color: var(--h-ink); font-size: var(--h-fs-base); line-height: var(--h-lh-snug); outline: none; border-radius: var(--h-radius-sm); }
.h-proj__next { display: flex; gap: var(--h-s-3); align-items: baseline; margin: var(--h-s-3) 0 0; padding: var(--h-s-2) var(--h-s-3); background: var(--h-paper); border-left: 2px solid var(--h-cyan); }
.h-proj__label { font-size: var(--h-fs-xs); font-weight: var(--h-fw-semibold); letter-spacing: var(--h-tracking-wide); text-transform: uppercase; color: var(--h-grey-50); flex: none; }
.h-proj__next-text { flex: 1; font-size: var(--h-fs-sm); color: var(--h-ink); outline: none; }
.h-proj__foot { display: flex; align-items: center; gap: var(--h-s-2); margin-top: var(--h-s-3); flex-wrap: wrap; }
.h-proj__spacer { flex: 1; }
.h-idea__toggle { flex: 1; text-align: left; cursor: pointer; display: block; }
.h-idea__title { font-size: var(--h-fs-base); font-weight: var(--h-fw-semibold); color: var(--h-blue); }
.h-idea__toggle:hover .h-idea__title { text-decoration: underline; }
.h-idea__meta { margin-top: var(--h-s-1); }
.h-idea__body { margin-top: var(--h-s-3); border-top: 1px solid var(--h-grey-10); padding-top: var(--h-s-3); }
.h-idea__text { font-family: var(--h-font-sans); font-size: var(--h-fs-sm); white-space: pre-wrap; margin: 0; color: var(--h-ink); line-height: var(--h-lh-base); max-height: 360px; overflow: auto; }
.h-idea__notes { list-style: none; padding: 0; margin: var(--h-s-3) 0 0; display: flex; flex-direction: column; gap: var(--h-s-2); font-size: var(--h-fs-sm); }
.h-idea__notes li { padding: var(--h-s-2) var(--h-s-3); background: var(--h-paper); border-radius: var(--h-radius-sm); }
.h-idea__note-form { display: flex; gap: var(--h-s-2); margin-top: var(--h-s-3); }
.h-idea__note-form .h-input { flex: 1; }
.h-idea__actions { display: flex; gap: var(--h-s-2); flex-wrap: wrap; margin-top: var(--h-s-3); }
@media (max-width: 768px) { .h-proj-form__grid { grid-template-columns: 1fr; } }

/* Project card sections (04/09/2026): heading → Description → Next step → Notes */
.h-proj__section { margin-top: var(--h-s-4); }
.h-proj__section > .h-proj__label { display: block; margin: 0 0 var(--h-s-1); }
.h-proj__count { display: inline-block; margin-left: var(--h-s-1); padding: 0 var(--h-s-2); background: var(--h-blue-10); color: var(--h-blue); border-radius: var(--h-radius); font-size: var(--h-fs-xs); letter-spacing: 0; text-transform: none; }
.h-proj__next-text { display: block; margin: 0; padding: var(--h-s-2) var(--h-s-3); background: var(--h-paper); border-left: 2px solid var(--h-cyan); font-size: var(--h-fs-sm); border-radius: var(--h-radius-sm); }
.h-proj__notes { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: var(--h-s-2); font-size: var(--h-fs-sm); }
.h-proj__notes:empty { display: none; }
.h-proj__notes li { padding: var(--h-s-2) var(--h-s-3); background: var(--h-paper); border-radius: var(--h-radius-sm); }
.h-proj__note-form { display: flex; gap: var(--h-s-2); margin-top: var(--h-s-2); }
.h-proj__note-form .h-input { flex: 1; }
.h-proj__foot { margin-top: var(--h-s-4); }

/* ---------- Studio: compact cards + pop-up card (Trello-style) 04/09/2026 -- */
.h-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: var(--h-s-3); }
.h-mini {
  background: var(--h-white); border: 1px solid var(--h-grey-10); border-radius: var(--h-radius);
  padding: var(--h-s-3) var(--h-s-4); cursor: pointer; display: flex; flex-direction: column; gap: var(--h-s-2);
  transition: box-shadow var(--h-duration) var(--h-ease), border-color var(--h-duration) var(--h-ease);
}
.h-mini:hover, .h-mini:focus-visible { box-shadow: var(--h-shadow); border-color: var(--h-blue-20); outline: none; }
.h-mini--done { opacity: 0.6; }
.h-mini__head { display: flex; align-items: flex-start; gap: var(--h-s-2); }
.h-mini__title { flex: 1; min-width: 0; margin: 0; font-size: var(--h-fs-base); font-weight: var(--h-fw-bold); color: var(--h-blue); line-height: var(--h-lh-snug); letter-spacing: var(--h-tracking-tight); overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.h-mini__next { margin: 0; font-size: var(--h-fs-sm); color: var(--h-ink); line-height: var(--h-lh-snug); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.h-mini__foot { margin-top: auto; }
/* Every tile in the grid starts and ends on the same line: a two-line title
   cap, and a floor so a one-line tile does not sit short next to a two-line
   one. 08/09/2026 — a pasted URL title made one tile three lines tall. */
.h-cards:not(.h-cards--list) .h-mini { min-height: 132px; }
/* Ideas tiles: set Now / Next / Later without opening the card. */
.h-mini__pri { display: flex; width: 100%; }
.h-mini__pri .h-segmented__option { flex: 1; padding: 3px var(--h-s-2); font-size: var(--h-fs-xs); letter-spacing: var(--h-tracking-wide); text-transform: uppercase; color: var(--h-grey-50); text-align: center; }
.h-mini__pri .h-segmented__option[aria-pressed="true"] { color: var(--h-white); }
.h-cards--list .h-mini__pri { display: none; }

body.h-modal-open { overflow: hidden; }
.h-modal--card { width: min(920px, calc(100vw - var(--h-s-6))); padding: 0; }
.h-modal--card .h-modal-close { position: absolute; top: var(--h-s-3); right: var(--h-s-3); z-index: 1; }
/* Prev / next through the cards behind a card modal (Studio projects and
   ideas). Sits beside the close button; the arrow keys do the same. */
.h-modal--card .h-modal-nav { position: absolute; top: var(--h-s-3); right: calc(var(--h-s-3) + 40px); z-index: 1; display: inline-flex; align-items: center; gap: var(--h-s-1); }
/* display:inline-flex above beats the hidden attribute, so a single-card modal
   was still showing "1 of 1" over the side rail. 08/09/2026. */
.h-modal--card .h-modal-nav[hidden] { display: none; }
.h-modal-nav .h-modal-close { position: static; }
.h-modal-nav .h-modal-close svg { width: 18px; height: 18px; }
.h-modal-nav .h-modal-close:disabled { opacity: 0.3; cursor: default; background: transparent; }
.h-modal-nav__count { min-width: 4.5em; text-align: center; font-size: var(--h-fs-xs); color: var(--h-grey-50); font-variant-numeric: tabular-nums; }
.h-modal--nav .h-cardm__side { padding-top: calc(var(--h-s-6) + var(--h-s-5)); }
/* Ideas tab: priority + department in the card rail, department strip on the toolbar */
.h-cardm__seg { display: flex; }
.h-cardm__seg .h-segmented__option { flex: 1; padding-left: 0; padding-right: 0; text-align: center; }
.h-cardm__side .h-select { width: 100%; }
.h-cardm__label--gap { margin-top: var(--h-s-4); }
.h-proj-toolbar--wrap { flex-wrap: wrap; }
/* Wrapped toolbar: the filter box and the view toggle still finish hard right,
   whichever line they end up on. */
.h-proj-toolbar--wrap .h-filter { margin-left: auto; }
.h-dept-filter { flex-wrap: wrap; }
.h-dept-filter__n { margin-left: 2px; font-size: var(--h-fs-xs); font-weight: var(--h-fw-regular); color: var(--h-grey-50); font-variant-numeric: tabular-nums; }
.h-segmented__option[aria-pressed="true"] .h-dept-filter__n { color: var(--h-white); opacity: 0.75; }
.h-cardm { display: grid; grid-template-columns: 1fr 220px; }
.h-cardm__main { padding: var(--h-s-6); min-width: 0; }
.h-cardm__side { padding: var(--h-s-6) var(--h-s-5); background: var(--h-paper); border-left: 1px solid var(--h-grey-10); display: flex; flex-direction: column; gap: var(--h-s-2); }
.h-cardm__side .h-btn { justify-content: center; }
.h-cardm__owner { margin-top: var(--h-s-4); }
.h-cardm__side .h-label { display: flex; flex-direction: column; gap: var(--h-s-1); font-size: var(--h-fs-xs); }
.h-cardm__title { margin: 0 0 var(--h-s-1); font-size: var(--h-fs-2xl); font-weight: var(--h-fw-bold); color: var(--h-blue); letter-spacing: var(--h-tracking-tight); line-height: var(--h-lh-tight); outline: none; border-radius: var(--h-radius-sm); }
.h-cardm__section { margin-top: var(--h-s-6); }
.h-cardm__label { margin: 0 0 var(--h-s-2); font-size: var(--h-fs-xs); font-weight: var(--h-fw-semibold); letter-spacing: var(--h-tracking-wide); text-transform: uppercase; color: var(--h-grey-70); }
.h-cardm__text { font-size: var(--h-fs-base); line-height: var(--h-lh-base); color: var(--h-ink); outline: none; border-radius: var(--h-radius-sm); padding: var(--h-s-2) var(--h-s-3); margin: 0 calc(-1 * var(--h-s-3)); }
.h-cardm__text--pre { white-space: pre-wrap; font-size: var(--h-fs-sm); }
.h-cardm__next { font-size: var(--h-fs-sm); padding: var(--h-s-2) var(--h-s-3); background: var(--h-paper); border-left: 2px solid var(--h-cyan); border-radius: var(--h-radius-sm); outline: none; }
.h-cardm [contenteditable="true"]:hover { background: var(--h-blue-10); }
.h-cardm [contenteditable="true"]:focus { background: var(--h-white); box-shadow: 0 0 0 2px var(--h-cyan); }
.h-cardm [contenteditable="true"]:empty::before { content: attr(data-placeholder); color: var(--h-grey-50); }
.h-cardm__note-form { display: flex; flex-direction: column; gap: var(--h-s-2); align-items: flex-end; margin-bottom: var(--h-s-3); }
.h-cardm__note-input { width: 100%; min-height: 56px; }
.h-cardm__notes { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: var(--h-s-2); font-size: var(--h-fs-sm); }
.h-cardm__notes li { padding: var(--h-s-2) var(--h-s-3); background: var(--h-paper); border-radius: var(--h-radius-sm); white-space: pre-wrap; }
/* Project tasks — the checklist on a project card (Studio /projects) */
.h-tasks__track { height: 3px; background: var(--h-grey-10); border-radius: var(--h-radius-sm); overflow: hidden; margin-bottom: var(--h-s-3); }
.h-tasks__fill { display: block; height: 100%; width: 0; background: var(--h-cyan); transition: width var(--h-duration) var(--h-ease); }
.h-tasks { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; }
.h-tasks__item { display: flex; align-items: flex-start; gap: var(--h-s-3); padding: var(--h-s-2) var(--h-s-2) var(--h-s-2) 0; border-bottom: 1px solid var(--h-grey-10); font-size: var(--h-fs-sm); line-height: var(--h-lh-base); }
.h-tasks__item:last-child { border-bottom: 0; }
.h-tasks__check { display: flex; align-items: flex-start; gap: var(--h-s-2); flex: 1; min-width: 0; cursor: pointer; }
.h-tasks__check input { margin: 3px 0 0; accent-color: var(--h-blue); flex: none; }
.h-tasks__item.is-done .h-tasks__check span { text-decoration: line-through; color: var(--h-grey-50); }
.h-tasks__acts { flex: none; opacity: 0; transition: opacity var(--h-duration) var(--h-ease); white-space: nowrap; }
.h-tasks__item:hover .h-tasks__acts, .h-tasks__item:focus-within .h-tasks__acts { opacity: 1; }
.h-tasks__acts a { color: var(--h-grey-50); }
.h-tasks__acts a:hover { color: var(--h-blue); }
.h-tasks__editor { width: 100%; font-size: var(--h-fs-sm); }
.h-tasks__empty { margin: 0; }
.h-tasks__add { display: flex; gap: var(--h-s-2); align-items: flex-start; margin-top: var(--h-s-3); }
.h-tasks__input { flex: 1; min-height: 38px; font-size: var(--h-fs-sm); }
@media (max-width: 768px) { .h-tasks__acts { opacity: 1; } }
.h-attach { list-style: none; padding: 0; margin: 0 0 var(--h-s-3); display: flex; flex-direction: column; gap: var(--h-s-2); }
.h-attach:empty { margin: 0; }
.h-attach__item { display: flex; gap: var(--h-s-3); align-items: center; }
.h-attach__thumb { width: 72px; height: 52px; flex: none; background: var(--h-grey-10); border-radius: var(--h-radius-sm); overflow: hidden; display: flex; align-items: center; justify-content: center; text-decoration: none; }
.h-attach__thumb img { width: 100%; height: 100%; object-fit: cover; }
.h-attach__ext { font-size: var(--h-fs-xs); font-weight: var(--h-fw-bold); color: var(--h-blue); letter-spacing: var(--h-tracking-wide); }
.h-attach__meta { min-width: 0; }
.h-attach__name { display: block; font-size: var(--h-fs-sm); font-weight: var(--h-fw-semibold); color: var(--h-blue); text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-attach__name:hover { text-decoration: underline; }
.h-attach__add { cursor: pointer; }
@media (max-width: 768px) {
  .h-cardm { grid-template-columns: 1fr; }
  .h-cardm__side { border-left: 0; border-top: 1px solid var(--h-grey-10); }
  .h-cardm__main { padding: var(--h-s-5) var(--h-s-4); }
}

/* Tiles / List toggle for card grids (04/09/2026) */
.h-view-toggle { flex: none; }
.h-cards--list { display: flex; flex-direction: column; gap: 0; border: 1px solid var(--h-grey-10); border-radius: var(--h-radius); background: var(--h-white); }
.h-cards--list .h-mini { flex-direction: row; align-items: center; gap: var(--h-s-3); border: 0; border-bottom: 1px solid var(--h-grey-10); border-radius: 0; padding: var(--h-s-2) var(--h-s-4); }
.h-cards--list .h-mini:last-child { border-bottom: 0; }
.h-cards--list .h-mini:hover { box-shadow: none; background: var(--h-blue-10); }
.h-cards--list .h-mini__head { flex: 1; align-items: center; min-width: 0; }
.h-cards--list .h-mini__title { display: block; font-size: var(--h-fs-sm); font-weight: var(--h-fw-semibold); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.h-cards--list .h-mini__next { display: none; }
.h-cards--list .h-mini__foot { margin: 0; flex: none; white-space: nowrap; }
@media (max-width: 640px) { .h-cards--list .h-mini__foot { display: none; } }

/* Studio: phone layout — sidebar collapses to a top bar with a menu button (04/09/2026) */
.h-sidebar__top { display: flex; align-items: center; justify-content: space-between; }
.h-sidebar__menu { display: none; color: var(--h-white); margin-right: var(--h-s-3); padding: var(--h-s-2); }
.h-sidebar__menu svg { width: 22px; height: 22px; }
.h-sidebar__drawer { display: contents; }
.h-due--over { color: var(--h-error-ink); font-weight: var(--h-fw-semibold); }
@media (max-width: 900px) {
  .h-sidebar__menu { display: inline-flex; }
  .h-sidebar__drawer { display: none; flex-direction: column; padding-bottom: var(--h-s-2); }
  .h-sidebar__drawer.is-open { display: flex; }
  .h-sidebar__user { border-top: 1px solid rgba(255,255,255,0.12); }
  .h-sidebar__brand { padding: var(--h-s-4) var(--h-s-5); }
}
.h-sidebar__menu:hover, .h-sidebar__menu[aria-expanded="true"] { background: rgba(255,255,255,0.12); color: var(--h-white); }

/* Quiet filter box — icon + underline, no bulk (04/09/2026) */
.h-filter { display: inline-flex; align-items: center; gap: var(--h-s-2); color: var(--h-grey-50); border-bottom: 1px solid var(--h-grey-30); padding: var(--h-s-1) 0; margin-right: var(--h-s-3); transition: border-color var(--h-duration) var(--h-ease); }
.h-filter:focus-within { border-bottom-color: var(--h-cyan); color: var(--h-blue); }
.h-filter svg { width: 15px; height: 15px; flex: none; }
.h-filter__input { border: 0; background: none; outline: none; font-family: var(--h-font-sans); font-size: var(--h-fs-sm); color: var(--h-ink); width: 140px; padding: 0; }
.h-filter__input::placeholder { color: var(--h-grey-50); }
.h-filter__input::-webkit-search-cancel-button { -webkit-appearance: none; }
.h-cardm__note-editrow { display: flex; justify-content: flex-end; gap: var(--h-s-2); margin-top: var(--h-s-2); }
.h-cardm__notes li .h-meta a { color: var(--h-grey-50); }
.h-cardm__notes li .h-meta a:hover { color: var(--h-blue); }
@media (max-width: 640px) { .h-filter__input { width: 90px; } }
.h-mini[hidden] { display: none; }

/* List view: fixed right-hand columns so badges and dates line up (04/09/2026) */
.h-mini__badges { display: inline-flex; gap: var(--h-s-1); flex: none; justify-content: flex-end; }
/* Same column on every tile, whatever the words are: fixed-width badges, hard
   right. In tile view the priority badge stands down — the Now/Next/Later
   buttons at the foot carry it — so one badge sits in one place. */
.h-mini__badges .h-badge { min-width: 72px; text-align: center; }
.h-cards:not(.h-cards--list) .h-mini__badges [data-tile-priority] { display: none; }
.h-mini__date { display: none; }
.h-cards--list .h-mini__date { display: inline-block; width: 92px; text-align: right; flex: none; font-variant-numeric: tabular-nums; }
.h-cards--list .h-mini__badges { width: 96px; justify-content: flex-end; }
.h-cards--list .h-mini__badges .h-badge { min-width: 72px; text-align: center; }
.h-cards--list .h-mini__foot { display: none; }
@media (max-width: 640px) { .h-cards--list .h-mini__date { display: none; } }
.h-ref { display: inline-block; margin-right: var(--h-s-2); font-family: var(--h-font-mono); font-size: var(--h-fs-xs); font-weight: var(--h-fw-regular); color: var(--h-grey-50); letter-spacing: 0; vertical-align: 1px; }

/* ---------- Calculator page pattern (Break Lease Fee etc.) 04/09/2026 ------- */
.h-calc { max-width: 860px; padding: var(--h-s-6); }
.h-calc:hover { transform: none; box-shadow: var(--h-shadow); }
.h-calc__grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--h-s-4); }
.h-calc__grid .h-label { display: flex; flex-direction: column; gap: var(--h-s-1); }
.h-calc__actions { margin-top: var(--h-s-5); }
.h-calc__result { margin-top: var(--h-s-5); }
.h-calc__result[hidden], .h-calc .h-notice[hidden] { display: none; }
.h-calc .h-notice { margin-top: var(--h-s-4); }
.h-calc__big { font-size: var(--h-fs-4xl); font-weight: var(--h-fw-bold); color: var(--h-blue); letter-spacing: var(--h-tracking-tight); line-height: 1; margin: 0 0 var(--h-s-2); }
.h-calc__tiers { margin-top: var(--h-s-5); }
.h-calc__tiers tr.is-active td { background: var(--h-blue); color: var(--h-white); font-weight: var(--h-fw-semibold); }
.h-calc__notes { max-width: 860px; margin: var(--h-s-6) 0 0; padding-left: var(--h-s-5); line-height: var(--h-lh-base); }
.h-calc__notes li { margin-bottom: var(--h-s-2); }
.h-launch__logo--icon { color: var(--h-blue); background: var(--h-blue-10); }
.h-launch__logo--icon svg { width: 16px; height: 16px; }
@media (max-width: 640px) { .h-calc__grid { grid-template-columns: 1fr; } }

/* ---------- Simple form card (Shout Out etc.) 05/09/2026 -------------------- */
.h-form-card { max-width: 620px; padding: var(--h-s-6); }
.h-form-card:hover { transform: none; box-shadow: var(--h-shadow); }
.h-form-card .h-label { display: flex; flex-direction: column; gap: var(--h-s-1); margin-bottom: var(--h-s-4); }
.h-form-card__counter { text-align: right; }
.h-form-card__check { display: flex; align-items: center; gap: var(--h-s-3); padding: var(--h-s-3) var(--h-s-4); background: var(--h-paper); border-radius: var(--h-radius); font-size: var(--h-fs-sm); color: var(--h-grey-70); cursor: pointer; margin-bottom: var(--h-s-5); }
.h-form-card__check input { width: 16px; height: 16px; flex: none; }
.h-form-card__actions { display: flex; justify-content: flex-start; margin-top: var(--h-s-5); }
.h-form-card__done { text-align: center; padding: var(--h-s-4) 0; }
.h-form-card__done-title { font-size: var(--h-fs-lg); font-weight: var(--h-fw-semibold); color: var(--h-blue); margin: 0 0 var(--h-s-1); }
.h-form-card__done .h-btn { margin-top: var(--h-s-5); }
.h-feed { max-width: 620px; margin-top: var(--h-s-8); }
.h-feed__item { background: var(--h-white); border: 1px solid var(--h-grey-10); border-left: 2px solid var(--h-cyan); border-radius: var(--h-radius); padding: var(--h-s-3) var(--h-s-4); margin-bottom: var(--h-s-2); }
.h-feed__to { margin: 0 0 var(--h-s-1); font-weight: var(--h-fw-bold); color: var(--h-blue); font-size: var(--h-fs-sm); }
.h-feed__msg { margin: 0 0 var(--h-s-2); font-size: var(--h-fs-sm); line-height: var(--h-lh-base); }

/* Notification counts — the red number ball (05/09/2026) */
.h-sidebar__badge--alert { background: var(--h-error); color: var(--h-white); border-radius: 50%; min-width: 20px; height: 20px; padding: 0 6px; }
.h-launch { position: relative; }
.h-launch__badge { position: absolute; top: -8px; right: -8px; min-width: 22px; height: 22px; padding: 0 6px; border-radius: 50%; background: var(--h-error); color: var(--h-white); font-size: var(--h-fs-xs); font-weight: var(--h-fw-bold); display: inline-flex; align-items: center; justify-content: center; box-shadow: 0 0 0 2px var(--h-paper); }
.h-feed--you { margin-top: 0; margin-bottom: var(--h-s-6); }
.h-feed__item--you { border-left-color: var(--h-blue); }
.h-form-card__check { margin-bottom: var(--h-s-3); }
.h-form-card__check + .h-form-card__check { margin-bottom: var(--h-s-5); }

/* ---------- Usage report: bar chart + ranked bars (05/09/2026) -------------- */
.h-chart { position: relative; padding: var(--h-s-5) var(--h-s-5) var(--h-s-4); }
.h-chart:hover { transform: none; box-shadow: var(--h-shadow); }
.h-chart__bars { display: flex; align-items: flex-end; gap: 3px; height: 160px; border-bottom: 1px solid var(--h-grey-10); }
.h-chart__col { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; align-items: stretch; height: 100%; position: relative; cursor: default; }
.h-chart__col:hover .h-chart__bar { background: var(--h-cyan); }
.h-chart__bar { height: var(--h, 0%); min-height: 2px; background: var(--h-blue); border-radius: 4px 4px 0 0; transition: background var(--h-duration) var(--h-ease); }
.h-chart__col--dim .h-chart__bar { background: var(--h-blue-20); }
.h-chart__x { position: absolute; top: 100%; left: 0; margin-top: var(--h-s-1); font-size: var(--h-fs-xs); color: var(--h-grey-50); white-space: nowrap; }
.h-chart__bars { margin-bottom: var(--h-s-5); }
.h-chart__tip { position: absolute; top: var(--h-s-2); left: var(--x, 50%); transform: translateX(-50%); background: var(--h-blue); color: var(--h-white); font-size: var(--h-fs-xs); font-weight: var(--h-fw-semibold); padding: var(--h-s-1) var(--h-s-3); border-radius: var(--h-radius); white-space: nowrap; pointer-events: none; }
.h-chart__tip[hidden] { display: none; }
.h-delta--down { color: var(--h-error-ink); font-weight: var(--h-fw-semibold); }
.h-delta--up { color: var(--h-success-ink); font-weight: var(--h-fw-semibold); }
.h-usage-grid { display: grid; grid-template-columns: 3fr 2fr; gap: var(--h-s-5); align-items: start; }
.h-table--tight th, .h-table--tight td { padding: var(--h-s-2) var(--h-s-3); }
.h-bars { list-style: none; margin: 0; padding: var(--h-s-2) var(--h-s-4); }
.h-bars__row { display: grid; grid-template-columns: 130px 1fr 40px 70px; align-items: center; gap: var(--h-s-3); padding: var(--h-s-2) 0; border-bottom: 1px solid var(--h-grey-10); font-size: var(--h-fs-sm); }
.h-bars__row:last-child { border-bottom: 0; }
.h-bars__label { font-weight: var(--h-fw-semibold); color: var(--h-blue); }
.h-bars__track { height: 8px; background: var(--h-grey-10); border-radius: 4px; overflow: hidden; }
.h-bars__fill { display: block; height: 100%; width: var(--w, 0%); background: var(--h-blue); border-radius: 4px; }
.h-bars__val { text-align: right; }
.h-people-list { list-style: none; margin: 0; padding: var(--h-s-2) var(--h-s-4); display: flex; flex-direction: column; gap: var(--h-s-2); }
.h-mt-6 { margin-top: var(--h-s-6); }
.h-mt-7 { margin-top: var(--h-s-7); }
.h-mb-6 { margin-bottom: var(--h-s-6); }
@media (max-width: 900px) { .h-usage-grid { grid-template-columns: 1fr; } .h-bars__row { grid-template-columns: 110px 1fr 36px; } .h-bars__sub { display: none; } }
@media (max-width: 640px) {
  .h-chart__col:last-child .h-chart__x { display: none; }
  .h-table--tight th:nth-child(3), .h-table--tight td:nth-child(3), .h-table--tight th:nth-child(4), .h-table--tight td:nth-child(4) { display: none; }
  .h-user-cell__sub { display: none; }
}

/* Sidebar call-to-action under the wordmark ("Make It Better") 05/09/2026 */
.h-sidebar__cta { margin: 0 var(--h-s-4) var(--h-s-4); justify-content: center; gap: var(--h-s-2); font-weight: var(--h-fw-bold); letter-spacing: 0.02em; }
.h-sidebar__cta svg { width: 16px; height: 16px; }

/* ---------- Issues: stars, thread, mentions, sharing (05/09/2026) ---------- */
.h-stars { display: inline-flex; align-items: center; gap: 2px; }
.h-stars__star { display: inline-flex; width: 28px; height: 28px; color: var(--h-grey-30); cursor: default; }
.h-stars__star svg { width: 100%; height: 100%; fill: currentColor; }
.h-stars__star.is-on { color: var(--h-blue); }
.h-stars--edit .h-stars__star, .h-form-card .h-stars__star { cursor: pointer; }
.h-stars--edit .h-stars__star:hover, .h-form-card .h-stars__star:hover { color: var(--h-cyan); }
.h-stars__label { margin-left: var(--h-s-2); }
.h-stars--tiny { vertical-align: -3px; margin-right: var(--h-s-2); }
.h-stars--tiny .h-stars__star { width: 13px; height: 13px; }
.h-form-card--wide { max-width: 760px; }
.h-form-card .h-label > .h-segmented, .h-form-card .h-label > .h-stars, .h-form-card .h-label > .h-attach__add { align-self: flex-start; margin-top: var(--h-s-1); }
.h-segmented--form .h-segmented__option { cursor: pointer; }
/* Four-way pickers in a table cell (leave editor: Full / Morning / Afternoon / Off)
   wrap on a phone instead of forcing the whole table to scroll sideways. */
.h-segmented--wrap { flex-wrap: wrap; }
.h-thread { list-style: none; margin: 0 0 var(--h-s-3); padding: 0; display: flex; flex-direction: column; gap: var(--h-s-3); }
.h-thread__item { display: flex; gap: var(--h-s-3); align-items: flex-start; }
.h-thread__avatar { width: 28px; height: 28px; font-size: 10px; flex: none; }
.h-thread__body { flex: 1; background: var(--h-paper); border-radius: var(--h-radius); padding: var(--h-s-2) var(--h-s-3); font-size: var(--h-fs-sm); }
.h-thread__item--me .h-thread__body { background: var(--h-blue-10); }
.h-thread__text { white-space: pre-wrap; line-height: var(--h-lh-base); margin-top: 2px; }
.h-mention-host { position: relative; }
.h-mention { position: absolute; left: 0; bottom: calc(100% - 2px); background: var(--h-white); border: 1px solid var(--h-grey-10); border-radius: var(--h-radius); box-shadow: var(--h-shadow); z-index: 2; min-width: 200px; overflow: hidden; }
.h-mention[hidden] { display: none; }
.h-mention__item { display: block; padding: var(--h-s-2) var(--h-s-3); font-size: var(--h-fs-sm); color: var(--h-blue); text-decoration: none; }
.h-mention__item:hover { background: var(--h-blue-10); }
.h-share { display: flex; flex-direction: column; gap: 2px; max-height: 260px; overflow: auto; }
.h-share__row { display: flex; align-items: center; gap: var(--h-s-2); font-size: var(--h-fs-xs); padding: 3px 0; cursor: pointer; color: var(--h-ink); }
.h-share__row input { width: 14px; height: 14px; }
.h-btn svg { width: 16px; height: 16px; flex: none; }
.h-btn { white-space: nowrap; }

/* Wordmark + extension lockup, per the official horizontal logo (05/09/2026):
   no divider, Light weight, cap height = wordmark cap height, same baseline,
   gap about half a cap height. */
.h-sidebar__brand-ext { border-left: 0; padding-left: 0; margin-left: 7px; font-weight: var(--h-fw-light); }
.h-sidebar__brand { gap: 0; }

/* Person chip for @mentions (05/09/2026; retuned 17/09/2026). The pill version
   read as loudly as the sentence it sat in: a tinted box, 0.95em text and an
   18px photo on a 14px line, aligned on the IMAGE's baseline so the name rode
   high, with 8px of right padding pushing the following comma clear of the
   name ("Jarath Moss , which letters?"). A mention is part of the sentence, not
   a button, so it now sits IN the text — small photo, name in brand blue, no
   box, line-height 1 so it never stretches the line it lands on. The picker
   below keeps a bigger photo because it is a tap target. */
.h-chip { display: inline-flex; align-items: center; gap: 4px; padding: 0; margin: 0; color: var(--h-blue); font-weight: var(--h-fw-semibold); font-size: 0.9em; line-height: 1; vertical-align: middle; white-space: nowrap; }
.h-chip img, .h-chip i { width: 15px; height: 15px; border-radius: 50%; object-fit: cover; flex: none; }
.h-chip i { display: inline-flex; align-items: center; justify-content: center; background: var(--h-blue); color: var(--h-white); font-style: normal; font-size: 7px; font-weight: var(--h-fw-bold); }
.h-mention__item { display: flex; align-items: center; }
.h-mention__item .h-chip { font-size: var(--h-fs-sm); gap: var(--h-s-2); }
.h-mention__item .h-chip img, .h-mention__item .h-chip i { width: 22px; height: 22px; }
.h-mention__item .h-chip i { font-size: 9px; }

/* Issues: sent page, similar list, timeline, phone-only camera (05/09/2026) */
.h-sent { text-align: left; }
.h-sent__num { margin: 0; font-family: var(--h-font-mono); font-size: var(--h-fs-sm); color: var(--h-grey-50); }
.h-sent__title { margin: var(--h-s-1) 0 var(--h-s-2); font-size: var(--h-fs-3xl); font-weight: var(--h-fw-bold); color: var(--h-blue); letter-spacing: var(--h-tracking-tight); line-height: var(--h-lh-tight); }
.h-sent__what { margin: 0 0 var(--h-s-5); color: var(--h-grey-70); }
.h-sent__steps { list-style: none; margin: 0 0 var(--h-s-6); padding: 0; display: flex; flex-direction: column; gap: var(--h-s-3); font-size: var(--h-fs-sm); }
.h-sent__steps li { display: flex; gap: var(--h-s-3); align-items: flex-start; line-height: var(--h-lh-snug); }
.h-sent__dot { width: 10px; height: 10px; border-radius: 50%; background: var(--h-cyan); flex: none; margin-top: 5px; }
.h-similar { margin: calc(-1 * var(--h-s-3)) 0 var(--h-s-4); padding: var(--h-s-3) var(--h-s-4); background: var(--h-warning-soft); border-radius: var(--h-radius); }
.h-similar[hidden] { display: none; }
.h-similar__list { list-style: none; margin: var(--h-s-2) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--h-s-1); }
.h-similar__item { display: flex; align-items: center; gap: var(--h-s-2); text-decoration: none; color: var(--h-blue); font-size: var(--h-fs-sm); font-weight: var(--h-fw-semibold); }
.h-similar__item:hover .h-similar__title { text-decoration: underline; }
.h-similar__title { flex: 1; }
.h-timeline { list-style: none; margin: 0; padding: 0; display: flex; gap: var(--h-s-6); }
.h-timeline li { display: flex; gap: var(--h-s-2); align-items: flex-start; font-size: var(--h-fs-sm); position: relative; }
.h-timeline li div { display: flex; flex-direction: column; line-height: 1.3; }
.h-timeline li strong { color: var(--h-grey-50); font-weight: var(--h-fw-semibold); }
.h-timeline li.is-done strong { color: var(--h-blue); }
.h-timeline__dot { width: 12px; height: 12px; border-radius: 50%; border: 2px solid var(--h-grey-30); background: var(--h-white); flex: none; margin-top: 3px; }
.h-timeline li.is-done .h-timeline__dot { background: var(--h-blue); border-color: var(--h-blue); }
.h-timeline li.is-parked .h-timeline__dot { background: var(--h-warning); border-color: var(--h-warning); }
.h-only-phone { display: none; }
@media (max-width: 640px) { .h-only-phone { display: inline-flex; } .h-timeline { flex-direction: column; gap: var(--h-s-3); } }

/* Issues: reactions, combine search, sticky reply on phone (05/09/2026) */
.h-react { display: flex; align-items: center; gap: var(--h-s-1); margin-top: var(--h-s-2); flex-wrap: wrap; }
.h-react__list { display: inline-flex; gap: var(--h-s-1); flex-wrap: wrap; }
.h-react__pill { display: inline-flex; align-items: center; gap: 3px; padding: 1px 8px; border: 1px solid var(--h-grey-10); border-radius: var(--h-radius); background: var(--h-white); font-size: var(--h-fs-xs); color: var(--h-ink); text-decoration: none; line-height: 1.6; }
.h-react__pill.is-mine { border-color: var(--h-cyan); background: var(--h-info-soft); color: var(--h-info-ink); }
.h-react__add { position: relative; }
.h-react__plus { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 22px; border: 1px dashed var(--h-grey-30); border-radius: var(--h-radius); color: var(--h-grey-50); text-decoration: none; font-size: var(--h-fs-sm); line-height: 1; }
.h-react__plus:hover { color: var(--h-blue); border-color: var(--h-blue); }
.h-react__picker { position: absolute; left: 0; top: 100%; margin-top: 4px; display: flex; gap: 2px; padding: 4px; background: var(--h-white); border: 1px solid var(--h-grey-10); border-radius: var(--h-radius); box-shadow: var(--h-shadow); z-index: 3; }
.h-react__picker[hidden] { display: none; }
.h-react__picker a { display: inline-flex; width: 30px; height: 30px; align-items: center; justify-content: center; border-radius: var(--h-radius); text-decoration: none; font-size: 18px; }
.h-react__picker a:hover { background: var(--h-blue-10); }
.h-mention--down { top: calc(100% + 2px); bottom: auto; width: 100%; }
@media (max-width: 768px) {
  .h-cardm__note-form { position: sticky; bottom: 0; background: var(--h-white); padding: var(--h-s-3) 0 var(--h-s-2); margin-top: var(--h-s-3); border-top: 1px solid var(--h-grey-10); z-index: 2; }
}

/* Home v2 (05/09/2026): waiting-for-you, Today strip, external tiles */
.h-waiting { display: flex; flex-wrap: wrap; gap: var(--h-s-2); margin: calc(-1 * var(--h-s-2)) 0 var(--h-s-6); }
.h-waiting__item { display: inline-flex; align-items: center; gap: var(--h-s-2); padding: var(--h-s-2) var(--h-s-4) var(--h-s-2) var(--h-s-2); background: var(--h-white); border: 1px solid var(--h-grey-10); border-radius: var(--h-radius); color: var(--h-blue); font-weight: var(--h-fw-semibold); font-size: var(--h-fs-sm); text-decoration: none; }
.h-waiting__item:hover { border-color: var(--h-blue-20); box-shadow: var(--h-shadow); }
.h-waiting__count { min-width: 22px; height: 22px; padding: 0 6px; border-radius: 50%; background: var(--h-error); color: var(--h-white); font-size: var(--h-fs-xs); font-weight: var(--h-fw-bold); display: inline-flex; align-items: center; justify-content: center; }
.h-today { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--h-s-3); }
.h-today__tile { display: flex; flex-direction: column; gap: 2px; padding: var(--h-s-3) var(--h-s-4); background: var(--h-white); border: 1px solid var(--h-grey-10); border-left: 3px solid var(--h-blue); border-radius: var(--h-radius); text-decoration: none; color: var(--h-ink); min-height: 84px; transition: box-shadow var(--h-duration) var(--h-ease); }
.h-today__tile:hover { box-shadow: var(--h-shadow); }
.h-today__tile--cyan { border-left-color: var(--h-cyan); }
.h-today__tile--warn { border-left-color: var(--h-warning); }
.h-today__label { font-size: var(--h-fs-xs); font-weight: var(--h-fw-semibold); letter-spacing: var(--h-tracking-wide); text-transform: uppercase; color: var(--h-grey-50); }
.h-today__value { font-size: var(--h-fs-xl); font-weight: var(--h-fw-bold); color: var(--h-blue); line-height: 1.15; letter-spacing: var(--h-tracking-tight); }
.h-today__sub { font-size: var(--h-fs-xs); color: var(--h-grey-70); line-height: 1.3; }
.h-launch__ext, .h-sidebar__ext { margin-left: auto; opacity: 0.45; }
.h-launch__ext svg, .h-sidebar__ext svg { width: 13px; height: 13px; }
.h-sidebar__link--ext .h-sidebar__ext { display: inline-flex; }

/* Home: quiet zero tiles, birthday tile, shortcuts (05/09/2026) */
.h-today__tile--quiet { border-left-color: var(--h-grey-30); background: var(--h-paper); }
.h-today__tile--quiet .h-today__value { color: var(--h-grey-50); font-size: var(--h-fs-lg); font-weight: var(--h-fw-semibold); }
.h-today__tile--quiet .h-today__sub { color: var(--h-grey-50); }
.h-today__tile--big { grid-column: span 2; background: var(--h-blue); border-color: var(--h-blue); }
.h-today__tile--big .h-today__label { color: var(--h-cyan); }
.h-today__tile--big .h-today__value { color: var(--h-white); font-size: var(--h-fs-2xl); }
.h-today__tile--big .h-today__sub { color: rgba(255,255,255,0.75); }
.h-launch-grid--shortcuts { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
.h-launch--shortcut { border-color: var(--h-blue-20); background: var(--h-blue-10); }
.h-launch--shortcut .h-launch__logo--icon { background: var(--h-white); }

/* Page-lead headline: brand mixed-weight (Light + Bold on the key word) at a
   page size rather than the 64px hero. 05/09/2026 */
.h-display--page { font-size: var(--h-fs-4xl); margin-bottom: var(--h-s-5); }
.h-display strong { font-weight: var(--h-fw-bold); }
@media (max-width: 640px) { .h-display--page { font-size: var(--h-fs-3xl); } }
.h-home-section__title .h-live-flag { text-transform: none; letter-spacing: 0; font-weight: var(--h-fw-regular); margin-left: var(--h-s-2); }

/* Date calculator bits (05/09/2026) */
.h-calc__check { margin: var(--h-s-4) 0 0; }
.h-calc__alts { margin: var(--h-s-4) 0 var(--h-s-3); }
.h-calc__alt { font-size: var(--h-fs-lg); font-weight: var(--h-fw-semibold); color: var(--h-blue); margin: 0; }
.h-calc__presets { display: flex; flex-wrap: wrap; align-items: center; gap: var(--h-s-2); margin-top: var(--h-s-4); }
.h-calc + .h-calc { margin-top: var(--h-s-4); }

/* ---------- Drop zone (file upload) 05/09/2026 --------------------------- */
.h-drop {
  display: block;
  border: 2px dashed var(--h-border);
  border-radius: var(--h-radius);
  padding: var(--h-s-8) var(--h-s-5);
  text-align: center;
  cursor: pointer;
  transition: border-color var(--h-duration) var(--h-ease), background var(--h-duration) var(--h-ease);
}
.h-drop:hover, .h-drop.is-drag { border-color: var(--h-blue); background: var(--h-grey-10); }
.h-drop input[type="file"] { display: none; }
.h-drop__icon { color: var(--h-grey-50); margin-bottom: var(--h-s-3); }
.h-drop__icon svg { width: 32px; height: 32px; }
.h-drop__title { font-weight: var(--h-fw-semibold); color: var(--h-blue); }
.h-drop__sub { color: var(--h-grey-50); font-size: var(--h-fs-sm); margin-top: var(--h-s-1); }

/* ---------- File list (selected before upload) --------------------------- */
.h-filelist { margin-top: var(--h-s-5); }
.h-filelist:empty { display: none; }
.h-filelist__row {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--h-s-2) 0; border-top: 1px solid var(--h-border);
  font-size: var(--h-fs-sm); color: var(--h-grey-70);
}
.h-filelist__row:first-child { border-top: 0; }
.h-filelist__row a { color: var(--h-grey-50); text-decoration: none; }
.h-filelist__row a:hover { color: var(--h-error); }

/* ---------- Progress bar --------------------------------------------------- */
.h-progress { margin-top: var(--h-s-5); display: none; }
.h-progress.show { display: block; }
.h-progress__label { font-size: var(--h-fs-sm); color: var(--h-grey-50); margin-bottom: var(--h-s-2); }
.h-progress__track { background: var(--h-grey-10); border-radius: var(--h-radius); height: 8px; overflow: hidden; }
.h-progress__bar { background: var(--h-blue); height: 100%; width: 0%; transition: width var(--h-duration) var(--h-ease); border-radius: var(--h-radius); }
.h-progress__bar.is-indeterminate { width: 40%; animation: h-progress-indeterminate 1.1s ease-in-out infinite; }
@keyframes h-progress-indeterminate {
  0%   { margin-left: 0%; }
  50%  { margin-left: 60%; }
  100% { margin-left: 0%; }
}

/* ---------- Result row list (per-item outcome) ---------------------------- */
.h-resultlist__row {
  display: flex; align-items: center; gap: var(--h-s-2); padding: var(--h-s-2) 0;
  border-top: 1px solid var(--h-border); font-size: var(--h-fs-sm);
}
.h-resultlist__row:first-child { border-top: 0; }

/* ---------- Staff Directory (team cards) 05/09/2026 ------------------------ */
.h-team-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--h-s-5);
}
.h-team-card {
  background: var(--h-white);
  border: 1px solid var(--h-border);
  border-radius: var(--h-radius);
  padding: var(--h-s-5);
  transition: box-shadow var(--h-duration) var(--h-ease), transform var(--h-duration) var(--h-ease);
}
.h-team-card:hover { box-shadow: var(--h-shadow-lg); transform: translateY(-2px); }
.h-team-card__top { display: flex; align-items: center; gap: var(--h-s-4); margin-bottom: var(--h-s-4); }
.h-team-card__photo {
  width: 64px; height: 64px; flex: none;
  border-radius: 50%;
  overflow: hidden;
  background: var(--h-blue);
  color: var(--h-white);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--h-fs-xl);
  font-weight: var(--h-fw-bold);
}
.h-team-card__photo img { width: 100%; height: 100%; object-fit: cover; }
.h-team-card__name { margin: 0; font-size: var(--h-fs-lg); font-weight: var(--h-fw-bold); color: var(--h-blue); letter-spacing: var(--h-tracking-tight); line-height: var(--h-lh-tight); }
.h-team-card__role { margin: 2px 0 0; font-size: var(--h-fs-sm); color: var(--h-grey-50); }
.h-team-card__contact { display: flex; flex-direction: column; gap: var(--h-s-2); }
.h-team-card__link {
  display: flex; align-items: center; gap: var(--h-s-2);
  font-size: var(--h-fs-sm); color: var(--h-ink);
  text-decoration: none;
}
.h-team-card__link:hover { color: var(--h-blue); }
.h-team-card__link svg { width: 15px; height: 15px; flex: none; color: var(--h-grey-50); }
.h-team-card__link:hover svg { color: var(--h-blue); }
.h-team-card__tag { margin-left: auto; font-size: var(--h-fs-xs); color: var(--h-grey-50); text-transform: uppercase; letter-spacing: var(--h-tracking-wide); }
.h-team-card__bio { margin: var(--h-s-4) 0 0; padding-top: var(--h-s-4); border-top: 1px solid var(--h-border); font-size: var(--h-fs-sm); color: var(--h-grey-70); line-height: var(--h-lh-base); }

/* Edit mode: same card shell, form fields instead of static text */
.h-team-edit-card { display: flex; gap: var(--h-s-5); align-items: flex-start; }
.h-team-edit-card--archived { opacity: 0.55; }
.h-team-edit-photo { display: flex; flex-direction: column; align-items: center; gap: var(--h-s-2); flex: none; width: 96px; }
.h-team-edit-photo__img { width: 80px; height: 80px; border-radius: 50%; overflow: hidden; background: var(--h-blue); color: var(--h-white); display: flex; align-items: center; justify-content: center; font-size: var(--h-fs-xl); font-weight: var(--h-fw-bold); }
.h-team-edit-photo__img img { width: 100%; height: 100%; object-fit: cover; }
.h-team-edit-fields { display: grid; grid-template-columns: 1fr 1fr; gap: var(--h-s-3) var(--h-s-4); flex: 1; }
.h-team-edit-fields .h-label { display: flex; flex-direction: column; gap: var(--h-s-1); font-size: var(--h-fs-xs); font-weight: var(--h-fw-semibold); color: var(--h-grey-70); }
.h-team-edit-fields--bio, .h-team-edit-fields__actions { grid-column: 1 / -1; }
.h-team-edit-actions { display: flex; flex-direction: column; gap: var(--h-s-2); flex: none; }

/* ---------- Birthday splash -------------------------------------------------
   A once-a-day "moment", deliberately its own family rather than a reuse of
   .h-modal (a white card for editing things). Full-bleed navy scrim, a
   cyan-ringed photo circle, mixed-weight display headline.
   Markup: .h-splash-backdrop > .h-splash > .h-splash__photo, __eyebrow,
   __title (with <strong> for the name), __sub, .h-btn.h-btn-accent. */
.h-splash-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 18, 51, 0.82);
  z-index: var(--h-z-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--h-s-5);
}
.h-splash {
  width: min(440px, 100%);
  background: var(--h-dark-raise);
  border: 1px solid var(--h-dark-line);
  border-radius: var(--h-radius-lg);
  padding: var(--h-s-8) var(--h-s-6) var(--h-s-6);
  text-align: center;
  box-shadow: var(--h-shadow-lg);
}
.h-splash__photo {
  width: 88px;
  height: 88px;
  margin: 0 auto var(--h-s-5);
  border-radius: 50%;
  border: 2px solid var(--h-cyan);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--h-blue);
  color: var(--h-cyan);
}
.h-splash__photo img { width: 100%; height: 100%; object-fit: cover; }
.h-splash__photo svg { width: 40px; height: 40px; }
.h-splash__eyebrow {
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-semibold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  color: var(--h-cyan);
  margin: 0 0 var(--h-s-2);
}
.h-splash__title {
  font-family: var(--h-font-display);
  font-weight: var(--h-fw-light);
  font-size: var(--h-fs-3xl);
  line-height: var(--h-lh-tight);
  letter-spacing: var(--h-tracking-tight);
  color: var(--h-white);
  margin: 0 0 var(--h-s-3);
}
.h-splash__title strong { font-weight: var(--h-fw-bold); color: var(--h-cyan); }
.h-splash__sub {
  font-size: var(--h-fs-base);
  color: var(--h-dark-muted);
  line-height: var(--h-lh-base);
  margin: 0 0 var(--h-s-6);
}
.h-splash__action { min-width: 140px; }
.h-splash__actions { display: flex; gap: var(--h-s-2); justify-content: center; }

/* Quiet 7-day heads-up banner — sits above page content, dismissible for the
   day. Lower key than the splash: paper background, cyan rule, no scrim. */
.h-bday-banner {
  display: flex;
  align-items: center;
  gap: var(--h-s-3);
  padding: var(--h-s-3) var(--h-s-8);
  background: var(--h-info-soft);
  border-bottom: 1px solid var(--h-grey-10);
  border-left: 3px solid var(--h-cyan);
  font-size: var(--h-fs-sm);
  color: var(--h-ink);
}
.h-bday-banner svg { width: 18px; height: 18px; flex: none; color: var(--h-blue); }
.h-bday-banner strong { font-weight: var(--h-fw-bold); }
.h-bday-banner__dismiss {
  margin-left: auto;
  border: 0;
  background: transparent;
  cursor: pointer;
  color: var(--h-grey-50);
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--h-radius);
}
.h-bday-banner__dismiss:hover { background: var(--h-grey-10); color: var(--h-charcoal); }

/* Ghost button on the dark splash card needs its own contrast — the global
   .h-btn-ghost is navy text for light surfaces and disappears on navy. */
.h-splash .h-btn-ghost,
.h-splash .h-btn--ghost {
  color: var(--h-dark-muted);
  border-color: var(--h-dark-line);
}
.h-splash .h-btn-ghost:hover,
.h-splash .h-btn--ghost:hover {
  background: rgba(255, 255, 255, 0.08);
  color: var(--h-white);
}

/* Cake icon inline with the recipient name on the public birthday wall. */
.h-feed__to svg { width: 14px; height: 14px; vertical-align: -2px; margin-right: 4px; color: var(--h-cyan); }

/* ---------- Meeting Room ----------------------------------------------------
   Free/busy hero panel + a week of grouped bookings. Reuses .h-badge for the
   "Now" tag rather than a bespoke one. */
.h-mr-status {
  border-radius: var(--h-radius-lg);
  padding: var(--h-s-6) var(--h-s-6) var(--h-s-5);
  color: var(--h-white);
  margin-bottom: var(--h-s-6);
}
.h-mr-status--free { background: var(--h-success); }
.h-mr-status--busy { background: var(--h-error); }
.h-mr-status__label {
  display: flex;
  align-items: center;
  gap: var(--h-s-2);
  font-size: var(--h-fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--h-tracking-wide);
  opacity: 0.85;
  margin: 0 0 var(--h-s-2);
}
.h-mr-status__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--h-white); box-shadow: 0 0 0 4px rgba(255,255,255,0.25); }
.h-mr-status__headline { font-size: var(--h-fs-2xl); font-weight: var(--h-fw-bold); margin: 0 0 var(--h-s-1); line-height: var(--h-lh-tight); }
.h-mr-status__detail { font-size: var(--h-fs-base); opacity: 0.95; margin: 0; }

.h-mr-day { margin-bottom: var(--h-s-5); }
.h-mr-day__title { font-size: var(--h-fs-xs); text-transform: uppercase; letter-spacing: var(--h-tracking-wide); color: var(--h-grey-50); font-weight: var(--h-fw-semibold); margin: 0 0 var(--h-s-2); }
.h-mr-events { border: var(--h-border); border-radius: var(--h-radius); overflow: hidden; background: var(--h-white); }
.h-mr-event { display: flex; align-items: center; gap: var(--h-s-3); padding: var(--h-s-3) var(--h-s-4); border-bottom: 1px solid var(--h-grey-10); }
.h-mr-event:last-child { border-bottom: none; }
.h-mr-event--now { background: var(--h-error-soft); }
.h-mr-event__time { flex: 0 0 130px; font-variant-numeric: tabular-nums; color: var(--h-blue); font-size: var(--h-fs-sm); font-weight: var(--h-fw-semibold); }
.h-mr-event__summary { flex: 1; color: var(--h-grey-70); font-size: var(--h-fs-sm); }

/* Trailing de-emphasised note inside a bold .h-label, e.g. "— optional". */
.h-label__note { font-weight: var(--h-fw-regular); }
/* Chrome's date field is 2px taller than a text field with the same padding,
   which is enough to break a row of inputs. Pin the line box and they match. */
.h-input[type="date"], .h-input[type="time"], .h-input[type="month"] { line-height: 1; }


/* Narrow a standalone .h-input that would otherwise stretch full-width
   inside a wide card (a date field sitting on its own, not in a grid). */
.h-input--narrow { max-width: 220px; }

/* ---------- Leave -----------------------------------------------------------
   Request form, this-year chips, the team month grid and the timeline.
   Encoding shared by grid + timeline + legend: cyan = annual/LSL/neutral
   leave, amber = sick, navy = leader away, mid-grey dashed = pending. */
.h-lv-form { padding: var(--h-s-6); margin-bottom: var(--h-s-6); }
.h-lv-form:hover { transform: none; box-shadow: var(--h-shadow); }
.h-lv-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--h-s-4); }
.h-lv-grid .h-label { display: flex; flex-direction: column; gap: var(--h-s-1); margin: 0; }
.h-lv-grid--full { grid-column: 1 / -1; }
.h-lv-grid--3 { grid-template-columns: 1fr 1fr 1fr; }
.h-lv-calc { display: flex; flex-wrap: wrap; gap: var(--h-s-3); margin-top: var(--h-s-4); }
.h-lv-calc__item { flex: 1 1 140px; background: var(--h-paper); border-radius: var(--h-radius); padding: var(--h-s-3) var(--h-s-4); }
.h-lv-calc__label { display: block; font-size: var(--h-fs-xs); text-transform: uppercase; letter-spacing: var(--h-tracking-wide); color: var(--h-grey-50); }
.h-lv-calc__value { display: block; font-size: var(--h-fs-xl); font-weight: var(--h-fw-bold); color: var(--h-blue); line-height: var(--h-lh-tight); margin-top: 2px; }
.h-lv-calc__sub { display: block; font-size: var(--h-fs-xs); color: var(--h-grey-50); margin-top: 2px; }
.h-lv-form .h-notice { margin-top: var(--h-s-4); }
.h-lv-form .h-notice[hidden], .h-lv-calc[hidden] { display: none; }

.h-lv-year { display: flex; flex-wrap: wrap; gap: var(--h-s-2); margin: var(--h-s-2) 0 var(--h-s-5); }
.h-lv-year__chip { background: var(--h-white); border: var(--h-border); border-radius: var(--h-radius); padding: var(--h-s-2) var(--h-s-3); font-size: var(--h-fs-sm); color: var(--h-grey-70); }
.h-lv-year__chip strong { color: var(--h-blue); }

.h-lv-tablewrap { overflow-x: auto; border: var(--h-border); border-radius: var(--h-radius); background: var(--h-white); }
.h-lv-tablewrap .h-table th { white-space: nowrap; }
.h-lv-notes { color: var(--h-grey-50); font-size: var(--h-fs-xs); max-width: 260px; }
.h-lv-actions { white-space: nowrap; text-align: right; }
.h-lv-actions form { margin: 0; display: inline-flex; gap: var(--h-s-2); align-items: center; vertical-align: middle; }
.h-lv-actions form + form { margin-left: var(--h-s-2); }
.h-lv-days-input { width: 64px; text-align: center; padding: var(--h-s-2); font-size: var(--h-fs-sm); }
.h-lv-reason { width: 180px; padding: var(--h-s-2) var(--h-s-3); font-size: var(--h-fs-sm); }
.h-lv-coverage { display: flex; flex-wrap: wrap; gap: 3px; max-width: 260px; }
.h-lv-coverage .h-badge { cursor: default; }

.h-lv-sectionhead { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--h-s-4); flex-wrap: wrap; margin-bottom: var(--h-s-3); }

/* Month grid */
.h-cal__head { display: flex; align-items: center; gap: var(--h-s-2); margin-bottom: var(--h-s-3); }
.h-cal__title { font-size: var(--h-fs-lg); font-weight: var(--h-fw-bold); color: var(--h-blue); margin: 0 var(--h-s-2); min-width: 170px; text-align: center; }
.h-cal__legend { display: flex; flex-wrap: wrap; gap: var(--h-s-4); font-size: var(--h-fs-xs); color: var(--h-grey-50); margin-bottom: var(--h-s-3); }
.h-cal__leg { display: inline-flex; align-items: center; gap: 5px; }
.h-cal__swatch { width: 12px; height: 12px; border-radius: var(--h-radius-sm); display: inline-block; }
.h-cal__swatch--annual, .h-cal__swatch--leave { background: var(--h-cyan); }
.h-cal__swatch--sick { background: var(--h-warning); }
.h-cal__swatch--away { background: var(--h-blue); }
.h-cal__swatch--rdo { background: var(--h-success); }
.h-cal__swatch--pending { background: var(--h-grey-30); outline: 1px dashed var(--h-grey-50); outline-offset: -1px; }
.h-cal__swatch--ph { background: var(--h-blue-10); border: 1px solid var(--h-blue-20); }
.h-cal__grid { display: grid; grid-template-columns: repeat(7, 1fr); background: var(--h-white); border: var(--h-border); border-radius: var(--h-radius); overflow: hidden; }
.h-cal__dow { background: var(--h-blue-10); color: var(--h-blue); font-size: var(--h-fs-xs); font-weight: var(--h-fw-bold); text-transform: uppercase; letter-spacing: var(--h-tracking-wide); padding: var(--h-s-2); text-align: center; border-bottom: var(--h-border); }
.h-cal__day { min-height: 92px; padding: var(--h-s-1) var(--h-s-1) var(--h-s-1); border-right: 1px solid var(--h-grey-10); border-bottom: 1px solid var(--h-grey-10); display: flex; flex-direction: column; gap: 2px; position: relative; }
.h-cal__day:nth-child(7n) { border-right: 0; }
.h-cal__day--other { background: var(--h-paper); }
.h-cal__day--other .h-cal__num { color: var(--h-grey-30); }
.h-cal__day--weekend { background: var(--h-paper); }
.h-cal__day--ph { background: var(--h-blue-10); }
.h-cal__day--today { box-shadow: inset 0 0 0 2px var(--h-cyan); }
.h-cal__num { font-size: var(--h-fs-xs); font-weight: var(--h-fw-bold); color: var(--h-ink); padding: 1px 4px; align-self: flex-start; }
.h-cal__day--today .h-cal__num { background: var(--h-cyan); color: var(--h-white); border-radius: var(--h-radius-sm); }
.h-cal__ph { position: absolute; top: 4px; right: 4px; font-size: 9px; font-weight: var(--h-fw-bold); letter-spacing: var(--h-tracking-wide); color: var(--h-info-ink); text-transform: uppercase; }
.h-cal__chip { display: flex; align-items: center; justify-content: center; gap: 4px; font-size: 11px; line-height: 1.2; color: var(--h-white); padding: 2px 5px; border-radius: var(--h-radius-sm); white-space: nowrap; overflow: hidden; cursor: default; }
.h-cal__chip > span { overflow: hidden; text-overflow: ellipsis; }
.h-cal__chip img, .h-cal__chip i { width: 16px; height: 16px; border-radius: 50%; object-fit: cover; flex: none; }
.h-cal__chip i { display: inline-flex; align-items: center; justify-content: center; background: var(--h-blue); color: var(--h-white); font-style: normal; font-size: 7px; font-weight: var(--h-fw-bold); }
.h-cal__chip--pending i { background: var(--h-blue); }
.h-cal__chip--annual, .h-cal__chip--long_service, .h-cal__chip--leave { background: var(--h-cyan); }
.h-cal__chip--sick { background: var(--h-warning); color: var(--h-charcoal); }
.h-cal__chip--away { background: var(--h-blue); }
/* RDO is not leave — green reads as "rostered", not as an absence being spent. */
.h-cal__chip--rdo { background: var(--h-success); }
.h-cal__chip--pending { background: var(--h-grey-30); color: var(--h-blue); outline: 1px dashed rgba(0, 31, 73, .4); outline-offset: -1px; }
.h-cal__more { font-size: 11px; color: var(--h-grey-50); padding-left: 4px; }
.h-cal__note { font-size: var(--h-fs-sm); color: var(--h-blue); font-weight: var(--h-fw-semibold); margin: 0 0 var(--h-s-3); }
.h-cal__note[hidden] { display: none; }
.h-cal__day--focus { background: var(--h-blue-10); box-shadow: inset 0 0 0 2px var(--h-blue); }
.h-cal__chip--focus { box-shadow: 0 0 0 2px var(--h-white), 0 0 0 4px var(--h-blue); }
/* Click a day to see EVERYONE off that day — the grid shows four chips and
   "+N more", and a hover title is no use on a phone. The open day is outlined
   in cyan (today's outline colour is the same; today's date pill tells them
   apart) and the list renders in .h-cal__detail under the grid. */
.h-cal__day--has { cursor: pointer; }
.h-cal__day--has:hover { background: var(--h-blue-10); }
.h-cal__day--open { box-shadow: inset 0 0 0 2px var(--h-cyan); background: var(--h-blue-10); }
.h-cal__more { cursor: pointer; text-decoration: underline dotted; }
.h-cal__detail { margin-top: var(--h-s-3); background: var(--h-white); border: var(--h-border); border-left: 3px solid var(--h-cyan); border-radius: var(--h-radius); padding: var(--h-s-3) var(--h-s-4); }
.h-cal__detail[hidden] { display: none; }
.h-cal__detail-head { display: flex; justify-content: space-between; align-items: center; gap: var(--h-s-3); margin-bottom: var(--h-s-2); font-weight: var(--h-fw-bold); color: var(--h-blue); }
.h-cal__detail-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--h-s-2); }
.h-cal__detail-row { display: flex; align-items: center; gap: var(--h-s-2); font-size: var(--h-fs-sm); color: var(--h-ink); }
.h-cal__detail-row img, .h-cal__detail-row i { width: 22px; height: 22px; border-radius: 50%; object-fit: cover; flex: none; }
.h-cal__detail-row i { display: inline-flex; align-items: center; justify-content: center; background: var(--h-blue); color: var(--h-white); font-style: normal; font-size: 9px; font-weight: var(--h-fw-bold); }
.h-cal__detail-row .h-cal__swatch { flex: none; }
.h-cal__detail-row small { color: var(--h-grey-50); }
@media (max-width: 768px) { .h-cal__day { min-height: 64px; } .h-cal__chip { font-size: 10px; padding: 2px 3px; } .h-cal__chip img, .h-cal__chip i { width: 14px; height: 14px; } }

/* Timeline (next 6 months) */
.h-tl { background: var(--h-white); border: var(--h-border); border-radius: var(--h-radius); padding: var(--h-s-4); overflow-x: auto; }
.h-tl__axis { position: relative; height: 18px; min-width: 760px; border-bottom: var(--h-border); margin-bottom: var(--h-s-2); }
.h-tl__month { position: absolute; top: 0; transform: translateX(-50%); font-size: var(--h-fs-xs); color: var(--h-grey-50); white-space: nowrap; }
.h-tl__row { display: flex; align-items: center; gap: var(--h-s-3); margin: var(--h-s-1) 0; min-width: 760px; }
.h-tl__name { width: 120px; flex: none; font-size: var(--h-fs-sm); font-weight: var(--h-fw-semibold); color: var(--h-blue); }
.h-tl__track { flex: 1; height: 22px; position: relative; background: var(--h-paper); border-radius: var(--h-radius-sm); }
.h-tl__bar { position: absolute; top: 0; bottom: 0; border-radius: var(--h-radius-sm); font-size: 11px; color: var(--h-white); padding: 0 6px; display: flex; align-items: center; white-space: nowrap; overflow: hidden; }
.h-tl__bar--annual, .h-tl__bar--long_service, .h-tl__bar--leave { background: var(--h-cyan); }
.h-tl__bar--sick { background: var(--h-warning); color: var(--h-charcoal); }
.h-tl__bar--away { background: var(--h-blue); }
.h-tl__bar--rdo { background: var(--h-success); }
.h-tl__bar--pending { opacity: .6; outline: 1px dashed rgba(0, 31, 73, .5); outline-offset: -1px; }
.h-tl__today { position: absolute; top: 0; bottom: 0; width: 2px; background: var(--h-error); pointer-events: none; }
.h-lv-view[hidden] { display: none; }

/* Working days (patterns) */
/* SUPERSEDED by .h-checkbox on 14/09/2026 (cyan tick, 22px box); kept and
   unchanged for the leave pages that already ship it. Do not use in new work. */
.h-wd-check { display: inline-flex; cursor: pointer; margin: 0; }
.h-wd-check input { position: absolute; opacity: 0; width: 0; height: 0; }
.h-wd-box { width: 22px; height: 22px; border: 1.5px solid var(--h-grey-30); border-radius: var(--h-radius); display: inline-block; position: relative; transition: all var(--h-duration) var(--h-ease); }
.h-wd-check input:checked + .h-wd-box { background: var(--h-cyan); border-color: var(--h-cyan); }
.h-wd-check input:checked + .h-wd-box::after { content: ""; position: absolute; left: 7px; top: 3px; width: 5px; height: 10px; border: solid var(--h-white); border-width: 0 2px 2px 0; transform: rotate(45deg); }
.h-wd-check input:focus-visible + .h-wd-box { box-shadow: var(--h-focus-glow); }
.h-wd-col { text-align: center; width: 56px; }
@media (max-width: 640px) { .h-lv-grid, .h-lv-grid--3 { grid-template-columns: 1fr; } }

/* Pending leave request card (approvals page) */
.h-lv-req { display: flex; gap: var(--h-s-5); align-items: flex-start; padding: var(--h-s-5); margin-bottom: var(--h-s-3); }
.h-lv-req:hover { transform: none; box-shadow: var(--h-shadow); }
.h-lv-req__main { flex: 1; min-width: 0; }
.h-lv-req__name { margin: 0; font-size: var(--h-fs-lg); font-weight: var(--h-fw-bold); color: var(--h-blue); }
.h-lv-req__meta { margin: 2px 0 var(--h-s-1); font-size: var(--h-fs-sm); color: var(--h-grey-70); }
.h-lv-req .h-lv-coverage { margin-top: var(--h-s-2); max-width: none; }
.h-lv-req__notes { margin-top: var(--h-s-3); background: var(--h-paper); border-left: 3px solid var(--h-cyan); border-radius: var(--h-radius); padding: var(--h-s-3) var(--h-s-4); font-size: var(--h-fs-sm); color: var(--h-grey-70); line-height: var(--h-lh-base); white-space: pre-wrap; }
.h-lv-req__actions { display: flex; flex-direction: column; gap: var(--h-s-2); flex: none; align-items: flex-end; }
.h-lv-req__actions form { display: inline-flex; gap: var(--h-s-2); align-items: center; margin: 0; }
.h-lv-req__days { display: inline-flex; align-items: center; gap: var(--h-s-2); font-size: var(--h-fs-xs); color: var(--h-grey-50); }
@media (max-width: 768px) { .h-lv-req { flex-direction: column; } .h-lv-req__actions { align-items: stretch; } }

/* Studio sign-in card: the official Harcourts Studio lockup, one line, one button. */
.h-login-card__lockup { display: block; height: 40px; width: auto; margin: var(--h-s-2) auto var(--h-s-5); }

/* Users page: one column grid shared by every department table, so the
   toggles line up down the whole page. */
.h-table--users { table-layout: fixed; }
.h-table--users th { white-space: nowrap; }
.h-table--users__name { width: 27%; }
.h-table--users__dept { width: 20%; }
.h-table--users__act { width: 12%; }
.h-table--users td:nth-child(6) { white-space: nowrap; }
.h-table--users .h-select { width: 100%; }
.h-table--users td:last-child { text-align: right; }
.h-table--users td:last-child form { display: inline; }
.h-table--users .h-user-cell__sub { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---------- Marketing Budget ------------------------------------------------
   A ledger page where the loudest thing is the deadline, not the balance:
   under use-it-or-lose-it the date is what costs money. */
.h-mk-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--h-s-4); margin-bottom: var(--h-s-5); align-items: start; }
.h-mk-grid--2 { grid-template-columns: 1fr 1fr; }
.h-mk-col { display: flex; flex-direction: column; gap: var(--h-s-4); }
.h-mk-form { margin-bottom: var(--h-s-5); }
.h-mk-agent .h-stat__label { margin-bottom: var(--h-s-3); }
.h-mk-agent .h-mk-table { margin-top: var(--h-s-4); }
.h-mk-rules { margin: 0; padding-left: var(--h-s-4); }
.h-mk-cats { margin-top: 0; }
@media (max-width: 900px) { .h-mk-grid--2 { grid-template-columns: 1fr; } }
.h-mk-agent { padding: var(--h-s-5); }
.h-mk-agent:hover { transform: none; box-shadow: var(--h-shadow); }
.h-mk-agent__head { display: flex; align-items: center; gap: var(--h-s-3); margin-bottom: var(--h-s-4); }
.h-mk-agent__photo { width: 40px; height: 40px; border-radius: 50%; overflow: hidden; background: var(--h-blue); color: var(--h-white); display: flex; align-items: center; justify-content: center; font-weight: var(--h-fw-bold); font-size: var(--h-fs-sm); flex: none; }
.h-mk-agent__photo img { width: 100%; height: 100%; object-fit: cover; }
.h-mk-agent__name { margin: 0; font-size: var(--h-fs-lg); font-weight: var(--h-fw-bold); color: var(--h-blue); }
.h-mk-agent__sub { margin: 0; font-size: var(--h-fs-xs); color: var(--h-grey-50); }
.h-mk-balance { display: flex; align-items: baseline; gap: var(--h-s-3); flex-wrap: wrap; }
.h-mk-balance__amt { font-size: var(--h-fs-4xl); font-weight: var(--h-fw-bold); color: var(--h-blue); line-height: 1; letter-spacing: var(--h-tracking-tight); font-variant-numeric: tabular-nums; }
.h-mk-balance__sub { font-size: var(--h-fs-sm); color: var(--h-grey-50); }
.h-mk-deadline { margin-top: var(--h-s-4); border-left: 3px solid var(--h-cyan); background: var(--h-paper); border-radius: var(--h-radius); padding: var(--h-s-3) var(--h-s-4); }
.h-mk-deadline--soon { border-left-color: var(--h-warning); background: var(--h-warning-soft); }
.h-mk-deadline--none { border-left-color: var(--h-grey-30); }
.h-mk-deadline__lead { font-size: var(--h-fs-lg); font-weight: var(--h-fw-bold); color: var(--h-blue); letter-spacing: var(--h-tracking-tight); }
.h-mk-deadline--none .h-mk-deadline__lead { font-size: var(--h-fs-base); font-weight: var(--h-fw-regular); color: var(--h-grey-70); }
.h-mk-deadline__note { font-size: var(--h-fs-xs); color: var(--h-grey-70); margin-top: 2px; }
.h-mk-table { width: 100%; border-collapse: collapse; margin-top: var(--h-s-3); font-size: var(--h-fs-sm); }
.h-mk-table th, .h-mk-table td { text-align: left; padding: var(--h-s-2) var(--h-s-3); border-bottom: 1px solid var(--h-grey-10); vertical-align: top; }
.h-mk-table th { font-size: var(--h-fs-xs); font-weight: var(--h-fw-semibold); color: var(--h-grey-50); text-transform: uppercase; letter-spacing: var(--h-tracking-wide); background: var(--h-paper); }
.h-mk-table .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.h-mk-table tr:last-child td { border-bottom: 0; }
.h-mk-table tr.is-warn td { background: var(--h-warning-soft); }
.h-mk-table tr.is-open td { background: var(--h-info-soft); }   /* opened ahead of the day, nothing in it yet — never the same as held-and-empty */
.h-mk-table .amt-credit { color: var(--h-success-ink); font-weight: var(--h-fw-semibold); }
.h-mk-table .amt-debit { color: var(--h-error-ink); font-weight: var(--h-fw-semibold); }
.h-mk-table .empty td { text-align: center; color: var(--h-grey-50); padding: var(--h-s-5); }
.h-mk-scroll { overflow-x: auto; }
.h-mk-nowrap { white-space: nowrap; font-variant-numeric: tabular-nums; }
.h-mk-days { display: block; font-size: var(--h-fs-xs); color: var(--h-grey-50); }
.h-mk-days--warn { color: var(--h-warning-ink); font-weight: var(--h-fw-semibold); }
.h-mk-file { display: inline-flex; align-items: center; gap: 4px; font-size: var(--h-fs-xs); color: var(--h-info-ink); text-decoration: none; margin-right: var(--h-s-2); }
.h-mk-file svg { width: 12px; height: 12px; }
.h-mk-cats { list-style: none; margin: var(--h-s-3) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--h-s-2); }
.h-mk-cat { display: grid; grid-template-columns: 1fr auto; gap: var(--h-s-3); font-size: var(--h-fs-sm); align-items: center; }
.h-mk-cat__bar { grid-column: 1 / -1; height: 6px; background: var(--h-grey-10); border-radius: var(--h-radius-sm); overflow: hidden; }
.h-mk-cat__fill { height: 100%; background: var(--h-cyan); }
.h-mk-cat__amt { font-variant-numeric: tabular-nums; font-weight: var(--h-fw-semibold); color: var(--h-blue); }
.h-mk-form { padding: var(--h-s-6); margin-bottom: var(--h-s-5); }
.h-mk-form:hover { transform: none; box-shadow: var(--h-shadow); }
.h-mk-form__grid { display: grid; grid-template-columns: 140px 1fr 150px 170px; gap: var(--h-s-4); }
.h-mk-form__grid .h-label { display: flex; flex-direction: column; gap: var(--h-s-1); margin: 0; }
.h-mk-form__grid--full { grid-column: 1 / -1; }
.h-mk-form__grid--two { grid-column: span 2; }
.h-mk-form__grid input[type="file"] { font-size: var(--h-fs-sm); }
.h-mk-details { margin-top: var(--h-s-5); border-top: var(--h-border); padding-top: var(--h-s-4); }
.h-mk-details summary { cursor: pointer; font-weight: var(--h-fw-semibold); color: var(--h-blue); font-size: var(--h-fs-sm); }
.h-mk-details[open] summary { margin-bottom: var(--h-s-3); }
.h-mk-rules { max-width: 70ch; }
.h-mk-rules li { margin-bottom: var(--h-s-1); }
@media (max-width: 900px) { .h-mk-form__grid { grid-template-columns: 1fr 1fr; } .h-mk-form__grid--two { grid-column: 1 / -1; } }
@media (max-width: 640px) { .h-mk-form__grid { grid-template-columns: 1fr; } .h-mk-balance__amt { font-size: var(--h-fs-3xl); } }

/* ---------- PM Referrals ----------------------------------------------------
   Two-step form: find the property in Rex, then the details. Step 2 sits
   dimmed until a property is picked (or manual entry is chosen). */
.h-rf-form { padding: var(--h-s-6); margin-bottom: var(--h-s-6); }
.h-rf-form:hover { transform: none; box-shadow: var(--h-shadow); }
.h-rf-step { display: flex; gap: var(--h-s-3); align-items: flex-start; margin-bottom: var(--h-s-3); }
.h-rf-step--2 { margin-top: var(--h-s-6); }
.h-rf-step__num { flex: none; width: 26px; height: 26px; border-radius: var(--h-radius); background: var(--h-blue); color: var(--h-white); display: flex; align-items: center; justify-content: center; font-size: var(--h-fs-xs); font-weight: var(--h-fw-bold); }
.h-rf-step__title { margin: 0; font-weight: var(--h-fw-bold); color: var(--h-blue); }
.h-rf-step--2, #rf-fields { opacity: .45; pointer-events: none; transition: opacity var(--h-duration) var(--h-ease); }
.h-rf-step--2.is-unlocked, #rf-fields.is-unlocked { opacity: 1; pointer-events: auto; }
.h-rf-search { position: relative; }
.h-rf-results { position: absolute; left: 0; right: 0; top: 100%; z-index: var(--h-z-dropdown); background: var(--h-white); border: var(--h-border-strong); border-top: 0; border-radius: 0 0 var(--h-radius) var(--h-radius); box-shadow: var(--h-shadow); max-height: 260px; overflow: auto; }
.h-rf-results[hidden] { display: none; }
.h-rf-result { padding: var(--h-s-3) var(--h-s-4); font-size: var(--h-fs-sm); cursor: pointer; border-bottom: 1px solid var(--h-grey-10); }
.h-rf-result:last-child { border-bottom: 0; }
.h-rf-result:hover { background: var(--h-blue-10); }
.h-rf-result--empty { color: var(--h-grey-50); cursor: default; }

/* ---------- Dropdown (detached popover menu) -------------------------------
   A small menu that floats just under whatever opened it — a multi-select
   checkbox list, a short action list. DETACHED: its own border and corners,
   a gap above it, unlike .h-rf-results, which grows out of the bottom edge of
   a search input. Hidden until JS adds `is-open` (the system's state
   convention: authored variants are --x, JS state is is-*); [hidden] also
   works for markup that prefers the attribute. The parent must be
   position: relative.
     <div class="h-dropdown is-open">
       <label class="h-dropdown-item"><input type="checkbox"> Erin</label>
     </div>                                                                   */
.h-dropdown {
  display: none;
  position: absolute;
  left: 0;
  top: calc(100% + var(--h-s-1));
  z-index: var(--h-z-dropdown);
  min-width: 160px;
  max-height: 280px;
  overflow-y: auto;
  padding: var(--h-s-1) 0;
  background: var(--h-white);
  border: var(--h-border);
  border-radius: var(--h-radius);
  box-shadow: var(--h-shadow-lg);
}
.h-dropdown.is-open { display: block; }
.h-dropdown[hidden] { display: none; }
.h-dropdown-item {
  display: flex; align-items: center; gap: var(--h-s-2);
  padding: var(--h-s-2) var(--h-s-4);
  font-size: var(--h-fs-sm);
  color: var(--h-ink);
  cursor: pointer;
  user-select: none;
}
.h-dropdown-item:hover { background: var(--h-paper); }
.h-dropdown-item input[type="checkbox"] { cursor: pointer; accent-color: var(--h-blue); }
/* A menu of choices or actions: the items are <button>s, and the chosen one
   (aria-checked, for a menuitemradio) reads as chosen. */
button.h-dropdown-item { width: 100%; border: 0; background: none; text-align: left; font: inherit; color: inherit; }
.h-dropdown-item[aria-checked="true"] { font-weight: var(--h-fw-semibold); color: var(--h-blue); }
.h-rf-status { margin: var(--h-s-2) 0 0; }
.h-rf-status.is-ok { color: var(--h-success-ink); }
.h-rf-status.is-bad { color: var(--h-error-ink); }
.h-rf-manual-cta { display: flex; align-items: center; gap: var(--h-s-3); margin-top: var(--h-s-2); }
.h-rf-manual-cta[hidden] { display: none; }
.h-rf-form .h-notice { margin: var(--h-s-3) 0; }
.h-rf-form .h-notice[hidden] { display: none; }
.h-rf-form .h-notice .h-btn { margin-left: var(--h-s-2); vertical-align: middle; }
.h-rf-form .h-form-card__actions { align-items: center; gap: var(--h-s-3); }
.h-rf-form .h-form-card__actions .h-meta[hidden] { display: none; }

/* ---------- Studio Commissions: workflow shell -------------------------------- */
.h-cm-month { display: flex; align-items: center; gap: var(--h-s-3); flex-wrap: wrap; margin-bottom: var(--h-s-5); }
.h-cm-month .h-select { width: auto; min-width: 200px; }
.h-cm-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--h-s-3); }
.h-cm-step { display: grid; grid-template-columns: 44px 1fr auto; gap: var(--h-s-4); align-items: center; padding: var(--h-s-4) var(--h-s-5); }
.h-cm-step:hover { transform: none; box-shadow: var(--h-shadow); }
.h-cm-step__num { width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; border-radius: var(--h-radius); background: var(--h-blue); color: var(--h-white); font-size: var(--h-fs-lg); font-weight: var(--h-fw-bold); }
.h-cm-step--hub .h-cm-step__num { background: var(--h-grey-10); color: var(--h-grey-70); }
.h-cm-step__title { margin: 0; font-size: var(--h-fs-lg); font-weight: var(--h-fw-bold); color: var(--h-blue); display: flex; align-items: center; gap: var(--h-s-2); flex-wrap: wrap; }
.h-cm-step__desc { margin: 2px 0 0; font-size: var(--h-fs-sm); color: var(--h-grey-70); }
.h-cm-step__count { font-size: var(--h-fs-xs); font-weight: var(--h-fw-semibold); color: var(--h-grey-50); text-transform: uppercase; letter-spacing: var(--h-tracking-wide); margin-top: var(--h-s-1); }
.h-cm-step__count--live { color: var(--h-blue); }
.h-cm-step__act { display: flex; align-items: center; gap: var(--h-s-2); }
.h-cm-step__act svg { width: 14px; height: 14px; }
@media (max-width: 768px) { .h-cm-step { grid-template-columns: 36px 1fr; } .h-cm-step__act { grid-column: 1 / -1; } .h-cm-step__num { width: 36px; height: 36px; font-size: var(--h-fs-base); } }

/* ---------- Studio Commissions: PM Reviews ----------------------------------- */
.h-rv-section { margin-bottom: var(--h-s-6); }
.h-rv-list { display: grid; gap: var(--h-s-3); }
.h-rv { padding: var(--h-s-5); }
.h-rv:hover { transform: none; box-shadow: var(--h-shadow); }
.h-rv--pending { border-left: 4px solid var(--h-cyan); }
.h-rv__head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--h-s-3); flex-wrap: wrap; }
.h-rv__who { margin: 0; font-size: var(--h-fs-lg); font-weight: var(--h-fw-bold); color: var(--h-blue); }
.h-rv__meta { margin: 2px 0 0; font-size: var(--h-fs-sm); color: var(--h-grey-50); display: flex; align-items: center; gap: var(--h-s-2); flex-wrap: wrap; }
.h-rv__stars { display: inline-flex; gap: 1px; color: var(--h-grey-20); }
.h-rv__stars svg { width: 15px; height: 15px; fill: currentColor; stroke: none; }
.h-rv__stars .is-on { color: var(--h-warning); }
.h-rv__text { margin: var(--h-s-3) 0 0; padding: var(--h-s-3) var(--h-s-4); background: var(--h-paper); border-left: 3px solid var(--h-grey-10); border-radius: var(--h-radius); font-size: var(--h-fs-sm); color: var(--h-grey-70); line-height: var(--h-lh-base); white-space: pre-wrap; }
.h-rv__text--empty { font-style: italic; }
.h-rv-name { color: var(--h-blue); font-weight: var(--h-fw-bold); }
.h-rv__note { margin: var(--h-s-2) 0 0; font-size: var(--h-fs-sm); color: var(--h-warning-ink); }
.h-rv__pms { display: flex; flex-wrap: wrap; gap: var(--h-s-2); margin: var(--h-s-4) 0 0; }
.h-rv__pm { display: inline-flex; align-items: center; gap: var(--h-s-2); padding: var(--h-s-2) var(--h-s-3); border: 1px solid var(--h-grey-10); border-radius: var(--h-radius); font-size: var(--h-fs-sm); cursor: pointer; background: var(--h-white); }
.h-rv__pm:hover { border-color: var(--h-blue-20); background: var(--h-blue-10); }
.h-rv__pm input { margin: 0; accent-color: var(--h-blue); }
.h-rv__pm:has(input:checked) { border-color: var(--h-blue); background: var(--h-blue); color: var(--h-white); }
.h-rv__pm img, .h-rv__pm i { width: 20px; height: 20px; border-radius: var(--h-radius-pill); object-fit: cover; display: inline-flex; align-items: center; justify-content: center; background: var(--h-blue-10); color: var(--h-blue); font-size: 10px; font-weight: var(--h-fw-bold); font-style: normal; }
.h-rv__pm:has(input:checked) i { background: rgba(255,255,255,0.2); color: var(--h-white); }
.h-rv__row { display: flex; align-items: center; gap: var(--h-s-3); flex-wrap: wrap; margin-top: var(--h-s-4); }
.h-rv__row .h-select { width: auto; }
.h-rv__row form { display: inline-flex; align-items: center; gap: var(--h-s-2); margin: 0; }
.h-rv__row .h-meta { margin: 0; }
.h-rv__pay { display: inline-flex; align-items: baseline; gap: var(--h-s-1); font-variant-numeric: tabular-nums; }
.h-rv__pay strong { color: var(--h-blue); }
.h-rv__paid-to { display: inline-flex; gap: var(--h-s-1); flex-wrap: wrap; }
.h-rv__lock { display: inline-flex; align-items: center; gap: var(--h-s-1); }
.h-rv__lock svg { width: 13px; height: 13px; }
.h-rv-picker { display: flex; align-items: center; gap: var(--h-s-3); flex-wrap: wrap; margin-bottom: var(--h-s-5); }
.h-rv-picker .h-select { width: auto; min-width: 200px; }

/* ---------- Studio Commissions: PM Referrals ledger -------------------------- */
.h-lg-section { margin-bottom: var(--h-s-6); }
.h-lg-group { margin-bottom: var(--h-s-4); }
.h-lg-group__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--h-s-3); padding: var(--h-s-2) 0; border-bottom: 2px solid var(--h-blue); margin-bottom: var(--h-s-2); }
.h-lg-group__title { margin: 0; font-size: var(--h-fs-base); font-weight: var(--h-fw-bold); color: var(--h-blue); display: flex; align-items: center; gap: var(--h-s-2); }
.h-lg-group__total { font-variant-numeric: tabular-nums; font-weight: var(--h-fw-bold); color: var(--h-blue); }
.h-lg-group__total small { font-weight: var(--h-fw-regular); color: var(--h-grey-50); margin-left: var(--h-s-2); }
.h-lg-chase { border-top: 1px dashed var(--h-grey-10); margin-top: var(--h-s-3); padding-top: var(--h-s-3); }
.h-lg-chase__note { max-width: 320px; }
.h-lg-chase__fail { color: var(--h-warning-ink); font-weight: var(--h-fw-semibold); }
/* Sales sign-off and PM sign-off are the same table twice, so they use one
   fixed column set: whatever the names are, Payable, Status, Sent, Opened,
   Signed and Payroll told sit on the same x in both. */
.h-cm-table { table-layout: fixed; }
/* Badges and the Open button set the row height, so plain text — the name, the
   figure, the dashes — sat at the top of a 53px row while the badges beside it
   looked centred. Everything centres against the row. */
.h-cm-table td { vertical-align: middle; }
.h-cm-col-amt { width: 110px; }
.h-cm-col-status { width: 190px; }
.h-cm-col-date { width: 130px; }
.h-cm-col-open { width: 84px; }
.h-cm-table td:first-child, .h-cm-table th:first-child { overflow: hidden; text-overflow: ellipsis; }
.h-cm-live { color: var(--h-grey-50); font-variant-numeric: tabular-nums; }
.h-cm-open .h-meta { font-size: var(--h-fs-xs); }
/* Past statement months and the Closed list fold away — the page opens on what's live. */
.h-lg-fold > summary { list-style: none; cursor: pointer; }
.h-lg-fold > summary::-webkit-details-marker { display: none; }
.h-lg-fold > summary:hover .h-lg-group__title, .h-lg-fold > summary:hover .h-home-section__title { color: var(--h-blue-80); }
.h-lg-fold > summary.h-lv-sectionhead { display: flex; }
.h-lg-fold > summary .h-lg-group__title svg:first-child,
.h-lg-fold > summary .h-home-section__title svg:first-child { width: 16px; height: 16px; color: var(--h-grey-50); transition: transform .15s; margin-right: var(--h-s-2); vertical-align: -3px; }
.h-lg-fold[open] > summary .h-lg-group__title svg:first-child,
.h-lg-fold[open] > summary .h-home-section__title svg:first-child { transform: rotate(180deg); }
.h-lg-list { display: grid; gap: var(--h-s-2); }
.h-lg-row { border: 1px solid var(--h-grey-10); border-radius: var(--h-radius); background: var(--h-white); }
.h-lg-row--ready { border-left: 4px solid var(--h-cyan); }
.h-lg-row--warn { border-left: 4px solid var(--h-warning); }
.h-lg-row > summary { list-style: none; cursor: pointer; display: grid; grid-template-columns: minmax(0, 1fr) 100px minmax(120px, auto) 110px 24px; gap: var(--h-s-3); align-items: center; padding: var(--h-s-3) var(--h-s-4); }
.h-lg-row > summary > div:first-child { min-width: 0; }
.h-badge svg, .h-lg-group__title svg { width: 12px; height: 12px; vertical-align: -2px; margin-right: 2px; }
.h-lg-row > summary::-webkit-details-marker { display: none; }
.h-lg-row > summary:hover { background: var(--h-paper); }
.h-lg-row__addr { margin: 0; font-weight: var(--h-fw-bold); color: var(--h-blue); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-rf-addr { color: var(--h-blue); text-decoration: none; display: inline-flex; align-items: baseline; gap: 5px; }
.h-rf-addr:hover { color: var(--h-blue-80); text-decoration: underline; }
.h-rf-addr svg { width: 11px; height: 11px; color: var(--h-grey-50); align-self: center; }
.h-lg-row__addr a { color: inherit; text-decoration: none; }
.h-lg-row__addr a:hover { color: var(--h-blue-80); text-decoration: underline; }
.h-lg-row__sub { margin: 1px 0 0; font-size: var(--h-fs-xs); color: var(--h-grey-50); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-lg-row__cell { font-size: var(--h-fs-sm); color: var(--h-grey-70); font-variant-numeric: tabular-nums; white-space: nowrap; }
.h-lg-row__cell strong { color: var(--h-blue); }
.h-lg-row__cell--r { text-align: right; }
.h-lg-row__chev { width: 18px; height: 18px; color: var(--h-grey-50); transition: transform .15s; justify-self: end; }
.h-lg-row[open] > summary .h-lg-row__chev { transform: rotate(180deg); }
.h-lg-row__body { border-top: 1px solid var(--h-grey-10); padding: var(--h-s-4); background: var(--h-paper); }
.h-lg-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--h-s-3) var(--h-s-4); }
.h-lg-grid .h-label { margin: 0; }
.h-lg-grid--full { grid-column: 1 / -1; }
.h-lg-actions { display: flex; align-items: center; justify-content: space-between; gap: var(--h-s-3); flex-wrap: wrap; margin-top: var(--h-s-4); }
.h-lg-actions__left, .h-lg-actions__right { display: flex; align-items: center; gap: var(--h-s-2); flex-wrap: wrap; }
.h-lg-actions form { display: inline-flex; align-items: center; gap: var(--h-s-2); margin: 0; }
.h-lg-actions .h-select { width: auto; }
.h-lg-rex { display: inline-flex; align-items: center; gap: var(--h-s-1); font-size: var(--h-fs-sm); }
.h-lg-rex svg { width: 12px; height: 12px; }
.h-lg-link { position: relative; }
.h-lg-link .h-rf-results { top: 100%; }
.h-lg-tags { display: inline-flex; gap: var(--h-s-1); flex-wrap: wrap; }
.h-lg-empty { padding: var(--h-s-5); text-align: center; color: var(--h-grey-50); font-size: var(--h-fs-sm); border: 1px dashed var(--h-grey-10); border-radius: var(--h-radius); }
.h-lg-notes { white-space: pre-wrap; }
@media (max-width: 900px) {
  .h-lg-row > summary { grid-template-columns: minmax(0, 1fr) 90px 24px; }
  .h-lg-row__cell--hide { display: none; }
  .h-lg-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 640px) { .h-lg-grid { grid-template-columns: 1fr; } }

/* ---------- Studio Commissions: Staff Deductions ----------------------------- */
.h-dd-grid { display: grid; grid-template-columns: 3fr 2fr; gap: var(--h-s-4); margin-bottom: var(--h-s-6); align-items: start; }
.h-dd-card { padding: var(--h-s-5); }
.h-dd-card:hover { transform: none; box-shadow: var(--h-shadow); }
.h-dd-card > .h-meta { margin: 0 0 var(--h-s-4); }
.h-dd-fields { margin-bottom: var(--h-s-3); }
.h-dd-grouphead { margin: var(--h-s-4) 0 var(--h-s-2); font-size: var(--h-fs-xs); font-weight: var(--h-fw-semibold); letter-spacing: var(--h-tracking-wide); text-transform: uppercase; color: var(--h-grey-50); }
.h-dd-people { margin-top: 0; }
.h-rv__pm.is-locked { opacity: .5; cursor: not-allowed; }
.h-rv__pm.is-locked:hover { background: var(--h-white); border-color: var(--h-grey-10); }
.h-dd-lock { display: inline-flex; color: var(--h-grey-50); }
.h-dd-lock svg { width: 12px; height: 12px; }
.h-dd-lock[hidden] { display: none; }
.h-dd-actions { align-items: center; gap: var(--h-s-3); }
.h-dd-actions .h-meta { margin: 0; }
.h-dd-list { display: grid; gap: var(--h-s-3); }
.h-dd-person { padding: var(--h-s-4) var(--h-s-5); }
.h-dd-person:hover { transform: none; box-shadow: var(--h-shadow); }
.h-dd-person__head { display: flex; align-items: center; gap: var(--h-s-3); }
.h-dd-person__head .h-meta { margin: 0; }
.h-dd-person__photo { width: 36px; height: 36px; border-radius: var(--h-radius-pill); object-fit: cover; flex: none; display: inline-flex; align-items: center; justify-content: center; }
.h-dd-person__photo--i { background: var(--h-blue-10); color: var(--h-blue); font-weight: var(--h-fw-bold); }
.h-dd-person__name { margin: 0; font-weight: var(--h-fw-bold); color: var(--h-blue); display: flex; align-items: center; gap: var(--h-s-2); }
.h-dd-person .h-mk-table { margin-top: var(--h-s-3); }
.h-dd-person .h-mk-table form { margin: 0; display: inline; }
@media (max-width: 900px) { .h-dd-grid { grid-template-columns: 1fr; } }

/* ---------- Studio Commissions: Sales statement --------------------------------- */
.h-sc-pick { display: flex; align-items: center; gap: var(--h-s-3); flex-wrap: wrap; margin-bottom: var(--h-s-5); }
.h-sc-pick .h-select { width: auto; min-width: 190px; }
.h-sc-pick .h-segmented__option { text-decoration: none; }
.h-stat--accent { border-color: var(--h-blue); background: var(--h-blue); }
.h-stat--accent .h-stat__label, .h-stat--accent .h-stat__sub { color: rgba(255,255,255,0.75); }
.h-stat--accent .h-stat__value { color: var(--h-white); }
.h-sc-neg { color: var(--h-error-ink); }
.h-sc-section { margin-bottom: var(--h-s-5); }
.h-sc-table { margin-top: 0; }
.h-sc-table tfoot td { border-top: 2px solid var(--h-blue); border-bottom: 0; font-weight: var(--h-fw-semibold); color: var(--h-blue); }
.h-sc-table td a { color: var(--h-blue); text-decoration: none; font-weight: var(--h-fw-semibold); }
.h-sc-table td a:hover { text-decoration: underline; }
.h-sc-roles { display: inline-flex; gap: 2px; }
.h-sc-roles i { display: inline-flex; width: 18px; height: 18px; align-items: center; justify-content: center; font-size: 10px; font-style: normal; font-weight: var(--h-fw-bold); border-radius: var(--h-radius-sm); background: var(--h-grey-10); color: var(--h-grey-50); }
.h-sc-roles i.is-on { background: var(--h-blue); color: var(--h-white); }
.h-sc-note { margin: var(--h-s-2) 0 0; }
.h-sc-prop { min-width: 220px; }
.h-sc-table .h-mk-days { white-space: normal; }
.h-sc-table .h-mk-days .h-badge { vertical-align: baseline; }
.h-sc-grid { display: grid; grid-template-columns: 1fr 1fr 1.3fr; gap: var(--h-s-4); align-items: start; margin-bottom: var(--h-s-5); }
.h-sc-card { padding: var(--h-s-4) var(--h-s-5); }
.h-sc-card:hover { transform: none; box-shadow: var(--h-shadow); }
.h-sc-card .h-mk-table { margin-top: var(--h-s-3); }
.h-sc-card tfoot td { border-top: 1px solid var(--h-grey-20); border-bottom: 0; }
.h-sc-sum tr.h-sc-sub td { font-weight: var(--h-fw-semibold); color: var(--h-blue); border-top: 1px solid var(--h-grey-20); }
.h-sc-sum tr.h-sc-net td { font-weight: var(--h-fw-bold); color: var(--h-blue); background: var(--h-paper); }
.h-sc-sum tr.h-sc-total td { font-weight: var(--h-fw-bold); color: var(--h-white); background: var(--h-blue); border-bottom: 0; }
.h-sc-quarter p { margin: var(--h-s-2) 0 0; line-height: var(--h-lh-base); }
.h-sc-quarter .h-badge { margin-left: var(--h-s-2); vertical-align: middle; }
@media (max-width: 1100px) { .h-sc-grid { grid-template-columns: 1fr 1fr; } .h-sc-grid > :last-child { grid-column: 1 / -1; } }
@media (max-width: 768px) { .h-sc-grid { grid-template-columns: 1fr; } }

.h-sc-editrow td { background: var(--h-paper); padding: var(--h-s-4) var(--h-s-5) !important; }
.h-sc-editrow[hidden] { display: none; }
.h-sc-edit__roles { display: flex; align-items: center; gap: var(--h-s-2); flex-wrap: wrap; margin-bottom: var(--h-s-3); }
.h-sc-edit__roles .h-label { margin: 0 var(--h-s-2) 0 0; }
.h-sc-edit__pcts { margin-bottom: var(--h-s-2); }
.h-sc-editcard { margin-bottom: var(--h-s-4); }
.h-sc-editcard > .h-meta { margin: 0 0 var(--h-s-3); }
.h-sc-editcard .h-lv-grid { margin-bottom: var(--h-s-2); }
.h-sc-grid--edit { grid-template-columns: 1fr 1fr 1fr; }
.h-sc-actions { white-space: nowrap; }
.h-sc-actions form, .h-sc-inline { display: inline-flex; margin: 0; vertical-align: middle; }
.h-sc-actions form + form, .h-sc-actions form + button { margin-left: var(--h-s-1); }
.h-sc-rejected td { color: var(--h-grey-50); }
/* The editing bench — Add an adjustment · Add a referral · Quarterly bonus.
   The three cards are meant to read as one row: equal height, one intro line
   each under the eyebrow, inputs on a shared baseline whatever the label
   wraps to, and each card's disclosure pinned to the same bottom rule. */
.h-sc-grid--edit { align-items: stretch; }
.h-sc-editcard { display: flex; flex-direction: column; }
.h-sc-editcard > .h-stat__label + .h-meta { margin: 0 0 var(--h-s-4); min-height: 2.6em; }
.h-sc-editcard > .h-sc-more:last-child { margin-top: auto; }
/* A row listing what's already there (an adjustment, a Westpac referral) sits
   directly under the fields that add one, so it lines up with them: no cell
   padding at the card's two edges, a money column of its own rather than one
   the widest label pushes around, and the row's Edit/Remove button flush right
   with the input above it. */
.h-sc-editcard .h-mk-table th:first-child, .h-sc-editcard .h-mk-table td:first-child { padding-left: 0; }
.h-sc-editcard .h-mk-table th:last-child, .h-sc-editcard .h-mk-table td:last-child { padding-right: 0; width: 1%; white-space: nowrap; }
.h-sc-editcard .h-mk-table td.num:not(:last-child) { width: 110px; }
.h-sc-editcard .h-mk-table td:last-child:not(.h-sc-actions) .h-btn-ghost,
.h-sc-editcard .h-mk-table td:last-child:not(.h-sc-actions) .h-btn--ghost { padding-left: 0; padding-right: 0; }
/* A queue row: the amount and the buttons centre against the event cell, which
   runs to two lines. Top-aligning them put the number on the address's line and
   the buttons' centre below it — the "off-centre" look. The last button in the
   row loses its right padding so the row of buttons ends on the same edge as
   the amounts and the header above them. */
.h-sc-editcard .h-mk-table td.num, .h-sc-editcard .h-mk-table td.h-sc-actions { vertical-align: middle; }
.h-sc-actions > * { vertical-align: middle; }
/* Only a BORDERLESS last button loses its right padding to sit flush with the
   column edge. Doing it to a bordered one (Save + approve) put the label on
   the border. */
.h-sc-editcard .h-sc-actions > :last-child.h-btn-ghost,
.h-sc-editcard .h-sc-actions > :last-child .h-btn-ghost,
.h-sc-editcard .h-sc-actions > :last-child.h-btn--ghost,
.h-sc-editcard .h-sc-actions > :last-child .h-btn--ghost { padding-right: 0; }

.h-sc-editcard > .h-sc-more { border-top: 1px solid var(--h-grey-10); padding-top: var(--h-s-3); }
/* Each field hugs the bottom of its row — label directly above its input —
   so a label that wraps to two lines eats into the space ABOVE it instead of
   pushing its field below its neighbour's. On the bench the rows have a floor
   height, which puts every input, every Add button and every disclosure on one
   line across all three cards. */
.h-lv-grid .h-label { justify-content: flex-end; }
.h-sc-editcard .h-lv-grid { grid-auto-rows: minmax(96px, auto); }

.h-sc-more { margin-top: var(--h-s-3); }
.h-sc-more summary { cursor: pointer; }
/* A brand caret instead of the browser's black triangle. */
.h-sc-more > summary { list-style: none; display: inline-flex; align-items: center; gap: var(--h-s-2); }
.h-sc-more > summary::-webkit-details-marker { display: none; }
.h-sc-more > summary::before {
  content: ""; width: 6px; height: 6px; flex: none;
  border-right: 1.5px solid var(--h-grey-50); border-bottom: 1.5px solid var(--h-grey-50);
  transform: rotate(-45deg); transition: transform .15s;
}
.h-sc-more[open] > summary::before { transform: rotate(45deg); }
.h-sc-more > summary:hover { color: var(--h-blue); }
.h-sc-more > summary:hover::before { border-color: var(--h-blue); }
.h-sc-more form { margin-top: var(--h-s-2); }
.h-sc-editcard .h-lg-actions { justify-content: flex-start; }
.h-sc-editcard .h-lg-actions form { gap: var(--h-s-2); flex-wrap: wrap; }
.h-sc-editcard .h-input--narrow { width: 120px; }
@media (max-width: 1100px) { .h-sc-grid--edit { grid-template-columns: 1fr; } }

/* ---------- Studio Commissions: public sign page + send controls ------------- */
.h-sign { background: var(--h-paper); margin: 0; min-height: 100vh; font-family: var(--h-font-sans); color: var(--h-blue); }
.h-sign__bar { background: var(--h-blue); padding: var(--h-s-4) var(--h-s-6); }
.h-sign__lockup { height: 26px; width: auto; display: block; }
.h-sign__wrap { max-width: 1000px; margin: var(--h-s-6) auto; padding: 0 var(--h-s-4); }
.h-sign__card { padding: var(--h-s-6); }
.h-sign__card:hover { transform: none; box-shadow: var(--h-shadow); }
.h-sign__pdf { width: 100%; height: 78vh; border: 1px solid var(--h-grey-20); border-radius: var(--h-radius); margin-top: var(--h-s-4); background: var(--h-white); }
.h-sign__form { margin-top: var(--h-s-5); background: var(--h-paper); border: 1px solid var(--h-grey-10); border-radius: var(--h-radius); padding: var(--h-s-5); display: grid; gap: var(--h-s-4); }
.h-sign__name { font-family: var(--h-font-script); font-size: 26px; padding: var(--h-s-3) var(--h-s-4); }
.h-sign__ack { display: flex; gap: var(--h-s-3); align-items: flex-start; font-size: var(--h-fs-sm); color: var(--h-grey-70); line-height: var(--h-lh-base); }
.h-sign__ack input { margin-top: 4px; accent-color: var(--h-blue); }
/* The last thing on a statement page: check everything above, then send.
   A blue rule closes the page off so it reads as the end of the job. */
.h-sc-signoff { border-top: 2px solid var(--h-blue); padding-top: var(--h-s-4); margin-top: var(--h-s-6); }
.h-sc-signoff .h-sc-send { margin-bottom: 0; }
.h-sc-send { display: flex; align-items: center; gap: var(--h-s-2); flex-wrap: wrap; margin: 0 0 var(--h-s-5); }
.h-sc-send form { display: inline-flex; align-items: center; gap: var(--h-s-2); margin: 0; }
.h-sc-send .h-input { width: 220px; }

.h-cm-status { margin-top: var(--h-s-6); }
.h-cm-status .h-mk-table { background: var(--h-white); border: 1px solid var(--h-grey-10); border-radius: var(--h-radius); }

/* Principal statement */
.h-pr-grid { grid-template-columns: 1fr 1fr; }
.h-pr-big { font-size: var(--h-fs-xl); font-weight: var(--h-fw-bold); }
.h-pr-table td:first-child { color: var(--h-grey-70); }
.h-pr-table .h-mk-days { display: inline; margin-left: var(--h-s-1); }
@media (max-width: 900px) { .h-pr-grid { grid-template-columns: 1fr; } }

/* ── Studio · PM commissions (steps 5–7) ─────────────────────────────────── */
.h-pe-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--h-s-4); align-items: start; margin-bottom: var(--h-s-5); }
.h-pe-side { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); gap: var(--h-s-4); min-width: 0; align-items: start; }
.h-pe-main { min-width: 0; }
.h-pe-name { min-width: 200px; }
.h-pe-row--paused td { color: var(--h-grey-50); }
.h-pe-in { width: 96px; text-align: right; padding: var(--h-s-1) var(--h-s-2); font-variant-numeric: tabular-nums; }
.h-pe-in--money { width: 120px; }
.h-pe-in[readonly], .h-pe-office input[readonly] { background: var(--h-paper); color: var(--h-grey-70); }
.h-pe-in.is-imported, .h-pe-office .is-imported { border-color: var(--h-cyan); font-weight: var(--h-fw-semibold); }
.h-pe-foot { justify-content: flex-start; align-items: center; margin-top: var(--h-s-3); }
.h-pe-import { display: grid; gap: var(--h-s-3); margin-top: var(--h-s-3); }
.h-pe-office { display: grid; gap: var(--h-s-3); margin-top: var(--h-s-3); }
.h-pe-office > .h-meta { margin: 0; }
.h-pe-person { border-top: 1px solid var(--h-grey-10); padding-top: var(--h-s-3); display: grid; gap: var(--h-s-2); }
.h-pe-person__head { display: flex; align-items: center; justify-content: space-between; gap: var(--h-s-2); flex-wrap: wrap; }
.h-pe-person__fields { display: grid; grid-template-columns: 120px minmax(0, 1fr); gap: var(--h-s-3); }
.h-pe-person__fields .h-input--narrow { width: 100%; max-width: none; }
.h-pe-base { display: flex; align-items: center; gap: var(--h-s-3); flex-wrap: wrap; font-size: var(--h-fs-sm); }
.h-pe-base .h-mk-days { flex-basis: 100%; }
.h-pe-check { display: inline-flex; align-items: center; gap: var(--h-s-1); font-size: var(--h-fs-sm); color: var(--h-grey-70); cursor: pointer; }
.h-pe-check input { accent-color: var(--h-blue); }
.h-pq-table td { vertical-align: top; }
.h-pq-miss { color: var(--h-error-ink); font-weight: var(--h-fw-semibold); }
.h-pq-table tfoot td { border-top: 2px solid var(--h-blue); border-bottom: 0; font-weight: var(--h-fw-semibold); color: var(--h-blue); }
.h-pq-rules { display: grid; gap: var(--h-s-3); margin-top: var(--h-s-3); justify-items: start; }
.h-pq-rules .h-pe-check { font-size: var(--h-fs-base); color: var(--h-blue); }
.h-pm-sublabel { margin-top: var(--h-s-4); }
@media (max-width: 900px) { .h-pe-side { grid-template-columns: 1fr; } }
.h-mk-days svg, .h-meta svg { width: 12px; height: 12px; vertical-align: -2px; margin-right: 2px; }
.h-pe-in { width: 72px; }
.h-pe-in--money { width: 110px; }
.h-pe-table .h-badge { white-space: nowrap; }
/* One row per portfolio, and it reads as one row: Save and Save + approve sit
   side by side at the right rather than stacked full-width (which turned the
   borderless Save into a line of floating centred text), and every cell centres
   against the name block, which is the tallest thing in the row. */
.h-pe-table .h-sc-actions { white-space: nowrap; text-align: right; min-width: 0; }
.h-pe-table .h-sc-actions button { display: inline-flex; width: auto; white-space: nowrap; margin: 0 0 0 var(--h-s-2); }
.h-pe-table .h-sc-actions form { display: inline-flex; margin: 0; }
.h-pe-table td { vertical-align: middle; }
.h-pe-table td.num .h-mk-days { white-space: normal; }

/* Office pool: the fees field stacks like every other field in the card, at the
   same width and the same left edge as Share % below it, and the two buttons
   sit together instead of at opposite ends of the card. */
.h-pe-office > .h-label > span { display: block; margin-bottom: var(--h-s-1); }
.h-pe-office > .h-label .h-input { width: 120px; }
.h-pe-office > .h-lg-actions { justify-content: flex-start; gap: var(--h-s-2); }
/* ── Studio · Fee Matrix ─────────────────────────────────────────────────── */
.h-fm-line { display: grid; grid-template-columns: 1fr auto; gap: var(--h-s-4); align-items: center; padding: var(--h-s-4) var(--h-s-5); margin-bottom: var(--h-s-4); }
.h-fm-line:hover { transform: none; box-shadow: var(--h-shadow); }
.h-fm-line__value { font-size: var(--h-fs-xl); font-weight: var(--h-fw-bold); color: var(--h-blue); margin: 0; font-variant-numeric: tabular-nums; }
.h-fm-line__form { display: flex; align-items: flex-end; gap: var(--h-s-2); }
.h-fm-line__form .h-input { width: 140px; }
.h-fm-line__hist { grid-column: 1 / -1; margin: 0; }
.h-fm-check { max-width: none; margin-bottom: var(--h-s-5); }
.h-fm-fields { grid-template-columns: 1fr 1fr auto; align-items: end; }
.h-fm-actions { margin-top: 0; }
.h-fm-verdict { margin-top: var(--h-s-4); }
.h-fm-verdict__head { font-size: var(--h-fs-xl); font-weight: var(--h-fw-bold); margin: 0 0 var(--h-s-1); color: var(--h-blue); }
.h-fm-verdict.is-yes .h-fm-verdict__head { color: var(--h-success-ink); }
.h-fm-verdict.is-no .h-fm-verdict__head { color: var(--h-error-ink); }
.h-fm-verdict__sub { margin: 0 0 var(--h-s-3); color: var(--h-grey-70); }
.h-fm-answers { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--h-s-3); }
.h-fm-outcome { display: flex; align-items: center; gap: var(--h-s-2); flex-wrap: wrap; margin-top: var(--h-s-4); }
.h-fm-outcome form { margin: 0; }
.h-fm-grid-wrap { margin-bottom: var(--h-s-5); }
.h-fm-grid th:first-child, .h-fm-grid td:first-child { position: sticky; left: 0; background: var(--h-white); font-weight: var(--h-fw-semibold); }
.h-fm-grid thead th { position: sticky; top: 0; background: var(--h-paper); }
.h-fm-grid td { font-variant-numeric: tabular-nums; }
.h-fm-grid td.is-ok { background: var(--h-blue-10); color: var(--h-blue); font-weight: var(--h-fw-semibold); }
.h-fm-grid tr.is-hit td { box-shadow: inset 0 -2px 0 var(--h-cyan); }
.h-fm-grid tr.is-hit td:first-child { color: var(--h-cyan); }
.h-fm-full { margin-top: var(--h-s-3); }
.h-fm-full summary { display: inline-flex; cursor: pointer; list-style: none; }
.h-fm-full summary::-webkit-details-marker { display: none; }
.h-fm-scroll { max-height: 520px; overflow: auto; margin-top: var(--h-s-3); border: 1px solid var(--h-grey-10); }
.h-fm-ledger .h-mk-table { margin-top: var(--h-s-3); }
@media (max-width: 900px) { .h-fm-line { grid-template-columns: 1fr; } .h-fm-fields { grid-template-columns: 1fr; } }
.h-fm-line__fields { display: grid; grid-template-columns: 1fr 100px auto 1fr auto; gap: var(--h-s-2); align-items: end; }
.h-fm-line__fields .h-input { width: 100%; }
.h-fm-line__or { align-self: center; padding-bottom: var(--h-s-2); color: var(--h-grey-50); font-size: var(--h-fs-sm); }
.h-fm-line__hint { margin: 0 0 var(--h-s-2); }
.h-fm-line { grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); align-items: start; }
.h-fm-line__form { display: block; }
.h-fm-more { margin-top: var(--h-s-3); }
.h-fm-more summary { cursor: pointer; }
.h-fm-fields--more { grid-template-columns: 1fr 1fr 1fr; margin-top: var(--h-s-3); }
.h-fm-outcome { display: flex; align-items: center; gap: var(--h-s-2); flex-wrap: wrap; margin-top: var(--h-s-4); }
.h-fm-outcome__note { flex: 1 1 260px; }
.h-fm-pending .h-notice__title { margin-bottom: var(--h-s-2); }
.h-fm-pending__row { display: flex; align-items: center; gap: var(--h-s-2); flex-wrap: wrap; padding: var(--h-s-1) 0; }
.h-fm-pending__row form { margin: 0; }
.h-fm-portfolio { margin-bottom: var(--h-s-5); }
.h-fm-portfolio__stats { margin: var(--h-s-3) 0; }
.h-fm-portfolio .h-mk-table { margin-top: var(--h-s-3); }
.h-fm-upload { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--h-s-3); align-items: end; margin-top: var(--h-s-4); }
@media (max-width: 900px) { .h-fm-line__fields, .h-fm-fields--more, .h-fm-upload { grid-template-columns: 1fr; } }
/* ── Studio · Meeting Agenda + Sales Meeting ─────────────────────────────── */
.h-ag-grid { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(280px, 1fr); gap: var(--h-s-4); align-items: start; }
.h-ag-side { display: grid; gap: var(--h-s-4); min-width: 0; }
.h-ag-add { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--h-s-3); align-items: end; margin: var(--h-s-3) 0 var(--h-s-4); }
.h-ag-add__text { grid-column: 1 / -1; }
.h-ag-add textarea, .h-ag-add .h-select { width: 100%; }
.h-ag-add .h-label { display: flex; flex-direction: column; gap: var(--h-s-1); }
.h-ag-add textarea { resize: vertical; }
.h-ag-list { list-style: none; margin: 0; padding: 0; }
.h-ag-item { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--h-s-3); padding: var(--h-s-3) 0; border-top: 1px solid var(--h-grey-10); align-items: start; }
.h-ag-item.is-closed .h-ag-item__text { color: var(--h-grey-50); }
.h-ag-item__text { margin: 0 0 2px; color: var(--h-blue); font-weight: var(--h-fw-semibold); line-height: var(--h-lh-base); }
.h-ag-item__main .h-meta { margin: 0; }
.h-ag-item__actions { display: flex; gap: var(--h-s-1); flex-wrap: wrap; justify-content: flex-end; }
.h-ag-item__actions form { margin: 0; }
.h-ag-edit { grid-column: 1 / -1; display: grid; grid-template-columns: minmax(0, 1fr) 200px auto; gap: var(--h-s-2); align-items: start; }
.h-ag-edit[hidden] { display: none; }
.h-ag-list--compact .h-ag-item { padding: var(--h-s-2) 0; }
.h-ag-list--compact .h-ag-item__text { font-weight: var(--h-fw-regular); font-size: var(--h-fs-sm); }
.h-sm-new { max-width: none; }
.h-sm-dates { margin-bottom: var(--h-s-3); flex-wrap: wrap; }
.h-sm-dates .h-segmented__option input { position: absolute; opacity: 0; width: 0; height: 0; }
.h-sm-dates .h-segmented__option { cursor: pointer; }
.h-sm-other { max-width: 260px; margin-bottom: var(--h-s-3); }
.h-sm-transcript { font-family: var(--h-font-mono, ui-monospace, monospace); font-size: var(--h-fs-sm); }
.h-sm-grid { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); gap: var(--h-s-4); align-items: start; }
.h-sm-card { margin-bottom: var(--h-s-4); }
.h-sm-list { margin: var(--h-s-3) 0 0; padding-left: 0; list-style: none; }
.h-sm-list li { padding: var(--h-s-2) 0; border-top: 1px solid var(--h-grey-10); line-height: var(--h-lh-base); }
.h-sm-list li:first-child { border-top: 0; }
.h-sm-list--num { list-style: decimal; padding-left: var(--h-s-5); }
.h-sm-card--wins .h-sm-list li strong { color: var(--h-blue); }
.h-sm-commit { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--h-s-3); align-items: start; }
.h-sm-commit.is-closed .h-sm-commit__text { color: var(--h-grey-50); }
.h-sm-commit__text { margin: 0; }
.h-sm-commit .h-meta { margin: 2px 0 0; }
.h-sm-transcript-box { margin-top: var(--h-s-3); }
.h-sm-transcript-box summary { display: inline-flex; cursor: pointer; list-style: none; }
.h-sm-transcript-box summary::-webkit-details-marker { display: none; }
.h-sm-pre { white-space: pre-wrap; font-family: var(--h-font-sans); font-size: var(--h-fs-sm); color: var(--h-grey-70); background: var(--h-white); border: 1px solid var(--h-grey-10); padding: var(--h-s-4); max-height: 420px; overflow: auto; margin-top: var(--h-s-2); }
.h-sm-delete { display: flex; flex-wrap: wrap; align-items: center; gap: var(--h-s-3); margin-top: var(--h-s-4); }
.h-sm-edit { margin-top: var(--h-s-4); }
.h-sm-edit[hidden] { display: none; }
.h-sm-edit textarea { resize: vertical; }
/* One line of the meeting notes, with its own Edit. Same shape as .h-ag-item
   above — text left, actions right, the edit box spanning underneath once it is
   unhidden — but it sits INSIDE an <li> rather than being one, because
   .h-sm-list--num numbers its items and an li turned into a grid loses its
   marker. The li keeps the list, this keeps the layout. */
.h-sm-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--h-s-3); align-items: start; }
.h-sm-row__main { min-width: 0; }
.h-sm-row__actions { display: flex; gap: var(--h-s-1); flex-wrap: wrap; justify-content: flex-end; }
.h-sm-row__actions form { margin: 0; }
.h-sm-edit-box { grid-column: 1 / -1; display: grid; gap: var(--h-s-2); margin-top: var(--h-s-2); }
.h-sm-edit-box[hidden] { display: none; }
.h-sm-edit-box .h-label { margin-bottom: 0; }
.h-sm-edit-box textarea { resize: vertical; }
.h-sm-edit-box__actions { display: flex; gap: var(--h-s-2); flex-wrap: wrap; align-items: center; }
/* The source text for a copy-to-clipboard button: read by script, never shown.
   Off the page entirely rather than visually hidden — nothing here is for a
   reader, and the clipboard reads .value whatever the display. */
.h-sm-copy-src { display: none; }
@media (max-width: 1100px) { .h-ag-grid, .h-sm-grid { grid-template-columns: 1fr; } .h-ag-add, .h-ag-edit { grid-template-columns: 1fr; } }

/* ── Studio · phone + form polish (06/09) ────────────────────────────────── */
.h-page-header__actions { flex-wrap: wrap; }
input[type="checkbox"], input[type="radio"] { accent-color: var(--h-blue); }
.h-sc-pick .h-badge, .h-sc-pick .h-select { max-width: 100%; }
@media (max-width: 640px) { .h-page-header__actions .h-btn { flex: 1 1 auto; text-align: center; } .h-stat-row { grid-template-columns: 1fr 1fr; } }

/* ── Studio · What needs you ─────────────────────────────────────────────────
   The Home panel that answers "what is outstanding for me". A list, not a
   feed: one row per thing, the count first, one plain sentence, one way in.
   The left rule carries the urgency so it reads before the words do — the
   same idea as .h-notice, sized down to sit many rows deep. */
.h-att { padding: var(--h-s-5); }
.h-att:hover { box-shadow: none; transform: none; }

.h-att__title {
  margin: 0 0 var(--h-s-4);
  font-size: var(--h-fs-lg);
  font-weight: var(--h-fw-semibold);
  letter-spacing: var(--h-tracking-tight);
  color: var(--h-blue);
}

.h-att__list { list-style: none; margin: 0; padding: 0; }

.h-att__row {
  display: flex;
  align-items: center;
  gap: var(--h-s-3);
  padding: var(--h-s-3);
  padding-left: var(--h-s-4);
  border-left: 3px solid var(--h-grey-30);
  border-bottom: 1px solid var(--h-grey-10);
}
.h-att__row:last-child { border-bottom: 0; }
.h-att__row--error   { border-left-color: var(--h-error); }
.h-att__row--warning { border-left-color: var(--h-warning); }
.h-att__row--info    { border-left-color: var(--h-cyan); }
.h-att__row--muted   { border-left-color: var(--h-grey-30); }

/* Counts line up down the left edge whether they read 1 or 24. */
.h-att__count { flex: none; min-width: 2.25rem; text-align: center; }

.h-att__text {
  flex: 1;
  min-width: 0;
  font-size: var(--h-fs-sm);
  line-height: var(--h-lh-snug);
  color: var(--h-ink);
}
.h-att__row--muted .h-att__text { color: var(--h-grey-70); }

.h-att__open { flex: none; }

.h-att__empty { margin: 0; font-size: var(--h-fs-sm); color: var(--h-grey-50); }

@media (max-width: 640px) {
  .h-att__row { flex-wrap: wrap; }
  .h-att__text { flex: 1 1 100%; order: 3; }
}

/* The collapsed form: one line on Home instead of the full list. The bar
   carries the count and the worst tone; the list itself moves into .h-modal.
   Home is a launcher — outstanding work announces itself, it doesn't occupy
   the fold. .h-att (the open card) is unchanged and still used inside the
   modal, so both forms read identically row for row. */
.h-att-bar {
  display: flex;
  align-items: center;
  gap: var(--h-s-3);
  width: 100%;
  margin: 0 0 var(--h-s-5);
  padding: var(--h-s-3) var(--h-s-4);
  font: inherit;
  text-align: left;
  color: var(--h-ink);
  background: var(--h-white);
  border: var(--h-border-strong);
  border-left: 3px solid var(--h-grey-30);
  border-radius: var(--h-radius);
  box-shadow: var(--h-shadow-sm);
  cursor: pointer;
  transition: box-shadow var(--h-duration) var(--h-ease),
              border-color var(--h-duration) var(--h-ease);
}
.h-att-bar:hover { box-shadow: var(--h-shadow); }
.h-att-bar:focus-visible { outline: var(--h-focus-ring); outline-offset: 2px; }
.h-att-bar--error   { border-left-color: var(--h-error); }
.h-att-bar--warning { border-left-color: var(--h-warning); }
.h-att-bar--info    { border-left-color: var(--h-cyan); }
.h-att-bar--muted   { border-left-color: var(--h-grey-30); }

.h-att-bar__icon { flex: none; display: inline-flex; color: var(--h-blue); }
.h-att-bar__icon svg { width: 18px; height: 18px; }

.h-att-bar__label {
  flex: 1;
  min-width: 0;
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-semibold);
  color: var(--h-blue);
}
/* The headline row, so the bar still says something when it is closed. */
.h-att-bar__lead { font-weight: var(--h-fw-regular); color: var(--h-grey-70); }

.h-att-bar__count { flex: none; }
.h-att-bar__chev { flex: none; display: inline-flex; color: var(--h-grey-50); }
.h-att-bar__chev svg { width: 16px; height: 16px; transform: rotate(-90deg); }

/* Cleared state — a sentence, not a card. */
.h-att-clear {
  margin: 0 0 var(--h-s-5);
  font-size: var(--h-fs-sm);
  color: var(--h-grey-50);
}

/* Inside the modal the card chrome is already supplied by .h-modal. */
.h-modal .h-att { padding: 0; border: 0; box-shadow: none; background: transparent; }

@media (max-width: 640px) {
  .h-att-bar__lead { display: none; }
}

/* ── Studio · My Week ─────────────────────────────────────────────────────────
   /my-week (sales) and /my-day (property management). Phone-first: one column
   at 390px, nothing wider than the screen, and the only loud elements are the
   single action that is owed and the pace badge on a number. Everything else
   is quiet navy on paper. */

.h-mw-sec { margin: 0 0 var(--h-s-6); }
.h-mw-sec__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--h-s-3); margin: 0 0 var(--h-s-3); flex-wrap: wrap; }
.h-mw-sec__title { font-size: var(--h-fs-lg); font-weight: var(--h-fw-semibold); color: var(--h-blue); margin: 0; }

/* The one-line "nothing needs you" statement — deliberately not a stat tile,
   because a $0 tile reads as a failure and a sentence reads as an answer. */
.h-mw-quiet { margin: 0; color: var(--h-grey-70); font-size: var(--h-fs-sm); line-height: var(--h-lh-base); }

/* Action strip: what is owed, and the button that finishes it. */
.h-mw-strip { display: flex; align-items: center; justify-content: space-between; gap: var(--h-s-4); flex-wrap: wrap; }
.h-mw-strip__text { margin: 0; min-width: 0; }
.h-mw-strip__actions { display: flex; gap: var(--h-s-2); flex-wrap: wrap; }

/* A row with words on the left and one control on the right. Collapses to a
   stack on a phone so the button never squeezes the text to two characters. */
.h-mw-list { list-style: none; margin: 0; padding: 0; }
.h-mw-list > li { padding: var(--h-s-3) 0; border-top: 1px solid var(--h-grey-10); }
.h-mw-list > li:first-child { border-top: 0; }
.h-mw-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--h-s-3); align-items: start; }
.h-mw-row__text { margin: 0; line-height: var(--h-lh-base); }
.h-mw-row__actions { display: flex; gap: var(--h-s-2); align-items: center; }
.h-mw-row__brief { margin: var(--h-s-2) 0 0; padding-left: var(--h-s-3); border-left: 2px solid var(--h-grey-10); color: var(--h-grey-70); font-size: var(--h-fs-sm); white-space: pre-line; }

/* Numbers: label, actual vs target, a thin bar, a pace badge. The bar's width
   comes from data-pct via the page script — never an inline style attribute. */
.h-mw-num { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--h-s-1) var(--h-s-3); align-items: baseline; }
.h-mw-num__label { font-size: var(--h-fs-sm); font-weight: var(--h-fw-semibold); color: var(--h-blue); margin: 0; }
.h-mw-num__value { font-size: var(--h-fs-sm); color: var(--h-grey-70); margin: 0; font-variant-numeric: tabular-nums; white-space: nowrap; }
.h-mw-num__value strong { color: var(--h-blue); font-size: var(--h-fs-lg); font-weight: var(--h-fw-bold); }
.h-mw-num__foot { grid-column: 1 / -1; display: flex; align-items: center; justify-content: space-between; gap: var(--h-s-3); flex-wrap: wrap; margin: var(--h-s-1) 0 0; }
.h-mw-bar { grid-column: 1 / -1; height: 6px; background: var(--h-grey-10); border-radius: var(--h-radius); overflow: hidden; margin: var(--h-s-2) 0 0; }
.h-mw-bar__fill { display: block; height: 100%; width: 0; background: var(--h-blue); border-radius: var(--h-radius); }
.h-mw-bar__fill.is-ahead { background: var(--h-success); }
.h-mw-bar__fill.is-behind { background: var(--h-warning); }

/* Who's away, and my own leave. */
.h-mw-away { list-style: none; margin: 0; padding: 0; }
.h-mw-away > li { display: flex; justify-content: space-between; gap: var(--h-s-3); padding: var(--h-s-2) 0; border-top: 1px solid var(--h-grey-10); font-size: var(--h-fs-sm); }
.h-mw-away > li:first-child { border-top: 0; }
.h-mw-away__who { font-weight: var(--h-fw-semibold); color: var(--h-blue); }
.h-mw-away__when { color: var(--h-grey-50); white-space: nowrap; }

/* Inline "raise something" / "what happened" forms. */
.h-mw-form { display: grid; gap: var(--h-s-2); margin: var(--h-s-3) 0 0; }
.h-mw-form__actions { display: flex; gap: var(--h-s-2); flex-wrap: wrap; }

/* Footer: the full pages this one summarises. */
.h-mw-foot { display: flex; flex-wrap: wrap; gap: var(--h-s-2); padding-top: var(--h-s-4); border-top: 1px solid var(--h-grey-10); }

@media (max-width: 640px) {
  .h-mw-row { grid-template-columns: 1fr; }
  .h-mw-row__actions { justify-content: flex-start; }
  .h-mw-strip__actions .h-btn { flex: 1 1 auto; text-align: center; }
}

/* ── Studio · Notifications ───────────────────────────────────────────────────
   /notifications — the record of what Studio has told one person, and how they
   want to be told next time. A dated list, not a feed: every row keeps its own
   read state, because opening a page marks a whole category read and surviving
   that is the entire point of the page.

   Unread carries a navy left rule, a cyan dot and heavier text; read fades to
   grey and keeps its place in the list. Cyan appears twice — the dot and the
   link hover — so the surface stays navy-and-paper. */

.h-nt-day {
  margin: var(--h-s-5) 0 var(--h-s-2);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-bold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  color: var(--h-grey-50);
}
.h-nt-day:first-child { margin-top: 0; }

.h-nt { list-style: none; margin: 0; padding: 0; }

.h-nt__row {
  display: flex;
  align-items: flex-start;
  gap: var(--h-s-3);
  padding: var(--h-s-3) var(--h-s-4);
  margin: 0 0 var(--h-s-2);
  background: var(--h-white);
  border: 1px solid var(--h-grey-10);
  border-left: 3px solid var(--h-grey-30);
  border-radius: var(--h-radius);
}
.h-nt__row--unread { border-left-color: var(--h-blue); }

/* The dot repeats the left rule at row level so a scan down the page finds
   the unread items without reading a word. */
.h-nt__dot {
  flex: none;
  width: 8px;
  height: 8px;
  margin-top: 0.4rem;
  border-radius: 50%;
  background: var(--h-grey-30);
}
.h-nt__row--unread .h-nt__dot { background: var(--h-cyan); }

.h-nt__body { flex: 1; min-width: 0; }

.h-nt__label {
  margin: 0 0 var(--h-s-1);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-semibold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  color: var(--h-grey-50);
}
.h-nt__row--unread .h-nt__label { color: var(--h-blue); }

.h-nt__text {
  margin: 0;
  font-size: var(--h-fs-sm);
  line-height: var(--h-lh-snug);
  color: var(--h-grey-70);
}
.h-nt__row--unread .h-nt__text { color: var(--h-ink); font-weight: var(--h-fw-semibold); }

/* Every row links to the thing itself, so the whole sentence is the target. */
.h-nt__link { color: inherit; text-decoration: none; border-bottom: 1px solid var(--h-grey-30); }
.h-nt__link:hover { border-bottom-color: var(--h-cyan); }
.h-nt__link:focus-visible { outline: var(--h-focus-ring); outline-offset: 2px; }

.h-nt__time {
  flex: none;
  font-size: var(--h-fs-xs);
  color: var(--h-grey-50);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.h-nt__act { flex: none; display: flex; align-items: center; gap: var(--h-s-2); }
.h-nt__act form { margin: 0; }
.h-nt__done { font-size: var(--h-fs-xs); color: var(--h-grey-50); }

/* On a phone the sentence keeps the dot's company and the time and the one
   action drop underneath, right-aligned — never a lone dot on its own line. */
@media (max-width: 640px) {
  .h-nt__row { flex-wrap: wrap; }
  .h-nt__dot { order: 1; }
  .h-nt__body { order: 2; flex: 1 1 calc(100% - 1.25rem); }
  .h-nt__time { order: 3; margin-left: auto; }
  .h-nt__act { order: 4; }
}

/* How Studio contacts you — one choice, described in the words a person would
   use themselves, not the channel's brand name alone. */
.h-nt-choices { display: grid; gap: var(--h-s-2); margin: 0 0 var(--h-s-5); }

/* SUPERSEDED by .h-radio + .h-fieldset on 14/09/2026; kept unchanged for
   Studio notifications. Do not use in new work. */
.h-nt-choice {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--h-s-1) var(--h-s-3);
  padding: var(--h-s-3) var(--h-s-4);
  background: var(--h-paper);
  border: 1px solid var(--h-grey-10);
  border-radius: var(--h-radius);
  cursor: pointer;
}
.h-nt-choice input { grid-row: span 2; width: 16px; height: 16px; margin-top: 0.2rem; }
.h-nt-choice:has(input:checked) { background: var(--h-white); border-color: var(--h-blue); }
.h-nt-choice:has(input:disabled) { cursor: default; }
.h-nt-choice__name { font-size: var(--h-fs-sm); font-weight: var(--h-fw-semibold); color: var(--h-blue); }
.h-nt-choice__desc { grid-column: 2; font-size: var(--h-fs-sm); color: var(--h-grey-70); }

.h-nt-mutes { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: var(--h-s-2); }
.h-nt-mutes .h-form-card__check { margin: 0; }

/* ---------- Pill + tile modifiers for filter/flag rows (added 06/09/2026) ---
   Purely additive — nothing above is changed. Added for the Call Log queue,
   available to any app.

   .h-pill--xs   an in-table size, so a pill can sit inside a table row
                 without pushing the row height around.
   .h-pill--warn a pill that FLAGS something rather than selects it (Calls'
                 repeat-caller marker, the Unassigned filter). It stays a
                 .h-pill because it's clickable — a tappable thing must never
                 masquerade as a .h-badge, which is a status label only. */
.h-pill--xs { padding: 1px var(--h-s-2); font-size: var(--h-fs-xs); gap: var(--h-s-1); }
.h-pill--warn { background: var(--h-warning-soft); color: var(--h-warning-ink); border-color: var(--h-warning); }
.h-pill--warn:hover { background: var(--h-warning); color: var(--h-charcoal); border-color: var(--h-warning); }
.h-pill--warn.h-pill--active,
.h-pill--warn.is-active { background: var(--h-warning); color: var(--h-charcoal); border-color: var(--h-warning); }

/* Selected state for a .h-today__tile that doubles as a filter control (the
   Call Log stat tiles are also the status filters). Only the three outer
   borders move, so the tile keeps the left rule that carries its category. */
.h-today__tile.is-active {
  border-top-color: var(--h-blue);
  border-right-color: var(--h-blue);
  border-bottom-color: var(--h-blue);
  box-shadow: var(--h-shadow);
}

/* ---------- Generic primitives, promoted from app-specific ones (06/09/2026)
   Purely additive — nothing above is changed.

   These three patterns existed only under a feature's own prefix, so a second
   app that needed the same shape had to borrow the first app's class. That
   couples them: restyling Studio's reviews would silently restyle the Call Log
   email-action page. Same visuals, feature-neutral names, so neither app owns
   the other's look.

   .h-quote     verbatim text quoted back to the reader — a caller's message,
                a note, anything typed by a human that we're echoing, not
                editing. (Was .h-rv__text, Studio reviews.)
   .h-choice    a radio option with a name and a supporting line, in a
                .h-choices list. (Was .h-nt-choice, Studio notifications.)
   .h-actions   a row of buttons that WRAPS. .h-form-card__actions has neither
                gap nor wrap, so two buttons collide on a narrow phone.

   Studio's .h-rv__text and .h-nt-choice are left in place and unchanged; they
   should migrate onto these later so there is one definition, not two. */

.h-quote {
  margin: var(--h-s-3) 0 0;
  padding: var(--h-s-3) var(--h-s-4);
  background: var(--h-paper);
  border-left: 3px solid var(--h-grey-10);
  border-radius: var(--h-radius);
  font-size: var(--h-fs-sm);
  color: var(--h-grey-70);
  line-height: var(--h-lh-base);
  white-space: pre-wrap;
}
.h-quote--empty { font-style: italic; }

.h-choices { display: grid; gap: var(--h-s-2); margin: 0 0 var(--h-s-5); }

/* Agenda item owners. Six names in a single-column .h-choices grid made the
   add form six rows tall and pushed the button off the fold; these are short
   labels that belong on one or two lines beside it. Declared after .h-choices
   so the flex layout wins where both classes are applied. */
.h-ag-owners {
  display: flex;
  flex-wrap: wrap;
  gap: var(--h-s-1) var(--h-s-4);
  margin: 0;   /* zero: the row aligns to its end edge, so any bottom margin
                  here lifts the names off the button beside them. */
}
/* SUPERSEDED by .h-radio + .h-fieldset on 14/09/2026 for the plain
   one-line-label case; .h-choice keeps the name + description card layout,
   which .h-radio does not do. Use .h-radio unless you need the description. */
.h-choice {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--h-s-1) var(--h-s-3);
  padding: var(--h-s-3) var(--h-s-4);
  background: var(--h-paper);
  border: 1px solid var(--h-grey-10);
  border-radius: var(--h-radius);
  cursor: pointer;
}
.h-choice input { grid-row: span 2; width: 16px; height: 16px; margin-top: 0.2rem; }
.h-choice:has(input:checked) { background: var(--h-white); border-color: var(--h-blue); }
.h-choice:has(input:disabled) { cursor: default; }
.h-choice__name { font-size: var(--h-fs-sm); font-weight: var(--h-fw-semibold); color: var(--h-blue); }
.h-choice__desc { grid-column: 2; font-size: var(--h-fs-sm); color: var(--h-grey-70); }

.h-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--h-s-3);
  margin-top: var(--h-s-5);
}

/* .h-badge is inline-flex, which overrides the `hidden` attribute — a badge
   markup-hidden by a script stayed visible. */
.h-badge[hidden] { display: none; }

/* ---------- Call report (Calls /report) 06/09/2026 ------------------------ */
/* Additive only. .h-bars__track/.h-bars__fill are reused as-is; the modifier
   below exists because a track dropped into a table cell (rather than the
   .h-bars grid) stays inline, so its 8px height never applies. Modifier rather
   than an edit to .h-bars__track — five apps share that rule. */
.h-bars__track--cell { display: block; width: 100%; min-width: 60px; }

/* The sentence between the headline tiles and the tables: what the number
   means, said once, before the detail starts. */
.h-report-lead {
  margin: var(--h-s-4) 0 var(--h-s-6);
  font-size: var(--h-fs-base);
  line-height: var(--h-lh-base);
  color: var(--h-grey-70);
}

/* Method note at the foot of the report — what each period actually covers. */
.h-report-foot {
  margin: var(--h-s-6) 0 var(--h-s-8);
  padding-top: var(--h-s-4);
  border-top: var(--h-border);
  line-height: var(--h-lh-base);
}

/* .h-table--tight drops columns 3 and 4 below 640px. On the report that would
   take "Completed" and "Rate" off the assignee table — the two things the page
   exists to show. This modifier keeps them and drops the last column instead
   (the share bar, and the oldest period on the source table), which is the
   decoration rather than the substance. Additive: the base rule is untouched. */
@media (max-width: 640px) {
  .h-table--report th:nth-child(3), .h-table--report td:nth-child(3),
  .h-table--report th:nth-child(4), .h-table--report td:nth-child(4) { display: table-cell; }
  .h-table--report th:last-child,  .h-table--report td:last-child  { display: none; }
}

/* ---------- Quiet + informational variants (06/09/2026) ---------------------
   Purely additive — nothing above is changed.

   Colour should mark the exception, not the rule. Two surfaces had drifted the
   other way: the Call Log queue was flagging repeat callers, unassigned rows
   and the Assign action all in the same warning amber as a genuinely overdue
   message, so four different meanings shouted equally; and the call report
   showed a wall of success-green because nearly every rate is 100%.

   .h-badge--quiet  the expected, unremarkable value. Recedes so the
                    exceptions beside it are the thing you see.
   .h-pill--info    a clickable pill carrying a FACT, not an alert — the
                    repeat-caller marker. Amber now means only "chase this".  */
.h-badge--quiet { background: var(--h-grey-10); color: var(--h-grey-70); }
.h-pill--info { background: var(--h-blue-10); color: var(--h-blue); border-color: var(--h-blue-20); }
.h-pill--info:hover { background: var(--h-blue-20); color: var(--h-blue); border-color: var(--h-blue); }

/* .h-btn--xs — a button at badge height (06/09/2026). BRAND.md: anything you
   tap is a .h-btn, never a badge class; but a small action sitting in a row
   of badges has to match their box or the row looks ragged. Same padding,
   size, tracking and case as .h-badge, still a rectangular button. */
.h-btn--xs { padding: var(--h-s-1) var(--h-s-3); font-size: var(--h-fs-xs); min-height: 0; line-height: 1.45;
             letter-spacing: var(--h-tracking-wide); text-transform: uppercase; white-space: nowrap; }
/* ...but `min-height: 0` opts out of the 44px floor, and on a phone that is not
   a style choice, it is a 27px tap target (06/09/2026: the Delete on the ECR
   review screen measured 71 x 27.4). Matching a badge box only matters on a
   pointer device; two ECR surfaces had already re-added the floor by hand,
   which is the tell that the base rule was wrong. Restore it here so nothing
   else has to remember. */
@media (max-width: 768px) {
  .h-btn--xs { min-height: 44px; }
}

/* ---------- Chart axis: a label under every column (06/09/2026) -------------
   Purely additive. The base .h-chart__x is left-aligned and meant for the
   occasional marker — one date every seventh bar. When every column carries a
   label it has to be centred under its own bar, and it needs room for two
   lines: the weekday on every column, the date only where the week turns.  */
.h-chart--axis .h-chart__bars { margin-bottom: var(--h-s-6); }
.h-chart__x--each { left: 50%; transform: translateX(-50%); text-align: center; line-height: 1.35; }
.h-chart__dow { display: block; font-weight: var(--h-fw-semibold); color: var(--h-grey-70); }
.h-chart__date { display: block; color: var(--h-grey-50); }

/* ---------- .h-col--optional: a table column the phone can do without -------
   Purely additive (06/09/2026). Added for the Call report's assignee table,
   which gained two time-to-close columns: on a 390px screen six columns turn
   into a horizontal scroll and the last two get clipped. Mark the columns that
   are detail rather than substance — the header cell AND every body cell — and
   the phone falls back to the layout it had before. The aggregate figures stay
   visible in the tiles above, so nothing is only-on-desktop. */
@media (max-width: 640px) {
  .h-col--optional { display: none; }
}

/* ---------- Condition report primitives (ECR → Studio port) 06/09/2026 ------
   Purely additive — nothing above is changed. These are the ten patterns the
   ECR spec (studio/spec/ecr/01_screens.md §11.9) found had no existing .h-*
   equivalent. Names are deliberately feature-neutral, not .h-ecr-*: the same
   shapes are wanted elsewhere (.h-evidence is a before/after reading,
   .h-commitbar is any sticky commit bar), and the file's convention since
   06/09/2026 is to promote app-specific classes to neutral names rather than
   make a second app borrow the first app's prefix.

   Phone first throughout. ECR is used one-handed, standing in a property,
   between inspections; the desktop layout is the secondary case.
   -------------------------------------------------------------------------- */

/* === 1. .h-roomgrid — the NSW Schedule 2 room grid ==========================
   A per-room card with a tinted header band and a Y/N/comment table inside it.
   Used by the report grid and by carry-forward, which share a row shape.

   The desktop table is genuinely a table — seven columns of one-word answers
   read as a grid and nothing else. Below 768px it stops being one: the row
   becomes a three-column block card so each Y/N control keeps its own caption
   above it. That is the whole point of the rewrite. The old stylesheet stacked
   the Y/N cells inline and printed the caption from attr(data-label), but the
   template never emitted data-label — so on an iPhone the Clean / Undamaged /
   Working controls sat side by side with no captions at all and Michelle had
   to count columns. data-label is now REQUIRED on every stacking cell; the
   guard at the end of the phone block makes a missing one visible instead of
   silent. */
.h-roomgrid {
  background: var(--h-white);
  border: 1px solid var(--h-grey-10);
  border-radius: var(--h-radius);
  overflow: hidden;
  margin-bottom: var(--h-s-4);
  box-shadow: var(--h-shadow-sm);
}
.h-roomgrid__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--h-s-3);
  padding: var(--h-s-3) var(--h-s-4);
  background: var(--h-blue-10);
  border-bottom: 1px solid var(--h-grey-10);
}
.h-roomgrid__name {
  margin: 0;
  font-size: var(--h-fs-base);
  font-weight: var(--h-fw-bold);
  letter-spacing: var(--h-tracking-tight);
  color: var(--h-blue);
}

/* The navy band above already carries the room, so the column headings inside
   it stay quiet — a navy .h-table header repeated once per room would make the
   page a stack of navy bars and break 60/30/10. */
.h-roomgrid__table { margin: 0; }
.h-roomgrid__table th {
  background: var(--h-paper);
  color: var(--h-grey-70);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-semibold);
  text-transform: uppercase;
  letter-spacing: var(--h-tracking-wide);
  padding: var(--h-s-2) var(--h-s-3);
  border-bottom: 1px solid var(--h-grey-10);
}
.h-roomgrid__table td {
  padding: var(--h-s-2) var(--h-s-3);
  vertical-align: top;
  border-bottom: 1px solid var(--h-grey-10);
}
.h-roomgrid__table tbody tr:last-child td { border-bottom: 0; }
.h-roomgrid__table tr:hover td { background: transparent; }
.h-roomgrid .h-select {
  padding: var(--h-s-2) var(--h-s-3);
  font-size: var(--h-fs-sm);
  min-width: 96px;
}

/* Schedule 2 column widths. Scoped to .h-roomgrid on purpose — "sub" and "yn"
   mean nothing on any other table, and a bare .h-col--yn utility would be a
   width with no subject. */
.h-roomgrid .h-col--sub {
  width: 28%;
  font-weight: var(--h-fw-semibold);
  color: var(--h-blue);
}
.h-roomgrid .h-col--yn       { width: 6%; }
.h-roomgrid .h-col--disc     { width: 12%; }
.h-roomgrid .h-col--resolved { width: 16%; }
.h-roomgrid .h-col--copy     { width: 44px; text-align: center; }
/* .h-col--comment takes whatever is left — no width. */

/* Row states. Tint carries the exit tag; it sits on the row so the whole line
   reads as one thing, and it is built on the existing soft tokens — no new
   colours. */
/* Tint sits on the ROW, not the cells: .h-table paints td on hover, which
   would otherwise wipe the tag colour off the line you are pointing at. */
.h-roomgrid__row--cleaning { background: var(--h-warning-soft); }
.h-roomgrid__row--damage   { background: var(--h-error-soft); }
.h-roomgrid__row.is-uncertain .h-col--sub { box-shadow: inset 3px 0 0 var(--h-warning); }
.h-roomgrid__row.is-empty .h-col--sub {
  color: var(--h-grey-50);
  font-weight: var(--h-fw-regular);
  font-style: italic;
}

@media (max-width: 768px) {
  .h-roomgrid__table thead { display: none; }
  .h-roomgrid__table,
  .h-roomgrid__table tbody,
  .h-roomgrid__table td { display: block; width: 100%; }

  /* The Y/N answers sit in a band, each under its own caption; everything else
     spans the full width.

     06/09/2026 — this was `repeat(3, minmax(0, 1fr))`, which forced all three
     answers into one 332px band on a 390px phone: each group got 102.7px, so
     each of its three options measured 30.9 x 44. That is 30% under the 44px
     floor D4/T9 asks for, on the control a property manager taps most, with
     one hand, standing up — the ergonomics this port was justified on.
     minmax(0, 1fr) is the culprit: a 0 minimum lets a track shrink below the
     size of the thing in it, silently.

     auto-fit + a REAL minimum (3 x 44px option + hairlines) lets the band
     reflow instead: two groups per row at 390-430px (160px each, so ~53 x 44
     per option), three across from ~520px, and the desktop table is untouched
     because none of this applies above 768px. */
  .h-roomgrid__table tbody tr {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--h-s-2) var(--h-s-3);
    padding: var(--h-s-3);
    border-bottom: 1px solid var(--h-grey-10);
  }
  .h-roomgrid__table td { padding: 0; border-bottom: 0; }
  .h-roomgrid .h-col--sub,
  .h-roomgrid .h-col--comment,
  .h-roomgrid .h-col--disc,
  .h-roomgrid .h-col--resolved,
  .h-roomgrid .h-col--copy { grid-column: 1 / -1; width: auto; }
  .h-roomgrid .h-col--yn { grid-column: auto; width: auto; }

  .h-roomgrid .h-col--sub {
    font-size: var(--h-fs-base);
    line-height: var(--h-lh-snug);
    margin-bottom: var(--h-s-1);
  }
  /* The caption every control must have. */
  .h-roomgrid__table td[data-label]::before {
    content: attr(data-label);
    display: block;
    margin-bottom: var(--h-s-1);
    font-size: var(--h-fs-xs);
    font-weight: var(--h-fw-semibold);
    text-transform: uppercase;
    letter-spacing: var(--h-tracking-wide);
    color: var(--h-grey-50);
  }
  .h-roomgrid .h-col--sub[data-label]::before { content: none; }
  .h-roomgrid .h-select { padding: var(--h-s-3) var(--h-s-4); font-size: var(--h-fs-base); min-height: 44px; }
  /* The uncertain marker runs down the whole block card here, not one cell. */
  .h-roomgrid__row.is-uncertain { box-shadow: inset 3px 0 0 var(--h-warning); }
  .h-roomgrid__row.is-uncertain .h-col--sub { box-shadow: none; }
  .h-roomgrid .h-col--copy { text-align: left; }
  .h-roomgrid .h-col--copy .h-btn,
  .h-roomgrid__head .h-btn { min-height: 44px; }
  .h-roomgrid .h-col--resolved .h-pe-check { min-height: 44px; font-size: var(--h-fs-base); }
  .h-roomgrid .h-col--resolved .h-pe-check input { width: 22px; height: 22px; }

  /* A Y/N cell with no data-label is the defect this component exists to kill.
     Leave it visible rather than silent — an unlabelled control in a property
     is worse than an ugly one. */
  .h-roomgrid .h-col--yn:not([data-label]) { outline: 2px dashed var(--h-error); }
}

/* === 2. .h-segmented--yn — a two-option answer, not a dropdown ==============
   Clean / Undamaged / Working are yes-or-no. A <select> costs a tap, a native
   sheet, a scroll and a confirm for a binary answer; two buttons cost one tap.
   Sized down to sit in a table cell on desktop, 44px and full width on a
   phone. Works with <button> (mark .is-active) or with a <label> wrapping a
   hidden radio, which is what a form post wants. A third option ("—", clear)
   fits without any change: the columns are auto-flow. */
.h-segmented--yn {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  width: 100%;
  max-width: 108px;
}
.h-segmented--yn .h-segmented__option {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 32px;
  padding: var(--h-s-1) var(--h-s-2);
  position: relative;
}
.h-segmented--yn .h-segmented__option input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
.h-segmented--yn .h-segmented__option:has(input:checked) {
  background: var(--h-blue);
  color: var(--h-white);
}
@media (max-width: 768px) {
  .h-segmented--yn { max-width: none; }
  /* min-WIDTH as well as min-height (06/09/2026). A 44px floor on one axis is
     not a 44px tap target: the height was right and the width was 30.9px. If a
     future container is too narrow to give every option its 44px the group now
     overflows visibly rather than shrinking silently, which is the failure you
     want — you can see it in a screenshot. */
  .h-segmented--yn .h-segmented__option {
    min-width: 44px;
    min-height: 44px;
    font-size: var(--h-fs-base);
  }
}
/* Every segmented option is a tap target, not just the Y/N ones. 44px is the
   floor for anything used one-handed in a property. */
@media (max-width: 768px) {
  .h-segmented__option {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
  }
}

/* === 3. .h-cellinput — a borderless textarea inside a table cell ============
   The comment column is the only free-text field in a row of one-word answers,
   so it stays invisible until you touch it: transparent, no resize handle, no
   scrollbar (the JS grows it to scrollHeight). On a phone it becomes the
   primary edit target, so it gets a real border and a 44px floor. */
.h-cellinput {
  width: 100%;
  min-height: 2rem;
  padding: var(--h-s-2);
  font-family: var(--h-font-sans);
  font-size: var(--h-fs-sm);
  line-height: var(--h-lh-snug);
  color: var(--h-ink);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--h-radius);
  resize: none;
  overflow: hidden;
}
.h-cellinput:hover { background: var(--h-paper); }
.h-cellinput:focus {
  outline: none;
  background: var(--h-white);
  border-color: var(--h-cyan);
  box-shadow: var(--h-focus-glow);
}
.h-cellinput:disabled { background: var(--h-paper); color: var(--h-grey-70); }

/* A .h-textarea the script grows to fit: no handle, no scrollbar, no 120px
   floor. The full-size sibling of .h-cellinput — same behaviour, but it keeps
   its border because it is the main field on its screen, not a table cell. */
.h-textarea--auto { min-height: 0; resize: none; overflow: hidden; }
@media (max-width: 768px) {
  .h-cellinput {
    min-height: 44px;
    font-size: var(--h-fs-base);
    background: var(--h-white);
    border-color: var(--h-grey-10);
  }
}

/* === 4. .h-notice--muted / --check + a list and footnote body ===============
   .h-notice already carries a status colour on a left rule. These two add the
   remaining tones the attendance screen needs — muted for "nothing here yet",
   check for "read these before you file it" — and a body that can hold a list
   of flagged items plus the line explaining why they were flagged. The list
   itself is .h-att__list / .h-att__row, unchanged, with a stacked variant for
   a headline over its reason. */
.h-notice--muted {
  border-left-color: var(--h-grey-30);
  background: var(--h-grey-10);
  color: var(--h-grey-70);
}
.h-notice--check {
  border-left-color: var(--h-warning);
  background: var(--h-warning-soft);
  color: var(--h-warning-ink);
}
.h-notice__foot {
  margin: var(--h-s-3) 0 0;
  padding-top: var(--h-s-3);
  border-top: 1px solid var(--h-grey-30);
  font-size: var(--h-fs-xs);
  line-height: var(--h-lh-base);
  color: var(--h-grey-70);
}
.h-notice .h-att__list { margin: var(--h-s-2) 0 0; }
.h-notice .h-att__row { border-left: 0; padding-left: 0; border-bottom-color: var(--h-grey-30); }
/* order: 0 is not redundant — the base .h-att__row sends .h-att__text to
   order 3 below 640px so a count and an action can lead. A stacked row is a
   headline over its reason; the headline has to stay first. */
.h-att__row--stack { flex-direction: column; align-items: flex-start; gap: var(--h-s-1); }
.h-att__row--stack .h-att__text { order: 0; flex: 1 1 auto; width: 100%; font-weight: var(--h-fw-semibold); }
.h-att__row--stack .h-textarea,
.h-att__row--stack .h-evidence { width: 100%; }
.h-att__why { font-size: var(--h-fs-sm); line-height: var(--h-lh-snug); color: var(--h-grey-70); }

/* === 5. .h-charcount — a live counter beside a .h-textarea ==================
   Pairs with a label row. Tabular figures so the number doesn't jiggle the
   row on every keystroke; warning ink, not error, once it is over the limit —
   being over a paste limit is a nuisance, not a failure. */
.h-charcount {
  font-size: var(--h-fs-sm);
  color: var(--h-grey-50);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.h-charcount--over { color: var(--h-warning-ink); font-weight: var(--h-fw-semibold); }

/* .h-labelbar — the row that pairs a field label with a live counter or state
   on the right, above the control they belong to. The counter has to sit
   beside the label, not under the box: under the box it is below the fold on
   a long note, which is exactly when the count matters. Below 640px the
   label, its hint and the count fought each other for one line and wrapped
   through each other, so the count takes its own row. */
.h-labelbar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--h-s-3);
  flex-wrap: wrap;
  margin-bottom: var(--h-s-1);
}
.h-labelbar .h-label { margin-bottom: 0; }
@media (max-width: 640px) {
  .h-labelbar { display: block; }
  .h-labelbar .h-charcount { display: block; margin-top: var(--h-s-1); }
}

/* === 6. .h-divider--label — "— or —" ======================================== */
.h-divider--label {
  display: flex;
  align-items: center;
  gap: var(--h-s-3);
  border: 0;
  margin: var(--h-s-4) 0;
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-semibold);
  text-transform: uppercase;
  letter-spacing: var(--h-tracking-wide);
  color: var(--h-grey-50);
}
.h-divider--label::before,
.h-divider--label::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: var(--h-grey-10);
}

/* === 7. .h-optional-panel — an alternate path through a form ================
   A dashed edge says "you can skip this" without a colour saying "warning".
   Holds a .h-choices list of candidate records, or a second way of supplying
   the same thing (link an existing report, or upload the PDF). */
.h-optional-panel {
  padding: var(--h-s-4);
  margin: 0 0 var(--h-s-5);
  background: var(--h-paper);
  border: 1px dashed var(--h-grey-30);
  border-radius: var(--h-radius);
}
.h-optional-panel__title {
  margin: 0 0 var(--h-s-2);
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-semibold);
  color: var(--h-blue);
}
.h-optional-panel .h-choices { margin-bottom: 0; }

/* A numbered .h-filelist — the upload queue is ordered, and the order is the
   order the recordings get transcribed in, so it has to be on screen. */
.h-filelist--numbered .h-filelist__row { justify-content: flex-start; gap: var(--h-s-3); }
.h-filelist__index {
  flex: none;
  min-width: 1.75rem;
  font-weight: var(--h-fw-bold);
  color: var(--h-grey-50);
  font-variant-numeric: tabular-nums;
}
.h-filelist__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-filelist__size { flex: none; font-size: var(--h-fs-xs); color: var(--h-grey-50); }
@media (max-width: 768px) {
  .h-filelist--numbered .h-filelist__row { flex-wrap: wrap; }
  .h-filelist--numbered .h-filelist__row .h-btn { min-height: 44px; }
}

/* === 8. .h-stat--warning-soft / --error-soft + the panel button =============
   Soft-tinted .h-stat tiles, for a count that is itself the problem (items
   needing cleaning, items needing repair). Tint and ink only — same box.
   .h-btn--panel is the wide, wrapping, left-aligned button that carries a
   sentence rather than a verb ("N items need checking against the ingoing
   report"); .h-btn-warning is its amber skin. It is a .h-btn because it is
   tapped — BRAND.md: a tappable thing is never a badge or a tile. */
.h-stat--warning-soft { background: var(--h-warning-soft); border-color: var(--h-warning-soft); }
.h-stat--warning-soft .h-stat__value,
.h-stat--warning-soft .h-stat__label { color: var(--h-warning-ink); }
.h-stat--error-soft { background: var(--h-error-soft); border-color: var(--h-error-soft); }
.h-stat--error-soft .h-stat__value,
.h-stat--error-soft .h-stat__label { color: var(--h-error-ink); }

.h-btn--panel {
  display: flex;
  align-items: center;
  gap: var(--h-s-3);
  width: 100%;
  text-align: left;
  padding: var(--h-s-4) var(--h-s-5);
  font-weight: var(--h-fw-regular);
  line-height: var(--h-lh-snug);
  letter-spacing: var(--h-tracking-body);
  text-transform: none;
  white-space: normal;
}
.h-btn--panel .h-btn__go { flex: none; font-weight: var(--h-fw-semibold); }
/* On a phone the sentence needs the full width, so the call to action drops
   to its own line underneath rather than squeezing the words into a column. */
@media (max-width: 640px) {
  .h-btn--panel { flex-wrap: wrap; }
  .h-btn--panel .h-btn__go { width: 100%; }
}
.h-btn-warning,
.h-btn--warning {
  background: var(--h-warning-soft);
  color: var(--h-warning-ink);
  border: 1px solid var(--h-warning);
}
.h-btn-warning:hover,
.h-btn--warning:hover {
  background: var(--h-white);
  color: var(--h-warning-ink);
  border-color: var(--h-warning);
}

/* === 9. .h-sectionrule — a label with a hairline to the right edge ==========
   Groups rows under a heading without spending a card on it. Used for the room
   name above a list of items. */
.h-sectionrule {
  display: flex;
  align-items: center;
  gap: var(--h-s-3);
  margin: 0 0 var(--h-s-3);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-bold);
  text-transform: uppercase;
  letter-spacing: var(--h-tracking-wide);
  color: var(--h-blue);
}
.h-sectionrule::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: var(--h-grey-10);
}

/* Two row states for .h-att__row. .is-flash marks the row you were just sent
   to; .is-dropped is a row you removed — it stays on screen, faded, with its
   editable parts gone, so you can see what you took out. */
.h-att__row.is-flash { background: var(--h-warning-soft); box-shadow: var(--h-shadow); }
.h-att__row.is-dropped { opacity: 0.45; }
.h-att__row.is-dropped .h-cellinput,
.h-att__row.is-dropped .h-textarea,
.h-att__row.is-dropped .h-evidence { display: none; }

/* === 10. .h-evidence — the Ingoing / Final label column =====================
   A fixed label column beside a value, stacked. Two readings of the same thing
   at two points in time, side by side and always on screen: what was recorded
   going in, what was recorded at the end. Deliberately quiet — the eye should
   land on the editable line above and come down here only to check it.
   Nothing about it is ECR-specific: any before/after pair fits (appraisal then
   sale price, quoted then invoiced, first then latest reading). */
.h-evidence {
  margin-top: var(--h-s-2);
  padding-top: var(--h-s-2);
  border-top: 1px solid var(--h-grey-10);
}
.h-evidence__row {
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 1fr);
  gap: var(--h-s-2);
  align-items: baseline;
}
.h-evidence__row + .h-evidence__row { margin-top: var(--h-s-1); }
.h-evidence__label {
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-semibold);
  text-transform: uppercase;
  letter-spacing: var(--h-tracking-wide);
  color: var(--h-grey-50);
}
.h-evidence__value {
  margin: 0;
  font-size: var(--h-fs-sm);
  line-height: var(--h-lh-snug);
  color: var(--h-grey-70);
}
.h-evidence__value--now { color: var(--h-ink); }
.h-evidence__value--empty { font-style: italic; color: var(--h-grey-50); }

/* === 11. .h-commitbar — the sticky bottom commit bar ========================
   One irreversible action, always reachable, with the save state beside it.
   Not .h-sign__bar, which is a navy header band. Below 860px the buttons go
   full width — this is the last thing tapped before walking out of a property,
   and it should be a thumb-sized target. */
.h-commitbar {
  position: sticky;
  bottom: 0;
  z-index: 2;
  margin-top: var(--h-s-6);
  background: var(--h-white);
  border-top: 2px solid var(--h-blue);
  box-shadow: var(--h-shadow-lg);
}
.h-commitbar__in {
  max-width: var(--h-container);
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--h-s-4);
  flex-wrap: wrap;
  padding: var(--h-s-3) var(--h-s-4);
}
.h-commitbar__state { font-size: var(--h-fs-sm); color: var(--h-grey-70); }
@media (max-width: 900px) {
  .h-commitbar__in { padding: var(--h-s-2) var(--h-s-3); }
  .h-commitbar__in .h-btn { flex: 1 1 auto; min-height: 48px; }
}

/* .h-sr-only — text for screen readers only. A column of icon-only buttons
   still needs a heading; this is where it goes, rather than an empty <th>. */
.h-sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* === 12. .h-table--stack — a table that becomes card rows on a phone ========
   Added 06/09/2026 with the ECR list. A .h-table of records side-scrolls on an
   iPhone: the ECR dashboard did exactly that, and the columns that fell off the
   right were status and who it belonged to — the two the property manager was
   scanning for. Below 640px each row becomes a bordered card, the first cell is
   its heading, and every other cell carries its column name from data-label.

   Same discipline as .h-roomgrid: data-label is REQUIRED on every cell except
   the first, and a missing one is outlined rather than silently unlabelled. */
.h-table--stack .h-table__lead { font-weight: var(--h-fw-semibold); color: var(--h-blue); }
@media (max-width: 640px) {
  .h-table--stack thead { display: none; }
  .h-table--stack,
  .h-table--stack tbody,
  .h-table--stack td { display: block; width: 100%; }
  .h-table--stack tbody tr {
    display: block;
    margin-bottom: var(--h-s-3);
    padding: var(--h-s-3) var(--h-s-4);
    background: var(--h-white);
    border: 1px solid var(--h-grey-10);
    border-radius: var(--h-radius);
    box-shadow: var(--h-shadow-sm);
  }
  .h-table--stack tbody tr:hover td { background: transparent; }
  .h-table--stack td {
    padding: var(--h-s-1) 0;
    border-bottom: 0;
    display: flex;
    gap: var(--h-s-3);
    align-items: baseline;
    justify-content: space-between;
  }
  .h-table--stack td[data-label]::before {
    content: attr(data-label);
    flex: none;
    font-size: var(--h-fs-xs);
    font-weight: var(--h-fw-semibold);
    text-transform: uppercase;
    letter-spacing: var(--h-tracking-wide);
    color: var(--h-grey-50);
  }
  .h-table--stack .h-table__lead {
    display: block;
    font-size: var(--h-fs-base);
    line-height: var(--h-lh-snug);
    padding-bottom: var(--h-s-2);
    margin-bottom: var(--h-s-2);
    border-bottom: 1px solid var(--h-grey-10);
  }
  .h-table--stack .h-table__act { justify-content: stretch; padding-top: var(--h-s-3); }
  .h-table--stack .h-table__act .h-btn { width: 100%; min-height: 44px; }
  /* The .h-roomgrid rule, for the same reason: an unlabelled value in a stack
     of values is a number with no name. */
  .h-table--stack td:not([data-label]):not(.h-table__lead):not(.h-table__act) {
    outline: 2px dashed var(--h-error);
  }
}


/* === 13. .h-roomjump — jump to a room, and fold the ones you are done with ==
   Report 83 is 66,010px tall: 78 phone screens, and "Garage" is 63 swipes from
   the top. A condition report is not read top to bottom — a property manager
   opens it to find ONE room. So the rooms fold, and there is a jump control
   that stays on screen while she scrolls.

   A <select> rather than a scroller of chips: on a phone it opens the native
   wheel, which is one tap and reachable with a thumb, and it does not eat a
   second line of a 390px screen when a property has fourteen rooms. */
.h-roomjump {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: var(--h-s-3);
  padding: var(--h-s-3) 0;
  margin-bottom: var(--h-s-4);
  background: var(--h-paper);
  border-bottom: 1px solid var(--h-grey-10);
}
.h-roomjump__label {
  flex: none;
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-semibold);
  text-transform: uppercase;
  letter-spacing: var(--h-tracking-wide);
  color: var(--h-grey-50);
}
.h-roomjump .h-select { flex: 1 1 auto; min-height: 44px; }
.h-roomjump__fold { flex: none; min-height: 44px; }

/* The room card as a <details>. The head is the <summary>, so the whole band
   is the 44px target rather than a chevron she has to hit. */
.h-roomgrid > summary.h-roomgrid__head {
  cursor: pointer;
  list-style: none;
  min-height: 44px;
}
.h-roomgrid > summary.h-roomgrid__head::-webkit-details-marker { display: none; }
.h-roomgrid__fold {
  flex: none;
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-semibold);
  color: var(--h-blue);
}
.h-roomgrid[open] > summary .h-roomgrid__fold::after { content: "\2212"; }
.h-roomgrid:not([open]) > summary .h-roomgrid__fold::after { content: "\002B"; }

/* === 14. .h-searchbox — filter a list in place ==============================
   Twenty-nine reports on one page and no way to find the one you did this
   morning except by reading every address. Client-side: the rows are already
   on the phone, and a round trip on 4G to filter them is a round trip for
   nothing. */
.h-searchbox {
  display: flex;
  align-items: center;
  gap: var(--h-s-3);
  margin-bottom: var(--h-s-5);
}
.h-searchbox .h-input { flex: 1 1 auto; min-height: 44px; margin: 0; }
.h-searchbox__count {
  flex: none;
  font-size: var(--h-fs-sm);
  color: var(--h-grey-50);
  white-space: nowrap;
}
.h-searchbox__empty {
  font-size: var(--h-fs-sm);
  color: var(--h-grey-70);
  padding: var(--h-s-5) 0;
}

/* A filtered-out row has to actually go. .h-table--stack sets display:block on
   the table, the tbody and every row for the phone layout, and .h-sectionrule
   is display:flex — all of which beat the UA stylesheet [hidden] rule. Same
   trap as .h-label[hidden]: the element stays on screen and the code that
   hid it looks correct. */
.h-table[hidden],
.h-table--stack tbody tr[hidden],
.h-sectionrule[hidden] { display: none !important; }
/* .h-btn is display:inline-flex, so a button toggled with [hidden] stayed on
   screen — the Call Log's "Add a name" hint showed under every real name, and
   Studio's ECR "Copy" button under every empty comment. (07/09/2026) */
.h-btn[hidden] { display: none !important; }

/* ---------- Card modal: phone sheet + pinned actions (07/09/2026) ----------
   Opt-in modifiers for .h-modal--card, added for the Call Log message card.
   Additive only: without .h-modal--sheet the card behaves exactly as before.

   .h-cardm__actionbar  — the stack of primary actions in the side rail.
   .h-modal--sheet      — at phone width the 920px card stops being a dialog
                          cropped to the viewport and becomes a full-height
                          sheet, with the action bar pinned to the bottom edge
                          so "call them back" is always one thumb away. The
                          sheet clears the transform on .h-modal so the fixed
                          bar positions against the viewport, not the card. */
.h-cardm__actionbar { display: flex; flex-direction: column; gap: var(--h-s-2); }
.h-cardm__actionbar:empty { display: none; }

@media (max-width: 768px) {
  .h-modal--sheet {
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    transform: none;
    width: 100%;
    max-width: 100%;
    height: 100%;
    max-height: 100%;
    border-radius: 0;
    overscroll-behavior: contain;
  }
  /* Clears a two-row action bar — the last thing in the rail must not sit
     under it. */
  .h-modal--sheet .h-cardm__side {
    padding-bottom: calc(var(--h-s-10) + var(--h-s-10));
  }
  .h-modal--sheet .h-cardm__actionbar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    flex-direction: row;
    flex-wrap: wrap;
    padding: var(--h-s-3) var(--h-s-4);
    padding-bottom: calc(var(--h-s-3) + env(safe-area-inset-bottom, 0px));
    background: var(--h-white);
    border-top: 1px solid var(--h-grey-10);
    box-shadow: var(--h-shadow-lg);
    z-index: 2;
  }
  .h-modal--sheet .h-cardm__actionbar .h-btn { flex: 1 1 40%; }
}

/* ---------- Modal stacked over another modal (07/09/2026) ------------------
   A confirm opened FROM an already-open .h-modal. Both sat at --h-z-modal, so
   the winner was whichever came later in the DOM — in the Call Log that was
   the message card, which painted over its own Rex confirm: you pressed
   "Rex Appraisal" and got a dim screen you could not click through. Order in
   the document decides a tie, and relying on that is how it broke; these say
   it out loud. Additive — only a dialog that opts in moves up.

   The backdrop keys off --h-z-modal, not --h-z-backdrop: it has to cover the
   modal it was opened from, or the dialog paints on top while the modal
   underneath still wins every click — backdrop-to-dismiss does nothing and the
   fields behind stay editable. Same bug wearing a different hat. */
.h-modal-backdrop--over { z-index: calc(var(--h-z-modal) +  5); }
.h-modal--over          { z-index: calc(var(--h-z-modal) + 10); }

/* ---------- Presentation deck (added 07/09/2026) ---------------------------
   Full-screen slide viewer, first used by Studio /agenda/present. Opened on an
   iPad in Safari, AirPlayed to the office screen, clicked through during the
   Tuesday sales meeting — so it is read from four metres by six people, not at
   arm's length.

   Two deliberate choices:
   • Sizes are viewport-relative (vh), not breakpoint-switched. The same deck
     has to read on a 12.9" iPad and a 65" TV; a headline number is a fixed
     share of the screen's height on both. clamp() only stops small text
     collapsing on a phone-width window.
   • Weight extremes only — the light end against 700, nothing in between. A
     middling 600 at wall scale reads as neither light nor emphatic. The light
     end is --present-fw-light and it is 300 on this deck, not the 200 of the
     navy original; see the token for why the polarity flip forced that.

   White is the field and navy is the type — flipped from the original navy
   deck on 08/09/2026 (the palette block below says why). Navy still carries
   every mark on the slide, so navy stays the dominant colour under 60/30/10;
   cyan is down to a single decorative use, the progress rail, which keeps it
   comfortably inside its 10%.
   -------------------------------------------------------------------------- */
/* THE PALETTE LIVES HERE — eight tokens, consumed by every .h-present* rule
   below. There are no bare colour tokens further down: a colour change on this
   deck is one block to read and one block to edit.

   Why light. The deck was navy field / white type until 08/09/2026. The
   meeting room's lights glare off a dark screen, so from four metres the wall
   TV washed out. The sales team asked for the inverse at the 08/09 meeting and
   MG agreed. Light is the only mode — there is no toggle and no dark variant
   to keep in step, so nothing here needs to work on both.

   CYAN IS NOT TYPE ON THIS DECK. Harcourts Cyan on white is ~2.4:1 — it fails
   WCAG for body text (4.5:1) AND for large text (3:1), and on a glare-lit wall
   TV it would read worse than the navy deck this replaced, which would undo
   the entire point of the change. So the eyebrow and a figure's unit are navy
   now. Their hierarchy was never coming from colour: the eyebrow separates by
   being semibold, uppercase and wide-tracked, the unit by being bold and
   0.24em, both against a 23vh extralight figure. Cyan survives as
   --present-accent on exactly one element, the progress rail — a decorative
   non-text bar, where contrast ratios do not apply and the brand accent still
   lands on every slide. Do not "restore" cyan to the eyebrow. MG 08/09/2026. */
.h-present {
  --present-bg:     var(--h-white);   /* the field */
  --present-ink:    var(--h-blue);    /* all primary type — figure, title, statement, headline, rows, stats */
  --present-muted:  var(--h-grey-70); /* secondary type — notes, subs, the fixed chrome */
  --present-faint:  var(--h-grey-70); /* the jump panel's hint line — quieter in ROLE than muted, but
                                         not in contrast: grey-50 on the pale panel measured ~2.9:1 and
                                         went soft on the wall, which is the fault this whole theme
                                         exists to fix. Same token as muted; the weight carries it. */
  --present-line:   var(--h-grey-30); /* row hairlines and jump-item borders */
  --present-panel:  var(--h-blue-10); /* the jump overlay's field */
  --present-raise:  var(--h-white);   /* a jump item lifting off that field */
  --present-accent: var(--h-cyan);    /* the progress rail ONLY — see above */

  /* The light end of the weight pairing. 300, not the 200 this deck used when
     it was navy. Same ink at the same weight does NOT render the same on both
     polarities: light type on a dark field optically thickens, dark type on a
     light field thins, so the 200 that read as elegant in white-on-navy came
     back as a hairline in navy-on-white — worst on the 23vh figure, where a
     thin stroke against glare is exactly what this theme set out to fix. The
     section note above still holds; the extremes are simply 300/700 now, which
     is still a two-step gap and nothing middling. MG 08/09/2026. */
  --present-fw-light: var(--h-fw-light);

  margin: 0;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  background: var(--present-bg);
  color: var(--present-ink);
  font-family: var(--h-font-display);
  overscroll-behavior: none;
  touch-action: manipulation;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

/* The click/tap target. Left half = back, right half = forward; the halves are
   handled in JS off clientX rather than as two absolutely-positioned hit areas,
   so a slide's own links stay clickable. */
.h-present__stage {
  position: fixed;
  inset: 0;
}

/* Anchored to a fixed line, NOT centred. Centring made every slide's content
   sit at a height determined by its own length, so clicking through a run of
   appraisals or stock made the address bounce up and down — a two-line address
   or a closing note shifted everything above it by up to 46px. The section
   label, the address and the figures now land at the same height on every
   slide; only the content differs. MG 08/09/2026. */
.h-present__slide {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  padding: 28vh 9vw 8vh;
  opacity: 0;
  visibility: hidden;
  transition: opacity 120ms var(--h-ease);
}
.h-present__slide[data-active] {
  opacity: 1;
  visibility: visible;
}

.h-present__eyebrow {
  margin: 0 0 var(--h-s-4);
  font-size: clamp(0.75rem, 1.8vh, 1.5rem);
  font-weight: var(--h-fw-semibold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  color: var(--present-ink);          /* navy, not cyan — see the palette block */
}

/* The headline number. 23vh — a fifth of the screen, legible across a room. */
.h-present__figure {
  margin: 0;
  font-size: 23vh;
  font-weight: var(--present-fw-light);
  line-height: 0.84;
  letter-spacing: -0.045em;
  color: var(--present-ink);
  font-variant-numeric: tabular-nums lining-nums;
}
.h-present__figure-unit {
  margin-left: 0.22em;
  font-size: 0.24em;
  font-weight: var(--h-fw-bold);
  letter-spacing: var(--h-tracking-tight);
  color: var(--present-ink);          /* navy, not cyan — the bold weight is what marks it as a unit */
}

/* Two lines of height are RESERVED whether the address needs them or not.
   "214 / 24 College Avenue, Shellharbour City Centre" wraps to two lines and
   "3 Lavis Drive, Mount Warrigal" does not; without a reserved block the
   figures underneath jump a line between one slide and the next. Everything
   below the address now sits at the same height on every slide. MG 08/09/2026. */
.h-present__label {
  margin: var(--h-s-5) 0 0;
  max-width: 20ch;
  min-height: calc(2 * 1.04em);
  font-size: clamp(1.4rem, 5vh, 4.25rem);
  font-weight: var(--h-fw-bold);
  line-height: 1.04;
  letter-spacing: var(--h-tracking-tight);
  color: var(--present-ink);
}

/* A ledger label is normally an address, and 20ch breaks a street-and-suburb
   over three lines. Wider, and still short enough to stay one thought. */
.h-present__label--wide { max-width: 34ch; }

.h-present__note {
  margin: var(--h-s-6) 0 0;
  max-width: 44ch;
  font-size: clamp(0.95rem, 2.4vh, 2rem);
  font-weight: var(--h-fw-light);
  line-height: var(--h-lh-snug);
  letter-spacing: var(--h-tracking-body);
  color: var(--present-muted);
}

/* Section opener. Mixed weight inside one sentence is the brand's headline
   habit — wrap the words that carry the point in <strong>. */
.h-present__title {
  margin: 0;
  max-width: 18ch;
  font-size: clamp(2.25rem, 12vh, 10rem);
  font-weight: var(--present-fw-light);
  line-height: 0.96;
  letter-spacing: -0.035em;
  color: var(--present-ink);
}
.h-present__statement {
  margin: 0;
  max-width: 24ch;
  font-size: clamp(1.75rem, 8.5vh, 7rem);
  font-weight: var(--present-fw-light);
  line-height: 1.04;
  letter-spacing: -0.03em;
  color: var(--present-ink);
}
.h-present__title strong,
.h-present__statement strong {
  font-weight: var(--h-fw-bold);
}

/* A short ledger — name on the left, figure on the right, hairline between.
   Not a table, not cards; the rule does the alignment work. */
.h-present__rows {
  margin: var(--h-s-6) 0 0;
  padding: 0;
  list-style: none;
  max-width: 74vw;
}
.h-present__rows + .h-present__note { margin-top: var(--h-s-8); }
.h-present__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--h-s-8);
  padding: 1.5vh 0;
  border-bottom: 1px solid var(--present-line);
}
.h-present__row:last-child { border-bottom: 0; }
.h-present__row-name,
.h-present__row-value {
  font-size: clamp(1.05rem, 4.4vh, 3.5rem);
  line-height: 1.1;
  letter-spacing: var(--h-tracking-tight);
  color: var(--present-ink);
}
.h-present__row-name  { font-weight: var(--present-fw-light); }
.h-present__row-value { font-weight: var(--h-fw-bold); flex: none; font-variant-numeric: tabular-nums; }

/* A full ledger under a two-line address ran off the bottom of the slide and
   printed over the meeting date. `stats` has always scaled itself off how many
   numbers it carries; `rows` now does the same, applied by _agenda_slide.html
   at five rows and up.

   The slide's 28vh anchor does NOT move to make room — that anchor is what
   stopped addresses bouncing between slides, and buying space by breaking it
   would trade a rare collision for a fault on every slide. The ledger gets
   denser instead. Shrinking is also the right failure: six rows still readable
   beats six rows where the last one is under the footer. */
.h-present__rows--dense .h-present__row { padding: 0.8vh 0; }
.h-present__rows--dense .h-present__row-name,
.h-present__rows--dense .h-present__row-value {
  font-size: clamp(0.95rem, 3.3vh, 2.6rem);
}
/* The note's normal gap is generous because it usually follows four short
   rows. Behind a dense ledger it is the last thing between the content and
   the footer, so it closes up too. */
.h-present__rows--dense + .h-present__note { margin-top: var(--h-s-5); }

/* Several numbers of EQUAL weight — week / MTD / QTD against target, a
   listing's DOM + enquiries + inspections + offers, this year against last.
   Not a card grid: no boxes, no rules, no fills. The numbers sit on the navy
   and the whitespace between them does the grouping. Added 07/09/2026 for the
   sales-meeting deck.

   Scale is set by how many there are, because a slide carrying two numbers and
   a slide carrying six are not the same slide. Two reads nearly as large as a
   headline figure; six has to come down or it wraps into the note. */
.h-present__stats {
  display: flex;
  flex-wrap: wrap;
  column-gap: 6.5vw;
  row-gap: 4.5vh;
  margin: var(--h-s-6) 0 0;
  padding: 0;
  list-style: none;
  max-width: 82vw;
}
.h-present__stat {
  display: flex;
  flex-direction: column;
  min-width: 11vw;
}
.h-present__stats--lead .h-present__stat  { min-width: 26vw; }
.h-present__stats--dense .h-present__stat { min-width: 22vw; }

.h-present__stat-value {
  font-size: 13vh;
  font-weight: var(--present-fw-light);
  line-height: 0.86;
  letter-spacing: -0.04em;
  color: var(--present-ink);
  font-variant-numeric: tabular-nums lining-nums;
}
.h-present__stats--lead  .h-present__stat-value { font-size: 17vh; }
.h-present__stats--dense .h-present__stat-value { font-size: 9.5vh; }

.h-present__stat-label {
  margin-top: 1.4vh;
  font-size: clamp(0.8rem, 2.5vh, 2rem);
  font-weight: var(--h-fw-bold);
  line-height: 1.1;
  letter-spacing: var(--h-tracking-tight);
  color: var(--present-ink);
}
.h-present__stat-sub {
  margin-top: 0.5vh;
  max-width: 26ch;
  font-size: clamp(0.7rem, 1.95vh, 1.5rem);
  font-weight: var(--h-fw-light);
  line-height: var(--h-lh-snug);
  letter-spacing: var(--h-tracking-body);
  color: var(--present-muted);
}
.h-present__stats + .h-present__note { margin-top: var(--h-s-10); }

/* The record headline — an address, a suburb, an agent's name — above a stat
   strip. Bold where .h-present__title is extralight: this is a label for the
   numbers underneath, not the point of the slide. */
/* Same reserved two lines as .h-present__label, for the same reason: the stock
   run mixes "3 Lavis Drive, Mount Warrigal" with "214 / 24 College Avenue,
   Shellharbour City Centre", and without it the figures below jumped 58px
   between one property and the next. MG 08/09/2026. */
.h-present__headline {
  margin: 0;
  max-width: 36ch;
  min-height: calc(2 * 1.02em);
  font-size: clamp(1.3rem, 5.2vh, 4.25rem);
  font-weight: var(--h-fw-bold);
  line-height: 1.02;
  letter-spacing: var(--h-tracking-tight);
  color: var(--present-ink);
}
.h-present__sub {
  margin: 1.6vh 0 0;
  max-width: 40ch;
  font-size: clamp(0.85rem, 2.7vh, 2.25rem);
  font-weight: var(--h-fw-light);
  line-height: var(--h-lh-snug);
  letter-spacing: var(--h-tracking-body);
  color: var(--present-muted);
}
.h-present__sub + .h-present__stats { margin-top: var(--h-s-6); }

/* Persistent chrome. Deliberately quiet — it is furniture, not content. But on
   the light deck "quiet" is the grey token, not a low opacity: white at 0.5 on
   navy still read from the back of the room, where navy at 0.5 on white goes
   pale and washed out. The lockup keeps a light touch; the meta line and the
   counter dropped their opacity entirely and lean on --present-muted, which is
   quiet by hue rather than by fade. MG 08/09/2026. */
.h-present__mark {
  position: fixed;
  top: 5.5vh;
  left: 9vw;
  height: 2.6vh;
  min-height: 15px;
  width: auto;
  opacity: 1;                         /* no fade: the lockup's office line is cyan, and cyan on
                                         white is already ~2.4:1 — dimming it compounds that.
                                         The mark stays quiet by being 2.6vh tall. */
}
.h-present__meta,
.h-present__counter {
  position: fixed;
  bottom: 5.5vh;
  margin: 0;
  font-size: clamp(0.7rem, 1.55vh, 1.2rem);
  font-weight: var(--h-fw-semibold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  color: var(--present-muted);
}
.h-present__meta    { left: 9vw; }
.h-present__counter { right: 9vw; font-variant-numeric: tabular-nums; }

.h-present__rail {
  position: fixed;
  left: 0;
  bottom: 0;
  width: 0;
  height: 3px;
  background: var(--present-accent);
  transition: width 160ms var(--h-ease);
}

/* Slide-jump overlay ("o"). A pale blue tint rather than the deck's plain
   white, so it still reads as a layer over the meeting rather than as another
   slide that happens to be a grid. */
.h-present-jump {
  position: fixed;
  inset: 0;
  z-index: var(--h-z-modal);
  display: none;
  flex-direction: column;
  padding: 5vh 6vw;
  background: var(--present-panel);
}
.h-present-jump[data-open] { display: flex; }
.h-present-jump__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--h-s-5);
  margin-bottom: var(--h-s-5);
}
.h-present-jump__title {
  margin: 0;
  font-size: clamp(1.25rem, 3.6vh, 2.5rem);
  font-weight: var(--present-fw-light);
  letter-spacing: var(--h-tracking-tight);
  color: var(--present-ink);
}
.h-present-jump__hint {
  margin: 0;
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-semibold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  color: var(--present-faint);
}
.h-present-jump__grid {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: var(--h-s-2);
  align-content: start;
  -webkit-overflow-scrolling: touch;
}
/* Sits on .h-btn .h-btn-ghost — a jump IS a button, per the buttons-vs-pills
   standard. These rules only re-scope it for the overlay panel and let it wrap. */
.h-present-jump__item {
  display: flex;
  align-items: baseline;
  justify-content: flex-start;
  gap: var(--h-s-3);
  width: 100%;
  padding: var(--h-s-3) var(--h-s-4);
  text-align: left;
  white-space: normal;
  font-size: var(--h-fs-base);
  font-weight: var(--h-fw-regular);
  line-height: var(--h-lh-snug);
  letter-spacing: var(--h-tracking-body);
  color: var(--present-ink);
  background: transparent;
  border: 1px solid var(--present-line);
}
/* Hover, focus and "you are here" all lift the item onto white and firm the
   border to navy. That border is deliberately not cyan — a 2.4:1 edge is a
   focus indicator you cannot find on a lit screen, and focus is the one state
   that has to be unmissable. */
.h-present-jump__item:hover,
.h-present-jump__item:focus-visible {
  background: var(--present-raise);
  border-color: var(--present-ink);
  color: var(--present-ink);
}
.h-present-jump__item[aria-current="true"] {
  background: var(--present-raise);
  border-color: var(--present-ink);
  color: var(--present-ink);
}
.h-present-jump__n {
  flex: none;
  min-width: 2.6ch;
  font-weight: var(--h-fw-bold);
  font-variant-numeric: tabular-nums;
  color: var(--present-muted);        /* an index, not a heading — and cyan is not type here */
}
.h-present-jump__close,
.h-present-jump__close:hover {
  color: var(--present-muted);
  background: transparent;
}
/* Hover DARKENS to navy. It used to brighten to white, which on the light deck
   would have hovered the word straight off the panel. */
.h-present-jump__close:hover { color: var(--present-ink); }

@media (prefers-reduced-motion: reduce) {
  .h-present__slide,
  .h-present__rail { transition: none; }
}

/* The cyan underline, re-proportioned for wall scale.
   .h-underline's bar is one cap-height and sits BEHIND the word — the right
   look at 36px. At 12vh the same em ratio paints a solid cyan block through
   the middle of the word, and white on cyan is ~2.1:1: unreadable from four
   metres, which is the only distance this page is ever read from. Scoped to
   the deck so the treatment is unchanged everywhere else.
   Still right on the light deck: the accent word is now navy on white, so the
   thin bar reads as an underline beneath the type instead of a block through
   it — and it is the one place other than the rail where cyan appears. */
.h-present__title .h-underline::after,
.h-present__statement .h-underline::after {
  height: 0.2em;
  bottom: 0.03em;
}

/* ── Email preview (Studio · Sales Meeting) ──────────────────────────────────
   The note to the team, shown in a modal exactly as it will arrive — the same
   HTML send() posts, in a frame so the email's own inline styles cannot leak
   into the page or be restyled by it. Wider than the default .h-modal because
   the email body is built at 600px. */
.h-modal--email { width: min(760px, calc(100vw - var(--h-s-6))); }
.h-email-frame {
  display: block;
  width: 100%;
  height: min(58vh, 560px);
  border: 1px solid var(--h-grey-10);
  border-radius: var(--h-radius);
  background: var(--h-paper);
}
.h-email-to { margin: var(--h-s-2) 0 0; }
/* The stand-in the preview route serves when there is nothing to preview yet. */
.h-preview-empty { margin: 0; padding: var(--h-s-5); font-family: var(--h-font-sans); background: var(--h-paper); }

/* Transcript upload, on the meeting's own page. */
.h-sm-upload { display: grid; gap: var(--h-s-3); margin-top: var(--h-s-3); }
.h-sm-upload textarea { resize: vertical; }
/* A meeting page with only the agenda on it (nobody but a leader gets the
   right-hand column) is one column, not one column and a gap. */
.h-sm-grid--one { grid-template-columns: minmax(0, 1fr); }

/* ==========================================================================
   PHASE 2 — the interactive state matrix                added 14/09/2026
   --------------------------------------------------------------------------
   Everything below is ADDITIVE. No rule above this line had a declaration
   changed, renamed or removed; ~20 apps link this file by symlink, so an
   existing class name is a public API. Where a rule below necessarily changes
   how markup that already exists renders — a disabled input that today looks
   enabled — that is the intended fix, and the pages it moves are named in the
   phase 2 report.

   Conventions kept: authored variants are --modifier, JS-toggled state is
   is-*; keyframes are component-prefixed; every animation has a
   prefers-reduced-motion guard; corners are --h-radius (4px) except true
   circles; anything clickable is a .h-btn.
   ========================================================================== */


/* === A. Field states — .h-input / .h-textarea / .h-select ==================
   Four verdicts a field can carry, in one place. Written as separate rules per
   element because .h-select needs its own chevron and has no real readonly.

   ERROR is [aria-invalid="true"] or --error. VALID is --valid ONLY — never
   :valid, which paints every untouched optional field green on first paint.
   ========================================================================== */

/* -- disabled: the control exists but is not yours to change right now.
      Not for "you may never do this" — leave that control out. No opacity:
      a faded label on a form is unreadable, a grey one is merely quiet. */
.h-input:disabled,
.h-input[aria-disabled="true"],
.h-input--disabled {
  background-color: var(--h-grey-10);
  color: var(--h-grey-70);
  border-color: var(--h-grey-30);
  cursor: not-allowed;
}
.h-textarea:disabled,
.h-textarea[aria-disabled="true"],
.h-textarea--disabled {
  background-color: var(--h-grey-10);
  color: var(--h-grey-70);
  border-color: var(--h-grey-30);
  cursor: not-allowed;
  resize: none;
}
.h-select:disabled,
.h-select[aria-disabled="true"],
.h-select--disabled {
  background-color: var(--h-grey-10);
  color: var(--h-grey-70);
  border-color: var(--h-grey-30);
  cursor: not-allowed;
  /* second chevron, grey — the enabled one hardcodes navy so it cannot be
     recoloured with a variable. Same path, --h-grey-50 (#8a8a8a). */
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path fill='%238a8a8a' d='M0 0l5 6 5-6z'/></svg>");
}

/* -- readonly: the value is real and worth reading, just not editable here.
      Paper, not grey — that is the idiom .h-pe-in[readonly] already set, so
      pm_entry's locked months do not move. Matched on the ATTRIBUTE, not
      :read-only: :read-only also matches every <select> and every file input,
      which would have papered 23 selects and 7 file pickers across Studio.
      Never use readonly to mean disabled — a readonly field still submits. */
.h-input[readonly]:not(:disabled):not(.h-pe-in):not(.h-pe-in--money),
.h-input--readonly {
  background-color: var(--h-paper);
  border-color: var(--h-grey-30);
  cursor: default;
}
.h-textarea[readonly]:not(:disabled),
.h-textarea--readonly {
  background-color: var(--h-paper);
  border-color: var(--h-grey-30);
  cursor: default;
  resize: none;
}
/* <select> has no readonly attribute and :read-only matches every select, so
   the only honest hook is the modifier (plus aria-readonly for AT). A truly
   uneditable select should be :disabled with the value repeated in a hidden
   input — this is for the case where the value must still post. This rule is
   VISUAL ONLY: a keyboard can still change the selection, so the caller must
   also revert the change server-side or on change. */
.h-select--readonly,
.h-select[aria-readonly="true"] {
  background-color: var(--h-paper);
  border-color: var(--h-grey-30);
  cursor: default;
}
/* .h-textarea--auto grows to fit and never shows a handle — keep that when it
   also goes readonly (the resize:none above already agrees; stated so a later
   edit to either rule does not quietly reintroduce a handle). */
.h-textarea--auto[readonly],
.h-textarea--auto.h-textarea--readonly { resize: none; overflow: hidden; }

/* -- error: this field is why the form did not save. Border AND the message in
      .h-field__error — a red border alone is not a reason. */
.h-input[aria-invalid="true"],
.h-input--error,
.h-textarea[aria-invalid="true"],
.h-textarea--error,
.h-select[aria-invalid="true"],
.h-select--error { border-color: var(--h-error); }

.h-input[aria-invalid="true"]:focus,
.h-input--error:focus,
.h-textarea[aria-invalid="true"]:focus,
.h-textarea--error:focus,
.h-select[aria-invalid="true"]:focus,
.h-select--error:focus {
  border-color: var(--h-error);
  box-shadow: var(--h-focus-glow-error);
}

/* -- valid: use ONLY to confirm something the user could not have known was
      right (an ABN that checksummed, an address that matched). Never as the
      resting state of a filled-in field. */
.h-input--valid,
.h-textarea--valid,
.h-select--valid { border-color: var(--h-success); }

.h-input--valid:focus,
.h-textarea--valid:focus,
.h-select--valid:focus {
  border-color: var(--h-success);
  box-shadow: var(--h-focus-glow-success);
}

/* === .h-field — label, control, hint and error as one unit =================
   Use when the label is a SIBLING of the control (<label for> + id), so hint
   and error text can be tied to the input with aria-describedby. Use .h-label
   instead when the label WRAPS its control — that is the older idiom and it is
   not going anywhere.

   Announcing the error: server-rendered text inside role="alert" is never
   announced, because the node already existed when the page loaded. Put a
   persistent aria-live="polite" container on the page and write into it, or
   move focus to the first failed field.

     <div class="h-field h-field--required">
       <label class="h-field__label" for="rent">Weekly rent</label>
       <input class="h-input" id="rent" name="rent" required
              aria-describedby="rent-hint">
       <p class="h-field__hint" id="rent-hint">What the statement pays.</p>
       <p class="h-field__error">Enter the rent before saving.</p>
     </div>
   ========================================================================== */
.h-field { display: block; margin-bottom: var(--h-s-4); }

/* Same type as .h-label, declared in full rather than aliased: .h-label is a
   flex wrapper in ten different contexts and must stay free to change. */
.h-field__label {
  display: block;
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-semibold);
  color: var(--h-blue);
  margin-bottom: var(--h-s-1);
}
/* The sentence that stops the question being asked. Always visible — a hint
   that only appears on focus is a hint nobody reads. */
.h-field__hint {
  display: block;
  margin: var(--h-s-1) 0 0;
  font-size: var(--h-fs-sm);
  color: var(--h-grey-70);
}
/* Hidden until the field fails. Say what to do, not that something is wrong. */
.h-field__error {
  display: none;
  margin: var(--h-s-1) 0 0;
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-semibold);
  color: var(--h-error-ink);
}
.h-field--error > .h-field__error { display: block; }
.h-field--error > .h-field__label { color: var(--h-error-ink); }
.h-field--error .h-input,
.h-field--error .h-textarea,
.h-field--error .h-select { border-color: var(--h-error); }

/* Label beside the control instead of above it. For a row of short numeric
   fields; never for a form a person fills in top to bottom. */
.h-field--inline {
  display: flex;
  align-items: baseline;
  gap: var(--h-s-3);
  flex-wrap: wrap;
}
.h-field--inline > .h-field__label { margin-bottom: 0; flex: none; }

/* Required marker, drawn for you. Use this OR .h-label__req, never both. The
   `required` attribute carries the semantics; the star is only a scan aid. */
.h-field--required > .h-field__label::after {
  content: "*";
  color: var(--h-error);
  font-weight: var(--h-fw-bold);
  margin-left: 2px;
}

/* The same star as a real element, for the .h-label wrapper idiom, where an
   ::after would land after the INPUT rather than after the caption:
     <label class="h-label"><span>Rent <span class="h-label__req"
       aria-hidden="true">*</span></span><input class="h-input" required></label>
   Not a substitute for the `required` attribute. */
.h-label__req {
  color: var(--h-error);
  font-weight: var(--h-fw-bold);
  margin-left: 2px;
}


/* === B. Pressed feedback (:active) ========================================
   Before this section the file had 91 :hover rules and ZERO :active rules —
   nothing in the estate acknowledged a tap until the page changed, which on a
   slow connection reads as "it didn't work" and gets double-submitted.

   The rule: a control gets :active only if it already has :hover, and the
   pressed look is the hovered look pushed 1px down with the lift removed.
   Every one is guarded with :not(:disabled):not([aria-disabled="true"]) —
   .h-btn:disabled only dims, it does not block pointer events, so without the
   guard a dead button would still animate under the thumb.

   The other 70-odd :hover rules are deliberately NOT given a pressed state:
   link colour/underline changes, card hover-SUPPRESSIONS (transform: none),
   row and cell tints, parent-hover child reveals, and the presentation deck's
   own --present-* subsystem. None of them is a control being pressed.
   ========================================================================== */

/* Every button: the press itself. Colour comes from the variant rules below. */
.h-btn:active:not(:disabled):not([aria-disabled="true"]) {
  transform: translateY(1px);
  box-shadow: none;
}
.h-btn-primary:active:not(:disabled):not([aria-disabled="true"]),
.h-btn--primary:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--h-blue-90);
  color: var(--h-white);
}
.h-btn-secondary:active:not(:disabled):not([aria-disabled="true"]),
.h-btn--secondary:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--h-blue);
  color: var(--h-white);
}
.h-btn-ghost:active:not(:disabled):not([aria-disabled="true"]),
.h-btn--ghost:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--h-blue-20);
  color: var(--h-blue);
}
.h-btn-accent:active:not(:disabled):not([aria-disabled="true"]),
.h-btn--accent:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--h-cyan-90);
  color: var(--h-white);
}
.h-btn--accent-ink:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--h-cyan-90);
  color: var(--h-blue);
}
.h-btn-success:active:not(:disabled):not([aria-disabled="true"]),
.h-btn--success:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--h-success-ink);
  color: var(--h-white);
}
.h-btn-danger:active:not(:disabled):not([aria-disabled="true"]),
.h-btn--danger:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--h-error-ink);
  color: var(--h-white);
}
.h-btn-warning:active:not(:disabled):not([aria-disabled="true"]),
.h-btn--warning:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--h-warning-soft);
  color: var(--h-warning-ink);
  border-color: var(--h-warning);
}
/* The ghost button on the navy splash card has its own hover, so its own press. */
.h-splash .h-btn-ghost:active:not(:disabled):not([aria-disabled="true"]),
.h-splash .h-btn--ghost:active:not(:disabled):not([aria-disabled="true"]) {
  background: rgba(255, 255, 255, 0.22);
  color: var(--h-white);
}

/* Filter / tab pills. No translate — a pill sits in a row of pills and one of
   them jumping is more distracting than it is informative. */
.h-pill:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--h-blue-20);
  border-color: var(--h-blue);
}
.h-pill--warn:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--h-warning);
  color: var(--h-charcoal);
  border-color: var(--h-warning);
}
.h-pill--info:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--h-blue-20);
  color: var(--h-blue);
  border-color: var(--h-blue);
}
.h-segmented__option:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--h-blue-20);
}
/* The selected segment is navy with white text; pressing it must darken,
   never fade to blue-20 (white on blue-20 is 1.5:1 — found in verify 14/09/2026). */
.h-segmented__option.is-active:active:not(:disabled):not([aria-disabled="true"]),
.h-segmented__option[aria-pressed="true"]:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--h-blue-90);
  color: var(--h-white);
}

/* App launcher tile — the card drops onto the page instead of lifting off it. */
.h-launch:active:not([aria-disabled="true"]) {
  box-shadow: none;
  border-color: var(--h-blue);
  transform: translateY(1px);
}
/* A placeholder tile is not a control; it suppresses hover, so it suppresses
   press too. */
.h-launch--placeholder:active {
  box-shadow: none;
  border-color: var(--h-grey-10);
  transform: none;
}

/* Chrome: nav links, sidebar links, menus, the modal close and the dismiss
   buttons. All of these already had hover; all of them are pressed by a thumb
   on a phone, where hover does not exist at all. */
.h-app-nav__links a:active:not([aria-disabled="true"]),
.h-app-nav__back:active:not([aria-disabled="true"]),
.h-app-nav__logout:active:not([aria-disabled="true"]) {
  background: rgba(255, 255, 255, 0.2);
  color: var(--h-white);
}
.h-sidebar__link:active:not([aria-disabled="true"]),
.h-sidebar__back:active:not([aria-disabled="true"]),
.h-sidebar__menu:active:not(:disabled):not([aria-disabled="true"]) {
  background: rgba(255, 255, 255, 0.2);
  color: var(--h-white);
}
.h-sidebar__signout:active:not([aria-disabled="true"]) { color: var(--h-white); }
.h-modal-close:active:not(:disabled) {
  background: var(--h-grey-30);
  color: var(--h-charcoal);
}
.h-bday-banner__dismiss:active:not(:disabled) {
  background: var(--h-grey-30);
  color: var(--h-charcoal);
}
.h-mini:active:not([aria-disabled="true"]) {
  box-shadow: none;
  border-color: var(--h-blue);
}
.h-react__plus:active:not([aria-disabled="true"]) {
  color: var(--h-blue);
  border-color: var(--h-blue);
  background: var(--h-blue-10);
}

/* .h-switch had a focus ring, a checked state and a disabled state but no
   hover and no press — the one control in the file you are most likely to
   mis-tap. Hover firms the track; press firms it further; aria-invalid is for
   the case where a switch is the field that failed validation. */
.h-switch:hover:not(:disabled) { background: var(--h-grey-50); }
.h-switch[aria-checked="true"]:hover:not(:disabled) { background: var(--h-cyan-90); }
.h-switch:active:not(:disabled) { background: var(--h-grey-70); }
.h-switch[aria-checked="true"]:active:not(:disabled) { background: var(--h-cyan-90); }
/* Hover already darkens the track, so the press lives on the thumb: it shrinks
   a touch in BOTH states (the on-state keeps its 18px travel). */
.h-switch:active:not(:disabled)::after { transform: scale(0.88); }
.h-switch[aria-checked="true"]:active:not(:disabled)::after { transform: translateX(18px) scale(0.88); }
.h-switch[aria-invalid="true"] { box-shadow: 0 0 0 2px var(--h-error); }


/* === C. Loading and busy ==================================================
   Three scales: a button that is waiting, a region that is waiting, and a
   placeholder for content that has not arrived.

   No Studio template sets aria-busy today — these rules are proven by the
   styleguide section and nothing else. Wire them up when you next make a form
   post without a full page reload.
   ========================================================================== */

/* A button mid-submit. The label stays in the flow (colour goes transparent,
   not display:none) so the button does not resize under the thumb, and
   pointer-events go so the second tap cannot double-post. Set aria-busy="true"
   as well as the class — the class is what draws, aria is what is announced. */
.h-btn.is-loading,
.h-btn[aria-busy="true"] {
  position: relative;
  color: transparent;
  pointer-events: none;
}
.h-btn.is-loading::after,
.h-btn[aria-busy="true"]::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 1em;
  height: 1em;
  margin: -0.5em 0 0 -0.5em;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-top-color: var(--h-white);
  border-radius: var(--h-radius-pill);
  animation: h-spinner-rotate 0.7s linear infinite;
}
/* On the light variants a white spinner is invisible. */
.h-btn-ghost.is-loading::after,
.h-btn--ghost.is-loading::after,
.h-btn-secondary.is-loading::after,
.h-btn--secondary.is-loading::after,
.h-btn-warning.is-loading::after,
.h-btn--warning.is-loading::after,
.h-btn-ghost[aria-busy="true"]::after,
.h-btn--ghost[aria-busy="true"]::after,
.h-btn-secondary[aria-busy="true"]::after,
.h-btn--secondary[aria-busy="true"]::after,
.h-btn-warning[aria-busy="true"]::after,
.h-btn--warning[aria-busy="true"]::after {
  border-color: var(--h-blue-20);
  border-top-color: var(--h-blue);
}

/* Standalone spinner, for a region that has no button to put one in. Give it
   an .h-sr-only sibling saying what is loading — a bare spinner announces
   nothing. Never use one for a wait under about 300ms. */
.h-spinner {
  display: inline-block;
  width: 20px;
  height: 20px;
  border: 2px solid var(--h-grey-30);
  border-top-color: var(--h-blue);
  border-radius: var(--h-radius-pill);   /* a true circle — the permitted use */
  animation: h-spinner-rotate 0.7s linear infinite;
  vertical-align: -4px;
}
.h-spinner--sm { width: 14px; height: 14px; }
.h-spinner--lg { width: 32px; height: 32px; border-width: 3px; }
/* On navy — the sidebar, the app nav, the splash card. */
.h-spinner--light {
  border-color: rgba(255, 255, 255, 0.3);
  border-top-color: var(--h-white);
}

@keyframes h-spinner-rotate {
  to { transform: rotate(360deg); }
}

/* A whole region waiting on a refresh. main.h-shell__content, NOT
   .h-shell__main — that one wraps the topbar, and greying out the nav while a
   table reloads strands the user. Dim, not hide: the old figures stay readable
   while the new ones land. */
.h-card[aria-busy="true"],
.h-table[aria-busy="true"],
main.h-shell__content[aria-busy="true"] {
  opacity: 0.55;
  pointer-events: none;
  cursor: progress;
  transition: opacity var(--h-duration) var(--h-ease);
}

/* Skeletons — a shape where the content will be, for a first paint that has no
   old content to dim. Sizes, so a caller does not reach for inline styles. */
.h-skeleton--text  { height: 0.9em; margin: 0.35em 0; }
.h-skeleton--title { height: 1.4em; width: 60%; margin-bottom: var(--h-s-3); }
.h-skeleton--block { height: 120px; }

/* Reduced motion: the global guard at the top of this file collapses every
   animation to 0.01ms, which freezes a spinner at an arbitrary angle. Say what
   should happen instead — a static three-quarter ring, and a flat skeleton. */
@media (prefers-reduced-motion: reduce) {
  .h-spinner,
  .h-btn.is-loading::after,
  .h-btn[aria-busy="true"]::after { animation: none; }
  .h-skeleton { animation: none; background: var(--h-grey-10); }
}


/* === D. .h-checkbox and .h-radio — the canonical tick and dot ==============
   A native checkbox cannot be styled consistently across browsers, so the real
   input is hidden (1px, clipped, opacity 0 — still focusable, still in the tab
   order, still what the form posts) and a <span> is drawn beside it.

     <label class="h-checkbox">
       <input class="h-checkbox__input" type="checkbox" name="copy">
       <span class="h-checkbox__box" aria-hidden="true"></span>
       <span class="h-checkbox__label">Send the tenant a copy</span>
     </label>

   Same shape for .h-radio, with __dot instead of __box.

   CHECKED IS HARCOURTS BLUE, not cyan. The older .h-wd-check and .h-switch
   tick in cyan; a column of twenty cyan boxes is not a 10% accent, and a form
   control is structure, not emphasis. Both older idioms are untouched.

   There is no readonly checkbox: use :disabled, or aria-readonly plus a change
   handler that reverts. A readonly checkbox that still posts is a trap.
   ========================================================================== */
.h-checkbox,
.h-radio {
  display: inline-flex;
  align-items: flex-start;
  gap: var(--h-s-2);
  position: relative;
  margin: 0;
  padding: var(--h-s-1) 0;
  min-height: 32px;
  font-size: var(--h-fs-sm);
  line-height: var(--h-lh-snug);
  color: var(--h-ink);
  cursor: pointer;
}
.h-checkbox__input,
.h-radio__input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
  clip-path: inset(50%);
  pointer-events: none;
}
.h-checkbox__box,
.h-radio__dot {
  position: relative;
  flex: none;
  width: 18px;
  height: 18px;
  margin-top: 2px;
  border: 1.5px solid var(--h-grey-30);
  border-radius: var(--h-radius);
  background: var(--h-white);
  transition: background var(--h-duration) var(--h-ease),
              border-color var(--h-duration) var(--h-ease);
}
.h-radio__dot { border-radius: var(--h-radius-pill); }  /* a true circle */
.h-checkbox__label,
.h-radio__label { min-width: 0; }

/* hover */
.h-checkbox:hover .h-checkbox__box,
.h-radio:hover .h-radio__dot { border-color: var(--h-blue); }

/* keyboard focus — the glow on the drawn box, the idiom .h-wd-check uses.
   Not --h-focus-ring: an outline on a 1px clipped input draws nothing. */
.h-checkbox__input:focus-visible ~ .h-checkbox__box,
.h-radio__input:focus-visible ~ .h-radio__dot {
  border-color: var(--h-cyan);
  box-shadow: var(--h-focus-glow);
}
/* On navy the translucent glow disappears against the ground (verify 14/09/2026
   measured a 1.16:1 lift). Cyan is the dark-surface focus colour, so the ring is
   drawn opaque there. */
.h-checkbox--light .h-checkbox__input:focus-visible ~ .h-checkbox__box,
.h-radio--light .h-radio__input:focus-visible ~ .h-radio__dot {
  border-color: var(--h-cyan);
  box-shadow: 0 0 0 2px var(--h-blue), 0 0 0 4px var(--h-cyan);
}

/* checked — CSS-drawn tick, no SVG and no icon font */
.h-checkbox__input:checked ~ .h-checkbox__box {
  background: var(--h-blue);
  border-color: var(--h-blue);
}
.h-checkbox__input:checked ~ .h-checkbox__box::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 1px;
  width: 5px;
  height: 9px;
  border: solid var(--h-white);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
/* indeterminate — "some of the rows below, not all". JS-only: there is no
   attribute for it, so set el.indeterminate = true. */
.h-checkbox__input:indeterminate ~ .h-checkbox__box {
  background: var(--h-blue);
  border-color: var(--h-blue);
}
.h-checkbox__input:indeterminate ~ .h-checkbox__box::after {
  content: "";
  position: absolute;
  left: 3px;
  top: 6px;
  width: 9px;
  height: 2px;
  background: var(--h-white);
  border: 0;
  transform: none;
}
.h-radio__input:checked ~ .h-radio__dot {
  border-color: var(--h-blue);
  border-width: 2px;
}
.h-radio__input:checked ~ .h-radio__dot::after {
  content: "";
  position: absolute;
  left: 3px;
  top: 3px;
  width: 8px;
  height: 8px;
  border-radius: var(--h-radius-pill);
  background: var(--h-blue);
}

/* disabled */
.h-checkbox__input:disabled ~ .h-checkbox__box,
.h-radio__input:disabled ~ .h-radio__dot {
  background: var(--h-grey-10);
  border-color: var(--h-grey-50);
}
.h-checkbox__input:disabled:checked ~ .h-checkbox__box,
.h-checkbox__input:disabled:indeterminate ~ .h-checkbox__box,
.h-radio__input:disabled:checked ~ .h-radio__dot {
  background: var(--h-grey-50);
  border-color: var(--h-grey-50);
}
.h-radio__input:disabled:checked ~ .h-radio__dot { background: var(--h-white); }
.h-radio__input:disabled:checked ~ .h-radio__dot::after { background: var(--h-grey-50); }
.h-checkbox:has(.h-checkbox__input:disabled),
.h-radio:has(.h-radio__input:disabled) {
  cursor: not-allowed;
  color: var(--h-grey-70);
}
.h-checkbox:has(.h-checkbox__input:disabled):hover .h-checkbox__box,
.h-radio:has(.h-radio__input:disabled):hover .h-radio__dot { border-color: var(--h-grey-50); }

/* error — for "you must tick this to continue". Pair it with a
   .h-field__error or a .h-fieldset--error legend; a red box alone says nothing. */
.h-checkbox__input[aria-invalid="true"] ~ .h-checkbox__box,
.h-checkbox--error .h-checkbox__box,
.h-radio__input[aria-invalid="true"] ~ .h-radio__dot,
.h-radio--error .h-radio__dot { border-color: var(--h-error); }

/* On navy — the sidebar, the splash card, a dark panel. A checked box is
   Harcourts Blue, which on a navy ground is a box you cannot see: the tick
   floats. --light puts a white edge on it and lifts the label off the dark.
   Caught by the styleguide's navy panel on 14/09/2026. */
.h-checkbox--light,
.h-radio--light { color: var(--h-dark-text); }
.h-checkbox--light .h-checkbox__input:checked ~ .h-checkbox__box,
.h-checkbox--light .h-checkbox__input:indeterminate ~ .h-checkbox__box,
.h-radio--light .h-radio__input:checked ~ .h-radio__dot { border-color: var(--h-white); }
.h-checkbox--light:hover .h-checkbox__box,
.h-radio--light:hover .h-radio__dot { border-color: var(--h-cyan); }
.h-checkbox--light:has(.h-checkbox__input:disabled),
.h-radio--light:has(.h-radio__input:disabled) { color: var(--h-dark-muted); }

/* Dense variant — for a tick inside a table row, where 18px crowds the line.
   Never on a phone-first form; the tap target shrinks with it. */
.h-checkbox--sm,
.h-radio--sm { min-height: 0; }
.h-checkbox--sm .h-checkbox__box,
.h-radio--sm .h-radio__dot { width: 14px; height: 14px; margin-top: 1px; }
.h-checkbox--sm .h-checkbox__input:checked ~ .h-checkbox__box::after {
  left: 3px; top: 0; width: 4px; height: 8px;
}
.h-checkbox--sm .h-checkbox__input:indeterminate ~ .h-checkbox__box::after {
  left: 2px; top: 4px; width: 7px; height: 2px;
}
.h-radio--sm .h-radio__input:checked ~ .h-radio__dot::after {
  left: 2px; top: 2px; width: 6px; height: 6px;
}

/* === .h-fieldset — the group the boxes belong to ==========================
   A set of checkboxes or radios needs one caption, and a <legend> is the only
   thing a screen reader reads before every option in the group.

     <fieldset class="h-fieldset">
       <legend class="h-fieldset__legend">How should we tell you</legend>
       <div class="h-fieldset__items"> ...radios... </div>
     </fieldset>

   Not .h-choices/.h-choice — those are the name-plus-description card idiom,
   which is a different thing and still the right one when each option needs a
   sentence of explanation. */
.h-fieldset {
  border: 0;
  padding: 0;
  margin: 0 0 var(--h-s-4);
  min-width: 0;   /* a fieldset will not shrink inside a grid without this */
}
.h-fieldset__legend {
  padding: 0;
  margin-bottom: var(--h-s-1);
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-semibold);
  color: var(--h-blue);
}
/* The items need their own box: <legend> is laid out by the browser and
   cannot be a flex or grid item of its own fieldset. */
.h-fieldset__items { display: grid; gap: var(--h-s-1); }
.h-fieldset--inline > .h-fieldset__items {
  display: flex;
  flex-wrap: wrap;
  gap: var(--h-s-2) var(--h-s-5);
}
.h-fieldset--error > .h-fieldset__legend { color: var(--h-error-ink); }

/* Phones: 44px of tappable label, per the front-door rule. 640px is this
   file's dominant phone query (19 of the 54). */
@media (max-width: 640px) {
  .h-checkbox,
  .h-radio { min-height: 44px; padding: var(--h-s-2) 0; }
  .h-checkbox--sm,
  .h-radio--sm { min-height: 0; padding: var(--h-s-1) 0; }
}


/* === F. .h-tooltip — the label that would not fit ==========================
   For an icon-only button or an abbreviated column head. The text lives in
   data-tip and is drawn by ::after.

     <button class="h-btn h-btn--ghost h-tooltip" data-tip="Archive this lead">
       <span class="h-sr-only">Archive this lead</span> ...icon...
     </button>

   attr() content is NOT reliably exposed to assistive technology. The trigger
   must carry the same words in an aria-label or an .h-sr-only span — the tip
   is a convenience for people who can see it, never the only copy.
   Never put a link, a button or anything else interactive in a tip: the
   pointer cannot reach it. If it needs to be read slowly, it is body copy.
   ========================================================================== */
.h-tooltip { position: relative; }
.h-tooltip::after {
  content: attr(data-tip);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  z-index: var(--h-z-dropdown);
  width: max-content;
  max-width: 28ch;
  padding: var(--h-s-2) var(--h-s-3);
  background: var(--h-blue);
  color: var(--h-white);
  font-family: var(--h-font-sans);
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-regular);
  line-height: var(--h-lh-snug);
  letter-spacing: var(--h-tracking-body);
  text-align: left;
  text-transform: none;
  white-space: normal;
  border-radius: var(--h-radius);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--h-duration) var(--h-ease);
}
.h-tooltip:hover::after,
.h-tooltip:focus::after,
.h-tooltip:focus-visible::after,
.h-tooltip:focus-within::after { opacity: 1; visibility: visible; }

/* Nothing to say, nothing drawn — an empty box under the cursor is worse than
   no tip at all. */
.h-tooltip:not([data-tip])::after,
.h-tooltip[data-tip=""]::after { content: none; }

.h-tooltip--bottom::after { bottom: auto; top: calc(100% + 6px); }
.h-tooltip--left::after {
  bottom: auto; top: 50%; left: auto; right: calc(100% + 6px);
  transform: translateY(-50%);
}
.h-tooltip--right::after {
  bottom: auto; top: 50%; left: calc(100% + 6px);
  transform: translateY(-50%);
}

/* Touch: there is no hover, and a :hover that sticks after a tap leaves the
   tip stranded over the next thing you tap. Focus and press only. */
@media (hover: none) {
  .h-tooltip:hover::after { opacity: 0; visibility: hidden; }
  .h-tooltip:focus::after,
  .h-tooltip:focus-within::after,
  .h-tooltip:active::after { opacity: 1; visibility: visible; }
}


/* === G. .h-pagination — page 3 of 11 ======================================
   A layout block. The page numbers are ordinary buttons, per the
   buttons-vs-pills standard: .h-btn .h-btn--sm .h-btn--ghost, nothing bespoke.

     <nav class="h-pagination" aria-label="Pages">
       <p class="h-pagination__summary">21&ndash;40 of 212</p>
       <ul class="h-pagination__list">
         <li><a class="h-btn h-btn--sm h-btn--ghost" href="?p=2">Previous</a></li>
         <li><a class="h-btn h-btn--sm h-btn--ghost" href="?p=3"
                aria-current="page">3</a></li>
         <li class="h-pagination__ellipsis">&hellip;</li>
       </ul>
     </nav>

   Say the range as well as the page number: "21-40 of 212" answers the
   question people actually have, which is how much is left.
   ========================================================================== */
.h-pagination {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--h-s-3);
  margin-top: var(--h-s-5);
}
.h-pagination__summary {
  margin: 0;
  font-size: var(--h-fs-sm);
  color: var(--h-grey-70);
  font-variant-numeric: tabular-nums;
}
.h-pagination__list {
  display: flex;
  align-items: center;
  gap: var(--h-s-1);
  margin: 0 0 0 auto;
  padding: 0;
  list-style: none;
}
.h-pagination__ellipsis {
  padding: 0 var(--h-s-2);
  font-size: var(--h-fs-sm);
  color: var(--h-grey-50);
}
.h-pagination .h-btn { min-width: 36px; font-variant-numeric: tabular-nums; }

/* The page you are on. aria-current does the announcing; this does the seeing. */
.h-pagination [aria-current="page"],
.h-pagination [aria-current="page"]:hover {
  background: var(--h-blue);
  color: var(--h-white);
  border-color: var(--h-blue);
}
/* First page has no Previous. Keep the control in place and disable it —
   a control that disappears makes the row jump under the thumb. */
.h-pagination [aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}
@media (max-width: 640px) {
  .h-pagination__list { margin-left: 0; }
  .h-pagination .h-btn { min-height: 44px; min-width: 44px; }
}


/* === H. Two of the seven undefined classes, defined ========================
   Seven classes appeared in Studio templates with no rule behind them. Five
   are accounted for elsewhere: .h-pe-row, .h-sc-edit and .h-fm-line__now are
   deliberately style-free (a base with defined modifiers, a form namespace,
   and a grid cell the parent positions), and .h-launch--ext and .h-lg-edit
   were dead — removed from the templates 14/09/2026, never defined here. These
   two had an obvious intent and now have a rule. */

/* The style-free hooks, declared (16/09/2026). brand-lint now fails on any
   h-* class that harcourts.css does not define, because oab.html shipped five
   classes that existed nowhere and rendered unstyled behind a green tick. A
   BEM block whose only rules sit on its modifier or its children (.h-pe-row
   → .h-pe-row--paused, .h-due → .h-due--over, .h-sc-edit → .h-sc-edit__roles,
   .h-fm-line__now as the grid cell .h-fm-line positions) is still a real
   class the markup relies on, so it is declared here with no declarations:
   the lint sees it, a reader sees the block exists on purpose, and nothing
   renders differently. Do not add properties here — if a hook needs styling,
   give it its own rule beside its modifiers. */
.h-pe-row,
.h-sc-edit,
.h-fm-line__now,
.h-due {}

/* The fourth notice colour. Cyan-derived, matching .h-badge--info-soft, so
   "here is what happened" no longer borrows the plain navy .h-notice that
   means "read this". */
.h-notice--info {
  border-left-color: var(--h-cyan);
  background: var(--h-info-soft);
  color: var(--h-info-ink);
}

/* A .h-lv-calc figure that is a date, not a number: --h-fs-xl wraps
   "Mon 22 Sep" onto two lines in a 140px tile. */
.h-lv-calc__value--sm { font-size: var(--h-fs-lg); }


/* ==========================================================================
   PAR (Property Assessment Report) blocks — added 15/09/2026
   --------------------------------------------------------------------------
   par.hdas.com.au had 995 lines of its own stylesheet, including a local
   :root that aliased --blue/--faint/--font onto the --h-* tokens. It is gone;
   these are the patterns PAR needs that the library did not already have.
   Everything here is ADDITIVE — no rule above this line changed.

   Reused rather than reinvented, for the record, because the next app should
   reach for the same ones: .h-card + .h-card__body (list rows, ad panels),
   .h-page-header (+__title/__sub/__actions) for every page and room heading,
   .h-field (+__label) for every labelled control, .h-input/.h-textarea/
   .h-select, .h-checkbox, .h-segmented--yn (the rental Yes/No), .h-pill (the
   room picker and every feature chip), .h-badge--* (assessment status),
   .h-toast + .h-toast__action (the toast AND the delete-undo snackbar),
   .h-notice--info/--error/--warning, .h-empty, .h-list, .h-actions,
   .h-eyebrow, .h-meta, .h-muted, .h-mono, .h-btn.is-loading, .h-form-card.

   Conventions kept: authored variants --modifier, JS state is-*, keyframes
   component-prefixed with a prefers-reduced-motion guard, 4px corners except
   true circles, anything clickable is a .h-btn or a .h-pill.
   Breakpoints are the library's: the old sheet's 600px queries moved to 640px
   (--h-bp-phone); its 768px queries stayed at 768px (--h-bp-tablet).
   ========================================================================== */

/* ---------- The page an .h-app-nav app sits on ---------------------------- */
/* body { background: white } is the library default and right for a marketing
   page; an internal tool wants paper under its cards, the way .h-shell gives
   Studio. Pair with .h-app-nav. --h-pa-capture-h is the height of a fixed
   bottom bar the page has to clear (PAR's voice capture); 0 when there isn't
   one, which is why the toast rule below is exact for every other app. */
.h-app-page {
  --h-pa-capture-h: 0px;
  min-height: 100vh;
  background: var(--h-paper);
}
.h-app-page--capture {
  --h-pa-capture-h: 92px;             /* .h-pa-capture: 56px button + padding */
  padding-bottom: calc(var(--h-pa-capture-h) + var(--h-s-6));
}
.h-app-page__main { padding-top: var(--h-s-5); padding-bottom: var(--h-s-8); }
/* A .h-toast is fixed with left:50% and no right, so its containing width is
   half the viewport — 195px on a 390px phone, which folds "Deleted <address>"
   into a four-line sliver. Given both edges and auto margins it centres the
   same way and can use the screen. Scoped to .h-app-page so .h-shell (Studio)
   and the styleguide are untouched. */
.h-app-page .h-toast {
  right: var(--h-s-4);
  bottom: calc(var(--h-s-5) + var(--h-pa-capture-h));
  left: var(--h-s-4);
  transform: none;
  justify-content: center;
  max-width: 460px;
  margin: 0 auto;
}

/* One-column form page. .h-form-card caps the form at 620px, so the heading,
   the brochure link and any error notice above it take the same cap instead of
   running to the container's full width and leaving the form looking inset. */
.h-pa-formpage { max-width: 620px; }

/* ---------- The assessment list ------------------------------------------- */
/* A .h-card per assessment: the whole row is one link, with the actions as
   real buttons underneath it — nesting a Delete button inside an <a> is the
   bug this shape avoids. */
.h-pa-list { display: flex; flex-direction: column; gap: var(--h-s-2); }
.h-pa-item { overflow: hidden; }
.h-pa-item__link {
  display: block;
  padding: var(--h-s-3) var(--h-s-4);
  color: var(--h-ink);
  text-decoration: none;
}
.h-pa-item__link:hover { color: var(--h-ink); }
.h-pa-item__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--h-s-2);
}
.h-pa-item__addr {
  flex: 1 1 auto;
  min-width: 0;
  font-weight: var(--h-fw-semibold);
}
.h-pa-item__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--h-s-2);
  padding: 0 var(--h-s-4) var(--h-s-3);
}
/* The destructive action sits away from the primary ones, hard right. */
.h-pa-item__actions > .h-btn--danger-soft { margin-left: auto; }

/* A delete that is not shouting. .h-btn--danger is solid red, which is right
   for one irreversible button on a detail page and wrong for a column of
   eighty of them in a list. Error ink on a soft tint, filling in on hover. */
.h-btn--danger-soft {
  background: transparent;
  color: var(--h-error-ink);
  border-color: var(--h-error-soft);
}
.h-btn--danger-soft:hover {
  background: var(--h-error-soft);
  color: var(--h-error-ink);
  border-color: var(--h-error);
}
.h-btn--danger-soft:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--h-error-soft);
  border-color: var(--h-error-ink);
}

/* ---------- A fold, and the rows inside it -------------------------------- */
/* <details> for "recently deleted" — closed is the normal state, so it costs
   no height until someone needs it. */
.h-pa-fold { margin-top: var(--h-s-6); }
.h-pa-fold__summary {
  cursor: pointer;
  padding: var(--h-s-2) 0;
  font-weight: var(--h-fw-semibold);
  color: var(--h-grey-70);
}
.h-pa-fold__body { display: flex; flex-direction: column; gap: var(--h-s-2); margin-top: var(--h-s-3); }

/* A plain bordered row: something named on the left, one action on the right. */
.h-pa-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--h-s-4);
  padding: var(--h-s-3) var(--h-s-4);
  background: var(--h-white);
  border: 1px solid var(--h-grey-10);
  border-radius: var(--h-radius);
}
.h-pa-row__main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.h-pa-row__title { font-weight: var(--h-fw-semibold); color: var(--h-ink); }

/* ---------- The sticky property bar --------------------------------------- */
/* Address, agent, status and the four things you do with an assessment, on
   one line under the nav. top:60px is the height of .h-app-nav. */
.h-pa-bar {
  position: sticky;
  top: 60px;
  z-index: var(--h-z-nav);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--h-s-2);
  padding: var(--h-s-2) var(--h-s-5);
  background: var(--h-white);
  border-bottom: 1px solid var(--h-grey-10);
  box-shadow: var(--h-shadow-sm);
}
/* The two text fields share the leftover width and may shrink; everything
   else in the bar keeps its own size. */
.h-pa-bar .h-input.h-pa-bar__field {
  flex: 1 1 200px;
  width: auto;
  min-width: 0;
  padding: var(--h-s-2) var(--h-s-3);
  font-size: var(--h-fs-sm);
}

/* ---------- The room picker ----------------------------------------------- */
/* A strip of .h-pill tabs — one per room, plus the Add tiles and the two
   special sections. Sticky under .h-pa-bar on a desktop; on a phone it stops
   being a strip and becomes the list you choose a room from (see the master
   /detail block at the end of this section). */
.h-pa-tiles {
  position: sticky;
  top: 114px;                      /* .h-app-nav (60) + .h-pa-bar (54) */
  z-index: var(--h-z-nav);
  display: flex;
  flex-wrap: wrap;
  gap: var(--h-s-2);
  padding: var(--h-s-3) var(--h-s-5);
  background: var(--h-white);
  border-bottom: 1px solid var(--h-grey-10);
}
.h-pa-tile { font-size: var(--h-fs-sm); }
.h-pa-tile__icon { font-size: var(--h-fs-base); line-height: 1; }
.h-pa-tile__label { min-width: 0; }
/* Empty / part-done / done, as a dot rather than a word — the tile already
   carries the room name and there is no room for a second label. */
.h-pa-tile__dot {
  flex: none;
  width: 7px;
  height: 7px;
  margin-left: 2px;
  border-radius: var(--h-radius-pill);   /* a true circle */
  background: var(--h-grey-30);
}
.h-pa-tile.is-complete .h-pa-tile__dot { background: var(--h-success); }
.h-pa-tile.is-partial  .h-pa-tile__dot { background: var(--h-warning); }
.h-pa-tile.is-active   .h-pa-tile__dot { background: rgba(255, 255, 255, 0.7); }
.h-pa-tile__remove { margin-left: var(--h-s-1); opacity: 0.5; }
.h-pa-tile__remove:hover { opacity: 1; color: var(--h-error); }
/* "Add bedroom" is not a room you have, it is a room you could add. */
.h-pa-tile--add { background: transparent; border-style: dashed; color: var(--h-grey-70); }
/* The owner interview is not a room at all, so it reads as its own thing. */
.h-pa-tile--owner:not(.is-active) { background: var(--h-info-soft); border-color: var(--h-cyan); }

/* ---------- The room heading ---------------------------------------------- */
.h-pa-roomtitle { display: flex; align-items: center; gap: var(--h-s-3); min-width: 0; }
.h-pa-roomtitle__icon { font-size: var(--h-fs-2xl); line-height: 1; flex: none; }
/* A renameable room ("Bedroom 2"): the heading IS the field, so it carries no
   border until you point at it. */
.h-pa-roomtitle__edit.h-input {
  width: auto;
  min-width: 200px;
  padding: 2px var(--h-s-2);
  font-size: var(--h-fs-2xl);
  font-weight: var(--h-fw-bold);
  color: var(--h-blue);
  letter-spacing: var(--h-tracking-tight);
  background: transparent;
  border-color: transparent;
}
.h-pa-roomtitle__edit.h-input:hover { border-color: var(--h-grey-30); }

/* The room picker sits directly above, so the room heading does not also need
   the library's 32px top margin; and the "1 of 3 groups" counter is a <p>, so
   its UA margin has to go or it floats off the heading's baseline. */
.h-pa-room > .h-page-header { margin-top: 0; }
.h-pa-room > .h-page-header .h-meta { margin: 0; }

/* ---------- A group of answers, folded -------------------------------------
   Every room is a stack of these: a head you tap, a one-line summary of what
   is already in it, and the controls underneath. Not .h-roomgrid — that is a
   table of one-word answers; this is a disclosure around free-form controls.
   The head is a real <button>, so it is reachable from a keyboard. */
.h-pa-group {
  background: var(--h-white);
  border: 1px solid var(--h-grey-10);
  border-radius: var(--h-radius);
  overflow: hidden;
  margin-bottom: var(--h-s-3);
  box-shadow: var(--h-shadow-sm);
}
.h-pa-group__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--h-s-3);
  width: 100%;
  min-height: 44px;
  padding: var(--h-s-3) var(--h-s-4);
  font-family: var(--h-font-sans);
  text-align: left;
  background: transparent;
  border: 0;
  cursor: pointer;
}
.h-pa-group__head:hover { background: var(--h-paper); }
.h-pa-group__title {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--h-s-2);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-bold);
  text-transform: uppercase;
  letter-spacing: var(--h-tracking-wide);
  color: var(--h-ink);
}
.h-pa-group__tick { color: var(--h-success); }
.h-pa-group__mark { color: var(--h-grey-50); }
.h-pa-group__meta {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: right;
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-regular);
  text-transform: none;
  letter-spacing: normal;
  color: var(--h-grey-70);
}
.h-pa-group__toggle {
  flex: none;
  font-size: var(--h-fs-xs);
  color: var(--h-grey-50);
  transition: transform var(--h-duration) var(--h-ease);
}
.h-pa-group.is-open .h-pa-group__toggle { transform: rotate(90deg); }
.h-pa-group__body {
  display: none;
  gap: var(--h-s-2);
  padding: var(--h-s-1) var(--h-s-4) var(--h-s-4);
  border-top: 1px dashed var(--h-grey-10);
}
.h-pa-group.is-open .h-pa-group__body { display: grid; }
/* A room with exactly one group has nothing to choose between, so it opens
   flat — no head to tap before you can answer anything. */
.h-pa-solo { display: grid; gap: var(--h-s-2); margin-top: var(--h-s-1); }

/* A group the voice transcript just filled, called out for a second and a
   half so you can see what the recording landed on. */
.h-pa-group.is-filled-now { animation: h-pa-filled 1.6s var(--h-ease); }
@keyframes h-pa-filled {
  0%   { box-shadow: 0 0 0 0 var(--h-cyan); }
  20%  { box-shadow: 0 0 0 3px var(--h-cyan); }
  100% { box-shadow: 0 0 0 0 var(--h-cyan); }
}

/* ---------- Feature chips -------------------------------------------------- */
/* A room's features, grouped into labelled segments (Flooring, Lighting…) so
   the list reads the way you walk a room. Each chip is a .h-pill. */
.h-pa-opts { display: grid; gap: var(--h-s-2); }
.h-pa-opts__seg { margin-top: var(--h-s-2); }
.h-pa-opts__seg:first-child { margin-top: 0; }
.h-pa-opts__seg-label {
  padding: var(--h-s-1) 0 2px;
  border-bottom: 1px solid var(--h-grey-10);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-bold);
  text-transform: uppercase;
  letter-spacing: var(--h-tracking-wide);
  color: var(--h-grey-70);
}
.h-pa-opts__list { display: flex; flex-wrap: wrap; gap: var(--h-s-2); margin-top: var(--h-s-2); }
/* The shared pill is 40px, which is a mouse's target. Every chip here is
   tapped one-handed standing in someone's lounge room, so it carries the 44px
   touch minimum at EVERY width — PAR has no desk mode. min-height rather than
   padding: the pill is already centred (inline-flex + align-items: center), so
   the label stays on the chip's middle line and the wrap rhythm is unchanged. */
.h-pa-opt { min-height: 44px; font-size: var(--h-fs-sm); }
/* Single-select: the chosen chip is navy like any active pill, plus an inset
   cyan rule so a list of one answer does not read as a list of many. */
.h-pa-opts__list--single .h-pa-opt.is-active { box-shadow: inset 0 0 0 2px var(--h-cyan); }
/* "3 powerpoints" — the count lives on the chip, not in a second control. */
.h-pa-opt__count {
  padding: 1px var(--h-s-1);
  border-radius: var(--h-radius-sm);
  background: rgba(255, 255, 255, 0.18);
  font-family: var(--h-font-mono);
  font-size: 0.75em;
}
.h-pa-opt__count-input {
  width: 34px;
  padding: 0 2px;
  color: inherit;
  background: rgba(255, 255, 255, 0.2);
  border: 0;
  border-radius: var(--h-radius-sm);
  font-family: var(--h-font-mono);
  font-size: 0.75em;
  text-align: center;
}
.h-pa-opt__count-input:focus { outline: 1px solid rgba(255, 255, 255, 0.6); }

/* ---------- A raised panel inside a room ---------------------------------- */
/* Owner names, "paste what they wrote", and the generated owner story: three
   sub-forms that are part of the interview but are not questions. One block,
   because they are one idea — an aside on paper inside a white page. */
.h-pa-panel {
  margin: 0 0 var(--h-s-5);
  padding: var(--h-s-4) var(--h-s-5);
  background: var(--h-paper);
  border: 1px solid var(--h-grey-10);
  border-radius: var(--h-radius);
}
.h-pa-panel__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--h-s-4);
  margin-bottom: var(--h-s-3);
}
.h-pa-panel__head > :first-child { flex: 1 1 auto; min-width: 0; }
.h-pa-panel__head .h-eyebrow { margin: 0; }
.h-pa-panel__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--h-s-3);
  margin-top: var(--h-s-3);
}
/* The story itself is long-form prose an owner reads and corrects in place. */
.h-pa-panel .h-textarea--story { min-height: 260px; line-height: var(--h-lh-base); }

/* ---------- Voice capture -------------------------------------------------- */
/* Fixed to the bottom of the assessment page: one big mic and the transcript
   it produced. The page above it reserves the height (.h-app-page--capture). */
.h-pa-capture {
  position: fixed;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: var(--h-z-nav);
  display: flex;
  align-items: flex-end;
  gap: var(--h-s-3);
  padding: var(--h-s-4) var(--h-s-5) var(--h-s-5);
  background: var(--h-paper);
  border-top: 1px solid var(--h-grey-10);
}
/* A circle, because it is a record button and nothing else on the page is
   round. Still a .h-btn — the variant only changes its box. */
.h-pa-capture__btn.h-btn {
  flex: none;
  width: 56px;
  height: 56px;
  min-height: 0;
  padding: 0;
  border-width: 4px;
  border-color: var(--h-info-soft);
  border-radius: var(--h-radius-pill);
  font-size: var(--h-fs-xl);
}
.h-pa-capture__btn.h-btn:hover:not(:disabled) { transform: scale(1.05); }
.h-pa-capture__btn.is-recording {
  background: var(--h-error);
  color: var(--h-white);
  border-color: var(--h-error-soft);
  animation: h-pa-rec 1.5s infinite;
}
.h-pa-capture__btn.is-processing {
  background: var(--h-warning);
  color: var(--h-white);
  border-color: var(--h-warning-soft);
}
@keyframes h-pa-rec {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.6); }
  50%      { box-shadow: 0 0 0 14px rgba(255, 255, 255, 0); }
}
.h-pa-capture__box {
  flex: 1 1 auto;
  max-height: 110px;
  overflow-y: auto;
  padding: var(--h-s-2) var(--h-s-3);
  background: var(--h-white);
  border: 1px solid var(--h-grey-10);
  border-radius: var(--h-radius);
  font-size: var(--h-fs-sm);
  box-shadow: var(--h-shadow-sm);
}
.h-pa-capture__label {
  margin-bottom: 2px;
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-bold);
  text-transform: uppercase;
  letter-spacing: var(--h-tracking-wide);
  color: var(--h-cyan);
}
.h-pa-capture__placeholder { color: var(--h-grey-50); font-style: italic; }

/* ---------- The rental appraisal range ------------------------------------ */
/* "$ [620] to $ [660] per week" as one line of controls, so the two numbers
   read as one answer. */
.h-pa-range { display: flex; flex-wrap: wrap; align-items: center; gap: var(--h-s-2); }
.h-pa-range__cell { position: relative; display: inline-flex; align-items: center; }
.h-pa-range__prefix {
  position: absolute;
  left: var(--h-s-3);
  color: var(--h-grey-50);
  pointer-events: none;
}
.h-pa-range__cell .h-input { width: 120px; padding-left: var(--h-s-6); }
.h-pa-range__sep { color: var(--h-grey-70); }

/* ---------- Master / detail on a phone -------------------------------------
   A 390px screen cannot show a fourteen-room picker AND the room. So below
   768px the picker is the page until you choose a room, and the room is the
   page after that — body.is-room-active is the switch, set by the client.
   Above 768px both are on screen and the class does nothing. */
/* .h-btn--sm is 36px. This one is the only way out of a room on a phone, so
   it takes the same 44px minimum as the chips. Centred by .h-btn's own
   align-items, so the arrow and label do not drift off the baseline. */
.h-pa-back { display: none; min-height: 44px; }
@media (max-width: 768px) {
  .h-pa-tiles {
    position: static;
    flex-direction: column;
    align-items: stretch;
    gap: var(--h-s-2);
    padding: var(--h-s-3) var(--h-s-4) var(--h-s-5);
  }
  .h-pa-tile { justify-content: space-between; min-height: 44px; font-size: var(--h-fs-base); }
  .h-pa-tile__label { flex: 1 1 auto; }
  .h-pa-tile__dot { width: 9px; height: 9px; }
  .h-pa-room, .h-pa-capture { display: none; }
  .is-room-active .h-pa-tiles { display: none; }
  .is-room-active .h-pa-room { display: block; }
  .is-room-active .h-pa-capture { display: flex; }
  .is-room-active .h-pa-back { display: inline-flex; }
  .h-pa-roomtitle__icon { font-size: var(--h-fs-xl); }
  .h-pa-roomtitle__edit.h-input { min-width: 0; flex: 1 1 auto; font-size: var(--h-fs-xl); }
}
@media (max-width: 640px) {
  .h-pa-bar { padding: var(--h-s-2) var(--h-s-3); }
  .h-pa-bar .h-input.h-pa-bar__field { flex: 1 1 120px; }
  .h-pa-range__cell .h-input { width: 110px; }
}

/* Motion is decoration on both of these: the record button still turns red,
   and a just-filled group still redraws with its answers in it. */
@media (prefers-reduced-motion: reduce) {
  .h-pa-capture__btn.is-recording,
  .h-pa-group.is-filled-now { animation: none; }
  .h-pa-capture__btn.h-btn:hover:not(:disabled) { transform: none; }
}

/* ==========================================================================
   Patch (door-knocking) blocks — added 15/09/2026
   --------------------------------------------------------------------------
   patch.hdas.com.au carried 941 lines of its own CSS across three files
   (style.css 481, screens.css 331, doorstep.css 129), each opening with a
   local :root that aliased --navy/--scr-navy/--border onto the --h-* tokens.
   All three are gone; what is left here are the patterns Patch needs that the
   library did not already have. Everything is ADDITIVE — no rule above this
   line changed.

   Two numbers here are deliberately NOT the library defaults, and both come
   from the same fact: Patch is held in one hand, in sunlight, with someone
   standing in front of you, and every tap on the doorstep card commits —
   there is no Save to scroll back to.
     · .h-btn--door is 56px, not the 44px floor (--h-btn-min-h). 44px is the
       minimum for a thing you tap sitting down. The outcome buttons are
       pressed standing up, one-handed, sometimes in rain.
     · .h-pt-app keeps Patch's 14px root size. The property page is a stack of
       seven cards read as one screen; at 16px it becomes two.

   Reused rather than reinvented, for the record, because the next app should
   reach for the same ones: .h-shell + .h-sidebar (the chrome, untouched),
   .h-app-page (paper under the cards, and the full-width toast PAR added),
   .h-card + .h-card--static (every card and every section), .h-page-header,
   .h-display--page (the light-word/bold-word page title), .h-badge--* (every
   status flag and owner-type pill — they were .flag-* and .owner-pill at
   --h-radius-pill, which BRAND.md forbids), .h-notice + --muted (the "Rex
   already knows them" panel, the caveat strip, every flash), .h-pill (every
   filter chip), .h-segmented--yn (Add to Database), .h-field/.h-field__label/
   .h-label/.h-input/.h-select/.h-textarea (every control), .h-progress__track
   + __bar (the zone coverage bar), .h-empty, .h-actions, .h-toast,
   .h-phone-link, .h-muted, .h-btn.

   Conventions kept: authored variants --modifier, JS state is-*, JS-hidden is
   the `hidden` attribute (see .h-pt-app [hidden]), 4px corners, colour only
   through tokens, breakpoints 640/900 from --h-bp-phone/--h-bp-laptop.
   ========================================================================== */

/* ---------- The app frame ------------------------------------------------- */
/* On <body>, with .h-app-page. Patch's own 14px root, and the clearance the
   fixed bottom tab bar needs so the last row of a list is still tappable. */
.h-pt-app {
  font-size: var(--h-fs-sm);
  padding-bottom: var(--h-s-10);
}
/* JS hides things with the `hidden` attribute rather than a display class.
   The UA rule for [hidden] loses to any class that sets display, which is how
   a "hidden" panel stays on screen (the library already patches .h-label for
   exactly this). One attribute selector, scoped to Patch, settles it. */
.h-pt-app [hidden] { display: none; }

/* ---------- Two library defaults Patch cannot take as they ship ------------
   Both are scoped to .h-pt-app (which is on <body>), so the shared selector
   itself is untouched and no other app sees either rule.

   · .h-muted is --h-grey-50 (#8a8a8a): 3.45:1 on white, 3.22:1 on --h-paper.
     That is a decorative grey for a desk. Every muted line in Patch —
     the suburb under the address, "No knocks recorded yet.", the row count —
     is read at arm's length in sunlight by someone who cannot lean in, so all
     of it moves to --h-grey-70 (#4a4a4a, 8.86:1) along with the rest of this
     section. Quiet is still quiet: body ink here is --h-ink (#2a2a2a).
   · .h-badge is uppercase. Sentence case was what Patch shipped, and the
     difference is not cosmetic: "OWNER OCCUPIED" is wide enough to push the
     phone number off the dashboard row onto a line of its own, and to wrap
     every visit in the history to two lines. Letter-spacing stays — that is
     what makes a badge read as a badge. */
.h-pt-app .h-muted { color: var(--h-grey-70); }
.h-pt-app .h-badge { text-transform: none; }

.h-pt-main {
  width: 100%;
  max-width: 920px;
  margin: 0 auto;
  padding: var(--h-s-3);
}

/* ---------- Navigation at a front gate ------------------------------------
   Studio's phone layout folds the whole nav behind the hamburger. That is
   fine on a desk and wrong at a gate: an agent standing in front of someone
   should never spend a tap revealing a menu. Below the shell's own collapse
   point .h-pt-nav leaves the sidebar and becomes a fixed bottom bar — same
   navy, same .h-sidebar__link, same cyan active marker — so Today /
   Properties / Zones are always one thumb press away. Everything that is NOT
   a destination (back to Studio, who you are, sign out) stays in the drawer,
   which is what a hamburger is for. */
@media (max-width: 900px) {
  .h-pt-app {
    /* the bar's height, in the token .h-app-page already uses to lift a toast
       clear of a fixed bottom element */
    --h-pa-capture-h: calc(58px + env(safe-area-inset-bottom, 0px));
    padding-bottom: calc(var(--h-pa-capture-h) + var(--h-s-3));
  }
  .h-pt-app .h-sidebar { overflow: visible; }
  .h-pt-nav {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: var(--h-z-nav);
    display: flex;
    padding: 0 0 env(safe-area-inset-bottom, 0px);
    background: var(--h-blue);
    border-top: 1px solid rgba(255, 255, 255, 0.14);
  }
  .h-pt-nav .h-sidebar__link {
    flex: 1 1 0;
    flex-direction: column;
    justify-content: center;
    gap: 3px;
    min-height: 58px;
    padding: var(--h-s-2) var(--h-s-1);
    margin: 0;
    border-left: 0;
    border-top: 2px solid transparent;
    border-radius: 0;
    font-size: var(--h-fs-xs);
    font-weight: var(--h-fw-semibold);
    letter-spacing: var(--h-tracking-wide);
    text-transform: uppercase;
  }
  .h-pt-nav .h-sidebar__link svg { width: 23px; height: 23px; opacity: 1; }
  .h-pt-nav .h-sidebar__link.is-active {
    border-top-color: var(--h-cyan);
    background: rgba(255, 255, 255, 0.1);
  }
}

/* ---------- /today and /zones --------------------------------------------- */
/* A navy-led single-column card stack: one hero number per card, rows tall
   enough to hit with a thumb, and cyan reserved for the single "carry on
   here" action so it never becomes the page. */
.h-pt-screen {
  max-width: 640px;
  margin: 0 auto;
}
/* Every button on these two screens is hit standing at a gate. The shared
   --sm button is 36px, which is fine on a desk and not fine here. */
.h-pt-screen .h-btn { min-height: 44px; }

/* The knock counts are the SCORE, not the job. On a 390px screen the shared
   .h-today grid falls to one tile per row and pushes the market-report list —
   the thing that actually earns — three screens down. Three across, compact. */
.h-pt-screen .h-today {
  grid-template-columns: repeat(3, 1fr);
  gap: var(--h-s-2);
  margin-bottom: var(--h-s-4);
}
.h-pt-screen .h-today__tile { min-height: 0; padding: var(--h-s-3); gap: 0; }
/* Colour as well as size: at 10px the library's --h-grey-50 label measures
   3.22:1 on --h-paper, and these tiles are read outdoors. Scoped to
   .h-pt-screen so the shared tile is unchanged everywhere else. */
.h-pt-screen .h-today__label { font-size: 10px; letter-spacing: 0.06em; color: var(--h-grey-70); }
.h-pt-screen .h-today__value { font-size: var(--h-fs-2xl); }
.h-pt-screen .h-today__sub { font-size: 10px; color: var(--h-grey-70); }

/* The caveat strips and the zero-state on these screens are <p>, which the UA
   stylesheet gives a 1em margin. Spacing on these screens is the s-scale. */
.h-pt-screen > .h-notice,
.h-pt-screen > .h-empty { margin: 0 0 var(--h-s-4); }

/* margin-top:0 because .h-page-header carries s-6 above it on the dashboard,
   and a phone-first app starts at the top of the screen. */
.h-pt-head { margin-top: 0; margin-bottom: var(--h-s-4); }
.h-pt-head .h-display { margin-bottom: var(--h-s-1); }
.h-pt-head__sub {
  font-size: var(--h-fs-sm);
  color: var(--h-grey-70);
  margin: 0;
}
.h-pt-switch {
  display: flex; flex-wrap: wrap;
  gap: var(--h-s-2);
  margin-top: var(--h-s-3);
}

/* A section of the day: a title, the number that matters, rows, a footnote. */
.h-pt-sec {
  border-radius: var(--h-radius);
  margin-bottom: var(--h-s-4);
}
/* The money one — owed a market report — carries the navy rule. */
.h-pt-sec--money { border-color: var(--h-blue-20); border-top: 3px solid var(--h-blue); }
.h-pt-sec__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--h-s-3);
  padding: var(--h-s-3) var(--h-s-4);
  border-bottom: 1px solid var(--h-grey-10);
}
.h-pt-sec__title {
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-semibold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  color: var(--h-grey-70);
  margin: 0;
}
.h-pt-sec__count {
  font-size: var(--h-fs-2xl);
  font-weight: var(--h-fw-bold);
  letter-spacing: var(--h-tracking-tight);
  color: var(--h-blue);
  line-height: 1;
}
.h-pt-sec__note {
  padding: var(--h-s-2) var(--h-s-4) var(--h-s-3);
  font-size: var(--h-fs-xs);
  color: var(--h-grey-70);
  line-height: var(--h-lh-snug);
  margin: 0;
}
.h-pt-sec__foot {
  padding: var(--h-s-3) var(--h-s-4);
  border-top: 1px solid var(--h-grey-10);
  background: var(--h-paper);
}
/* .h-empty is sized for a whole page of nothing; inside a section card it is
   one line saying this list is clear. */
.h-pt-sec .h-empty {
  margin: 0;
  padding: var(--h-s-5) var(--h-s-4);
  font-size: var(--h-fs-sm);
}

/* A row you tap to open a door. */
.h-pt-rows { display: block; }
.h-pt-row {
  display: flex; align-items: center;
  gap: var(--h-s-3);
  min-height: 52px;
  padding: var(--h-s-3) var(--h-s-4);
  border-bottom: 1px solid var(--h-grey-10);
  color: var(--h-ink);
  text-decoration: none;
}
.h-pt-row:last-child { border-bottom: 0; }
.h-pt-row:hover { color: var(--h-ink); }
.h-pt-row:active { background: var(--h-blue-10); }
.h-pt-row__main { display: block; flex: 1 1 auto; min-width: 0; }
.h-pt-row__addr {
  display: block;
  font-size: var(--h-fs-base);
  font-weight: var(--h-fw-semibold);
  color: var(--h-blue);
  line-height: var(--h-lh-snug);
  overflow-wrap: anywhere;
}
.h-pt-row__meta {
  display: block;
  font-size: var(--h-fs-xs);
  color: var(--h-grey-70);
  margin-top: 2px;
  overflow-wrap: anywhere;
}
.h-pt-row__right {
  display: block; flex: 0 0 auto;
  text-align: right;
  line-height: var(--h-lh-snug);
  font-size: var(--h-fs-xs);
  color: var(--h-grey-70);
  white-space: nowrap;
}
.h-pt-row__age {
  display: block;
  font-size: var(--h-fs-lg);
  font-weight: var(--h-fw-bold);
  color: var(--h-grey-70);
  line-height: 1;
}
.h-pt-row__age--old { color: var(--h-warning-ink); }

/* "Morning" / "Afternoon" above the rows that belong to it. */
.h-pt-slot {
  padding: var(--h-s-2) var(--h-s-4);
  background: var(--h-paper);
  border-bottom: 1px solid var(--h-grey-10);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-semibold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  color: var(--h-grey-70);
}

/* ---------- Carry on here — the ONE cyan thing on the page ---------------- */
.h-pt-carry {
  display: block;
  padding: var(--h-s-4);
  background: var(--h-blue);
  border-radius: var(--h-radius);
  margin-bottom: var(--h-s-4);
  color: var(--h-white);
  text-decoration: none;
}
.h-pt-carry:hover { color: var(--h-white); }
.h-pt-carry__label {
  display: block;
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-semibold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  color: var(--h-cyan);
}
.h-pt-carry__street {
  display: block;
  font-size: var(--h-fs-2xl);
  font-weight: var(--h-fw-bold);
  letter-spacing: var(--h-tracking-tight);
  line-height: var(--h-lh-tight);
  margin-top: var(--h-s-1);
  color: var(--h-white);
  overflow-wrap: anywhere;
}
.h-pt-carry__sub {
  display: block;
  font-size: var(--h-fs-sm);
  color: var(--h-blue-20);
  margin-top: var(--h-s-2);
}

/* ---------- Zone cards ---------------------------------------------------- */
.h-pt-zones { display: grid; grid-template-columns: 1fr; gap: var(--h-s-3); }
.h-pt-zone {
  display: block;
  border-left: 3px solid var(--h-blue);
  border-radius: var(--h-radius);
  padding: var(--h-s-3) var(--h-s-4);
  color: var(--h-ink);
  text-decoration: none;
}
.h-pt-zone:hover { color: var(--h-ink); }
.h-pt-zone--next { border-left-color: var(--h-cyan); }
.h-pt-zone--empty { border-left-color: var(--h-grey-30); }
.h-pt-zone__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--h-s-3);
}
.h-pt-zone__label {
  display: block;
  font-size: var(--h-fs-lg);
  font-weight: var(--h-fw-bold);
  color: var(--h-blue);
  letter-spacing: var(--h-tracking-tight);
}
.h-pt-zone__name {
  display: block;
  font-size: var(--h-fs-sm);
  color: var(--h-grey-70);
  margin-top: 2px;
  overflow-wrap: anywhere;
}
.h-pt-zone__when {
  flex: 0 0 auto;
  font-size: var(--h-fs-xs);
  color: var(--h-grey-70);
  text-align: right;
  white-space: nowrap;
}
.h-pt-zone__stats { display: flex; flex-wrap: wrap; gap: var(--h-s-4); margin-top: var(--h-s-3); }
.h-pt-zone__stat { min-width: 64px; }
.h-pt-zone__num {
  display: block;
  font-size: var(--h-fs-xl);
  font-weight: var(--h-fw-bold);
  color: var(--h-blue);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.h-pt-zone__cap {
  display: block;
  font-size: var(--h-fs-xs);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  color: var(--h-grey-70);
  margin-top: var(--h-s-1);
}
/* The "longest since knocked" marker is a status, not a button. It stays the
   quiet navy badge — the cyan left border on the card is already the accent,
   and a second cyan block on the same card pushes past the 10% rule. */
.h-pt-zone .h-badge {
  display: inline-flex; align-items: center;
  width: auto; max-width: 100%;
  margin-top: var(--h-s-2);
}

/* Coverage, on .h-progress__track / __bar so there is one bar in the estate. */
.h-pt-bar { display: flex; align-items: center; gap: var(--h-s-3); margin-top: var(--h-s-3); }
.h-pt-bar .h-progress__track { flex: 1 1 auto; }
/* The library's bar is a <div> in a <div>; inside an <a> it has to be a
   <span>, and height:100% does nothing to an inline box — the fill vanished. */
.h-pt-bar .h-progress__bar { display: block; }
.h-progress__bar.h-pt-bar--full { background: var(--h-success); }
.h-pt-bar__pct {
  flex: 0 0 auto;
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-bold);
  color: var(--h-blue);
  font-variant-numeric: tabular-nums;
}

@media (min-width: 640px) {
  .h-pt-zones { grid-template-columns: 1fr 1fr; }
}

/* ---------- The property list and its filters ----------------------------- */
.h-pt-filters {
  display: flex; flex-direction: column;
  gap: var(--h-s-3);
  padding: var(--h-s-3);
  box-shadow: var(--h-shadow-sm);
}
.h-pt-filters__row { display: flex; gap: var(--h-s-2); flex-wrap: wrap; align-items: center; }
.h-pt-filters__row--chips { gap: var(--h-s-2) 6px; }
.h-pt-filters__row--end {
  justify-content: flex-end;
  padding-top: var(--h-s-1);
  border-top: 1px dashed var(--h-grey-10);
}
.h-pt-filters .h-input,
.h-pt-filters .h-select { flex: 1 1 140px; min-width: 140px; width: auto; }
.h-pt-filters .h-input[type="search"] { flex: 2 1 200px; }
.h-pt-filters__label {
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-bold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--h-grey-70);
  margin-right: var(--h-s-1);
}
.h-pt-filters__sort {
  display: flex; align-items: center; gap: var(--h-s-2);
  flex: 1 1 100%;
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-bold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--h-grey-70);
  margin: 0;
}

/* A filter chip is a .h-pill wrapping its own checkbox or radio, so a form
   post carries it. The library's .h-pill.is-active is for a chip a script
   marks; this is the same look driven by the control itself. */
.h-pt-chip { cursor: pointer; user-select: none; }
.h-pt-chip:has(input:checked) {
  background: var(--h-blue);
  border-color: var(--h-blue);
  color: var(--h-white);
}
.h-pt-chip:has(input:focus-visible) { box-shadow: var(--h-focus-glow); border-color: var(--h-cyan); }
/* The quick filters answer "what state is this door in", so the chosen ones
   read as the accent rather than as more navy. */
.h-pt-chip--status:has(input:checked) {
  background: var(--h-cyan);
  border-color: var(--h-cyan);
  color: var(--h-blue);
}

.h-pt-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--h-s-2); }
.h-pt-prop {
  display: block;
  padding: var(--h-s-3) var(--h-s-4);
  background: var(--h-white);
  border: 1px solid var(--h-grey-10);
  border-radius: var(--h-radius);
  color: var(--h-ink);
  text-decoration: none;
  transition: border-color var(--h-duration) var(--h-ease),
              box-shadow var(--h-duration) var(--h-ease);
}
.h-pt-prop:hover { border-color: var(--h-cyan); box-shadow: var(--h-shadow-sm); color: var(--h-ink); }
.h-pt-prop__main { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--h-s-3); margin-bottom: 6px; }
.h-pt-prop__addr { font-weight: var(--h-fw-bold); font-size: var(--h-fs-base); color: var(--h-blue); }
.h-pt-prop__meta {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--h-s-2) var(--h-s-3);
  font-size: var(--h-fs-xs);
  color: var(--h-grey-70);
}
.h-pt-prop__owner { font-weight: var(--h-fw-regular); color: var(--h-ink); }
.h-pt-prop__phone { font-variant-numeric: tabular-nums; }
.h-pt-flags { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }

/* Someone ELSE'S client sitting in your patch. Cyan, because "this one isn't
   yours" is the most useful thing to spot in the list — and navy ON cyan, not
   white on cyan, which is the only pair of the two that is readable. */
.h-pt-badge--other { background: var(--h-cyan); color: var(--h-blue); }
/* An owner type nobody has set yet: the error tint plus a dashed edge, so it
   reads as a gap in the data rather than as a state the property is in. */
.h-pt-badge--unset { border: 1px dashed var(--h-error); }

/* ---------- The doorstep -------------------------------------------------- */
/* Everything the agent needs with the owner standing there: who they are, how
   to call them, and the outcome — which saves on tap. */
.h-pt-top { display: flex; align-items: flex-start; gap: var(--h-s-3); margin-bottom: var(--h-s-4); }
.h-pt-back { flex: 0 0 auto; width: 44px; padding: 0; font-size: var(--h-fs-xl); }
.h-pt-id { min-width: 0; }
.h-pt-id .h-h2 { margin: 0; }

.h-pt-card { padding: var(--h-s-4); margin-bottom: var(--h-s-3); box-shadow: var(--h-shadow-sm); }
/* rows= is the authored height of the short notes fields on this page; the
   library's 120px floor turns a three-line note into half a phone screen.
   Same reason the stacked fields take the s-3 rhythm rather than s-4: the
   property page is seven cards deep and every 8px is a scroll at a door. */
.h-pt-card .h-textarea { min-height: 0; }
.h-pt-card > .h-field { margin-bottom: var(--h-s-3); }
.h-pt-card__title {
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-bold);
  color: var(--h-blue);
  margin: 0 0 var(--h-s-3);
}

.h-pt-who { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--h-s-3); }
.h-pt-who--stack { flex-direction: column; align-items: stretch; gap: 0; }
.h-pt-name { font-size: var(--h-fs-xl); font-weight: var(--h-fw-bold); color: var(--h-blue); }
.h-pt-name--none { color: var(--h-grey-70); font-weight: var(--h-fw-regular); }

/* 2,278 of 2,741 properties have no owner name, and the only place to type one
   was a form 400px down the page. Two inputs here, saved without a reload — a
   reload after a save has previously made agents think their typing vanished. */
.h-pt-nameedit {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--h-s-2);
  width: 100%;
  margin-top: var(--h-s-2);
}
/* 48px, the doorstep minimum for a secondary control — a 16px font so iOS
   does not zoom the page on focus and lose the agent's place in the card. */
.h-pt-nameedit .h-input { min-height: 48px; }
.h-pt-nameedit__save { grid-column: 1 / -1; min-height: 48px; }

.h-pt-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: var(--h-s-3) 0 var(--h-s-1); }

/* The question above a row of answers. */
.h-pt-q {
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-bold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  color: var(--h-grey-70);
  margin: var(--h-s-5) 0 var(--h-s-3);
}
.h-pt-q--sub { margin-top: var(--h-s-4); }
.h-pt-q__opt {
  margin-left: var(--h-s-2);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-regular);
  letter-spacing: 0;
  text-transform: none;
  color: var(--h-grey-70);
}
.h-pt-answers { display: grid; grid-template-columns: 1fr 1fr; gap: var(--h-s-3); }

/* Thumb-sized, gloves-and-rain sized. See the note at the top of this section
   for why this is 56 and not --h-btn-min-h. */
.h-btn--door { min-height: 56px; font-size: var(--h-fs-lg); }
.h-btn--door.is-on {
  background: var(--h-blue);
  border-color: var(--h-blue);
  color: var(--h-white);
}

/* On a phone :hover sticks after a tap, and .h-btn--secondary's hover fill is
   the same navy as .is-on — so a button an agent merely brushed past would sit
   there reading as the answer they gave. On the doorstep that is the one thing
   the colour is for, so on a touch screen these buttons take no hover. */
@media (hover: none) {
  .h-btn--door:hover:not(.is-on):not(:disabled) {
    background: var(--h-white);
    color: var(--h-blue);
    border-color: var(--h-blue);
  }
}

/* A status line under a form that saves itself: what just happened, in place,
   because there is no page reload to carry the news. */
.h-pt-status {
  display: block;
  margin-top: var(--h-s-3);
  font-size: var(--h-fs-sm);
  color: var(--h-grey-70);
}
.h-pt-status.is-ok  { color: var(--h-success-ink); font-weight: var(--h-fw-semibold); }
.h-pt-status.is-err { color: var(--h-error-ink);   font-weight: var(--h-fw-semibold); }
/* Small print under an optional extra, not under the thing that saved. */
.h-pt-when { display: block; margin-top: 2px; font-size: var(--h-fs-xs); opacity: 0.75; }

/* 146 of the 259 knocks ever recorded found nobody home. Both of these appear
   only after the knock is saved, so neither can block it. */
.h-pt-extras { margin-top: var(--h-s-4); padding-top: var(--h-s-4); border-top: 1px solid var(--h-grey-10); }

/* 1,410 of Ben's 1,476 properties have no bed/bath/car on file, so the print
   CMA refused nearly all of them. Ask for exactly the fields that are missing,
   then queue in the same tap. */
.h-pt-feat {
  margin-top: var(--h-s-4);
  padding: var(--h-s-4);
  background: var(--h-warning-soft);
  border: 1px solid var(--h-grey-10);
  border-radius: var(--h-radius);
}
.h-pt-feat .h-pt-q { margin-top: 0; }
.h-pt-feat__row { display: grid; grid-template-columns: 1fr; gap: var(--h-s-3); }

/* ---------- Forms on the property page ------------------------------------ */
/* Two columns on purpose: First name / Surname belong on one line whatever the
   screen, and stacking them costs a scroll at a door. The one exception is a
   select, which cannot shrink its own value — see the 640 block below. */
.h-pt-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--h-s-2) var(--h-s-3);
}
.h-pt-grid--3 { grid-template-columns: repeat(3, 1fr); }
.h-pt-grid .h-field { margin-bottom: 0; }
.h-pt-grid__full { grid-column: 1 / -1; }
.h-pt-subhead {
  grid-column: 1 / -1;
  margin: var(--h-s-1) 0 calc(-1 * var(--h-s-1));
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-bold);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--h-blue);
  opacity: 0.75;
}
.h-pt-subhead:first-child { margin-top: 0; }
@media (max-width: 640px) {
  .h-pt-grid--3 { grid-template-columns: 1fr; }
  /* An input shrinks its text; a select cannot — it clips the chosen option
     and shows a word with its tail cut off, which on this form is a FACT about
     the house. At 390 a grid column is 160px, and .h-select spends 16 left and
     34 right (the chevron) of it, leaving 108px: "Owner Occupied" needs 111 and
     rendered as "Owner Occupiec"; "Government Owned - Other" needs 184. So any
     field holding a select takes the whole row at phone width. The name pairs,
     phone and email keep their two columns — those are inputs, and pairing them
     is the whole reason this grid does not simply stack (see above). */
  .h-pt-grid > .h-field:has(> .h-select) { grid-column: 1 / -1; }
}

/* Add to Database is a two-option answer; the library already owns that shape.
   Only the width differs — 108px is a table cell, this is a card. */
.h-pt-seg { max-width: 340px; }

/* ---------- A fold ---------------------------------------------------------
   Everything that is not the doorstep folds away. The marker is drawn on the
   summary so no app has to ship a chevron image. */
.h-pt-fold { margin-bottom: var(--h-s-3); }
.h-pt-fold > summary {
  display: flex; align-items: baseline; gap: var(--h-s-3);
  cursor: pointer;
  list-style: none;
}
.h-pt-fold > summary::-webkit-details-marker { display: none; }
.h-pt-fold > summary::after { content: "\FF0B"; margin-left: auto; color: var(--h-grey-70); }
.h-pt-fold[open] > summary::after { content: "\FF0D"; }
.h-pt-fold__title {
  font-size: var(--h-fs-sm);
  font-weight: var(--h-fw-bold);
  color: var(--h-blue);
}
.h-pt-fold__hint { font-size: var(--h-fs-sm); color: var(--h-grey-70); }
.h-pt-fold[open] > summary { margin-bottom: var(--h-s-3); }

/* ---------- Visit history -------------------------------------------------- */
.h-pt-visits { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--h-s-3); }
.h-pt-visit {
  padding: var(--h-s-3);
  background: var(--h-paper);
  border-left: 3px solid var(--h-cyan);
  border-radius: var(--h-radius);
}
.h-pt-visit__when {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 6px;
  margin-bottom: var(--h-s-1);
  font-size: var(--h-fs-xs);
  color: var(--h-grey-70);
}
.h-pt-visit__notes { font-size: var(--h-fs-sm); color: var(--h-ink); line-height: var(--h-lh-snug); }

/* ---------- Patch: don't knock again ---------------------------------------
   "No, we don't want anything to do with real estate." Recorded at the door,
   honoured on every rotation after it. A Patch flag only — it has nothing to
   do with Rex, marketing or contact preferences.

   .h-pt-btn--dnk   the opener in the extras strip. Reads as the heavy thing it
                    is without being a filled red button sitting beside two
                    harmless ones.
   .h-pt-dnk        the notice on a flagged property, with the undo.
   .h-pt-prop--dnk  the greyed row in the list. Greyed, never hidden — a hidden
                    house is indistinguishable from one nobody has knocked. */
/* The doorstep answer rows hold short words — "CMA yes", "Morning" — so a
   plain 1fr column has always been wide enough. The don't-knock reasons are
   phrases, and .h-btn is white-space: nowrap, so the column was sized by the
   longest label and pushed the second one past the modal's edge (caught at
   375px, 17/09/2026). Shrinkable columns, and labels that may wrap. */
.h-pt-answers--reasons { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.h-pt-answers--reasons .h-btn {
  white-space: normal;
  line-height: var(--h-lh-snug);
  text-align: center;
  font-size: var(--h-fs-base);
}

.h-pt-btn--dnk {
  border-color: var(--h-error);
  color: var(--h-error-ink);
  background: var(--h-white);
}
.h-pt-btn--dnk:hover:not(:disabled) {
  background: var(--h-error-soft);
  border-color: var(--h-error);
  color: var(--h-error-ink);
}

.h-pt-dnk {
  margin: var(--h-s-3) 0 var(--h-s-4);
  padding: var(--h-s-3) var(--h-s-4);
  background: var(--h-error-soft);
  border: 1px solid var(--h-error);
  border-radius: var(--h-radius);
}
.h-pt-dnk[hidden] { display: none; }
.h-pt-dnk__head {
  font-weight: var(--h-fw-bold);
  color: var(--h-error-ink);
  letter-spacing: var(--h-tracking-tight);
}
.h-pt-dnk__why {
  margin: var(--h-s-1) 0 var(--h-s-3);
  font-size: var(--h-fs-sm);
  color: var(--h-grey-70);
}

/* Legible, plainly de-emphasised, and still a link you can open — an agent
   walking the street has to be able to read the address to know which house
   it is, and tap it to lift the flag when it has changed hands. */
.h-pt-prop--dnk { background: var(--h-grey-10); border-style: dashed; }
.h-pt-prop--dnk .h-pt-prop__addr,
.h-pt-prop--dnk .h-pt-prop__meta { opacity: 0.55; }
.h-pt-prop--dnk:hover .h-pt-prop__addr,
.h-pt-prop--dnk:hover .h-pt-prop__meta { opacity: 1; }

/* ==========================================================================
   CBC Self Storage (storage.hdas.com.au) blocks — added 15/09/2026
   --------------------------------------------------------------------------
   storage.hdas.com.au carried about 2,100 lines of CSS spread across twelve
   inline <style> blocks, opening with a local :root that aliased
   --navy — --cyan — --bg — --border — --muted onto values this file already
   owns. All of it is gone; what is left here are the patterns CBC needs that
   the library did not already have. Everything is ADDITIVE — no rule above
   this line changed.

   CBC is a different business that Harcourts manages, and the site is public
   and indexed, so its identity is untouched: the CBC logo, the three-location
   structure, the copy, the SEO head and the sitemap are byte-for-byte what
   they were. What changed is that the chrome and the components are the
   library's.

   Reused rather than reinvented, for the record, because the next app should
   reach for the same ones: .h-shell + .h-sidebar (the whole left chrome, the
   grouped links, the count badges AND the built-in 900px hamburger drawer —
   it replaced 240 lines of bespoke mobile overlay), .h-shell__main and
   .h-shell__content, .h-footer, .h-card + .h-card--static + .h-card__body —
   __title — __meta (every panel on every page), .h-page-header (every section
   heading), .h-h1 — .h-h2 — .h-h3, .h-eyebrow, .h-lead, .h-underline,
   .h-on-blue, .h-stat-row + .h-stat (the home counters), .h-form-card and
   .h-field — .h-field__label — .h-label__note — .h-label__req — .h-input —
   .h-select — .h-textarea — .h-input--readonly — .h-checkbox (every control
   on the enquiry and application forms), .h-grid--2 (the paired name and
   phone rows), .h-notice + --info — --warning — --error — --muted (the
   alerts, the declaration, the default warning, the payment warning),
   .h-badge--quiet (the unit type), .h-badge--info-soft (the floor label),
   .h-list, .h-empty, .h-actions, .h-divider, .h-modal-backdrop + .h-modal +
   .h-modal-close (the floor-plan popup), .h-phone-link (every tel and mailto
   link), .h-btn and its variants (every button and button-styled link).

   Three numbers here are deliberately NOT the old sheet's, and each fixes a
   measured defect rather than a taste:
     · Body text never sits on --h-grey-50. The old sheet's --muted was
       #8a8a8a, which is 3.0:1 on white and fails AA. Every reading style in
       this section is --h-grey-70 or --h-ink, and the .h-st-page block below
       lifts the library's own grey-50 text to grey-70 for this site only.
     · "17 units available" and the map and contact links were cyan on white
       at 2.4:1. Cyan stays where it is an accent — rules, the eyebrow, the
       underline band, the tick — and the reading colour is --h-info-ink
       (6.0:1) or navy.
     · The mobile breakpoint is 900px (--h-bp-laptop), the sidebar's own, not
       the old 720px. Between 720 and 768 the 260px sidebar had been pushing
       every page 44px wider than the viewport.

   Conventions kept: authored variants --modifier, JS state is-*, JS-hidden is
   the hidden attribute, 4px corners except true circles, colour only through
   tokens, breakpoints 640 and 900 from --h-bp-phone and --h-bp-laptop.
   ========================================================================== */

/* ---------- The page, and the contrast sweep ------------------------------ */
/* On <body>, with .h-shell. Everything below is rooted here or in .h-st-*, so
   this section cannot reach another app's markup. The grey-50 lifts are the
   contrast fix described above: they are scoped to this site, so the library
   keeps its own value everywhere else. */
.h-st-page { background: var(--h-paper); }
/* The home page's "View Available Units" is an in-page anchor. scroll-behavior
   only takes effect on the element that actually scrolls — the root, not the
   body — so it is reached through :has() rather than declared on html, which
   would reach every app that links this file. */
html:has(> body.h-st-page) { scroll-behavior: smooth; }
.h-st-page .h-meta,
.h-st-page .h-muted,
.h-st-page .h-stat:not(.h-stat--accent) .h-stat__label,
.h-st-page .h-stat:not(.h-stat--accent) .h-stat__sub,
.h-st-page .h-page-header__sub,
.h-st-page .h-card__meta,
.h-st-page .h-empty,
.h-st-page .h-empty__hint { color: var(--h-grey-70); }
/* :not(.h-stat--accent) matters — that tile is navy, and grey-70 on navy is
   1.8:1. The library already gives it white at 0.75 alpha. */
.h-st-page .h-sidebar__group { color: rgba(255, 255, 255, 0.6); }

/* A section heading: .h-page-header carrying an .h-h2 and optional .h-meta.
   The library's headings own a bottom margin for prose flow; inside the
   header row it would push the rule off the baseline. Scoped to this site. */
.h-st-page .h-page-header > .h-h2,
.h-st-page .h-page-header > .h-h3 { margin: 0; }

/* The content column. .h-shell__content already caps and pads it; CBC's
   panels stack, so give them a rhythm without a wrapper class per page. */
.h-st-page .h-shell__content { max-width: var(--h-container); }
/* CBC's pages are a stack of panels. .h-page-header, .h-stat-row, .h-actions
   and .h-st-floorhead each carry their own vertical margin already, so the
   rhythm is declared once here and those four opt out rather than every page
   carrying a spacing class. */
.h-st-page .h-shell__content > * + *:not(.h-page-header):not(.h-stat-row):not(.h-actions):not(.h-st-floorhead),
.h-st-page .h-shell__content > form > * + * { margin-top: var(--h-s-4); }

/* The application form is a reading-width column, not the full grid. */
.h-st-page .h-shell__content.h-container--narrow { max-width: var(--h-container-narrow); }

/* A marketing page can be one screen tall (a thank-you, a 404). The content
   column grows so the footer sits on the fold rather than halfway up, and the
   library's generous footer offset is trimmed because CBC's pages already end
   in a panel. */
.h-st-page .h-shell__content { flex: 1 0 auto; }
.h-st-page .h-footer { margin-top: var(--h-s-6); }

/* The library underlines every <a> by default, which is right for a link in
   prose and wrong for a card that is entirely a link. */
.h-st-page a.h-card { text-decoration: none; }
.h-st-page .h-st-band .h-eyebrow a { text-decoration: none; color: inherit; }

/* .h-notice and .h-checkbox carry no outer margin in the library, because in
   Studio they sit in flex or grid parents. CBC's form sections stack them in
   normal flow. */
.h-st-page .h-notice { margin-bottom: var(--h-s-4); }
.h-st-page .h-notice:last-child { margin-bottom: 0; }
.h-st-page .h-checkbox { margin: var(--h-s-2) 0 var(--h-s-5); }

/* ---------- Managed by Harcourts ------------------------------------------ */
/* CBC is managed by the office, and says so in five places: the sidebar, the
   mobile drawer, the home page, the application form and the footer. One
   block, two grounds. The logo keeps its own aspect; the dark variant is the
   white wordmark on navy. */
.h-st-managed {
  display: inline-flex;
  align-items: center;
  gap: var(--h-s-4);
  text-decoration: none;
}
.h-st-managed--stack {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--h-s-2);
}
.h-st-managed__label {
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-semibold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  color: var(--h-grey-70);
  white-space: nowrap;
}
.h-st-managed__logo { display: block; height: 28px; width: auto; }
.h-st-managed--sm .h-st-managed__logo { height: 20px; }
/* The stacked mark carries the office names on a second line, so it has to be
   sized by width — at a 28px cap height the "Dapto | Albion Park |
   Shellharbour" line is unreadable. */
.h-st-managed--stack .h-st-managed__logo { width: 140px; height: auto; }
.h-st-managed--dark .h-st-managed__label { color: rgba(255, 255, 255, 0.55); }
.h-st-managed--dark .h-st-managed__logo { opacity: 0.6; transition: opacity var(--h-duration) var(--h-ease); }
.h-st-managed--dark:hover .h-st-managed__logo { opacity: 0.9; }
.h-st-managed--card {
  display: flex;
  flex-wrap: wrap;
  margin-top: var(--h-s-6);
  padding: var(--h-s-5) var(--h-s-6);
  border-top: 2px solid var(--h-cyan);
}
@media (max-width: 640px) {
  .h-st-managed__label { white-space: normal; }
}

/* ---------- Sidebar head and foot ----------------------------------------- */
/* The CBC mark is a raster logo on a white plate, not a wordmark, so it needs
   its own lockup rather than .h-sidebar__brand's baseline alignment. */
.h-st-brand { display: block; padding: var(--h-s-5) var(--h-s-5) var(--h-s-4); text-decoration: none; }
.h-st-brand__logo { display: block; width: 150px; max-width: 100%; height: auto; }
/* Sits inside .h-sidebar__drawer, so it is a sibling of .h-st-brand rather
   than a child (the drawer is display:contents above 900px) and carries its
   own padding. Hidden with the rest of the drawer on a phone, where the
   footer says the same thing. */
.h-st-brand__by {
  display: block;
  padding: var(--h-s-4) var(--h-s-5);
  border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.h-st-sidefoot {
  padding: var(--h-s-4) var(--h-s-5);
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  font-size: var(--h-fs-xs);
  color: rgba(255, 255, 255, 0.5);
}

/* ---------- Full-bleed page band ------------------------------------------ */
/* Every page opens with a band that runs the width of the main column: white
   for an interior page, navy for the home hero. .h-section is the library's
   vertical rhythm but carries no ground and no centring, and the band has to
   sit OUTSIDE .h-shell__content to bleed, so it is its own block. */
.h-st-band {
  background: var(--h-white);
  border-bottom: var(--h-border);
  padding: var(--h-s-10) var(--h-s-8) var(--h-s-8);
  text-align: center;
}
.h-st-band__inner { max-width: 820px; margin: 0 auto; }
.h-st-band__title { margin: 0; }
.h-st-band__sub {
  max-width: 560px;
  margin: var(--h-s-3) auto 0;
  font-size: var(--h-fs-base);
  line-height: var(--h-lh-base);
  color: var(--h-grey-70);
}
.h-st-band .h-actions { justify-content: center; }
.h-st-band--hero {
  background: var(--h-blue);
  border-bottom: 0;
  padding: var(--h-s-12) var(--h-s-8) var(--h-s-10);
}
.h-st-band--hero .h-st-band__sub { color: rgba(255, 255, 255, 0.75); font-size: var(--h-fs-lg); }
.h-st-band--hero .h-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--h-s-2);
  margin-bottom: var(--h-s-4);
}
.h-st-band__mark { display: block; height: 16px; width: auto; opacity: 0.8; }
.h-st-band__sep { color: rgba(255, 255, 255, 0.6); }

/* The second action on a navy band. .h-btn-ghost is navy-on-transparent and
   disappears here; .h-btn-secondary is solid white and competes with the
   primary. This is the outline form, at 12:1 on navy. */
.h-st-btn--ondark {
  background: transparent;
  color: var(--h-white);
  border-color: rgba(255, 255, 255, 0.45);
}
.h-st-btn--ondark:hover {
  background: rgba(255, 255, 255, 0.12);
  color: var(--h-white);
  border-color: var(--h-white);
}
.h-st-btn--ondark:active:not(:disabled):not([aria-disabled="true"]) {
  background: rgba(255, 255, 255, 0.2);
  color: var(--h-white);
}

/* The one big marketing headline on the site. The library's .h-display is
   light 300 by design; CBC's hero has always been the bold end of the weight
   pairing, and it is the first thing a storage customer sees. */
.h-st-band--hero .h-st-band__title {
  font-size: var(--h-fs-4xl);
  font-weight: var(--h-fw-bold);
  line-height: var(--h-lh-tight);
  letter-spacing: var(--h-tracking-tight);
  color: var(--h-white);
}

/* ---------- Shared small parts -------------------------------------------- */
/* An uppercase micro-label. The library's .h-stat__label is the same shape at
   --h-grey-50; this one reads at AA on white, which matters because CBC uses
   it over addresses, bank details and contact rows, not just over a number. */
.h-st-label {
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-semibold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  color: var(--h-grey-70);
  margin: 0 0 var(--h-s-2);
}
/* The same label doing a heading's job — a clause group, a bank account, a
   person's role. .h-eyebrow is the library's block for this and is cyan by
   brand rule, which is 2.5:1 on white; this site has thirty of them in the
   agreement alone, so they are navy here. */
.h-st-label--head { color: var(--h-blue); }

/* Reading copy inside a card. --dense is the legal and reference scale used
   by the agreement page and the in-form terms. */
.h-st-prose > p,
.h-st-prose > ul,
.h-st-prose > ol { margin: 0 0 var(--h-s-3); font-size: var(--h-fs-base); line-height: var(--h-lh-base); color: var(--h-ink); }
.h-st-prose > :last-child { margin-bottom: 0; }
.h-st-prose strong { color: var(--h-blue); font-weight: var(--h-fw-semibold); }
.h-st-prose--dense > p,
.h-st-prose--dense > ul,
.h-st-prose--dense > ol { font-size: var(--h-fs-sm); }

/* A cyan hairline across the top of a card — the accent that says "this is a
   fact about the facility". --error is the same device on the prohibited
   items, where the point is the opposite. */
.h-st-accent { border-top: 3px solid var(--h-cyan); }
.h-st-accent--error { border-top-color: var(--h-error); }

/* An auto-filling card grid. One block, four densities, because CBC lays out
   units, facts, locations and prohibited items with the same idea at
   different sizes. */
.h-st-grid {
  display: grid;
  gap: var(--h-s-3);
  grid-template-columns: repeat(auto-fill, minmax(var(--h-st-col, 220px), 1fr));
}
.h-st-grid--xs { --h-st-col: 150px; }
.h-st-grid--sm { --h-st-col: 170px; }
.h-st-grid--lg { --h-st-col: 280px; }

/* A circular mark that numbers or ticks a step. */
.h-st-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: var(--h-radius-pill);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-bold);
  background: var(--h-blue);
  color: var(--h-white);
}
.h-st-mark--tick { background: var(--h-success-soft); color: var(--h-success-ink); }
.h-st-mark--accent { background: var(--h-cyan); color: var(--h-white); }
.h-st-mark--lg { width: 32px; height: 32px; font-size: var(--h-fs-sm); }
.h-st-mark--xl { width: 64px; height: 64px; }
.h-st-mark--xl svg { width: 30px; height: 30px; }

/* ---------- Divided row list ---------------------------------------------- */
/* Packing tips, the moving checklist, what you need to get started, the fee
   schedule, the FAQ and the agreement's clause groups are all the same thing:
   rows divided by a hairline inside one card. Six patterns, one block. */
.h-st-rows { display: flex; flex-direction: column; }
.h-st-rows__head {
  padding: var(--h-s-3) var(--h-s-6);
  background: var(--h-paper);
  border-bottom: var(--h-border);
}
.h-st-row {
  display: flex;
  align-items: flex-start;
  gap: var(--h-s-4);
  padding: var(--h-s-5) var(--h-s-6);
  border-bottom: var(--h-border);
}
.h-st-row:last-child { border-bottom: 0; }
.h-st-row__glyph { flex: none; width: 32px; text-align: center; font-size: var(--h-fs-xl); line-height: 1.2; }
.h-st-row__body { min-width: 0; flex: 1; }
.h-st-row__title {
  display: block;
  margin: 0 0 var(--h-s-1);
  font-size: var(--h-fs-base);
  font-weight: var(--h-fw-semibold);
  color: var(--h-blue);
  line-height: var(--h-lh-snug);
}
.h-st-sub { display: block; font-size: var(--h-fs-sm); color: var(--h-grey-70); line-height: var(--h-lh-snug); }
.h-st-row__amount {
  flex: none;
  font-size: var(--h-fs-xl);
  font-weight: var(--h-fw-bold);
  color: var(--h-blue);
  white-space: nowrap;
}
.h-st-row__amount small { font-size: var(--h-fs-xs); font-weight: var(--h-fw-regular); color: var(--h-grey-70); }

/* ---------- Unit cards ----------------------------------------------------- */
.h-st-unit { display: flex; flex-direction: column; padding: var(--h-s-5); }
.h-st-unit__media { margin: calc(var(--h-s-5) * -1) calc(var(--h-s-5) * -1) var(--h-s-4); aspect-ratio: 16 / 9; overflow: hidden; }
.h-st-unit__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.h-st-unit__tag {
  display: block;
  margin: 0 0 var(--h-s-2);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-bold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  color: var(--h-grey-70);
}
.h-st-unit__size {
  margin: 0 0 var(--h-s-1);
  font-size: var(--h-fs-2xl);
  font-weight: var(--h-fw-bold);
  line-height: 1;
  letter-spacing: var(--h-tracking-tight);
  color: var(--h-blue);
}
.h-st-unit__size sup { font-size: var(--h-fs-sm); font-weight: var(--h-fw-semibold); letter-spacing: 0; }
.h-st-unit__vol { margin: 0 0 var(--h-s-2); font-size: var(--h-fs-xs); color: var(--h-grey-70); }
.h-st-unit__dims {
  margin: 0 0 var(--h-s-3);
  padding-bottom: var(--h-s-3);
  border-bottom: var(--h-border);
  font-size: var(--h-fs-xs);
  color: var(--h-grey-70);
}
.h-st-unit__dims:empty { padding-bottom: 0; border-bottom: 0; }
.h-st-unit .h-badge { align-self: flex-start; margin-bottom: var(--h-s-3); }
.h-st-unit__price { margin: 0; font-size: var(--h-fs-xl); font-weight: var(--h-fw-bold); color: var(--h-blue); }
.h-st-unit__price--poa { font-size: var(--h-fs-base); color: var(--h-grey-70); }
.h-st-unit__cadence { font-size: var(--h-fs-xs); font-weight: var(--h-fw-regular); color: var(--h-grey-70); }
.h-st-unit__notes { margin: var(--h-s-2) 0 0; font-size: var(--h-fs-xs); color: var(--h-grey-70); line-height: var(--h-lh-snug); }
/* The library keeps button labels on one line, which is right for a toolbar
   and wrong in a 170px unit tile — "Enquire about this unit" was overflowing
   the card. Scoped to the unit card only. */
.h-st-unit .h-btn {
  margin-top: var(--h-s-4);
  white-space: normal;
  line-height: var(--h-lh-snug);
}
.h-st-unit__notes + .h-btn { margin-top: var(--h-s-3); }

/* How many units are free at a location. --h-info-ink, not cyan: this is a
   line people read, and cyan on white is 2.4:1. */
.h-st-avail { margin: var(--h-s-2) 0 0; font-size: var(--h-fs-sm); font-weight: var(--h-fw-semibold); color: var(--h-info-ink); }
.h-st-avail--none { color: var(--h-grey-70); font-weight: var(--h-fw-regular); }

.h-st-floorhead { display: flex; align-items: center; flex-wrap: wrap; gap: var(--h-s-3); margin: var(--h-s-6) 0 var(--h-s-4); }
.h-st-floorhead__sub { font-size: var(--h-fs-sm); color: var(--h-grey-70); }
.h-st-floorempty { margin: 0; padding: var(--h-s-5) 0; font-size: var(--h-fs-sm); color: var(--h-grey-70); }

/* ---------- Wollongong floor plan ------------------------------------------ */
/* An SVG site map where every available unit is a link into the enquiry form.
   Taken units are inert. Colour is carried on the group so one class per cell
   drives both the rectangle and its label. */
.h-st-fp__frame {
  padding: var(--h-s-3);
  background: var(--h-blue-10);
  border: var(--h-border);
  border-radius: var(--h-radius);
  overflow-x: auto;
}
.h-st-fp__svg { display: block; width: 100%; max-width: 560px; margin: 0 auto; }
.h-st-fp__building { fill: var(--h-white); stroke: var(--h-blue); stroke-width: 2.5; stroke-linejoin: miter; }
.h-st-fp__link { text-decoration: none; }
.h-st-fp__unit rect { stroke-width: 1.5; transition: fill var(--h-duration) var(--h-ease); }
.h-st-fp__unit text { font-family: var(--h-font-sans); font-size: 10px; font-weight: var(--h-fw-bold); pointer-events: none; }
.h-st-fp__unit--taken rect { fill: var(--h-blue-10); stroke: var(--h-grey-30); }
.h-st-fp__unit--taken text { fill: var(--h-grey-70); }
.h-st-fp__unit--avail rect { fill: var(--h-info-soft); stroke: var(--h-cyan); stroke-width: 2; }
.h-st-fp__unit--avail text { fill: var(--h-info-ink); }
.h-st-fp__link:hover .h-st-fp__unit--avail rect { fill: var(--h-blue-10); stroke: var(--h-blue); }
.h-st-fp__legend { display: flex; flex-wrap: wrap; gap: var(--h-s-3) var(--h-s-6); margin-top: var(--h-s-3); font-size: var(--h-fs-sm); }
.h-st-fp__key { display: inline-flex; align-items: center; gap: var(--h-s-2); color: var(--h-grey-70); }
.h-st-fp__swatch { width: 14px; height: 14px; flex: none; border-radius: var(--h-radius-sm); border: 1px solid var(--h-grey-30); background: var(--h-blue-10); }
.h-st-fp__swatch--avail { background: var(--h-info-soft); border-color: var(--h-cyan); }

/* The popup a floor-plan cell opens: the library's .h-modal carrying a unit
   card. Narrower than the library default because it holds one card, and it
   clears the close button at the top. */
.h-st-unitmodal {
  width: min(340px, calc(100vw - var(--h-s-6)));
  padding-top: var(--h-s-8);
}

/* ---------- Map panel ------------------------------------------------------ */
.h-st-map__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--h-s-4);
  padding: var(--h-s-5) var(--h-s-6);
  border-bottom: var(--h-border);
}
.h-st-map__frame { display: block; width: 100%; height: 360px; border: 0; }

/* ---------- Definitions list ----------------------------------------------- */
.h-st-defs {
  display: grid;
  grid-template-columns: 180px 1fr;
  margin: var(--h-s-3) 0 0;
  border: var(--h-border);
  border-radius: var(--h-radius);
  overflow: hidden;
  font-size: var(--h-fs-sm);
  line-height: var(--h-lh-snug);
}
.h-st-defs__term {
  margin: 0;
  padding: var(--h-s-3) var(--h-s-4);
  font-weight: var(--h-fw-bold);
  color: var(--h-blue);
  border-bottom: var(--h-border);
}
.h-st-defs__desc {
  margin: 0;
  padding: var(--h-s-3) var(--h-s-4);
  color: var(--h-ink);
  border-bottom: var(--h-border);
}
.h-st-defs__term:nth-last-of-type(1),
.h-st-defs__desc:nth-last-of-type(1) { border-bottom: 0; }

/* ---------- Bank details and contact rows ---------------------------------- */
.h-st-bank {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
  gap: var(--h-s-5);
  padding-bottom: var(--h-s-5);
  border-bottom: var(--h-border);
  margin-bottom: var(--h-s-4);
}
.h-st-bank--plain { padding-bottom: 0; border-bottom: 0; margin-bottom: 0; gap: var(--h-s-4); }
.h-st-bank__field { display: flex; flex-direction: column; gap: var(--h-s-1); }
.h-st-bank__field .h-st-label { margin: 0; }
.h-st-bank__value { font-size: var(--h-fs-lg); font-weight: var(--h-fw-bold); color: var(--h-blue); }
.h-st-bank--plain .h-st-bank__value { font-size: var(--h-fs-sm); }

.h-st-deets { display: flex; flex-direction: column; gap: var(--h-s-3); }
.h-st-deets__row { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--h-s-2) var(--h-s-3); font-size: var(--h-fs-sm); }
.h-st-deets__label { flex: none; min-width: 72px; font-size: var(--h-fs-xs); font-weight: var(--h-fw-semibold); color: var(--h-grey-70); }
.h-st-deets__value { color: var(--h-ink); }

/* ---------- Scrolling terms box -------------------------------------------- */
.h-st-scroll {
  max-height: 340px;
  overflow-y: auto;
  padding: var(--h-s-5) var(--h-s-6);
  background: var(--h-paper);
  border: var(--h-border);
  border-radius: var(--h-radius);
}
.h-st-scroll .h-st-label { margin-top: var(--h-s-5); color: var(--h-blue); }
.h-st-scroll > :first-child { margin-top: 0; }

/* ---------- Application step header ---------------------------------------- */
.h-st-stephead {
  display: flex;
  align-items: flex-start;
  gap: var(--h-s-4);
  padding: var(--h-s-5) var(--h-s-6);
  background: var(--h-paper);
  border-bottom: var(--h-border);
}
.h-st-stephead__title { margin: 0 0 var(--h-s-1); font-size: var(--h-fs-lg); font-weight: var(--h-fw-bold); color: var(--h-blue); }
.h-st-stephead__sub { margin: 0; font-size: var(--h-fs-sm); color: var(--h-grey-70); line-height: var(--h-lh-snug); }

/* ---------- Thanks and error pages ------------------------------------------ */
.h-st-thanks {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: var(--h-s-12) var(--h-s-5);
}
.h-st-thanks__body { max-width: 440px; }
.h-st-thanks .h-st-mark { margin-bottom: var(--h-s-5); }
.h-st-thanks .h-actions { justify-content: center; }
.h-st-thanks .h-st-rows {
  width: 100%;
  max-width: 420px;
  margin-top: var(--h-s-6);
  text-align: left;
  background: var(--h-white);
  border: var(--h-border);
  border-radius: var(--h-radius-lg);
}
.h-st-errcode {
  margin: 0 0 var(--h-s-4);
  font-size: var(--h-fs-5xl);
  font-weight: var(--h-fw-bold);
  line-height: 1;
  letter-spacing: var(--h-tracking-tight);
  color: var(--h-blue);
}

/* ---------- Prohibited items ------------------------------------------------ */
.h-st-prohibited {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--h-s-3);
  padding: var(--h-s-5) var(--h-s-4) var(--h-s-4);
  text-align: center;
}
.h-st-prohibited__icon { font-size: var(--h-fs-2xl); line-height: 1; }
.h-st-prohibited__label { font-size: var(--h-fs-xs); font-weight: var(--h-fw-semibold); color: var(--h-blue); line-height: var(--h-lh-snug); }

/* ---------- Footer ---------------------------------------------------------- */
/* .h-footer supplies the navy ground and the padding; CBC's four columns and
   its location and contact lists are the part the library did not have. */
.h-st-footer__grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1.4fr 1fr;
  gap: var(--h-s-8);
  max-width: var(--h-container);
  margin: 0 auto;
  padding: 0 var(--h-s-8);
}
.h-st-footer__logo { display: block; width: 110px; height: auto; margin-bottom: var(--h-s-4); }
.h-st-footer__tagline { margin: 0 0 var(--h-s-5); font-size: var(--h-fs-sm); line-height: var(--h-lh-base); color: rgba(255, 255, 255, 0.7); }
.h-st-footer__heading {
  margin: 0 0 var(--h-s-4);
  font-size: var(--h-fs-xs);
  font-weight: var(--h-fw-bold);
  letter-spacing: var(--h-tracking-wide);
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
}
.h-st-footer__links { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--h-s-3); }
.h-st-footer__links a { font-size: var(--h-fs-sm); line-height: var(--h-lh-snug); color: rgba(255, 255, 255, 0.8); text-decoration: none; }
.h-st-footer__links a:hover { color: var(--h-white); text-decoration: underline; }
.h-st-footer__links strong { display: block; color: var(--h-white); font-weight: var(--h-fw-semibold); }
.h-st-footer__hours { font-size: var(--h-fs-xs); color: rgba(255, 255, 255, 0.6); }
.h-st-footer__cta { color: var(--h-cyan); font-weight: var(--h-fw-semibold); }
.h-st-footer__contact {
  display: flex;
  flex-direction: column;
  gap: var(--h-s-2);
  margin-top: var(--h-s-4);
  padding-top: var(--h-s-4);
  border-top: 1px solid rgba(255, 255, 255, 0.15);
}
.h-st-footer__contact a { font-size: var(--h-fs-sm); color: rgba(255, 255, 255, 0.75); text-decoration: none; }
.h-st-footer__contact a:hover { color: var(--h-white); text-decoration: underline; }
.h-st-footer__bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--h-s-3);
  max-width: var(--h-container);
  margin: var(--h-s-6) auto 0;
  padding: var(--h-s-4) var(--h-s-8) 0;
  border-top: 1px solid rgba(255, 255, 255, 0.15);
  font-size: var(--h-fs-sm);
  color: rgba(255, 255, 255, 0.7);
}
.h-st-footer__bottom a { color: rgba(255, 255, 255, 0.8); text-decoration: none; }
.h-st-footer__bottom a:hover { color: var(--h-white); text-decoration: underline; }

/* ---------- Phone and tablet ------------------------------------------------ */
@media (max-width: 900px) {
  /* Below 900 the sidebar folds into the hamburger drawer, and these ten links
     become the whole navigation for a customer standing at a unit on a phone.
     The library's .h-sidebar__link is 38px — right for a desk shell, under the
     44px touch minimum here. Raised only inside this site's drawer and only
     inside this breakpoint: .h-sidebar__link is shared with Studio and others,
     so it is left alone globally and CBC's desktop sidebar is untouched.
     min-height keeps the label centred on .h-sidebar__link's own align-items
     rather than pushing it off-centre with extra top padding. */
  .h-st-page .h-sidebar__drawer .h-sidebar__link { min-height: 44px; }
  .h-st-footer__grid { grid-template-columns: 1fr 1fr; gap: var(--h-s-6); padding: 0 var(--h-s-5); }
  .h-st-footer__bottom { padding-left: var(--h-s-5); padding-right: var(--h-s-5); }
  .h-st-band { padding: var(--h-s-8) var(--h-s-5) var(--h-s-6); }
  .h-st-band--hero { padding: var(--h-s-10) var(--h-s-5) var(--h-s-8); }
  .h-st-brand { padding: var(--h-s-4) var(--h-s-5); }
  .h-st-brand__logo { width: 120px; }
}

@media (max-width: 640px) {
  .h-st-footer__grid { grid-template-columns: 1fr; }
  .h-st-footer__bottom { flex-direction: column; align-items: flex-start; }
  .h-st-band,
  .h-st-band--hero { text-align: left; }
  .h-st-band__inner,
  .h-st-band__sub { margin-left: 0; margin-right: 0; }
  .h-st-band .h-actions,
  .h-st-thanks .h-actions { justify-content: flex-start; }
  .h-st-band--hero .h-st-band__title { font-size: var(--h-fs-3xl); }
  .h-st-band__title { font-size: var(--h-fs-2xl); }
  .h-st-row,
  .h-st-rows__head,
  .h-st-stephead,
  .h-st-map__head { padding-left: var(--h-s-5); padding-right: var(--h-s-5); }
  .h-st-defs { grid-template-columns: 1fr; }
  .h-st-defs__term { padding-bottom: 0; border-bottom: 0; }
  .h-st-defs__desc { padding-top: var(--h-s-1); }
  .h-st-map__frame { height: 280px; }
  .h-st-thanks { padding: var(--h-s-8) var(--h-s-3); text-align: left; align-items: stretch; }
  .h-st-row__amount { font-size: var(--h-fs-lg); }
}

/* ==========================================================================
   Video landing pages (video.hdas.com.au) — added 15/09/2026
   --------------------------------------------------------------------------
   One URL per agent per topic, handed to one seller at a time by SMS or email.
   The whole surface is: a navy bar with the logo, a line of eyebrow, a heading,
   the video, the agent, the office. No navigation, because there is nowhere
   else to go — every other path on the host is a 404 on purpose.

   Direction: the video is the only large thing on the page, and everything
   round it stays quiet. Cyan appears exactly twice — the eyebrow and the short
   rule under the heading — which is well inside the 10% accent rule on a page
   this sparse.

   Reused rather than reinvented: .h-app-nav + __brand + __brand-img (the same
   60px navy bar Calls, Issues, ECR and PAR wear), .h-container--narrow,
   .h-eyebrow, .h-h1, .h-lead, .h-card + .h-card--static, .h-actions, .h-btn
   and its variants, .h-footer, and the new general .h-video frame above.
   Only the parts below are specific to this site.
   ========================================================================== */

/* A short page — the 404 — must not leave a band of paper under the navy
   footer. Column flex with the footer on margin-top:auto sits it on the bottom
   of the viewport when the content is short and straight after the content when
   it is not; the gap above it is .h-vid-main's own padding-bottom. */
.h-vid-page { display: flex; flex-direction: column; min-height: 100vh; }
.h-vid-page .h-vid-footer { margin-top: auto; }

/* The bar carries the wordmark alone. .h-app-nav__brand baseline-aligns the
   logo with a franchise suffix and nudges the image down 7px to do it; with no
   suffix there is nothing to align to, so both are undone here. It is also not
   a link — / is a 404 — so it must not offer a pointer. */
.h-vid-page .h-app-nav__brand      { align-items: center; cursor: default; }
.h-vid-page .h-app-nav__brand-img  { top: 0; }

/* 720px, narrower than --h-container-narrow: at 880 a 16:9 player is 495px tall
   and stops being something you take in at a glance on a laptop. */
.h-vid-main {
  max-width: 720px;
  padding-top: var(--h-s-8);
  padding-bottom: var(--h-s-6);
}

/* The one cyan rule, between the heading and the reading copy. */
.h-vid-rule {
  width: 48px;
  height: 3px;
  background: var(--h-cyan);
  border: 0;
  border-radius: var(--h-radius-sm);
  margin: 0 0 var(--h-s-5);
}

.h-vid-title { letter-spacing: var(--h-tracking-tight); margin-bottom: var(--h-s-4); }
.h-vid-intro { margin: 0 0 var(--h-s-4); }
.h-vid-video { margin-top: var(--h-s-6); }

/* The agent slab under the player: who is talking, and the one thing to do
   about it. Photo left, actions right, and on a phone the actions drop under
   and go full width — a thumb reaches the bottom of the screen, not the middle
   of a row. */
.h-vid-agent {
  margin-top: var(--h-s-6);
  padding: var(--h-s-5);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--h-s-5);
}
.h-vid-agent__id {
  display: flex;
  align-items: center;
  gap: var(--h-s-4);
  min-width: 0;
}
.h-vid-agent__photo {
  width: 72px;
  height: 72px;
  border-radius: var(--h-radius-pill);
  overflow: hidden;
  background: var(--h-blue-10);
  flex: none;
}
.h-vid-agent__photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.h-vid-agent__name {
  margin: 0;
  font-size: var(--h-fs-lg);
  font-weight: var(--h-fw-bold);
  color: var(--h-blue);
  letter-spacing: var(--h-tracking-tight);
}
.h-vid-agent__role { margin: 0; font-size: var(--h-fs-sm); color: var(--h-grey-70); }
.h-vid-agent .h-actions { margin-top: 0; margin-left: auto; }

/* The footer sits on the same 720px column as the content — .h-container's own
   --narrow is 880 and left the office details starting 80px to the left of the
   heading above them, which reads as two different pages stacked. */
.h-vid-footer__inner { max-width: 720px; }
.h-vid-footer__line {
  margin: 0;
  font-size: var(--h-fs-sm);
  line-height: var(--h-lh-base);
}
.h-vid-footer__line a { font-weight: var(--h-fw-semibold); }

/* The dead end. Deliberately the smallest page on the host: what happened, and
   the number to ring. No list of agents, no search, no "did you mean" — the
   URLs are given out one at a time and the 404 must not enumerate them. */
.h-vid-404 { max-width: 480px; padding-top: var(--h-s-12); padding-bottom: var(--h-s-12); }
.h-vid-404__line { margin: 0 0 var(--h-s-5); }

@media (max-width: 640px) {
  /* The library hides the wide horizontal logo on phones because .h-app-nav
     normally carries a cyan app name beside it and a user chip after it. This
     bar has neither — it is the wordmark alone — so hiding it leaves a seller
     looking at an empty navy strip on the device most of them open the link on.
     Put it back, smaller. */
  .h-vid-page .h-app-nav__brand-img { display: block; height: 20px; }
  .h-vid-main { padding-top: var(--h-s-6); }
  .h-vid-agent { gap: var(--h-s-4); }
  .h-vid-agent .h-actions { margin-left: 0; width: 100%; }
  .h-vid-agent .h-btn { flex: 1 1 auto; justify-content: center; }
  .h-vid-404 { padding-top: var(--h-s-8); }
}

/* ---------- Modal as a native <dialog> (15/09/2026) --------------------------
   .h-modal on a <dialog> opened with showModal(), added for Studio Videos'
   per-row Edit. The element brings its own top layer, its own ::backdrop and
   its own Escape handling, so the .h-modal-backdrop div is not used with this
   form. Purely additive: every div-based .h-modal consumer is untouched.

   The three resets are the UA dialog defaults .h-modal does not already state:
   the solid border, the auto margins that fight the centring transform, and
   the UA max-width/height caps that would override the width: min() above. */
dialog.h-modal {
  margin: 0;
  border: 0;
  max-width: none;
  color: inherit;
}
dialog.h-modal::backdrop { background: rgba(0, 18, 51, 0.55); }

/* A dialog is a form card without the card. .h-label is display:block on its
   own, which leaves the caption sitting BESIDE any field narrower than the row
   (a .h-input--narrow, a .h-switch) instead of above it — so stack it here the
   same way .h-form-card does. Scoped to dialog.h-modal on purpose: the older
   div-based .h-modal--card consumers lay their own content out. */
dialog.h-modal .h-label {
  display: flex;
  flex-direction: column;
  gap: var(--h-s-1);
  margin-bottom: var(--h-s-4);
}
dialog.h-modal .h-label > .h-switch-row { align-self: flex-start; }

@media (max-width: 480px) {
  /* Phone: a full-width sheet on the bottom edge rather than a small dialog
     floating mid-screen — the fields and the Save button land under the thumb,
     and a long intro textarea has the height to be typed into. */
  dialog.h-modal {
    top: auto;
    bottom: 0;
    left: 0;
    transform: none;
    width: 100%;
    max-height: 90vh;
    padding: var(--h-s-5);
    border-radius: var(--h-radius-lg) var(--h-radius-lg) 0 0;
  }
}
