/* ---------------------------------------------------------------------------
   Vibe tiles and the reader they open.

   One component, two pages: the search Quickview's Vibes tab and the listing
   page's "How it feels". Both draw the same thing — a place's vibe, the writing
   that goes with it and the places it names — so both draw it from here.

   Written for search first (as .gq-se-vc / .gq-se-vread) and moved out whole
   when the listing page asked for the same tiles. Nothing in it knows which
   page it is on: the tile carries its own colour on --vc and its own copy in
   data-note, and shared/vibe-reader.js fills the dialog from whichever tile was
   pressed.

   Unscoped, like every other shared component: the reader is appended near the
   end of the page and the tiles sit inside whatever the page puts them in.
   Loaded alongside shared/vibe-blank.css, which draws the emblem a vibe with no
   photograph falls back to.
   --------------------------------------------------------------------------- */


/* ==================== the tiles ====================
   All picture, with the writing laid over it. The vibe's colour is the ground
   under the photograph rather than a tint beside it, so a tile with no picture
   still comes out as that vibe rather than as an empty box. */

/* One row that scrolls sideways — for a panel that has a fixed height and any
   number of vibes to show in it, like the search Quickview.

   align-items: center because a flex row stretches its children, which would
   pull every tile to the full height of the pane it sits in. */
.gq-vt-row {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: 10px;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: thin;
}

/* The same tiles as a bento, for a page with the width to lay them out — the
   listing page's own band, where a sideways strip would waste a full-width
   section on two vibes and hide the rest.

   Written as an upgrade to the row rather than a layout of its own: the page
   carries BOTH classes, and everything below sits inside a min-width query. A
   phone therefore gets exactly what search gets — the row above, one height,
   one size, scrolled sideways with a thumb, which is the gesture a phone
   already uses for this page's photo mosaic. Nothing to undo, and the row's
   rules are written once.

   The first vibe leads at twice the width and twice the height. It is not an
   arbitrary emphasis: the vibes are in the partner's own rank order, so the
   first one is the one they put first, and it is the only tile with the room
   to show four lines of its note rather than two.

   760px is the listing page's own phone breakpoint — the width at which its
   photo mosaic becomes a scroller too. */
@media (min-width: 761px) {
    /* A fixed column count rather than auto-fill, because the lead spans two of
       them and a track count that changes with the container would leave it
       spanning a row it no longer fits. */
    .gq-vt-bento {
        display: grid;
        grid-template-columns: repeat(4, minmax(0, 1fr));
        grid-auto-rows: 200px;
        gap: 12px;

        /* Both undo the row underneath. align-items:center is what stops a flex
           row stretching its tiles to the pane's height; left on a grid it stops
           them filling their track instead, and a tile whose contents are all
           absolutely positioned then measures zero. overflow-x:auto is the row's
           sideways scroll, and a grid with one axis scrollable makes the other
           scrollable too — which clips the hover lift and its shadow. */
        align-items: stretch;
        overflow: visible;
    }

    .gq-vt-bento .gq-vt {
        /* The row height sizes these, not the tile — see .gq-vt, which is fixed
           at 236x200 for the sideways row it was written for. */
        flex: none;
        height: auto;
    }

    /* At five vibes exactly, and at no other count. A lead of two columns by two
       rows leaves four cells beside it: four others fill them and the band comes
       out as one clean rectangle. Three would leave a hole next to the lead, and
       six would leave one tile alone on a row below it. Every other count is
       drawn as equal tiles, which wrap without a gap at any number.

       Today that is two destinations out of 133; the other 114-odd carry four
       vibes and are drawn as equal tiles. The rule is about what tiles cleanly,
       not about what is common. */
    .gq-vt-bento > .gq-vt:first-child:nth-last-child(5) { grid-column: span 2; grid-row: span 2; }

    /* Everything on the lead tile grows with it. Left at the small sizes, a
       400px-tall picture carries a caption meant for a tile a quarter its size. */
    .gq-vt-bento > .gq-vt:first-child:nth-last-child(5) .gq-vt-body { padding: 34px 16px 15px; gap: 5px; }
    .gq-vt-bento > .gq-vt:first-child:nth-last-child(5) .gq-vt-name { font-size: 17px; gap: 8px; }

    .gq-vt-bento > .gq-vt:first-child:nth-last-child(5) .gq-vt-note {
        font-size: 13.5px;
        line-height: 1.55;
        -webkit-line-clamp: 4;
        line-clamp: 4;
    }

    .gq-vt-bento > .gq-vt:first-child:nth-last-child(5) .gq-vt-more {
        width: 32px;
        height: 32px;
        font-size: 12px;
    }
}

/* Two columns, so the lead is the full width of the band and the rest pair off
   under it. Four tracks at this width put every tile below reading size — this
   is also where the listing page has dropped its sidebar and the band runs the
   whole width. */
@media (min-width: 761px) and (max-width: 980px) {
    .gq-vt-bento { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}


/* A div, not a button: the whole tile opens the note, but the button inside it
   is the only focusable thing, so the keyboard gets one stop per tile instead
   of two that do the same job. */
.gq-vt {
    position: relative;
    /* The name shares its row with a 26px arrow rather than a labelled button,
       so the tile does not have to be wide enough for both. */
    flex: 0 0 236px;
    height: 200px;
    border-radius: 10px;
    /* The picture goes edge to edge inside the rounded corners. */
    overflow: hidden;
    background: var(--vc, var(--gq-blue));
    cursor: pointer;
    transition: box-shadow .18s ease, transform .18s ease;
}

.gq-vt:hover {
    box-shadow: 0 16px 28px -18px rgba(10, 32, 56, .75);
    transform: translateY(-2px);
}

.gq-vt:has(.gq-vt-more:focus-visible) {
    outline: 3px solid var(--vc, var(--gq-blue));
    outline-offset: 2px;
}

/* The whole tile. .gq-vibe-blank pins itself to the box it is given, which is
   why this one is positioned. */
.gq-vt-art {
    position: absolute;
    inset: 0;
    display: block;
    overflow: hidden;
}

.gq-vt-art img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* The emblem a vibe with no photograph falls back to sits centred in its box
   by default — right for the picker previews and the vibe directory, where
   nothing covers it. Here the caption lies over the foot of the picture, so
   centred reads as low: the disc is in the middle of the tile but below the
   middle of what can still be seen of it. A third from the top puts it back in
   the clear. Only inside a tile — shared/vibe-blank.css is left alone. */
.gq-vt-art .gq-vibe-blank-disc {
    position: absolute;
    top: 33%;
    left: 50%;
    transform: translate(-50%, -50%);
}

/* Over the foot of the picture, on a scrim mixed from the vibe's own colour.
   A caption bar sized to the text would eat a third of the tile and put the
   writing beside the picture again; a gradient keeps white legible over
   whatever the photograph happens to be while the tile stays all image. */
.gq-vt-body {
    position: absolute;
    inset: auto 0 0 0;
    min-width: 0;
    padding: 22px 12px 11px;
    display: flex;
    flex-direction: column;
    gap: 3px;
    color: #fff;
    background: linear-gradient(to top,
        color-mix(in srgb, var(--vc, #123B63) 92%, #000 30%) 28%,
        transparent);
}

/* Name and the way in, on one line. */
.gq-vt-head {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

.gq-vt-name {
    margin: 0;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 13.5px;
    font-weight: 800;
    color: #fff;
    text-shadow: 0 1px 6px rgba(0, 0, 0, .55);
    /* One line: the button holds the right of this row and a wrapping name
       would push it out of the tile. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.gq-vt-name i { flex-shrink: 0; opacity: .92; }

/* Two lines over the picture. Three was right when the writing had a white card
   to itself; over a photograph the scrim has to grow to carry every line, and
   at three it covered half the image the tile exists to show. */
.gq-vt-note {
    margin: 0;
    font-size: 12px;
    line-height: 1.45;
    color: rgba(255, 255, 255, .93);
    text-shadow: 0 1px 5px rgba(0, 0, 0, .5);
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
}

.gq-vt-more {
    margin-left: auto;
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    /* An arrow, no word. Quiet on purpose: a solid white pill read as the
       loudest thing on the tile and pulled the eye off both the picture and the
       name beside it — glass says "press me" without competing for the tile. */
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    border: 1px solid rgba(255, 255, 255, .38);
    border-radius: 999px;
    background: rgba(255, 255, 255, .16);
    backdrop-filter: blur(3px);
    color: #fff;
    font: inherit;
    font-size: 10.5px;
    cursor: pointer;
    transition: background .18s ease, border-color .18s ease;
}

.gq-vt:hover .gq-vt-more {
    border-color: rgba(255, 255, 255, .7);
    background: rgba(255, 255, 255, .28);
}

/* The word stays in the markup for anything reading the page rather than
   looking at it — a button whose only content is an arrow says nothing to a
   screen reader. */
.gq-vt-more > span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}


/* ==================== the reader ==================== */

.gq-vr { position: fixed; inset: 0; z-index: 11600; display: grid; place-items: center; }
.gq-vr[hidden] { display: none; }
.gq-vr-bg { position: absolute; inset: 0; background: rgba(8, 22, 38, .72); }

.gq-vr-box {
    position: relative;
    width: min(560px, calc(100vw - 32px));
    max-height: calc(100vh - 48px);
    overflow: auto;
    border-radius: 14px;
    background: #fff;
    box-shadow: 0 40px 80px -30px rgba(6, 20, 36, .7);
}

.gq-vr-x {
    position: absolute;
    top: 10px;
    right: 10px;
    z-index: 2;
    width: 32px;
    height: 32px;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, .92);
    color: var(--gq-navy);
    cursor: pointer;
    box-shadow: 0 3px 10px -2px rgba(0, 0, 0, .4);
}

/* Sized here rather than by the picture, for the same reason as everywhere else
   this component appears: the emblem is absolutely positioned. */
.gq-vr-art { position: relative; aspect-ratio: 16 / 9; background: var(--vc, var(--gq-blue)); }
.gq-vr-art img { width: 100%; height: 100%; object-fit: cover; display: block; }

.gq-vr-body { padding: 16px 18px 20px; }

.gq-vr-body h3 {
    margin: 0 0 8px;
    font-size: 17px;
    font-weight: 800;
    color: color-mix(in srgb, var(--vc, var(--gq-navy)) 72%, #000 16%);
}

.gq-vr-body p { margin: 0; font-size: 13.5px; line-height: 1.65; color: var(--gq-slate); }

.gq-vr-body h4 {
    margin: 16px 0 6px;
    font-size: 11px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--gq-mist);
}

.gq-vr-list { margin: 0; padding-left: 18px; font-size: 13px; line-height: 1.6; color: var(--gq-slate); }

/* A named place and why it was named. The reason is what a partner actually
   took the trouble to write, and search is the only caller that has to cut it. */
.gq-vr-list b { display: block; font-weight: 700; color: var(--gq-navy); }

/* The way on, and the last thing in the reader. Only the listing page carries
   one — a vibe read from a search result already sits in a list of places, and
   a second way into one from there is a way back to where you are. */
/* Scoped to the dialog rather than named alone: the website puts .gqv2 on
   <body>, and `.gqv2 a` would otherwise repaint this link's text. */
.gq-vr .gq-vr-cta {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    margin-top: 18px;
    padding: 13px 20px;
    border-radius: 11px;
    /* --vfill, not --vc: this is the one place white sits ON the colour rather
       than over a photograph, and four of the palette's hexes fail white text
       outright. web_vibe_tile() darkens it only as far as AA needs. */
    background: var(--vfill, var(--vc, var(--gq-navy)));
    color: #fff;
    font-size: 13.5px;
    font-weight: 700;
    transition: filter .18s ease, transform .18s ease;
}

.gq-vr .gq-vr-cta:hover { color: #fff; filter: brightness(1.12); transform: translateY(-2px); }
.gq-vr .gq-vr-cta i { font-size: 11px; }

.gq-vr-count { margin: 10px 0 0; text-align: center; font-size: 12.5px; color: var(--gq-mist); }

@media (max-width: 560px) {
    .gq-vr { place-items: end center; }
    .gq-vr-box { width: 100%; max-height: 92vh; border-radius: 14px 14px 0 0; }
}
