/* ══════════════════════════════════════════════════════════════════════════════
   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. A cell with no data-cell still shows - it
   just has no heading, which is right for the actions cell. */
@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; }
  /* 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 > button { 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; }
/* ── Research ▾ on the site's section bar (22 Sep) ───────────────────────────────
   The "look into it" tools in ONE dropdown, each with a line saying what it answers; the
   phone list groups them under a Research heading. */
.site-research > summary::-webkit-details-marker { display: none; }
.site-research-menu { position: absolute; left: 0; top: calc(100% + 4px); z-index: 45; width: 290px; padding: 6px;
  border-radius: var(--geo-r-card); background: var(--geo-panel); border: 1px solid var(--geo-border); box-shadow: 0 14px 34px rgba(0, 0, 0, .4); }
.site-research-menu > a, .site-research-menu > button { display: flex; width: 100%; text-align: left; padding: 9px 12px;
  border: 0; border-radius: var(--geo-r-ctrl); background: none; color: var(--geo-text2); font: inherit; font-size: 14px; text-decoration: none; cursor: pointer; }
.site-research-menu small { display: block; font-size: 12px; color: var(--geo-muted); margin-top: 1px; }
.site-research-menu > a:hover, .site-research-menu > button:hover { background: var(--geo-surface2); }
.site-research-menu [aria-current="page"] { background: var(--geo-surface2); box-shadow: inset 3px 0 0 var(--geo-accent); }
.site-sections-group { padding: 12px 12px 4px; font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--geo-muted); }
html[data-theme="light"] .site-research-menu > a:hover, html[data-theme="light"] .site-research-menu > button:hover,
/* Review: the Research tab keeps a steady width, so "· Citations" does not push Settings along;
   the help bubble steps aside while the phone section list is open. */
.site-research > summary { min-width: 10rem; }
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; }