/*
    Marquee's design system, carried over from the Apps Script app it replaces.

    Two deliberate registers, because the two audiences are not the same person:

    PUBLIC — navy masthead band over a single floating white card, and TWO type registers on
    purpose: Inter for headings, input values and buttons; the browser's own sans for every
    label, hint and counter. That pairing is what the live app does, and it is why the form
    reads as a document with annotations rather than as a UI.

    STAFF — all sans, denser, closer to the tools people already have open. A scheduler works
    this list for an hour at a time, so the type is smaller, the rows are tighter, and status
    is carried by colour rather than by reading.

    The palette is one block. The campaign's brand colour lives in --brand and everything
    else is derived from it, so a rebrand is two lines rather than a search-and-replace.
*/

:root {
    /* brand */
    --brand:        #1C3C73;
    --brand-dark:   #15306b;
    --brand-tint:   #E8EEF7;
    --brand-soft:   #F4F6FB;
    --brand-border: #b5c5de;
    --accent:       #D4A843;   /* muted gold — the only saturated colour, and it means "forward" */
    --on-brand:     #ffffff;

    /* surfaces */
    --surface:      #ffffff;
    --surface-bg:   #f8f9fa;
    --surface-alt:  #fafafa;
    --surface-hover:#f1f3f4;
    --row-hover:    #f8f9ff;

    /* ink */
    --ink:          #202124;
    --ink-soft:     #5f6368;
    --ink-faint:    #999;

    /* lines */
    --border:       #dadce0;
    --border-light: #ececec;
    --border-strong:#D6DBE8;

    /* state */
    --ok:           #137333;
    --ok-bg:        #E6F4EA;
    --warn:         #A37200;
    --warn-bg:      #FEF7E0;
    --error:        #C5221F;
    --error-bg:     #FCE8E6;

    /* form */
    --radius:       6px;
    --radius-card:  12px;
    --shadow:       0 1px 3px rgba(0,0,0,.12);
    --shadow-card:  0 2px 16px rgba(28,60,115,.10);

    /* type — two registers on the public form, one on the console */
    --font-display: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
    --font-ui:      sans-serif;                /* the browser's own, deliberately */
    --sans:         var(--font-display);

    /* status pills — background / ink pairs, one per lifecycle status */
    --pill-new-bg:       #fff3e0;  --pill-new-txt:       #e65100;
    --pill-interested-bg:#e8eaf6;  --pill-interested-txt:#283593;
    --pill-followup-bg:  #fce4ec;  --pill-followup-txt:  #c62828;
    --pill-scheduling-bg:#e0f2f1;  --pill-scheduling-txt:#00695c;
    --pill-tentative-bg: #fff3cd;  --pill-tentative-txt: #856404;
    --pill-scheduled-bg: #d4edda;  --pill-scheduled-txt: #155724;
    --pill-cancelled-bg: #f8d7da;  --pill-cancelled-txt: #721c24;
    --pill-archived-bg:  #f5f5f5;  --pill-archived-txt:  #757575;
    --pill-hold-bg:      #ffe0c2;  --pill-hold-txt:      #b84900;

    /* row tints — the list is scannable by colour before it is read */
    --row-held:      #fff4ec;
    --row-accepted:  #f0faf4;
    --row-cancelled: #fff5f5;
    --row-tentative: #fffdf0;
}

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

body {
    margin: 0;
    font-family: var(--sans);
    font-size: 14px;
    line-height: 1.5;
    color: var(--ink);
    background: var(--surface-bg);
    -webkit-font-smoothing: antialiased;
}

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

/* ─────────────────────────────────────────────────────── public: masthead */

/* The public form rounds its controls at 8px where the console rounds at 6px — the console
   is dense and wants tighter corners. Overriding the custom property here rather than in the
   rules means every input, select and button inside the form picks it up. */
.pub { font-family: var(--font-display); background: #F7F8FB; min-height: 100vh; --radius: 8px; }

.pub-header { background: var(--brand); display: flex; justify-content: center; }
.pub-header-inner {
    width: 100%; max-width: 800px; display: flex; align-items: center; gap: 8px 24px; flex-wrap: wrap;
    padding: 18px 24px 14px;
}
/* Sized by height, so swapping the SVG for the campaign's own artwork needs no CSS change
   whatever aspect ratio it has. The anchor is the flex child now, so it carries the shrink
   rule; line-height:0 keeps the inline box from adding a few pixels under the image. */
.pub-logo-link { display: block; flex-shrink: 0; line-height: 0; border-radius: 4px; }
.pub-logo-link:focus-visible { outline: 2px solid rgba(255,255,255,.8); outline-offset: 4px; }
.pub-logo { height: 52px; width: auto; display: block; }

/* The headline the campaign actually edits — separated from the wordmark by the same divider
   line the Apps Script masthead uses between its logo and its title block. */
.pub-mark { color: #fff; padding-left: 20px; border-left: 1px solid rgba(255,255,255,.2); flex: 1; }
.pub-mark h1 { font-size: 18px; font-weight: normal; letter-spacing: .01em; line-height: 1.25; margin: 0; }
.pub-mark p { font-family: var(--font-ui); font-size: 11px; opacity: .65; margin: 3px 0 0; }

/* progress rail — dots joined by a line that fills as the wizard advances */
.pub-progress { background: var(--brand); display: flex; justify-content: center; }
.pub-progress-inner { width: 100%; max-width: 800px; padding: 0 24px 18px; }
.steps { display: flex; align-items: flex-start; position: relative; }
.steps::before {
    content: ''; position: absolute; top: 14px; left: 14px; right: 14px; height: 2px;
    background: rgba(255,255,255,.2);
}
.steps-fill {
    position: absolute; top: 14px; left: 14px; height: 2px; background: var(--accent);
    z-index: 1; transition: width .4s cubic-bezier(.25,1,.5,1);
}
.step { flex: 1; display: flex; flex-direction: column; align-items: center; position: relative; z-index: 2; }
.step .dot {
    width: 28px; height: 28px; border-radius: 50%; background: rgba(255,255,255,.2);
    border: 2px solid rgba(255,255,255,.3); display: flex; align-items: center; justify-content: center;
    font-family: var(--font-ui); font-size: 11px; font-weight: 600; color: rgba(255,255,255,.6);
    transition: background .25s, border-color .25s, color .25s;
}
.step.done .dot { background: var(--accent); border-color: var(--accent); color: #fff; }
.step.active .dot { background: #fff; border-color: #fff; color: var(--brand); }
.step .label {
    margin-top: 6px; font-family: var(--font-ui); font-size: 10px; color: rgba(255,255,255,.5);
    text-align: center; white-space: nowrap;
}
.step.active .label, .step.done .label { color: rgba(255,255,255,.8); }

@media (prefers-reduced-motion: reduce) { .steps-fill, .step .dot { transition: none; } }

/* ───────────────────────────────────────────────────────── public: card */

.pub-body { display: flex; justify-content: center; padding: 32px 16px 64px; }
.card {
    background: #fff; border-radius: var(--radius-card); box-shadow: var(--shadow-card);
    width: 100%; max-width: 800px; overflow: hidden;
}
/* 180px and center 25% are the Apps Script form's numbers, not new ones: the crop it uses
   keeps the subject's face in frame at both heights. The card's overflow:hidden rounds the
   top corners, so the image needs no radius of its own. */
.pub-hero { width: 100%; height: 180px; object-fit: cover; object-position: center 25%; display: block; }

.card-hdr { padding: 24px 36px 18px; border-bottom: 1px solid var(--border-strong); }
.card-hdr h2 { font-size: 22px; color: var(--brand); font-weight: normal; margin: 0; }
.card-hdr p { font-family: var(--font-ui); font-size: 13px; color: var(--ink-soft); margin: 4px 0 0; }

.fields { padding: 24px 36px; display: flex; flex-direction: column; gap: 18px; }
.field { display: flex; flex-direction: column; gap: 6px; }
.field > label { font-family: var(--font-ui); font-size: 13px; display: flex; align-items: center; gap: 4px; }
.field .req { color: var(--error); }
.field .hint { font-family: var(--font-ui); font-size: 11px; color: var(--ink-soft); }

input[type=text], input[type=email], input[type=tel], input[type=url], input[type=search],
input[type=date], input[type=time], input[type=number], select, textarea {
    border: 1.5px solid var(--border-strong); border-radius: var(--radius);
    padding: 10px 14px; font-size: 14px; font-family: var(--sans);
    color: var(--ink); background: #fff; outline: none; width: 100%;
    transition: border-color .15s, box-shadow .15s;
}
input:focus, select:focus, textarea:focus {
    border-color: var(--brand); box-shadow: 0 0 0 3px rgba(28,60,115,.08);
}
textarea { resize: vertical; min-height: 88px; }
select {
    appearance: none; padding-right: 36px; background-repeat: no-repeat;
    background-position: right 14px center;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%235f6368' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
}

.section-hdr {
    font-family: var(--font-ui); font-size: 12px; color: var(--ink-soft); letter-spacing: .08em;
    text-transform: uppercase; padding-bottom: 4px; border-bottom: 1px solid var(--border-strong);
}

.card-nav {
    padding: 18px 36px 24px; border-top: 1px solid var(--border-strong);
    display: flex; justify-content: space-between; align-items: center; gap: 12px;
}
.step-count { font-family: var(--font-ui); font-size: 12px; color: var(--ink-soft); }

/* ────────────────────────────────────────────────────────────── buttons */

.btn {
    padding: 11px 28px; border-radius: var(--radius); font-size: 14px; font-family: var(--sans);
    cursor: pointer; border: 1.5px solid transparent; transition: filter .15s, border-color .15s, color .15s, background .15s;
    text-decoration: none; display: inline-flex; align-items: center; gap: 8px; line-height: 1;
}
.btn:disabled { opacity: .55; cursor: not-allowed; }
.btn-primary { background: var(--brand); color: #fff; box-shadow: 0 2px 8px rgba(28,60,115,.2); }
.btn-primary:hover:not(:disabled) { filter: brightness(1.12); }
.btn-accent { background: var(--accent); color: #fff; box-shadow: 0 2px 8px rgba(0,0,0,.15); padding: 12px 36px; font-size: 15px; }
.btn-accent:hover:not(:disabled) { filter: brightness(1.1); }
.btn-ghost { background: transparent; border-color: var(--border-strong); color: var(--ink-soft); }
.btn-ghost:hover:not(:disabled) { border-color: var(--brand); color: var(--brand); }
.btn-danger { background: #fff; border-color: #f6aea9; color: var(--error); }
.btn-danger:hover:not(:disabled) { background: var(--error-bg); }
.btn-sm { padding: 7px 14px; font-size: 13px; }

/* ─────────────────────────────────────────────────────────────── notices */

/* A full 1px border in the status colour over the status tint, which is what the Apps Script
   app's .banner does. It used to be a 4px left stripe — the one accent pattern the design
   system rules out by name, because a stripe reads as decoration where a full border reads
   as the shape of the message. */
.notice {
    font-family: var(--font-ui); font-size: 13px; border-radius: var(--radius);
    padding: 10px 14px; border: 1px solid var(--border); background: var(--surface-hover);
    display: flex; gap: 10px; align-items: flex-start;
}
.notice-ok    { border-color: #a8d5b5; background: var(--ok-bg);    color: var(--ok); }
.notice-warn  { border-color: #e0b045; background: var(--warn-bg);  color: var(--warn); }
.notice-error { border-color: #e0a09e; background: var(--error-bg); color: var(--error); }
.notice ul { margin: 0; padding-left: 18px; }

.success-view { text-align: center; padding: 64px 36px; }
.success-ico {
    width: 64px; height: 64px; background: var(--ok-bg); border-radius: 50%;
    display: flex; align-items: center; justify-content: center; font-size: 28px; margin: 0 auto 24px;
}
.success-view h2 { font-size: 24px; color: var(--brand); margin: 0 0 12px; font-weight: normal; }
.success-view p { font-family: var(--font-ui); font-size: 14px; color: var(--ink-soft); max-width: 440px; margin: 0 auto; line-height: 1.6; }

.honeypot { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }

/* ────────────────────────────────────────────────────────── staff: shell */

.topbar {
    background: var(--brand); color: var(--on-brand); height: 52px; padding: 0 20px;
    display: flex; align-items: center; gap: 16px; position: sticky; top: 0; z-index: 100;
    box-shadow: 0 2px 4px rgba(0,0,0,.2);
}
.topbar .wordmark { font-size: 17px; font-weight: 700; letter-spacing: .4px; }
.topbar .role-badge {
    background: rgba(255,255,255,.18); border-radius: 10px; padding: 2px 10px;
    font-size: 11px; font-weight: 600; letter-spacing: .5px; text-transform: uppercase;
}
.topbar .spacer { flex: 1; }
.topbar .user-email { font-size: 13px; opacity: .85; }
.topbar form { margin: 0; }

/* Every secondary action in the bar — Calendar, Settings, Switch account, Sign out — is this
   one look, same as the Apps Script console's .back-btn. A link and a <button type=submit>
   both take it, which is why it's a class and not tied to either element. */
.back-btn {
    background: rgba(255,255,255,.15); border: none; color: #fff; border-radius: var(--radius);
    padding: 5px 12px; font-size: 13px; font-weight: 600; font-family: var(--sans);
    text-decoration: none; cursor: pointer; white-space: nowrap;
}
.back-btn:hover { background: rgba(255,255,255,.25); }


.staff { max-width: 1280px; margin: 0 auto; padding: 20px; }
.staff h1 { font-size: 20px; font-weight: 600; margin: 0 0 4px; }
.staff h2 { font-size: 15px; font-weight: 600; margin: 0 0 12px; }
.staff .sub { color: var(--ink-soft); font-size: 13px; margin: 0 0 16px; }

.panel {
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
    box-shadow: var(--shadow); padding: 16px 18px; margin-bottom: 16px;
}
.panel > h2 { padding-bottom: 10px; border-bottom: 1px solid var(--border-light); }

.toolbar { display: flex; flex-wrap: wrap; gap: 12px; align-items: end; }
.toolbar .field { flex: 0 0 auto; min-width: 170px; gap: 4px; }
.toolbar .field > label { font-size: 12px; color: var(--ink-soft); }
.toolbar input, .toolbar select { padding: 7px 12px; font-size: 13px; }
.toolbar .check { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; white-space: nowrap; padding-bottom: 8px; }
.toolbar .check input { width: auto; accent-color: var(--brand); }

/* ────────────────────────────────────────────────────────── staff: table */

.grid { width: 100%; border-collapse: collapse; font-size: 13px; }
.grid th {
    text-align: left; font-weight: 700; color: var(--brand); font-size: 11px;
    text-transform: uppercase; letter-spacing: .6px; padding: 10px 12px;
    border-bottom: 1px solid var(--border); position: sticky; top: 52px; background: var(--brand-soft);
}
.grid td { padding: 11px 10px; border-bottom: 1px solid var(--border-light); vertical-align: top; }
/* Zebra first, status wash second, hover last — in that order, so a scheduler can follow a
   row across six columns without a ruler, and a status tint still reads over the stripe.
   The stripe is applied from the loop rather than :nth-child because the expand row is a <tr>
   too, and nth-child would flip the parity of everything below an open one. */
.grid tbody tr { transition: background .1s; border-bottom: 1px solid var(--border); }
.grid tbody tr.alt { background: #f6f8fc; }
.grid tr.is-accepted  { background: var(--row-accepted); }
.grid tr.is-cancelled { background: var(--row-cancelled); }
.grid tr.is-tentative { background: var(--row-tentative); }
.grid tr.is-held      { background: var(--row-held); }
.grid tr.is-accepted.alt  { background: #e9f6ee; }
.grid tr.is-cancelled.alt { background: #ffeeee; }
.grid tr.is-tentative.alt { background: #fffbe4; }
.grid tr.is-held.alt      { background: #ffece0; }
.grid tbody tr:hover, .grid tbody tr.alt:hover { background: var(--brand-tint); }
.grid td.num, .grid th.num { text-align: right; white-space: nowrap; }
.grid a { font-weight: 600; text-decoration: none; }
.grid a:hover { text-decoration: underline; }
.grid .empty { padding: 32px; text-align: center; color: var(--ink-soft); }

/* ────────────────────────────────────────────────────────── staff: pills */

.pill {
    display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 11px;
    font-weight: 700; letter-spacing: .3px; white-space: nowrap; text-transform: uppercase;
    background: var(--surface-hover); color: var(--ink-soft);
}
.pill-new             { background: var(--pill-new-bg);        color: var(--pill-new-txt); }
.pill-interested      { background: var(--pill-interested-bg); color: var(--pill-interested-txt); }
.pill-needs_follow_up { background: var(--pill-followup-bg);   color: var(--pill-followup-txt); }
.pill-scheduling      { background: var(--pill-scheduling-bg); color: var(--pill-scheduling-txt); }
.pill-tentative       { background: var(--pill-tentative-bg);  color: var(--pill-tentative-txt); }
.pill-scheduled       { background: var(--pill-scheduled-bg);  color: var(--pill-scheduled-txt); }
.pill-cancelled       { background: var(--pill-cancelled-bg);  color: var(--pill-cancelled-txt); }
.pill-archived        { background: var(--pill-archived-bg);   color: var(--pill-archived-txt); }
.pill-hold      { background: var(--pill-hold-bg);      color: var(--pill-hold-txt); }
.pill-nodate    { background: var(--error-bg);          color: var(--error); }
.pill-conflict  { background: var(--error-bg);          color: var(--error); }

/* The status dropdown wears its own status's colours, so a column of them stays scannable
   the way a column of pills was. Declared AFTER .pill-* on purpose: those use the
   `background` shorthand, which would otherwise wipe out the caret image set here. */
.status-select {
    appearance: none; -webkit-appearance: none;
    border: 1px solid transparent; border-radius: 10px;
    padding: 3px 22px 3px 8px; max-width: 100%;
    font: inherit; font-size: 11px; font-weight: 700; letter-spacing: .3px;
    text-transform: uppercase; cursor: pointer;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23555' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 7px center;
}
.status-select:hover:not(:disabled) { border-color: var(--border); }
.status-select:disabled { opacity: .6; cursor: progress; }

/* ───────────────────────────────────────────────────── staff: detail view */

.detail-grid { display: grid; grid-template-columns: minmax(9rem, 12rem) 1fr; gap: 8px 16px; font-size: 13px; }
.detail-grid dt { color: var(--ink-soft); }
.detail-grid dd { margin: 0; }

.field-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 14px; }
.field-grid .field > label { font-size: 12px; color: var(--ink-soft); }
.field-grid input, .field-grid select, .field-grid textarea { padding: 8px 12px; font-size: 13px; }

.actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }

.thread { display: flex; flex-direction: column; gap: 10px; }
.comment { border-left: 3px solid var(--brand-tint); padding: 8px 12px; background: var(--surface-alt); border-radius: 0 var(--radius) var(--radius) 0; }
.comment .meta { font-size: 11px; color: var(--ink-soft); margin-bottom: 4px; }
.comment .body { white-space: pre-wrap; font-size: 13px; }

.history { font-size: 12px; color: var(--ink-soft); }
.history td { padding: 6px 12px; border-bottom: 1px solid var(--border-comment, var(--border-light)); }

/* ──────────────────────────────────────────────────────── staff: calendar */

.calendar { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 2px; }
.calendar-head { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em;
                 color: var(--ink-soft); text-align: center; padding: 6px 0; }
.calendar-cell { border: 1px solid var(--border); border-radius: 4px; min-height: 92px; padding: 4px; background: var(--surface); }
.calendar-empty { border-color: transparent; background: transparent; }
.calendar-today { border-color: #4285f4; background: #e8f0fe; }
.calendar-day { font-size: 11px; color: var(--ink-soft); margin-bottom: 2px; }
.calendar-today .calendar-day { color: #1a73e8; font-weight: 700; }
/* A button now, so it needs the button defaults stripped back to what the div had. */
.calendar-event {
    display: block; width: 100%; text-align: left; border: none; cursor: pointer;
    background: var(--brand-tint); color: var(--brand-dark); border-radius: 3px; padding: 2px 5px;
    margin-top: 2px; font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-family: var(--sans);
}
.calendar-event:hover { filter: brightness(.95); }
.calendar-event:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
/* Read by prefix at a glance. Four states, four fills — REQUEST: (Marquee's own hold) keeps
   the orange it had, and HOLD: (somebody's manual one) takes yellow, because two things that
   both mean "not settled yet" sharing a colour is the same as having no colour. */
.cal-confirmed { background: #E6F4EA; color: #137333; }   /* light green  */
.cal-hold      { background: #FEF7E0; color: #A37200; }   /* yellow       */
.cal-declined  { background: #FCE8E6; color: #C5221F; }   /* light red    */
.cal-request   { background: var(--pill-hold-bg); color: var(--pill-hold-txt); }

/* The time carries the weight; the title is what wraps away when the cell is narrow. */
.calendar-event .ev-time { font-weight: 700; margin-right: 4px; }
.calendar-event .ev-title { font-weight: 400; }

/* Everything inside, so the cursor does not flick back to an arrow between controls. */
.is-busy, .is-busy * { cursor: wait; }

/* ─────────────────────────────────────────────── the calendar's detail drawer */

.drawer-backdrop {
    position: fixed; inset: 0; z-index: 200; background: rgba(18, 24, 43, .38);
    animation: drawer-fade .16s ease-out;
}
.drawer {
    position: fixed; top: 0; right: 0; bottom: 0; z-index: 201; width: min(460px, 100%);
    background: var(--surface); border-left: 1px solid var(--border);
    box-shadow: -8px 0 28px -14px rgba(30, 40, 80, .45);
    display: flex; flex-direction: column; overflow-y: auto;
    animation: drawer-in .22s cubic-bezier(.2, .8, .2, 1);
}
@keyframes drawer-in { from { transform: translateX(100%); } to { transform: none; } }
@keyframes drawer-fade { from { opacity: 0; } to { opacity: 1; } }

/* A panel that flies in is decoration; a panel that is simply there is the content. */
@media (prefers-reduced-motion: reduce) {
    .drawer, .drawer-backdrop { animation: none; }
}

.drawer-head {
    display: flex; align-items: flex-start; gap: 12px; padding: 18px 20px 14px;
    border-bottom: 1px solid var(--border); position: sticky; top: 0; background: var(--surface);
}
.drawer-head h2 { font-size: 16px; font-weight: 600; margin: 0; flex: 1; line-height: 1.35; }
.drawer-close {
    background: none; border: none; cursor: pointer; font-size: 15px; color: var(--ink-soft);
    padding: 2px 6px; border-radius: var(--radius); line-height: 1;
}
.drawer-close:hover { background: var(--surface-hover); color: var(--ink); }

.drawer-body { margin: 0; padding: 18px 20px; }
.drawer-body dt {
    font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
    color: var(--ink-soft); margin-top: 16px;
}
.drawer-body dt:first-child { margin-top: 0; }
.drawer-body dd { margin: 4px 0 0; font-size: 14px; line-height: 1.55; }

/* Google descriptions arrive as markup, so this styles what the sanitiser let through and
   nothing else — no rule here should assume a tag that is not on that allowlist. */
.drawer-html { font-size: 13px; line-height: 1.6; }
.drawer-html p { margin: 0 0 8px; }
.drawer-html p:last-child { margin-bottom: 0; }
.drawer-html ul, .drawer-html ol { margin: 0 0 8px; padding-left: 20px; }
.drawer-html a { color: var(--brand); }
.drawer-html code, .drawer-html pre { font-size: 12px; background: var(--surface-hover); border-radius: 3px; }
.drawer-html code { padding: 1px 4px; }
.drawer-html pre { padding: 8px 10px; overflow-x: auto; white-space: pre-wrap; }
.drawer-html blockquote {
    margin: 0 0 8px; padding-left: 10px; border-left: 2px solid var(--border); color: var(--ink-soft);
}

@media (max-width: 720px) {
    .drawer { width: 100%; }
}

/* ────────────────────────────────────────────────────────────── the report */

.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-bottom: 20px; }
.kpi { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
       box-shadow: var(--shadow); padding: 14px 16px; }
.kpi .k { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-soft); }
.kpi .v { font-size: 24px; font-weight: 600; margin-top: 4px; letter-spacing: -.02em; }
.kpi-accent .v { color: var(--brand); }

.bar-row { display: grid; grid-template-columns: 12rem 1fr auto auto; gap: 12px; align-items: center;
           padding: 6px 0; border-bottom: 1px solid var(--border-light); font-size: 13px; }
.bar-track { background: var(--surface-hover); border-radius: 3px; overflow: hidden; }
.bar { height: 10px; background: var(--brand); border-radius: 3px; min-width: 2px;
       transition: width .4s cubic-bezier(.25,1,.5,1); }
.bar-row .num { text-align: right; white-space: nowrap; color: var(--ink-soft); }

/* ───────────────────────────────────────────────────────────────── mobile */

@media (max-width: 720px) {
    .pub-header-inner, .pub-progress-inner { padding-left: 16px; padding-right: 16px; }
    /* The lockup and the headline both give a little; the logo keeps its whole shape rather
       than dropping a line, because it is the one piece of the masthead that is artwork. */
    .pub-logo { height: 40px; }
    .pub-mark { padding-left: 14px; }
    .card-hdr, .fields, .card-nav { padding-left: 20px; padding-right: 20px; }
    .step .label { display: none; }
    .staff { padding: 12px; }
    .grid th { position: static; }
    .detail-grid { grid-template-columns: 1fr; gap: 2px 0; }
    .detail-grid dd { margin-bottom: 8px; }
    .bar-row { grid-template-columns: 1fr auto; }
    .bar-row .bar-track { display: none; }
}

#blazor-error-ui {
    color-scheme: light only; background: lightyellow; bottom: 0; box-sizing: border-box;
    box-shadow: 0 -1px 2px rgba(0,0,0,.2); display: none; left: 0;
    padding: .6rem 1.25rem .7rem; position: fixed; width: 100%; z-index: 1000;
}
#blazor-error-ui .dismiss { cursor: pointer; position: absolute; right: .75rem; top: .5rem; }

/* Checkbox rows outside the toolbar (the schema-driven checkbox fields in the request
   detail's .field-grid) need the same inline treatment the toolbar gives them. */
.field-grid .check { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; }
.field-grid .check input { width: auto; accent-color: var(--brand); }

/* ─────────────────────────────────────────────── staff: quick-filter chips */

.chips { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.chip {
    display: inline-flex; align-items: center; gap: 5px; padding: 6px 12px; font-size: 12.5px;
    font-family: var(--sans); border: 1px solid var(--border); border-radius: 16px;
    background: var(--surface); color: var(--ink); cursor: pointer; white-space: nowrap;
    text-decoration: none; transition: border-color .12s, background .12s, color .12s;
}
.chip:hover { border-color: var(--brand-border); background: var(--brand-soft); }
.chip.active { border-color: var(--brand); background: var(--brand-tint); color: var(--brand-dark); font-weight: 600; }
.chip-warn.active { border-color: var(--warn); background: var(--warn-bg); color: var(--warn); }
.chip-ok.active { border-color: var(--ok); background: var(--ok-bg); color: var(--ok); }

.toolbar-end { margin-left: auto; display: flex; align-items: center; gap: 12px; padding-bottom: 8px; }
.count { font-size: 12.5px; color: var(--ink-soft); white-space: nowrap; }

/* second line in a table cell: the address under an event, the time under a date */
.cell-sub { font-size: 11.5px; color: var(--ink-soft); margin-top: 2px; }
.dash { color: var(--ink-faint); }

.grid tbody tr.clickable { cursor: pointer; }
.grid .caret { color: var(--ink-soft); font-size: 11px; }
.grid tbody tr.clickable:hover .caret { color: var(--brand); }

.linkish {
    background: none; border: 0; padding: 0; font: inherit; font-size: 12.5px;
    color: var(--brand); cursor: pointer; white-space: nowrap;
}
.linkish:hover { text-decoration: underline; }

/* the row that opens inside the row — triage without losing your place in the list */
.expand-row > td { background: var(--brand-soft); border-top: 2px solid var(--brand); padding: 18px 20px; }
.expand { display: grid; grid-template-columns: minmax(0, 1fr) 240px; gap: 32px; align-items: start; }
.expand-actions { display: flex; flex-direction: column; gap: 10px; align-items: flex-start; }
.expand-actions .muted-line { font-size: 12.5px; color: var(--ink-soft); }

/* The quick edit heads the expander's action column: the three fields triage changes, stacked
   at the 240px the column already is. Its own block rather than reusing .toolbar, which lays
   fields out in a row and would spill out of that column. */
.quick-edit { display: flex; flex-direction: column; gap: 8px; width: 100%; }
.quick-edit > .field { gap: 3px; }
.quick-edit > .field > label { font-size: 11.5px; color: var(--ink-soft); }
.quick-edit input, .quick-edit select { width: 100%; }
.quick-edit > .btn { align-self: flex-start; }

@media (max-width: 900px) {
    .expand { grid-template-columns: 1fr; gap: 16px; }
    .toolbar-end { margin-left: 0; }

    /* The bar wraps rather than scrolling off. Five buttons, an address and an avatar need
       about 920px before anything gives; below that the address is the one thing safe to
       drop, since the avatar's initial and email-on-hover cover the same ground. */
    .topbar { height: auto; flex-wrap: wrap; gap: 8px 10px; }
    .topbar .user-email, .topbar .spacer { display: none; }
    .topbar-cta { margin-left: auto; }
}

.topbar .avatar {
    width: 26px; height: 26px; border-radius: 50%; background: rgba(255,255,255,.22);
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 12px; font-weight: 700; flex-shrink: 0;
}

/* The one action the bar carries. Editors only — a viewer is never shown a door they cannot
   open, and the create action refuses them anyway if they find the URL. */
.topbar-cta {
    background: #fff; color: var(--brand); border-radius: var(--radius); padding: 6px 14px;
    font-size: 13px; font-weight: 600; text-decoration: none; white-space: nowrap;
    transition: background .12s;
}
.topbar-cta:hover { background: var(--brand-tint); }

/* ──────────────────────────────────────── staff: money chip, files, mentions */

.chip-money.active { border-color: var(--brand); background: #eef7f0; color: #1F7A4C; }

/* Attachments. A list of links with their weight and provenance underneath — the two
   things somebody checks before opening a file they did not upload. */
.filelist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.filelist li {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 8px 0; border-bottom: 1px solid var(--border-light); font-size: 13px;
}
.filelist li:last-child { border-bottom: 0; }
.filelist a { font-weight: 600; text-decoration: none; }
.filelist a:hover { text-decoration: underline; }
.filelist .sub { margin: 0; font-size: 11.5px; color: var(--ink-soft); }
.filelist button { margin-left: auto; }

/* The @ sits inside the field rather than in the label, so the row reads as the mention
   it will become instead of as a name with a rule attached to it. */
.mention-input { display: flex; align-items: center; gap: 0; }
.mention-input .at {
    display: inline-flex; align-items: center; align-self: stretch; padding: 0 9px;
    background: var(--surface-hover); border: 1px solid var(--border); border-right: 0;
    border-radius: var(--radius) 0 0 var(--radius); color: var(--ink-soft); font-weight: 600;
}
.mention-input input { border-radius: 0 var(--radius) var(--radius) 0; }

/* ─────────────────────────────────────────────────────────── mobile, staff */

@media (max-width: 720px) {
    .topbar { padding: 10px 14px; }
    .topbar .wordmark { font-size: 15px; }
    /* The role is the same every time you look; on a phone it is costing a row of chrome
       above the queue. The Apps Script console hides it here too. */
    .topbar .role-badge { display: none; }

    /* Filters stack full width. A 170px minimum makes two ragged columns on a phone. */
    .toolbar { gap: 10px; }
    .toolbar .field { flex: 1 1 100%; min-width: 0; }
    .toolbar-end { width: 100%; }

    .panel { padding: 14px; }
    .actions { flex-wrap: wrap; }

    /* The queue keeps event, date, money in and status — the four things a triage decision
       needs. Host and the goal are one tap away in the expanded row, which is where somebody
       goes to act on the request anyway. Money in outranks the goal here: what an event
       actually raised is the number staff chase. */
    .grid-requests th:nth-child(2), .grid-requests td:nth-child(2),
    .grid-requests th:nth-child(4), .grid-requests td:nth-child(4) { display: none; }
    .grid-requests td:first-child { max-width: 42vw; }
    .grid { font-size: 12.5px; }
    .grid th, .grid td { padding: 9px 7px; }

    /* Settings. The display name goes first, then the access pill — "Revoke access" and
       "Restore access" already say which state the row is in, so the pill beside the button
       was saying it twice. What is left is who, what they can do, and the way to change it. */
    .grid-staff th:nth-child(2), .grid-staff td:nth-child(2),
    .grid-staff th:nth-child(4), .grid-staff td:nth-child(4) { display: none; }
    .grid-staff td:first-child { word-break: break-word; }

    /* Two text inputs in one row only fit if they are allowed to be narrower than their
       content wants — inputs default to a size attribute's worth of width. */
    .panel .grid input { min-width: 0; width: 100%; }
    .panel .grid { table-layout: fixed; }

    .filelist button { margin-left: 0; }
}
.grid td.is-fail { color: var(--danger, #B4232B); font-weight: 600; }

/* Below 420px something has to give. Money in goes — the goal is already hidden at this
   width, and a raised figure with nothing to compare it against is the least useful of the
   four; the event's own name is what somebody is scanning for. Both money columns are in the
   expanded row. */
@media (max-width: 420px) {
    .grid-requests th:nth-child(5), .grid-requests td:nth-child(5) { display: none; }
    .grid-requests td:first-child { max-width: 48vw; }
    .grid-requests td:nth-child(3) { white-space: nowrap; font-size: 11.5px; }
}

/* The state, as a badge rather than buried in the address line. Neutral by default and in
   the campaign's own colour when it is Georgia, so "do I need a flight" is answered by
   colour before anybody reads the letters. */
.state-badge {
    display: inline-block; min-width: 22px; padding: 1px 5px; margin-right: 5px;
    font-size: 10.5px; font-weight: 700; letter-spacing: .04em; text-align: center;
    border-radius: 3px; background: var(--surface-hover); color: var(--ink-soft);
    border: 1px solid var(--border);
}
.state-badge.state-home { background: var(--brand-tint); color: var(--brand-dark); border-color: var(--brand-border); }

/* Present only for a signed-in staffer, so it stays out of a constituent's way. */
.pub-staff {
    margin-left: auto; align-self: center; color: rgba(255,255,255,.9); text-decoration: none;
    font-size: 13px; font-weight: 600; white-space: nowrap;
    border: 1px solid rgba(255,255,255,.3); border-radius: var(--radius); padding: 5px 12px;
    transition: background .12s, border-color .12s;
}
.pub-staff:hover { background: rgba(255,255,255,.14); border-color: rgba(255,255,255,.55); }

/* ───────────────────────────────────────────────────────────── touch hardening

   The two rules the Apps Script app applies on every small screen, and the two most
   commonly missed. Both public form and console, because a scheduler triages from a
   phone and a constituent fills the form on one. */

@media (max-width: 720px) {
    /* Below 16px, iOS Safari zooms the page in on focus and does not zoom back out —
       the constituent is left scrolled sideways mid-form. This is the whole fix. */
    input[type=text], input[type=email], input[type=tel], input[type=url], input[type=search],
    input[type=date], input[type=time], input[type=number], select, textarea {
        font-size: 16px; padding: 12px 14px;
    }

    /* 44px is the touch floor; a 34px-tall button is a miss waiting to happen. */
    .btn { padding: 13px 22px; min-height: 44px; }
    .btn-accent { padding: 14px 28px; font-size: 15px; min-height: 46px; }
    .btn-sm { padding: 9px 14px; min-height: 38px; }
    .chip { min-height: 38px; }
    .back-btn { padding: 9px 14px; min-height: 38px; }

    /* A phone has no hover, so every hover affordance needs a press equivalent or the
       control feels dead under the thumb. */
    .btn:active:not(:disabled) { filter: brightness(.92); }
    .chip:active { background: var(--brand-tint); }
    .back-btn:active { background: rgba(255,255,255,.3); }

    .pub-hero { height: 130px; }
}

/* Narrow phones: the masthead is the only thing that still needs to give. */
@media (max-width: 400px) {
    .pub-mark h1 { font-size: 15px; }
    .pub-mark p { display: none; }
}

/* ──────────────────────────────────────────── public: footer and long-form pages */

.pub-footer {
    display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 0 24px 40px;
    font-family: var(--font-ui); font-size: 12px; color: var(--ink-soft); text-align: center;
}
.pub-footer p { margin: 0; }
.pub-footer-app strong { color: var(--ink); font-weight: 600; }
.pub-footer a { color: var(--ink-soft); }
.pub-footer a:hover { color: var(--brand); }

/* The privacy and terms pages. Narrower than the form's card content, because prose read at
   the form's full width is a paragraph nobody finishes. */
.prose { padding: 8px 36px 32px; max-width: 62ch; }
.prose h3 {
    font-size: 15px; color: var(--brand); font-weight: 600; margin: 26px 0 8px;
    font-family: var(--font-ui);
}
.prose p { font-family: var(--font-ui); font-size: 14px; line-height: 1.65; margin: 0 0 12px; }
.prose .fine {
    margin-top: 26px; padding-top: 14px; border-top: 1px solid var(--border-strong);
    font-size: 13px; color: var(--ink-soft);
}

@media (max-width: 720px) {
    .prose { padding: 8px 20px 26px; }
}
