/* =========================================================================
   Roofage — app.css
   StormView-derived dark design system (WP-A).
   No build step. No CDN. Everything the app renders must be styleable from
   here alone — the CSP is style-src 'self' with no 'unsafe-inline', so any
   inline <style> block or style="" attribute on any page is a bug in that
   page, not something this file can fix for it.
   ========================================================================= */

/* -------------------------------------------------------------------------
   Fonts — self-hosted, latin-subset woff2, fetched from the Google Fonts
   CSS API and re-served from /static/fonts/ so the browser never talks to
   fonts.gstatic.com (CSP has no font-src exception for it, and doesn't need
   one). If these files are ever missing, the family names below simply fail
   to match and every --font-* stack falls through to its system keyword —
   nothing else in this file references a family name directly.
   ------------------------------------------------------------------------- */
@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/barlow-400.woff2) format("woff2");
}
@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/static/fonts/barlow-600.woff2) format("woff2");
}
@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/static/fonts/barlow-700.woff2) format("woff2");
}
@font-face {
  font-family: "Barlow Condensed";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/static/fonts/barlow-cond-600.woff2) format("woff2");
}
@font-face {
  font-family: "Barlow Condensed";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/static/fonts/barlow-cond-700.woff2) format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/plex-mono-400.woff2) format("woff2");
}

/* -------------------------------------------------------------------------
   Tokens — verbatim from StormView tokens/colors.css, dark mapping.
   Ratios in comments are against --surface-page unless noted; see WP-A's
   final report for independent verification of these numbers.
   ------------------------------------------------------------------------- */
:root {
  /* raw ramp — verbatim from StormView tokens/colors.css */
  --red-50:#FFF3F3; --red-100:#FFE2E2; --red-200:#FFBDBD; --red-500:#FF0707;
  --red-600:#E30B0B; --red-700:#C71F1F; --red-800:#9E1414;
  --ink-950:#0F1216; --ink-900:#14171C; --ink-800:#1D2128; --ink-700:#2A2F38;
  --ink-600:#3C424E; --ink-500:#565E6C; --ink-400:#78808F; --ink-300:#A3AAB6;
  --ink-200:#CDD2DA; --ink-100:#E6E9EE; --ink-50:#F3F5F8; --white:#FFFFFF;

  /* dark aliases — what components actually reference */
  --surface-page:    var(--ink-950);   /* #0F1216 */
  --surface-card:    var(--ink-900);   /* #14171C */
  --surface-raised:  var(--ink-800);   /* #1D2128  menus, chips, dropdowns */
  --surface-sunken:  #0A0C0F;          /* code blocks, table zebra */
  --border-subtle:   var(--ink-800);
  --border-default:  var(--ink-700);
  --border-strong:   var(--ink-600);
  --text-heading:    var(--ink-50);    /* 16.8:1 */
  --text-body:       var(--ink-100);   /* 14.9:1 */
  --text-muted:      var(--ink-300);   /*  8.2:1 */
  --text-faint:      var(--ink-400);   /*  5.1:1 — smallest allowed for text */
  --brand:           var(--red-500);   /* wordmark, focus ring, active nav marker */
  /* Solid fills that carry white text use red-600, NOT the brand red-500.
     White on #FF0707 is 3.97:1 -- it fails WCAG AA (4.5:1) for normal-size
     text, and every primary button in this app is normal-size text. red-600
     is 4.86:1 and red-700 is 5.76:1, both AA, and both visually read as the
     same Storm Red at button scale. Hover DARKENS rather than brightens for
     the same reason: the obvious dark-UI move (a lighter red, the previous
     #FF3D3D) drops to 3.51:1, i.e. worse than resting. Keep --brand itself
     as authored -- it is correct for the wordmark and for thin accents that
     carry no text on top. */
  --brand-fill:      var(--red-600);   /* 4.86:1 with white */
  --brand-fill-hover:var(--red-700);   /* 5.76:1 with white */
  --text-on-brand:   var(--white);
  --brand-text:      #FF6B6B;          /* red TEXT on dark — red-500 is only 4.1:1 */

  /* semantic — lightened from StormView's light-mode hues to clear 4.5:1 on ink-950 */
  --success:#35C77D; --success-soft:#0F2A1D;
  --warning:#E9A23B; --warning-soft:#2C1F0C;
  --danger: #FF5A4E; --danger-soft: #2E1210;
  --info:   #4FA3E8; --info-soft:   #0D2033;

  --focus-ring: 0 0 0 3px rgba(255,7,7,.35);
  --shadow-card:    0 1px 2px rgba(0,0,0,.40), 0 1px 3px rgba(0,0,0,.30);
  --shadow-overlay: 0 12px 32px rgba(0,0,0,.55), 0 4px 8px rgba(0,0,0,.35);
  --ease-out: cubic-bezier(.2,.8,.3,1); --dur-fast:120ms; --dur-med:200ms;

  --font-display:"Barlow Condensed","Arial Narrow",sans-serif;
  --font-body:"Barlow","Helvetica Neue",Arial,sans-serif;
  --font-mono:"IBM Plex Mono",ui-monospace,monospace;
  --text-xs:12px; --text-sm:13px; --text-base:15px; --text-md:17px; --text-lg:20px;
  --text-xl:24px; --text-2xl:32px; --text-3xl:44px; --text-4xl:64px;
  --leading-tight:1.05; --leading-snug:1.25; --leading-normal:1.5;
  --tracking-caps:.08em;
  --weight-regular:400; --weight-medium:500; --weight-semibold:600; --weight-bold:700;

  --space-1:4px; --space-2:8px; --space-3:12px; --space-4:16px; --space-5:20px;
  --space-6:24px; --space-8:32px; --space-10:40px; --space-12:48px; --space-16:64px;
  --radius-sm:4px; --radius-md:8px; --radius-lg:12px; --radius-pill:999px;
  --control-h-sm:32px; --control-h-md:40px; --control-h-lg:48px;
  --container-max:1200px;
}

/* -------------------------------------------------------------------------
   Reset + base
   ------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--surface-page);
  color: var(--text-body);
  font: var(--weight-regular) var(--text-base)/var(--leading-normal) var(--font-body);
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
}
h1 {
  font-family: var(--font-display);
  color: var(--text-heading);
  font-weight: var(--weight-semibold);
  margin: 0 0 var(--space-1);
  line-height: var(--leading-tight);
  font-size: var(--text-2xl); letter-spacing: .2px;
}
h2 {
  font-size: var(--text-sm); color: var(--text-muted); font-weight: var(--weight-semibold);
  margin: var(--space-8) 0 var(--space-3); text-transform: uppercase; letter-spacing: var(--tracking-caps);
  font-family: var(--font-body); line-height: var(--leading-tight);
}
/* sub-section labels nested inside a card body (e.g. admin.js's per-block
   headings) — same caption treatment as h2 but tighter margins since
   there's already card padding around them */
h3 {
  font-size: var(--text-xs); color: var(--text-muted); font-weight: var(--weight-semibold);
  margin: var(--space-5) 0 var(--space-2); text-transform: uppercase; letter-spacing: var(--tracking-caps);
  font-family: var(--font-body); line-height: var(--leading-tight);
}
p { margin: 0 0 var(--space-3); }
a { color: var(--brand-text); text-decoration: none; }
a:hover { text-decoration: underline; }
hr { border: 0; border-top: 1px solid var(--border-subtle); margin: var(--space-2) 0; }
footer { margin-top: var(--space-10); color: var(--text-muted); font-size: var(--text-xs); }

/* -------------------------------------------------------------------------
   Accessibility globals — focus, selection, motion
   ------------------------------------------------------------------------- */
:focus { outline: none; }
:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-sm);
}
a:focus-visible, button:focus-visible, .btn:focus-visible {
  box-shadow: var(--focus-ring);
}
::selection { background: var(--brand-fill); color: var(--text-on-brand); }

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

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

/* -------------------------------------------------------------------------
   Layout
   ------------------------------------------------------------------------- */
.wrap {
  max-width: var(--container-max);
  margin: 0 auto;
  padding: var(--space-8) var(--space-8) var(--space-16);
}
.narrow {
  max-width: 420px;
  margin: var(--space-12) auto;
  padding: 0 var(--space-4);
}
.stack { display: flex; flex-direction: column; gap: var(--space-4); }
.row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.row--end { align-items: flex-end; }
.row > .field { flex: 1 1 220px; }

/* -------------------------------------------------------------------------
   Header + profile menu
   ------------------------------------------------------------------------- */
.app-header, header.nav {
  display: flex; align-items: center; gap: var(--space-5);
  padding: var(--space-3) var(--space-8);
  background: var(--surface-card);
  border-bottom: 1px solid var(--border-subtle);
  flex-wrap: wrap;
}
.app-header__brand, header.nav .brand {
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  font-size: var(--text-lg);
  letter-spacing: .04em;
  color: var(--text-heading);
  text-decoration: none;
  white-space: nowrap;
}
.app-header__brand:hover, header.nav .brand:hover { text-decoration: none; color: var(--text-heading); }

.app-header__nav { display: flex; align-items: center; gap: var(--space-5); flex-wrap: wrap; }
.app-header__nav a, header.nav a {
  color: var(--text-muted);
  text-decoration: none;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  padding: var(--space-1) 0;
  position: relative;
}
.app-header__nav a:hover, header.nav a:hover { color: var(--text-body); text-decoration: none; }
.app-header__nav a.on, header.nav a.on {
  color: var(--text-heading);
}
.app-header__nav a.on::after, header.nav a.on::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -6px;
  height: 2px; background: var(--brand); border-radius: var(--radius-pill);
}

.app-header__spacer, header.nav .spacer { flex: 1; }

.chip {
  display: inline-flex; align-items: center; gap: var(--space-1);
  background: var(--surface-raised); border: 1px solid var(--border-default);
  border-radius: var(--radius-pill); padding: var(--space-1) var(--space-3);
  font-size: var(--text-xs); color: var(--text-muted); white-space: nowrap;
}
.chip--credits { color: var(--text-body); font-variant-numeric: tabular-nums; }

.avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: var(--radius-pill);
  background: var(--surface-raised); border: 1px solid var(--border-default);
  color: var(--text-heading); font-size: var(--text-xs); font-weight: var(--weight-semibold);
  letter-spacing: 0; flex-shrink: 0;
}

.profile { position: relative; }
.profile__button {
  display: flex; align-items: center; gap: var(--space-2);
  background: transparent; border: 1px solid transparent; border-radius: var(--radius-pill);
  padding: var(--space-1) var(--space-2); cursor: pointer;
  height: auto; font: inherit; color: var(--text-body);
}
.profile__button:hover { background: var(--surface-raised); }
.profile__caret { color: var(--text-muted); font-size: var(--text-xs); }

.profile__menu {
  position: absolute; top: calc(100% + var(--space-2)); right: 0; z-index: 30;
  min-width: 220px;
  background: var(--surface-raised); border: 1px solid var(--border-default);
  border-radius: var(--radius-md); box-shadow: var(--shadow-overlay);
  padding: var(--space-2);
  display: flex; flex-direction: column;
}
.profile__menu[hidden] { display: none; }
.profile__menu.open { display: flex; }
.profile__menu a {
  display: block; color: var(--text-body); text-decoration: none;
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm);
  font-size: var(--text-sm);
}
.profile__menu a:hover, .profile__menu a:focus-visible { background: var(--surface-card); text-decoration: none; }
/* `border:0` + a single top border, otherwise the default 3D groove renders as
   an invisible gap on a dark surface -- the separators read as stray whitespace. */
.profile__menu hr {
  margin: var(--space-2) var(--space-1);
  border: 0; border-top: 1px solid var(--border-default);
}
.profile__id {
  padding: var(--space-2) var(--space-3) var(--space-3);
  display: flex; flex-direction: column; gap: var(--space-1);
  align-items: flex-start;   /* else the Owner badge stretches the menu's full width */
}
.profile__id strong { color: var(--text-heading); font-size: var(--text-sm); font-weight: var(--weight-semibold); }
.profile__id .mono { color: var(--text-muted); }

/* -------------------------------------------------------------------------
   Page head
   ------------------------------------------------------------------------- */
.page-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--space-4); flex-wrap: wrap;
  margin-bottom: var(--space-6);
}
.page-head h1 { margin: 0 0 var(--space-1); }
.page-head .desc { color: var(--text-muted); margin: 0; max-width: 60ch; }
.page-head__actions { display: flex; gap: var(--space-3); flex-wrap: wrap; align-items: center; }

/* generic "sub" / "desc" text used stand-alone (legacy + descriptions in
   permit rows) — kept distinct from .page-head .desc above */
.sub { color: var(--text-muted); margin: 0 0 var(--space-6); font-size: var(--text-sm); }
.desc { color: var(--text-muted); max-width: 320px; }
.muted { color: var(--text-muted); font-size: var(--text-sm); }

/* -------------------------------------------------------------------------
   Surfaces
   ------------------------------------------------------------------------- */
.card, .card-plain {
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  margin-top: var(--space-3);
  box-shadow: var(--shadow-card);
}
.card--flush { padding: 0; overflow: hidden; }
.card__head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3); padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--border-subtle);
}
.card__title { font-size: var(--text-md); font-weight: var(--weight-semibold); color: var(--text-heading); }
.card__body { padding: var(--space-5); }

.empty {
  text-align: center; color: var(--text-muted);
  padding: var(--space-10) var(--space-4);
  font-size: var(--text-sm);
}

.note {
  max-width: 560px;
}
.note p { margin: 0 0 var(--space-2); }
.note p:last-child { margin: 0; }

/* -------------------------------------------------------------------------
   Controls — buttons, inputs, forms
   ------------------------------------------------------------------------- */
button, .btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--space-2);
  height: var(--control-h-md);
  padding: 0 var(--space-5);
  font: inherit; font-size: var(--text-base); font-weight: var(--weight-semibold);
  color: var(--text-on-brand);
  background: var(--brand-fill);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
button:hover, .btn:hover { background: var(--brand-fill-hover); }
button:disabled, .btn:disabled { opacity: .5; cursor: wait; }

.btn--ghost, button.ghost {
  background: transparent; color: var(--text-body);
  border: 1px solid var(--border-default);
}
.btn--ghost:hover, button.ghost:hover { background: var(--surface-raised); border-color: var(--border-strong); }

.btn--danger {
  background: var(--danger-soft); color: var(--danger);
  border: 1px solid var(--danger-soft);
}
.btn--danger:hover { background: var(--danger-soft); border-color: var(--danger); }

.btn--sm { height: var(--control-h-sm); padding: 0 var(--space-3); font-size: var(--text-sm); }

form { display: flex; gap: var(--space-3); flex-wrap: wrap; }

label {
  display: block; font-size: var(--text-sm); color: var(--text-muted);
  margin: var(--space-4) 0 var(--space-1);
}
.field { display: flex; flex-direction: column; }
.field label { margin-top: 0; }

input[type=checkbox], input[type=radio] { accent-color: var(--brand-fill); }
/* a bare checkbox+text label (e.g. admin.html's "Make owner") rather than
   a caption-above-control label — progressive enhancement, degrades to the
   plain block label above in browsers without :has() */
label:has(> input[type=checkbox]) {
  display: inline-flex; align-items: center; gap: var(--space-2);
  margin: var(--space-2) 0; color: var(--text-body); font-size: var(--text-sm);
  cursor: pointer;
}

input[type=text], input[type=email], input[type=password], input[type=number],
input[type=file], select, textarea {
  width: 100%;
  padding: 0 var(--space-4);
  height: var(--control-h-md);
  font: inherit; font-size: var(--text-base);
  color: var(--text-body);
  background: var(--surface-raised);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  outline: none;
}
textarea { height: auto; padding: var(--space-3) var(--space-4); min-height: 140px; resize: vertical; font-family: inherit; }
input[type=file] { padding: var(--space-2) var(--space-4); }
select { padding: 0 var(--space-3); }

/* `width:100%` above is right for a stacked form (login, invite, change
   password) where every control owns its own line. Inside a horizontal
   `.row` it is wrong -- it makes a county dropdown span the full content
   width next to a 100px button. Controls placed directly in a row size to
   their content instead, and still wrap to full width on narrow screens. */
.row > select, .row > input, .row > button, .row > .btn { width: auto; }
/* Fixed basis, not auto: a <select> sizes to its WIDEST option, and the
   jurisdiction picker holds 64 county names, so `width:auto` let it eat
   ~630px and squeeze the address field -- the primary input -- down to
   394px. Pin it and let .addr-wrap's flex-grow take the remaining space. */
.row > select { flex: 0 0 auto; width: 240px; max-width: 100%; min-width: 0; }

input:focus-visible, select:focus-visible, textarea:focus-visible {
  box-shadow: var(--focus-ring);
  border-color: var(--brand);
}

.form-error { color: var(--danger); font-size: var(--text-sm); margin: var(--space-2) 0 0; }

/* -------------------------------------------------------------------------
   Feedback — badges, status, errors, spinner
   ------------------------------------------------------------------------- */
.badge {
  display: inline-flex; align-items: center; gap: var(--space-1);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs); font-weight: var(--weight-semibold);
  background: var(--surface-raised); border: 1px solid var(--border-default);
  color: var(--text-muted);
  white-space: nowrap;
}
.badge--ok, .badge.permit-src { background: var(--success-soft); border-color: var(--success-soft); color: var(--success); }
.badge--warn, .badge.yb-src   { background: var(--warning-soft); border-color: var(--warning-soft); color: var(--warning); }
.badge--bad                    { background: var(--danger-soft);  border-color: var(--danger-soft);  color: var(--danger); }
.badge--info                   { background: var(--info-soft);    border-color: var(--info-soft);    color: var(--info); }
.badge--neutral                { background: var(--surface-raised); border-color: var(--border-default); color: var(--text-muted); }
.badge.solar { background: var(--warning-soft); border-color: var(--warning-soft); color: var(--warning); }

.status, .status-line { margin: var(--space-4) 2px; color: var(--text-muted); min-height: 22px; font-size: var(--text-sm); }
.error { color: var(--danger); }

.spinner {
  display: inline-block; width: 16px; height: 16px;
  border: 2px solid var(--border-default); border-top-color: var(--brand);
  border-radius: 50%; animation: spin var(--dur-med) linear infinite;
  animation-duration: 800ms;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .spinner { animation: none; border-top-color: var(--border-default); border-right-color: var(--brand); }
}

/* -------------------------------------------------------------------------
   Data — tables, mono, numerals
   ------------------------------------------------------------------------- */
.tablebox { overflow-x: auto; margin-top: var(--space-3); }
table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
th {
  text-align: left; color: var(--text-muted); font-weight: var(--weight-semibold);
  font-size: var(--text-xs); text-transform: uppercase; letter-spacing: var(--tracking-caps);
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--border-default);
  white-space: nowrap;
}
td {
  padding: var(--space-3); border-bottom: 1px solid var(--border-subtle);
  vertical-align: top; color: var(--text-body);
}
tr:last-child td { border-bottom: 0; }
tr:hover td { background: var(--surface-raised); }
td a { color: var(--brand-text); }

.mono { font-family: var(--font-mono); font-size: var(--text-xs); overflow-wrap: anywhere; }
td.mono, th.mono, .profile__id .mono, .chip .mono { white-space: nowrap; }
/* a <pre class="mono"> (e.g. the curl example on keys.html) needs to keep
   its authored line breaks and wrap long lines instead of overflowing */
pre.mono {
  white-space: pre-wrap;
  background: var(--surface-sunken);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  margin: 0;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}
.num { text-align: right; font-variant-numeric: tabular-nums; }
/* `min-width: 0`, NOT `max-width: 1px` -- these sit inside flex rows, where a
   flex item's default `min-width:auto` refuses to shrink below its content and
   defeats the ellipsis. min-width:0 is the fix for that; max-width:1px just
   collapses the element (it made every email in the admin user list invisible). */
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }

code.key {
  display: block; font-family: var(--font-mono);
  background: var(--surface-sunken); border: 1px solid var(--border-default);
  border-radius: var(--radius-sm); padding: var(--space-3);
  font-size: var(--text-sm); word-break: break-all; margin: var(--space-3) 0;
  color: var(--text-body);
}

.kind { font-weight: var(--weight-semibold); white-space: nowrap; }
.kind.solar { color: var(--warning); }
.kind.roof { color: var(--brand-text); }

/* -------------------------------------------------------------------------
   Result headline
   ------------------------------------------------------------------------- */
.result-headline, .headline {
  display: flex; gap: var(--space-8); flex-wrap: wrap; align-items: center;
}
.age-num {
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  font-weight: var(--weight-bold);
  line-height: var(--leading-tight);
}
.age-good { color: var(--success); }
.age-warn { color: var(--warning); }
.age-bad  { color: var(--danger); }
.age-label { color: var(--text-muted); font-size: var(--text-xs); margin-top: var(--space-1); text-transform: uppercase; letter-spacing: var(--tracking-caps); }

.facts { display: flex; gap: var(--space-6); flex-wrap: wrap; }
.fact .v { font-size: var(--text-md); font-weight: var(--weight-semibold); color: var(--text-heading); }
.fact .k { color: var(--text-muted); font-size: var(--text-xs); text-transform: uppercase; letter-spacing: var(--tracking-caps); }

/* -------------------------------------------------------------------------
   Autocomplete
   ------------------------------------------------------------------------- */
/* `flex: 1 1 380px` here would be a bug: .addr-wrap's parent on the search
   page is `form.stack`, i.e. flex-direction:column, where flex-basis sizes the
   VERTICAL axis -- so a row-oriented basis turned the address field into a
   380px-tall box with the suggestions dropdown floating far below it. Default
   to full width, and only opt into flexing when it actually sits in a `.row`. */
.addr-wrap { position: relative; width: 100%; }
.row > .addr-wrap { flex: 1 1 380px; width: auto; }
.suggestions {
  position: absolute; top: calc(100% + var(--space-1)); left: 0; right: 0; z-index: 20;
  background: var(--surface-raised); border: 1px solid var(--border-default);
  border-radius: var(--radius-md); overflow: hidden; box-shadow: var(--shadow-overlay);
  display: none;
}
.suggestions.open { display: block; }
.suggestions div {
  padding: var(--space-3) var(--space-4); cursor: pointer; font-size: var(--text-base);
  border-bottom: 1px solid var(--border-subtle); color: var(--text-body);
}
.suggestions div:last-child { border-bottom: 0; }
.suggestions div:hover, .suggestions div.sel { background: var(--brand-fill); color: var(--text-on-brand); }

/* -------------------------------------------------------------------------
   Login extras (moved out of login.html's inline <style>, CSP-blocked there)
   ------------------------------------------------------------------------- */
.divider {
  display: flex; align-items: center; gap: var(--space-3);
  margin: var(--space-4) 0 var(--space-1);
  color: var(--text-muted); font-size: var(--text-xs); text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
}
.divider::before, .divider::after { content: ""; flex: 1; height: 1px; background: var(--border-default); }
.btn-google {
  display: flex; align-items: center; justify-content: center; gap: var(--space-3);
  margin-top: var(--space-3); height: var(--control-h-md); padding: 0 var(--space-4);
  border: 1px solid var(--border-default); border-radius: var(--radius-md);
  background: var(--surface-raised); color: var(--text-body);
  font-size: var(--text-base); font-weight: var(--weight-semibold); text-decoration: none;
}
.btn-google:hover { border-color: var(--border-strong); text-decoration: none; }

/* -------------------------------------------------------------------------
   Admin
   ------------------------------------------------------------------------- */
.admin-grid { display: grid; grid-template-columns: 1fr; gap: var(--space-6); }
.user-row { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }

.toggle { position: relative; display: inline-flex; align-items: center; width: 40px; height: 22px; }
.toggle input {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; margin: 0; cursor: pointer;
}
.toggle span {
  position: absolute; inset: 0; background: var(--surface-raised);
  border: 1px solid var(--border-default); border-radius: var(--radius-pill);
  transition: background var(--dur-fast) var(--ease-out);
}
.toggle span::before {
  content: ""; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px;
  border-radius: 50%; background: var(--text-muted);
  transition: transform var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}
.toggle input:checked + span { background: var(--success-soft); border-color: var(--success); }
.toggle input:checked + span::before { transform: translateX(18px); background: var(--success); }
.toggle input:focus-visible + span { box-shadow: var(--focus-ring); }
.toggle input:disabled + span { opacity: .5; cursor: not-allowed; }

/* -------------------------------------------------------------------------
   Small utilities — for JS-rendered fragments that would otherwise need
   inline style="" (blocked by the CSP). Owning pages should reach for
   these instead of setting .style.* directly.
   ------------------------------------------------------------------------- */
.hidden { display: none !important; }

/* MUST come with `!important`, and must live after every layout rule. The
   browser's built-in `[hidden]{display:none}` lives in the UA stylesheet, which
   loses to ANY author declaration -- so `.row{display:flex}` on a `<div class="row"
   hidden>` silently un-hides it. Every progressive-disclosure panel in the app
   (the invite form, the per-user grant-credits panels, the one-time secret
   reveal) uses the native `hidden` attribute, and without this they all render
   expanded at once. */
[hidden] { display: none !important; }
.mt-2 { margin-top: var(--space-2); }
.mt-3 { margin-top: var(--space-3); }
.mt-4 { margin-top: var(--space-4); }
.mt-5 { margin-top: var(--space-5); }
.mt-6 { margin-top: var(--space-6); }

/* =========================================================================
   Responsive — mobile-first. Breakpoints at 560 / 720 / 960.
   ========================================================================= */
@media (min-width: 560px) {
  /* enough width that the .narrow login card no longer needs edge padding
     to keep it off the viewport edge */
  .narrow { padding: 0; }
}

@media (min-width: 720px) {
  .wrap { padding-left: var(--space-8); padding-right: var(--space-8); }
  .age-num { font-size: var(--text-4xl); }
  .facts { flex-wrap: nowrap; }
}

@media (min-width: 960px) {
  .admin-grid { grid-template-columns: 1fr 1fr; }
}

/* below 720px: tighter shell, collapsed/wrapped header nav, single-column
   facts/admin grid — written mobile-first above, this block only pulls
   back space that assumes a wide viewport */
@media (max-width: 719.98px) {
  .wrap { padding: var(--space-4) var(--space-4) var(--space-10); }
  .narrow { margin: var(--space-8) auto; }
  .app-header, header.nav { padding: var(--space-3) var(--space-4); gap: var(--space-3); }
  .app-header__nav, header.nav { row-gap: var(--space-2); }
  .facts { gap: var(--space-4); }
  .admin-grid { grid-template-columns: 1fr; }
  .page-head { flex-direction: column; align-items: stretch; }
}
