/* ===========================================================================
   Search — the search and its results at 60%, a map at 40%, filters in a dialog.

   Same shape as the guide directory and the vibe page, and deliberately so: the
   visitor has met this layout twice before reaching search. Tokens, buttons and
   the section shell all come from site.css; only search's own pieces are here.

   The card is wide rather than a grid tile. A result has to carry a place, a
   feature list, a blurb, a rating and up to two actions, and a column of tiles
   would either crop all of that or grow tall enough to show one result per
   screen. Legacy reached the same layout for the same reason.

   Filters are behind a button rather than in a rail, as legacy had them: three
   columns left too little of any of them.
   =========================================================================== */

/* THE HIDDEN ATTRIBUTE WINS HERE. Read this before adding a `display`.

   `hidden` is only enforced by a user-agent rule, so any author-level `display`
   beats it and the element stays on screen while every script and every
   accessibility tool believes it is gone. This page toggles `hidden` on the
   autocomplete, the filter dialog, the map's status panel, the "search this
   area" button and all four Quickview panes — and it caught three of them in
   turn: an opaque "Loading the map…" panel sat on top of a working map for a
   long stretch, and every Quickview tab showed at once because the panes are
   grids.

   So it is settled once, for everything inside .gq-se, rather than paired up
   rule by rule and remembered. !important is right here: this is not styling, it
   is restoring a platform guarantee that author CSS is allowed to break.

   The Quickview panes are the one deliberate exception, and they are excepted
   here rather than by shouting louder further down. They have to keep taking up
   room while hidden — that is what holds the panel at one height as the tabs
   change — so they are hidden with `visibility` instead, which keeps them out of
   the tab order and the accessibility tree just as `hidden` would. Excluding
   them by name also keeps their own `display: grid` intact: overriding it to
   `block` would stack a gallery into one column and size the panel to a shape
   nobody will ever see. See .gq-se-qv below. */
.gq-se [hidden]:not(.gq-se-qvpane) { display: none !important; }

/* ---------------- banner and the search bar ----------------
   Inside the left column rather than across the page, so the map stands beside
   the whole search and not just beside its results. */
.gq-se-top {
    background: var(--gq-sand);
    border: 1px solid var(--gq-line);
    border-radius: var(--gq-radius);
    padding: 20px;
    margin-bottom: 18px;
}
.gq-se-top-lead .gqv2-script { font-size: 24px; color: var(--gq-blue); }
.gq-se-top-lead h1 {
    margin: 0 0 14px;
    font-size: clamp(24px, 3.2vw, 34px);
    font-weight: 800;
    line-height: 1.1;
    color: var(--gq-navy);
}

/* Type switching: real links, one per listing type. */
.gq-se-types {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 16px;
}
.gq-se-type {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 16px;
    border: 1px solid var(--gq-line);
    border-radius: 999px;
    background: #fff;
    color: var(--gq-slate);
    font-size: 14px;
    font-weight: 600;
    text-decoration: none;
    transition: all .18s ease;
}
.gq-se-type:hover { border-color: var(--gq-blue); color: var(--gq-blue); }
.gq-se-type.is-active {
    background: var(--gq-navy);
    border-color: var(--gq-navy);
    color: #fff;
}

.gq-se-bar { display: flex; gap: 10px; align-items: stretch; }

.gq-se-box { position: relative; flex: 1 1 auto; min-width: 0; }
.gq-se-box > i.fa-magnifying-glass {
    position: absolute;
    left: 16px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--gq-mist);
    pointer-events: none;
}
.gq-se-box input {
    width: 100%;
    height: 52px;
    padding: 0 44px 0 44px;
    border: 1px solid var(--gq-line);
    border-radius: var(--gq-radius);
    background: #fff;
    font-size: 15px;
    color: var(--gq-charcoal);
}
.gq-se-box input:focus {
    outline: none;
    border-color: var(--gq-blue);
    box-shadow: 0 0 0 4px rgba(36, 116, 166, .12);
}
.gq-se-box-x {
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
    width: 30px;
    height: 30px;
    display: none;
    place-items: center;
    border: 0;
    border-radius: 50%;
    background: var(--gq-cloud);
    color: var(--gq-mist);
    cursor: pointer;
}
.gq-se-box.has-text .gq-se-box-x { display: grid; }

/* The disambiguation menu is assets/shared/place-picker.css — the homepage
   location card raises the same one, and it is loaded alongside this file. */

/* The sort control is gone — there is one order and it is not the visitor's to
   override. Its rules went with it; see the note in search/index.php. */
.gq-se-go {
    height: 52px;
    padding: 0 22px;
    border: 0;
    border-radius: var(--gq-radius);
    background: var(--gq-navy);
    color: #fff;
    font-size: 15px;
    font-weight: 700;
    cursor: pointer;
}
/* Hidden once the script is running: a facet change swaps results in place, so
   there is nothing left for a submit button to do. */
.gq-se.is-live .gq-se-go { display: none; }

/* ---------------- layout ----------------
   Results and map, 60/40. Filters are not a column — they are behind a button,
   as legacy had them, which is what leaves both of these enough room.

   fr units rather than percentages so the gap comes out of the grid rather than
   out of the 100, and the split stays exactly 60/40 of what is left. Without a
   Maps key the second column is not rendered at all and the results take the
   whole width — .has-map is what says which. */
.gq-se-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
    align-items: start;
}

/* Room above and below, and only that — the 24px side gutter belongs to
   .gqv2-wrap, which this element also carries.
 *
 * Written as `.gqv2 .gq-se-layout` to match that rule's specificity. As a bare
 * .gq-se-layout it lost the cascade to `.gqv2 .gqv2-wrap`'s padding shorthand
 * and computed to zero, so the results column and the map ran straight into the
 * "see something you like" band underneath with nothing between them.
 *
 * padding-block rather than the shorthand, so this can never be read as also
 * having an opinion about the gutter and quietly take it away. The bottom is the
 * larger of the two because what follows is a full-bleed coloured band: the same
 * gap that reads as generous against white reads as a collision against that. */
.gqv2 .gq-se-layout { padding-block: 20px 72px; }
.gq-se-layout.has-map { grid-template-columns: minmax(0, 60fr) minmax(0, 40fr); }

/* ---------------- map pane ----------------
   Sticky and as tall as the screen allows, because its job is to stay beside the
   search while the results scroll past it. */
.gq-se-mapwrap {
    position: sticky;
    top: calc(var(--gq-header-h) + 12px);
    height: calc(100vh - var(--gq-header-h) - 32px);
    border: 1px solid var(--gq-line);
    border-radius: var(--gq-radius);
    overflow: hidden;
    background: var(--gq-cloud);
}
.gq-se-map { width: 100%; height: 100%; }

/* Until the tiles arrive, and if a key is refused, the pane says so rather than
   sitting there as an empty grey box. Toggled by `hidden`, which the rule at the
   top of this file makes stick. */
.gq-se-mapnote {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    padding: 24px;
    text-align: center;
    font-size: 13px;
    line-height: 1.6;
    color: var(--gq-mist);
    background: var(--gq-cloud);
}

.gq-se-here {
    position: absolute;
    z-index: 3;
    left: 50%;
    top: 14px;
    transform: translateX(-50%);
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 18px;
    border: 0;
    border-radius: 999px;
    background: var(--gq-navy);
    color: #fff;
    font-size: 13px;
    font-weight: 700;
    box-shadow: var(--gq-shadow-sm);
    cursor: pointer;
}
.gq-se-here:hover { background: var(--gq-navy-dark); }

/* A card and its pin light up together, from either side. */
.gq-se-card.is-hot {
    border-color: var(--gq-blue);
    box-shadow: 0 0 0 3px rgba(36, 116, 166, .14);
}

/* ---------------- the filter modal ----------------
   Legacy put filters behind a button and so does this. The facets live inside
   the dialog permanently rather than being moved in and out of a rail: two
   copies of the same checkboxes would post the same names twice and nothing
   could say which set the visitor meant.

   Centred on a wide screen, a bottom sheet on a phone. One element either way,
   because it is one dialog. */
/* Same height as the vibe modal, and for the same reason: a dialog belongs above
   the sticky header rather than under it. See the scale noted on .gq-se-lb. */
.gq-se-sheet { position: fixed; inset: 0; z-index: 1100; }
.gq-se-sheet-bg {
    position: absolute;
    inset: 0;
    background: rgba(18, 59, 99, .5);
    backdrop-filter: blur(2px);
}
.gq-se-sheet-card {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: min(760px, calc(100vw - 40px));
    max-height: min(80vh, 720px);
    display: flex;
    flex-direction: column;
    border-radius: var(--gq-radius);
    background: #fff;
    box-shadow: var(--gq-shadow);
    overflow: hidden;
}

.gq-se-sheet-head,
.gq-se-sheet-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 15px 20px;
    flex-shrink: 0;
}
.gq-se-sheet-head { border-bottom: 1px solid var(--gq-line); }
.gq-se-sheet-foot { border-top: 1px solid var(--gq-line); background: var(--gq-cloud); }
.gq-se-sheet-foot .gqv2-btn { width: 100%; justify-content: center; }
.gq-se-sheet-head h3 {
    margin: 0;
    display: flex;
    align-items: center;
    gap: 9px;
    font-size: 18px;
    font-weight: 800;
    color: var(--gq-navy);
}
.gq-se-sheet-head h3 i { color: var(--gq-blue); }
.gq-se-sheet-x {
    width: 34px;
    height: 34px;
    flex-shrink: 0;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: 50%;
    background: var(--gq-cloud);
    color: var(--gq-slate);
    cursor: pointer;
}
.gq-se-sheet-x:hover { background: var(--gq-line); }
.gq-se-sheet-body { flex: 1 1 auto; overflow-y: auto; }

/* ---------------- the facets themselves ---------------- */
.gq-se-group { padding: 16px 20px; border-bottom: 1px solid var(--gq-line); }
.gq-se-group:last-of-type { border-bottom: 0; }
.gq-se-group h4 {
    margin: 0 0 10px;
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--gq-mist);
}
.gq-se-group h4 i { color: var(--gq-blue); }

/* A heading inside a facet group, for a catalogue that comes in sections — an
   attraction's kinds do, a destination's features do not, and the panel renders
   both from the same markup. Lighter than the h4 above it, which names the facet
   itself. */
.gq-se-subgroup {
    margin: 14px 0 6px;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--gq-mist);
    opacity: .85;
}

.gq-se-subgroup:first-of-type { margin-block-start: 0; }

/* Two columns in the modal, because it is wide enough for them and 24 features
   in one list is a lot of scrolling. Collapses to one on a phone. */
.gq-se-checks {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 2px 14px;
}

.gq-se-check {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 7px 8px;
    border-radius: 9px;
    font-size: 14px;
    color: var(--gq-charcoal);
    cursor: pointer;
}
.gq-se-check:hover { background: var(--gq-cloud); }
.gq-se-check input { accent-color: var(--gq-blue); cursor: pointer; flex-shrink: 0; }
.gq-se-check > span:not(.cnt) { flex: 1 1 auto; min-width: 0; }
.gq-se-check .cnt {
    flex-shrink: 0;
    font-size: 12px;
    font-weight: 700;
    color: var(--gq-mist);
}
/* A facet with nothing behind it stays visible — "no wineries here" is
   information, and a list that shortens as you filter is disorienting. */
.gq-se-check.is-empty { opacity: .45; cursor: default; }
.gq-se-check.is-empty:hover { background: none; }

.gq-se-clear { padding: 12px 20px; border-bottom: 1px solid var(--gq-line); }
.gq-se-clear button {
    width: 100%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 9px;
    border: 1px solid var(--gq-line);
    border-radius: 10px;
    background: #fff;
    color: var(--gq-gold-dark);
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
}
.gq-se-clear button:hover { border-color: var(--gq-gold); }
.gq-se-clear .n {
    padding: 1px 7px;
    border-radius: 999px;
    background: var(--gq-gold);
    color: #fff;
    font-size: 11px;
}

.gq-se-note {
    margin: 0;
    padding: 14px 20px;
    background: var(--gq-cloud);
    font-size: 12px;
    line-height: 1.5;
    color: var(--gq-mist);
}
/* ---------------- results ---------------- */
.gq-se-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 14px;
}
.gq-se-count { margin: 0; font-size: 15px; color: var(--gq-slate); }
.gq-se-count b { color: var(--gq-navy); }

.gq-se-list { display: flex; flex-direction: column; gap: 14px; }

/* ---- while a swap is in flight ----

   The count line names the old place and the old number, so it is exactly as
   stale as the cards beneath it and fades with them. It used to sit at full
   strength over a faded list, which read as a heading that had been confirmed.

   Faded, not hidden: the results keep their height, so the page does not
   collapse and jump back as the new set arrives. */
#gqSeResults[aria-busy="true"] .gq-se-head,
#gqSeResults[aria-busy="true"] .gq-se-list {
    opacity: .45;
    transition: opacity .15s ease;
}

/* The map is still drawn for the previous place — its pins, and its outline —
   so it says the same thing the list does. Dimmed rather than covered: a map
   that disappears and comes back is more disruptive than one that waits. */
.gq-se-layout.is-busy .gq-se-mapwrap { opacity: .55; transition: opacity .15s ease; }

/* The veil itself is site-wide now — .gqv2-veil in site.css, raised by
   window.gqBusy. What stays here is only what this page dims behind it. */

/* A block, not the grid: the photo-beside-text grid is .gq-se-cardmain, so the
   Quickview panel can span the full width beneath it. */
/* A card has to hold its own edge against a white page. --gq-line is the rule
   colour — right for a divider inside something, too faint for the boundary of
   the thing itself, which left the results reading as one pale sheet rather than
   a stack of separate places. A darker edge and a resting shadow give each card
   its own footprint; hover then has somewhere to go. */
.gq-se-card {
    position: relative;
    border: 1px solid #b6c6d6;
    border-radius: var(--gq-radius);
    background: #fff;
    box-shadow: 0 1px 3px rgba(18, 59, 99, .09);
    overflow: hidden;
    transition: box-shadow .2s ease, border-color .2s ease;
}
.gq-se-card:hover {
    border-color: #8fa6bd;
    box-shadow: 0 10px 22px -14px rgba(18, 59, 99, .5);
}

/* ---- an unclaimed place ----
   Padding from the Google cache, filling out a thin area. Quieter than a member's
   card on purpose: it earns its place by being useful to the visitor, not by being
   sold, and a directory entry that looked identical to a paid listing would cheapen
   both. A dashed edge and a tinted ground, no more — it is still a real answer to
   the search and must not read as an error. */
.gq-se-card.is-place {
    border-style: dashed;
    background: color-mix(in srgb, var(--gq-cloud) 55%, #fff);
}
.gq-se-card.is-place:hover { border-color: #c2cedb; }

/* Google has no photograph for plenty of small tourism offices. In the flow with
   the same ratio as the image it replaces — absolutely positioned it would give the
   media column no height at all and collapse the card. */
.gq-se-nophoto {
    display: grid;
    place-items: center;
    width: 100%;
    aspect-ratio: 3 / 2;
    background: var(--gq-cloud);
    color: #c6d2df;
    font-size: 30px;
}

/* Whose words these are. Beside the About heading on an unclaimed place, in the
   quietest thing the panel has: it is a caveat about the writing under it, not a
   badge, and it must not read as a feature of the place. */
.gq-se-qvsrc {
    margin-left: 6px;
    color: var(--gq-mist);
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .02em;
    text-transform: none;
}

/* Google's disclosure on a generated summary. Nothing carries this class today —
   the Quickview does not print the line; see the note where it would go. Kept so
   that putting it back is uncommenting the markup and nothing else, and because a
   rule this small is cheaper to hold than to work out twice. */
.gq-se-qvdisc {
    margin: 4px 0 0;
    color: var(--gq-mist);
    font-size: 10.5px;
    letter-spacing: .02em;
}

/* Its own website and its own phone. No longer used on the card — both moved into
   the Details tab when an unclaimed place gained a Quickview — and kept because
   the same treatment is wanted for any bare outbound link in a card footer. */
.gq-se-plink {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 10px;
    border: 1px solid var(--gq-line);
    border-radius: 999px;
    background: #fff;
    color: var(--gq-slate);
    font-size: 11.5px;
    font-weight: 700;
    text-decoration: none;
}
.gq-se-plink:hover { border-color: var(--gq-green); color: var(--gq-green); }

/* The plan ribbon. Only paid tiers get one — see the note in _results.php on
   why Basic does not. */
.gq-se-ribbon {
    position: absolute;
    z-index: 3;
    top: 12px;
    left: 0;
    padding: 4px 12px 4px 10px;
    border-radius: 0 999px 999px 0;
    background: var(--gq-gold);
    color: #fff;
    font-size: 11px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .05em;
}

/* The map number. A teardrop rather than a plain circle, and in the map's own
   navy, because it is the pin off the map restated on the card — the visitor has
   to recognise it as the same object without being told. Colours are literally
   the ones in search-map.js (#123B63 on #0d2c4b, and the muted pair for a place);
   if either moves, both move.

   Top RIGHT of the card: the ribbon owns the top left and the Request Info toggle
   owns the top right of the photograph, so this is the one free corner. It sits
   above the ribbon's layer so nothing can cover it on a card that has both. */
.gq-se-num {
    position: absolute;
    z-index: 4;
    top: 11px;
    right: 13px;
    display: grid;
    place-items: center;
    width: 25px;
    height: 25px;
    border: 1.5px solid #0d2c4b;
    /* Square corner at the bottom left, then turned a quarter turn anticlockwise
       so the point hangs downward — a pin, from one radius and one rotation. */
    border-radius: 50% 50% 50% 0;
    transform: rotate(-45deg);
    background: var(--gq-navy);
    box-shadow: 0 2px 6px rgba(9, 22, 37, .35);
    color: #fff;
    font-size: 11.5px;
    font-weight: 800;
    /* Two digits must not be wider than two other digits, down a column of them. */
    font-variant-numeric: tabular-nums;
    transition: transform .15s ease;
}
/* The digit is turned back, so only the box is a pin. */
.gq-se-num > b { transform: rotate(45deg); font-weight: inherit; }

/* Pinned in grey on the map, so grey here — see the note on unclaimed places in
   drawPins(). */
.gq-se-card.is-place .gq-se-num { background: #8A9BAD; border-color: #6f8296; }

/* The other half of the pairing: hovering a pin already lights its card, and this
   is what tells you WHICH marker did it. Matches the scale lift() gives the pin. */
.gq-se-card.is-hot .gq-se-num { transform: rotate(-45deg) scale(1.15); }

/* Room for it beside the title, which is a truncated flex row hard against the
   card's right edge — without this the name runs under the pin before its
   ellipsis ever appears. Only while the body IS at that edge; below the split it
   sits under the photograph and the corner is the photo's own. */
.gq-se-body h3 { padding-right: 26px; }

/* 3:2 and cropped, on every plan — the ladder changes how wide the photograph is
   and never its shape, so the pictures stay comparable down the page and a
   partner's hero is framed the same whatever they pay.

   Aligned to the top rather than stretched with the row: the height follows from
   the width, so on a card whose text runs taller there is space under the photo,
   and it is the card's own white rather than a band of bare grey. Legacy did the
   same — a fixed box in a flex row, with the card showing beneath it. */
.gq-se-media {
    position: relative;
    align-self: start;
    display: flex;
    flex-direction: column;
    background: var(--gq-cloud);
}
.gq-se-media > img {
    display: block;
    width: 100%;
    aspect-ratio: 3 / 2;
    object-fit: cover;
}
/* The strip exists only where the plan pays for more than one photo, so it is
   laid out for however many arrive rather than a fixed four. */
.gq-se-thumbs {
    display: flex;
    gap: 3px;
    padding: 3px;
}
/* 3:2, the same shape as the hero above — a thumbnail is a preview of what
   hovering it puts up there, and a square one crops away the part of the
   photograph the swap is about to show. */
.gq-se-thumbs img {
    flex: 1 1 0;
    min-width: 0;
    aspect-ratio: 3 / 2;
    object-fit: cover;
    border-radius: 4px;
    cursor: pointer;
    transition: opacity .15s, outline-color .15s;
    outline: 2px solid transparent;
    outline-offset: -2px;
}

/* The one being previewed, marked on the thumbnail as well as in the hero, so
   it is clear which of them is up. Outline rather than border: it is drawn
   inside the same box, so nothing reflows as the strip is crossed. */
.gq-se-thumbs img:hover,
.gq-se-thumbs img.is-showing {
    outline-color: #fff;
    opacity: .85;
}

/* CONCENTRIC with the card's own corner, not square inside it.
   On a tier that buys a thumbnail strip the media column is the tallest thing in
   the card, so the strip's bottom-left IS the card's bottom-left. The card clips
   at 14px; the thumbnail sits 1px of border plus 3px of padding inside that, so
   its own curve has to be 10px for the two to run parallel. At 4px it read as a
   square corner sitting in a round one — which is what it was.

   Only while the Quickview is shut: open, the panel spans the foot of the card
   and this corner is interior, where a curve would show a notch of the panel
   through it. :has() is the whole point here — the rule is "round it when it is
   the corner", and a browser without :has() simply keeps the square one. */
.gq-se-card:has(> .gq-se-qv[hidden]) .gq-se-thumbs img:first-child,
.gq-se-card:not(:has(> .gq-se-qv)) .gq-se-thumbs img:first-child {
    border-bottom-left-radius: calc(var(--gq-radius) - 4px);
}
.gq-se-media .gqv2-reqbtn { position: absolute; top: 10px; right: 10px; z-index: 3; }

.gq-se-body { padding: 14px 16px; display: flex; flex-direction: column; gap: 8px; }
/* One line, always. Titles run to any length and a card that grows a second
   line pushes everything under it out of step with its neighbours, so the name
   is truncated and the full text kept in the title attribute. */
.gq-se-body h3 {
    margin: 0;
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    font-size: 18px;
    font-weight: 800;
    line-height: 1.25;
    color: var(--gq-navy);
}
.gq-se-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.gq-se-place {
    margin: 0;
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 13px;
    color: var(--gq-mist);
}
.gq-se-place > i { color: var(--gq-gold); }

/* Vibes lead the card where the listing has them; features are the fallback —
   see the note in _results.php. Both occupy the same slot, so they are sized to
   sit interchangeably.

   NOT capsules here. The pill from site.css is a solid fill made to sit on a
   photo, and three of them in a row inside a card read as three buttons with
   gaps punched between them — chrome competing with the title right above it.
   So the colour moves to the ink and the capsule goes: --vfill was derived to
   clear white text, which makes it dark enough to read on white as well.

   Set to run on as one line of labels rather than separate objects. The icon is
   what separates one from the next, so they need no boxes to be told apart. */
/* Three to a line, spread across the full width of the body. Both chip rows are
   laid out identically — see .gq-se-features — because on Elite they sit one above
   the other, and two rows spaced by different rules read as a mistake.

   space-between rather than a fixed column gap: the row is as wide as the card,
   the card is as wide as the results column, and a gap chosen for one width leaves
   the third chip stranded at another. Three columns rather than nowrap so the one
   row that can hold more than three — features on a card with no vibes to lead
   with — becomes two tidy lines of three instead of six squeezed into one. */
.gq-se-vibechips {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, auto));
    justify-content: space-between;
    gap: 4px 12px;
}
.gq-se-vibechips .gqv2-vibe-tag { min-width: 0; }
.gq-se-vibechips .gqv2-vibe-tag {
    position: static;
    padding: 0;
    background: none;
    box-shadow: none;
    color: var(--vfill, var(--gq-navy));
    font-size: 12px;
    letter-spacing: .3px;
}
.gq-se-vibechips .gqv2-vibe-tag i { font-size: 12px; }

/* Room for the real name here — "Outdoor Adventure", not "Adventure". The card
   is the width of the results column, and a vibe is the reason someone reads the
   card, so it is worth the characters. Phones get the short form and one fewer,
   further down. */
.gq-se-vibechips .gqv2-vibe-tag .gqv2-vibe-full { display: inline; }
.gq-se-vibechips .gqv2-vibe-tag .gqv2-vibe-short { display: none; }

/* Three to a line and spread, exactly as the vibe row above it — see the note
   there. It was as many columns as happened to fit while features were shown
   INSTEAD of vibes and nothing had to line up with anything; now the two rows
   appear together on Elite and have to agree with each other. */
.gq-se-features {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, auto));
    justify-content: space-between;
    gap: 6px 12px;
}
/* Legible in its own right, and still plainly the second row.
 *
 * The shared tag is drawn for a dense list of twenty, where light grey text is
 * what keeps it from becoming a wall. Three of them on a card is the opposite
 * problem: at 12px and --gq-slate, directly under a row of bold coloured
 * capitals, the features read as a caption on the vibes rather than as facts
 * about the place — and they are the harder of the two to read, being sentence
 * case and specific rather than four words the eye already knows.
 *
 * So: darker ink, slightly larger, semibold. The hierarchy is kept by every other
 * means instead — a vibe is heavier, capitalised and carries its own colour,
 * while these stay a weight down in the body's own navy. */
.gq-se-features .gqv2-feature-tag {
    min-width: 0;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--gq-navy);
}

/* The glyph up with it. A 12px icon beside a semibold label is the same
   afterthought the Quickview chips had — see the note on .gq-se-qvfeatures. */
.gq-se-features .gqv2-feature-tag > i { flex-basis: 16px; font-size: 13px; }

/* One line each, since a card is not the place to discover that a feature has a
   long name. The full list is a Quickview tab away, where it can wrap. */
.gq-se-features .gqv2-feature-tag > span {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* --lines is the PLAN's clamp, set per card — see s_desc_lines. */
.gq-se-desc {
    margin: 0;
    display: -webkit-box;
    -webkit-line-clamp: var(--lines, 2);
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: 13.5px;
    line-height: 1.55;
    color: var(--gq-slate);
}

.gq-se-foot {
    margin-top: auto;
    padding-top: 4px;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
}
/* Kept while the card is being settled — nothing renders .gq-se-rating now. */
.gq-se-rating {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 13px;
    color: var(--gq-charcoal);
}
.gq-se-rating i { color: #f2b01e; }
.gq-se-rating small { color: var(--gq-mist); }
.gq-se-vibes { display: inline-flex; gap: 5px; flex-wrap: wrap; }
.gq-se-actions { margin-left: auto; display: inline-flex; gap: 8px; }
.gq-se-actions a {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 13px;
    border: 1px solid var(--gq-line);
    border-radius: 999px;
    font-size: 12.5px;
    font-weight: 700;
    text-decoration: none;
    color: var(--gq-blue);
    transition: all .18s ease;
}
.gq-se-actions a:hover { border-color: var(--gq-blue); background: var(--gq-blue-tint); }
.gq-se-events { color: var(--gq-green) !important; }
.gq-se-events:hover { border-color: var(--gq-green) !important; background: #eef5f0 !important; }

/* The way onward, and the only filled thing on the card.

   It took the slot Events had, and an outline pill there would have made the
   card's main action look like one more errand beside Guide. Filled navy, the
   same as the copy inside the Quickview panel, so the two read as the same
   button wherever a visitor meets it. */
.gq-se-full {
    border-color: var(--gq-navy) !important;
    background: var(--gq-navy);
    color: #fff !important;
}

.gq-se-full:hover {
    border-color: var(--gq-green) !important;
    background: var(--gq-green) !important;
    color: #fff !important;
}

/* ---------------- admin cache drawer ----------------
   Only ever rendered for a signed-in admin — see the note in index.php; for a
   visitor none of this markup is sent. Deliberately not styled like the site: a
   dark panel and a warm tab, so it reads as instrumentation sitting ON the page
   rather than part of it.

   Driven by a hidden checkbox, not a script — the drawer's only job is to open
   and shut, and a label can do that on a page whose JavaScript has already
   failed, which is a state an admin is quite likely to be looking at. */
.gq-se-admin-switch { position: absolute; opacity: 0; pointer-events: none; }

/* STACKED, not a row: the icon and label on one line, the age under them. Side
   by side the tab grew with the words — "3 months ago" made it twice the width
   of "8d ago" — and a control fixed to the edge of the viewport should not change
   size depending on how stale the thing behind it is. */
.gq-se-admin-tab {
    position: fixed;
    right: 0;
    top: 40%;
    z-index: 1200;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    padding: 10px 12px;
    border-radius: 12px 0 0 12px;
    background: #2c3444;
    color: #f6d9a5;
    font-size: 11px;
    font-weight: 800;
    line-height: 1.25;
    letter-spacing: .4px;
    text-transform: uppercase;
    text-align: center;
    cursor: pointer;
    box-shadow: 0 6px 18px rgba(0, 0, 0, .22);
}
.gq-se-admin-tab:hover { background: var(--gq-navy); }
.gq-se-admin-tab > i { font-size: 13px; }

/* The age, under the label. Lowercase and a different colour so the two read as
   one thing rather than two shouted words. */
.gq-se-admin-age {
    padding-top: 3px;
    border-top: 1px solid rgba(246, 217, 165, .28);
    width: 100%;
    color: #f0b64a;
    font-size: 10px;
    font-weight: 700;
    text-transform: none;
    letter-spacing: 0;
    white-space: nowrap;
}

.gq-se-admin-drawer {
    position: fixed;
    top: 0;
    right: 0;
    z-index: 1210;
    width: min(360px, 92vw);
    height: 100%;
    overflow-y: auto;
    padding: 18px 20px 26px;
    background: #222a38;
    color: #dfe5ee;
    font-size: 13px;
    box-shadow: -14px 0 34px rgba(0, 0, 0, .3);

    /* Off-screen rather than display:none, so it slides. */
    transform: translateX(100%);
    transition: transform .22s ease;
}
.gq-se-admin-switch:checked ~ .gq-se-admin-drawer { transform: translateX(0); }
.gq-se-admin-switch:checked ~ .gq-se-admin-tab { opacity: 0; pointer-events: none; }

.gq-se-admin-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.gq-se-admin-top h2 {
    margin: 0;
    font-size: 13px;
    font-weight: 800;
    letter-spacing: .6px;
    text-transform: uppercase;
    color: #f6d9a5;
}
.gq-se-admin-shut {
    cursor: pointer;
    padding: 0 6px;
    font-size: 26px;
    line-height: 1;
    color: #8e9aac;
}
.gq-se-admin-shut:hover { color: #fff; }

.gq-se-admin-area {
    margin: 4px 0 16px;
    font-size: 17px;
    font-weight: 800;
    line-height: 1.3;
    color: #fff;
}

/* The search this cache belongs to, under the place name. Monospace, because it
   is a URL path and reads as one — and it is the line that says which of the
   four caches for this area is being looked at. */
.gq-se-admin-path {
    display: block;
    margin-top: 3px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12px;
    font-weight: 600;
    color: #8e9aac;
}

.gq-se-admin-done,
.gq-se-admin-none {
    display: flex;
    gap: 8px;
    margin: 0 0 14px;
    padding: 10px 12px;
    border-radius: 10px;
    background: rgba(255, 255, 255, .06);
    line-height: 1.45;
}
.gq-se-admin-done { color: #b9e6c6; }
.gq-se-admin-done > i { margin-top: 2px; }
.gq-se-admin-none { color: #c9b998; }

/* Two columns, label and value, so the dates line up and can be read down. */
.gq-se-admin-facts {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 7px 14px;
    margin: 0 0 18px;
}
.gq-se-admin-facts dt { color: #96a2b4; white-space: nowrap; }
.gq-se-admin-facts dd { margin: 0; color: #fff; font-weight: 700; }
.gq-se-admin-facts dd small { display: block; color: #8e9aac; font-weight: 400; }
.gq-se-admin-nil { color: #6d7789; }

.gq-se-admin-tag {
    display: inline-block;
    padding: 2px 9px;
    border-radius: 999px;
    background: #46506380;
    font-size: 11px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .4px;
}
.gq-se-admin-tag.is-ready   { background: #1e6b3d; color: #cdf0d9; }
.gq-se-admin-tag.is-partial { background: #7a5a12; color: #f6e3b5; }
.gq-se-admin-tag.is-pending { background: #33507a; color: #cfe0f7; }
.gq-se-admin-tag.is-empty,
.gq-se-admin-tag.is-failed  { background: #7a2b2b; color: #f7cfcf; }

.gq-se-admin-go {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    padding: 11px 16px;
    border-radius: 10px;
    background: #f0b64a;
    color: #2a2213;
    font-weight: 800;
    text-decoration: none;
}
.gq-se-admin-go:hover { background: #ffc964; color: #2a2213; }
.gq-se-admin-note { margin: 9px 0 0; color: #8e9aac; line-height: 1.5; }

/* ---------------- paging and empty ---------------- */
.gq-se-pager {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 16px;
    padding: 26px 0 0;
}
.gq-se-pager a {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 18px;
    border: 1px solid var(--gq-line);
    border-radius: 999px;
    background: #fff;
    color: var(--gq-navy);
    font-size: 14px;
    font-weight: 700;
    text-decoration: none;
}
.gq-se-pager a:hover { border-color: var(--gq-blue); color: var(--gq-blue); }

/* The numbers. Square-ish rather than the pill Previous and Next wear, so the
   row reads as two kinds of control: one moves you a step, one jumps you
   somewhere. */
.gq-se-pager-nums { display: flex; align-items: center; gap: 6px; }
.gq-se-pager-num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 38px;
    height: 38px;
    padding: 0 10px;
    border: 1px solid var(--gq-line);
    border-radius: 10px;
    background: #fff;
    color: var(--gq-navy);
    font-size: 14px;
    font-weight: 700;
    text-decoration: none;
}
.gq-se-pager a.gq-se-pager-num:hover { border-color: var(--gq-blue); color: var(--gq-blue); }

/* The page you are on: filled, and not a link. */
.gq-se-pager-num.is-at {
    border-color: var(--gq-navy);
    background: var(--gq-navy);
    color: #fff;
    cursor: default;
}
.gq-se-pager-gap { padding: 0 2px; color: var(--gq-mist); font-weight: 700; }

.gq-se-pager-at {
    margin: 12px 0 0;
    font-size: 13px;
    color: var(--gq-mist);
    text-align: center;
}

/* Phones: the words go, the arrows stay. "‹ 1 … 4 [5] 6 … 12 ›" is the whole
   control in the width a single pill would have taken. */
@media (max-width: 575.98px) {
    .gq-se-pager { gap: 8px; }
    .gq-se-pager a { padding: 10px 12px; }
    .gq-se-pager-word { display: none; }
    .gq-se-pager-nums { gap: 4px; }
    .gq-se-pager-num { min-width: 34px; height: 34px; padding: 0 6px; font-size: 13px; }
}

.gq-se-empty {
    padding: 54px 20px;
    text-align: center;
    border: 1px dashed var(--gq-line);
    border-radius: var(--gq-radius);
    background: #fff;
}
.gq-se-empty > i { font-size: 40px; color: var(--gq-sky); }
.gq-se-empty h2 {
    margin: 14px 0 6px;
    font-size: 20px;
    font-weight: 800;
    color: var(--gq-navy);
}
.gq-se-empty p { margin: 0; font-size: 14px; color: var(--gq-mist); }

/* ---------------- the filters and map buttons ----------------
   Both sit in the search bar. Filters is there at every width now; Map only
   appears where the pane cannot, on a narrow screen. */
.gq-se-filterbtn,
.gq-se-mapbtn {
    height: 52px;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    padding: 0 18px;
    border: 1px solid var(--gq-line);
    border-radius: var(--gq-radius);
    background: #fff;
    color: var(--gq-navy);
    font-size: 14px;
    font-weight: 700;
    cursor: pointer;
    transition: all .18s ease;
}
.gq-se-filterbtn:hover,
.gq-se-mapbtn:hover { border-color: var(--gq-blue); color: var(--gq-blue); }
.gq-se-filterbtn .n {
    padding: 1px 8px;
    border-radius: 999px;
    background: var(--gq-gold);
    color: #fff;
    font-size: 11px;
}
/* The pane is beside the results above the breakpoint, so there is nothing to
   toggle — see the media queries below. */
.gq-se-mapbtn { display: none; }
.gq-se-mapbtn[aria-pressed="true"] {
    background: var(--gq-navy);
    border-color: var(--gq-navy);
    color: #fff;
}

/* ---------------- narrower screens ---------------- */
@media (max-width: 1100px) {
    /* The map cannot usefully share the width with a list at this size, so it
       goes behind the toggle and the list takes the room. */
    .gq-se-layout,
    .gq-se-layout.has-map { grid-template-columns: minmax(0, 1fr); }
    .gq-se-mapwrap { display: none; }
    .gq-se-mapbtn { display: inline-flex; }

    /* Toggled on: the map takes the screen and the list steps aside. */
    .gq-se-layout.map-open .gq-se-mapwrap {
        display: block;
        height: calc(100vh - var(--gq-header-h) - 120px);
    }
    .gq-se-layout.map-open #gqSeResults { display: none; }
}

@media (max-width: 760px) {
    /* The bar stacks, so the two buttons share a row of their own. */
    .gq-se-bar { flex-wrap: wrap; }
    .gq-se-box { flex: 1 1 100%; }
    .gq-se-filterbtn,
    .gq-se-mapbtn { flex: 1 1 0; padding: 0 12px; }

    /* A dialog centred on a phone leaves slivers of page around it; a sheet
       rising from the bottom is reachable with a thumb. */
    .gq-se-sheet-card {
        left: 0;
        right: 0;
        bottom: 0;
        top: auto;
        transform: none;
        width: auto;
        max-height: 86vh;
        border-radius: 18px 18px 0 0;
    }
    .gq-se-checks { grid-template-columns: minmax(0, 1fr); }

    /* Two lines here, one on the desktop. A phone card is a fraction of the
       width, so the same name that fits on one line beside a photo is cut after
       three or four words stacked above it. */
    .gq-se-name {
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
        line-clamp: 2;
        white-space: normal;
    }
    /* Stacked, because 248px of photo beside text is unreadable at this width. */
    /* .gq-se-cardmain carries the grid now — see the rule near the Quickview. */
    .gq-se-type span { display: none; }
    .gq-se-type { padding: 9px 14px; }
    .gq-se-type.is-active span { display: inline; }

    /* All three vibes here too, the same as the desktop card — the short names
       are what make them fit, so the third no longer has to go. Wrapping to a
       second line is fine; three short labels say more about a place than two
       do, and the row is the only thing on the card that describes it. */
    .gq-se-vibechips .gqv2-vibe-tag .gqv2-vibe-full { display: none; }
    .gq-se-vibechips .gqv2-vibe-tag .gqv2-vibe-short { display: inline; }
    .gq-se-vibechips { gap: 4px 20px; }
}

/* ---------------- the visitor guides strip ----------------
   Above the results, as legacy's was. Covers rather than titles, because a
   guide is a physical-looking thing and its cover is what makes it read as one
   worth opening. */
.gq-se-guides {
    margin-bottom: 18px;
    padding: 14px 16px 16px;
    border: 1px solid var(--gq-line);
    border-radius: var(--gq-radius);
    background: #fff;
}
.gq-se-guides-head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 12px;
}
.gq-se-guides-head h2 {
    margin: 0;
    display: flex;
    align-items: center;
    gap: 9px;
    font-size: 15px;
    font-weight: 800;
    color: var(--gq-navy);
}
.gq-se-guides-head h2 i { color: var(--gq-gold); }
.gq-se-guides-head span {
    padding: 1px 9px;
    border-radius: 999px;
    background: var(--gq-cloud);
    color: var(--gq-mist);
    font-size: 11px;
    font-weight: 700;
}

.gq-se-guides-more { margin-left: auto; }

.gq-se-guides-rail { position: relative; }
.gq-se-guide-card {
    display: flex;
    flex-direction: column;
    gap: 2px;
    text-decoration: none;
}
/* Anchored to the top, not the middle. Covers are taller than 3:4 more often
   than not, and centring the crop took the masthead off the top and the strap
   line off the bottom — the two parts of a cover that say which guide it is.
   Cropping from the bottom only costs the end of a photograph. */
.gq-se-guide-card img {
    width: 100%;
    aspect-ratio: 3 / 4;
    margin-bottom: 4px;
    object-fit: cover;
    object-position: top;
    border-radius: 8px;
    border: 1px solid var(--gq-line);
    box-shadow: var(--gq-shadow-sm);
    transition: transform .2s ease;
}
.gq-se-guide-card:hover img { transform: translateY(-3px); }
.gq-se-guide-name {
    font-size: 12px;
    font-weight: 700;
    line-height: 1.3;
    color: var(--gq-navy);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.gq-se-guide-read { font-size: 11px; font-weight: 700; color: var(--gq-blue); }

.gq-se-guides-prev,
.gq-se-guides-next {
    position: absolute;
    z-index: 3;
    top: 38%;
    width: 32px;
    height: 32px;
    display: grid;
    place-items: center;
    border: 1px solid var(--gq-line);
    border-radius: 50%;
    background: #fff;
    color: var(--gq-navy);
    box-shadow: var(--gq-shadow-sm);
    cursor: pointer;
}
.gq-se-guides-prev { left: -8px; }
.gq-se-guides-next { right: -8px; }
.gq-se-guides-prev:disabled,
.gq-se-guides-next:disabled { opacity: 0; pointer-events: none; }

/* ---------------- the Quickview panel ----------------
   The card's photo-beside-text grid moved into its own element so this can span
   the whole width beneath it. */
.gq-se-cardmain { display: grid; grid-template-columns: var(--gq-se-photo) minmax(0, 1fr); }

/* ---- how much photograph a plan buys ----
   The one measurement on this page that is sold. Legacy sized the same column off
   the tier and v2 had flattened it to a single width, which quietly gave away the
   most visible thing a membership pays for — a bigger picture is what a stronger
   plan looks like from across the page, before any ribbon is read.

   Legacy's grouping (244 / 244 / 244 / 216 / 160), at the sizes this design wants:
   the three plans a partner pays a real subscription for share the top rung, Basic
   — the free tier every unclaimed listing sits on — steps down, and a place that
   is not a member at all steps down again. Elite and Premium are told apart by
   what fills the card, not by how wide it is: the strip of four thumbnails is
   Elite's alone, and it is the more visible difference of the two.

   Keyed off data-tier and expressed as a custom property rather than a
   grid-template of its own, so the single-column rule at 760px still overrides
   the whole ladder with one line — a phone has no room to sell width with.

   The default is the bottom rung and is what an unclaimed Google place gets, and
   with it any listing whose term has lapsed: both arrive with ListingPlan's
   NO_PLAN_TIER, and neither is paying for the space. */
.gq-se-card { --gq-se-photo: 208px; }
.gq-se-card[data-tier="4"] { --gq-se-photo: 262px; }
.gq-se-card[data-tier="3"],
.gq-se-card[data-tier="2"],
.gq-se-card[data-tier="1"] { --gq-se-photo: 300px; }

/* Carries the auto margin that pushes the rest of the row right. It sat on the
   Modal view button while that ran beside this one; that candidate is gone and
   the margin comes back here, as its note said it would. */
.gq-se-qvbtn {
    margin-right: auto;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 6px 12px;
    border: 1px solid var(--gq-line);
    border-radius: 999px;
    background: #fff;
    color: var(--gq-slate);
    font-size: 12.5px;
    font-weight: 700;
    cursor: pointer;
}
.gq-se-qvbtn:hover { border-color: var(--gq-blue); color: var(--gq-blue); }
.gq-se-qvbtn i { transition: transform .2s ease; }
.gq-se-qvbtn[aria-expanded="true"] i { transform: rotate(180deg); }

/* Every pane occupies the same grid cell, so the panel is as tall as its
   tallest tab and stays that height whichever tab is showing. Switching tabs
   used to resize the panel under the pointer — and with the panel sitting
   inside a card in a list, that shunted every card below it up or down.

   The height still comes from the content rather than a number: a listing whose
   biggest tab is six feature chips gets a short panel, one with a full gallery
   gets the capped 320. What it never does is change while you use it.

   Sized by the tallest pane rather than measured in script because the panes are
   all rendered with the card already — see the note in _results.php — so the
   browser can do it, and it stays right if a tab's content changes. */
/* White throughout, divided by one hairline. There were three surfaces before —
   a grey band behind the tabs, a white pane, and grey chips inside it that
   echoed the band two layers away — and the panel read as washed out. The top
   edge is the card's own border colour, not the lighter rule: this is where the
   card's body ends, and a seam inside a card should not be fainter than the
   card's outline. */
.gq-se-qv {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    border-top: 1px solid #b6c6d6;
    background: #fff;
}

/* Author `display` beats the UA's [hidden] rule, so closing has to be said
   again here or the panel could never shut. */
.gq-se-qv[hidden] { display: none; }

.gq-se-qv > .gq-se-qvtabs { grid-area: 1 / 1; }
.gq-se-qv > .gq-se-qvpane { grid-area: 2 / 1; }

/* Still laid out, so it goes on holding the row open; not painted, and out of
   both the tab order and the accessibility tree. No `display` here on purpose —
   each pane keeps its own, so it measures at the size it will really be. The
   blanket [hidden] rule at the top of this file excepts these for that reason. */
.gq-se-qv > .gq-se-qvpane[hidden] { visibility: hidden; }

.gq-se-qvtabs {
    display: flex;
    gap: 6px;
    padding: 10px 16px;
    border-bottom: 1px solid var(--gq-line);
    overflow-x: auto;
    scrollbar-width: none;
}
.gq-se-qvtabs::-webkit-scrollbar { display: none; }

/* Pills. They were folder tabs — flat-bottomed, to join the pane below — and
   nothing joins any more now the open one is a filled block on a white ground,
   so the square corners were the last trace of a shape that had gone. */
.gq-se-qvtabs button {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 8px 14px;
    border: 0;
    border-radius: 999px;
    background: none;
    color: var(--gq-slate);
    font-size: 12.5px;
    font-weight: 700;
    white-space: nowrap;
    cursor: pointer;
}
/* Grey now, not white — the strip is white, so a white hover said nothing. */
.gq-se-qvtabs button:hover { background: var(--gq-cloud); }

/* The open tab is filled, not merely lighter. It used to go white on a pale grey
   strip, which is a difference you have to look for — and the tabs scroll, so
   the one you are on can be off-screen when you come back to the panel. */
.gq-se-qvtabs button.is-on {
    background: var(--gq-navy);
    color: #fff;
    box-shadow: 0 6px 14px -8px rgba(18, 59, 99, .6);
}

.gq-se-qvtabs .n {
    padding: 0 6px;
    border-radius: 999px;
    background: var(--gq-line);
    font-size: 10px;
}
.gq-se-qvtabs button.is-on .n { background: rgba(255, 255, 255, .24); color: #fff; }

/* One height, everywhere. max-height only stopped a pane growing past a ceiling,
   so the panel still took the size of whatever the tallest tab happened to be —
   steady while you used one card, a different size on the next. A set height
   makes every Quickview on the page the same object, which is what stops the
   list jumping as they open and close.

   Sized to the vibe cards, the tallest thing that has to fit whole; anything
   longer scrolls, which is also why the description is never truncated — cutting
   HTML at a character count leaves tags open.

   The number allows for the horizontal scrollbar the strips carry: it is drawn
   inside the content box and takes about ten pixels of height with it, which is
   what clipped the bottom of the vibe cards when the height was set to the cards
   alone. */
.gq-se-qvpane {
    padding: 14px 16px;
    background: #fff;
    height: var(--qv-pane-h, 240px);
    overflow-y: auto;
}

/* One row that scrolls sideways, not a grid that wraps — legacy's
   `.listing-photos { display: flex; flex-wrap: nowrap; overflow: auto }`, and it
   is the better idea. A wrapping grid grows a row for every four photos, so a
   gallery of twenty pushed the pane to its cap and put the rest behind a
   vertical scrollbar inside a panel that is itself inside a scrolling page.
   Held to one row, the pane is the height of a thumbnail whether there are
   three photos or thirty, and more of them is a sideways swipe rather than a
   taller card.

   Fixed-width items rather than fractions: 1fr columns stretch to fill, which is
   what made four photos look like a deliberate four-up layout and twelve look
   like a contact sheet. */
.gq-se-qvphotos,
.gq-se-qvvideos {
    /* One width for both strips, so a photo and a video poster read as the same
       size of thing. Set once here rather than twice below, where the two drifted
       apart and photos ended up two-thirds the size of videos for no reason. */
    --strip-w: 208px;

    display: flex;
    flex-wrap: nowrap;
    /* Centred, and their own height rather than the pane's. Two jobs in one
       value: `stretch` would pull each thumbnail into a tall box with the
       picture at the top and dead space under it, and `flex-start` left the
       whole strip sitting against the top of a pane sized for a taller tab,
       with the slack collecting underneath as a hole. Centred, that same slack
       reads as margin. */
    align-items: center;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: thin;
}
.gq-se-qvphotos { gap: 8px; }
.gq-se-qvphotos > a { flex: 0 0 var(--strip-w); }
.gq-se-qvphotos img {
    width: 100%;
    aspect-ratio: 3 / 2;
    object-fit: cover;
    border-radius: 6px;
    display: block;
}

.gq-se-qvvideos { gap: 8px; }
.gq-se-qvvideos > .gq-se-qvvideo { flex: 0 0 var(--strip-w); }
.gq-se-qvvideo {
    position: relative;
    padding: 0;
    border: 0;
    border-radius: 8px;
    overflow: hidden;
    background: #000;
    cursor: pointer;
    aspect-ratio: 16 / 9;
}
.gq-se-qvvideo img { width: 100%; height: 100%; object-fit: cover; display: block; opacity: .85; }
.gq-se-qvvideo .play {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    color: #fff;
    font-size: 26px;
    text-shadow: 0 2px 12px rgba(0, 0, 0, .6);
}
.gq-se-qvvideo iframe { width: 100%; height: 100%; border: 0; display: block; }

/* Room to breathe: 10px between rows and 32px between columns, so the eye reads
   down a column rather than across two names that happen to be adjacent. */
/* Columns that flow sideways, not rows that wrap downwards. A listing with
   sixteen features grew four rows and dragged the whole panel down with it;
   filling four rows and then starting a new column keeps the pane one height and
   puts the rest a swipe away — the same bargain the photo strip makes.

   Four rows rather than one long line: these are short labels, and a single row
   of sixteen would be two thousand pixels of swiping to read a word each. */
.gq-se-qvfeatures {
    display: grid;
    grid-auto-flow: column;
    grid-template-rows: repeat(4, auto);
    /* Sized to their contents, not to a 178px floor. Thirteen features into four
       rows leaves a last column holding one chip, and a floor made that orphan
       as wide as a full column — a void the height of three rows beside it.
       Let each column be its own width and the ragged edge is just a short
       column. */
    grid-auto-columns: max-content;
    align-content: center;
    gap: 8px 14px;
    /* The pane's own padding, restated. This element carries .gq-se-qvpane too
       and this rule sits after it, so a shorthand here replaces it outright —
       which is how the first column ended up flush against the left edge. */
    padding: 14px 16px;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: thin;
}

/* Each feature gets a box of its own here. Bare text in a grid left the icon of
   one line sitting a few pixels from the label of the next, so sixteen features
   read as one grey block rather than sixteen things — padding and a ground are
   what separate them. Centred rather than baseline-aligned: once there is a box
   around it, the icon should sit in the middle of it. */
.gq-se-qvfeatures .gqv2-feature-tag {
    align-items: center;
    gap: 10px;
    padding: 7px 12px;
    border-radius: 8px;
    background: var(--gq-cloud);
    font-size: 13px;
    color: var(--gq-charcoal);
}

/* The shared tag sizes its icon for a dense card list, where it is a marker
   beside a line of text. In a chip it is one of two things in a box and reads as
   an afterthought at 12px, so it goes up to sit level with the label. */
.gq-se-qvfeatures .gqv2-feature-tag > i {
    flex: 0 0 17px;
    font-size: 14px;
}

/* ---- the Details pane -------------------------------------------------------
   Legacy's shape: the name across the top, then About on the left and how to get
   in touch on the right. Two columns because they are read for different reasons
   — one to decide, the other to act. */
.gq-se-qvdetails {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 4px 30px;
}
.gq-se-qvname {
    grid-column: 1 / -1;
    margin: 0 0 2px;
    font-size: 16px;
    font-weight: 800;
    color: var(--gq-navy);
}
.gq-se-qvcol { min-width: 0; }
/* A listing with no description has only the contact column, which reads badly
   squeezed into half the pane with nothing beside it. */
.gq-se-qvcol:only-of-type { grid-column: 1 / -1; }
.gq-se-qvcol h5 {
    margin: 0 0 8px;
    font-size: 12px;
    font-weight: 800;
    letter-spacing: .4px;
    text-transform: uppercase;
    color: var(--gq-mist);
}

.gq-se-qvtext { font-size: 13.5px; line-height: 1.65; color: var(--gq-slate); }
.gq-se-qvtext p { margin: 0 0 10px; }
.gq-se-qvtext :last-child { margin-bottom: 0; }

/* Four lines, then Read more. The pane is a preview, and a full description runs
   to two thousand characters — unclamped it decides how tall every open card is. */
.gq-se-qvtext.is-clamped {
    display: -webkit-box;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.gq-se-qvmore {
    margin-top: 6px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--gq-green);
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
}
.gq-se-qvmore:hover { text-decoration: underline; }

.gq-se-qvcontact {
    margin: 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: 7px;
    font-size: 13px;
    color: var(--gq-charcoal);
}
.gq-se-qvcontact li { display: flex; align-items: baseline; gap: 9px; }
/* Fixed width, so the address and the phone number start at the same place
   whatever their icons happen to measure. */
.gq-se-qvcontact i { flex: 0 0 15px; text-align: center; color: var(--gq-green); font-size: 12px; }
.gq-se-qvcontact a { color: inherit; text-decoration: none; }
.gq-se-qvcontact a:hover { text-decoration: underline; }

/* Legacy ruled a line above its buttons and stretched them across the column;
   same here, and they wrap rather than shrink past readable. */
.gq-se-qvlinks {
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--gq-line);
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.gq-se-qvlinks a,
.gq-se-qvlinks span {
    flex: 1 1 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    padding: 7px 12px;
    border: 1px solid var(--gq-line);
    border-radius: 8px;
    background: #fff;
    color: var(--gq-navy);
    font-size: 12.5px;
    font-weight: 700;
    text-decoration: none;
    white-space: nowrap;
    transition: border-color .15s ease, color .15s ease, background .15s ease;
}
.gq-se-qvlinks a:hover {
    border-color: var(--gq-green);
    background: color-mix(in srgb, var(--gq-green) 8%, #fff);
    color: var(--gq-green);
}

/* View Full Details is the way further in, so it takes the whole width under the
   others rather than competing with them for a third of a row. */
.gq-se-qvlinks .is-primary {
    flex: 1 1 100%;
    border-color: var(--gq-navy);
    background: var(--gq-navy);
    color: #fff;
}
.gq-se-qvlinks a.is-primary:hover {
    border-color: var(--gq-green);
    background: var(--gq-green);
    color: #fff;
}
/* Not yet a link — see web_listing_url(). Reads as a button that is not ready,
   which is honest, rather than one that leads to a 404. */
.gq-se-qvlinks .is-soon {
    border-color: var(--gq-line);
    background: color-mix(in srgb, var(--gq-navy) 6%, #fff);
    color: var(--gq-mist);
    cursor: default;
}

/* One column below the split — two columns of forty characters each is not a
   layout, and the contact block reads better under the description than beside a
   sliver of it. */
@media (max-width: 900px) {
    .gq-se-qvdetails { grid-template-columns: minmax(0, 1fr); gap: 16px; }
    .gq-se-qvname { margin-bottom: 0; }
}


@media (max-width: 760px) {
    .gq-se-cardmain { grid-template-columns: minmax(0, 1fr); }

    /* One column puts the photograph across the whole card, which brings the
       Request Info toggle into the corner the pin number is in. The number keeps
       the corner — it is the fixed landmark tying the row to the map — and the
       toggle steps aside by its width. */
    .gq-se-media .gqv2-reqbtn { right: 44px; }

    /* The title is under the photo now, not beside it, so nothing is over it. */
    .gq-se-body h3 { padding-right: 0; }

    /* One column puts the text UNDER the photo, so the strip is no longer at the
       foot of the card and its corner is interior again. Square, as the others. */
    .gq-se-card .gq-se-thumbs img:first-child { border-bottom-left-radius: 4px; }
}

/* ---------------- the lightbox ----------------
   One overlay for every Quickview photo and video on the page — see the note in
   the markup. Above the filter dialog, because it can be opened from a card while
   that is closed and nothing else stacks with it.

   A framed box rather than a picture pinned to the glass. The first attempt let
   the image fill the viewport, and it read as a page that had gone wrong rather
   than a gallery: the counter collided with the bottom edge of the photo, the
   arrows were stranded at the edges of the screen, and with nothing else on show
   there was no saying which listing any of it belonged to. */
/* Above the header, which is sticky at 1000, and above the guide reader at 2000
   — this is the topmost thing on the page while it is open. 200 put it UNDER the
   header, so the site chrome sat across the top of the photo.

   The scale this joins, so the next overlay does not have to guess: header 1000,
   bell 1050, vibe modal 1100, guide reader 2000, request tray 9999. */
.gq-se-lb { position: fixed; inset: 0; z-index: 2200; }
.gq-se-lb-bg {
    position: absolute;
    inset: 0;
    background: rgba(9, 22, 37, .9);
    backdrop-filter: blur(3px);
}

/* The request-info tray is fixed at 9999 so it survives every other overlay on
   the site — but it is a basket, and it has no business floating over a photo
   somebody is looking at. Out-bidding it would start a numbers race; the tray is
   simply put away while the viewer is open, and comes straight back after. */
body.gq-se-lb-open .gqv2-tray { display: none; }

.gq-se-lb-box {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
    /* Air around it, so it reads as a layer over the page and not a new one. */
    padding: 18px clamp(16px, 4vw, 56px) 20px;
    /* Shown by removing `hidden` rather than kept in the DOM visible, so an
       animation runs on every open with no class juggling. */
    animation: gqSeLbIn .18s ease-out both;
}
@keyframes gqSeLbIn {
    from { opacity: 0; transform: scale(.985); }
    to   { opacity: 1; transform: none; }
}

.gq-se-lb-bar {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 14px;
    color: #fff;
}
.gq-se-lb-bar h3 {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    font-size: 16px;
    font-weight: 700;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.gq-se-lb-count {
    flex-shrink: 0;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .06em;
    color: rgba(255, 255, 255, .6);
}

.gq-se-lb-x {
    flex-shrink: 0;
    width: 38px;
    height: 38px;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, .12);
    color: #fff;
    font-size: 16px;
    cursor: pointer;
    transition: background .15s ease;
}
.gq-se-lb-x:hover { background: rgba(255, 255, 255, .26); }

/* Picture and arrows on one row, so the arrows sit beside what they move rather
   than pinned to the glass at either edge.

   min-height:0 is what keeps the media off the thumbnail strip. A flex item
   defaults to min-height:auto, which refuses to shrink below its content — so a
   tall photo pushed this row past its share and the strip went under it. With the
   floor removed the row takes exactly what the bar and the strip leave, and the
   media is capped to that. */
.gq-se-lb-stagewrap {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    align-items: center;
    gap: clamp(8px, 2vw, 20px);
}
.gq-se-lb-stage {
    flex: 1 1 auto;
    min-width: 0;
    min-height: 0;
    margin: 0;
    /* The frame the media is fitted into. Sized by flex, and the media is laid
       out against it absolutely rather than with percentages. */
    position: relative;
    align-self: stretch;
    overflow: hidden;
}

/* object-fit rather than max-height. A percentage max-height has to resolve
   against the containing block, and this one gets its height from flex — which
   engines treat as indefinite for that purpose, so the rule was ignored and a
   tall photo rendered at 697px inside a 556px frame and was cropped. Fitting to
   an absolutely-positioned box needs no percentage to resolve, and `contain`
   shows the whole picture whatever shape it is. */
.gq-se-lb-stage img,
.gq-se-lb-stage iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
    border-radius: 10px;
}
/* No border-radius on a fitted photo: `contain` letterboxes it inside the frame,
   so the corners would be rounded off the empty box rather than the picture.
   YouTube letterboxes its own player, so the iframe can fill the frame. */
.gq-se-lb-stage img { object-fit: contain; border-radius: 0; }

.gq-se-lb-nav {
    flex-shrink: 0;
    width: 46px;
    height: 46px;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, .14);
    color: #fff;
    font-size: 18px;
    cursor: pointer;
    transition: background .15s ease;
}
.gq-se-lb-nav:hover { background: rgba(255, 255, 255, .3); }

/* ---- the thumbnail strip ----
   Twelve photos is more than anyone will arrow through blind. */
.gq-se-lb-strip {
    flex-shrink: 0;
    display: flex;
    justify-content: center;
    gap: 6px;
    overflow-x: auto;
    /* Room for the selected thumbnail's ring. A scroll container clips whatever
       paints outside its padding box, so with less than the ring's offset plus its
       width the top and bottom edges were cut off and it read as two brackets. */
    padding: 5px;
    scrollbar-width: thin;
}
.gq-se-lb-strip button {
    flex: 0 0 auto;
    width: 74px;
    height: 50px;
    padding: 0;
    border: 0;
    border-radius: 6px;
    overflow: hidden;
    background: none;
    cursor: pointer;
    opacity: .45;
    outline: 2px solid transparent;
    outline-offset: 2px;
    transition: opacity .15s ease, outline-color .15s ease;
}
.gq-se-lb-strip button:hover { opacity: .8; }
.gq-se-lb-strip button.is-on { opacity: 1; outline-color: #fff; }
.gq-se-lb-strip img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* A play badge over a video thumbnail, so the strip says which is which. The icon
   is a real element built in search.js, so it uses whichever Font Awesome release
   the page loads rather than a codepoint and family name pinned here. */
.gq-se-lb-strip button.is-video { position: relative; }
.gq-se-lb-play {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    font-size: 13px;
    color: #fff;
    background: rgba(0, 0, 0, .35);
}

@media (max-width: 760px) {
    .gq-se-lb-box { padding: 12px 10px 14px; gap: 10px; }
    .gq-se-lb-bar h3 { font-size: 14px; }
    .gq-se-lb-nav { width: 38px; height: 38px; font-size: 15px; }
    /* Thumbnails cost height a phone has not got; swiping covers the same job. */
    .gq-se-lb-strip { display: none; }
}

.gq-se-qvphotos a { display: block; cursor: zoom-in; }


/* ---------------- vibe notes ----------------
   Not here any more. The tiles and the reader they open are one component
   shared with the listing page: shared/vibe-reader.css for the look,
   shared/vibe-reader.js for the dialog and web_vibe_tile() for the markup.
   This page lays them out in a sideways row (.gq-vt-row) because the Quickview
   pane has a fixed height; the listing page wraps them into a grid. */
