/* ══════════════════════════════════════════════════════════════════════════════
   geo-ui.css - the app's shared, phone-first patterns.

   Edward, 20 Sep: "uniform style, so you have one style that can be reused instead of
   inline style" and "97%" of people are on a phone. Every page here was built as a
   desktop layout that merely also loads at 390px, and the results were not small
   problems: on /clients/{id} a paragraph rendered 24px wide over 27 lines - one
   character per line - and /sites drew a 1962px table on a 390px screen.

   The rules below are the app's answer to the handful of shapes that keep breaking:
     .geo-row    a row of [icon] [words] [action] that WRAPS instead of squeezing
     .geo-table  a table that becomes one card per row on a phone
     .geo-meta   small print that never drops below a readable size

   They are written to sit on top of Tailwind without fighting it: add the class beside
   the utilities that are already there. Both themes are covered - the app's pages are
   light by default and dark under html[data-theme="dark"].
   ══════════════════════════════════════════════════════════════════════════════ */

:root {
  /* One scale, the same seven steps the chat panel uses, so the app and the panel
     agree instead of drifting apart. */
  --geo-t-xs: 11px;
  --geo-t-sm: 12px;
  --geo-t-md: 13px;
  --geo-t-base: 14px;
  --geo-t-lg: 15px;
  --geo-t-xl: 20px;
  --geo-s-1: 4px; --geo-s-2: 8px; --geo-s-3: 12px; --geo-s-4: 16px; --geo-s-5: 24px;
  --geo-r: 12px;

  --geo-line: var(--geo-border);
  --geo-card: var(--geo-surface);
  --geo-faint: var(--geo-muted);
}
html[data-theme="dark"] {
  --geo-line: var(--geo-border);
  --geo-card: var(--geo-surface);
  --geo-faint: var(--geo-muted);
}

/* ── .geo-row ──────────────────────────────────────────────────────────────────
   The shape that broke: [icon] [flex-1 min-w-0 words] [shrink-0 button]. With
   min-w-0 the words column shrinks to nothing rather than pushing the button onto
   its own line, so the text ends up one word - or one letter - per line.

   The fix is a flex-basis, not a media query: the words ask for 15rem, and when the
   action cannot fit beside that, the action wraps under it. It behaves correctly at
   every width, including ones nobody thought to test. */
.geo-row { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--geo-s-3) var(--geo-s-4); }
.geo-row > .geo-row-ico { flex: none; }
.geo-row > .geo-row-main { flex: 1 1 15rem; min-width: 0; }
.geo-row > .geo-row-act { flex: none; margin-left: auto; }
@media (max-width: 640px) {
  /* Once it has wrapped, a lone button hugging the right edge looks like a mistake.
     Full width reads as the row's action. */
  .geo-row > .geo-row-act { width: 100%; margin-left: 0; }
  .geo-row > .geo-row-act > button,
  .geo-row > .geo-row-act > a,
  .geo-row > .geo-row-act > form,
  .geo-row > .geo-row-act > form > button { width: 100%; }
}

/* ── .geo-table ────────────────────────────────────────────────────────────────
   A table is a grid of columns, and a phone has room for about two. Below 640px each
   row becomes a card and each cell carries its own heading, taken from data-cell.

   Requirements on the markup: put .geo-table on the <table>, and data-cell="Domain"
   on every <td> that should be labelled. geo-table.js fills any missing data-cell from the
   column's heading; a column with no heading (an actions cell) stays unlabelled. */
@media (max-width: 640px) {
  .geo-table thead {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  .geo-table, .geo-table tbody, .geo-table tr, .geo-table td { display: block; width: auto; }
  /* A minimum width beats display:block: /leads stacked its cells correctly and the stack
     was still 900px across, because the table carried min-width: 900px from a utility
     class (measured live, 21 Sep). Below 640px a minimum width is never what we want. */
  .geo-table { min-width: 0 !important; max-width: 100%; }
  .geo-table tr {
    margin: 0 0 var(--geo-s-2); padding: var(--geo-s-3);
    border: 1px solid var(--geo-line); border-radius: var(--geo-r); background: var(--geo-card);
  }
  .geo-table td {
    padding: 3px 0 !important; text-align: left !important;
    white-space: normal !important; overflow: visible !important;
  }
  .geo-table td > * { white-space: normal; }
  .geo-table td[data-cell]::before {
    content: attr(data-cell); display: block;
    font-size: var(--geo-t-xs); font-weight: 600; line-height: 1.5;
    color: var(--geo-faint);
  }
  /* The spacer rows that separate one client's sites from the next are a table
     device; as a card they are an empty box. */
  .geo-table tr.geo-table-gap { display: none; }
  /* A row kept closed until somebody opens it (an AI reply under its question) stays closed: "display: block" above
     outranked Tailwind's .hidden, so every reply opened at once on a phone (design window, 18 Oct: ~6,500px page). */
  .geo-table tr.hidden, .geo-table tr[hidden] { display: none; }
  /* The wrapper that gave the table a sideways scrollbar has nothing left to scroll. */
  .geo-table-wrap { overflow-x: visible !important; }
}

/* ── .geo-clamp-2 ──────────────────────────────────────────────────────────────
   `truncate` shows one line and an ellipsis. In a desktop table that is right; in a
   narrow phone row it means about twenty-five characters of a question and then nothing,
   which is not a question any more. Below 640px the text wraps to two lines instead.
   Put it BESIDE truncate - the wide layout keeps truncating. */
@media (max-width: 640px) {
  .geo-clamp-2 {
    overflow: hidden; text-overflow: clip; white-space: normal !important;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  }
}

/* ── The floating buttons ──────────────────────────────────────────────────────
   "Fix my visibility" and "Need help?" stack in the bottom-right of every page. Together
   they are about 210x130 on a 390px screen - a fifth of the width - and page content
   scrolls underneath them. The primary one keeps its words; the support one becomes a
   round icon, which is what every app does with it on a phone.

   !important because that button carries an inline style in the layout, and an inline
   style beats a stylesheet. One !important is cheaper than rewriting a shared button for
   a phone-only change. */
@media (max-width: 640px) {
  #support-fab {
    width: 46px !important; height: 46px !important; padding: 0 !important;
    justify-content: center !important; gap: 0 !important;
    bottom: 16px !important; right: 16px !important;
    font-size: 0 !important; line-height: 0 !important;
  }
  #support-fab svg { width: 20px !important; height: 20px !important; }
  /* The primary one sits above it, clear of the shrunken circle. */
  #gfd-launch { bottom: 74px; right: 16px; padding: 10px 14px; font-size: 13px; }
  /* And the page can scroll past both of them, so the last card is never trapped. */
  body:not(.gfd-panel-open) { padding-bottom: 96px; }
}

/* ── .geo-meta ─────────────────────────────────────────────────────────────────
   Small print that stays readable. 10px column headings were being rendered on a
   phone; that is below what a phone can comfortably read at arm's length. */
.geo-meta { font-size: var(--geo-t-xs) !important; }

/* ══════════════════════════════════════════════════════════════════════════════
   Table tools - copy, export, search, sort.
   Driven by public/js/geo-table.js, which attaches itself to every .geo-table
   with three rows or more. Written once here so a table gets the same small
   functions wherever it appears, instead of each screen inventing its own.
   ══════════════════════════════════════════════════════════════════════════ */

.geo-tt {
  display: flex; align-items: center; gap: var(--geo-s-3);
  flex-wrap: wrap;
  /* Room to breathe, and the same inset as the table's own cells - a toolbar
     flush against the card's edge reads as a mistake (23 Sep). */
  padding: var(--geo-s-3) var(--geo-s-4);
  margin: 0;
}
.geo-tt-count {
  font-size: var(--geo-t-md); color: var(--geo-muted, var(--geo-faint));
  margin-right: auto; white-space: nowrap;
}
.geo-tt-search {
  flex: 1 1 8rem; min-width: 0; max-width: 18rem;
  font-size: var(--geo-t-base); line-height: 1.4;
  min-height: 36px; padding: 6px var(--geo-s-3);
  border: 1px solid var(--geo-border, var(--geo-line)); border-radius: var(--geo-r-ctrl, 10px);
  background: var(--geo-surface2, var(--geo-card)); color: inherit;
}
.geo-tt-search:focus { outline: 2px solid var(--geo-accent); outline-offset: 1px; }
.geo-tt-btn {
  font-size: var(--geo-t-md); font-weight: 600; line-height: 1;
  min-height: 36px; padding: 0 var(--geo-s-4); white-space: nowrap;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--geo-border2, var(--geo-line)); border-radius: var(--geo-r-ctrl, 999px);
  background: transparent; color: var(--geo-text, var(--geo-faint));
  cursor: pointer; transition: color .12s, border-color .12s;
}
.geo-tt-btn:hover { color: var(--geo-text); border-color: var(--geo-accent); }
.geo-tt-btn.is-said { color: var(--geo-good); border-color: var(--geo-good); }
.geo-tt-none {
  font-size: var(--geo-t-sm); color: var(--geo-faint);
  text-align: center; padding: var(--geo-s-4) var(--geo-s-2);
}

/* ── Rows per page, and pages (plan item 7) ─────────────────────────────────
   A long table stops being a list and becomes a scroll. The size picker and the
   two arrows sit in the same bar as everything else, in the same shapes. */
.geo-tt-size {
  font-size: var(--geo-t-md); font-weight: 600; line-height: 1;
  min-height: 36px; padding: 0 var(--geo-s-3);
  border: 1px solid var(--geo-border, var(--geo-line)); border-radius: var(--geo-r-ctrl, 10px);
  background: var(--geo-surface2, var(--geo-card)); color: var(--geo-text);
}
.geo-tt-pager { display: inline-flex; align-items: center; gap: var(--geo-s-2); }
.geo-tt-where { font-size: var(--geo-t-md); color: var(--geo-muted, var(--geo-faint)); white-space: nowrap; }
.geo-tt-btn.geo-tt-page {
  min-width: 36px; padding: 0 var(--geo-s-2);
  font-size: 15px; line-height: 1;
}
.geo-tt-btn.geo-tt-page:disabled { opacity: .4; cursor: not-allowed; border-color: var(--geo-border); }
.geo-tt-btn.geo-tt-page:disabled:hover { color: var(--geo-text); border-color: var(--geo-border); }
@media (max-width: 640px) {
  .geo-tt-size, .geo-tt-pager { order: 4; }
  .geo-tt-btn.geo-tt-page { min-width: 44px; min-height: 44px; }
  .geo-tt-size { min-height: 44px; }
}

/* A sortable heading says so, quietly, and says which way it is sorted. */
th.geo-tt-sortable { cursor: pointer; user-select: none; }
th.geo-tt-sortable:hover { color: var(--geo-accent); }
th.geo-tt-sortable.is-asc::after  { content: " \2191"; font-weight: 400; }
th.geo-tt-sortable.is-desc::after { content: " \2193"; font-weight: 400; }

html[data-theme="dark"] .geo-tt-btn:hover { color: var(--geo-text); border-color: var(--geo-accent); }
html[data-theme="dark"] .geo-tt-btn.is-said { color: var(--geo-good); border-color: var(--geo-good); }

/* On a phone the count and the buttons share one line; the search box takes the next. */
@media (max-width: 640px) {
  .geo-tt-search { order: 3; flex-basis: 100%; max-width: none; }
  .geo-tt-btn { padding: 5px var(--geo-s-2); }
}

/* The sort picker exists only where the headings do not.
   Below 640px the stacked layout hides thead, which takes the sort control with it - and
   97% of our people are on a phone. The picker says the same thing in words. */
.geo-tt-sort { display: none; }
@media (max-width: 640px) {
  .geo-tt-sort {
    display: block; order: 2;
    font-size: var(--geo-t-xs); font-weight: 600; line-height: 1.5;
    padding: 5px var(--geo-s-2); max-width: 11rem;
    border: 1px solid var(--geo-line); border-radius: 999px;
    background: var(--geo-card); color: var(--geo-faint);
  }
}

/* On paper the buttons are not buttons. A printed table should be the table. */
@media print {
  .geo-tt { display: none !important; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   Backlinks screen - /sites/{id}/backlinks and its partials.
   Moved here from <style> blocks inside the views (21 Sep): one shared stylesheet,
   not styles written into each page.
   ══════════════════════════════════════════════════════════════════════════ */

.bl-tab.is-on { color: var(--geo-accent); border-color: var(--geo-accent); }
html[data-theme="dark"] .bl-tab.is-on { color: var(--geo-accent); border-color: var(--geo-accent); }
.bl-panel[hidden] { display: none; }

/* Quick filters: pressed looks pressed. The rows they hide are hidden by the TABLE carrying
   a class, so Copy and Export (which ask the browser what is showing) take only what is left. */
.geo-tt-btn[aria-pressed="true"],
html[data-theme="dark"] .geo-tt-btn[aria-pressed="true"] {
  color: var(--geo-text); border-color: var(--geo-text);
  background: color-mix(in oklab, var(--geo-accent) 12%, transparent);
}
/* One class more specific than the phone grid below, so a filtered row stays hidden on a
   phone too - with equal weight the later grid rule would have shown it again. */
table.geo-table.bl-hide-lost     tr[data-lost]     { display: none; }
table.geo-table.bl-hide-broken   tr[data-broken]   { display: none; }
table.geo-table.bl-hide-nofollow tr[data-nofollow] { display: none; }

/* Charts. Colour by role so light and dark swap together. Values from the dataviz reference
   palette, validated against our card surface in both modes: slot 1 blue, and the blue/red
   diverging pair for new against lost (colour-blind separation 21.6 light, 19.2 dark). */
/* DATA colours, not chrome. This blue/red pair was validated for colourblind
   separation; green-and-red is the pair that fails it, so these stay as measured
   values and do NOT become accent/good/bad (tried and reverted, 23 Sep). */
.bl-viz { --bl-line: #2a78d6; --bl-new: #2a78d6; --bl-lost: #e34948; --bl-base: #c3c2b7; }
html[data-theme="dark"] .bl-viz { --bl-line: #3987e5; --bl-new: #3987e5; --bl-lost: #e66767; --bl-base: #383835; }
/* One continuous baseline across the whole chart, drawn on the container - not a stub under
   each bar, which made the axis look broken wherever the months spread apart. Thin marks:
   past 28px a bar reads as a block, so wide screens spread the months instead. */
.bl-bars { display: flex; align-items: stretch; justify-content: space-between; gap: 2px; height: 140px;
           background: linear-gradient(var(--bl-base), var(--bl-base)) 0 50% / 100% 1px no-repeat; }
.bl-col  { flex: 1 1 0; min-width: 0; max-width: 28px; display: flex; flex-direction: column; cursor: default; }
.bl-up, .bl-down { flex: 1 1 0; display: flex; }
/* A 2px gap each side of the baseline, so a bar never sits on the line. */
.bl-up   { align-items: flex-end; padding-bottom: 2px; }
.bl-down { align-items: flex-start; padding-top: 2px; }
/* 4px rounded at the data end, square where the bar meets the baseline. */
.bl-bar-new  { width: 100%; background: var(--bl-new);  border-radius: 4px 4px 0 0; min-height: 1px; }
.bl-bar-lost { width: 100%; background: var(--bl-lost); border-radius: 0 0 4px 4px; min-height: 1px; }
.bl-col:hover .bl-bar-new, .bl-col:hover .bl-bar-lost { filter: brightness(1.15); }
.bl-key { display: inline-block; width: 8px; height: 8px; border-radius: 2px; margin-right: 4px; }
.bl-key-new  { background: var(--bl-new); }
.bl-key-lost { background: var(--bl-lost); }

/* The toolbar sits inside the table's rounded border; give it room to breathe. */
.geo-table-wrap > .geo-tt { padding: var(--geo-s-2) var(--geo-s-3) 0; }

/* Backlinks tables on a phone.
   The shared stacking turns every cell into its own labelled line, which made a link an
   8-line card and ten links a 4,800px page (measured 21 Sep). OpenSEO's table is built for a
   desktop; this is where we do better. Words run full width; numbers sit three to a row. */
@media (max-width: 640px) {
  table.geo-table[data-bl-table] tr {
    /* The fourth column is the date: wider, so "12 Mar 2025" never breaks in two. */
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.7fr);
    column-gap: var(--geo-s-2); row-gap: 2px;
  }
  table.geo-table[data-bl-table] td.bl-k-date,
  table.geo-table[data-bl-table] td.bl-k-date * { white-space: nowrap !important; }
  table.geo-table[data-bl-table] td { grid-column: 1 / -1; }
  /* Numbers and the date share one row, four across. */
  table.geo-table[data-bl-table] td.bl-k-num,
  table.geo-table[data-bl-table] td.bl-k-dec,
  table.geo-table[data-bl-table] td.bl-k-date { grid-column: auto; }
  /* No badges, no line - and badges need no heading: "Lost" says what it is. */
  table.geo-table[data-bl-table] td.bl-k-flags:not(:has(span)) { display: none; }
  table.geo-table[data-bl-table] td.bl-k-flags::before { content: none; }
  /* Target and anchor read as themselves on a phone, so they lose their headings: the target
     gets an arrow ("→ /pricing") and the anchor its quotation marks. Two lines saved per link. */
  table.geo-table[data-bl-table] td.bl-k-path::before {
    content: "\2192\00a0"; display: inline; font-weight: 400;
  }
  table.geo-table[data-bl-table] td.bl-k-anchor::before { content: none; }
  table.geo-table[data-bl-table] td.bl-k-anchor > span.break-words::before { content: "\201C"; }
  table.geo-table[data-bl-table] td.bl-k-anchor > span.break-words::after  { content: "\201D"; }
  /* Tab descriptions stay, but smaller: they are a note, not a heading. */
  .bl-tab-help { font-size: var(--geo-t-xs); }
  table.geo-table[data-bl-table] td.bl-k-source { padding-bottom: 4px !important; }
}

/* ── Site page header (sites/show.php, 22 Sep) ──────────────────────────────────
   The freshness ring and dot: green under 14 days, amber to 30, red after, blue while an
   audit runs. The words beside them always say the same thing, so colour is never the
   only signal. The More menu is a dropdown on a laptop and a sheet from the bottom on a
   phone, where the thumb already is. */
.site-head-ring, .site-head-fresh { --fresh: var(--geo-muted); }
.site-head-ring[data-fresh="fresh"],   .site-head-fresh[data-fresh="fresh"]   { --fresh: var(--geo-good); }
.site-head-ring[data-fresh="aging"],   .site-head-fresh[data-fresh="aging"]   { --fresh: var(--geo-warn); }
.site-head-ring[data-fresh="stale"],   .site-head-fresh[data-fresh="stale"]   { --fresh: var(--geo-bad); }
.site-head-ring[data-fresh="running"], .site-head-fresh[data-fresh="running"] { --fresh: var(--geo-accent); }
.site-head-ring {
  width: 56px; height: 56px; border-radius: 16px; padding: 3px;
  background: conic-gradient(var(--fresh) var(--arc, 0%), rgba(148, 163, 184, .18) 0);
}
.site-head-ring[data-fresh="running"] { animation: site-head-spin 2.4s linear infinite; }
.site-head-avatar {
  width: 100%; height: 100%; border-radius: 13px; display: flex; align-items: center;
  justify-content: center; font-weight: 700; font-size: 18px; color: var(--geo-accent-ink);
  box-shadow: 0 0 0 2px var(--geo-bg);
}
.site-head-fresh { color: var(--geo-muted); }
.site-head-dot { width: 8px; height: 8px; border-radius: 999px; background: var(--fresh); flex: none; }
.site-head-fresh[data-fresh="stale"] > span:last-child { color: var(--geo-bad); }
@keyframes site-head-spin { 50% { opacity: .55; } }
@media (prefers-reduced-motion: reduce) { .site-head-ring[data-fresh="running"] { animation: none; } }
@media (max-width: 767px) { .site-head-ring { width: 48px; height: 48px; border-radius: 14px; } .site-head-avatar { border-radius: 11px; font-size: 16px; } }

.site-head-sites { scrollbar-width: none; }
.site-head-sites::-webkit-scrollbar { display: none; }
@media print { #site-run-audit, .site-sections { display: none !important; } }

/* ── Phone bar (partials/phone_bar.php, 22 Sep) ─────────────────────────────────
   Five doors in the thumb zone below 768px. Above that the side menu does the job, so the
   bar is gone. Content gets room at the bottom so the bar never covers the last row, and
   the floating help button steps up above it; the agent's own floating button hides on a
   phone because "Ask" in the bar is the same door. */
#geo-phonebar { display: none; }
@media (max-width: 767px) {
  #geo-phonebar {
    display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); align-items: center;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 29; /* under the menu's backdrop (30), so the open menu dims it */
    padding: 6px 6px calc(6px + env(safe-area-inset-bottom, 0px));
    background: color-mix(in oklab, var(--geo-panel) 96%, transparent); border-top: 1px solid var(--geo-border);
    -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  }
  #geo-phonebar > a, #geo-phonebar > button {
    position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 3px; min-height: 52px; background: none; border: 0; color: var(--geo-muted);
    font: inherit; font-size: 11px; text-decoration: none; cursor: pointer; -webkit-tap-highlight-color: transparent;
  }
  #geo-phonebar [data-on="1"] { color: var(--geo-text); font-weight: 600; }
  #geo-phonebar svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8;
    stroke-linecap: round; stroke-linejoin: round; }
  #geo-phonebar .geo-pb-ask { width: 46px; height: 30px; border-radius: 999px; background: var(--geo-accent);
    display: flex; align-items: center; justify-content: center; }
  #geo-phonebar .geo-pb-ask svg { width: 19px; height: 19px; stroke: var(--geo-accent-ink); stroke-width: 2; }
  #geo-phonebar .geo-pb-dot { position: absolute; top: 8px; left: calc(50% + 7px); width: 8px; height: 8px;
    border-radius: 999px; background: var(--geo-accent); box-shadow: 0 0 0 2px var(--geo-panel); }
  body:has(#geo-phonebar) #main-content { padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }
  body:has(#geo-phonebar) #gfd-launch { display: none !important; }
  body:has(#geo-phonebar) #support-fab { bottom: calc(80px + env(safe-area-inset-bottom, 0px)) !important; }
  body.gfd-panel-open #geo-phonebar { display: none; }
  /* One door to the full menu: the bar's Menu, in thumb reach. The corner hamburger goes. */
  body:has(#geo-phonebar) #mobile-header > .mh-menu { display: none; }
  body:has(#geo-phonebar) #mobile-header > img, body:has(#geo-phonebar) #mobile-header > span { margin-left: 0; }
}
@media print { #geo-phonebar { display: none !important; } }

/* ── Nothing on a phone is wider than the phone (22 Sep) ──────────────────────────
   A <select> is as wide as its longest option, so one long client name made /tasks and
   /reports 517-534px wide on a 390px phone - which also drags every fixed element (the
   phone bar) off the right edge. Form fields never grow past their container on a phone.
   Found and re-checked by scripts/phone_width_sweep.js. */
@media (max-width: 767px) {
  #main-content select,
  #main-content input:not([type="checkbox"]):not([type="radio"]),
  #main-content textarea { max-width: 100%; }
  /* A grid cell or a flex-1 column is as wide as its longest unbreakable line by default. A
     "truncate" client name is exactly that - nowrap - so Home's Client Health column grew to
     the full "Premier Roofing of Jacksonville, LLC" and the page rendered 499px wide on a
     390px phone, dragging the phone bar with it (Edward's screenshot, 25 Sep). Letting cells
     shrink is what makes truncate truncate. */
  #main-content .grid > *,
  #main-content .flex-1 { min-width: 0; }
}

/* Light-theme + contrast pass (22 Sep, review of light screenshots):
   - the menu's fade is a thin band at its very bottom edge only. The first version faded the
     last 100px of the VISIBLE menu at all times, hiding real items (Action Items, Clients) -
     a check that tested behaviour, not looks, could not see it.
   - small print in the new header, switcher and phone bar reaches 4.5:1 in light mode
   - the active menu item's bar matches its text colour in light mode
   - the help bubble steps aside while the phone menu is open */
.sidebar nav { -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 44px), transparent calc(100% - 12px));
  mask-image: linear-gradient(to bottom, #000 calc(100% - 44px), transparent calc(100% - 12px)); }
html[data-theme="light"] .site-head label.text-gray-400, html[data-theme="light"] .site-head .text-gray-400 { color: var(--geo-text2) !important; }
html[data-theme="light"] .site-head-sites .text-xs.text-gray-500 { color: var(--geo-text2); }
body:has(.sidebar.open) #support-fab { display: none !important; }

/* ── A site's sections on its own pages (partials/site_sections.php, 22 Sep) ───────────
   Laptop: the tab row (Tailwind classes in the partial). Phone: ONE sandwich button on the
   page naming the section you are in; it opens every section as a full-width list. */
.site-sections-m > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: 10px;
  min-height: 48px; padding: 0 14px; border-radius: 12px;
  /* Tokens, not fixed greys: this was the last blue-grey surface the sweep found. */
  background: var(--geo-surface); border: 1px solid var(--geo-border); color: var(--geo-text); }
.site-sections-m > summary::-webkit-details-marker { display: none; }
.site-sections-m > summary svg { width: 20px; height: 20px; flex: none; fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round; }
.site-sections-m .site-sections-now { font-weight: 600; font-size: 15px; }
.site-sections-m .site-sections-hint { margin-left: auto; font-size: 12px; color: var(--geo-muted); }
.site-sections-m .site-sections-chev { width: 16px; height: 16px; color: var(--geo-muted); transition: transform .15s; }
.site-sections-m[open] .site-sections-chev { transform: rotate(180deg); }
.site-sections-list { margin-top: 6px; padding: 6px; border-radius: 12px;
  background: var(--geo-panel); border: 1px solid var(--geo-border); }
.site-sections-list > a, .site-sections-list > button { display: flex; align-items: center; justify-content: space-between;
  width: 100%; min-height: 48px; padding: 0 12px; border: 0; border-radius: 10px; background: none; color: var(--geo-text2);
  font: inherit; font-size: 15px; text-align: left; text-decoration: none; }
.site-sections-list > a:hover, .site-sections-list > button:hover { background: var(--geo-surface2); color: var(--geo-text); }
.site-sections-list [aria-current="page"] { background: var(--geo-surface2); color: var(--geo-text); box-shadow: inset 3px 0 0 var(--geo-accent); font-weight: 600; }
.site-sections-list small { color: var(--geo-muted); font-size: 12px; }
html[data-theme="light"] .site-sections-m .site-sections-hint, html[data-theme="light"] .site-sections-m .site-sections-chev,
html[data-theme="light"] .site-sections-list > a:hover, html[data-theme="light"] .site-sections-list > button:hover,
/* Kept from the menu review: room for the floating agent button on a laptop, brighter chip text. */
@media (min-width: 768px) { body:has(#gfd-launch) #main-content { padding-bottom: 96px; } }
.site-head-sites .opacity-60, .site-head-sites .opacity-70 { opacity: .85; }
/* ── A website's sections, grouped (18 Oct; OpenSEO check, interface point 1) ────────────
   Every section in view on a laptop, under a small group name (AI visibility, Google, This
   website), Settings at the end. It replaced the Research ▾ dropdown, which hid eight tools.
   The phone list carries the same group names as headings, and each section's one line. */
.site-tab-group-name { padding: 6px 12px 0; font-size: 11px; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--geo-muted); }
.site-tab-group-end { margin-left: auto; }
/* Spacing lives here, not in Tailwind classes: tailwind.build.css is compiled and has no
   gap-x-6 or xl:px-3. Tighter below 1280px, so each group stays on one line at 1024. */
.site-tab-row { column-gap: 16px; row-gap: 4px; }
.site-tab-row .site-tab-btn { padding: 10px 6px; }
@media (min-width: 1280px) { .site-tab-row { column-gap: 24px; } .site-tab-row .site-tab-btn { padding: 10px 12px; } }
.site-sections-list small { display: block; margin-top: 1px; }
/* each row: name and line on the left, the count on the right; a section, not a link colour */
.site-sections-list > a > span:first-child, .site-sections-list > button > span:first-child { flex: 1; min-width: 0; text-align: left; }
.main-content .site-sections-list > a { color: var(--geo-text2) !important; text-decoration: none !important; }
.main-content .site-sections-list > a[aria-current="page"] { color: var(--geo-text) !important; }
.site-sections-list > a, .site-sections-list > button { padding-top: 6px; padding-bottom: 6px; }
.site-sections-group { padding: 12px 12px 4px; font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--geo-muted); }
body:has(.site-sections-m[open]) #support-fab { display: none !important; }

/* While someone types in a field, the floating help and agent buttons step aside - they must
   never sit on top of what is being written (Context review, 22 Sep). */
body:has(#main-content textarea:focus, #main-content input[type="text"]:focus, #main-content input:not([type]):focus) #support-fab,
body:has(#main-content textarea:focus, #main-content input[type="text"]:focus, #main-content input:not([type]):focus) #gfd-launch { opacity: 0; pointer-events: none; }

/* ── Repeat audits page (schedules/index.php, 18 Oct) ─────────────────────────────
   The heading stacks over the back link on a phone; the pause switch is a track and knob
   inside a 44px tap target (the design system makes every button there 44px tall); the
   chosen How often option is outlined in both themes. */
.sched-head { display: flex; flex-direction: column; gap: 8px; }
@media (min-width: 640px) { .sched-head { flex-direction: row; align-items: flex-start; justify-content: space-between; gap: 16px; } }
.main-content .sched-switch { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px;
  padding: 0; border: 0; background: none !important; cursor: pointer; }
.sched-switch .sched-track { position: relative; display: block; width: 44px; height: 24px; border-radius: 999px;
  background: var(--geo-border2); transition: background .2s; }
.sched-switch[aria-pressed="true"] .sched-track { background: var(--geo-accent); }
.sched-switch .sched-knob { position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 2px rgba(0, 0, 0, .3); transition: transform .2s; }
.sched-switch[aria-pressed="true"] .sched-knob { transform: translateX(20px); }
.sched-switch:focus-visible { outline: 2px solid var(--geo-accent); outline-offset: 2px; border-radius: 999px; }
.main-content .sched-freq input:checked + div { border-color: var(--geo-accent) !important; color: var(--geo-text) !important;
  box-shadow: inset 0 0 0 1px var(--geo-accent); }
.main-content .sched-freq input:focus-visible + div { outline: 2px solid var(--geo-accent); outline-offset: 2px; }

/* ── Search Console for a website (sites/search_console.php, 18 Oct) ──────────────────────
   Tiles reuse rank tracking's .rt-tile; the trend is two small one-series charts (clicks,
   impressions): a 2px accent line on a recessive baseline, a hover label on each day. */
.gsc-bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; margin: 0 0 14px; }
.gsc-ranges { display: flex; flex-wrap: wrap; gap: 6px; }
.gsc-ranges .geo-pill { display: inline-flex; align-items: center; min-height: 36px; padding: 0 14px; border: 1px solid var(--geo-border);
  color: var(--geo-text2); text-decoration: none !important; font-size: 13px; font-weight: 600; }
.gsc-ranges .geo-pill.is-on { border-color: var(--geo-accent); color: var(--geo-text); box-shadow: inset 0 0 0 1px var(--geo-accent); }
@media (min-width: 900px) { .gsc-tiles { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.gsc-vs { font-weight: 500; color: var(--geo-muted); }
.gsc-hint { font-size: 11px; color: var(--geo-muted); }
.gsc-card { background: var(--geo-surface); border: 1px solid var(--geo-border); border-radius: var(--geo-r-card); padding: 14px 16px; margin: 0 0 14px; min-width: 0; }
.gsc-h { font-size: 15px; font-weight: 700; color: var(--geo-text); margin: 0 0 10px; }
.gsc-trends { display: grid; gap: 14px; }
@media (min-width: 900px) { .gsc-trends { grid-template-columns: 1fr 1fr; } }
.gsc-trends figure { margin: 0; min-width: 0; }
.gsc-trends figcaption { font-size: 12px; font-weight: 600; color: var(--geo-text2); margin: 0 0 4px; }
.gsc-spark { display: block; width: 100%; height: 120px; overflow: visible; }
.gsc-spark .gsc-line { fill: none; stroke: var(--geo-accent); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.gsc-spark .gsc-base { stroke: var(--geo-border); stroke-width: 1; vector-effect: non-scaling-stroke; }
.gsc-spark .gsc-hit { fill: transparent; }
.gsc-spark .gsc-hit:hover { fill: var(--geo-surface2); fill-opacity: .6; }
.gsc-grid { display: grid; gap: 0 14px; }
@media (min-width: 1100px) { .gsc-grid { grid-template-columns: 1fr 1fr; } }
.gsc-key { max-width: 32ch; overflow-wrap: anywhere; }
.gsc-note { background: var(--geo-surface); border: 1px solid var(--geo-border); border-radius: var(--geo-r-card); padding: 16px; margin: 0 0 14px; }
.gsc-note-t { font-weight: 700; color: var(--geo-text); }
.gsc-note-warn { border-color: var(--geo-warn); }

.gsc-card .geo-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.gsc-card .geo-table th { padding: 8px 10px; text-align: right; font-size: 11px; font-weight: 700; letter-spacing: .03em;
  text-transform: uppercase; color: var(--geo-text2); border-bottom: 1px solid var(--geo-border); white-space: nowrap; }
.gsc-card .geo-table td { padding: 8px 10px; text-align: right; color: var(--geo-text); border-bottom: 1px solid var(--geo-border);
  font-variant-numeric: tabular-nums; }
.gsc-card .geo-table th:first-child, .gsc-card .geo-table td:first-child { text-align: left; }
.gsc-card .geo-table tbody tr:last-child td { border-bottom: 0; }
.main-content .gsc-ranges .geo-pill { color: var(--geo-text2) !important; }
.main-content .gsc-ranges .geo-pill.is-on { color: var(--geo-text) !important; }
.gsc .geo-btn, [data-gsc-card] .geo-btn { display: inline-flex; align-items: center; justify-content: center; min-height: 44px;
  padding: 0 18px; border-radius: var(--geo-r-ctrl); font-size: 14px; font-weight: 600; text-decoration: none !important; }
/* The open section reads in the text colour in both themes (its Tailwind text-white was white on
   white in light mode for the sections that are their own pages). */
.main-content .site-tab-row .site-tab-btn[aria-current="page"] { color: var(--geo-text) !important; }

/* ── Site audit: speed, severity chips, previous audits (sites/show.php Technical, 18 Oct) ── */
.sa-card { background: var(--geo-surface); border: 1px solid var(--geo-border); border-radius: var(--geo-r-card); padding: 16px; min-width: 0; }
.sa-h { font-size: 15px; font-weight: 700; color: var(--geo-text); margin: 0 0 8px; }
.sa-speed { display: grid; gap: 16px; align-items: start; }
@media (min-width: 900px) { .sa-speed { grid-template-columns: 140px 1fr; } }
.sa-speed-score { display: flex; flex-direction: column; align-items: center; justify-content: center; width: 120px; height: 120px;
  border-radius: 50%; border: 6px solid var(--geo-border2); }
.sa-speed-score[data-band="good"] { border-color: var(--geo-good); }
.sa-speed-score[data-band="ok"] { border-color: var(--geo-warn); }
.sa-speed-score[data-band="poor"] { border-color: var(--geo-bad, #dc2626); }
.sa-speed-score strong { font-size: 32px; line-height: 1; color: var(--geo-text); font-variant-numeric: tabular-nums; }
.sa-speed-score span { font-size: 11px; color: var(--geo-text2); margin-top: 4px; text-align: center; }
.sa-speed-list { display: grid; gap: 10px; margin: 0; }
@media (min-width: 640px) { .sa-speed-list { grid-template-columns: 1fr 1fr; } }
.sa-speed-list > div { background: var(--geo-surface2); border-radius: var(--geo-r-ctrl); padding: 10px 12px; }
.sa-speed-list dt { font-size: 12px; font-weight: 700; color: var(--geo-text2); }
.sa-speed-list dd { margin: 2px 0; font-size: 20px; font-weight: 700; color: var(--geo-text); font-variant-numeric: tabular-nums; }
.sa-speed-list p { font-size: 12px; color: var(--geo-muted); margin: 0; }
.sa-speed-switch { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 4px 8px; margin: 0 0 12px;
  font-size: 13px; color: var(--geo-text); cursor: pointer; }
.sa-speed-switch small { flex-basis: 100%; text-align: center; font-size: 12px; color: var(--geo-muted); }
.sa-sev { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 14px; }
.main-content .sa-chip { display: inline-flex; align-items: center; gap: 6px; min-height: 36px; padding: 0 12px; border-radius: 999px;
  border: 1px solid var(--geo-border); background: var(--geo-surface) !important; color: var(--geo-text2); font-size: 13px; font-weight: 600; cursor: pointer; }
.main-content .sa-chip.is-on { border-color: var(--geo-accent); color: var(--geo-text); box-shadow: inset 0 0 0 1px var(--geo-accent); }
.sa-chip b { font-variant-numeric: tabular-nums; }
.sa-sev-c, .sa-chip[data-sev="critical"] b { color: var(--geo-bad, #dc2626); }
.sa-sev-w, .sa-chip[data-sev="warning"] b { color: var(--geo-warn); }
.sa-sev-n, .sa-chip[data-sev="notice"] b { color: var(--geo-text2); }
.sa-card .geo-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.sa-card .geo-table th, .sa-card .geo-table td { padding: 8px 10px; text-align: left; border-bottom: 1px solid var(--geo-border); }
.sa-card .geo-table th { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--geo-text2); }
.sa-hist-on td { background: var(--geo-surface2); font-weight: 600; }
.sa-older { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; margin: 0 0 14px; padding: 10px 14px;
  border: 1px solid var(--geo-accent); border-radius: var(--geo-r-card); background: var(--geo-surface); font-size: 14px; color: var(--geo-text); }
/* Problems to fix: its header (design window, 24 Oct). On a phone the title and its line take the full width,
   then progress, the estimate and Download all wrap in a row of their own; side by side from 640px. */
.ta-head { display: flex; flex-direction: column; gap: 12px; }
.ta-head-t { min-width: 0; }
.ta-stats { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; }
.ta-stats .ta-download { margin-left: auto; }
@media (min-width: 640px) {
  .ta-head { flex-direction: row; align-items: center; justify-content: space-between; gap: 16px; }
  .ta-stats { flex-wrap: nowrap; flex-shrink: 0; }
  .ta-stats .ta-download { margin-left: 0; }
}

/* What AI reads on the home page (O-022): the quote is the line agencies show their client. Tokens only. */
.wa-quote { margin: 14px 0 8px; padding: 10px 14px; border-left: 3px solid var(--geo-accent); background: var(--geo-surface2);
  border-radius: 0 var(--geo-r-ctrl) var(--geo-r-ctrl) 0; font-size: 16px; line-height: 1.5; color: var(--geo-text); overflow-wrap: anywhere; }
.wa-quote.wa-empty { font-size: 15px; color: var(--geo-text2); }
.wa-note { margin: 10px 0 0; font-size: 14px; font-weight: 600; color: var(--geo-warn-ink, var(--geo-warn)); }
.wa-fix { margin: 10px 0 0; font-size: 14px; line-height: 1.55; color: var(--geo-text2); }
.wa-fix-link { display: inline-flex; align-items: center; min-height: 44px; margin-top: 4px; color: var(--geo-accent); font-size: 14px; font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }

/* Selected and pressed must win over the outline button (design window, 18 Oct). geo-2026.css
   gives .geo-tt-btn its colour and border with !important, so the two rules above lost: the
   Backlinks sub-tab you're on, and a pressed quick filter, looked exactly like the others. */
.bl-tab.is-on.is-on { color: var(--geo-accent) !important; border-color: var(--geo-accent) !important;
  background: color-mix(in oklab, var(--geo-accent) 10%, transparent) !important; }
.geo-tt-btn[aria-pressed="true"][aria-pressed="true"] { color: var(--geo-text) !important; border-color: var(--geo-text) !important;
  background: color-mix(in oklab, var(--geo-accent) 12%, transparent) !important; }

/* The open site tab is underlined, so its corners stay square: a 999px radius bent the 2px
   underline into a curve under the label (design window, 18 Oct). */
.site-tab-row .site-tab-btn { border-radius: 0; }

/* Google listing check (sites/local_check.php, local SEO 3a, 24 Oct). Tokens only. Rows stack on a phone. */
.lc-run { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; margin: 0 0 16px; }
.lc-run .geo-btn { padding: 0 18px; white-space: nowrap; justify-content: center; }
.lc-when { font-size: 14px; color: var(--geo-text2); }
.lc-note { margin: 12px 0 0; font-size: 14px; line-height: 1.5; color: var(--geo-text2); }
.lc-card { margin: 0 0 16px; padding: 16px; border: 1px solid var(--geo-card-edge); border-radius: var(--geo-r-card); background: var(--geo-surface); color: var(--geo-text); }
.lc-name { margin: 8px 0 2px; font-size: 18px; font-weight: 700; overflow-wrap: anywhere; }
.lc-sub { margin: 2px 0 0; font-size: 14px; color: var(--geo-text2); }
.lc-bad-line, .lc-warn-line, .lc-good-line { margin: 8px 0 0; font-size: 15px; font-weight: 600; line-height: 1.5; }
.lc-bad-line { color: var(--geo-bad-ink); }
.lc-warn-line { color: var(--geo-warn-ink); }
.lc-good-line { margin: 0 0 12px; color: var(--geo-good-ink); }
.lc-table { display: grid; gap: 0; }
.lc-tr { display: grid; grid-template-columns: 9rem 1fr 1fr 6.5rem; gap: 8px 14px; align-items: start; padding: 12px 0;
  border-top: 1px solid var(--geo-border); font-size: 14px; line-height: 1.5; overflow-wrap: anywhere; }
.lc-th { border-top: 0; padding-top: 0; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--geo-text2); }
.lc-tr.is-bad { box-shadow: inset 3px 0 0 var(--geo-bad); padding-left: 10px; }
.lc-tr.is-warn { box-shadow: inset 3px 0 0 var(--geo-warn); padding-left: 10px; }
.lc-th, .lc-tr.is-good, .lc-tr.is-info { padding-left: 10px; }
.lc-k { font-weight: 600; }
.lc-src, .lc-differ { display: block; margin-top: 4px; font-size: 12px; color: var(--geo-text2); }
.lc-differ { font-weight: 600; color: var(--geo-warn-ink); }
.lc-chip { display: inline-block; padding: 2px 8px; border-radius: 999px; border: 1px solid currentColor; font-size: 12px; font-weight: 700; white-space: nowrap; }
.lc-chip.is-bad { color: var(--geo-bad-ink); }
.lc-chip.is-warn { color: var(--geo-warn-ink); }
.lc-chip.is-good { color: var(--geo-good-ink); }
@media (max-width: 640px) {
  .lc-run .geo-btn { width: 100%; }
  .lc-th { display: none; }
  .lc-tr { grid-template-columns: 1fr auto; }
  .lc-k { grid-column: 1; }
  .lc-s { grid-column: 2; grid-row: 1; }
  .lc-g, .lc-o { grid-column: 1 / -1; }
  .lc-g::before { content: attr(data-l); display: block; font-size: 12px; font-weight: 700; color: var(--geo-text2); }
  .lc-o::before { content: attr(data-l); display: block; font-size: 12px; font-weight: 700; color: var(--geo-text2); }
}

/* Domain overview (sites/domain_overview.php, slice 4b, 24 Oct). Tokens only. */
.do-card { margin: 0 0 16px; padding: 16px; border: 1px solid var(--geo-card-edge); border-radius: var(--geo-r-card); background: var(--geo-surface); color: var(--geo-text); }
.do-label { display: block; margin: 0 0 6px; font-size: 13px; font-weight: 600; color: var(--geo-text2); }
.do-run-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.do-input { flex: 1 1 16rem; min-width: 0; min-height: 44px; padding: 0 12px; border: 1px solid var(--geo-border); border-radius: var(--geo-r-ctrl);
  background: var(--geo-surface); color: var(--geo-text); font-size: 15px; }
.do-run .geo-btn { padding: 0 18px; white-space: nowrap; justify-content: center; }
.do-note { margin: 10px 0 0; font-size: 14px; line-height: 1.5; color: var(--geo-text2); }
.do-when { margin: 0 0 10px; font-size: 14px; color: var(--geo-text2); overflow-wrap: anywhere; }
.do-plain { margin: 0; font-size: 15px; line-height: 1.5; color: var(--geo-text2); }
.do-more { display: none; }
.do-recent { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 16px; }
.do-recent-h { font-size: 13px; font-weight: 600; color: var(--geo-text2); }
.do-chip { display: inline-flex; align-items: center; min-height: 32px; padding: 0 12px; border: 1px solid var(--geo-border); border-radius: 999px;
  font-size: 13px; color: var(--geo-text); text-decoration: none; overflow-wrap: anywhere; }
.do-chip.is-on { border-color: var(--geo-accent); color: var(--geo-accent); font-weight: 600; }
.do-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.do-stats .do-card { margin-bottom: 16px; }
.do-stat-h { margin: 0; font-size: 14px; font-weight: 600; color: var(--geo-text2); }
.do-stat-n { margin: 6px 0 4px; font-size: 28px; font-weight: 700; line-height: 1.1; color: var(--geo-text); }
.do-sub { margin: 0; font-size: 13px; line-height: 1.45; color: var(--geo-text2); }
.do-table th, .do-table td { padding: 8px 12px; text-align: left; vertical-align: top; border-bottom: 1px solid var(--geo-border); font-size: 14px; }
.do-table th { font-size: 12px; font-weight: 700; color: var(--geo-text2); white-space: nowrap; }
.do-table tbody tr:last-child td { border-bottom: 0; }
.do-table th.do-r, .do-table td.do-r { text-align: right; }
.do-table .do-r { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.do-table .do-url { max-width: 22rem; overflow-wrap: anywhere; color: var(--geo-text2); }
@media (max-width: 640px) {
  .do-stats { grid-template-columns: 1fr; gap: 0; }
  /* The top 5 keywords on a phone; the rest behind "Show all" (design gate, 24 Oct). */
  .do-kw:not(.is-all) tbody tr:nth-child(n+6) { display: none !important; }
  .do-more { display: inline-flex; width: 100%; justify-content: center; margin-top: 12px; }
  .do-more[hidden] { display: none; }
  .do-run .geo-btn { width: 100%; }
/* Backlinks for any website: one form, one button (design gate, 24 Oct). The button sits beside the dropdown at
   desktop width and under the typed box on a phone. A typed website greys the dropdown out. */
.bl-pick { display: grid; grid-template-columns: minmax(0, 28rem) auto; grid-template-areas: "sel btn" "oth ."; gap: 12px; align-items: end; }
.bl-pick-sel { grid-area: sel; } .bl-pick-oth { grid-area: oth; } .bl-pick-btn { grid-area: btn; }
.bl-pick select:disabled { opacity: .5; cursor: not-allowed; }
@media (max-width: 640px) {
  .bl-pick { grid-template-columns: 1fr; grid-template-areas: "sel" "oth" "btn"; }
  .bl-pick-btn .geo-tt-btn { width: 100%; justify-content: center; }
}
