/* =========================================================================
   Royal Park — design system
   Palette: deep park green, brass, warm sand. One accent, used sparingly.
   Type:    Fraunces (display serif) + Inter (text), with system fallbacks.
   ====================================================================== */

:root {
  /* Brand */
  --green-900: #0c231c;
  --green-800: #10382c;
  --green-700: #17493a;
  --green-600: #1f6a52;
  --green-300: #7fbfa6;
  --green-100: #dcece4;

  --brass-700: #7d5c1a; /* text-safe on sand: 5.8:1 */
  --brass-600: #84621d;
  --brass-500: #c9a24a;
  --brass-300: #e5cd90;

  --sand-50: #fbf9f5;
  --sand-100: #f4efe6;
  --sand-200: #e8e0d2;
  --sand-300: #d6cab5;

  --ink-900: #161a18;
  --ink-700: #33403a;
  --ink-500: #5d6b64;
  --ink-300: #8b9791;

  /* Semantic (light) */
  --bg: var(--sand-50);
  --bg-raised: #ffffff;
  --bg-sunken: var(--sand-100);
  --bg-inverse: var(--green-900);
  --text: var(--ink-900);
  --text-soft: var(--ink-500);
  --text-inverse: #f3f7f4;
  --text-inverse-soft: #a9c4b8;
  --line: var(--sand-200);
  --line-strong: var(--sand-300);
  --accent: var(--brass-600);
  --accent-soft: var(--brass-300);
  --brand: var(--green-700);
  --brand-soft: var(--green-100);
  --on-brand: #ffffff; /* text that sits on --brand */

  --ok-bg: #e6f4ec;
  --ok-fg: #1c6b42;
  --warn-bg: #fdf1dc;
  --warn-fg: #8a5b12;
  --err-bg: #fbe9e7;
  --err-fg: #9c2f22;
  --info-bg: #e7eef6;
  --info-fg: #2b5279;

  /* Type scale — fluid, no media queries needed */
  --font-display: 'Fraunces', 'Iowan Old Style', 'Palatino Linotype', Palatino,
    'Times New Roman', serif;
  --font-text: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
    'Helvetica Neue', Arial, sans-serif;

  --step--1: clamp(0.82rem, 0.79rem + 0.13vw, 0.9rem);
  --step-0: clamp(1rem, 0.96rem + 0.18vw, 1.09rem);
  --step-1: clamp(1.2rem, 1.12rem + 0.36vw, 1.45rem);
  --step-2: clamp(1.45rem, 1.3rem + 0.7vw, 1.95rem);
  --step-3: clamp(1.8rem, 1.5rem + 1.3vw, 2.7rem);
  --step-4: clamp(2.2rem, 1.7rem + 2.3vw, 3.9rem);
  --step-5: clamp(2.6rem, 1.8rem + 3.6vw, 5.2rem);

  /* Space & shape */
  --gutter: clamp(1.1rem, 4vw, 2.5rem);
  --measure: 68ch;
  --wrap: 1220px;
  --wrap-narrow: 780px;
  --radius: 14px;
  --radius-lg: 22px;
  --radius-pill: 999px;

  --shadow-sm: 0 1px 2px rgba(12, 35, 28, 0.06), 0 2px 8px rgba(12, 35, 28, 0.05);
  --shadow-md: 0 2px 6px rgba(12, 35, 28, 0.07), 0 14px 34px rgba(12, 35, 28, 0.09);
  --shadow-lg: 0 4px 12px rgba(12, 35, 28, 0.08), 0 28px 60px rgba(12, 35, 28, 0.14);

  --ease: cubic-bezier(0.22, 0.68, 0, 1);
}

/* Dark: system preference, overridable by the toggle. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --bg: #0a1712;
    --bg-raised: #10241d;
    --bg-sunken: #081310;
    --bg-inverse: #061009;
    --text: #eaf2ed;
    --text-soft: #9db3a8;
    --text-inverse: #eaf2ed;
    --text-inverse-soft: #8fae9f;
    --line: #1d3a2f;
    --line-strong: #2a4f40;
    --accent: var(--brass-500);
    --accent-soft: var(--brass-600);
    --brand: var(--green-300);
    --brand-soft: #143528;
    --on-brand: #06120c;

    --ok-bg: #12301f;
    --ok-fg: #7fd6a3;
    --warn-bg: #33260e;
    --warn-fg: #e8c274;
    --err-bg: #37160f;
    --err-fg: #f0a394;
    --info-bg: #10263a;
    --info-fg: #9cc6ef;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-md: 0 2px 8px rgba(0, 0, 0, 0.4), 0 16px 40px rgba(0, 0, 0, 0.45);
    --shadow-lg: 0 6px 18px rgba(0, 0, 0, 0.45), 0 30px 70px rgba(0, 0, 0, 0.55);
  }
}
:root[data-theme='dark'] {
  --bg: #0a1712;
  --bg-raised: #10241d;
  --bg-sunken: #081310;
  --bg-inverse: #061009;
  --text: #eaf2ed;
  --text-soft: #9db3a8;
  --text-inverse: #eaf2ed;
  --text-inverse-soft: #8fae9f;
  --line: #1d3a2f;
  --line-strong: #2a4f40;
  --accent: var(--brass-500);
  --accent-soft: var(--brass-600);
  --brand: var(--green-300);
  --brand-soft: #143528;
  --on-brand: #06120c;
  --ok-bg: #12301f;
  --ok-fg: #7fd6a3;
  --warn-bg: #33260e;
  --warn-fg: #e8c274;
  --err-bg: #37160f;
  --err-fg: #f0a394;
  --info-bg: #10263a;
  --info-fg: #9cc6ef;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-md: 0 2px 8px rgba(0, 0, 0, 0.4), 0 16px 40px rgba(0, 0, 0, 0.45);
  --shadow-lg: 0 6px 18px rgba(0, 0, 0, 0.45), 0 30px 70px rgba(0, 0, 0, 0.55);
}

/* ------------------------------------------------------------------ reset */

*,
*::before,
*::after {
  box-sizing: border-box;
}
* {
  margin: 0;
}
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 6rem;
  color-scheme: light dark;
}
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-text);
  font-size: var(--step-0);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  min-height: 100dvh;
  overflow-x: hidden;
}
img,
svg,
video {
  display: block;
  max-width: 100%;
  height: auto;
}
h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.018em;
  text-wrap: balance;
  font-variation-settings: 'SOFT' 0, 'WONK' 0;
}
h1 {
  font-size: var(--step-4);
}
h2 {
  font-size: var(--step-3);
}
h3 {
  font-size: var(--step-2);
}
h4 {
  font-size: var(--step-1);
}
p,
li {
  text-wrap: pretty;
}
a {
  color: inherit;
  text-decoration-color: color-mix(in oklab, var(--accent) 55%, transparent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  transition: color 0.18s var(--ease);
}
a:hover {
  color: var(--accent);
}
:focus-visible {
  outline: 2.5px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}
button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}
::selection {
  background: var(--accent-soft);
  color: var(--ink-900);
}
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
}

.skip-link {
  position: absolute;
  left: 50%;
  top: 0;
  translate: -50% -150%;
  z-index: 200;
  background: var(--bg-raised);
  color: var(--text);
  padding: 0.7rem 1.2rem;
  border-radius: 0 0 var(--radius) var(--radius);
  box-shadow: var(--shadow-md);
  transition: translate 0.2s var(--ease);
}
.skip-link:focus {
  translate: -50% 0;
}
.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ----------------------------------------------------------------- layout */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.wrap-narrow {
  max-width: var(--wrap-narrow);
}
.section {
  padding-block: clamp(3rem, 8vw, 7rem);
}
.section-tight {
  padding-block: clamp(2rem, 5vw, 4rem);
}
.section-sunken {
  background: var(--bg-sunken);
  border-block: 1px solid var(--line);
}
.section-inverse {
  background: var(--bg-inverse);
  color: var(--text-inverse);
}
.section-inverse h2,
.section-inverse h3 {
  color: var(--text-inverse);
}
.stack > * + * {
  margin-top: var(--stack-gap, 1rem);
}
.grid {
  display: grid;
  gap: clamp(1.1rem, 2.6vw, 2rem);
}
.cols-2 {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
}
.cols-3 {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
}
.cols-4 {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
}
.split {
  display: grid;
  gap: clamp(1.5rem, 5vw, 4rem);
  align-items: center;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
}
.prose {
  max-width: var(--measure);
}
.prose > * + * {
  margin-top: 1.1em;
}
.prose h3,
.prose h4 {
  margin-top: 2em;
}
.prose ul,
.prose ol {
  padding-left: 1.3em;
}
.prose li + li {
  margin-top: 0.4em;
}
.prose blockquote {
  border-left: 3px solid var(--accent);
  padding-left: 1.2rem;
  font-family: var(--font-display);
  font-size: var(--step-1);
  color: var(--text-soft);
}
.prose code {
  background: var(--bg-sunken);
  padding: 0.1em 0.4em;
  border-radius: 5px;
  font-size: 0.9em;
}
.prose img {
  border-radius: var(--radius);
  margin-block: 1.6em;
}

/* --------------------------------------------------------------- eyebrows */

.eyebrow {
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  display: flex;
  align-items: center;
  gap: 0.7rem;
}
.eyebrow::before {
  content: '';
  width: clamp(1.2rem, 3vw, 2.4rem);
  height: 1px;
  background: currentColor;
  opacity: 0.6;
  flex: none;
}
.section-inverse .eyebrow {
  color: var(--brass-300);
}
.lede {
  font-size: var(--step-1);
  color: var(--text-soft);
  max-width: 46ch;
  line-height: 1.5;
}
.section-inverse .lede {
  color: var(--text-inverse-soft);
}

/* --------------------------------------------------------------- controls */

.btn {
  --btn-bg: var(--brand);
  --btn-fg: var(--on-brand);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  padding: 0.8em 1.5em;
  min-height: 44px;
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.02em;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease),
    background 0.2s var(--ease), color 0.2s var(--ease);
  box-shadow: var(--shadow-sm);
}
.btn:hover {
  color: var(--btn-fg);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}
.btn:active {
  transform: translateY(0);
}
.btn-accent {
  --btn-bg: var(--brass-500);
  --btn-fg: #1a1405;
}
.btn-ghost {
  --btn-bg: transparent;
  --btn-fg: var(--text);
  border-color: var(--line-strong);
  box-shadow: none;
}
.btn-ghost:hover {
  border-color: var(--accent);
  --btn-fg: var(--accent);
}
.section-inverse .btn-ghost {
  --btn-fg: var(--text-inverse);
  border-color: rgba(255, 255, 255, 0.28);
}
.btn-sm {
  padding: 0.5em 1em;
  min-height: 36px;
  font-size: 0.8rem;
}
.btn-danger {
  --btn-bg: transparent;
  --btn-fg: var(--err-fg);
  border-color: color-mix(in oklab, var(--err-fg) 40%, transparent);
  box-shadow: none;
}
.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem;
  align-items: center;
}

.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-weight: 600;
  font-size: var(--step--1);
  letter-spacing: 0.02em;
  text-decoration: none;
  color: var(--brand);
}
.link-arrow::after {
  content: '→';
  transition: translate 0.2s var(--ease);
}
.link-arrow:hover::after {
  translate: 4px 0;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3em 0.75em;
  border-radius: var(--radius-pill);
  background: var(--bg-sunken);
  border: 1px solid var(--line);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-decoration: none;
  white-space: nowrap;
}
.chip-brand {
  background: var(--brand-soft);
  border-color: transparent;
  color: var(--brand);
}
.chip-accent {
  background: color-mix(in oklab, var(--accent) 16%, transparent);
  border-color: transparent;
  color: var(--accent);
}
.chip[aria-current='true'],
.chip.is-active {
  background: var(--brand);
  border-color: transparent;
  color: var(--on-brand);
}
/* .chip is nowrap so short filter labels never break mid-word. A chip holding
   a longer phrase - "Duplex free-standing villas - under construction" - needs
   to wrap instead, or it forces its card wider than the column. */
.chip-wrap {
  white-space: normal;
  text-align: left;
}
.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.chip-scroll {
  display: flex;
  gap: 0.5rem;
  overflow-x: auto;
  padding-block: 0.3rem;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}
.chip-scroll::-webkit-scrollbar {
  height: 4px;
}
.chip-scroll::-webkit-scrollbar-thumb {
  background: var(--line-strong);
  border-radius: 4px;
}

.status {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.25em 0.7em;
  border-radius: var(--radius-pill);
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.status::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.status-open {
  background: var(--info-bg);
  color: var(--info-fg);
}
.status-in_progress {
  background: var(--warn-bg);
  color: var(--warn-fg);
}
.status-answered {
  background: var(--ok-bg);
  color: var(--ok-fg);
}
.status-closed {
  background: var(--bg-sunken);
  color: var(--text-soft);
}
.status-pending {
  background: var(--warn-bg);
  color: var(--warn-fg);
}
.status-active {
  background: var(--ok-bg);
  color: var(--ok-fg);
}
.status-suspended {
  background: var(--err-bg);
  color: var(--err-fg);
}
.status-draft {
  background: var(--bg-sunken);
  color: var(--text-soft);
}
.status-published {
  background: var(--ok-bg);
  color: var(--ok-fg);
}

/* ------------------------------------------------------------ site header */

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: color-mix(in oklab, var(--bg) 82%, transparent);
  backdrop-filter: blur(14px) saturate(150%);
  border-bottom: 1px solid transparent;
  transition: border-color 0.3s var(--ease), background 0.3s var(--ease),
    box-shadow 0.3s var(--ease);
}
.site-header.is-stuck {
  border-bottom-color: var(--line);
  box-shadow: var(--shadow-sm);
}
.header-inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  min-height: 4.5rem;
  transition: min-height 0.3s var(--ease);
}
.site-header.is-stuck .header-inner {
  min-height: 3.6rem;
}

.brand {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  text-decoration: none;
  margin-right: auto;
  flex: none;
  color: var(--text);
}

/* The supplied wordmark, drawn as a mask so it takes the page's own text
   colour. That is what lets one file sit correctly on the white header, on the
   green footer and in the dark theme — a black PNG would disappear on two of
   the three. */
.brand-logo {
  display: block;
  flex: none;
  height: 1.95rem;
  aspect-ratio: 1053 / 317;
  background: currentColor;
  -webkit-mask: url("/img/logo.svg") center / contain no-repeat;
  mask: url("/img/logo.svg") center / contain no-repeat;
  transition: height 0.3s var(--ease), opacity 0.25s var(--ease);
}
.brand:hover .brand-logo {
  opacity: 0.72;
}
/* If a browser cannot do masks it would otherwise paint a solid block, so fall
   back to the name set in type. Nested @supports because Safari needs the
   prefixed property tested separately. */
.brand-logo::after {
  content: "Royal Park";
  display: none;
}
@supports not (mask-image: url("/img/logo.svg")) {
  @supports not (-webkit-mask-image: url("/img/logo.svg")) {
    .brand-logo {
      background: none;
      aspect-ratio: auto;
      height: auto;
      font-family: var(--font-display);
      font-size: 1.15rem;
      font-weight: 600;
      letter-spacing: -0.01em;
    }
    .brand-logo::after {
      display: inline;
    }
  }
}
.site-header.is-stuck .brand-logo {
  height: 1.7rem;
}
.brand-sub {
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-soft);
  padding-left: 0.75rem;
  border-left: 1px solid var(--line);
  align-self: center;
}
@media (max-width: 32rem) {
  /* No room for the locality line beside the mark on a narrow phone. */
  .brand-sub {
    display: none;
  }
}

.nav {
  display: flex;
  align-items: center;
  gap: 0.15rem;
}
.nav a {
  padding: 0.5rem 0.7rem;
  border-radius: var(--radius-pill);
  font-size: 0.86rem;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  position: relative;
}
.nav a::after {
  content: '';
  position: absolute;
  left: 0.7rem;
  right: 0.7rem;
  bottom: 0.28rem;
  height: 1.5px;
  background: var(--accent);
  scale: 0 1;
  transform-origin: left;
  transition: scale 0.25s var(--ease);
}
.nav a:hover::after,
.nav a[aria-current='page']::after {
  scale: 1 1;
}
.nav a[aria-current='page'] {
  color: var(--accent);
  font-weight: 600;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex: none;
}
.icon-btn {
  display: grid;
  place-items: center;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: transparent;
  cursor: pointer;
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease),
    rotate 0.4s var(--ease);
}
.icon-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
  rotate: 12deg;
}
/* Between the drawer breakpoint and about 1050px the signed-in council menu is
   the longest the header ever gets — it carries the Council link and Sign out on
   top of the six public links — and at 1024px it came to 1026px, which put a
   horizontal scrollbar on every admin page. Tightening the link padding in that
   band alone recovers roughly 50px, so the header fits at every width and no
   other size is touched. */
@media (min-width: 62.01rem) and (max-width: 66rem) {
  .nav {
    gap: 0;
  }
  .nav a {
    padding-inline: 0.45rem;
  }
}

.nav-toggle {
  display: none;
}

/* Mobile drawer */
@media (max-width: 62rem) {
  .nav-toggle {
    display: grid;
  }
  .nav {
    position: fixed;
    inset: 4.5rem 0 auto;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--bg-raised);
    border-bottom: 1px solid var(--line);
    box-shadow: var(--shadow-lg);
    padding: 0.6rem var(--gutter) 1.4rem;
    max-height: calc(100dvh - 4.5rem);
    overflow-y: auto;
    clip-path: inset(0 0 100% 0);
    transition: clip-path 0.35s var(--ease);
  }
  .nav[data-open='true'] {
    clip-path: inset(0 0 0 0);
  }
  .nav a:not(.btn) {
    padding: 0.95rem 0.4rem;
    border-bottom: 1px solid var(--line);
    font-size: 1.02rem;
    border-radius: 0;
  }
  .nav a::after {
    display: none;
  }
  .nav .btn {
    margin-top: 1rem;
    justify-content: center;
  }
  .header-cta {
    display: none;
  }
  .nav .header-cta {
    display: inline-flex;
  }
}

/* ------------------------------------------------------------------- hero */

.hero {
  position: relative;
  isolation: isolate;
  color: var(--text-inverse);
  background: var(--green-900);
  overflow: hidden;
  min-height: min(88svh, 46rem);
  display: grid;
  align-items: end;
}
.hero-media {
  position: absolute;
  inset: 0;
  z-index: -2;
}
.hero-media img,
.hero-media svg {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
@keyframes kenburns {
  from {
    scale: 1;
    translate: 0 0;
  }
  to {
    scale: 1.09;
    translate: -1.5% -1.5%;
  }
}
/* The slow zoom on the hero photograph is off.

   It was decorative — a 9% zoom over 26 seconds — and it cost a full-screen
   resample every frame. It caused two separate complaints on real hardware: a
   4K television where it flickered, and a cold page open where it shuddered.
   Measured on the home page, frames over 20 ms in a three-second sample:

     1536 px   60 fps, 0 slow frames
     1600 px   57 fps, 7
     1920 px   41 fps, 43
     3840 px   27 fps, 75

   No compositing hint helped: will-change, transform instead of the individual
   scale/translate properties, and backface-visibility were each measured and
   each made no difference. A width-based cut-off was tried next and was the
   wrong test — screen width says nothing about how much machine is behind it,
   and a television reporting 1280 CSS pixels is far weaker than a laptop
   reporting the same. Detecting the difference at runtime proved unreliable
   too: an idle frame counter stays fast on a device that still cannot carry the
   work.

   So the photograph is simply still. Nothing of substance is lost.

   To bring it back, delete the `animation: none` below and restore
   `animation: kenburns 26s var(--ease) infinite alternate;` on .hero-media img.
   The @keyframes are left in place for that. */
.hero-media img,
.hero-media svg {
  animation: none;
}
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(
      to top,
      rgba(6, 18, 13, 0.92) 0%,
      rgba(6, 18, 13, 0.72) 40%,
      rgba(6, 18, 13, 0.2) 70%,
      rgba(6, 18, 13, 0.45) 100%
    ),
    radial-gradient(120% 90% at 15% 100%, rgba(12, 35, 28, 0.75), transparent 60%);
}
.hero-inner {
  padding-block: clamp(3rem, 12vh, 8rem) clamp(2.5rem, 6vh, 4.5rem);
  display: grid;
  gap: 1.6rem;
  max-width: 54rem;
}
.hero h1 {
  font-size: var(--step-5);
  font-variation-settings: 'SOFT' 20, 'WONK' 1;
  /* Keeps the headline legible over any photograph that goes in behind it. */
  text-shadow: 0 1px 24px rgba(4, 14, 10, 0.55);
}
.hero .lede {
  color: rgba(238, 247, 242, 0.9);
  text-shadow: 0 1px 16px rgba(4, 14, 10, 0.5);
  max-width: 44ch;
  font-size: var(--step-1);
}
.hero .eyebrow {
  color: var(--brass-300);
}
.hero-scroll {
  position: absolute;
  bottom: 1.2rem;
  right: var(--gutter);
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(238, 247, 242, 0.6);
  writing-mode: vertical-rl;
  display: flex;
  align-items: center;
  gap: 0.7rem;
}
.hero-scroll::after {
  content: '';
  width: 1px;
  height: 3rem;
  background: linear-gradient(to bottom, currentColor, transparent);
}
@media (max-width: 48rem) {
  .hero-scroll {
    display: none;
  }
}

/* Weather chip in the hero */
.weather-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.6rem 1.1rem 0.6rem 0.75rem;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.18);
  backdrop-filter: blur(10px);
  width: fit-content;
  text-decoration: none;
  color: inherit;
  font-size: 0.84rem;
}
.weather-chip:hover {
  color: inherit;
  border-color: var(--brass-300);
}
.weather-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--green-300);
  box-shadow: 0 0 0 0 color-mix(in oklab, var(--green-300) 70%, transparent);
  animation: pulse 2.4s ease-out infinite;
  flex: none;
  margin-inline: 0.3rem;
}
@keyframes pulse {
  70% {
    box-shadow: 0 0 0 9px transparent;
  }
  100% {
    box-shadow: 0 0 0 0 transparent;
  }
}
.weather-chip strong {
  font-family: var(--font-display);
  font-size: 1.05rem;
}
.weather-chip small {
  color: rgba(238, 247, 242, 0.6);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* ------------------------------------------------------------ stats band */

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
  border-top: 1px solid var(--line);
}
.stat {
  padding: clamp(1.4rem, 4vw, 2.6rem) clamp(1rem, 3vw, 2rem);
  border-bottom: 1px solid var(--line);
  border-right: 1px solid var(--line);
  display: grid;
  gap: 0.25rem;
  align-content: start;
}
.stat:last-child {
  border-right: none;
}
.stat-value {
  font-family: var(--font-display);
  font-size: var(--step-3);
  line-height: 1;
  color: var(--brand);
  font-variation-settings: 'SOFT' 10, 'WONK' 1;
}
.stat-label {
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.stat-note {
  font-size: var(--step--1);
  color: var(--text-soft);
}

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

.card {
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(1.3rem, 3vw, 2rem);
  display: grid;
  gap: 0.7rem;
  align-content: start;
  position: relative;
  transition: transform 0.3s var(--ease), box-shadow 0.3s var(--ease),
    border-color 0.3s var(--ease);
}
.card-hover:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-md);
  border-color: color-mix(in oklab, var(--accent) 45%, var(--line));
}
.card h3 {
  font-size: var(--step-1);
}
.card p {
  color: var(--text-soft);
  font-size: 0.95rem;
}
.card-note {
  font-size: 0.76rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--accent);
  font-weight: 600;
}
.card-icon {
  width: 2.6rem;
  height: 2.6rem;
  color: var(--brand);
}
.card-link {
  text-decoration: none;
  color: inherit;
}
.card-link:hover {
  color: inherit;
}

/* Numbered feature list */
.numbered {
  display: grid;
  gap: 1.6rem;
  counter-reset: n;
  list-style: none;
  padding: 0;
}
.numbered li {
  counter-increment: n;
  display: grid;
  grid-template-columns: 2.6rem 1fr;
  gap: 1rem;
  align-items: start;
}
.numbered li::before {
  content: counter(n, decimal-leading-zero);
  font-family: var(--font-display);
  font-size: 1.1rem;
  color: var(--accent);
  border-top: 2px solid var(--accent);
  padding-top: 0.35rem;
}
.numbered h4 {
  margin-bottom: 0.2rem;
}
.numbered p {
  color: var(--text-soft);
  font-size: 0.95rem;
}

/* ------------------------------------------------------------- estate map */

.map-panel {
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(1rem, 3vw, 1.8rem);
  box-shadow: var(--shadow-sm);
}
.estate-map {
  width: 100%;
  height: auto;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg-sunken);
}
.estate-map .zone {
  cursor: pointer;
  transition: opacity 0.25s var(--ease), filter 0.25s var(--ease);
}
.estate-map .zone:hover,
.estate-map .zone.is-active {
  filter: brightness(1.15) saturate(1.3);
}
.estate-map.has-active .zone:not(.is-active) {
  opacity: 0.35;
}
.estate-map .zone-label {
  font-family: var(--font-text);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  fill: #fff;
  pointer-events: none;
}
.map-legend {
  display: grid;
  gap: 0.4rem;
  margin-top: 1.2rem;
}
.map-legend button {
  display: grid;
  grid-template-columns: 0.85rem 1fr auto;
  align-items: center;
  gap: 0.7rem;
  width: 100%;
  padding: 0.55rem 0.7rem;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius);
  cursor: pointer;
  text-align: left;
  transition: background 0.2s var(--ease), border-color 0.2s var(--ease);
}
.map-legend button:hover,
.map-legend button.is-active {
  background: var(--bg-sunken);
  border-color: var(--line);
}
.map-legend .swatch {
  width: 0.85rem;
  height: 0.85rem;
  border-radius: 4px;
  flex: none;
}
.map-legend .legend-name {
  font-weight: 600;
  font-size: 0.92rem;
}
.map-legend .legend-kind {
  font-size: 0.76rem;
  color: var(--text-soft);
  display: block;
  font-weight: 400;
}
.map-readout {
  margin-top: 1rem;
  padding: 1rem 1.1rem;
  background: var(--bg-sunken);
  border-radius: var(--radius);
  border: 1px solid var(--line);
  min-height: 5.5rem;
  font-size: 0.92rem;
  color: var(--text-soft);
}
.map-readout strong {
  color: var(--text);
  display: block;
  font-family: var(--font-display);
  font-size: 1.1rem;
  margin-bottom: 0.25rem;
}
.map-readout em {
  color: var(--accent);
  font-style: normal;
  font-weight: 600;
}

/* -------------------------------------------------------------- news list */

.news-grid {
  display: grid;
  gap: clamp(1.1rem, 2.6vw, 1.8rem);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 19rem), 1fr));
}
.news-card {
  display: grid;
  grid-template-rows: auto 1fr;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  transition: transform 0.3s var(--ease), box-shadow 0.3s var(--ease);
}
.news-card:hover {
  color: inherit;
  transform: translateY(-4px);
  box-shadow: var(--shadow-md);
}
.news-card-media {
  aspect-ratio: 16 / 9;
  background: var(--bg-sunken);
  overflow: hidden;
}
.news-card-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: scale 0.5s var(--ease);
}
.news-card:hover .news-card-media img {
  scale: 1.05;
}
.news-card-body {
  padding: 1.2rem 1.3rem 1.4rem;
  display: grid;
  gap: 0.55rem;
  align-content: start;
}
.news-card h3 {
  font-size: var(--step-1);
}
.news-card p {
  color: var(--text-soft);
  font-size: 0.92rem;
}
.news-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 0.8rem;
  align-items: center;
  font-size: 0.78rem;
  color: var(--text-soft);
  letter-spacing: 0.03em;
}
.news-featured {
  display: grid;
  gap: clamp(1.2rem, 4vw, 3rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
  align-items: center;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.news-featured .news-card-media {
  aspect-ratio: 4 / 3;
  height: 100%;
}
.news-featured-body {
  padding: clamp(1.4rem, 4vw, 3rem);
  display: grid;
  gap: 0.9rem;
  align-content: center;
}
.news-featured h2 {
  font-size: var(--step-2);
}

/* ------------------------------------------------------- pdf attachment */

.attachment {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 1rem;
  margin-top: clamp(1.8rem, 4vw, 2.6rem);
  padding: 1rem 1.25rem;
  background: var(--bg-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  text-decoration: none;
  color: inherit;
  transition: border-color 0.2s var(--ease), transform 0.2s var(--ease),
    box-shadow 0.2s var(--ease);
}
.attachment:hover {
  color: inherit;
  border-color: var(--accent);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}
.attachment-icon {
  display: grid;
  place-items: center;
  width: 2.9rem;
  height: 3.4rem;
  flex: none;
  border-radius: 6px;
  background: color-mix(in oklab, var(--err-fg) 12%, var(--bg-sunken));
  border: 1px solid color-mix(in oklab, var(--err-fg) 35%, transparent);
  color: var(--err-fg);
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.06em;
}
.attachment-text {
  display: grid;
  gap: 0.15rem;
  min-width: 0;
}
.attachment-text strong {
  font-size: 0.98rem;
  overflow-wrap: anywhere;
}
.attachment-text small {
  font-size: 0.8rem;
  color: var(--text-soft);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.attachment-arrow {
  width: 2.2rem;
  height: 2.2rem;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--brand);
  color: var(--on-brand);
  font-size: 1.05rem;
  transition: translate 0.2s var(--ease);
}
.attachment:hover .attachment-arrow {
  translate: 0 3px;
}
/* The word is redundant beside the filename on a wide screen, but the arrow
   alone is ambiguous once it becomes a full-width bar on a phone. */
.attachment-arrow b {
  display: none;
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}
@media (max-width: 30rem) {
  .attachment {
    grid-template-columns: auto 1fr;
  }
  .attachment-arrow {
    grid-column: 1 / -1;
    width: 100%;
    border-radius: var(--radius-pill);
    height: 2.6rem;
    gap: 0.5rem;
    grid-auto-flow: column;
  }
  .attachment-arrow b {
    display: inline;
  }
}

.article-header {
  display: grid;
  gap: 1rem;
  padding-block: clamp(2rem, 6vw, 4rem) clamp(1.4rem, 3vw, 2.2rem);
}
.article-hero {
  aspect-ratio: 21 / 9;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--bg-sunken);
  margin-bottom: clamp(1.6rem, 4vw, 3rem);
}
.article-hero img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ------------------------------------------------------------------ board */

.board-list {
  display: grid;
  gap: 0.8rem;
}
.board-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 0.6rem 1rem;
  align-items: center;
  padding: 1.1rem 1.2rem;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  text-decoration: none;
  color: inherit;
  transition: border-color 0.2s var(--ease), transform 0.2s var(--ease),
    box-shadow 0.2s var(--ease);
}
.board-row:hover {
  color: inherit;
  border-color: color-mix(in oklab, var(--accent) 45%, var(--line));
  transform: translateX(3px);
  box-shadow: var(--shadow-sm);
}
.board-kind {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  flex: none;
  font-size: 1.1rem;
  background: var(--brand-soft);
  color: var(--brand);
}
.board-kind[data-kind='notification'] {
  background: var(--info-bg);
  color: var(--info-fg);
}
.board-kind[data-kind='request'] {
  background: var(--warn-bg);
  color: var(--warn-fg);
}
.board-main {
  display: grid;
  gap: 0.25rem;
  min-width: 0;
}
.board-main h3 {
  font-family: var(--font-text);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1.35;
}
.board-sub {
  font-size: 0.8rem;
  color: var(--text-soft);
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 0.7rem;
}
.board-side {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  flex: none;
}
.reply-count {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.82rem;
  color: var(--text-soft);
  font-variant-numeric: tabular-nums;
}
@media (max-width: 40rem) {
  .board-row {
    grid-template-columns: auto 1fr;
  }
  .board-side {
    grid-column: 1 / -1;
    justify-content: space-between;
    padding-top: 0.3rem;
    border-top: 1px solid var(--line);
  }
}

.thread {
  display: grid;
  gap: 1rem;
}
.message {
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.1rem 1.3rem;
  display: grid;
  gap: 0.6rem;
}
.message-council {
  border-color: color-mix(in oklab, var(--brand) 40%, var(--line));
  background: var(--brand-soft);
}
.message-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.8rem;
  font-size: 0.85rem;
}
.message-author {
  font-weight: 600;
}
.message-time {
  color: var(--text-soft);
  font-size: 0.8rem;
}
.avatar {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--bg-inverse);
  color: var(--text-inverse);
  font-size: 0.78rem;
  font-weight: 700;
  flex: none;
  letter-spacing: 0.02em;
}
.avatar-council {
  background: var(--brass-500);
  color: #1a1405;
}
/* The avatar is the way to your own account, so it has to behave like a link.
   It is NOT a nav item: adding one more word to the header pushed the
   signed-in council menu past the edge of a 1024px screen. */
a.avatar {
  text-decoration: none;
  transition: scale 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
a.avatar:hover {
  scale: 1.07;
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 35%, transparent);
  color: var(--text-inverse);
}
a.avatar.avatar-council:hover {
  color: #1a1405;
}

/* ------------------------------------------------------------------ forms */

.form {
  display: grid;
  gap: 1.1rem;
}
.field {
  display: grid;
  gap: 0.4rem;
  /* Without this, a field sitting beside a taller one (because that one has a
     hint line and this one does not) stretches its own input to match, so two
     inputs in a row end up different heights. */
  align-content: start;
}
.field > label {
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.field .hint {
  font-size: 0.8rem;
  color: var(--text-soft);
}
input[type='text'],
input[type='email'],
input[type='password'],
input[type='search'],
input[type='file'],
select,
textarea {
  width: 100%;
  padding: 0.75rem 0.9rem;
  min-height: 44px;
  background: var(--bg-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  transition: border-color 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
textarea {
  min-height: 9rem;
  resize: vertical;
  line-height: 1.6;
  font-family: inherit;
}
input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 22%, transparent);
}
select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 49%, currentColor 50%),
    linear-gradient(-45deg, transparent 49%, currentColor 50%);
  background-size: 6px 6px, 6px 6px;
  background-position: calc(100% - 1.15rem) 55%, calc(100% - 0.75rem) 55%;
  background-repeat: no-repeat;
  padding-right: 2.4rem;
}
.radio-cards {
  display: grid;
  gap: 0.6rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
}
.radio-card {
  position: relative;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  padding: 0.9rem 1rem;
  cursor: pointer;
  display: grid;
  gap: 0.2rem;
  transition: border-color 0.2s var(--ease), background 0.2s var(--ease);
}
.radio-card input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.radio-card:hover {
  border-color: var(--accent-soft);
}
.radio-card:has(input:checked) {
  border-color: var(--accent);
  background: color-mix(in oklab, var(--accent) 10%, transparent);
}
.radio-card:has(input:focus-visible) {
  outline: 2.5px solid var(--accent);
  outline-offset: 2px;
}
.radio-card strong {
  font-size: 0.94rem;
}
.radio-card span {
  font-size: 0.8rem;
  color: var(--text-soft);
}
.checkline {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.92rem;
}
.checkline input {
  width: 1.15rem;
  height: 1.15rem;
  accent-color: var(--brand);
  flex: none;
}
.form-panel {
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(1.3rem, 4vw, 2.4rem);
  box-shadow: var(--shadow-sm);
}

/* --------------------------------------------------------------- messages */

.alert {
  display: flex;
  gap: 0.8rem;
  align-items: flex-start;
  padding: 0.9rem 1.1rem;
  border-radius: var(--radius);
  font-size: 0.92rem;
  border: 1px solid transparent;
}
.alert-success {
  background: var(--ok-bg);
  color: var(--ok-fg);
  border-color: color-mix(in oklab, var(--ok-fg) 25%, transparent);
}
.alert-error {
  background: var(--err-bg);
  color: var(--err-fg);
  border-color: color-mix(in oklab, var(--err-fg) 25%, transparent);
}
.alert-info {
  background: var(--info-bg);
  color: var(--info-fg);
  border-color: color-mix(in oklab, var(--info-fg) 25%, transparent);
}
.alert ul {
  margin: 0;
  padding-left: 1.1rem;
}
.flash-slot {
  padding-top: 1.2rem;
}

.empty {
  text-align: center;
  padding: clamp(2.5rem, 8vw, 5rem) 1.5rem;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-lg);
  color: var(--text-soft);
  display: grid;
  gap: 0.8rem;
  justify-items: center;
}
.empty h3 {
  color: var(--text);
}

/* ------------------------------------------------------------------ admin */

.admin-shell {
  display: grid;
  gap: clamp(1.2rem, 3vw, 2.4rem);
  grid-template-columns: minmax(0, 1fr);
  padding-block: clamp(1.5rem, 4vw, 3rem);
}
@media (min-width: 60rem) {
  .admin-shell {
    grid-template-columns: 15rem minmax(0, 1fr);
    align-items: start;
  }
  .admin-nav {
    position: sticky;
    top: 6rem;
  }
}
.admin-nav {
  display: grid;
  gap: 0.2rem;
  align-content: start;
}
.admin-nav a {
  padding: 0.65rem 0.9rem;
  border-radius: var(--radius);
  text-decoration: none;
  font-size: 0.92rem;
  font-weight: 500;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  transition: background 0.2s var(--ease);
}
.admin-nav a:hover {
  background: var(--bg-sunken);
  color: inherit;
}
.admin-nav a[aria-current='page'] {
  background: var(--brand);
  color: var(--on-brand);
}
.admin-nav .count {
  font-size: 0.75rem;
  font-weight: 700;
  padding: 0.1rem 0.45rem;
  border-radius: var(--radius-pill);
  background: var(--brass-500);
  color: #1a1405;
}
.admin-nav a[aria-current='page'] .count {
  background: rgba(255, 255, 255, 0.9);
  color: var(--brand);
}

.tile-row {
  display: grid;
  gap: 0.9rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
}
.tile {
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.1rem 1.2rem;
  display: grid;
  gap: 0.15rem;
}
.tile-value {
  font-family: var(--font-display);
  font-size: var(--step-2);
  line-height: 1;
  color: var(--brand);
}
.tile-label {
  font-size: 0.8rem;
  color: var(--text-soft);
}

.table-scroll {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-raised);
}
table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
  min-width: 34rem;
}
th,
td {
  text-align: left;
  padding: 0.8rem 1rem;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}
th {
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-soft);
  background: var(--bg-sunken);
  white-space: nowrap;
}
tbody tr:last-child td {
  border-bottom: none;
}
tbody tr:hover {
  background: color-mix(in oklab, var(--accent) 5%, transparent);
}
td .btn-row {
  gap: 0.35rem;
}

/* Visually hidden, still read aloud. No negative margin and no absolute
   positioning: inside a table cell that scrolls sideways, an absolutely
   positioned copy of this is laid out against the page rather than the cell and
   drags the document width out with it — which put a horizontal scrollbar on
   the whole admin page on a phone. A static 1px box cannot do that. */
.sr-only {
  display: inline-block;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* The owners table is the widest in the site — seven columns, and the last one
   holds the buttons that do the actual work. Inside the admin layout the
   content column is around 670px at 1024px wide, so the table scrolls sideways
   and those buttons used to sit off the right-hand edge, invisible unless you
   thought to scroll a table. Two things stop that:
   the joining date is dropped on narrower screens, and the action column is
   pinned to the right so it stays put however far the rest scrolls. */
/* The email address and the joining date sit under the name instead of taking
   columns of their own. Seven columns never fitted: the admin content column is
   about 860px at any desktop size (the page has a maximum width) and only 670px
   at 1024px, so the action buttons — the ones that do the work — ended up off
   the right-hand edge behind a sideways scroll nobody thinks to try. Five
   columns fit, and no information is lost. */
/* ------------------------------------------------------------ council votes */

.poll-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  justify-content: space-between;
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-raised);
  text-decoration: none;
  transition: border-color 0.18s var(--ease), transform 0.18s var(--ease);
}
.poll-row:hover {
  border-color: var(--brand);
  transform: translateX(2px);
  color: inherit;
}
.poll-row-main {
  display: grid;
  gap: 0.15rem;
  min-width: 0;
}

.status-draft {
  background: var(--bg-sunken);
  color: var(--text-soft);
}

/* Turnout — who has finished answering, not how they answered. */
.turnout {
  display: grid;
  gap: 0.55rem;
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-sunken);
  font-size: 0.9rem;
}
.turnout-bar {
  height: 7px;
  border-radius: 999px;
  background: var(--line);
  overflow: hidden;
}
.turnout-bar span {
  display: block;
  height: 100%;
  background: var(--brand);
  transition: width 0.4s var(--ease);
}

.poll-q {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-raised);
  padding: 1.1rem 1.2rem;
  display: grid;
  gap: 1rem;
}
.poll-q-head {
  display: flex;
  gap: 0.8rem;
  align-items: baseline;
}
.poll-q-num {
  flex: none;
  width: 1.7rem;
  height: 1.7rem;
  border-radius: 50%;
  background: var(--brand);
  color: var(--on-brand);
  display: grid;
  place-items: center;
  font-size: 0.8rem;
  font-weight: 700;
  align-self: start;
}
.poll-q-text {
  font-family: var(--font-text);
  font-size: 1.02rem;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 0;
}

/* The three answers. Big targets, because most of this happens on a phone
   during or just after a meeting. */
.vote-choices {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.vote-choice {
  position: relative;
  flex: 1 1 7rem;
  min-width: 6rem;
}
.vote-choice input {
  position: absolute;
  opacity: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: pointer;
}
.vote-choice span {
  display: block;
  text-align: center;
  padding: 0.7rem 0.6rem;
  border: 1.5px solid var(--line);
  border-radius: var(--radius);
  font-weight: 600;
  font-size: 0.92rem;
  background: var(--bg);
  transition: border-color 0.15s var(--ease), background 0.15s var(--ease),
    color 0.15s var(--ease);
}
.vote-choice input:hover + span {
  border-color: var(--line-strong);
}
.vote-choice input:focus-visible + span {
  outline: 2.5px solid var(--accent);
  outline-offset: 2px;
}
.vote-yes input:checked + span {
  background: var(--ok-bg);
  border-color: var(--ok-fg);
  color: var(--ok-fg);
}
.vote-no input:checked + span {
  background: var(--err-bg);
  border-color: var(--err-fg);
  color: var(--err-fg);
}
.vote-abstain input:checked + span {
  background: var(--bg-sunken);
  border-color: var(--text-soft);
  color: var(--text-soft);
}
.vote-clear {
  flex: 0 1 6rem;
}
.vote-clear span {
  font-weight: 500;
  color: var(--text-soft);
  border-style: dashed;
}
.vote-clear input:checked + span {
  border-color: var(--err-fg);
  color: var(--err-fg);
  border-style: solid;
}

/* The save bar follows you down a long list of questions. It needs an opaque
   background of its own: sticky elements pass over the content behind them, and
   a bare button floating across a tally line looked like a rendering fault. */
.vote-save {
  position: sticky;
  bottom: 0;
  z-index: 5;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  padding: 0.85rem 0;
  background: color-mix(in oklab, var(--bg) 92%, transparent);
  backdrop-filter: blur(8px);
  border-top: 1px solid var(--line);
}
.vote-save span {
  font-size: 0.84rem;
  color: var(--text-soft);
}

.poll-result {
  display: grid;
  gap: 0.6rem;
}
.poll-bar {
  display: flex;
  height: 9px;
  border-radius: 999px;
  overflow: hidden;
  background: var(--line);
}
.poll-bar span {
  transition: width 0.4s var(--ease);
}
.bar-yes {
  background: var(--ok-fg);
}
.bar-no {
  background: var(--err-fg);
}
.bar-abstain {
  background: var(--ink-300);
}
.poll-tally {
  font-size: 0.88rem;
}
.poll-verdict {
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.76rem;
}
.poll-verdict.is-carried {
  color: var(--ok-fg);
}
.poll-verdict.is-lost {
  color: var(--err-fg);
}
.poll-verdict.is-tied {
  color: var(--warn-fg);
}
.poll-names {
  display: grid;
  gap: 0.3rem;
  font-size: 0.84rem;
  padding-top: 0.2rem;
  border-top: 1px solid var(--line);
}
.poll-names-group {
  display: flex;
  gap: 0.6rem;
  align-items: baseline;
}
.poll-names-label {
  flex: none;
  width: 4.6rem;
  font-weight: 700;
  font-size: 0.74rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.poll-names-list {
  min-width: 0;
}
.vote-yes-text {
  color: var(--ok-fg);
}
.vote-no-text {
  color: var(--err-fg);
}
.vote-abstain-text {
  color: var(--text-soft);
}

/* The one-time sign-in link, shown once after it is generated. */
.link-panel {
  border: 1px solid var(--brand);
  background: var(--brand-soft);
  border-radius: var(--radius);
  padding: 1.1rem 1.2rem;
}
.link-panel-title {
  margin: 0 0 0.4rem;
  font-weight: 700;
  color: var(--brand);
}
.link-panel-note {
  margin: 0 0 0.9rem;
  font-size: 0.88rem;
  line-height: 1.5;
  color: var(--text);
}
.link-copy {
  display: flex;
  gap: 0.5rem;
  align-items: stretch;
  flex-wrap: wrap;
}
.link-url {
  flex: 1 1 18rem;
  min-width: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.8rem;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg);
  color: var(--text);
}
.link-copy .btn {
  flex: none;
}

.table-owners .cell-meta {
  display: block;
  font-size: 0.78rem;
  font-weight: 400;
  color: var(--text-soft);
}
.table-owners td .btn-row {
  flex-wrap: wrap;
  justify-content: flex-end;
}
.inline-form {
  display: inline;
}

.page-head {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: flex-end;
  justify-content: space-between;
  padding-block: clamp(1.6rem, 5vw, 3.4rem) clamp(1rem, 2.5vw, 1.8rem);
}
.page-head .stack {
  --stack-gap: 0.6rem;
}
.page-head h1 {
  font-size: var(--step-3);
}

/* ----------------------------------------------------------------- footer */

.site-footer {
  background: var(--bg-inverse);
  color: var(--text-inverse);
  padding-block: clamp(2.5rem, 6vw, 4.5rem) 1.5rem;
  margin-top: auto;
}
.footer-grid {
  display: grid;
  gap: clamp(1.6rem, 4vw, 3rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
  padding-bottom: 2.5rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}
.footer-grid h4 {
  font-family: var(--font-text);
  font-size: 0.74rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brass-300);
  margin-bottom: 0.9rem;
  font-weight: 700;
}
.footer-grid ul {
  list-style: none;
  padding: 0;
  display: grid;
  gap: 0.5rem;
}
.footer-grid a {
  text-decoration: none;
  color: var(--text-inverse-soft);
  font-size: 0.92rem;
}
.footer-grid a:hover {
  color: var(--brass-300);
}
.footer-wordmark {
  margin: 0;
}
.footer-logo {
  height: 2.4rem;
  color: var(--text-inverse);
}
.footer-brand p {
  color: var(--text-inverse-soft);
  font-size: 0.92rem;
  max-width: 32ch;
  margin-top: 0.8rem;
}
.footer-notices {
  padding-block: 2rem;
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}
.footer-notice {
  font-size: 0.82rem;
  color: var(--text-inverse-soft);
  line-height: 1.6;
}
.footer-notice strong {
  color: var(--text-inverse);
  display: block;
  margin-bottom: 0.2rem;
  font-size: 0.86rem;
}
.footer-base {
  padding-top: 1.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.4rem;
  justify-content: space-between;
  align-items: center;
  font-size: 0.8rem;
  color: var(--text-inverse-soft);
}

/* ------------------------------------------------------- scroll reveal */

/* Scoped to .js so that with scripting off — or if site.js fails to load —
   every section is simply visible rather than transparent. */
.js .reveal {
  opacity: 0;
  translate: 0 18px;
  transition: opacity 0.7s var(--ease), translate 0.7s var(--ease);
}
.js .reveal.is-visible {
  opacity: 1;
  translate: 0 0;
}
@media (prefers-reduced-motion: reduce) {
  .js .reveal {
    opacity: 1;
    translate: 0 0;
  }
}

/* ------------------------------------------------------------------ print */

@media print {
  .site-header,
  .site-footer,
  .hero-media,
  .btn,
  .nav,
  .header-actions,
  .chip-scroll,
  .board-side,
  form {
    display: none !important;
  }
  body {
    background: #fff;
    color: #000;
    font-size: 11pt;
  }
  .hero {
    min-height: auto;
    color: #000;
    background: none;
  }
  .hero::after {
    display: none;
  }
  a[href^='http']::after {
    content: ' (' attr(href) ')';
    font-size: 9pt;
    color: #555;
  }
  .card,
  .message,
  .table-scroll {
    border: 1px solid #bbb;
    box-shadow: none;
    break-inside: avoid;
  }
  .section {
    padding-block: 1rem;
  }

  /* A council vote is meant to be printed for the minutes. The blanket
     "hide every form" rule above would take the questions with it while the
     vote is still open, since they live inside the voting form — so the form
     itself is put back, and only the controls are dropped. The names stay:
     they are the point of the record. */
  .admin-shell form {
    display: block !important;
  }
  .admin-nav,
  .vote-choices,
  .vote-save,
  .poll-q form,
  .form-panel .btn-row,
  /* `.admin-shell form` above puts every council form back so a poll's
     questions survive printing. The items register has no such need — its
     forms are controls, not content — so they are marked and dropped again
     here. Printing the register should give you the agenda, not the buttons.

     Written as `.admin-shell .no-print` rather than plain `.no-print`: both
     rules carry !important, so the winner is decided on specificity, and
     `.admin-shell form` (0,1,1) would otherwise beat `.no-print` (0,1,0) and
     put the form back again. */
  .no-print,
  .admin-shell .no-print {
    display: none !important;
  }
  .admin-shell {
    display: block;
  }
  .poll-q,
  .turnout {
    border: 1px solid #bbb;
    break-inside: avoid;
    background: none;
  }
  .poll-q-num {
    background: none;
    color: #000;
    border: 1px solid #666;
  }
  .poll-bar,
  .turnout-bar {
    display: none;
  }
  .poll-verdict.is-carried,
  .poll-verdict.is-lost,
  .poll-verdict.is-tied,
  .vote-yes-text,
  .vote-no-text,
  .vote-abstain-text {
    color: #000;
  }
}

/* ------------------------------------------------------- account menu */

/* Everything that belongs to the signed-in person lives behind the avatar
   rather than in the header bar. Three times during this build a single extra
   word in that bar pushed the signed-in council header past the edge of a
   1024px screen; a menu has room for the next item, and the one after that. */
.account {
  position: relative;
  display: flex;
}
button.avatar {
  border: none;
  cursor: pointer;
  font-family: inherit;
  transition: scale 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
button.avatar:hover,
.account-menu:not([hidden]) + button.avatar,
button.avatar[aria-expanded='true'] {
  scale: 1.07;
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 35%, transparent);
}
.account-menu {
  position: absolute;
  top: calc(100% + 0.6rem);
  right: 0;
  z-index: 120;
  min-width: 13rem;
  padding: 0.4rem;
  display: grid;
  gap: 0.1rem;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}
/* `hidden` sets display:none at user-agent weight, which a class selector
   beats — so without this the menu is permanently open. */
.account-menu[hidden] {
  display: none;
}
.account-who {
  display: grid;
  padding: 0.55rem 0.7rem 0.6rem;
  border-bottom: 1px solid var(--line);
  margin-bottom: 0.25rem;
  line-height: 1.3;
}
.account-who strong {
  font-size: 0.9rem;
}
.account-who span {
  font-size: 0.76rem;
  color: var(--text-soft);
}
.account-menu a,
.account-menu button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.55rem 0.7rem;
  border: none;
  background: none;
  border-radius: 9px;
  font-size: 0.88rem;
  text-decoration: none;
  cursor: pointer;
  color: var(--text);
}
.account-menu a:hover,
.account-menu button:hover {
  background: var(--bg-sunken);
  color: var(--text);
}
.account-menu a[aria-current='page'] {
  background: var(--brand-soft);
  color: var(--brand);
  font-weight: 600;
}
.account-menu form {
  margin: 0;
  border-top: 1px solid var(--line);
  padding-top: 0.25rem;
  margin-top: 0.25rem;
}

/* ------------------------------------------------------ visitor passes */

.pass-card {
  --pass-bg: var(--brand-soft);
  max-width: 26rem;
  margin-inline: auto;
  background: var(--pass-bg);
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid color-mix(in oklab, var(--brand) 25%, transparent);
}
.pass-card.is-void {
  --pass-bg: var(--bg-sunken);
  filter: saturate(0.35);
}
.pass-top {
  padding: 1.4rem 1.5rem 1.5rem;
  text-align: center;
}
.pass-kicker {
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brand);
  margin-bottom: 0.5rem;
}
.pass-estate {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.1;
}
.pass-residence {
  font-size: 0.92rem;
  color: var(--text-soft);
  margin-top: 0.15rem;
}
.pass-fields {
  display: grid;
  gap: 0.75rem;
  margin-top: 1.3rem;
  text-align: left;
}
.pass-fields dt {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-soft);
}
.pass-fields dd {
  font-size: 1.02rem;
  margin: 0.1rem 0 0;
  line-height: 1.35;
}
.pass-guest {
  font-size: 1.28rem !important;
  font-weight: 700;
}

/* The notch and dashed line that make it read as a ticket. */
.pass-perforation {
  position: relative;
  height: 1.4rem;
}
.pass-perforation::before {
  content: '';
  position: absolute;
  left: 1.2rem;
  right: 1.2rem;
  top: 50%;
  border-top: 2px dashed color-mix(in oklab, var(--brand) 40%, transparent);
}
.pass-perforation span {
  position: absolute;
  top: 50%;
  translate: 0 -50%;
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 50%;
  background: var(--bg);
}
.pass-perforation span:first-child {
  left: -0.7rem;
}
.pass-perforation span:last-child {
  right: -0.7rem;
}

.pass-bottom {
  padding: 0 1.5rem 1.5rem;
  text-align: center;
}
.pass-qr {
  background: #fff;
  border-radius: var(--radius);
  padding: 0.9rem;
  display: inline-block;
  line-height: 0;
}
.pass-qr svg {
  width: min(13rem, 55vw);
  height: auto;
}
.pass-instruction {
  font-size: 0.8rem;
  color: var(--text-soft);
  margin-top: 0.8rem;
}

/* The verdict. One word, big, unmissable at arm's length in the dark. */
.verdict {
  border-radius: var(--radius-lg);
  padding: 1.6rem 1.4rem;
  text-align: center;
}
.verdict-word {
  font-family: var(--font-display);
  font-size: clamp(2.4rem, 12vw, 3.6rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.02em;
}
.verdict-detail {
  margin-top: 0.6rem;
  font-size: 0.95rem;
}
.verdict-granted {
  background: var(--ok-bg);
  color: var(--ok-fg);
}
.verdict-expired,
.verdict-revoked,
.verdict-unknown {
  background: var(--err-bg);
  color: var(--err-fg);
}
.verdict-not_yet_valid {
  background: var(--warn-bg);
  color: var(--warn-fg);
}

.preset-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
}
.preset {
  position: relative;
}
.preset input {
  position: absolute;
  opacity: 0;
  inset: 0;
  cursor: pointer;
}
.preset span {
  display: block;
  padding: 0.5rem 0.85rem;
  border: 1.5px solid var(--line);
  border-radius: var(--radius-pill);
  font-size: 0.86rem;
  font-weight: 500;
  background: var(--bg);
}
.preset input:checked + span {
  border-color: var(--brand);
  background: var(--brand-soft);
  color: var(--brand);
  font-weight: 600;
}
.preset input:focus-visible + span {
  outline: 2.5px solid var(--accent);
  outline-offset: 2px;
}
.custom-window {
  display: grid;
  gap: 0.2rem;
  padding: 1rem;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius);
  background: var(--bg-sunken);
}

.scan-log {
  list-style: none;
  padding: 0;
  display: grid;
  gap: 0.35rem;
  font-size: 0.87rem;
}
.scan-log li {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.scan-when {
  color: var(--text-soft);
  white-space: nowrap;
}
.scan-result {
  text-transform: capitalize;
}
.scan-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
  display: inline-block;
  background: var(--ink-300);
}
.scan-granted {
  background: var(--ok-fg);
}
.scan-expired,
.scan-revoked,
.scan-unknown {
  background: var(--err-fg);
}
.scan-not_yet_valid {
  background: var(--warn-fg);
}

@media print {
  .verdict,
  .pass-card {
    break-inside: avoid;
  }
  .pass-card {
    border: 1px solid #999;
  }
}

.pass-number {
  margin-top: 0.9rem;
  display: grid;
  gap: 0.1rem;
}
.pass-number span {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-soft);
}
.pass-number strong {
  font-size: 1.7rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  font-variant-numeric: tabular-nums;
}
.code-input {
  font-size: 1.8rem !important;
  letter-spacing: 0.25em;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   Council items register
   ==========================================================================
   Shares the pills, cards and thread styling with the votes and the board.
   What is new here is the sense of time: whether a thing is late, due soon or
   finished has to be readable at a glance down a list, and readable without
   relying on colour alone — hence the wording in each due label as well as
   its colour. */

.item-tabs {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.chip-n {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  opacity: 0.75;
  margin-left: 0.15rem;
}
.chip-late[aria-current='true'],
.chip-late.is-active {
  background: var(--err-bg);
  color: var(--err-fg);
  border-color: currentColor;
}

.filter-note {
  font-size: 0.9rem;
  color: var(--text-soft);
}

/* One row per item. Built on the same shape as .poll-row so the two council
   lists feel like one place, with a left border carrying the urgency. */
.item-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  justify-content: space-between;
  padding: 0.85rem 1.05rem;
  border: 1px solid var(--line);
  border-left: 3px solid transparent;
  border-radius: var(--radius);
  background: var(--bg-raised);
  text-decoration: none;
  transition: border-color 0.18s var(--ease), transform 0.18s var(--ease);
}
.item-row:hover {
  border-color: var(--brand);
  transform: translateX(2px);
  color: inherit;
}
.item-row.is-late {
  border-left-color: var(--err-fg);
}
/* A finished item stays legible but stops competing for attention. */
.item-row.is-done strong {
  color: var(--text-soft);
  font-weight: 600;
}
.item-row-main {
  display: grid;
  gap: 0.15rem;
  min-width: 0;
}
.item-row-side {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  justify-content: flex-end;
  flex: none;
}

.due {
  font-size: 0.78rem;
  color: var(--text-soft);
  white-space: nowrap;
}
.due-late {
  color: var(--err-fg);
  font-weight: 700;
}
.due-soon {
  color: var(--warn-fg);
  font-weight: 600;
}
.pri-high {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--brand);
}

/* The facts panel at the top of an item. */
.item-facts {
  display: grid;
  gap: 0.9rem 1.8rem;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  padding: 1.1rem 1.3rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-raised);
}
.item-facts dt {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-soft);
  margin-bottom: 0.2rem;
}
.item-facts dd {
  margin: 0;
  display: grid;
  gap: 0.1rem;
}

.item-detail,
.item-outcome {
  padding: 1.1rem 1.3rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-raised);
}
.item-outcome {
  border-color: color-mix(in oklab, var(--ok-fg) 35%, var(--line));
  background: var(--ok-bg);
  color: var(--ok-fg);
}
.item-outcome .eyebrow {
  margin-bottom: 0.3rem;
}

.item-move {
  display: grid;
  gap: 0.9rem;
  padding: 1.1rem 1.3rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-sunken);
}
.move-choices {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.move-choice {
  position: relative;
  display: inline-flex;
  align-items: center;
  padding: 0.45rem 0.95rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--bg-raised);
  font-size: 0.88rem;
  font-weight: 600;
  cursor: pointer;
}
/* The radio itself is laid over the label rather than hidden, so it stays
   reachable by a screen reader and by touch, and keyboard focus still lands
   somewhere visible. */
.move-choice input {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
  margin: 0;
}
.move-choice:has(input:checked) {
  border-color: var(--brand);
  background: var(--brand-soft);
  color: var(--brand);
}
.move-choice:has(input:focus-visible) {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

/* Meetings view. */
.meeting-block {
  display: grid;
  gap: 0.9rem;
  padding: 1.2rem 1.3rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-raised);
}
.meeting-head {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem;
  align-items: flex-end;
  justify-content: space-between;
}
.meeting-progress {
  display: grid;
  gap: 0.35rem;
  min-width: 11rem;
}
.bar-track {
  display: block;
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--bg-sunken);
  overflow: hidden;
}
.bar-fill {
  display: block;
  height: 100%;
  background: var(--brand);
  border-radius: inherit;
}
.meeting-note {
  color: var(--text-soft);
  font-size: 0.92rem;
}
.meeting-foot {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem;
  align-items: center;
  padding-top: 0.2rem;
}
.btn-link {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-size: 0.85rem;
  color: var(--text-soft);
  text-decoration: underline;
  cursor: pointer;
}
.btn-link:hover {
  color: var(--err-fg);
}

@media (max-width: 34rem) {
  /* On a phone the status and the date want their own line rather than being
     squeezed against the title. */
  .item-row {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.55rem;
  }
  .item-row-side {
    justify-content: flex-start;
  }
}

@media print {
  /* Printing the register is a real thing — it is the agenda for the meeting.
     The status-change and note forms are hidden by the general `form` rule
     above, which is right; the list itself must survive. */
  .item-row,
  .meeting-block,
  .item-facts {
    break-inside: avoid;
    border-color: #999;
  }
  .item-row {
    transform: none;
  }
}

/* A touch target of 40px is on the small side for a thumb; 44 is the usual
   floor and these are the buttons a councillor presses on a phone. */
@media (max-width: 34rem) {
  .move-choice {
    padding-block: 0.6rem;
  }
}

/* The registration honeypot. Moved off-screen rather than display:none —
   some bots deliberately skip fields that are hidden that way, and the whole
   point is that they fill this one in. It is also aria-hidden and
   tabindex="-1" in the markup, so neither a screen reader nor the Tab key
   ever reaches it. */
.hp {
  position: absolute;
  left: -9999px;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Delete sits next to Suspend on the owners table, and only one of the two can
   be undone. The outline .btn-danger is right for Suspend; deleting an account
   is final, so it is filled in — different enough that the hand does not reach
   for it by muscle memory. */
.btn-destroy {
  --btn-bg: var(--err-fg);
  --btn-fg: #fff;
  border-color: var(--err-fg);
  box-shadow: none;
}
.btn-destroy:hover {
  --btn-bg: color-mix(in oklab, var(--err-fg) 85%, #000);
  --btn-fg: #fff;
}

/* ==========================================================================
   Council items — the table view, attachments, and shared notes
   ==========================================================================
   The table is for a screen wide enough to read seven columns; below that the
   .item-cards rows take over. Both are in the HTML and CSS picks one, rather
   than JavaScript swapping them, so the page is right before any script runs
   and right if none ever does. */

.item-table-wrap {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-raised);
  overflow: hidden;
}
.item-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.93rem;
}
.item-table th,
.item-table td {
  padding: 0.7rem 0.9rem;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--line);
}
.item-table thead th {
  padding: 0;
  background: var(--bg-sunken);
  font-size: 0.7rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-soft);
  white-space: nowrap;
}
/* The whole heading is the control, so the hit area is the cell and not just
   the word. */
.item-table thead a.sort {
  display: block;
  padding: 0.65rem 0.9rem;
  color: inherit;
  text-decoration: none;
  font-weight: 700;
}
.item-table thead a.sort:hover {
  color: var(--brand);
  background: color-mix(in oklab, var(--brand) 7%, transparent);
}
.item-table thead a.sort.is-sorted {
  color: var(--brand);
}
.sort-arrow {
  font-weight: 400;
}
.item-table tbody tr:last-child th,
.item-table tbody tr:last-child td {
  border-bottom: 0;
}
.item-table tbody tr:hover {
  background: color-mix(in oklab, var(--brand) 4%, transparent);
}
/* The site has a global `th` rule — uppercase, letter-spaced, on a tinted
   ground — which is right for a column heading and wrong for a row heading.
   Every item title is a `th scope="row"` (it is what names the row, and a
   screen reader should say it before each cell), so all of that has to be
   undone here or the titles read as SHOUTED SMALL CAPS on a striped table. */
.item-table tbody th {
  font-size: inherit;
  font-weight: 600;
  letter-spacing: normal;
  text-transform: none;
  color: inherit;
  background: none;
  white-space: normal;
  max-width: 26rem;
}
/* Every column but the title holds a short, known value — a date, a name, a
   pill. Left to wrap they turn a one-line row into three, and a table whose
   rows are all different heights is harder to read down than the stacked cards
   it replaced. The title gets whatever width is left and wraps alone. */
.item-table td {
  white-space: nowrap;
}
/* `width:100%` is not enough on an auto-layout table: the nowrap columns claim
   their intrinsic width first and the only cell that CAN wrap gets squeezed to
   whatever is left, which was 113px — three lines per title. A floor on the
   title column is what actually reserves the space. */
.item-table tbody th {
  min-width: 17rem;
  width: 100%;
}
/* …except the name, which can be long and must be allowed to break. Wide
   enough that a name plus its "estate" tag takes two lines at most — at 7rem
   "Benoit Estate" became three, and a council of nine includes
   "Yudish Lutchmenarraidoo". */
.item-table td:nth-child(3) {
  white-space: normal;
  min-width: 11rem;
}
.item-table .status {
  white-space: nowrap;
}
/* A caption is not a row, but an sr-only caption that is not taken out of flow
   still reserves a band above the first one. Taken out of flow here, and only
   here, where there is no sideways-scrolling cell for it to drag open. */
.item-table caption.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.item-table tbody th a {
  text-decoration: none;
  color: inherit;
}
.item-table tbody th a:hover {
  color: var(--brand);
  text-decoration: underline;
}
.item-table .soft {
  color: var(--text-soft);
}
.item-table .num {
  text-align: right;
  white-space: nowrap;
}
.item-table tr.is-late th a {
  color: var(--err-fg);
}
.item-table tr.is-done th a,
.item-table tr.is-done td {
  color: var(--text-soft);
  font-weight: 400;
}

/* One or the other, never both. */
.item-cards {
  display: none;
}
@media (max-width: 68rem) {
  .item-table-wrap {
    display: none;
  }
  .item-cards {
    display: grid;
  }
}

/* A person who is not on the council — the syndic's estate manager, a
   contractor — wherever their name appears. */
.tag-ext {
  display: inline-block;
  margin-left: 0.35rem;
  padding: 0.05em 0.45em;
  border-radius: var(--radius-pill);
  background: var(--bg-sunken);
  color: var(--text-soft);
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  vertical-align: 0.1em;
}

/* ------------------------------------------------------------ attachments */

.item-files {
  display: grid;
  gap: 0.9rem;
  padding: 1.1rem 1.3rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-raised);
}
.file-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.4rem;
}
.file-row {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  justify-content: space-between;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm, 0.5rem);
  background: var(--bg);
}
.file-main {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  min-width: 0;
  text-decoration: none;
  color: inherit;
}
.file-main:hover strong {
  color: var(--brand);
  text-decoration: underline;
}
.file-main > span {
  display: grid;
  gap: 0.1rem;
  min-width: 0;
}
.file-main strong {
  overflow-wrap: anywhere;
}
.file-icon {
  font-size: 1.1rem;
  flex: none;
}
.file-note {
  font-size: 0.82rem;
  color: var(--text-soft);
}

/* --------------------------------------------------------- shared notes */

/* A note the council has chosen to show the assignee. Marked so that, reading
   down the thread, it is obvious which lines somebody outside the council can
   see — the whole point of the tick being off by default. */
.message-shared {
  border-color: color-mix(in oklab, var(--brand) 35%, var(--line));
}
.share-toggle {
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  padding: 0.1em 0.6em;
  font: inherit;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-soft);
  cursor: pointer;
}
.share-toggle.is-shared {
  border-color: color-mix(in oklab, var(--brand) 45%, transparent);
  background: var(--brand-soft);
  color: var(--brand);
}
.share-toggle:hover {
  border-color: var(--brand);
  color: var(--brand);
}
.share-tick {
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  font-size: 0.9rem;
  color: var(--text-soft);
  cursor: pointer;
}
.share-tick input {
  margin-top: 0.15rem;
  flex: none;
}

.item-handover {
  display: grid;
  gap: 0.9rem;
  padding: 1.1rem 1.3rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-raised);
}

@media print {
  /* The table is the agenda; print that rather than the phone cards, whatever
     the paper width works out to. */
  .item-table-wrap {
    display: block !important;
    border-color: #999;
  }
  .item-cards {
    display: none !important;
  }
  .item-table tbody tr {
    break-inside: avoid;
  }
  .item-files {
    break-inside: avoid;
  }
}
