:root {
  --bg: #FAFAF8;
  --surface: #FFFFFF;
  --text-primary: #1A1A18;
  --text-secondary: #5B5B56;
  --text-muted: #8A8A84;
  --border: #E3E2DC;
  --accent: #0B5FA5;
  --accent-text: #FFFFFF;

  --badge-bill-bg: #EEEDFE;
  --badge-bill-text: #26215C;
  --badge-hearing-bg: #E1F5EE;
  --badge-hearing-text: #04342C;
  --badge-sboe-bg: #FAECE7;
  --badge-sboe-text: #4A1B0C;
  --badge-rule-bg: #FBEAF0;
  --badge-rule-text: #4B1528;
  --badge-minutes-bg: #FAEEDA;
  --badge-minutes-text: #412402;
  --badge-agenda-bg: #E3F6F5;
  --badge-agenda-text: #063638;
  --badge-sbec-bg: #E1F0F5;
  --badge-sbec-text: #0B3A47;
  --badge-news-bg: #EFEEE0;
  --badge-news-text: #3A3A1F;
  --badge-deadline-bg: #FCE3C2;
  --badge-deadline-text: #5C3300;

  --font-sans: 'Public Sans', system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, monospace;
  --radius: 12px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #161614;
    --surface: #1E1E1B;
    --text-primary: #F2F2EF;
    --text-secondary: #B5B5AE;
    --text-muted: #8A8A84;
    --border: #333330;
    --accent: #6FA8DC;
    --accent-text: #0B1F33;

    --badge-bill-bg: #26215C;
    --badge-bill-text: #CECBF6;
    --badge-hearing-bg: #04342C;
    --badge-hearing-text: #9FE1CB;
    --badge-sboe-bg: #4A1B0C;
    --badge-sboe-text: #F5C4B3;
    --badge-rule-bg: #4B1528;
    --badge-rule-text: #F4C0D1;
    --badge-minutes-bg: #633806;
    --badge-minutes-text: #FAC775;
    --badge-agenda-bg: #0F3D3D;
    --badge-agenda-text: #8FE0DC;
    --badge-sbec-bg: #0B3A47;
    --badge-sbec-text: #A8DCE8;
    --badge-news-bg: #3A3A1F;
    --badge-news-text: #D4D2A8;
    --badge-deadline-bg: #5C3300;
    --badge-deadline-text: #FBC989;
  }
}

* { box-sizing: border-box; }

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

.wrap {
  max-width: 640px;
  margin: 0 auto;
  padding: 0 16px 48px;
}

header.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px 0;
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
}

.wordmark {
  font-size: 21px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

a.wordmark {
  text-decoration: none;
  color: inherit;
}

.menu-btn {
  display: none;
}

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

.icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-secondary);
  cursor: pointer;
}

.icon-btn svg {
  width: 18px;
  height: 18px;
}

.icon-btn:hover {
  border-color: var(--text-muted);
}

.icon-btn.is-active {
  color: var(--accent);
  border-color: var(--accent);
}

nav.filters {
  display: flex;
  gap: 8px;
  padding: 14px 0;
}

/* Both the type filter and the Sign Up button share this exact shape/font --
   a select styled to match a plain button rather than looking like a native
   dropdown (appearance:none + a hand-drawn chevron). */
.filter-select {
  flex: 0 0 auto;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 500;
  padding: 8px 16px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-secondary);
  cursor: pointer;
}

select.filter-select {
  padding-right: 34px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235B5B56' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 14px;
}

.filter-select:hover {
  border-color: var(--text-muted);
}

/* Same blue used on the Sign Up button, applied to the type filter when a
   non-"All" value is active and to the search box when it has a query --
   a quick visual "a filter is applied" signal instead of relying on the
   dropdown/input's own text alone. */
.filter-select.is-active {
  color: var(--accent);
  border-color: var(--accent);
}

/* Fills whatever space is left between the type filter and Sign Up button --
   min-width:0 lets it shrink below its content size on narrow viewports
   instead of forcing the row to overflow (mobile-first: the dropdown and
   button keep their natural width, the search box absorbs the rest). */
.search-wrap {
  position: relative;
  flex: 1 1 0;
  min-width: 64px;
}

.search-input {
  width: 100%;
  padding-right: 34px;
  cursor: text;
  color: var(--text-primary);
}

.search-input::placeholder {
  color: var(--text-muted);
}

.search-input::-webkit-search-decoration,
.search-input::-webkit-search-cancel-button {
  -webkit-appearance: none;
}

.search-clear {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
}

.search-clear:hover {
  background: var(--bg);
  color: var(--text-primary);
}

.search-clear[hidden] {
  display: none;
}

#signup-btn {
  color: var(--accent);
  border-color: var(--accent);
}

.reset-filters-btn {
  display: block;
  margin: 16px auto 0;
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 500;
  padding: 8px 18px;
  border-radius: 999px;
  border: 1px solid var(--accent);
  background: var(--surface);
  color: var(--accent);
  cursor: pointer;
}

.reset-filters-btn:hover {
  background: var(--bg);
}

/* Board View: sits as a sibling of .wrap (not nested inside it) specifically
   so it can use more than .wrap's 640px max-width on desktop -- "much
   cleaner" per direct request means seeing multiple columns without
   scrolling, which the single-column-optimized .wrap width would prevent. */
.board-wrap {
  max-width: 1400px;
  margin: 0 auto;
  padding: 0 16px 48px;
}

.board-wrap[hidden] {
  display: none;
}

.board {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  overflow-x: auto;
  padding-bottom: 8px;
}

/* Applied via JS (app.js's renderBoard()) only when the rendered columns
   don't actually overflow the container -- typically after a filter hides
   some sections down to just 1-2 columns, which would otherwise sit
   left-aligned with a large empty gap on the right. */
.board.is-centered {
  justify-content: center;
}

.board-column {
  flex: 0 0 320px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}

.board-column-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
  background: var(--bg);
}

.board-column-title {
  font-size: 15px;
  font-weight: 600;
}

.board-column-count {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--text-muted);
}

.board-column-body {
  padding: 4px 16px 16px;
}

.board-column-body .date-heading {
  margin-top: 20px;
}

.board-column-body .date-heading:first-child {
  margin-top: 12px;
}

/* Mobile: snap between lanes as the user scrolls, one lane roughly filling
   the viewport at a time (a slight peek of the next column signals there's
   more to swipe to) -- per direct request. */
@media (max-width: 640px) {
  .board-column {
    flex: 0 0 88vw;
    scroll-snap-align: start;
  }

  .board {
    scroll-snap-type: x mandatory;
  }
}

.board-scroll-area {
  position: relative;
}

/* Left/right arrow hints on mobile, showing there's another lane to swipe
   to -- the 88vw column peek alone wasn't a clear enough signal on its own,
   per direct feedback. JS toggles a "visible" class based on actual scroll
   position (hidden at each end, since there's nothing further that way).
   Desktop shows enough columns at once that this isn't needed. */
.board-scroll-hint {
  display: none;
}

@media (max-width: 640px) {
  .board-scroll-hint {
    /* display:none by default, not opacity:0 -- an opacity-based toggle
       here proved unreliable in testing (even a forced inline-style
       override wouldn't take effect), so show/hide uses the far more
       basic and reliable display property instead. */
    display: none;
    align-items: center;
    justify-content: center;
    /* Fixed to the viewport, not absolute within .board-scroll-area --
       real bug found via user report on an actual iPhone: a long column
       (History/Closed alone can run 40+ cards) makes .board-scroll-area
       very tall, so "top: 50%" of THAT element placed the hint arrow far
       below the initial screen, effectively invisible without scrolling
       the whole page down first. Fixed positioning centers it against the
       actual viewport height instead, regardless of column content length. */
    position: fixed;
    top: 50%;
    transform: translateY(-50%);
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--accent);
    color: var(--accent-text);
    font-size: 20px;
    line-height: 1;
    pointer-events: none;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.35);
    z-index: 5;
  }

  .board-scroll-hint.is-visible {
    display: flex;
  }

  .board-scroll-hint-left {
    left: 4px;
  }

  .board-scroll-hint-right {
    right: 4px;
  }
}

/* Calendar (collapsible, month-grid, under the filter/search/signup row) */
.calendar-section {
  margin-bottom: 4px;
}

.calendar-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 500;
  padding: 8px 16px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-secondary);
  cursor: pointer;
}

.calendar-toggle:hover {
  border-color: var(--text-muted);
}

.calendar-toggle-arrow {
  transition: transform 0.15s ease;
  color: var(--text-muted);
}

.calendar-toggle[aria-expanded="true"] .calendar-toggle-arrow {
  transform: rotate(180deg);
}

.calendar-panel {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  margin-top: 8px;
  padding: 14px;
}

.calendar-panel[hidden] {
  display: none;
}

.calendar-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}

.calendar-nav-btn {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-primary);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
}

.calendar-nav-btn:hover:not(:disabled) {
  border-color: var(--text-muted);
}

.calendar-nav-btn:disabled {
  color: var(--text-muted);
  cursor: not-allowed;
  opacity: 0.4;
}

.calendar-month-label {
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-secondary);
}

.calendar-weekdays,
.calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}

.calendar-weekdays {
  margin-bottom: 4px;
}

.calendar-weekdays span {
  text-align: center;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-muted);
}

.calendar-day {
  position: relative;
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  color: var(--text-muted);
  border-radius: 8px;
}

.calendar-day.calendar-day-empty {
  visibility: hidden;
}

.calendar-day.has-items {
  font-weight: 600;
  border: 1px solid transparent;
  cursor: pointer;
  filter: brightness(1);
}

.calendar-day.has-items:hover {
  filter: brightness(0.92);
}

.calendar-day.cal-bill { background: var(--badge-bill-bg); color: var(--badge-bill-text); }
.calendar-day.cal-hearing { background: var(--badge-hearing-bg); color: var(--badge-hearing-text); }
.calendar-day.cal-sboe { background: var(--badge-sboe-bg); color: var(--badge-sboe-text); }
.calendar-day.cal-sbec { background: var(--badge-sbec-bg); color: var(--badge-sbec-text); }
.calendar-day.cal-minutes { background: var(--badge-minutes-bg); color: var(--badge-minutes-text); }
.calendar-day.cal-rule { background: var(--badge-rule-bg); color: var(--badge-rule-text); }
.calendar-day.cal-news { background: var(--badge-news-bg); color: var(--badge-news-text); }

.calendar-day.has-items:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Deadline-only day: filled with a dedicated light-orange badge pair (own
   color, not shared with any item type) -- "something is due" reads as its
   own distinct category alongside the item-type badges, not a lesser
   outlined variant of them. */
.calendar-day.has-deadline-only {
  font-weight: 600;
  background: var(--badge-deadline-bg);
  color: var(--badge-deadline-text);
  border: 1px solid transparent;
  cursor: pointer;
  filter: brightness(1);
}

.calendar-day.has-deadline-only:hover {
  filter: brightness(0.92);
}

.calendar-day.has-deadline-only:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Marks today's date, independent of whether the day also has items/a
   deadline on it (those are separate signals -- fill color means "has
   content", this ring means "this is today"). An inset box-shadow rather
   than a real border so it never shifts the grid layout relative to
   neighboring cells (none of the three day states above reserve border
   space the same way). A tighter, near-square radius (vs. the 8px every
   other day cell uses) is deliberate -- per direct request, a visibly
   square-cornered box reads more distinctly as "you are here" than another
   rounded pill would, especially on an already-colored has-items day. */
.calendar-day.is-today {
  border-radius: 3px;
  box-shadow: inset 0 0 0 2px var(--accent);
}

/* Small dot overlay marking a comment-deadline date -- shown on top of
   either treatment above when a day has both a posted item and a deadline,
   or stands alone visually on a deadline-only (now orange-filled) day.
   Dark and fixed (not currentColor) so it reads as a distinct mark against
   both the orange deadline-only fill and any of the pastel item-type badge
   colors -- currentColor previously matched whatever near-white badge text
   color sat underneath it and disappeared. The --surface ring gives it a
   clean edge against whichever background it lands on. */
.calendar-deadline-dot {
  position: absolute;
  bottom: 4px;
  left: 50%;
  transform: translateX(-50%);
  width: 6px;
  height: 6px;
  border-radius: 50%;
  /* Theme-aware, not a fixed hex -- badge-deadline-text is guaranteed to
     contrast against badge-deadline-bg (the deadline-only box's own fill)
     in both light and dark mode by construction, unlike a fixed color which
     would have matched the dark-mode box background and disappeared. */
  background: var(--badge-deadline-text);
  box-shadow: 0 0 0 1.5px var(--surface);
}

/* Calendar day hover/tap preview: hover (mouse) or click/tap (any device)
   both open this same panel, docked below the grid rather than a floating
   tooltip anchored to the hovered cell -- avoids edge-clipping math on
   narrow mobile screens, and needs no repositioning logic on resize. */
.calendar-detail {
  margin-top: 10px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
}

.calendar-detail[hidden] {
  display: none;
}

.calendar-detail-date {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  margin: 0 0 6px;
}

.calendar-detail-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.calendar-detail-row {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 8px;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}

.calendar-detail-row:hover,
.calendar-detail-row:focus-visible {
  background: var(--surface);
}

.calendar-detail-row .badge {
  flex-shrink: 0;
}

.calendar-detail-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.badge.deadline { background: var(--badge-deadline-bg); color: var(--badge-deadline-text); }

@keyframes item-jump-highlight {
  0%, 100% { background: var(--surface); }
  30% { background: var(--badge-sboe-bg); }
}

.card.jump-highlight {
  animation: item-jump-highlight 1.6s ease;
}

/* Signup modal */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  z-index: 100;
}

.modal-overlay[hidden] {
  display: none;
}

.modal {
  position: relative;
  width: 100%;
  max-width: 420px;
  max-height: 90vh;
  overflow-y: auto;
  background: var(--surface);
  border-radius: var(--radius);
  border: 1px solid var(--border);
  padding: 28px 24px 24px;
}

.modal-close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
}

.modal-close:hover {
  background: var(--bg);
  color: var(--text-primary);
}

/* Desktop-only in-page modal for this site's own AI-summary subpages
   (rule.html), loaded via iframe -- per direct request, replacing the
   new-tab behavior every other card link still uses. Wider/taller than
   the signup modal since it's showing a full page's worth of content, not
   a form. Mobile never gets this at all (see openCardTarget() in app.js);
   its own [hidden] state is all that governs visibility there, so no
   separate mobile CSS override is needed. */
.subpage-modal {
  position: relative;
  width: 100%;
  max-width: 720px;
  height: 90vh;
  background: var(--surface);
  border-radius: var(--radius);
  border: 1px solid var(--border);
  overflow: hidden;
}

.subpage-modal-iframe {
  width: 100%;
  height: 100%;
  border: none;
  display: block;
}

.subpage-modal .modal-close {
  background: var(--surface);
  border: 1px solid var(--border);
  z-index: 1;
}

.modal-title {
  font-size: 20px;
  font-weight: 600;
  margin: 0 0 6px;
}

.modal-subtitle {
  font-size: 14px;
  color: var(--text-secondary);
  margin: 0 0 20px;
  line-height: 1.5;
}

.modal-label {
  display: block;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  margin: 18px 0 8px;
}

.modal-input {
  width: 100%;
  font-family: var(--font-sans);
  font-size: 15px;
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text-primary);
}

.modal-input:focus {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
}

.modal-textarea {
  min-height: 140px;
  resize: vertical;
  font-family: var(--font-sans);
}

/* Honeypot field (feedback.html) -- off-screen rather than display:none or
   visibility:hidden, since some bots specifically detect and skip those. */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Toast: brief mobile-only instructional hint on Board/Feed toggle (app.js).
   [hidden] takes it out of layout entirely between shows; the transition
   only runs while it's actually displayed, driven by the .is-visible class
   toggled a frame after [hidden] is cleared. */
.toast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%) translateY(8px);
  background: var(--text-primary);
  color: var(--bg);
  font-size: 14px;
  font-weight: 500;
  padding: 12px 20px;
  border-radius: var(--radius);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
  opacity: 0;
  transition: opacity 0.25s ease, transform 0.25s ease;
  z-index: 150;
  max-width: calc(100vw - 32px);
  text-align: center;
  pointer-events: none;
}

.toast[hidden] {
  display: none;
}

.toast.is-visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

.modal-option-group {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
}

.modal-option-group--stacked {
  flex-direction: column;
  gap: 10px;
}

.modal-option {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  color: var(--text-primary);
  cursor: pointer;
}

.modal-option input {
  accent-color: var(--accent);
  cursor: pointer;
}

.modal-submit {
  width: 100%;
  margin-top: 24px;
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 600;
  padding: 11px;
  border-radius: var(--radius);
  border: none;
  background: var(--accent);
  color: var(--accent-text);
  cursor: pointer;
}

.modal-submit:hover {
  opacity: 0.92;
}

.modal-submit:disabled {
  opacity: 0.6;
  cursor: default;
}

.modal-status {
  font-size: 14px;
  margin: 12px 0 0;
  text-align: center;
}

.modal-status.error {
  color: #B3261E;
}

.modal-status.success {
  color: var(--accent);
}

.modal-success {
  text-align: center;
  padding: 12px 0 4px;
}

.modal-success .modal-title {
  margin-top: 0;
}

.modal-success .modal-subtitle {
  margin-bottom: 24px;
}

.date-heading {
  font-family: var(--font-mono);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin: 28px 0 12px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
}

/* A bigger structural break than a date-heading -- swim-lane section
   boundary (Up Next / In Progress / News / History), same accent-blue
   treatment as the digest email's own section headers for visual
   consistency between the two. */
.section-heading {
  font-family: var(--font-sans);
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 32px 0 4px;
  padding-top: 16px;
  border-top: 2px solid var(--accent);
}

.section-heading:first-child {
  margin-top: 20px;
}

.card {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  margin-bottom: 10px;
  background: var(--surface);
  cursor: pointer;
}

.card:hover {
  border-color: var(--text-muted);
}

.card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.card-icon {
  display: flex;
  align-items: center;
  gap: 5px;
  color: var(--text-muted);
  pointer-events: none;
  flex: 0 0 auto;
}

.card-icon.ai {
  color: var(--badge-bill-text);
}

.ai-label {
  font-style: italic;
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
}

.card-icon svg {
  display: block;
  width: 18px;
  height: 18px;
}

/* Most cards have exactly one badge, but a few (e.g. SBOE/SBEC meeting
   minutes -- genuinely both a minutes document and tied to a meeting type)
   have two. Wraps on narrow viewports rather than overflowing. */
.badge-group {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.badge {
  display: inline-block;
  font-size: 13px;
  font-weight: 500;
  padding: 3px 10px;
  border-radius: 999px;
}
.badge.bill { background: var(--badge-bill-bg); color: var(--badge-bill-text); }
.badge.hearing { background: var(--badge-hearing-bg); color: var(--badge-hearing-text); }
.badge.sboe_meeting { background: var(--badge-sboe-bg); color: var(--badge-sboe-text); }
.badge.sbec_meeting { background: var(--badge-sbec-bg); color: var(--badge-sbec-text); }
.badge.news { background: var(--badge-news-bg); color: var(--badge-news-text); }
.badge.minutes { background: var(--badge-minutes-bg); color: var(--badge-minutes-text); }
.badge.agenda { background: var(--badge-agenda-bg); color: var(--badge-agenda-text); }
.badge.rule { background: var(--badge-rule-bg); color: var(--badge-rule-text); }

.card h3 {
  font-size: 18px;
  font-weight: 600;
  margin: 10px 0 6px;
  line-height: 1.35;
}

.card p.desc,
.card p.caption,
.card p.status {
  font-size: 15px;
  color: var(--text-secondary);
  margin: 0 0 8px;
  line-height: 1.5;
}

.card p.desc {
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.card p.status {
  margin-bottom: 12px;
}

.card p.status strong {
  color: var(--text-primary);
}

.card p.location {
  font-size: 14px;
  color: var(--text-muted);
  margin: 0 0 8px;
  line-height: 1.4;
}

.map-link {
  color: var(--accent);
  text-decoration: none;
  white-space: nowrap;
}

.map-link:hover {
  text-decoration: underline;
}

.card .meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.card .source {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-muted);
  letter-spacing: 0.02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.card .actions {
  display: flex;
  gap: 10px;
  flex: 0 0 auto;
}

.cal-btn {
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 500;
  padding: 7px 12px;
  cursor: pointer;
  text-decoration: none;
}

.cal-btn:hover {
  border-color: var(--text-secondary);
}

.cal-btn svg {
  width: 17px;
  height: 17px;
  flex: 0 0 auto;
}

.empty {
  color: var(--text-muted);
  font-size: 15px;
  padding: 40px 0;
  text-align: center;
}

.back-link {
  display: inline-block;
  color: var(--text-secondary);
  font-size: 14px;
  text-decoration: none;
  margin: 16px 0;
}

.back-link:hover {
  color: var(--text-primary);
}

.rule-title {
  font-size: 22px;
  font-weight: 600;
  line-height: 1.35;
  margin: 12px 0 6px;
}

.rule-meta {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-muted);
  margin: 0 0 16px;
}

.pdf-link {
  display: inline-block;
  color: var(--accent);
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
  margin: 4px 0 28px;
}

.ai-summary-block {
  border-top: 1px solid var(--border);
  padding-top: 20px;
}

.ai-summary-heading {
  font-size: 16px;
  font-weight: 600;
  margin: 0 0 12px;
}

.ai-summary-list {
  margin: 0 0 16px;
  padding-left: 20px;
}

.ai-summary-list li {
  font-size: 15px;
  color: var(--text-secondary);
  line-height: 1.6;
  margin-bottom: 8px;
}

.ai-grounding-note {
  font-size: 14px;
  color: var(--text-secondary);
  font-style: italic;
  margin: 0 0 16px;
}

.ai-statutes-label {
  font-size: 13px;
  font-weight: 500;
  color: var(--text-muted);
  margin: 0 0 6px;
}

.ai-statutes-list {
  margin: 0 0 16px;
  padding-left: 20px;
}

.ai-statutes-list li {
  font-size: 13px;
  color: var(--text-muted);
  margin-bottom: 4px;
}

.ai-disclaimer {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-muted);
  margin: 20px 0 0;
}
