/* Boston Township Zoning Department */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
    --navy:   #1a3558;
    --navy2:  #102240;
    --gold:   #b8860b;
    --gold2:  #f0c040;
    --light:  #f0f4f8;
    --border: #c8d4e0;
    --text:   #1e2a38;
    --muted:  #5a6878;
    --white:  #ffffff;
    --green:  #1a6e3a;
    --red:    #a01c1c;
    --orange: #8a4800;
}

body {
    font-family: 'Segoe UI', Arial, sans-serif;
    font-size: 16px;
    color: var(--text);
    background: #e8edf2;
    line-height: 1.6;
}

a { color: var(--navy); text-decoration: none; }
a:hover { text-decoration: underline; color: var(--gold); }

/* ── HEADER ── */
#site-header {
    background: var(--navy);
    color: var(--white);
    border-bottom: 4px solid var(--gold);
}
#site-header .header-inner {
    max-width: 1100px;
    margin: 0 auto;
    padding: 0 1.5rem;
    display: flex;
    align-items: center;
    gap: 1.25rem;
    min-height: 80px;
}
.site-seal {
    height: 70px; width: auto;
    flex-shrink: 0;
}
.site-title h1 { font-size: 1.3rem; font-weight: 700; letter-spacing: .02em; color: var(--white); }
.site-title p  { font-size: .8rem; color: #a0b8d0; margin-top: 1px; }

/* Header auth controls (login / logout), shown on the navy header bars */
.header-auth { margin-left: auto; display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.header-auth form { margin: 0; }
.header-user { color: #cddcec; font-size: .82rem; }
.header-btn {
    display: inline-block; padding: .4rem .85rem; border-radius: 4px;
    font-size: .82rem; font-weight: 600; line-height: 1; cursor: pointer; white-space: nowrap;
    background: rgba(255,255,255,.14); color: var(--white); border: 1px solid rgba(255,255,255,.45);
    text-decoration: none; font-family: inherit;
}
.header-btn:hover { background: rgba(255,255,255,.28); color: var(--white); }
.header-btn-solid { background: var(--gold); border-color: var(--gold); color: #22303f; }
.header-btn-solid:hover { background: #d8b24a; color: #22303f; }

/* ── NAV ── */
#site-nav {
    background: var(--navy2);
    border-bottom: 2px solid var(--gold);
}
#site-nav ul {
    max-width: 1100px;
    margin: 0 auto;
    padding: 0 1.5rem;
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 0;
}
#site-nav ul li a {
    display: block;
    padding: .65rem 1.1rem;
    color: #c8d8e8;
    font-size: .9rem;
    font-weight: 500;
    letter-spacing: .02em;
    text-decoration: none;
    transition: background .15s, color .15s;
}
#site-nav ul li a:hover,
#site-nav ul li a.active {
    background: var(--gold);
    color: var(--navy2);
}

/* ── MAIN WRAPPER ── */
#main-wrapper {
    max-width: 1100px;
    margin: 2rem auto;
    padding: 0 1.5rem;
}

/* ── PAGE HEADER ── */
.page-header {
    background: var(--white);
    border-left: 5px solid var(--gold);
    border-radius: 4px;
    padding: 1.25rem 1.5rem;
    margin-bottom: 1.5rem;
    box-shadow: 0 1px 4px rgba(0,0,0,.08);
}
.page-header h2 { font-size: 1.5rem; color: var(--navy); }
.page-header p  { color: var(--muted); margin-top: .25rem; font-size: .95rem; }

/* ── CARDS ── */
.card {
    background: var(--white);
    border-radius: 6px;
    box-shadow: 0 1px 4px rgba(0,0,0,.09);
    padding: 1.5rem;
    margin-bottom: 1.5rem;
}
.card h3 { color: var(--navy); font-size: 1.1rem; margin-bottom: 1rem; border-bottom: 1px solid var(--border); padding-bottom: .5rem; }

/* ── GRID ── */
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.25rem; }
.grid-3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1.25rem; }

/* ── HERO TILES (home page) ── */
.hero-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1.25rem; margin-bottom: 1.75rem; }
.hero-tile {
    background: var(--white);
    border-radius: 6px;
    box-shadow: 0 1px 4px rgba(0,0,0,.09);
    padding: 1.5rem 1.25rem;
    text-align: center;
    text-decoration: none;
    border-top: 4px solid var(--navy);
    transition: transform .15s, box-shadow .15s;
    display: block;
    color: var(--text);
}
.hero-tile:hover { transform: translateY(-3px); box-shadow: 0 4px 12px rgba(0,0,0,.15); text-decoration: none; }
.hero-tile .tile-icon { font-size: 2.2rem; margin-bottom: .75rem; }
.hero-tile h3 { font-size: 1rem; color: var(--navy); margin-bottom: .35rem; }
.hero-tile p  { font-size: .82rem; color: var(--muted); }

/* ── FORMS ── */
.form-group { margin-bottom: 1.1rem; }
.form-group label { display: block; font-weight: 600; margin-bottom: .35rem; font-size: .9rem; color: var(--navy); }
.form-group input[type=text],
.form-group input[type=email],
.form-group input[type=tel],
.form-group input[type=date],
.form-group input[type=number],
.form-group input[type=password],
.form-group input[type=file],
.form-group select,
.form-group textarea {
    width: 100%;
    padding: .55rem .75rem;
    border: 1px solid var(--border);
    border-radius: 4px;
    font-size: .95rem;
    font-family: inherit;
    background: var(--white);
    color: var(--text);
    transition: border-color .15s;
}
.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
    outline: none;
    border-color: var(--navy);
    box-shadow: 0 0 0 3px rgba(26,53,88,.12);
}
.form-group textarea { min-height: 100px; resize: vertical; }
.form-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; }
.form-hint { font-size: .8rem; color: var(--muted); margin-top: .25rem; }

/* ── BUTTONS ── */
.btn {
    display: inline-block;
    padding: .55rem 1.25rem;
    border-radius: 4px;
    font-size: .9rem;
    font-weight: 600;
    cursor: pointer;
    border: none;
    text-decoration: none;
    transition: background .15s, opacity .15s;
}
.btn-primary   { background: var(--navy);  color: var(--white); }
.btn-primary:hover   { background: var(--navy2); color: var(--white); text-decoration: none; }
.btn-secondary { background: var(--light); color: var(--navy);  border: 1px solid var(--border); }
.btn-secondary:hover { background: var(--border); text-decoration: none; }
.btn-gold      { background: var(--gold);  color: var(--white); }
.btn-gold:hover      { background: #956f08; color: var(--white); text-decoration: none; }
.btn-danger    { background: var(--red);   color: var(--white); }
.btn-danger:hover    { opacity: .85; text-decoration: none; }
.btn-sm { padding: .3rem .75rem; font-size: .82rem; }

/* ── ALERTS ── */
.alert { padding: .85rem 1.1rem; border-radius: 4px; margin-bottom: 1.25rem; font-size: .92rem; }
.alert-success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
.alert-error   { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
.alert-info    { background: #d1ecf1; color: #0c5460; border: 1px solid #bee5eb; }
.alert-warning { background: #fff3cd; color: #856404; border: 1px solid #ffeeba; }
/* Alerts banner (partials/alert-banner): message on the left, Dismiss on the right, stacked on a phone. */
.alert-banner { display: flex; align-items: flex-start; gap: 1rem; margin-bottom: .75rem; }
.alert-banner-body { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.alert-banner form { margin: 0; flex-shrink: 0; }
.alert-banner .form-hint { color: inherit; opacity: .8; }
@media (max-width: 600px) { .alert-banner { flex-direction: column; gap: .5rem; } }
/* Count of showing alerts beside the Alerts nav link. */
.nav-count { display: inline-block; min-width: 1.25rem; margin-left: .35rem; padding: 0 .35rem; border-radius: 999px; background: var(--red); color: var(--white); font-size: .72rem; font-weight: 700; line-height: 1.25rem; text-align: center; }

/* ── TABLES ── */
.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: .9rem; }
table th {
    background: var(--navy);
    color: var(--white);
    padding: .65rem .85rem;
    text-align: left;
    font-size: .82rem;
    letter-spacing: .04em;
    text-transform: uppercase;
}
table td { padding: .6rem .85rem; border-bottom: 1px solid var(--border); vertical-align: top; }
table tr:hover td { background: #f5f8fb; }
table tr:last-child td { border-bottom: none; }

/* ── STATUS BADGES ── */
.badge {
    display: inline-block;
    padding: .2rem .6rem;
    border-radius: 20px;
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .03em;
}
.badge-pending    { background: #fff3cd; color: #856404; }
.badge-review     { background: #d1ecf1; color: #0c5460; }
.badge-approved   { background: #d4edda; color: #155724; }
.badge-issued     { background: #cce5ff; color: #004085; }
.badge-denied     { background: #f8d7da; color: #721c24; }
.badge-incomplete { background: #ffe5d0; color: #8a4b1a; }
.badge-expired    { background: #e2e3e5; color: #383d41; }
.badge-completed  { background: #c3e6cb; color: #155724; }
.badge-revoked    { background: #f8d7da; color: #721c24; }
.badge-recommended   { background: #fff3cd; color: #856404; }
.badge-assessed      { background: #ffe0b2; color: #7a4a00; }
.badge-court-ordered { background: #d1ecf1; color: #0c5460; }
.badge-paid          { background: #d4edda; color: #155724; }
.badge-waived        { background: #e2e3e5; color: #383d41; }
.badge-lien-filed    { background: #e9d8fd; color: #553c9a; }
.badge-initiated              { background: #fff3cd; color: #856404; }
.badge-referred-to-county     { background: #d1ecf1; color: #0c5460; }
.badge-zc-hearing-scheduled   { background: #d1ecf1; color: #0c5460; }
.badge-zc-recommended         { background: #cce5ff; color: #004085; }
.badge-trustee-hearing-scheduled { background: #cce5ff; color: #004085; }
.badge-adopted    { background: #d4edda; color: #155724; }
.badge-effective  { background: #c3e6cb; color: #155724; }
.badge-withdrawn  { background: #e2e3e5; color: #383d41; }
/* Suggested amendments. Initiated and Adopted reuse the zoning-amendment
   badges above, since they mean the same thing at the same point. */
.badge-identified        { background: #e2e3e5; color: #383d41; }
.badge-under-review      { background: #d1ecf1; color: #0c5460; }
.badge-ready-to-initiate { background: #fff3cd; color: #856404; }
.badge-declined          { background: #f8d7da; color: #721c24; }
.badge-superseded        { background: #e9d8fd; color: #553c9a; }

.badge-notice-sent    { background: #fff3cd; color: #856404; }
.badge-abated         { background: #d1ecf1; color: #0c5460; }
.badge-billed         { background: #ffe0b2; color: #7a4a00; }
.badge-lien-requested { background: #e9d8fd; color: #553c9a; }
.badge-closed         { background: #c3e6cb; color: #155724; }
.badge-vote-aye     { background: #d4edda; color: #155724; }
.badge-vote-nay     { background: #f8d7da; color: #721c24; }
.badge-vote-abstain { background: #fff3cd; color: #856404; }
.badge-vote-absent  { background: #e2e3e5; color: #383d41; }
.badge-vote-recused { background: #e9d8fd; color: #553c9a; }

/* §908 variance process on the application form. The left rule carries the
   state so the sequence reads at a glance with every step collapsed, and
   .vp-here marks the step the file is actually on. */
.vp-list { list-style: none; margin: .3rem 0 .6rem; padding: 0; counter-reset: vp; }
.vp-step { counter-increment: vp; border-left: 3px solid #e2e3e5; padding: .35rem 0 .35rem .7rem; margin: 0; }
.vp-step summary { cursor: pointer; }
.vp-step summary::marker { color: var(--muted); }
.vp-step summary strong::before { content: counter(vp) ". "; color: var(--muted); font-weight: normal; }
.vp-step .badge { margin-left: .4rem; }
.vp-state-done      { border-left-color: #c3e6cb; }
.vp-state-current   { border-left-color: #0c5460; }
.vp-state-pending   { border-left-color: #e2e3e5; }
.vp-state-attention { border-left-color: #b3261e; }
.vp-here { background: #f7f9fc; }
.vp-badge-done      { background: #d4edda; color: #155724; }
.vp-badge-current   { background: #d1ecf1; color: #0c5460; }
.vp-badge-pending   { background: #e2e3e5; color: #383d41; }
.vp-badge-attention { background: #f8d7da; color: #721c24; }
.badge-role-admin  { background: #cce5ff; color: #004085; }
.badge-role-staff  { background: #d4edda; color: #155724; }
.badge-role-viewer { background: #e2e3e5; color: #383d41; }
.badge-submitted          { background: #fff3cd; color: #856404; }
.badge-inspector-reviewed { background: #d1ecf1; color: #0c5460; }
.badge-before-bza         { background: #cce5ff; color: #004085; }
.badge-decided            { background: #c3e6cb; color: #155724; }
.badge-business   { background: #cce5ff; color: #004085; }
.badge-residence  { background: #d4edda; color: #155724; }

/* ── SEARCH BAR ── */
.search-bar {
    display: flex;
    gap: .5rem;
    margin-bottom: 1.25rem;
}
.search-bar input { flex: 1; }
.search-bar select { width: auto; }

/* ── PAGINATION ── */
.pagination { display: flex; gap: .35rem; margin-top: 1rem; flex-wrap: wrap; }
.pagination a, .pagination span {
    padding: .35rem .7rem;
    border: 1px solid var(--border);
    border-radius: 4px;
    font-size: .85rem;
    text-decoration: none;
    color: var(--navy);
}
.pagination .current { background: var(--navy); color: var(--white); border-color: var(--navy); }
.pagination a:hover  { background: var(--light); }
.pagination svg { width: 1.1rem; height: 1.1rem; vertical-align: middle; }
.pagination a, .pagination span { display: inline-flex; align-items: center; }

/* ── FOOTER ── */
#site-footer {
    background: var(--navy2);
    color: #8aaac8;
    text-align: center;
    padding: 1.5rem;
    font-size: .82rem;
    margin-top: 3rem;
    border-top: 3px solid var(--gold);
}
#site-footer strong { color: var(--white); }

/* ── ADMIN ── */
.admin-body { background: #f0f2f5; }
/* Admin content is wider than the public site (1100px) so data tables fit
   without horizontal scrolling. Header/nav are already full-bleed. */
.admin-body #main-wrapper { max-width: 1500px; }
#admin-header {
    background: var(--navy);
    color: var(--white);
    padding: .85rem 1.5rem;
    display: flex;
    align-items: center;
    gap: 1rem;
}
#admin-header h1 { font-size: 1.15rem; font-weight: 700; color: var(--white); }
#admin-nav {
    background: var(--navy2);
    padding: .5rem 1.5rem;
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
    align-items: center;
    border-bottom: 2px solid var(--gold);
    /* Above the Leaflet controls on /admin/map (they sit at 800-1000) so an
       open dropdown is not painted over by the map it overlaps. Below the
       photo lightbox at 2000, which is meant to cover everything. */
    position: relative;
    z-index: 1200;
}
#admin-nav a { color: #a0b8d0; font-size: .88rem; text-decoration: none; padding: .3rem .6rem; border-radius: 3px; }
#admin-nav a:hover, #admin-nav a.active { background: var(--gold); color: var(--navy2); }
#admin-nav .nav-brand { color: var(--gold2); font-weight: 700; font-size: .95rem; margin-right: .5rem; }
#admin-nav .nav-spacer, #admin-nav .spacer { flex: 1; }

/* ── ADMIN NAV GROUPS ──
   A <details> per heading. Click and keyboard come from the element itself,
   which is why it is not a div: the nav has to work before main.js runs. */
.nav-group { position: relative; }
.nav-group > summary {
    display: flex;
    align-items: center;
    gap: .3rem;
    color: #a0b8d0;
    font-size: .88rem;
    padding: .3rem .6rem;
    border-radius: 3px;
    cursor: pointer;
    user-select: none;
    /* Both, because the default triangle is a list marker in Firefox and a
       pseudo-element in older WebKit. */
    list-style: none;
}
.nav-group > summary::-webkit-details-marker { display: none; }
.nav-group > summary::after { content: "\25BE"; font-size: .65em; opacity: .75; }
.nav-group[open] > summary::after { content: "\25B4"; }
.nav-group > summary:hover { background: rgba(255, 255, 255, .12); color: var(--white); }
.nav-group > summary:focus-visible { outline: 2px solid var(--gold2); outline-offset: 1px; }
/* The heading of the section the current page belongs to. Gold text rather
   than the gold fill a current link gets, so "the section I am in" and "the
   page I am on" stay distinguishable when both are visible. */
.nav-group.active > summary { color: var(--gold2); font-weight: 600; }
.nav-group[open] > summary { background: rgba(255, 255, 255, .12); }

.nav-menu {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 1;
    display: flex;
    flex-direction: column;
    min-width: 12rem;
    margin-top: .5rem;
    padding: .35rem;
    background: var(--navy2);
    border: 1px solid var(--gold);
    border-radius: 4px;
    box-shadow: 0 .4rem 1.2rem rgba(0, 0, 0, .45);
}
#admin-nav .nav-menu a { padding: .45rem .6rem; white-space: nowrap; }

/* ── PINNED PAGES ──
   A thinner, paler bar than the nav above it. It has to read as a shortcut
   to something already in the menu, not as a second row of menu. */
#admin-pins {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .4rem;
    padding: .3rem 1.5rem;
    background: var(--navy);
    border-bottom: 1px solid rgba(255, 255, 255, .12);
}
#admin-pins a {
    color: #8fa6bd;
    font-size: .82rem;
    text-decoration: none;
    padding: .2rem .55rem;
    border-radius: 3px;
}
#admin-pins a:hover { background: rgba(255, 255, 255, .12); color: var(--white); }
#admin-pins a.active { background: var(--gold); color: var(--navy2); }
#admin-pins a:focus-visible { outline: 2px solid var(--gold2); outline-offset: 1px; }
#admin-pins .pin-empty { font-style: italic; opacity: .65; }

/* The checkbox list on My Account. Columns rather than one long list, so the
   headings stay visible as the thing being chosen from. */
.pin-picker {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
    gap: .75rem;
    margin-bottom: .5rem;
}
.pin-picker fieldset { border: 1px solid var(--border); border-radius: 6px; padding: .5rem .7rem; margin: 0; }
.pin-picker legend { font-size: .78rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); padding: 0 .3rem; }
.pin-picker label { display: flex; align-items: center; gap: .45rem; font-weight: 400; padding: .22rem 0; cursor: pointer; }
.pin-picker input { margin: 0; }

.stat-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 1rem; margin-bottom: 1.5rem; }
.stat-card {
    background: var(--white);
    border-radius: 6px;
    padding: 1.25rem;
    text-align: center;
    box-shadow: 0 1px 4px rgba(0,0,0,.08);
    border-top: 3px solid var(--navy);
}
.stat-card .stat-num { font-size: 2rem; font-weight: 700; color: var(--navy); line-height: 1; }
.stat-card .stat-lbl { font-size: .8rem; color: var(--muted); margin-top: .25rem; }

.actions-bar { display: flex; gap: .5rem; align-items: center; margin-bottom: 1rem; flex-wrap: wrap; }
.actions-bar .spacer { flex: 1; }

/* Application wizard. Both the nav and the controls carry `hidden` in the
   markup and are revealed by script, so with JavaScript off the form stays one
   long page with no dead Next button on it. */
.wizard-nav { display: flex; flex-wrap: wrap; gap: .3rem; list-style: none; margin: 0 0 1rem; padding: 0; counter-reset: wizard-step; }
.wizard-nav li { counter-increment: wizard-step; flex: 1 1 8rem; padding: .45rem .6rem; font-size: .82rem; color: var(--muted);
                 background: var(--light); border: 1px solid var(--border); border-radius: 4px; cursor: pointer; white-space: nowrap;
                 overflow: hidden; text-overflow: ellipsis; }
.wizard-nav li::before { content: counter(wizard-step) ". "; font-weight: 600; }
.wizard-nav li.active { background: #cce5ff; color: #004085; border-color: #9ec9ff; font-weight: 600; }
.wizard-nav li.done { background: #d4edda; color: #155724; border-color: #b7dfc2; }
/* Tabs standing in as wizard steps on the new-certificate form. */
.tab-btn.done { color: #155724; }
.tab-btn.done::after { content: " \2713"; }
.wizard-controls { display: flex; gap: .5rem; align-items: center; margin-top: 1rem; flex-wrap: wrap; }
.wizard-controls .spacer { flex: 1; }
.static-field { padding: .4rem 0; font-weight: 600; }

/* result info text */
.result-count { font-size: .85rem; color: var(--muted); margin-bottom: .75rem; }

/* ── PERMIT DETAIL BLOCK ── */
.permit-detail dt { font-weight: 600; color: var(--navy); font-size: .85rem; }
.permit-detail dd { margin-bottom: .75rem; margin-left: 0; color: var(--text); }
.permit-detail { display: grid; grid-template-columns: max-content 1fr; gap: .25rem 1.5rem; }

/* ── ORDINANCE ── */
.ordinance-item { border-bottom: 1px solid var(--border); padding: 1rem 0; }
.ordinance-item:last-child { border-bottom: none; }
.ordinance-item h4 { color: var(--navy); margin-bottom: .25rem; }
.ordinance-item .meta { font-size: .8rem; color: var(--muted); margin-bottom: .4rem; }
.ordinance-content { font-size: .9rem; line-height: 1.7; white-space: pre-wrap; }

/* ── ZONING RESULT ── */
.zone-result { background: var(--light); border: 2px solid var(--navy); border-radius: 6px; padding: 1.25rem 1.5rem; margin-top: 1rem; }
.zone-result h3 { color: var(--navy); font-size: 1.2rem; }
.zone-result .zone-code { background: var(--navy); color: var(--white); display: inline-block; padding: .2rem .7rem; border-radius: 4px; font-size: .85rem; font-weight: 700; margin-bottom: .75rem; }
.zone-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: .75rem; margin-top: .75rem; }
.zone-spec { background: var(--white); border-radius: 4px; padding: .6rem .85rem; }
.zone-spec .spec-label { font-size: .75rem; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.zone-spec .spec-val { font-weight: 700; color: var(--navy); margin-top: .1rem; }

/* ── DIRECTORY ── */
.dir-card {
    background: var(--white);
    border-radius: 6px;
    padding: 1.1rem 1.25rem;
    border-left: 4px solid var(--navy);
    box-shadow: 0 1px 3px rgba(0,0,0,.07);
}
.dir-card h4 { color: var(--navy); margin-bottom: .3rem; font-size: 1rem; }
.dir-card .dir-meta { font-size: .82rem; color: var(--muted); margin-bottom: .35rem; }
.dir-card .dir-desc { font-size: .88rem; }
.dir-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1rem; margin-top: 1rem; }

/* ── STAFF ── */
.staff-card {
    background: var(--white);
    border-radius: 6px;
    padding: 1.25rem;
    box-shadow: 0 1px 4px rgba(0,0,0,.08);
    display: flex;
    gap: 1rem;
    align-items: flex-start;
}
.staff-avatar {
    width: 56px; height: 56px;
    border-radius: 50%;
    background: var(--navy);
    color: var(--white);
    display: flex; align-items: center; justify-content: center;
    font-size: 1.4rem;
    flex-shrink: 0;
}
.staff-card h4 { color: var(--navy); font-size: 1rem; margin-bottom: .15rem; }
.staff-card .staff-title { font-size: .85rem; color: var(--gold); font-weight: 600; margin-bottom: .35rem; }
.staff-card .staff-info { font-size: .83rem; color: var(--muted); line-height: 1.7; }
.staff-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 1.25rem; }

/* ── TABS ── */
/* wrap: the application form carries eight tabs, which overflow a laptop screen
   on one line. Public pages with three tabs are unaffected. */
.tabs { display: flex; flex-wrap: wrap; gap: 0; border-bottom: 2px solid var(--border); margin-bottom: 1.5rem; }
.tab-btn {
    padding: .6rem 1.25rem;
    background: none;
    border: none;
    border-bottom: 3px solid transparent;
    margin-bottom: -2px;
    font-size: .92rem;
    font-weight: 600;
    color: var(--muted);
    cursor: pointer;
    transition: color .15s, border-color .15s;
}
.tab-btn.active, .tab-btn:hover { color: var(--navy); border-bottom-color: var(--navy); }
.tab-pane { display: none; }
.tab-pane.active { display: block; }
/* Section tabs built by main.js from data-tabs panes. Until the script has run
   (or if it never does) every section shows, as the page did before tabs. */
.tab-container[data-tabs]:not(.tabs-ready) .tab-pane { display: block; }
.tab-container > .tabs { position: sticky; top: 0; z-index: 20; background: #f0f2f5; padding-top: .25rem; }
.tab-select-wrap, .tab-pager { display: none; }
/* A section's own first card sits right under the tab bar rather than a gap below it. */
.tab-container.tabs-ready .tab-pane > .card:first-child { margin-top: 0; }
@media (min-width: 701px) and (max-width: 1024px) {
    .tab-btn { padding: .75rem 1rem; }
}
@media (max-width: 700px) {
    .has-tab-select > .tabs { display: none; }
    .has-tab-select > .tab-select-wrap {
        display: block; position: sticky; top: 0; z-index: 20;
        background: #f0f2f5; padding: .5rem 0 .75rem; margin-bottom: .75rem;
        border-bottom: 2px solid var(--border);
    }
    .tab-select-wrap label { display: flex; align-items: center; gap: .5rem; font-weight: 600; color: var(--navy); margin: 0; }
    .tab-select-wrap .tab-select { flex: 1; min-height: 2.75rem; font-size: 1rem; font-weight: 600; }
    .tab-container.tabs-ready .tab-pager { display: flex; justify-content: space-between; gap: .5rem; margin: 1rem 0 .5rem; }
    .tab-pager .tab-pager-next { margin-left: auto; }
    .tab-pager .btn { min-height: 2.5rem; }
}

/* ── FORMS & DOWNLOADS ── */
.form-downloads { display: flex; flex-direction: column; gap: .75rem; margin-top: .75rem; }
.form-download-item {
    display: flex;
    align-items: center;
    gap: 1rem;
    background: var(--light);
    border-radius: 6px;
    padding: .9rem 1.1rem;
    border: 1px solid var(--border);
}
.form-download-icon { font-size: 2rem; flex-shrink: 0; }
.form-download-body { flex: 1; min-width: 0; }
.form-download-title { display: block; color: var(--navy); font-size: .97rem; margin-bottom: .2rem; }
.form-download-desc { font-size: .85rem; color: var(--text); margin: .2rem 0 .25rem; }
.form-download-meta { font-size: .78rem; color: var(--muted); }
.form-download-action { flex-shrink: 0; }

/* badge colours for form categories */
.badge-commercial { background: #dbeafe; color: #1e40af; }
.badge-residential { background: #dcfce7; color: #166534; }
.badge-general     { background: #f3f4f6; color: #374151; }

/* ── MISC ── */
.text-muted { color: var(--muted); }
.text-center { text-align: center; }
.mt-1 { margin-top: .5rem; }
.mt-2 { margin-top: 1rem; }
.mt-3 { margin-top: 1.5rem; }
.mb-1 { margin-bottom: .5rem; }
.mb-2 { margin-bottom: 1rem; }
.empty-state { text-align: center; padding: 3rem 1rem; color: var(--muted); }
.empty-state .empty-icon { font-size: 3rem; margin-bottom: 1rem; }
hr { border: none; border-top: 1px solid var(--border); margin: 1.25rem 0; }

/* ── SHARED FORM COMPONENTS ──
   Extracted 2026-08-24 from inline styles repeated through the application
   form. They looked identical on desktop, but each copy needed its own mobile
   fix; as classes they get one. */

/* Every GET search/filter form in the admin: a search box and a button, or ten
   controls across the top of a list. Two views already carried class
   "filter-bar" with nothing defining it, so they rendered unstyled -- this is
   that class, finally written. */
.filter-bar,
.inline-form { display: flex; gap: .4rem; align-items: center; flex-wrap: wrap; }
.filter-bar input[type=text],
.filter-bar input[type=search] { flex: 1 1 12rem; min-width: 0; }
.filter-bar input, .filter-bar select {
    padding: .35rem .65rem;
    font-size: .88rem;
    border: 1px solid var(--border);
    border-radius: 4px;
    font-family: inherit;
    background: var(--white);
    color: var(--text);
}
.filter-bar input[type=date] { padding: .25rem .4rem; font-size: .82rem; }
.filter-bar .btn { flex: 0 0 auto; }

/* A labelled pair of inputs -- App# from/to, Date from/to -- kept together. */
.filter-group { display: inline-flex; align-items: center; gap: .25rem; font-size: .8rem; }
.filter-num { width: 5.5rem; }

/* A record on the left, the action that applies to it on the right. */
.list-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: .5rem;
    padding: .35rem 0;
    border-bottom: 1px solid var(--border);
}
.list-row form { margin: 0; }

/* A form-group holding only a button, sitting level with the field beside it. */
.form-group-btn { display: flex; align-items: flex-end; }

/* The Save/Cancel footer repeated on every tab of the application form. */
.save-bar {
    border-top: 1px solid var(--border);
    padding-top: 1rem;
    display: flex;
    gap: .5rem;
    align-items: center;
    flex-wrap: wrap;
}

/* ══════════════════════════════════════════════════════════════════════════
   RESPONSIVE / MOBILE  (added 2026-08-24)

   Everything above this line applies at every width. These rules apply only
   below a width threshold or on a touch device, so a desktop browser renders
   what it rendered before.

   Breakpoints, and why these two:
     900px — the admin nav carries ~32 links. It stops fitting on one or two
             rows well before phone width, so it collapses to a drawer here,
             which also covers tablets in portrait.
     700px — data tables stop being tables and become stacked cards, and
             multi-column grids drop to one column.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── ADMIN NAV DRAWER ──
   CSS-only toggle: a hidden checkbox before the nav, with a label as the
   button. Works with JavaScript disabled, which matters because the nav is the
   only way to reach any other admin page. main.js adds keyboard support. */
.nav-toggle { display: none; }
.nav-toggle-input { display: none; }

@media (max-width: 900px) {
    #admin-header { flex-wrap: wrap; padding: .7rem 1rem; gap: .6rem; }
    #admin-header h1 { font-size: 1rem; flex: 1 1 auto; min-width: 0; }
    .header-auth { margin-left: auto; }

    .nav-toggle {
        display: flex;
        align-items: center;
        gap: .5rem;
        background: var(--navy2);
        color: var(--gold2);
        border-bottom: 2px solid var(--gold);
        padding: .75rem 1rem;
        font-size: .95rem;
        font-weight: 600;
        cursor: pointer;
        user-select: none;
        min-height: 44px;
    }
    .nav-toggle::before { content: "\2630"; font-size: 1.15rem; line-height: 1; }
    .nav-toggle-input:checked ~ .nav-toggle::before { content: "\2715"; }
    .nav-toggle:focus-visible { outline: 2px solid var(--gold2); outline-offset: -4px; }

    #admin-nav {
        display: none;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        padding: 0 .5rem .5rem;
        max-height: 70vh;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
    }
    .nav-toggle-input:checked ~ #admin-nav { display: flex; }
    #admin-nav a {
        padding: .8rem .75rem;
        font-size: .95rem;
        border-radius: 0;
        border-bottom: 1px solid rgba(255,255,255,.08);
    }
    #admin-nav a:last-child { border-bottom: none; }
    #admin-nav .nav-spacer, #admin-nav .spacer { display: none; }

    /* In the drawer a group is an accordion section, not a dropdown: the
       submenu sits in the flow and indents, so the list reads as nine rows
       that open rather than thirty-four to scroll past. */
    .nav-group { position: static; border-bottom: 1px solid rgba(255, 255, 255, .08); }
    .nav-group:last-child { border-bottom: none; }
    .nav-group > summary {
        padding: .8rem .75rem;
        font-size: .95rem;
        min-height: 44px;
        border-radius: 0;
    }
    .nav-group > summary::after { margin-left: auto; }
    .nav-menu {
        position: static;
        min-width: 0;
        margin: 0;
        padding: 0 0 .4rem .75rem;
        background: none;
        border: none;
        border-radius: 0;
        box-shadow: none;
    }
    #admin-nav .nav-menu a {
        padding: .7rem .75rem;
        border-bottom: none;
        white-space: normal;
    }

    /* One line that scrolls sideways, not a block that wraps: eight pins
       stacked would push the page down further than the drawer they are
       meant to save. */
    #admin-pins {
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        padding: .35rem .75rem;
    }
    #admin-pins a { white-space: nowrap; padding: .35rem .6rem; }
}

/* ── PUBLIC HEADER (the login page lives here, so it has to work on a phone) ── */
@media (max-width: 700px) {
    #site-header .header-inner { padding: .75rem 1rem; min-height: 0; flex-wrap: wrap; gap: .75rem; }
    .site-seal { height: 48px; }
    .site-title h1 { font-size: 1.05rem; }
    #site-nav ul { padding: 0 .5rem; }
    #site-nav ul li a { padding: .6rem .8rem; font-size: .88rem; }
}

/* ── LAYOUT ── */
@media (max-width: 700px) {
    #main-wrapper { margin: 1rem auto; padding: 0 .75rem; }
    .page-header { padding: 1rem; margin-bottom: 1rem; }
    .page-header h2 { font-size: 1.25rem; }
    .card { padding: 1rem; margin-bottom: 1rem; }

    /* Multi-column grids collapse. Each of these is auto-fit/auto-fill with a
       px minimum, which does NOT collapse on its own — a 320px minimum in a
       300px container overflows the viewport rather than reflowing. */
    .grid-2, .grid-3, .hero-tiles, .form-row,
    .zone-grid, .dir-grid, .staff-grid { grid-template-columns: 1fr; }
    /* Stat tiles read fine two-up on a phone and halve the scrolling. */
    .stat-cards { grid-template-columns: repeat(2, 1fr); gap: .75rem; }
    .stat-card { padding: .9rem .5rem; }
    .stat-card .stat-num { font-size: 1.5rem; }

    .permit-detail { grid-template-columns: 1fr; gap: 0; }
    .permit-detail dt { margin-top: .6rem; }

    .search-bar { flex-direction: column; align-items: stretch; }
    .search-bar select { width: 100%; }

    .form-download-item { flex-wrap: wrap; gap: .6rem; }
    .form-download-action { flex-basis: 100%; }
}

/* ── TABS AND WIZARD STEPS ──
   The application form carries eight tabs. Wrapping them costs four rows of a
   phone screen before any content, so they become one swipeable strip. */
@media (max-width: 700px) {
    .tabs, .wizard-nav {
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }
    .tabs::-webkit-scrollbar, .wizard-nav::-webkit-scrollbar { display: none; }
    .tab-btn { flex: 0 0 auto; padding: .7rem .9rem; font-size: .88rem; }
    .wizard-nav li { flex: 0 0 auto; }
    .wizard-controls { flex-wrap: wrap; }
    .wizard-controls .spacer { display: none; }
}

/* ── TABLES BECOME CARDS ──
   Below 700px a table stops being a grid and each row becomes a labelled
   card. The labels come from the header cells, copied onto every td as
   data-label by main.js — so this works on all admin tables without touching
   65 Blade templates, and a table added later is covered automatically.
   Without JavaScript the rules below still apply but labels are absent, so
   .table-wrap keeps its horizontal scroll as the fallback. */
@media (max-width: 700px) {
    .table-wrap.is-stacked table,
    .table-wrap.is-stacked tbody,
    .table-wrap.is-stacked tr,
    .table-wrap.is-stacked td { display: block; width: 100%; }

    /* Header row is removed from view but left for screen readers. */
    .table-wrap.is-stacked thead {
        position: absolute;
        width: 1px; height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
    }

    .table-wrap.is-stacked tr {
        background: var(--white);
        border: 1px solid var(--border);
        border-radius: 6px;
        margin-bottom: .8rem;
        box-shadow: 0 1px 3px rgba(0,0,0,.06);
        overflow: hidden;
    }
    .table-wrap.is-stacked tr:hover td { background: transparent; }

    .table-wrap.is-stacked td {
        display: grid;
        grid-template-columns: 7.5rem 1fr;
        gap: .5rem 1rem;
        align-items: start;
        padding: .55rem .8rem;
        border-bottom: 1px solid var(--light);
        font-size: .92rem;
    }
    .table-wrap.is-stacked td:last-child { border-bottom: none; }
    .table-wrap.is-stacked td::before {
        content: attr(data-label);
        font-weight: 700;
        font-size: .72rem;
        line-height: 1.5;
        color: var(--muted);
        text-transform: uppercase;
        letter-spacing: .04em;
    }

    /* Cells the row can do without on a phone: nothing on either side of the
       label. Hiding them is what keeps a ten-column row down to a readable
       card. main.js marks them, because :empty does not match a cell holding
       only Blade whitespace. */
    .table-wrap.is-stacked td[data-empty] { display: none; }

    /* H is a single tick marking a historical record -- not worth a line of a
       phone screen, and still on the record itself. Cert # is deliberately NOT
       here: when it holds a number that number is a link to the signed or
       scanned PDF, and when it is blank the cell is hidden already by the
       empty-cell rule below. Scoped to .admin-body so the public certificate
       list is untouched. */
    .admin-body .table-wrap.is-stacked td[data-label="H"] { display: none; }

    /* A column with a blank <th> -- the action columns across a dozen admin
       views are written that way -- has no label to show. Without this the
       cell still reserves the 7.5rem label column and prints nothing in it. */
    .table-wrap.is-stacked td:not([data-label]) { grid-template-columns: 1fr; }
    .table-wrap.is-stacked td:not([data-label])::before { display: none; }

    /* An action cell is buttons, not a value — it gets the full width and the
       label is redundant next to a button that says Edit. */
    .table-wrap.is-stacked td.cell-actions {
        display: flex;
        flex-wrap: wrap;
        gap: .4rem;
        background: var(--light);
        padding: .6rem .8rem;
    }
    .table-wrap.is-stacked td.cell-actions::before { display: none; }
    .table-wrap.is-stacked td.cell-actions .btn { flex: 1 1 auto; text-align: center; }
    .table-wrap.is-stacked td.cell-actions form { display: inline-flex; flex: 1 1 auto; }
    .table-wrap.is-stacked td.cell-actions form .btn { width: 100%; }

    /* The first cell is usually the record's identifier — make it the title. */
    .table-wrap.is-stacked td.cell-primary {
        grid-template-columns: 1fr;
        background: var(--navy);
        padding: .6rem .8rem;
        font-size: 1rem;
        font-weight: 700;
    }
    .table-wrap.is-stacked td.cell-primary::before {
        color: #a0b8d0;
        font-size: .68rem;
        margin-bottom: -.35rem;
    }
    .table-wrap.is-stacked td.cell-primary,
    .table-wrap.is-stacked td.cell-primary a { color: var(--white); }
}

/* ── TOUCH TARGETS ──
   Scoped to touch pointers, so a desktop mouse keeps the compact original
   sizing. 44px is the accessible minimum for a tap target. */
@media (hover: none) and (pointer: coarse) {
    .btn {
        min-height: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        padding: .6rem 1.25rem;
    }
    .btn-sm { min-height: 38px; padding: .45rem .9rem; }
    .header-btn { min-height: 38px; display: inline-flex; align-items: center; }

    .pagination a, .pagination span { min-height: 42px; min-width: 42px; justify-content: center; }

    /* 16px is the threshold below which iOS Safari zooms the page on focus,
       which then leaves the user scrolled sideways on a form they were typing
       into. !important is deliberate: many admin filter controls carry an
       inline font-size, and an inline style wins over a plain rule. Each of
       those inline styles is worth removing on its own; this stops the
       symptom everywhere in the meantime. */
    input, select, textarea,
    .form-group input, .form-group select, .form-group textarea { font-size: 16px !important; }
    input[type=date] { min-height: 42px; }
    .form-group textarea { min-height: 120px; }
}

/* ── ACTION BARS ── */
@media (max-width: 700px) {
    .actions-bar { gap: .4rem; }
    .actions-bar .spacer { display: none; }
    .actions-bar > form { width: 100%; }
    .actions-bar > .btn { flex: 1 1 auto; text-align: center; }
}

/* The Filters button exists only at phone widths. */
.filter-toggle { display: none; }

/* ── SHARED FORM COMPONENTS ON A PHONE ── */
@media (max-width: 700px) {
    /* Ten filter controls in a row become ten full-width controls stacked --
       each one tappable, and the whole thing collapsed behind a Filters button
       (see main.js) so it does not bury the list it filters. */
    .filter-bar, .inline-form { flex-direction: column; align-items: stretch; }
    .inline-form > *, .inline-form input, .inline-form .btn { width: 100%; }
    .filter-bar > *, .filter-bar input, .filter-bar select { width: 100%; }
    .filter-bar .btn { width: 100%; }
    .filter-group { display: flex; width: 100%; }
    .filter-group .filter-num,
    .filter-group input[type=date] { flex: 1 1 0; width: auto; min-width: 0; }

    /* Collapsed by default on a phone; main.js adds the button and the class. */
    .filter-bar.is-collapsed { display: none; }
    .filter-toggle { display: flex; width: 100%; justify-content: space-between; }
    .filter-toggle .filter-count {
        background: var(--gold); color: var(--navy2);
        border-radius: 20px; padding: 0 .5rem;
        font-size: .78rem; font-weight: 700;
    }

    /* A parcel description and an Unlink button do not share 375px. The
       action drops below the text it applies to. */
    .list-row { flex-wrap: wrap; align-items: flex-start; padding: .6rem 0; }
    .list-row > span { flex: 1 1 100%; }
    .list-row form, .list-row .btn { margin-left: auto; }

    .form-group-btn { align-items: stretch; }
    .form-group-btn .btn { width: 100%; }

    /* The save bar sticks to the bottom of the screen. The application form is
       eight tabs of fields; without this, saving from the middle of one means
       scrolling to the end of it to find the button, on every save. The
       negative margins let it span the card's padding, so it reads as a bar
       rather than a floating button. */
    .save-bar {
        position: sticky;
        bottom: 0;
        z-index: 20;
        background: var(--white);
        margin: 1rem -1rem 0;
        padding: .7rem 1rem;
        border-top: 1px solid var(--border);
        box-shadow: 0 -2px 8px rgba(0,0,0,.10);
    }
    .save-bar .btn { flex: 1 1 auto; }
    .save-bar .form-hint { flex: 1 1 100%; }
}

/* ── LABEL/VALUE TABLES ──
   A two-column table of long values -- the signature attestation block on the
   application form -- has no header row for the stacking logic to label from,
   and squeezing a sentence into half of 375px is unreadable. The value moves
   under its label instead. */
@media (max-width: 700px) {
    .table-label-value,
    .table-label-value tbody,
    .table-label-value tr,
    .table-label-value td { display: block; width: 100%; }
    .table-label-value tr {
        padding: .5rem 0;
        border-bottom: 1px solid var(--border);
    }
    .table-label-value tr:last-child { border-bottom: none; }
    .table-label-value td { border: none; padding: .1rem 0; }
    .table-label-value td:first-child { color: var(--navy); }
    .table-label-value tr:hover td { background: transparent; }
}

/* ── LOGIN BOX ──
   The auth layout sizes itself (max-width 360px, width 100%), so it already
   fits a phone -- but the body it centres in has no padding, leaving the card
   flush against both edges at 375px. `html body` outranks the layout's own
   inline <style>, which is loaded after this file and would otherwise win. */
@media (max-width: 700px) {
    html body { padding: 1rem; }
    .login-box { padding: 1.5rem 1.25rem; }
}

/* ── ISSUE ROWS ──
   The issues list on the application form: one card per matter the application
   covers, with its type, its certificate number once issued, and its own fee
   from the schedule on the header line. */
.item-row {
    border: 1px solid var(--border);
    border-left: 4px solid var(--navy);
    border-radius: 6px;
    padding: .85rem 1rem .4rem;
    margin-bottom: .7rem;
    background: var(--white);
}
.item-row-head {
    display: flex;
    align-items: center;
    gap: .6rem;
    flex-wrap: wrap;
    margin-bottom: .6rem;
    padding-bottom: .5rem;
    border-bottom: 1px solid var(--light);
}
.item-row-head .spacer { flex: 1; }
.item-type { font-weight: 700; color: var(--navy); padding: .35rem .5rem; border: 1px solid var(--border); border-radius: 4px; background: var(--white); max-width: 22rem; }
.item-certno { font-size: .82rem; font-weight: 600; color: var(--navy); background: var(--light); border-radius: 3px; padding: .2rem .45rem; }
.item-fee { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--navy); }
.item-fee-unpriced { color: #856404; background: #fff3cd; border-radius: 3px; padding: .1rem .4rem; }
.item-unit { font-weight: normal; color: var(--muted); }
.item-total {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    border-top: 2px solid var(--border);
    padding: .6rem .2rem .2rem;
    font-variant-numeric: tabular-nums;
}
.item-total strong { font-size: 1.05rem; color: var(--navy); }

@media (max-width: 700px) {
    .item-row { padding: .75rem .75rem .25rem; }
    .item-row-head { gap: .4rem; }
    .item-row-head .spacer { display: none; }
    .item-type { max-width: none; flex: 1 1 100%; }
    .item-remove { margin-left: auto; }
}

/* ── PARTY ROWS ──
   The parties list on the application form: one card per party, with its role,
   whether it applied, and who it acted for on the header line. */
.party-row {
    border: 1px solid var(--border);
    border-left: 4px solid var(--navy);
    border-radius: 6px;
    padding: .85rem 1rem .4rem;
    margin-bottom: .9rem;
    background: var(--white);
}
.party-row-head {
    display: flex;
    align-items: center;
    gap: .6rem;
    flex-wrap: wrap;
    margin-bottom: .6rem;
    padding-bottom: .5rem;
    border-bottom: 1px solid var(--light);
}
.party-row-head .spacer { flex: 1; }
.owners-list .owner-add { margin: .1rem 0 .6rem; }
/* A work or business number with its Ext. box (main.js, data-phone-ext). */
.phone-with-ext { display: flex; gap: .4rem; }
.phone-with-ext input[type=tel] { flex: 1; min-width: 0; }
.phone-with-ext .phone-ext { width: 5.5rem; flex: none; }
.party-role { font-weight: 700; color: var(--navy); padding: .35rem .5rem; border: 1px solid var(--border); border-radius: 4px; background: var(--white); }
.party-applied, .party-acting { display: inline-flex; align-items: center; gap: .35rem; font-size: .85rem; color: var(--muted); }
.party-applied { font-weight: 600; color: var(--navy); }
.party-acting select { padding: .3rem .4rem; font-size: .82rem; border: 1px solid var(--border); border-radius: 4px; max-width: 16rem; }
/* The row that applied is the one people look for first. */
.party-row:has(.party-applied input:checked) { border-left-color: var(--gold); background: #fffdf7; }

@media (max-width: 700px) {
    .party-row { padding: .75rem .75rem .25rem; }
    .party-row-head { gap: .4rem; }
    .party-row-head .spacer { display: none; }
    .party-acting { flex: 1 1 100%; }
    .party-acting select { max-width: none; flex: 1; }
    .party-remove { margin-left: auto; }
}

/* ── SITE PHOTOS ──
   The grid on the field capture screen and in the photo card on parcels and
   applications. auto-fill with a minimum tile keeps one column on a phone held
   in portrait and four or five on a desk monitor without a breakpoint. */
.photo-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: .75rem;
    margin-top: .75rem;
}
.photo-tile {
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow: hidden;
    background: var(--white);
    display: flex;
    flex-direction: column;
}
.photo-tile a.photo-link { display: block; line-height: 0; background: var(--light); }
.photo-tile img {
    width: 100%;
    /* Fixed box, cropped fill: site photos arrive in both orientations and a
       ragged grid is much harder to scan than a cropped one. The full frame is
       one tap away. */
    aspect-ratio: 4 / 3;
    object-fit: cover;
    display: block;
}
.photo-meta { padding: .45rem .55rem; font-size: .78rem; line-height: 1.35; }
.photo-meta strong { display: block; font-weight: 600; word-break: break-word; }
.photo-meta .photo-source { color: var(--muted); }
.photo-missing {
    aspect-ratio: 4 / 3;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: .5rem;
    font-size: .78rem;
    color: #c0392b;
    background: #fdf3f2;
}

/* ── PHOTO LIGHTBOX ──
   Without JavaScript a tile links straight at the full image, which is correct
   and stays that way. With it, a grid becomes a set you page through in place:
   a site visit is eight or nine frames and Back-then-tap between each one is
   the wrong way to look at them. Chrome on the phone is the target, so the
   controls sit at the bottom where a thumb already is, not in the corners. */
.lightbox {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    flex-direction: column;
    background: rgba(0, 0, 0, .93);
}
.lightbox[hidden] { display: none; }
/* The page behind must not scroll under the overlay on a phone. */
body.lightbox-open { overflow: hidden; }
.lightbox-head,
.lightbox-foot {
    flex: none;
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .6rem .9rem;
    color: var(--white);
}
.lightbox-head { border-bottom: 1px solid rgba(255, 255, 255, .15); }
.lightbox-foot { border-top: 1px solid rgba(255, 255, 255, .15); justify-content: center; }
.lightbox-caption { min-width: 0; }
.lightbox-caption strong { display: block; font-size: 1rem; word-break: break-word; }
.lightbox-caption span { font-size: .82rem; opacity: .75; }
.lightbox-close {
    margin-left: auto;
    flex: none;
    background: none;
    border: 0;
    color: var(--white);
    font-size: 2rem;
    line-height: 1;
    padding: 0 .4rem;
    cursor: pointer;
}
/* min-height:0 lets the image shrink inside the flex column instead of
   pushing the controls off the bottom of a landscape phone. */
.lightbox-stage {
    flex: 1;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: .5rem;
}
.lightbox-stage img { max-width: 100%; max-height: 100%; object-fit: contain; }
.lightbox-step {
    background: var(--white);
    color: var(--navy);
    border: 0;
    border-radius: 6px;
    /* Thumb-sized on purpose: used one-handed, outdoors, sometimes in gloves. */
    padding: .7rem 1.4rem;
    font-size: 1rem;
    font-weight: 700;
    cursor: pointer;
}
.lightbox-step[disabled] { opacity: .35; cursor: default; }
.lightbox-count { min-width: 5.5rem; text-align: center; font-size: .9rem; opacity: .8; }

/* ── FIELD CAPTURE ──
   Sized for one hand outdoors: a full-width capture control that is obviously
   a button, and job rows big enough to hit without looking. */
.capture-drop {
    display: block;
    border: 2px dashed var(--border);
    border-radius: 8px;
    padding: 1.5rem 1rem;
    text-align: center;
    background: var(--light);
    cursor: pointer;
}
.capture-drop:hover { border-color: var(--navy); }
.capture-drop .capture-icon { font-size: 2rem; line-height: 1; }
.capture-drop .capture-label { display: block; font-weight: 700; color: var(--navy); margin-top: .35rem; }
.capture-drop .capture-hint { display: block; font-size: .82rem; color: var(--muted); margin-top: .2rem; }
.capture-drop input[type=file] { display: none; }

/* Take Photo buttons from data-camera (main.js). Beside a file input they sit
   under it; a mouse-and-keyboard computer has no camera to open, so they are
   hidden there and the input alone is shown. */
input[type=file] + .btn-camera { display: inline-block; margin-top: .4rem; }
.capture-camera { margin-bottom: .75rem; }
.capture-camera .btn-camera { display: block; width: 100%; padding: 1rem; font-size: 1.1rem; }
@media (hover: hover) and (pointer: fine) {
    .btn-camera { display: none !important; }
}

.job-row {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .8rem .25rem;
    border-bottom: 1px solid var(--light);
    text-decoration: none;
    color: inherit;
}
.job-row:last-child { border-bottom: 0; }
.job-row:hover { background: var(--light); }
.job-row .job-main { flex: 1; min-width: 0; }
.job-row .job-main strong { display: block; }
.job-row .job-sub { font-size: .82rem; color: var(--muted); }
.job-row .job-count { font-size: .82rem; color: var(--muted); white-space: nowrap; }

@media (max-width: 700px) {
    .photo-grid { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: .5rem; }
    .capture-drop { padding: 2rem 1rem; }
    /* Prev and Next split the width so neither needs aiming for. */
    .lightbox-step { flex: 1; padding: .8rem .5rem; }
    .lightbox-count { min-width: 0; }
}

/* ── TOWNSHIP SITE ──
   www.bostontownship-oh.gov (layouts/township). Shares the zoning site's header,
   nav and cards so the two read as one township; these rules are only what the
   calendar and content pages add. */
.township-search input {
    padding: .38rem .6rem; border-radius: 4px; border: 1px solid rgba(255,255,255,.45);
    background: rgba(255,255,255,.12); color: var(--white); font: inherit; font-size: .85rem; width: 12rem;
}
.township-search input::placeholder { color: #b8cadc; }
.township-footer-grid { max-width: 1100px; margin: 0 auto; display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: .75rem 1.5rem; text-align: left; }
.township-footer a { color: #cddcec; text-decoration: underline; }
.township-next { padding: .55rem 0; border-bottom: 1px solid var(--border); }
.township-next:last-of-type { border-bottom: none; }
.township-next-body { font-weight: 600; color: var(--navy); font-size: .9rem; }
.township-event-list { list-style: none; }
.township-event-list li { padding: .4rem 0; border-bottom: 1px solid var(--border); display: flex; gap: .6rem; flex-wrap: wrap; align-items: baseline; }
.township-event-list li:last-child { border-bottom: none; }
.township-event-date { font-weight: 700; color: var(--navy); min-width: 3.5rem; }
.township-notices { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 1rem; }
.township-notice h4 { font-size: 1rem; margin-bottom: .2rem; }
.township-notice p { color: var(--muted); font-size: .88rem; }
.township-columns { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 1.25rem; align-items: start; }
.township-columns > :only-child { grid-column: 1 / -1; }
.township-page-card { display: block; color: var(--text); }
.township-page-card:hover { text-decoration: none; box-shadow: 0 3px 10px rgba(0,0,0,.14); }
.township-page-card h3 { margin-bottom: .35rem; }
.township-page-card p { color: var(--muted); font-size: .9rem; }
.township-link-list { list-style: none; }
.township-link-list li { padding: .3rem 0; border-bottom: 1px solid var(--light); font-size: .92rem; }
.township-link-list li:last-child { border-bottom: none; }
.township-crumb { font-size: .82rem; text-transform: uppercase; letter-spacing: .06em; margin: 0 0 .2rem !important; }
.township-content { overflow-wrap: anywhere; }
.township-content h2, .township-content h3, .township-content h4, .township-content h5 { color: var(--navy); margin: 1.4rem 0 .5rem; }
.township-content h2:first-child, .township-content h3:first-child { margin-top: 0; }
.township-content p, .township-content ul, .township-content ol, .township-content table, .township-content blockquote { margin-bottom: .9rem; }
.township-content ul, .township-content ol { padding-left: 1.4rem; }
.township-content img { max-width: 100%; height: auto; border-radius: 4px; margin: .4rem 0; }
.township-content iframe { max-width: 100%; border: 0; }
.township-content blockquote { border-left: 4px solid var(--gold); padding-left: 1rem; color: var(--muted); }
.township-content a { text-decoration: underline; }
.township-content { display: flow-root; }
.township-content table td, .township-content table th { border: 1px solid var(--border); }
.township-content s { color: var(--muted); }

/* Page editor blocks: the only classes App\Support\SafeHtml keeps. They style the
   public page and, because the editor's writing area carries .township-content,
   the editor too, so what staff see while writing is what visitors get. */
.township-content .tw-align-left { text-align: left; }
.township-content .tw-align-center { text-align: center; }
.township-content .tw-align-right { text-align: right; }
.township-content .tw-callout { border-left: 5px solid var(--navy); background: #eaf1f8; padding: .8rem 1rem; border-radius: 4px; margin-bottom: .9rem; }
.township-content .tw-callout > :last-child { margin-bottom: 0; }
.township-content .tw-callout-warning { border-left-color: var(--orange); background: #fdf3e3; }
.township-content .tw-callout-success { border-left-color: var(--green); background: #e8f4ec; }
.township-content .tw-columns { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.25rem; margin-bottom: .9rem; }
.township-content .tw-column > :last-child { margin-bottom: 0; }
.township-content a.tw-button { display: inline-block; background: var(--navy); color: var(--white); padding: .5rem 1.1rem; border: 2px solid var(--navy); border-radius: 4px; font-weight: 600; text-decoration: none; }
.township-content a.tw-button:hover { background: var(--navy2); border-color: var(--navy2); color: var(--white); text-decoration: none; }
.township-content a.tw-button-secondary { background: var(--white); color: var(--navy); }
.township-content a.tw-button-secondary:hover { background: var(--light); color: var(--navy); }
.township-content details { border: 1px solid var(--border); border-radius: 4px; padding: .5rem .9rem; margin-bottom: .9rem; }
.township-content summary { cursor: pointer; font-weight: 600; color: var(--navy); }
.township-content details[open] > summary { margin-bottom: .5rem; }
.township-content details > :last-child { margin-bottom: 0; }
/* Boxes, columns, sections and tables start below an image floated beside the text before them. */
.township-content .tw-callout, .township-content .tw-columns, .township-content details, .township-content table { clear: both; }
.township-content .tw-img-left { float: left; margin: .3rem 1rem .6rem 0; }
.township-content .tw-img-right { float: right; margin: .3rem 0 .6rem 1rem; }
.township-content .tw-img-center { display: block; margin: .4rem auto .9rem; }
.township-content .tw-img-small { width: 30%; }
.township-content .tw-img-medium { width: 50%; }
.township-content .tw-img-large { width: 100%; }
@media (max-width: 700px) {
  .township-content .tw-columns { grid-template-columns: 1fr; }
  .township-content .tw-img-left, .township-content .tw-img-right { float: none; display: block; margin: .4rem auto .9rem; }
  .township-content .tw-img-small { width: 50%; }
  .township-content .tw-img-medium { width: 100%; }
}

/* Notices */
.township-notice-entry { border-bottom: 1px solid var(--border); padding-bottom: 1.1rem; margin-bottom: 1.1rem; }
.township-notice-entry:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; }
.township-notice-entry h3 { margin: 0 0 .15rem; }
.township-notice-meta { font-size: .85rem; color: var(--muted); margin-bottom: .6rem; }
.township-notice-attachments { list-style: none; padding: 0 !important; margin-top: .4rem; }
.township-notice-attachments li { padding: .2rem 0; }

/* Page editor (admin). The editor keeps its own chrome; the writing area is sized like the page. */
.rich-editor-wrap .jodit-container { border-color: var(--border); }
.rich-editor-wrap .jodit-wysiwyg { padding: 1rem 1.25rem !important; }
.rich-editor-wrap .jodit-wysiwyg details > :not(summary) { display: block; }

/* Calendar */
.cal-toolbar { display: flex; justify-content: space-between; align-items: center; gap: .75rem; flex-wrap: wrap; margin-bottom: 1rem; }
.cal-nav { display: flex; align-items: center; gap: .5rem; }
.cal-month { margin: 0 .5rem !important; padding: 0 !important; border: none !important; min-width: 10rem; text-align: center; }
.cal-filter select { padding: .35rem .5rem; border: 1px solid var(--border); border-radius: 4px; font: inherit; font-size: .9rem; }
.cal-grid { table-layout: fixed; min-width: 700px; }
.cal-grid th { text-align: center; }
.cal-grid td { height: 6.5rem; padding: .3rem; border: 1px solid var(--border); }
.cal-grid tr:hover td { background: transparent; }
.cal-grid td.cal-other { background: #f7f9fb; }
.cal-grid td.cal-other .cal-day { color: #a9b5c2; }
.cal-grid td.cal-today { box-shadow: inset 0 0 0 2px var(--gold); }
.cal-day { font-size: .8rem; font-weight: 700; color: var(--muted); }
.cal-event { display: block; font-size: .74rem; line-height: 1.25; padding: .15rem .3rem; margin-top: .2rem; border-radius: 3px; border-left: 3px solid var(--navy); background: var(--light); color: var(--text); overflow-wrap: anywhere; }
.cal-event:hover { text-decoration: none; filter: brightness(.95); }
.cal-time { font-weight: 700; }
.cal-event.is-cancelled, .cal-list-row.is-cancelled strong, .township-event-list li.is-cancelled a { text-decoration: line-through; opacity: .7; }
.cal-list { margin-top: 1.25rem; }
.cal-list-row { display: grid; grid-template-columns: 8rem minmax(0, 1fr); gap: .75rem; padding: .55rem 0; border-bottom: 1px solid var(--border); }
.cal-dot { display: inline-block; width: .6rem; height: .6rem; border-radius: 50%; margin-right: .35rem; background: var(--navy); vertical-align: baseline; }
.cal-cat-trustees { border-left-color: var(--navy); } .cal-dot.cal-cat-trustees { background: var(--navy); }
.cal-cat-zoning-commission { border-left-color: var(--green); } .cal-dot.cal-cat-zoning-commission { background: var(--green); }
.cal-cat-board-of-zoning-appeals { border-left-color: var(--gold); } .cal-dot.cal-cat-board-of-zoning-appeals { background: var(--gold); }
.cal-cat-township { border-left-color: #6b4c9a; } .cal-dot.cal-cat-township { background: #6b4c9a; }
.cal-cat-service-department { border-left-color: var(--orange); } .cal-dot.cal-cat-service-department { background: var(--orange); }
.cal-cat-community { border-left-color: #2a7f8f; } .cal-dot.cal-cat-community { background: #2a7f8f; }

@media (max-width: 900px) {
    .township-columns { grid-template-columns: 1fr; }
}
@media (max-width: 700px) {
    .township-search input { width: 100%; }
    /* Seven columns cannot be read on a phone; the list below the grid carries the same events. */
    .cal-grid-wrap { display: none; }
    .cal-list-row { grid-template-columns: 1fr; gap: .15rem; }
}

/* Zoning department sub-menu, under the township menu on the zoning services'
   pages (layouts/public). Lighter than #site-nav so the two read as levels. */
#zoning-subnav { background: var(--white); border-bottom: 1px solid var(--border); }
#zoning-subnav ul { max-width: 1100px; margin: 0 auto; padding: 0 1.5rem; list-style: none; display: flex; flex-wrap: wrap; }
#zoning-subnav a { display: block; padding: .5rem .8rem; color: var(--navy); font-size: .85rem; font-weight: 500; text-decoration: none; border-bottom: 3px solid transparent; }
#zoning-subnav a:hover { border-bottom-color: var(--border); text-decoration: none; }
#zoning-subnav a.active { border-bottom-color: var(--gold); font-weight: 700; }
@media (max-width: 700px) {
    #zoning-subnav ul { padding: 0 .75rem; }
    #zoning-subnav a { padding: .45rem .55rem; font-size: .8rem; }
}

/* Requirement sheets (partials/requirements-sheet): every line ends in the
   section it rests on, set apart so a reader can scan the citations. */
.req-sheet h4 { margin: .8rem 0 .25rem; color: var(--navy); }
.req-list { margin: 0 0 .4rem 1.1rem; padding: 0; }
.req-list li { margin: .2rem 0; line-height: 1.4; }
.req-cite { font-size: .8rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.req-group { border: 1px solid var(--border); border-radius: 6px; padding: .5rem .9rem; margin-bottom: .6rem; }
.req-group > summary { cursor: pointer; font-weight: 600; color: var(--navy); }
.req-group[open] > summary { margin-bottom: .3rem; }
