/* The public site's actual font families are loaded per-page (see
   site_google_fonts_url() in src/lib/fonts.php) since they're a per-site
   setting, not fixed — these :root values are just the fallback in case
   that per-page override style block is ever missing (e.g. app.css loaded
   somewhere on its own), so they intentionally match the old defaults. */
:root {
  /* Matches client.jaradlee.co.uk's palette (--text/--text-muted/--bg
     values taken directly from its app.css) so the public site and the
     client portal read as the same brand rather than two shades of it. */
  --bg: #faf9f7;
  --text: #2d2926;
  --text-muted: #6b6460;
  --border: #e8e4df;
  --accent: #8b7355;
  --surface: #f7f5f2;
  --font-heading: 'Playfair Display', Georgia, serif;
  --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body { font-family: var(--font-body); color: var(--text); background: var(--bg); line-height: 1.6; }
h1, h2, h3 { font-family: var(--font-heading); font-weight: 600; margin: 0 0 .5em; line-height: 1.2; }

/* Typography customisation (Settings > Typography) is public-site-only —
   scoped under .public-site rather than bare h1/h2/h3/p so it can never
   affect the admin dashboard, which shares this same stylesheet but never
   emits the --h1-weight/--h1-size/--h1-color etc. vars these read (only
   the public page <style> block does). Higher specificity than the plain
   h1/h2/h3 rule above, so it still wins on public pages. */
.public-site h1 { font-weight: var(--h1-weight); font-size: var(--h1-size); color: var(--h1-color); letter-spacing: var(--h1-letterspacing); font-style: var(--h1-style); }
.public-site h2 { font-weight: var(--h2-weight); font-size: var(--h2-size); color: var(--h2-color); letter-spacing: var(--h2-letterspacing); font-style: var(--h2-style); }
.public-site h3 { font-weight: var(--h3-weight); font-size: var(--h3-size); color: var(--h3-color); letter-spacing: var(--h3-letterspacing); font-style: var(--h3-style); }
.public-site p { font-weight: var(--p-weight); font-size: var(--p-size); color: var(--p-color); line-height: var(--p-lineheight); }
a { color: inherit; }
img { max-width: 100%; display: block; }

/* Deterrent only (see site.js for the matching contextmenu/dragstart
   listeners) — no CSS/JS combination can stop an actual screenshot.
   -webkit-user-drag hides the native "drag this image out" ghost;
   -webkit-touch-callout suppresses iOS's long-press "Save Image" menu. */
.public-site img { -webkit-user-drag: none; -webkit-touch-callout: none; }

.text-muted { color: var(--text-muted); }
.mt-2 { margin-top: 1rem; }

.form-control {
  width: 100%; padding: 10px 14px; border: 1.5px solid var(--border); border-radius: 6px;
  font-family: var(--font-body); font-size: .95rem; margin-bottom: 12px; background: #fff; color: var(--text);
}
.form-label { display: block; font-size: .85rem; font-weight: 500; margin-bottom: 4px; color: var(--text); }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 10px 20px; border-radius: 6px; border: 1.5px solid transparent; cursor: pointer;
  font-family: var(--font-body); font-size: .9rem; font-weight: 500; text-decoration: none; transition: opacity .15s;
  /* <button> doesn't inherit line-height the way <a>/<span> do (the UA
     stylesheet sets its own "normal") — same padding then renders a
     visibly shorter box than a link/span with the same classes sitting
     right next to it, e.g. the page editor's History link vs its buttons. */
  line-height: inherit;
}
.btn:hover { opacity: .85; }
.btn-primary { background: var(--text); color: #fff; }
.btn-outline { background: transparent; border-color: var(--border); color: var(--text); }
.btn-danger { background: #fff; border-color: #d9534f; color: #d9534f; }
.btn-sm { padding: 6px 12px; font-size: .82rem; }

/* ---------------- Auth ---------------- */
.auth-page { display: flex; align-items: center; justify-content: center; min-height: 100vh; background: var(--surface); }
.auth-card { width: 100%; max-width: 380px; padding: 40px 36px; background: #fff; border: 1px solid var(--border); border-radius: 12px; text-align: center; }
.auth-logo { font-family: var(--font-heading); font-size: 1.3rem; margin-bottom: 20px; }
.auth-error { color: #c0392b; font-size: .88rem; margin-bottom: 12px; }
.auth-card form { text-align: left; margin-top: 20px; }
.auth-card .btn { width: 100%; }

/* ---------------- Admin shell ---------------- */
/* Locked to the viewport height on every admin page (not just the fullbleed
   page editor) — the sidebar then stays put while only .admin-content
   scrolls internally, instead of the whole page (sidebar included) scrolling
   away on a long page like Analytics. */
.admin-shell { display: flex; height: 100vh; overflow: hidden; }
.admin-nav {
  width: 220px; flex-shrink: 0; background: #1a1714; color: #fff; display: flex; flex-direction: column;
  padding: 20px 16px; gap: 4px; height: 100vh; overflow-y: auto;
}
.admin-nav-brand { font-family: var(--font-heading); font-size: 1.1rem; margin-bottom: 20px; color: #fff; }
.admin-nav-link { display: flex; align-items: center; gap: 10px; color: #cfc9c0; text-decoration: none; padding: 8px 10px; border-radius: 6px; font-size: .9rem; }
.admin-nav-link:hover, .admin-nav-link.active { background: rgba(255,255,255,.08); color: #fff; }
.admin-nav-icon { width: 17px; height: 17px; flex-shrink: 0; opacity: .85; }
.admin-nav-link:hover .admin-nav-icon, .admin-nav-link.active .admin-nav-icon { opacity: 1; }
.admin-nav-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 5px; margin-left: auto;
  border-radius: 999px; background: #e03131; color: #fff;
  font-size: .68rem; font-weight: 700; line-height: 1;
}
/* Badges are wrapped in a stable-id span (see render_admin_page()) so the
   nav's polling JS can refresh them in place — that wrapper, not the badge
   itself, is now the actual flex item inside .admin-nav-link, so it's the
   one that needs the auto margin pushing the group to the right edge. */
.admin-nav-link > span[id^="nav-badge-"] { margin-left: auto; }
.admin-nav-badge-group { display: inline-flex; gap: 4px; }
.admin-nav-badge-group .admin-nav-badge { margin-left: 0; }
.admin-nav-badge-green { background: #1e7e34; }
.admin-nav-spacer { flex: 1; }
.admin-nav-link-btn { width: 100%; background: none; border: none; font-family: inherit; cursor: pointer; text-align: left; }
.admin-nav-user { color: #8a8478; font-size: .8rem; padding: 0 10px; }

/* Prompt dialog — the "New prompt" button in the admin nav opens this from
   any admin page (see render_admin_page()), so it lives in the shared
   layout rather than any one page's markup. */
.prompt-dialog-overlay {
  display: none; position: fixed; inset: 0; background: rgba(0,0,0,.5);
  z-index: 9999; align-items: center; justify-content: center;
}
.prompt-dialog-overlay.open { display: flex; }
.prompt-dialog {
  background: #fff; border-radius: 10px; padding: 24px 26px; width: 100%; max-width: 440px;
  box-shadow: 0 10px 40px rgba(0,0,0,.2);
}
.prompt-dialog h3 { margin: 0 0 6px; }
.prompt-dialog textarea {
  width: 100%; margin-top: 12px; padding: 10px; border: 1px solid var(--border); border-radius: 6px;
  font-family: inherit; font-size: .9rem; resize: vertical;
}
.prompt-dialog-error { color: #c0392b; font-size: .82rem; margin: 8px 0 0; }
.prompt-dialog-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }

.prompt-list { display: flex; flex-direction: column; gap: 14px; }
.prompt-row {
  padding: 14px 16px; border: 1px solid var(--border); border-radius: 8px; background: #fff;
}
.prompt-row-actioned { opacity: .65; }
.prompt-row-needs-review { border-color: #e0a030; background: #fffaf0; }
.prompt-row-denied { border-color: #c0392b; }
.prompt-row-header { display: flex; align-items: center; gap: 12px; }
.prompt-row-info { flex: 1; min-width: 0; }
.prompt-row-text { white-space: pre-wrap; }

/* Claude's update log — a left rail (like a comment thread) rather than
   another bordered card each, so a prompt with several entries doesn't
   turn into a wall of boxes-within-a-box. */
.prompt-update {
  margin: 10px 0 0 4px; padding: 8px 0 8px 12px; border-left: 2px solid var(--border);
}
.prompt-update-text { white-space: pre-wrap; font-size: .9rem; }
.badge-needs-review { background: #e0a030; color: #fff; }
.badge-denied { background: #c0392b; color: #fff; }
.admin-content { flex: 1; padding: 32px 40px; overflow-y: auto; overflow-x: auto; min-height: 0; }
/* The page editor manages its own internal scrolling per-pane (palette/
   canvas/settings each scroll independently) — the outer content area
   itself must not also scroll, or it'd double up with a second scrollbar. */
.admin-page-fullbleed .admin-content { padding: 0; display: flex; flex-direction: column; overflow: hidden; }

.admin-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; flex-wrap: wrap; gap: 16px; }
.admin-new-page-form { display: flex; gap: 8px; }
.admin-new-page-form .form-control { margin-bottom: 0; width: 240px; }

.admin-table-wrap { overflow-x: auto; }
.admin-table { width: 100%; border-collapse: collapse; }
.admin-table th { text-align: left; font-size: .78rem; text-transform: uppercase; letter-spacing: .05em; color: var(--text-muted); padding: 10px 12px; border-bottom: 2px solid var(--border); }
.admin-table td { padding: 12px; border-bottom: 1px solid var(--border); font-size: .92rem; }
.admin-table a { text-decoration: none; font-weight: 500; }

/* Access Log — warn (amber) for a single odd event, danger (red) for an
   actual pattern (see admin_access_log_severity() for the exact rules).
   Left border rather than a full background tint so a long run of flagged
   rows doesn't turn the whole table into a wall of colour. */
.access-log-table td { white-space: nowrap; font-size: .85rem; }
.access-log-table td:first-child { padding-left: 14px; padding-right: 0; width: 1%; }
.access-log-row-warn { background: #fdf6e8; border-left: 3px solid #f5a623; }
.access-log-row-danger { background: #fbecec; border-left: 3px solid #c0392b; }
.access-log-flag { cursor: help; font-size: .95rem; }
.access-log-flag-warn { color: #b8860b; }
.access-log-flag-danger { color: #c0392b; }
.admin-row-actions form { margin-right: 6px; }

.badge { display: inline-block; padding: 2px 9px; border-radius: 20px; font-size: .72rem; font-weight: 600; margin-left: 6px; }
.badge-published { background: #e6f4ea; color: #1e7e34; }
.badge-draft { background: #f5a623; color: #fff; }
.badge-home { background: #eef1fb; color: #3b5bdb; }

/* Published/unpublished quick-toggle — same green as .badge-published for
   "this is live", since it's the same underlying pages.status this badge
   used to represent before publish/draft became snapshot-based. */
.toggle-switch { position: relative; display: inline-flex; align-items: center; width: 36px; height: 20px; flex-shrink: 0; }
.toggle-switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.toggle-slider { position: absolute; inset: 0; background: #ccc; border-radius: 999px; transition: background .15s; pointer-events: none; }
.toggle-slider::before { content: ''; position: absolute; width: 14px; height: 14px; left: 3px; top: 3px; background: #fff; border-radius: 50%; transition: transform .15s; box-shadow: 0 1px 3px rgba(0,0,0,.3); }
.toggle-switch input:checked + .toggle-slider { background: #1e7e34; }
.toggle-switch input:checked + .toggle-slider::before { transform: translateX(16px); }
.toggle-switch input:disabled { cursor: not-allowed; }
.toggle-switch input:disabled + .toggle-slider { opacity: .5; }

.admin-flash { color: #1e7e34; font-size: .9rem; }
.trash-list { max-width: 700px; }
.trash-row {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 14px 16px; border: 1px solid var(--border); border-radius: 8px; margin-bottom: 10px; background: #fff;
}
.trash-row-info { display: flex; flex-direction: column; gap: 3px; }
.trash-row-title { font-weight: 500; }
.trash-row-meta { font-size: .78rem; }
.trash-row-actions { display: flex; gap: 8px; flex-shrink: 0; }
.admin-settings-form { max-width: 480px; }

.redirects-section-title { font-size: 1.05rem; margin: 32px 0 4px; }
.redirects-section-title:first-of-type { margin-top: 8px; }
.redirect-404-list, .redirect-list { max-width: 760px; }
.notfound-toolbar {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 10px 14px; margin-bottom: 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface);
  max-width: 760px;
}
.notfound-toolbar-selectall { display: flex; align-items: center; gap: 6px; font-size: .85rem; cursor: pointer; }
.notfound-toolbar-spacer { flex: 1; }
.redirect-404-row {
  display: flex; align-items: center; flex-wrap: wrap; gap: 12px 16px;
  padding: 14px 16px; border: 1px solid var(--border); border-radius: 8px; margin-bottom: 10px; background: #fff;
}
.redirect-404-info { flex: 1 1 220px; min-width: 0; }
.redirect-404-path { font-size: .88rem; word-break: break-all; }
.redirect-404-actions { display: flex; gap: 8px; flex-shrink: 0; }
.redirect-404-actions select { margin-bottom: 0; width: auto; max-width: 220px; }
.redirect-add-form { display: flex; gap: 8px; flex-wrap: wrap; max-width: 760px; margin-bottom: 20px; }
.redirect-add-form input[type="text"] { flex: 1 1 220px; margin-bottom: 0; }
.redirect-add-form select { flex: 1 1 220px; margin-bottom: 0; }
.redirect-row {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 14px 16px; border: 1px solid var(--border); border-radius: 8px; margin-bottom: 10px; background: #fff;
}
.redirect-row-info { flex: 1 1 auto; min-width: 0; font-size: .9rem; }
.redirect-row-info code, .redirect-404-path { background: var(--surface); padding: 2px 6px; border-radius: 4px; }

.admin-footer-layout { display: flex; gap: 32px; align-items: flex-start; flex-wrap: wrap; }
.admin-footer-layout .admin-settings-form { flex: 1 1 380px; }
.admin-footer-preview { flex: 1 1 420px; min-width: 320px; position: sticky; top: 20px; }
.admin-footer-preview-frame { border: 1px solid var(--border); border-radius: 8px; overflow: hidden; background: #fff; }
.admin-footer-preview-frame iframe { width: 100%; height: 320px; border: 0; display: block; }
/* Header preview is a single bar, not a whole footer's worth of content —
   same frame styling, much shorter. */
.admin-header-preview-frame iframe { height: 100px; }
.settings-tabs { display: flex; gap: 8px; margin-bottom: 20px; border-bottom: 1px solid var(--border); max-width: 480px; }
.settings-tab {
  padding: 9px 10px; margin-bottom: -1px; border: none; border-bottom: 2px solid transparent; background: none;
  font-size: .88rem; font-weight: 500; color: var(--text-muted); cursor: pointer;
}
.settings-tab.active { color: var(--text); border-bottom-color: var(--accent); }
.settings-tab-panel { display: none; }
.settings-tab-panel.active { display: block; }
.font-picker-preview {
  border: 1px solid var(--border); border-radius: 6px; padding: 14px 16px;
  margin: 8px 0 16px; font-size: 1.3rem; background: #fff; color: var(--text);
}

.typo-row { border: 1px solid var(--border); border-radius: 8px; padding: 14px 16px; margin-bottom: 14px; max-width: 560px; }
.typo-row-label { font-weight: 600; font-size: .85rem; margin-bottom: 8px; }
.typo-row-controls { display: flex; gap: 14px; margin-bottom: 10px; flex-wrap: wrap; }
.typo-field { font-size: .78rem; color: var(--text-muted); }
.typo-field select, .typo-field input[type="number"] { margin-bottom: 0; width: 110px; padding: 6px 8px; }
.typo-field input[type="color"] { margin-bottom: 0; width: 44px; height: 32px; padding: 2px; cursor: pointer; }
.typo-preview { border-top: 1px solid var(--border); padding-top: 10px; overflow-wrap: anywhere; }

/* Media manager */
.media-dropzone {
  display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center;
  gap: 4px; padding: 28px 20px; margin-bottom: 24px; border: 2px dashed var(--border); border-radius: 10px;
  background: var(--surface); cursor: pointer; transition: border-color .12s, background .12s;
}
.media-dropzone:hover, .media-dropzone:focus-visible { border-color: var(--accent); background: #fff; outline: none; }
.media-dropzone-drag-over { border-color: var(--accent); background: #fff; box-shadow: 0 0 0 2px var(--accent) inset; }
/* Same dropzone, sized to fit inside the (much smaller) image picker modal
   rather than a full page — less padding, no separate bottom-margin since
   it sits directly above the tabs/grid instead of a whole page section. */
.media-dropzone-compact { flex-direction: row; gap: 10px; padding: 10px 18px; margin: 0; border-radius: 0; border-width: 0 0 1px; justify-content: center; flex-shrink: 0; }
.media-dropzone-compact svg { margin-bottom: 0; flex-shrink: 0; }
.media-dropzone-compact .media-dropzone-text { font-size: .82rem; }
.media-dropzone svg { color: var(--accent); margin-bottom: 4px; }
.media-dropzone-text { font-size: .92rem; }
.media-dropzone-text strong { color: var(--accent); }
.media-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 16px; }
.media-card { position: relative; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; background: #fff; }
.media-card img { width: 100%; height: 130px; object-fit: cover; display: block; background: var(--surface); }
.media-card-info { padding: 8px 10px; }
.media-card-name { font-size: .8rem; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.media-card-meta { font-size: .74rem; color: var(--text-muted); margin-top: 2px; }
.media-usage { font-weight: 600; color: var(--text); }
.media-usage-none { font-weight: 400; color: var(--text-muted); }
.media-card-delete { width: calc(100% - 20px); margin: 0 10px 10px; }
.media-card { cursor: grab; }
.media-card:active { cursor: grabbing; }

.media-card-checkbox {
  position: absolute; top: 8px; left: 8px; z-index: 2; width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center; border-radius: 5px;
  background: rgba(255,255,255,.85); box-shadow: 0 1px 4px rgba(0,0,0,.2); cursor: pointer;
}
.media-card-checkbox input { width: 16px; height: 16px; margin: 0; cursor: pointer; }

/* Sticky so the bulk actions stay reachable while scrolling a long grid —
   only actually shown (see .active) once at least one image is selected,
   rather than taking up space with nothing to act on. */
.media-bulk-bar {
  display: none; align-items: center; gap: 10px; flex-wrap: wrap;
  position: sticky; top: 0; z-index: 10; margin-bottom: 14px; padding: 10px 14px;
  background: #fff; border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,.06);
}
.media-bulk-bar.active { display: flex; }
.media-bulk-bar select { margin-bottom: 0; width: auto; padding: 6px 10px; font-size: .82rem; }

/* ---------------- Media groups (tabs) ---------------- */
.media-tabs { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 6px; flex-shrink: 0; }
.media-tab {
  display: flex; align-items: center; gap: 6px; padding: 6px 12px; border: 1.5px solid var(--border); text-decoration: none;
  border-radius: 20px; background: #fff; font-size: .82rem; cursor: pointer; color: var(--text);
}
.media-tab:hover { border-color: var(--accent); }
.media-tab.active { background: var(--accent); border-color: var(--accent); color: #fff; }
.media-tab-delete { font-size: .9rem; line-height: 1; opacity: .6; }
.media-tab-delete:hover { opacity: 1; }
.media-tab-drag-over { border-color: var(--accent); background: var(--surface); box-shadow: 0 0 0 2px var(--accent) inset; }
.media-tab-add { display: flex; align-items: center; gap: 6px; margin-left: 4px; }
.media-tab-add input { margin-bottom: 0; width: 160px; padding: 6px 10px; font-size: .82rem; }
.media-tab-rename-input { font-size: .82rem; padding: 2px 4px; border: none; outline: 1px solid #fff; border-radius: 3px; width: 100px; }

.media-dropzone-overlay {
  display: none; position: fixed; inset: 0; z-index: 4000; background: rgba(139,115,85,.12);
  border: 3px dashed var(--accent); align-items: center; justify-content: center;
  font-size: 1.4rem; font-weight: 600; color: var(--accent); pointer-events: none;
}
.media-dropzone-overlay.active { display: flex; }

/* ---------------- Analytics ---------------- */
.analytics-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 14px; margin-bottom: 24px; }
.analytics-tile { border: 1px solid var(--border); border-radius: 8px; padding: 16px 18px; background: #fff; }
.analytics-tile-value { font-family: var(--font-heading); font-size: 1.8rem; line-height: 1.1; }
.analytics-tile-label { font-size: .78rem; color: var(--text-muted); margin-top: 4px; }

.analytics-panel { border: 1px solid var(--border); border-radius: 8px; padding: 18px 20px; margin-bottom: 20px; background: #fff; }
.analytics-panel h3 { margin: 0 0 12px; font-size: .95rem; }
.analytics-panel-header { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px; }
.analytics-panel-header h3 { margin-bottom: 0; }
.analytics-metric-tabs { display: flex; gap: 6px; margin-bottom: 12px; }
.analytics-chart-wrap { position: relative; min-width: 320px; }

.analytics-live-panel h3 { display: flex; align-items: center; gap: 8px; }
.analytics-live-dot { width: 9px; height: 9px; border-radius: 50%; background: #3fa84a; flex-shrink: 0; animation: analytics-live-pulse 1.6s ease-in-out infinite; }
@keyframes analytics-live-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
.analytics-live-row {
  display: flex; align-items: center; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--border); font-size: .85rem;
}
.analytics-live-row:last-child { border-bottom: none; }
.analytics-live-path { font-weight: 600; flex-shrink: 0; }
.analytics-live-meta { margin-left: auto; font-size: .78rem; color: var(--text-muted); flex-shrink: 0; white-space: nowrap; }
.analytics-chart-wrap svg { display: block; width: 100%; }
.analytics-chart-wrap svg rect[data-tip] { cursor: pointer; }
.analytics-chart-labels { position: relative; }
.analytics-chart-label {
  position: absolute; top: 5px; transform: translateX(-50%);
  font-size: 9px; color: #999; white-space: nowrap;
}
.chart-tooltip {
  display: none; position: fixed; z-index: 7000; pointer-events: none;
  background: #1a1714; color: #fff; font-size: .78rem; line-height: 1.3;
  padding: 6px 10px; border-radius: 6px; white-space: nowrap;
  box-shadow: 0 4px 14px rgba(0,0,0,.25);
}
.chart-tooltip.open { display: block; }
.analytics-legend { display: flex; gap: 16px; margin-bottom: 8px; font-size: .78rem; color: var(--text-muted); }
.analytics-legend-item { display: flex; align-items: center; gap: 5px; }
.analytics-legend-swatch { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }
.analytics-retention-form { display: flex; align-items: center; gap: 8px; }
.analytics-retention-form input { width: 70px; margin-bottom: 0; padding: 6px 10px; }
.analytics-retention-form .btn { flex-shrink: 0; }

.analytics-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; align-items: start; margin-bottom: 20px; }
.analytics-grid .analytics-panel { margin-bottom: 0; }

.analytics-bar-row { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; font-size: .85rem; }
.analytics-bar-label { width: 38%; flex-shrink: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text); }
.analytics-bar-track { flex: 1; height: 8px; background: var(--surface); border-radius: 4px; overflow: hidden; }
.analytics-bar-fill { display: block; height: 100%; background: var(--accent); border-radius: 4px; }
.analytics-bar-count { width: 34px; flex-shrink: 0; text-align: right; color: var(--text-muted); font-size: .8rem; }

.analytics-session { padding: 10px 0; border-bottom: 1px solid var(--border); }
.analytics-session:last-child { border-bottom: none; }
.analytics-session-meta { font-size: .76rem; color: var(--text-muted); margin-bottom: 3px; }
.analytics-session-path { font-size: .88rem; }

/* ---------------- Site Map — pure-CSS org chart ---------------- */
.sitemap-tree, .sitemap-tree ul { list-style: none; margin: 0; padding: 0; }
.sitemap-tree { text-align: center; overflow-x: auto; padding-bottom: 10px; }
.sitemap-tree li { display: inline-block; vertical-align: top; position: relative; padding: 26px 10px 0; }
.sitemap-tree ul { position: relative; padding-top: 26px; white-space: nowrap; }
.sitemap-tree > ul { padding-top: 0; }
/* Connector lines: each li gets a horizontal half-line to its sibling and a
   vertical drop from its parent's row — the classic CSS org-chart trick. */
.sitemap-tree li::before, .sitemap-tree li::after {
  content: ''; position: absolute; top: 0; right: 50%; width: 50%; height: 26px; border-top: 2px solid var(--border);
}
.sitemap-tree li::after { right: auto; left: 50%; border-left: 2px solid var(--border); }
.sitemap-tree li:only-child::before, .sitemap-tree li:only-child::after { display: none; }
.sitemap-tree li:only-child { padding-top: 0; }
.sitemap-tree li:first-child::before, .sitemap-tree li:last-child::after { border: 0 none; }
.sitemap-tree li:last-child::before { border-right: 2px solid var(--border); }
.sitemap-tree > ul > li::before, .sitemap-tree > ul > li::after { display: none; }
/* Vertical drop from a parent node into its own row of children — without
   this, only sibling-to-sibling connectors draw and each branch looks
   disconnected from the node above it. */
.sitemap-tree ul ul::before {
  content: ''; position: absolute; top: 0; left: 50%; width: 0; height: 26px; border-left: 2px solid var(--border);
}
.sitemap-node {
  display: inline-block; border: 1.5px solid var(--border); border-radius: 8px; padding: 10px 14px;
  background: #fff; text-align: left; white-space: normal; min-width: 160px;
}
.sitemap-node-title { font-weight: 600; font-size: .9rem; text-decoration: none; color: var(--text); }
.sitemap-node-title:hover { color: var(--accent); }
.sitemap-node-external { font-weight: 600; font-size: .9rem; background: #eef4fb; border-color: #bcd6ee; max-width: 220px; }
.sitemap-node-external .sitemap-node-stats span { word-break: break-all; }
.sitemap-node-external > a { color: var(--text); text-decoration: none; word-break: break-all; }
.sitemap-node-external > a:hover { color: var(--accent); }
.sitemap-node-stats { display: flex; flex-direction: column; gap: 2px; margin-top: 6px; font-size: .74rem; color: var(--text-muted); }
.sitemap-orphans { display: flex; flex-wrap: wrap; gap: 12px; }
.sitemap-orphan .sitemap-tree { padding-bottom: 0; }
.sitemap-orphan .sitemap-node { min-width: 180px; }
.sitemap-node-label { background: var(--bg-alt, #f6f5f3); font-weight: 600; font-size: .9rem; text-align: center; }
.sitemap-node-footer-only { background: #edf7ee; border-color: #b7ddb9; }
.sitemap-node-footer-only::after {
  content: 'Footer only'; display: inline-block; margin-top: 6px; font-size: .68rem; font-weight: 600;
  letter-spacing: .03em; text-transform: uppercase; color: #3f8a45;
}

/* Navigation — card-based list. Each top-level page is a card; its dropdown
   children sit nested inside the same group so dragging keeps them together. */
.nav-cards { display: flex; flex-direction: column; gap: 10px; }
.nav-card-group { border: 1px solid var(--border); border-radius: 8px; background: #fff; transition: background .1s, border-color .1s; }
.nav-card-group.drag-zone-before { box-shadow: 0 -3px 0 var(--accent); }
.nav-card-group.drag-zone-after { box-shadow: 0 3px 0 var(--accent); }
.nav-card-group.drag-zone-into { background: var(--surface); border-color: var(--accent); }
.nav-card { display: flex; align-items: center; gap: 10px; padding: 10px 12px; }
.nav-card-children { display: flex; flex-direction: column; gap: 6px; padding: 0 12px 10px 34px; }
.nav-card-children:empty { padding-bottom: 0; }
.nav-card-child { display: flex; align-items: center; gap: 10px; padding: 8px 10px; background: var(--surface); border-radius: 6px; border: 1px solid transparent; }
.nav-card-child.drag-over-top { border-top-color: var(--accent); }
.nav-card-child.drag-over-bottom { border-bottom-color: var(--accent); }
.nav-drag-handle { cursor: grab; color: var(--text-muted); font-size: .9rem; line-height: 1; user-select: none; letter-spacing: -2px; flex-shrink: 0; }
.nav-drag-handle:active { cursor: grabbing; }
.nav-card-label { flex: 1; font-size: .9rem; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nav-card-badge { font-size: .72rem; color: var(--text-muted); background: var(--surface); padding: 2px 8px; border-radius: 20px; flex-shrink: 0; }
.nav-card-child .nav-card-badge { background: #fff; }

/* Edit / add modal */
.nav-edit-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.5); z-index: 6000; align-items: center; justify-content: center; }
.nav-edit-modal { background: #fff; border-radius: 10px; padding: 24px 28px; width: 100%; max-width: 420px; max-height: 86vh; overflow-y: auto; }
.nav-edit-modal h3 { margin-top: 0; }

/* ---------------- Page editor ---------------- */
.editor-topbar {
  display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 12px;
  padding: 14px 24px; border-bottom: 1px solid var(--border); background: #fff; flex-shrink: 0;
}
.editor-topbar-fields { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.editor-topbar-fields .form-control { margin-bottom: 0; width: auto; }
#meta-title { width: 220px; }
#meta-slug { width: 160px; }
.editor-slug-prefix { color: var(--text-muted); }
.editor-topbar-actions { display: flex; align-items: center; gap: 10px; }

.editor-wrap { display: flex; flex: 1; min-height: 0; }
.editor-palette { width: 190px; flex-shrink: 0; border-right: 1px solid var(--border); padding: 16px 12px; overflow-y: auto; background: var(--surface); }
.editor-canvas { flex: 1; padding: 24px; overflow-y: auto; background: #fbfaf8; min-width: 240px; }
.editor-settings { width: 300px; flex-shrink: 0; padding: 20px; overflow-y: auto; background: #fff; display: flex; flex-direction: column; }

/* A settings field that should take up whatever vertical space is left in
   the panel instead of a fixed height — used by the Custom HTML editor
   so it isn't a short box with empty panel below it. */
.settings-field-grow { flex: 1; display: flex; flex-direction: column; min-height: 220px; }

/* Custom HTML editor — CodeMirror (self-hosted, see the <script> tags in
   admin_page_editor()), sized to fill the settings panel like the old
   editor did. */
.code-editor-wrap { position: relative; flex: 1; min-height: 180px; border: 1px solid var(--border); border-radius: 5px; overflow: hidden; }
.code-editor-wrap .CodeMirror { height: 100%; font-family: ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; font-size: .78rem; line-height: 1.5; }
.code-editor-fallback-textarea {
  position: absolute; inset: 0; margin: 0; padding: 8px 10px; box-sizing: border-box; border: none; resize: none;
  font-family: ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; font-size: .78rem; line-height: 1.5;
}
.editor-resize-handle { width: 7px; flex-shrink: 0; cursor: col-resize; position: relative; background: transparent; }
.editor-resize-handle::after { content: ''; position: absolute; top: 0; bottom: 0; left: 3px; width: 1px; background: var(--border); }
.editor-resize-handle:hover::after, .editor-resize-handle.dragging::after { left: 2px; width: 3px; background: var(--accent); }

.palette-item {
  padding: 10px 12px; margin-bottom: 6px; background: #fff; border: 1.5px solid var(--border); border-radius: 6px;
  cursor: grab; font-size: .85rem; text-align: center; transition: background .15s, color .15s, border-color .15s;
}
.palette-item:hover { border-color: var(--accent); }
.palette-item.armed { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }

/* Palette hover preview — a small illustrative diagram + description,
   positioned just to the right of whichever block-type button is
   hovered (see showPaletteTooltip() in editor.js). */
.palette-tooltip {
  display: none; position: fixed; z-index: 400; width: 220px; padding: 12px;
  background: #fff; border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 10px 30px rgba(0,0,0,.15);
  pointer-events: none;
}
.palette-tooltip-svg { display: block; width: 100%; height: 90px; border-radius: 5px; background: var(--surface); margin-bottom: 10px; }
.palette-tooltip strong { display: block; font-size: .9rem; margin-bottom: 4px; }
.palette-tooltip p { margin: 0; font-size: .78rem; color: var(--text-muted); line-height: 1.4; }

.editor-block {
  position: relative; background: #fff; border: 1.5px solid var(--border); border-radius: 8px; margin-bottom: 14px;
  padding: 12px 14px; cursor: grab;
}
.editor-block.selected { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(139,115,85,.15); }
.editor-block.drag-over-top { border-top: 3px solid var(--accent); }
.editor-block.drag-over-bottom { border-bottom: 3px solid var(--accent); }
.editor-block-hidden { opacity: .55; }
.editor-block-header { display: flex; justify-content: space-between; align-items: center; font-size: .82rem; color: var(--text-muted); margin-bottom: 6px; }
.editor-block-header-label { display: flex; align-items: center; gap: 8px; }
.editor-block-hidden-badge { font-size: .68rem; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: #b8860b; background: #fdf6e8; padding: 1px 7px; border-radius: 20px; }
.editor-block-header-actions { display: flex; gap: 8px; align-items: center; }
.editor-block-icon-btn {
  display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px;
  background: none; border: none; border-radius: 5px; color: var(--text-muted); cursor: pointer;
}
.editor-block-icon-btn:hover { background: var(--surface); color: var(--text); }
.editor-block-icon-btn.editor-block-remove:hover { background: #fbecec; color: #c0392b; }
.editor-block-icon-btn svg { width: 15px; height: 15px; }
.editor-block-preview { font-size: .85rem; color: var(--text); pointer-events: none; display: flex; flex-direction: column; gap: 3px; }
.editor-block-preview-line { color: var(--text-muted); }
.editor-block-preview-primary { color: var(--text); font-weight: 500; }
.editor-canvas-empty { color: var(--text-muted); text-align: center; padding: 60px 0; }

/* ---------------- Page history (split-screen version compare) ---------------- */
.history-layout { display: flex; flex: 1; min-height: 0; }
.history-versions { width: 220px; flex-shrink: 0; border-right: 1px solid var(--border); overflow-y: auto; background: var(--surface); padding: 10px; }
.history-version-item {
  display: flex; flex-direction: column; gap: 2px; width: 100%; text-align: left; padding: 8px 10px; margin-bottom: 4px;
  background: #fff; border: 1.5px solid var(--border); border-radius: 6px; cursor: pointer; font-size: .8rem;
}
.history-version-item:hover { border-color: var(--accent); }
.history-version-item.active { border-color: var(--accent); background: #faf7f2; }
.history-version-when { font-weight: 600; color: var(--text); }
.history-version-title { color: var(--text-muted); font-size: .75rem; }
.history-panes { display: flex; flex: 1; min-width: 0; }
.history-pane { flex: 1; min-width: 0; display: flex; flex-direction: column; border-left: 1px solid var(--border); }
.history-pane:first-child { border-left: none; }
.history-pane-label { padding: 8px 14px; font-size: .8rem; font-weight: 600; color: var(--text-muted); border-bottom: 1px solid var(--border); flex-shrink: 0; }
.history-pane iframe { flex: 1; width: 100%; border: none; }

.settings-field { margin-bottom: 14px; }
.settings-field label { display: block; font-size: .8rem; font-weight: 500; margin-bottom: 4px; }
.settings-field input, .settings-field textarea, .settings-field select { width: 100%; padding: 8px 10px; border: 1.5px solid var(--border); border-radius: 5px; font-family: var(--font-body); font-size: .85rem; }
.settings-field textarea { min-height: 70px; resize: vertical; }
/* height:auto + object-fit:contain (not a fixed cropped height) so the
   whole picked image is visible here — this is a "which image did I pick"
   check, not a crop preview (that's what the focal-point picker below is
   for), so hiding most of the photo to force it into a short fixed box
   made it hard to tell what was actually selected. */
.settings-image-preview { width: 100%; max-height: 260px; object-fit: contain; border-radius: 5px; margin-bottom: 6px; background: var(--surface); }

.text-style-field { padding: 10px 12px; border: 1px solid var(--border); border-radius: 6px; background: var(--surface); margin-top: -4px; }
.text-style-row { display: flex; gap: 14px; margin-top: 4px; }
.text-style-col { flex: 1; }
.text-style-col-size { flex: 2; }
.text-style-sublabel { display: block; font-size: .72rem; color: var(--text-muted); margin-bottom: 4px; }
.text-style-size-row { display: flex; align-items: center; gap: 10px; }
.text-style-size-row input[type="range"] { width: auto; flex: 1; }
.text-style-readout { font-size: .78rem; color: var(--text-muted); min-width: 42px; text-align: right; flex-shrink: 0; }
.text-style-preview-sample {
  margin-top: 10px; padding: 14px; border-radius: 5px; background: var(--bg);
  border: 1px dashed var(--border); text-align: center; overflow-wrap: break-word;
  font-family: var(--font-body); line-height: 1.3; color: var(--text);
}
.text-style-reset-btn { margin-top: 8px; width: 100%; }

.richtext-field { position: relative; }
/* Toolbar sits directly on top of the editable box with no gap between —
   one continuous bordered control, like a normal WYSIWYG editor, rather
   than two separate floating boxes. */
.richtext-toolbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
  padding: 6px; border: 1.5px solid var(--border); border-bottom: none;
  border-radius: 6px 6px 0 0; background: var(--surface);
}
.richtext-btn {
  padding: 5px 9px; border: 1px solid transparent; background: transparent; border-radius: 4px;
  font-size: .78rem; cursor: pointer; line-height: 1; color: var(--text); flex-shrink: 0;
}
.richtext-btn:hover { background: #fff; border-color: var(--border); }
/* Both selectors need the .richtext-toolbar ancestor in them, not just their
   own class — otherwise ".settings-field select"/".settings-field input"
   (a class + a type selector, so higher specificity than a single class)
   wins instead and stretches these to the full field width. */
.richtext-toolbar select.richtext-size-select {
  width: auto; flex-shrink: 0; padding: 4px 6px; border: 1px solid var(--border); border-radius: 4px;
  font-size: .78rem; background: #fff; cursor: pointer;
}
.richtext-toolbar input.richtext-color-input {
  width: 28px; height: 28px; flex-shrink: 0; padding: 2px; border: 1px solid var(--border); border-radius: 4px;
  background: #fff; cursor: pointer;
}
.richtext-editable {
  width: 100%; min-height: 140px; padding: 8px 10px; border: 1.5px solid var(--border); border-radius: 0 0 5px 5px;
  font-family: var(--font-body); font-size: .85rem; line-height: 1.5; overflow-y: auto;
}
.richtext-editable:focus { outline: none; border-color: var(--accent); }
.richtext-editable p { margin: 0 0 .8em; }
.richtext-editable h2, .richtext-editable h3 { font-family: var(--font-heading); margin: 0 0 .4em; }
.richtext-editable ul, .richtext-editable ol { margin: 0 0 .8em; padding-left: 1.4em; }
.richtext-link-popover {
  position: absolute; z-index: 20; top: 100%; left: 0; margin-top: 4px; display: flex; flex-direction: column; gap: 8px;
  padding: 10px; background: #fff; border: 1px solid var(--border); border-radius: 6px; box-shadow: 0 4px 16px rgba(0,0,0,.12);
  min-width: 320px;
}
.richtext-link-popover-row { display: flex; gap: 6px; }
.richtext-link-popover input { padding: 6px 8px; border: 1px solid var(--border); border-radius: 4px; font-size: .8rem; width: 200px; }
.richtext-link-page-select { width: 100%; padding: 6px 8px; border: 1px solid var(--border); border-radius: 4px; font-size: .8rem; }

/* Focal point picker — shows the actual crop (background-position driven by
   the stored x/y), click anywhere to move the marker and reposition it. */
/* Small read-only crop preview next to the "Set focus point" button —
   actual editing happens in the full-size lightbox below. */
.focal-preview-wrap { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; }
.focal-preview { width: 90px; height: 60px; flex-shrink: 0; border-radius: 5px; background-color: var(--surface); background-size: cover; background-repeat: no-repeat; border: 1px solid var(--border); }
.focal-preview-wrap .settings-img-btn { flex-shrink: 0; }

/* Full-size focus-point picker — matches client.jaradlee.co.uk's gallery
   cover picker, so a small inline box never forces a guess at precision. */
.focal-lightbox-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.85); z-index: 8000; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 18px; }
.focal-lightbox-hint { color: #fff; text-align: center; font-size: .92rem; }
.focal-lightbox-hint span { display: block; opacity: .7; font-size: .8rem; margin-top: 2px; }
.focal-lightbox-img-wrap { position: relative; cursor: crosshair; max-width: 90vw; max-height: 68vh; line-height: 0; }
.focal-lightbox-img { max-width: 90vw; max-height: 68vh; display: block; border-radius: 4px; }
.focal-lightbox-marker { position: absolute; width: 20px; height: 20px; margin: -10px 0 0 -10px; border: 2px solid #fff; border-radius: 50%; box-shadow: 0 0 0 1px rgba(0,0,0,.6), 0 1px 6px rgba(0,0,0,.5); pointer-events: none; }
.focal-lightbox-actions { display: flex; gap: 10px; }
.focal-lightbox-cancel { color: #fff; border-color: #fff; background: transparent; }
.settings-pkg { border: 1px solid var(--border); border-radius: 6px; margin-bottom: 10px; overflow: hidden; }
.settings-pkg.drag-over-top { border-top: 3px solid var(--accent); }
.settings-pkg.drag-over-bottom { border-bottom: 3px solid var(--accent); }

/* Gallery/slideshow image manager — a grid of larger cards instead of a
   cramped single-column list, so a gallery with a dozen-plus images is
   still easy to scan, reorder, and caption. */
.mosaic-img-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; }
.mosaic-img-card {
  border: 3px solid transparent; border-radius: 6px; cursor: grab; display: flex; flex-direction: column; gap: 6px;
}
.mosaic-img-card:active { cursor: grabbing; }
.mosaic-img-card.drag-over-before { border-left-color: var(--accent); }
.mosaic-img-card.drag-over-after { border-right-color: var(--accent); }
.mosaic-img-card-thumb { position: relative; aspect-ratio: 1; border-radius: 5px; overflow: hidden; background: var(--surface); }
.mosaic-img-card-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; cursor: zoom-in; }
.mosaic-img-card-drag {
  position: absolute; top: 4px; left: 4px; background: rgba(0,0,0,.55); color: #fff; font-size: .8rem; line-height: 1;
  border-radius: 4px; padding: 3px 5px; cursor: grab; user-select: none;
}
.mosaic-img-card-remove {
  position: absolute; top: 4px; right: 4px; width: 22px; height: 22px; border-radius: 50%; border: none;
  background: rgba(0,0,0,.55); color: #fff; font-size: 1rem; line-height: 1; cursor: pointer;
}
.mosaic-img-card-remove:hover { background: #c0392b; }
.mosaic-img-card-caption { width: 100%; padding: 5px 7px; border: 1px solid var(--border); border-radius: 4px; font-size: .78rem; }
.mosaic-img-card-selects { display: flex; gap: 4px; }
.mosaic-img-card-selects select { flex: 1; min-width: 0; padding: 4px 2px; border: 1px solid var(--border); border-radius: 4px; font-size: .72rem; }

/* Click-a-thumbnail full-screen preview, shared by any settings panel that
   lists images (Mosaic Gallery, Slideshow Hero, ...). */
.img-lightbox-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.85); z-index: 8000; display: flex; align-items: center; justify-content: center; }
.img-lightbox-img { max-width: 92vw; max-height: 92vh; object-fit: contain; border-radius: 4px; }
.img-lightbox-close {
  position: absolute; top: 18px; right: 22px; width: 38px; height: 38px; border-radius: 50%;
  background: #fff; border: none; color: var(--text); font-size: 1.4rem; line-height: 1; cursor: pointer;
  box-shadow: 0 2px 8px rgba(0,0,0,.3);
}
.settings-pkg-head { display: flex; align-items: center; gap: 8px; padding: 8px 10px; cursor: grab; background: var(--surface); }
.settings-pkg-head:active { cursor: grabbing; }
.settings-pkg-handle { color: var(--text-muted); font-size: .85rem; line-height: 1; user-select: none; }
.settings-pkg-chevron { color: var(--text-muted); font-size: .7rem; cursor: pointer; user-select: none; }
.settings-pkg-summary { flex: 1; font-size: .85rem; font-weight: 500; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.settings-pkg-body { padding: 10px; border-top: 1px solid var(--border); }
.settings-pkg-remove, .settings-add-btn, .settings-img-btn { font-size: .78rem; background: none; border: 1px solid var(--border); border-radius: 5px; padding: 4px 8px; cursor: pointer; flex-shrink: 0; }

/* ---------------- Media picker ---------------- */
.media-picker-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.5); z-index: 5000; display: flex; align-items: center; justify-content: center; }
.media-picker-modal { background: #fff; border-radius: 10px; width: 640px; max-width: 92vw; max-height: 80vh; display: flex; flex-direction: column; overflow: hidden; }
.media-picker-header { display: flex; justify-content: space-between; align-items: center; padding: 14px 18px; border-bottom: 1px solid var(--border); flex-shrink: 0; }
/* flex:1 + min-height:0 is what actually makes this scroll — without
   min-height:0 a flex column child won't shrink below its content's
   intrinsic height, so with a big library the grid (and the whole modal)
   just grew past max-height instead of clipping and scrolling internally. */
/* grid-auto-rows needs its own explicit floor here — once this grid is a
   flex item with min-height:0 (needed so it can shrink and actually
   scroll instead of ballooning the modal past max-height, see above),
   giving it a definite cross-size smaller than its content makes
   Chromium's implicit "auto" row tracks compress to fit that size rather
   than overflowing it, squashing every thumbnail down to a sliver instead
   of scrolling. minmax(90px, auto) puts a hard floor under that so rows
   can never shrink below the image height itself. */
.media-picker-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); grid-auto-rows: minmax(90px, auto); gap: 8px; padding: 16px 18px; overflow-y: auto; flex: 1 1 auto; min-height: 0; align-content: start; }
.media-picker-cell { position: relative; cursor: pointer; border-radius: 5px; overflow: hidden; border: 2px solid transparent; line-height: 0; }
.media-picker-cell img { width: 100%; height: 90px; object-fit: cover; display: block; }
.media-picker-cell:hover { border-color: var(--accent); }
.media-picker-cell-selected { border-color: var(--accent); }
.media-picker-tick {
  position: absolute; top: 5px; right: 5px; width: 22px; height: 22px; border-radius: 50%;
  background: var(--accent); color: #fff; font-size: .8rem; font-weight: 700; align-items: center;
  justify-content: center; display: none; box-shadow: 0 1px 4px rgba(0,0,0,.3);
}
.media-picker-cell-selected .media-picker-tick { display: flex; }
/* Already placed in a different block on this page — still clickable (see
   openMediaPicker's override menu) rather than fully disabled, so a photo
   can deliberately be duplicated or moved over instead of only ever being
   locked to whichever block grabbed it first. */
.media-picker-cell-used { opacity: .45; }
.media-picker-cell-used:hover { opacity: .8; }
.media-picker-cell-used.media-picker-cell-selected { opacity: 1; }
.media-picker-footer { padding: 12px 18px; border-top: 1px solid var(--border); flex-shrink: 0; }

.media-picker-override-menu {
  position: fixed; z-index: 5100; background: #fff; border-radius: 8px;
  box-shadow: 0 6px 24px rgba(0,0,0,.25); padding: 6px; display: flex; flex-direction: column; gap: 2px;
  min-width: 220px;
}
.media-picker-override-menu button {
  display: block; width: 100%; text-align: left; background: none; border: none; border-radius: 5px;
  padding: 8px 10px; font-size: .82rem; cursor: pointer; font-family: inherit;
}
.media-picker-override-menu button:hover { background: #f2f0eb; }
.media-picker-override-menu .text-muted { font-size: .7rem; padding: 2px 10px 4px; }

.upload-progress-dropdown { display: inline-block; position: relative; margin-left: 10px; vertical-align: middle; max-width: 320px; }
.upload-progress-toggle {
  background: none; border: none; padding: 0; font-size: .85rem; color: var(--text-muted);
  cursor: pointer; display: inline-flex; align-items: center; gap: 5px; font-family: inherit;
}
.upload-progress-toggle:hover { color: var(--text); }
.upload-progress-toggle-error { color: #c0392b; }
.upload-progress-caret { font-size: .7rem; transition: transform .15s; }
.upload-progress-toggle-open .upload-progress-caret { transform: rotate(180deg); }
.upload-progress-list {
  position: absolute; bottom: 100%; left: 0; margin-bottom: 8px; background: #fff;
  border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,.15);
  padding: 8px; width: 320px; max-height: 240px; overflow-y: auto; z-index: 10;
}
.upload-progress-row { display: flex; align-items: center; gap: 8px; padding: 4px 2px; font-size: .78rem; }
.upload-progress-name { flex: 0 0 90px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-muted); }
.upload-progress-bar { flex: 1 1 auto; height: 5px; border-radius: 3px; background: var(--border); overflow: hidden; }
.upload-progress-bar-fill { height: 100%; width: 0; background: var(--accent); transition: width .15s; }
.upload-progress-pct { flex: 0 0 38px; text-align: right; color: var(--text-muted); }
.upload-progress-row-done .upload-progress-bar-fill { background: #1e7e34; }
.upload-progress-row-done .upload-progress-pct { color: #1e7e34; }
.upload-progress-row-failed .upload-progress-bar-fill { background: #c0392b; width: 100% !important; }
.upload-progress-row-failed .upload-progress-pct { color: #c0392b; cursor: help; font-size: .9rem; }

/* Standalone Media page's drop-to-upload panel — same row styling as the
   picker modal's dropdown above, just always-open in a fixed corner panel
   instead of behind a toggle (there's no adjacent summary button here). */
.media-upload-panel {
  position: fixed; bottom: 20px; right: 20px; z-index: 4100; background: #fff;
  border-radius: 10px; box-shadow: 0 6px 24px rgba(0,0,0,.25); padding: 14px 16px;
  width: 320px; max-height: 70vh; overflow-y: auto;
}
.media-upload-panel-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
.media-upload-panel-title { font-size: .85rem; font-weight: 600; }
.media-upload-panel-close { background: none; border: none; cursor: pointer; color: var(--text-muted); font-size: 1.1rem; line-height: 1; padding: 0; }
.media-upload-panel-close:hover { color: var(--text); }
.media-upload-panel .upload-progress-name { flex-basis: 130px; }

/* ---------------- Page preview modal ---------------- */
/* inset: 4vmin keeps the same gap on every side regardless of aspect
   ratio (vw/vh alone would differ side to side), so the modal reads as a
   single large window rather than a slightly-off-center rectangle. */
.preview-modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.6); z-index: 7000; }
.preview-modal { position: absolute; inset: 4vmin; background: #fff; border-radius: 10px; box-shadow: 0 20px 60px rgba(0,0,0,.3); overflow: hidden; }
.preview-modal-iframe { width: 100%; height: 100%; border: 0; display: block; }
.preview-modal-close {
  position: absolute; top: 10px; right: 14px; z-index: 1; width: 34px; height: 34px; border-radius: 50%;
  background: #fff; border: 1px solid var(--border); color: var(--text); font-size: 1.3rem; line-height: 1;
  cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,.15); transition: background .12s;
}
.preview-modal-close:hover { background: var(--surface); }

/* ---------------- Move-block-to-page modal ---------------- */
.move-block-modal { background: #fff; border-radius: 10px; width: 380px; max-width: 92vw; max-height: 86vh; overflow-y: auto; padding: 20px 22px; }
.move-block-modal h3 { margin: 0 0 14px; font-size: 1.05rem; }
.move-block-modal select { width: 100%; margin-bottom: 16px; }
.move-block-modal-actions { display: flex; gap: 10px; }
.move-block-modal-error { color: var(--danger, #c0392b); font-size: .85rem; margin: -6px 0 12px; }

/* ---------------- Form builder (admin) ---------------- */
/* .form-control sets width:100% globally, which fights flex sizing in a row
   (same class of bug as the earlier checkbox/select width issues) — override
   explicitly rather than relying on flex-basis to win. */
.form-field-row-wrap { margin-bottom: 10px; padding-bottom: 4px; border-bottom: 1px solid var(--border); }
.form-field-row { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.form-field-row input[type=text].form-control { width: auto; flex: 2; margin-bottom: 0; }
.form-field-row select.form-control { width: auto; flex: 1; margin-bottom: 0; }
.form-field-row button { flex-shrink: 0; }

/* ---------------- Public site ---------------- */
.public-site { background: var(--bg); }
/* Sticky by default — a page whose first block is a Hero/Slideshow Hero with
   "Behind the nav bar" checked gets .site-header-overlay instead (fixed,
   transparent-to-solid over the hero); every other page still wants the nav
   pinned while scrolling rather than scrolling away with the page. */
/* -webkit-font-smoothing/-moz-osx-font-smoothing: switching a light/dark
   text-shadow on and off (see nav-use-light-logo below) can otherwise make
   some browsers re-hint glyphs at very slightly different widths, reading
   as the nav text "jumping" a pixel when the state changes. Forcing the
   same antialiasing mode regardless of colour/shadow keeps glyph metrics
   stable across the switch. */
/* Same colour as the page (var(--bg)) and no shadow at the very top — it
   should blend in rather than reading as a separate white bar sitting on
   top of a slightly different-toned page. Only becomes solid white with a
   shadow once there's actually content scrolled underneath it to separate
   from. See the plain-header scroll listener in site.js for the .scrolled
   toggle (the overlay header has its own separate one, for the
   transparent-over-a-hero case). */
.site-header { padding: 20px 40px; transition: background .25s, box-shadow .25s, color .25s; position: sticky; top: 0; z-index: 300; background: var(--bg); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
.site-header.scrolled { background: #fff; box-shadow: 0 2px 10px rgba(0,0,0,.06); }
.site-header-desktop { display: flex; justify-content: space-between; align-items: center; width: 100%; }
/* line-height:0 — the logo is an image, not visible text, so the font's
   own line-height shouldn't contribute any height of its own. Without
   this, swapping the dark/light logo (see nav-use-light-logo below) could
   shift the whole nav bar's height by several pixels: the dark wrap has no
   explicit display and defaults to inline, the light wrap is explicitly
   inline-block, and mixing the two inside a line box with a font strut
   computes a taller line for whichever one is showing at the time. */
.site-logo { font-family: var(--font-heading); font-size: 1.2rem; text-decoration: none; color: inherit; line-height: 0; }
.site-logo-img { max-height: 44px; max-width: 200px; object-fit: contain; vertical-align: middle; }
.site-nav { display: flex; align-items: center; gap: 24px; }
.site-nav a, .nav-dropdown-toggle { text-decoration: none; font-size: .9rem; letter-spacing: .02em; color: inherit; }
.site-nav a:hover, .nav-dropdown-toggle:hover { color: var(--accent); }
.site-main { min-height: 60vh; }

/* Logo-centre layout: nav links split either side of a centred logo (desktop only) */
.site-header.nav-layout-center .site-header-desktop { justify-content: center; gap: 40px; }
.site-header.nav-layout-center .site-nav-left { justify-content: flex-end; flex: 1; }
.site-header.nav-layout-center .site-nav-right { justify-content: flex-start; flex: 1; }

/* Mobile bar (logo left, burger right) — hidden on desktop, shown instead of
   .site-header-desktop below the 860px breakpoint regardless of which
   desktop nav_layout is chosen (logo_left/logo_center only make sense wide). */
.site-header-mobile { display: none; }
.site-logo-mobile { display: flex; align-items: center; text-decoration: none; color: inherit; font-family: var(--font-heading); font-size: .95rem; }
.site-logo-mobile img { max-height: 26px; max-width: 140px; object-fit: contain; }
.mobile-menu-toggle { display: none; background: none; border: none; cursor: pointer; color: inherit; padding: 4px; }
.mobile-menu-panel { display: none; }

/* Dropdown sub-menus — label links to the parent page itself; the chevron
   button is a separate control that only opens/closes the submenu. */
.nav-dropdown { position: relative; display: inline-flex; align-items: center; gap: 4px; }
.nav-dropdown-label { text-decoration: none; font-size: .9rem; letter-spacing: .02em; color: inherit; }
.nav-dropdown-label:hover { color: var(--accent); }
.nav-dropdown-toggle { display: inline-flex; align-items: center; background: none; border: none; font-family: inherit; cursor: pointer; padding: 2px; color: inherit; }
.nav-dropdown-menu {
  position: absolute; top: 100%; left: 50%; margin-top: 14px;
  background: #fff; border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 8px 24px rgba(0,0,0,.1);
  min-width: 180px; width: max-content; max-width: 320px; padding: 6px; display: flex; flex-direction: column; z-index: 200;
  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translate(-50%, -6px);
  transition: opacity .16s ease, transform .16s ease, visibility .16s;
}
.nav-dropdown.open .nav-dropdown-menu { opacity: 1; visibility: visible; pointer-events: auto; transform: translate(-50%, 0); }
.nav-dropdown-menu a { color: var(--text) !important; padding: 8px 12px; border-radius: 5px; font-size: .88rem; white-space: nowrap; transition: background .12s, color .12s; }
.nav-dropdown-menu a:hover { background: var(--surface); color: var(--text) !important; }
.nav-dropdown-toggle svg { transition: transform .18s ease; }
.nav-dropdown.open .nav-dropdown-toggle svg { transform: rotate(180deg); }

/* Overlay header — transparent over a hero, solid once scrolled past it.
   Sits lower and larger while over the hero (like the reference design),
   shrinking back to the compact bar once scrolled. Text/logo colour follows
   whichever logo variant is active (dark logo = dark text, light logo =
   white text) — but scrolled always reverts to dark logo + dark text,
   regardless of which was showing before. */
.site-header-overlay {
  position: fixed; top: 0; left: 0; right: 0; z-index: 300;
  background: transparent; color: var(--text); box-shadow: none;
  /* env(safe-area-inset-top) is 0 on anything without a status bar/notch
     to clear, so this is just 52px everywhere except iOS Safari — where,
     now that viewport-fit=cover lets the hero image itself reach the true
     screen edge, the nav text needs the extra push to not end up behind
     the clock/battery icons instead of below them. */
  padding-top: calc(52px + env(safe-area-inset-top, 0px));
  transition: background .25s, box-shadow .25s, color .25s, padding-top .25s;
}
.site-header-overlay .nav-dropdown-menu a { color: var(--text) !important; text-shadow: none; }
.site-header-overlay .site-logo-img { max-height: 68px; transition: max-height .25s; }
.site-header-overlay .site-logo { font-size: 1.55rem; transition: font-size .25s; }

/* A light-on-light hero (e.g. a pale/overexposed slideshow image) can make
   white nav text nearly disappear — a soft dark shadow keeps it readable
   without looking heavy on a normal dark hero, where it's barely visible. */
.site-header-overlay.nav-use-light-logo { color: #fff; text-shadow: 0 1px 6px rgba(0,0,0,.45); }
.site-header-overlay.nav-use-light-logo .mobile-menu-toggle svg,
.site-header-overlay.nav-use-light-logo .nav-dropdown-toggle svg,
.site-header-overlay.nav-use-light-logo .site-logo-img { filter: drop-shadow(0 1px 4px rgba(0,0,0,.45)); }

.site-header-overlay.scrolled {
  background: #fff; color: var(--text); box-shadow: 0 2px 12px rgba(0,0,0,.08);
  padding-top: calc(20px + env(safe-area-inset-top, 0px)); text-shadow: none;
}
.site-header-overlay.scrolled .mobile-menu-toggle svg,
.site-header-overlay.scrolled .nav-dropdown-toggle svg,
.site-header-overlay.scrolled .site-logo-img { filter: none; }
.site-header-overlay.scrolled .site-logo-img { max-height: 44px; }
.site-header-overlay.scrolled .site-logo { font-size: 1.2rem; }

/* No burger button while transparent over the hero and not yet scrolled —
   only once the header goes solid (.scrolled) does the mobile menu button
   appear. Higher specificity than the plain "show it on mobile" rule below
   (2 classes + :not vs. that rule's 1), so this wins regardless of source
   order once both apply. */
.site-header-overlay:not(.scrolled) .mobile-menu-toggle { display: none; }

/* Light-logo swap — shown only while transparent over the hero; reverts to
   the normal logo once the header goes solid (.scrolled), same as the text.
   Both wraps are inline-block (not the dark wrap's plain-span default) so
   neither one measures differently than the other while swapping. */
.site-logo-dark-wrap { display: inline-block; }
.site-logo-light-wrap { display: none; }
.site-header.nav-use-light-logo:not(.scrolled) .site-logo-dark-wrap { display: none; }
.site-header.nav-use-light-logo:not(.scrolled) .site-logo-light-wrap { display: inline-block; }
.site-footer { padding: 32px 40px; border-top: 1px solid var(--border); font-size: .85rem; color: var(--text-muted); }
.site-footer-simple { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 12px; }
.site-footer-social a { margin-left: 16px; text-decoration: none; }
.site-footer-bottom { margin-top: 28px; padding-top: 20px; border-top: 1px solid var(--border); font-size: .8rem; text-align: center; }

/* Columns footer layout */
.footer-columns-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 32px; }
.footer-col h4 { font-family: var(--font-body); font-weight: 600; font-size: .78rem; text-transform: uppercase; letter-spacing: .06em; color: var(--text); margin: 0 0 12px; }
/* Explicit font-size/color (re-asserting what .site-footer already sets)
   rather than relying on inheritance — the public-site-wide h1/h2/h3/p
   typography rule below matches this same "class + p" specificity, and an
   explicit declaration on the *other* rule is the only way to still win a
   property inheritance would otherwise have supplied for free. */
.footer-col p { margin: 0; line-height: 1.6; font-size: inherit; color: inherit; }
.footer-col-links .footer-links-list { display: flex; flex-direction: column; gap: 8px; }
.footer-links-list a, .footer-col a { text-decoration: none; color: var(--text-muted); }
.footer-links-list a:hover, .footer-col a:hover { color: var(--accent); }
.footer-nav-child { display: block; margin-left: 14px; font-size: .82rem; opacity: .85; }
.footer-social-icons { display: flex; gap: 10px; }
.footer-social-icon { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: 50%; border: 1px solid var(--border); color: var(--text-muted); }
.footer-social-icon:hover { color: var(--accent); border-color: var(--accent); }

/* Centred footer layout */
.site-footer-centered { text-align: center; }
.footer-centered-logo { font-family: var(--font-heading); font-size: 1.15rem; margin-bottom: 18px; }
.footer-centered-logo img { margin: 0 auto; max-height: 44px; }
.footer-centered-nav { display: flex; justify-content: center; flex-wrap: wrap; gap: 22px; margin-bottom: 18px; }
.footer-centered-nav a, .footer-centered-nav .nav-dropdown-toggle { text-decoration: none; color: var(--text-muted); font-size: .88rem; }
.footer-centered-nav a:hover, .footer-centered-nav .nav-dropdown-toggle:hover { color: var(--accent); }
.footer-centered-social { display: flex; justify-content: center; gap: 10px; margin-bottom: 4px; }

/* Minimal footer layout — just social icons + copyright, nothing else */
.footer-minimal-social { display: flex; justify-content: center; gap: 10px; }

/* Split footer layout — logo/about/social on the left, links/contact on
   the right, side by side rather than stacked or in equal columns. The row
   is capped and centered (matching every other block's 1100px content
   width) rather than spanning the full-bleed footer — with only two
   unequal-width groups, space-between across the whole viewport pushed
   them out to the edges and left a huge, lopsided-looking gap between them. */
.footer-split-row { max-width: 1100px; margin: 0 auto; display: flex; flex-wrap: wrap; gap: 40px; justify-content: space-between; }
.footer-split-left { flex: 1 1 260px; }
.footer-split-logo { font-family: var(--font-heading); font-size: 1.15rem; margin-bottom: 12px; }
.footer-split-logo img { max-height: 40px; }
.footer-split-left p { margin: 0 0 14px; line-height: 1.6; }
.footer-split-right { display: flex; gap: 40px; flex-wrap: wrap; justify-content: flex-end; flex: 1 1 260px; }

.public-404 { text-align: center; padding: 100px 20px; }
.public-404 a { text-decoration: underline; }

/* ---------------- Blocks ---------------- */
.block { padding: 0; }

/* Scroll reveal — site.js adds .reveal to each block below the first (the
   hero already has its own entrance) and .in-view once it scrolls into
   view, so a page with JS disabled never has content stuck invisible. */
.reveal { opacity: 0; transform: translateY(18px); transition: opacity .6s ease, transform .6s ease; }
.reveal.in-view { opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  * { scroll-behavior: auto !important; }
}

.block-hero {
  position: relative; height: 82vh; min-height: 420px; background-size: cover;
  background-image: var(--hero-bg-desktop); background-position: var(--hero-pos-desktop, center);
  display: flex; align-items: center; justify-content: center; color: #fff; text-align: center;
}
.block-hero-overlay { position: absolute; inset: 0; }
.block-hero-content { position: relative; z-index: 1; max-width: 700px; padding: 0 24px; }
.block-hero-content h1 { font-size: clamp(2rem, 5vw, 3.4rem); color: #fff; }
.block-hero-content p { font-size: 1.1rem; opacity: .92; color: #fff; }
.block-hero-cta {
  display: inline-block; margin-top: 20px; padding: 12px 28px; border: 1.5px solid #fff; border-radius: 4px;
  color: #fff; text-decoration: none; font-size: .9rem; letter-spacing: .04em;
  transition: background .18s, color .18s, transform .18s;
}
.block-hero-cta:hover { background: #fff; color: var(--text); transform: translateY(-2px); }

/* Slideshow Hero — images cross-fade untouched (no darkening overlay);
   text legibility comes from a shadow on the text itself, not the image. */
.block-slideshow-hero {
  position: relative; height: 82vh; min-height: 420px; overflow: hidden;
  display: flex; align-items: center; justify-content: center; color: #fff; text-align: center;
}
/* 100lvh after the 100vh fallback (see render_block_hero() in blocks.php
   for the equivalent on the plain Hero) — lets the image reach behind
   iOS Safari's status bar/bottom toolbar instead of stopping at the
   visible-chrome viewport height. */
.block-slideshow-hero.block-hero-full { height: 100vh; height: 100lvh; }
.slideshow-items { position: absolute; inset: 0; }
.slideshow-item { position: absolute; inset: 0; background-size: cover; background-position: center; opacity: 0; transition: opacity 1.4s ease; }
.slideshow-item.active { opacity: 1; }
.block-slideshow-hero .block-hero-content { text-shadow: 0 2px 16px rgba(0,0,0,.45); }
.block-slideshow-hero .block-hero-content h1 { color: #fff; }

/* Optional manual prev/next controls (see "show_arrows" in the block's
   settings) — a bare icon with just enough shadow to read on any photo,
   not a solid button, so it stays out of the way of the image itself
   until a visitor actually reaches for it. */
.slideshow-arrow {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 32px; height: 32px; border-radius: 50%; border: none; background: transparent; color: #fff;
  cursor: pointer; display: flex; align-items: center; justify-content: center;
  opacity: .7; filter: drop-shadow(0 1px 3px rgba(0,0,0,.5));
  transition: opacity .15s, background .15s;
}
.slideshow-arrow:hover { opacity: 1; background: rgba(0,0,0,.2); }
.slideshow-arrow-prev { left: 14px; }
.slideshow-arrow-next { right: 14px; }

.block-mosaic { padding: 60px 40px; }
.block-mosaic-title { text-align: center; margin-bottom: 32px; }
/* Real grid columns (not CSS `column-count`) so vertical alignment can be
   controlled. Grid rather than flex-wrap deliberately — flex-wrap's grow
   factor stretches a lone wrapped column to fill its whole row, badly
   distorting its width (and thus height) versus its siblings; grid tracks
   stay equal width regardless of wrapping. */
.mosaic-grid { width: 100%; display: grid; grid-template-columns: repeat(var(--mosaic-cols, 4), 1fr); }
.mosaic-grid.mosaic-align-top { align-items: start; }
.mosaic-grid.mosaic-align-center { align-items: center; }
.mosaic-grid.mosaic-align-bottom { align-items: end; }
.mosaic-col { display: flex; flex-direction: column; min-width: 0; }
.mosaic-item { position: relative; cursor: pointer; overflow: hidden; border-radius: 3px; }
.mosaic-item img { width: 100%; height: auto; display: block; transition: transform .3s; }
.mosaic-item:hover img { transform: scale(1.03); }
.mosaic-item-caption { position: absolute; left: 0; right: 0; bottom: 0; padding: 10px 12px; background: linear-gradient(transparent, rgba(0,0,0,.6)); color: #fff; font-size: .8rem; opacity: 0; transition: opacity .2s; }
.mosaic-item:hover .mosaic-item-caption { opacity: 1; }

/* Scrolling Gallery — same reading width as the text blocks (see the
   shared rule below), photos overflow that width sideways via scroll
   rather than the block itself going full-bleed. */
.block-scroll-gallery-title { text-align: center; margin-bottom: 24px; }
.scroll-gallery-track {
  display: flex; overflow-x: auto; padding-bottom: 10px;
  scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch;
}
.scroll-gallery-item { position: relative; flex: 0 0 auto; scroll-snap-align: start; cursor: pointer; }
.scroll-gallery-item img { display: block; border-radius: 6px; }
.scroll-gallery-caption { margin-top: 6px; font-size: .8rem; color: var(--text-muted); }

/* Duo Images — two equal columns, same fixed aspect ratio, cropped via the
   same focal-point mechanism as every other cropped image on the site. */
.duo-grid { display: flex; }
.duo-image { flex: 1 1 0; aspect-ratio: 4 / 5; border-radius: 8px; overflow: hidden; background: var(--surface); }
.duo-image img { width: 100%; height: 100%; object-fit: cover; }
.duo-caption { text-align: center; font-size: .85rem; color: var(--text-muted); margin-top: 14px; }

/* Editorial Photos — three curated overlapping layouts. Every photo slot
   is absolutely positioned as a percentage of .editorial-photos-inner,
   which gets its height from a padding-bottom percentage (the usual
   fluid-aspect-ratio trick) — so the composition scales with the block's
   width without needing JS. Collapses to a plain stacked column below
   860px (the site's usual mobile breakpoint), where overlap stops being
   legible at that size anyway. */
.block-editorial-photos { padding: 60px 40px; max-width: 1100px; margin: 0 auto; }
.editorial-photos-inner { position: relative; }
.editorial-photo { position: absolute; overflow: hidden; border-radius: 4px; background: var(--surface); box-shadow: 0 10px 30px rgba(0,0,0,.18); }
.editorial-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }

.editorial-layout-large_overlap .editorial-photos-inner { padding-bottom: 78%; }
.editorial-layout-large_overlap .editorial-photo-a { left: 0; top: 0; width: 78%; height: 90%; }
.editorial-layout-large_overlap .editorial-photo-b { right: 0; bottom: 0; width: 42%; height: 55%; border: 8px solid #fff; z-index: 2; }

.editorial-layout-offset_pair .editorial-photos-inner { padding-bottom: 68%; }
.editorial-layout-offset_pair .editorial-photo-a { left: 0; top: 0; width: 56%; height: 82%; z-index: 2; }
.editorial-layout-offset_pair .editorial-photo-b { right: 0; bottom: 0; width: 48%; height: 72%; border: 8px solid #fff; z-index: 1; }

.editorial-layout-layered_trio .editorial-photos-inner { padding-bottom: 62%; }
.editorial-layout-layered_trio .editorial-photo-a { left: 27%; top: 8%; width: 46%; height: 84%; z-index: 3; }
.editorial-layout-layered_trio .editorial-photo-b { left: 0; top: 0; width: 36%; height: 60%; z-index: 1; }
.editorial-layout-layered_trio .editorial-photo-c { right: 0; bottom: 0; width: 36%; height: 60%; z-index: 2; }

.editorial-no-border .editorial-photo-b { border: none; }

@media (max-width: 860px) {
  .editorial-photos-inner { padding-bottom: 0 !important; display: flex; flex-direction: column; gap: 16px; }
  .editorial-photo { position: static !important; width: 100% !important; height: auto !important; aspect-ratio: 4 / 5; border: none !important; box-shadow: 0 6px 20px rgba(0,0,0,.12); }
}

.block-text, .block-split, .block-quote, .block-cta, .block-pricing, .block-banner, .block-scroll-gallery, .block-duo, .block-vendor-credits { padding: 60px 40px; max-width: 1100px; margin: 0 auto; }
.block-text-body p { margin: 0 0 1em; color: var(--text); }
.block-text-2col .block-text-body { columns: 2; column-gap: 40px; }

.block-split { display: flex; gap: 48px; align-items: center; }
.block-split.block-split-reverse { flex-direction: row-reverse; }
.block-split-media, .block-split-content { flex: 1; min-width: 0; }
.block-split-media img { width: 100%; border-radius: 6px; }

.block-banner { max-width: none; padding: 0; height: 50vh; min-height: 300px; background-size: cover; background-position: center; position: relative; }
.block-banner-caption { position: absolute; bottom: 20px; left: 40px; color: #fff; font-size: .9rem; background: rgba(0,0,0,.45); padding: 6px 14px; border-radius: 4px; }
.block-banner-text { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 0 24px; color: #fff; }
/* h2.../p... (element + class) rather than just .block-banner-heading —
   matches the specificity of the public-site-wide h1/h2/h3/p typography
   rule so these still win on font-size/color (declared explicitly here,
   needed for legibility over a photo) instead of losing a tie to source
   order, or losing outright to a plain class selector's lower specificity. */
h2.block-banner-heading { font-size: 2.2rem; margin: 0 0 10px; text-shadow: 0 2px 12px rgba(0,0,0,.45); color: #fff; }
p.block-banner-subheading { font-size: 1.15rem; margin: 0; max-width: 600px; text-shadow: 0 2px 12px rgba(0,0,0,.45); color: #fff; }

.block-banner-plain { height: auto; min-height: 0; background: transparent !important; padding: 70px 40px; max-width: 1100px; margin: 0 auto; text-align: center; }
.block-banner-plain .block-banner-text { position: static; color: inherit; padding: 0; }
.block-banner-plain .block-banner-heading { color: var(--text); text-shadow: none; font-size: clamp(1.8rem, 3.2vw, 2.6rem); font-weight: 700; }
.block-banner-plain .block-banner-subheading { color: var(--text-muted); text-shadow: none; font-size: 1.25rem; max-width: none; }
.block-banner-plain .block-banner-caption { position: static; display: inline-block; margin-top: 12px; color: var(--text); background: none; padding: 0; }

/* "Behind the nav bar" (see Banner's settings): the header switches from
   sticky (reserving its own space) to fixed (reserving none), which shifts
   this block — and its centred text with it — up by the header's own
   height. Without this, the text ends up exactly where the logo now
   floats instead of staying where it visually sat before the checkbox was
   ticked. Scoped with a sibling selector to the actual rendered state
   (header has .site-header-overlay, this banner is truly the first block)
   rather than needing a PHP-side class of its own. Desktop/mobile need
   different amounts since the single-line mobile bar is much shorter. */
.site-header-overlay ~ .site-main > .block-banner:first-child .block-banner-text { padding-top: 140px; }
@media (max-width: 860px) {
  .site-header-overlay ~ .site-main > .block-banner:first-child .block-banner-text { padding-top: 90px; }
}

.block-quote { text-align: center; }
.block-quote blockquote { font-family: var(--font-heading); font-size: 1.6rem; font-style: italic; margin: 0 0 12px; }
/* CSS-generated curly quotes, not text interpolated server-side — the
   quote text is now rich HTML (see richTextField() in editor.js) rather
   than a single plain string, so there's no one place left to wrap
   &ldquo;/&rdquo; around. blockquote's own :first-child/:last-child p
   covers the common case of a single paragraph of quote text. */
.block-quote blockquote > :first-child::before { content: '\201C'; }
.block-quote blockquote > :last-child::after { content: '\201D'; }
.block-quote cite { color: var(--text-muted); font-style: normal; font-size: .9rem; }

.block-cta { text-align: center; }
.block-cta-btn { display: inline-block; margin-top: 16px; padding: 12px 28px; background: var(--text); color: #fff; text-decoration: none; border-radius: 4px; font-size: .9rem; transition: transform .18s, box-shadow .18s; }
.block-cta-btn:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(0,0,0,.15); }

.block-pricing-title { text-align: center; margin-bottom: 40px; }
.pricing-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 24px; }
.pricing-card { border: 1.5px solid var(--border); border-radius: 10px; padding: 28px 24px; text-align: center; overflow: hidden; transition: transform .2s, box-shadow .2s; }
.pricing-card:hover { transform: translateY(-4px); box-shadow: 0 10px 28px rgba(0,0,0,.1); }
.pricing-card-highlight { border-color: var(--accent); box-shadow: 0 4px 24px rgba(139,115,85,.15); }
.pricing-card-highlight:hover { box-shadow: 0 10px 32px rgba(139,115,85,.22); }
.pricing-card-image { width: calc(100% + 48px); max-width: none; height: 180px; object-fit: cover; margin: -28px -24px 20px; display: block; }
.pricing-card-name { font-family: var(--font-heading); font-size: 1.15rem; margin-bottom: 6px; }
.pricing-card-price { font-size: 1.6rem; font-weight: 600; margin-bottom: 16px; }
.pricing-card-price-heading { font-family: var(--font-heading); }
.pricing-card-features { list-style: none; padding: 0; margin: 0 0 20px; font-size: .88rem; color: var(--text-muted); }
.pricing-card-features li { padding: 6px 0; border-bottom: 1px solid var(--border); }
.pricing-card-cta { display: inline-block; padding: 10px 22px; border: 1.5px solid var(--text); border-radius: 4px; text-decoration: none; font-size: .85rem; transition: background .16s, color .16s; }
.pricing-card-cta:hover { background: var(--text); color: #fff; }
.pricing-card-highlight .pricing-card-cta:hover { opacity: .85; }
.pricing-card-highlight .pricing-card-cta { background: var(--text); color: #fff; }

/* Optional background image — cards become frosted glass over the photo.
   The darken/lighten slider (block-pricing-overlay) sits as a plain flat
   layer between the background image and the content, rather than a CSS
   filter on the section itself — a filter would also wash out the cards
   sitting on top of it, not just the photo behind them. */
.block-pricing-has-bg { position: relative; max-width: none; background-size: cover; background-position: center; padding: 90px 40px; }
.block-pricing-overlay { position: absolute; inset: 0; pointer-events: none; }
.block-pricing-has-bg .block-pricing-title,
.block-pricing-has-bg .pricing-grid { position: relative; z-index: 1; }
.block-pricing-has-bg .block-pricing-title { color: #fff; text-shadow: 0 2px 14px rgba(0,0,0,.45); }
.block-pricing-has-bg.pricing-title-dark .block-pricing-title { color: #1a1a1a; text-shadow: 0 2px 14px rgba(255,255,255,.55); }
.block-pricing-has-bg .pricing-grid { max-width: 1100px; margin: 0 auto; }
.block-pricing-has-bg .pricing-card { background: rgba(255,255,255,var(--pricing-card-opacity, .86)); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); border-color: rgba(255,255,255,.6); }
.block-pricing-has-bg .pricing-card-highlight { border-color: var(--accent); }

/* Link Cards — image + title + button, no price/features (see the Pricing
   block above for that). Column count is configurable, unlike Pricing's
   auto-fit, so a 3-item "My Work" style grid doesn't wrap oddly at 4. */
.block-cardgrid { padding: 60px 40px; max-width: 1100px; margin: 0 auto; }
.block-cardgrid-title { text-align: center; margin-bottom: 40px; }
/* Flexbox, not CSS Grid — a grid's unused explicit column tracks (e.g. 2
   cards in a 3-column layout) still reserve their space and leave the
   populated cards stranded on the left. Flexbox with justify-content:center
   sizes each card as if the row were full (via the same --cardgrid-cols
   variable) but centers a short row as a group instead. */
.cardgrid-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 24px; }
.cardgrid-card { flex: 0 0 calc((100% - (var(--cardgrid-cols, 3) - 1) * 24px) / var(--cardgrid-cols, 3)); max-width: calc((100% - (var(--cardgrid-cols, 3) - 1) * 24px) / var(--cardgrid-cols, 3)); }
.cardgrid-card { border: 1.5px solid var(--border); border-radius: 10px; padding: 24px; text-align: center; overflow: hidden; transition: transform .2s, box-shadow .2s; }
.cardgrid-card:hover { transform: translateY(-4px); box-shadow: 0 10px 28px rgba(0,0,0,.1); }
.cardgrid-card-image { width: calc(100% + 48px); max-width: none; height: 200px; object-fit: cover; margin: -24px -24px 20px; display: block; transition: transform .3s; }
.cardgrid-card:hover .cardgrid-card-image { transform: scale(1.04); }
.cardgrid-card-title { font-family: var(--font-heading); font-size: 1.15rem; margin-bottom: 6px; }
.cardgrid-card-text { font-size: .9rem; color: var(--text-muted); margin-bottom: 16px; }
.cardgrid-card-cta { display: inline-block; padding: 10px 22px; border: 1.5px solid var(--text); border-radius: 4px; text-decoration: none; font-size: .85rem; transition: background .16s, color .16s; }
.cardgrid-card-cta:hover { background: var(--text); color: #fff; }

/* Testimonials — same quote/cite idea as the single Quote block, repeated
   in a grid with a name/subtitle attribution instead of one plain <cite>. */
.block-testimonials { padding: 60px 40px; max-width: 1100px; margin: 0 auto; }
.block-testimonials-title { text-align: center; margin-bottom: 40px; }
.testimonials-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 24px; }
.testimonial-card { flex: 0 0 calc((100% - (var(--testimonials-cols, 3) - 1) * 24px) / var(--testimonials-cols, 3)); max-width: calc((100% - (var(--testimonials-cols, 3) - 1) * 24px) / var(--testimonials-cols, 3)); }
.testimonial-card { border: 1.5px solid var(--border); border-radius: 10px; padding: 28px 24px; transition: transform .2s, box-shadow .2s; }
.testimonial-card:hover { transform: translateY(-4px); box-shadow: 0 10px 28px rgba(0,0,0,.08); }
.testimonial-card blockquote { margin: 0 0 16px; font-family: var(--font-heading); font-style: italic; font-size: 1.05rem; line-height: 1.5; }
.testimonial-stars { color: var(--accent); letter-spacing: 2px; margin-bottom: 10px; font-size: .95rem; }
.testimonial-attr { display: flex; flex-direction: column; font-size: .85rem; }
.testimonial-name { font-weight: 600; }
.testimonial-subtitle { color: var(--text-muted); }

/* Vendor Credits — a plain role/name list, centred, the way a wedding
   feature's closing credits block is conventionally laid out. */
.block-vendor-credits-title { text-align: center; margin-bottom: 28px; font-size: .95rem; text-transform: uppercase; letter-spacing: .08em; color: var(--text-muted); }
.vendor-credits-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 20px 48px; text-align: center; }
.vendor-credit-item { min-width: 120px; }
.vendor-credit-role { font-size: .72rem; text-transform: uppercase; letter-spacing: .08em; color: var(--text-muted); margin-bottom: 4px; }
.vendor-credit-name { font-family: var(--font-heading); font-size: 1.05rem; }
.vendor-credit-name a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }

/* Video — a responsive 16:9 embed, sized by padding-top rather than
   aspect-ratio so it degrades the same way in any browser this site
   otherwise supports. */
.block-video { max-width: 900px; margin: 0 auto; padding: 60px 40px; }
.block-video-title { text-align: center; margin-bottom: 24px; }
.video-embed-wrap { position: relative; width: 100%; padding-top: 56.25%; border-radius: 8px; overflow: hidden; background: #000; }
.video-embed-wrap iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.block-video-caption { text-align: center; color: var(--text-muted); font-size: .85rem; margin-top: 14px; }

/* Stats — a plain flex row; wraps on its own at narrow widths rather than
   needing a configurable column count like the grid-based blocks. */
.block-stats { padding: 60px 40px; max-width: 1000px; margin: 0 auto; }
.block-stats-title { text-align: center; margin-bottom: 36px; }
.stats-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 40px 60px; text-align: center; }
.stat-number { font-family: var(--font-heading); font-size: 2.4rem; color: var(--accent); line-height: 1; }
.stat-label { margin-top: 8px; font-size: .9rem; color: var(--text-muted); }

/* FAQ — native <details>/<summary>, no JS needed for expand/collapse. */
.block-faq { padding: 60px 40px; max-width: 800px; margin: 0 auto; }
.block-faq-title { text-align: center; margin-bottom: 32px; }
.faq-item { border-bottom: 1px solid var(--border); padding: 18px 0; }
.faq-question { cursor: pointer; font-family: var(--font-heading); font-size: 1.05rem; list-style: none; display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.faq-question::-webkit-details-marker { display: none; }
.faq-question::after { content: '+'; font-size: 1.3rem; color: var(--accent); flex-shrink: 0; transition: transform .15s; }
.faq-item[open] .faq-question::after { transform: rotate(45deg); }
.faq-answer { padding-top: 12px; color: var(--text-muted); line-height: 1.6; }
.faq-answer p { margin: 0 0 .8em; }
.faq-answer p:last-child { margin-bottom: 0; }

.block-spacer { width: 100%; }
hr.block-divider { display: block; height: 0; }
.block-divider-ornament { display: flex; align-items: center; gap: 16px; }
.block-divider-line { flex: 1 1 auto; height: 1px; background: currentColor; }
.block-divider-symbol { flex: 0 0 auto; font-size: 1.1rem; line-height: 1; }

.block-html { max-width: 1100px; margin: 0 auto; padding: 20px 40px; }
.block-html img { max-width: 100%; height: auto; }
.block-html iframe, .block-html video, .block-html embed { max-width: 100%; }

.block-form { max-width: 620px; margin: 0 auto; padding: 40px 40px; }
.block-form-heading { text-align: center; margin-bottom: 24px; }
.block-form-body { text-align: center; color: var(--text-muted); margin: -12px 0 24px; }
.block-form-body p { margin: 0 0 .8em; }
.block-form-body p:last-child { margin-bottom: 0; }
.block-form-form { display: flex; flex-direction: column; gap: 16px; }
.block-form-field { display: flex; flex-direction: column; gap: 6px; font-size: .9rem; color: var(--text); }
.block-form-required { color: var(--accent); }
.block-form-field input, .block-form-field textarea {
  font-family: var(--font-body); font-size: .95rem; padding: 10px 14px; border: 1.5px solid var(--border);
  border-radius: 6px; color: var(--text); background: #fff;
}
.block-form-field textarea { resize: vertical; }
.block-form-options { display: flex; flex-direction: column; gap: 8px; }
.block-form-option { display: flex; align-items: center; gap: 8px; font-size: .9rem; font-weight: 400; cursor: pointer; }
.block-form-option input[type=checkbox], .block-form-option input[type=radio] {
  width: auto; padding: 0; border: none; flex-shrink: 0;
}
.block-form-honeypot { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.btn-form-submit {
  align-self: flex-start; padding: 12px 28px; background: var(--accent); color: #fff; border: none;
  border-radius: 4px; font-size: .9rem; letter-spacing: .04em; cursor: pointer;
}
.btn-form-submit:hover { opacity: .9; }
.block-form-success { text-align: center; font-size: 1.05rem; padding: 20px 0; }
.block-form-error { color: #c0392b; font-size: .85rem; margin: -6px 0 0; }

/* ---------------- Lightbox ---------------- */
.lightbox { position: fixed; inset: 0; background: rgba(0,0,0,.9); z-index: 9000; display: flex; align-items: center; justify-content: center; }
.lightbox img { max-width: 90vw; max-height: 90vh; object-fit: contain; }
.lightbox-close { position: absolute; top: 20px; right: 30px; background: none; border: none; color: #fff; font-size: 2rem; cursor: pointer; }

/* ---------------- Cookie consent banner ---------------- */
.cookie-banner {
  display: none; position: fixed; left: 0; right: 0; bottom: 0; z-index: 6000;
  background: var(--accent); color: #fff; padding: 16px 24px; align-items: center; justify-content: space-between;
  gap: 20px; flex-wrap: wrap; box-shadow: 0 -4px 20px rgba(0,0,0,.2);
}
.cookie-banner.open { display: flex; }
.cookie-banner p { margin: 0; font-size: .85rem; color: #f3ece2; max-width: 640px; }
.cookie-banner p a { color: #fff; }
.cookie-banner-actions { display: flex; gap: 10px; flex-shrink: 0; }
.cookie-banner-actions .btn-outline { color: #fff; border-color: rgba(255,255,255,.5); }
.cookie-banner-actions .btn-outline:hover { border-color: #fff; }

@media (max-width: 860px) {
  .editor-wrap { flex-direction: column; }
  .editor-palette, .editor-settings { width: 100% !important; }
  .editor-resize-handle { display: none; }
  .block-split { flex-direction: column; }
  .block-split.block-split-reverse { flex-direction: column; }
  /* Falls back to the desktop image/position when no mobile override was
     uploaded — var() with a fallback means this rule is harmless either way. */
  .block-hero { background-image: var(--hero-bg-mobile, var(--hero-bg-desktop)); background-position: var(--hero-pos-mobile, var(--hero-pos-desktop, center)); }
  .slideshow-item[data-device="desktop"] { display: none; }
  .site-header { padding: 14px 20px; }
  .site-header-desktop { display: none; }
  .site-header-mobile { display: flex; align-items: center; justify-content: space-between; width: 100%; position: relative; }
  .mobile-menu-toggle { display: flex; align-items: center; }
  /* Mirrors the desktop "logo centred" choice — burger stays pinned to the
     right edge (still reachable with a thumb) while the logo centers in
     the remaining space rather than sitting flush left. */
  .site-header-mobile-center { justify-content: center; }
  .site-header-mobile-center .mobile-menu-toggle { position: absolute; right: 0; top: 50%; transform: translateY(-50%); }
  .mobile-menu-panel {
    display: flex; flex-direction: column; position: absolute; top: 100%; left: 0; right: 0;
    background: #fff; color: var(--text); padding: 6px 20px 20px; box-shadow: 0 10px 28px rgba(0,0,0,.14);
    max-height: calc(100vh - 60px); overflow-y: auto; z-index: 250;
    opacity: 0; visibility: hidden; pointer-events: none; transform: translateY(-8px);
    transition: opacity .18s ease, transform .18s ease, visibility .18s;
  }
  .mobile-menu-panel.open { opacity: 1; visibility: visible; pointer-events: auto; transform: translateY(0); }
  .mobile-menu-panel a { display: block; padding: 12px 0; text-decoration: none; color: var(--text); font-size: .95rem; border-bottom: 1px solid var(--border); transition: color .12s, padding-left .12s; }
  .mobile-menu-panel a:hover { color: var(--accent); padding-left: 4px; }
  .mobile-menu-panel .footer-nav-child { margin-left: 14px; font-size: .85rem; opacity: .85; }
  .block-hero, .block-mosaic, .block-text, .block-split, .block-quote, .block-cta, .block-pricing, .block-cardgrid, .block-testimonials, .block-faq { padding: 40px 20px; }
  /* !important since the desktop column count is set inline (a plain
     stylesheet rule can't win against that) — overrides the custom
     property itself, not grid-template-columns directly, so site.js's
     masonry rebuild (which reads this same variable) re-packs into the
     right number of columns instead of just squeezing the desktop-packed
     columns into fewer grid tracks, which used to leave mismatched
     column heights and gaps at this breakpoint. */
  .mosaic-grid { --mosaic-cols: 2 !important; }
  .cardgrid-card, .testimonial-card { flex-basis: calc(50% - 12px) !important; max-width: calc(50% - 12px) !important; }
  .footer-columns-row { grid-template-columns: 1fr 1fr; gap: 24px; }
  .site-footer { padding: 32px 20px; }

  /* Split footer layout — desktop's logo/about-left, links/contact-right
     arrangement reads as lopsided once everything stacks to one column on
     a phone. Centre the logo/about/social group, and give the links and
     contact columns an even 50/50 split instead of each just sizing to
     its own content (which left them unevenly indented). */
  .footer-split-left { text-align: center; }
  .footer-split-logo { display: flex; justify-content: center; }
  .footer-social-icons { justify-content: center; }
  /* flex-basis 50% plus the row's existing 40px gap adds up to more than
     100% (50% + 50% + 40px), which is exactly enough to overflow and
     trigger flex-wrap back to one stacked column — gap has to come out of
     each column's own share via calc(), not sit on top of two full halves. */
  .footer-split-right { justify-content: space-between; gap: 20px; }
  .footer-split-right .footer-col { flex: 1 1 calc(50% - 10px); max-width: calc(50% - 10px); }
}

@media (min-width: 861px) {
  .slideshow-item[data-device="mobile"] { display: none; }
}

@media (max-width: 480px) {
  /* Mosaic Gallery deliberately stays at 2 columns even on a phone (see the
     860px breakpoint above) rather than dropping to 1 — a single column of
     full-width photos scrolls a lot further for a gallery. */
  .cardgrid-card, .testimonial-card { flex-basis: 100% !important; max-width: 100% !important; }
  .footer-columns-row { grid-template-columns: 1fr; }
}
