/*
 * Tiles theme, a friendlier tile-based layout for the owner and member areas.
 *
 * Loads AFTER the base public stylesheet, so it only carries the DELTA from
 * Classic. Same full feature set as Classic, nothing removed. All rules are
 * scoped under .tiled-home so nothing outside the themed dashboards is touched.
 *
 * Design intent: one calm screen, hierarchy by depth. A big adaptive hero, two
 * big daily tiles, then lighter tools, then compact numbers, then a quiet list.
 * Text is given room and balanced so words never break awkwardly across lines.
 */

.tiled-home { display: flex; flex-direction: column; }
.tiled-home * { overflow-wrap: break-word; }

/* Greeting */
.tiled-home .th-greet {
	display: flex; align-items: center; gap: var(--sp-3);
	flex-wrap: wrap; margin: var(--sp-2) 0 var(--sp-5);
}
.tiled-home .th-greet__hi {
	font-family: var(--font-display); font-weight: 800;
	font-size: var(--fs-lg); letter-spacing: -0.02em; line-height: 1.1; color: var(--ink);
}
.tiled-home .th-greet__venue {
	margin-left: auto; display: inline-flex; align-items: center; gap: 6px;
	background: var(--bg-card); border: 1px solid var(--line); border-radius: var(--r-pill);
	padding: 6px 13px; font-size: var(--fs-sm); font-weight: 650; color: var(--ink-soft);
}

/* Adaptive "right now" hero, the signature element */
.tiled-home .th-hero { border-radius: var(--r-xl); padding: var(--sp-5); position: relative; overflow: hidden; }
.tiled-home .th-hero__top { display: flex; align-items: center; gap: var(--sp-4); }
.tiled-home .th-hero__n {
	flex: none; width: 60px; height: 60px; border-radius: var(--r-lg);
	display: grid; place-items: center;
	font-family: var(--font-display); font-weight: 800; font-size: var(--fs-xl);
}
.tiled-home .th-hero__n svg { width: 30px; height: 30px; }
.tiled-home .th-hero__tx { flex: 1; min-width: 0; }
.tiled-home .th-hero__tx b {
	display: block; font-family: var(--font-display); font-size: var(--fs-md);
	font-weight: 750; letter-spacing: -0.01em; line-height: 1.2; text-wrap: balance;
}
.tiled-home .th-hero__tx span { display: block; font-size: var(--fs-sm); margin-top: 3px; text-wrap: pretty; }
.tiled-home .th-hero__go {
	display: inline-block; margin-top: var(--sp-4);
	background: #fff; color: var(--act-hover); font-weight: 750; font-size: var(--fs-base);
	padding: 11px 22px; border-radius: var(--r-pill); text-decoration: none;
	box-shadow: 0 4px 12px rgba(16, 40, 44, 0.12);
}
/* urgent */
.tiled-home .th-hero--urgent { background: linear-gradient(135deg, var(--act), var(--act-hover)); color: #fff; box-shadow: 0 16px 32px -14px rgba(14, 110, 104, 0.7); }
.tiled-home .th-hero--urgent::after { content: ""; position: absolute; right: -34px; top: -34px; width: 150px; height: 150px; border-radius: 50%; background: radial-gradient(circle, rgba(240, 167, 44, 0.4), transparent 70%); }
.tiled-home .th-hero--urgent .th-hero__top, .tiled-home .th-hero--urgent .th-hero__go { position: relative; }
.tiled-home .th-hero--urgent .th-hero__n { background: rgba(255, 255, 255, 0.17); }
.tiled-home .th-hero--urgent .th-hero__tx span { color: #c3e2de; }
/* clear */
.tiled-home .th-hero--clear { background: var(--act-wash); color: var(--act-hover); }
.tiled-home .th-hero--clear .th-hero__n { background: #fff; color: var(--good-600); }
.tiled-home .th-hero--clear .th-hero__tx span { color: var(--act); }

/* Sections: big gaps between, tight within */
.tiled-home .th-sec { margin-top: var(--sp-8); }
.tiled-home .th-sec__label {
	font-family: var(--font-display); font-weight: 700; font-size: var(--fs-sm);
	color: var(--ink-soft); margin: 0 0 var(--sp-3); padding: 0 2px;
}

/* Primary tiles (the daily work) */
.tiled-home .th-primary { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
.tiled-home .th-ptile {
	position: relative; display: flex; flex-direction: column;
	background: var(--bg-card); border-radius: var(--r-xl); padding: var(--sp-4);
	min-height: 108px; box-shadow: var(--shadow-card);
	text-decoration: none; color: inherit; transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.tiled-home .th-ptile:hover { transform: translateY(-2px); box-shadow: var(--shadow-pop); }
.tiled-home .th-ptile:focus-visible { outline: none; box-shadow: var(--ring); }
.tiled-home .th-ptile__ic { width: 48px; height: 48px; border-radius: var(--r-md); display: grid; place-items: center; margin-bottom: var(--sp-3); }
.tiled-home .th-ptile__ic svg { width: 24px; height: 24px; }
.tiled-home .th-ic--act { background: var(--act-wash); color: var(--act-hover); }
.tiled-home .th-ic--sun { background: var(--sun-wash); color: #b9791a; }
.tiled-home .th-ptile__lb { font-family: var(--font-display); font-weight: 750; font-size: var(--fs-md); letter-spacing: -0.01em; line-height: 1.15; text-wrap: balance; }
.tiled-home .th-ptile__st { font-size: var(--fs-sm); color: var(--ink-faint); margin-top: 3px; font-weight: 600; }
.tiled-home .th-ptile__st.is-hot { color: var(--match); font-weight: 750; }
.tiled-home .th-ptile__cnt {
	position: absolute; top: var(--sp-4); right: var(--sp-4);
	min-width: 26px; height: 26px; padding: 0 7px; border-radius: 13px;
	background: var(--match); color: #fff;
	font-family: var(--font-display); font-weight: 800; font-size: var(--fs-base);
	display: grid; place-items: center; box-shadow: 0 4px 10px rgba(206, 61, 110, 0.4);
}

/* Your move teaser (one card, links to the full briefing) */
.tiled-home .th-move { background: var(--bg-card); border: 1px solid var(--line); border-left: 3px solid var(--match); border-radius: var(--r-lg); padding: var(--sp-4); }
.tiled-home .th-move__top { display: flex; align-items: flex-start; gap: var(--sp-3); }
.tiled-home .th-move__ic { width: 34px; height: 34px; flex: none; border-radius: 10px; background: var(--match-wash); color: var(--match); display: grid; place-items: center; }
.tiled-home .th-move__ic svg { width: 18px; height: 18px; }
.tiled-home .th-move h4 { font-family: var(--font-display); font-weight: 750; font-size: var(--fs-base); margin: 0; letter-spacing: -0.01em; text-wrap: balance; }
.tiled-home .th-move p { margin: 4px 0 0; font-size: var(--fs-sm); color: var(--ink-soft); line-height: 1.5; text-wrap: pretty; }
.tiled-home .th-move__row { display: flex; align-items: center; gap: var(--sp-4); margin-top: var(--sp-4); flex-wrap: wrap; }
.tiled-home .th-move__row .btn-act { padding: 9px 18px; font-size: var(--fs-sm); }
.tiled-home .th-move__see { font-size: var(--fs-sm); font-weight: 650; color: var(--act); text-decoration: none; display: inline-flex; align-items: center; gap: 5px; }
.tiled-home .th-move__see svg { width: 14px; height: 14px; }
.tiled-home .th-receipt { display: flex; align-items: center; gap: 8px; margin-top: var(--sp-3); font-size: var(--fs-xs); color: var(--good-600); font-weight: 600; }
.tiled-home .th-receipt__chk { width: 18px; height: 18px; flex: none; border-radius: 6px; background: var(--good-100); display: grid; place-items: center; }
.tiled-home .th-receipt__chk svg { width: 11px; height: 11px; }

/* Grow tiles (flat, lighter than primary) */
.tiled-home .th-grow { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(150px, 100%), 1fr)); gap: var(--sp-3); }
.tiled-home .th-gtile { display: flex; flex-direction: column; background: var(--bg-card); border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--sp-4); min-height: 82px; text-decoration: none; color: inherit; transition: background 0.12s ease; }
.tiled-home .th-gtile:hover { background: var(--wash-50); }
.tiled-home .th-gtile__ic { width: 36px; height: 36px; border-radius: var(--r-md); display: grid; place-items: center; margin-bottom: var(--sp-2); background: var(--wash-100); color: var(--petrol-600); }
.tiled-home .th-gtile__ic svg { width: 18px; height: 18px; }
.tiled-home .th-gtile__lb { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-base); letter-spacing: -0.01em; line-height: 1.15; text-wrap: balance; }
.tiled-home .th-gtile__st { font-size: var(--fs-xs); color: var(--ink-faint); margin-top: 3px; font-weight: 600; }

/* Numbers strip + trends disclosure */
.tiled-home .th-stats { display: flex; background: var(--bg-card); border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden; }
.tiled-home .th-stats__s { flex: 1; text-align: center; padding: var(--sp-4) var(--sp-2); border-right: 1px solid var(--line); }
.tiled-home .th-stats__s:last-child { border-right: 0; }
.tiled-home .th-stats__s b { display: block; font-family: var(--font-display); font-weight: 800; font-size: var(--fs-xl); color: var(--act); letter-spacing: -0.02em; }
.tiled-home .th-stats__s span { display: block; font-size: var(--fs-xs); color: var(--ink-faint); margin-top: 2px; font-weight: 600; }
.tiled-home .th-trends-toggle { margin-top: var(--sp-2); display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-sm); font-weight: 650; color: var(--act); cursor: pointer; padding: 8px 2px; user-select: none; background: none; border: 0; }
.tiled-home .th-trends-toggle svg { width: 14px; height: 14px; transition: transform 0.2s ease; }
.tiled-home .th-trends-toggle.is-open svg { transform: rotate(90deg); }
.tiled-home .th-trends { display: none; grid-template-columns: repeat(auto-fill, minmax(min(240px, 100%), 1fr)); gap: var(--sp-4); margin-top: var(--sp-3); }
.tiled-home .th-trends.is-open { display: grid; }

/* Manage list (quiet, dividers) */
.tiled-home .th-manage { background: var(--bg-card); border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden; }
.tiled-home .th-manage a { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); text-decoration: none; color: var(--ink); border-top: 1px solid var(--line); font-size: var(--fs-base); font-weight: 600; min-height: 48px; }
.tiled-home .th-manage a:first-child { border-top: 0; }
.tiled-home .th-manage__ic { width: 20px; height: 20px; flex: none; color: var(--ink-faint); }
.tiled-home .th-manage__ic svg { width: 20px; height: 20px; }
.tiled-home .th-manage__ct { margin-left: auto; display: flex; align-items: center; gap: 8px; color: var(--ink-faint); }
.tiled-home .th-manage__ct .b { background: var(--match-wash); color: var(--match); font-weight: 750; font-size: var(--fs-xs); padding: 2px 8px; border-radius: var(--r-pill); }
.tiled-home .th-manage__ct svg { width: 16px; height: 16px; }

/* Venue switcher cards keep their base styling, just spaced under the heading */
.tiled-home .card-grid { margin-top: var(--sp-3); }

/* ============================================================================
 * Carry the Tiles look to EVERY owner page, not just the dashboard.
 *
 * Scoped through .portal-nav__scan, the "Open The Pass" button that appears
 * only in the OWNER nav (the member account nav has no scan button), so the
 * public site and the member area are left exactly as Classic. This is a
 * visual restyle only, no page is restructured and no feature is touched.
 * ============================================================================ */

/* Owner nav: warmer, roomier, a clearer active tab */
.portal-nav:has(.portal-nav__scan) { border-radius: var(--r-xl); box-shadow: var(--shadow-card); padding: var(--sp-4); gap: var(--sp-4); }
.portal-nav:has(.portal-nav__scan) .portal-nav__scan { border-radius: var(--r-lg); }
.portal-nav:has(.portal-nav__scan) .portal-tab { min-height: 46px; padding: 0 16px; }
.portal-nav:has(.portal-nav__scan) .portal-tab.is-here { box-shadow: 0 4px 12px rgba(14, 110, 104, 0.28); }

/* Owner page shells: balanced headings, and long words never force sideways scroll */
.section:has(.portal-nav__scan) * { overflow-wrap: break-word; }
.section:has(.portal-nav__scan) h1,
.section:has(.portal-nav__scan) h2 { text-wrap: balance; }

/* Cards and notes: rounder and softer, the tile warmth */
.section:has(.portal-nav__scan) .card { border-radius: var(--r-xl); box-shadow: var(--shadow-card); }
.section:has(.portal-nav__scan) .memory-note { border-radius: var(--r-lg); padding: var(--sp-4) var(--sp-5); }
.section:has(.portal-nav__scan) .panel { border-radius: var(--r-xl); }

/* Friendly buttons: the default CTAs get a comfortable tap size; inline-styled
   utility buttons carry their own padding and are deliberately left as they are. */
.section:has(.portal-nav__scan) .btn:not([style]) { min-height: 46px; padding: 12px 22px; font-size: var(--fs-base); font-weight: 700; }

/* Comfortable, rounded form controls (native controls like checkboxes untouched) */
.section:has(.portal-nav__scan) input[type="text"],
.section:has(.portal-nav__scan) input[type="email"],
.section:has(.portal-nav__scan) input[type="tel"],
.section:has(.portal-nav__scan) input[type="number"],
.section:has(.portal-nav__scan) input[type="date"],
.section:has(.portal-nav__scan) input[type="time"],
.section:has(.portal-nav__scan) input[type="password"],
.section:has(.portal-nav__scan) input[type="search"],
.section:has(.portal-nav__scan) select,
.section:has(.portal-nav__scan) textarea {
	border-radius: var(--r-md); border: 1px solid var(--line);
	padding: 11px 14px; font-size: var(--fs-base);
	background: var(--bg-card); color: var(--ink);
}
.section:has(.portal-nav__scan) input:focus,
.section:has(.portal-nav__scan) select:focus,
.section:has(.portal-nav__scan) textarea:focus {
	outline: none; border-color: var(--act); box-shadow: var(--ring);
}

/* Stat tiles keep the friendly radius */
.section:has(.portal-nav__scan) .stat { border-radius: var(--r-lg); }

/* ============================================================================
 * Compact owner nav: the tab grid folds behind one Menu toggle, so an owner
 * page opens on content instead of a screen of links. Open The Pass stays out,
 * always one thumb away. On a wide screen theme.js adds .is-wide + [open] so
 * the tabs read inline exactly as Classic does.
 * ============================================================================ */

.portal-nav--fold .portal-menu > summary {
	list-style: none; cursor: pointer;
	display: flex; align-items: center; gap: var(--sp-2);
	min-height: 46px; padding: 0 14px;
	border-radius: var(--r-pill);
	background: var(--bg-dip); color: var(--ink);
	font-family: var(--font-display); font-weight: 700; font-size: var(--fs-sm);
}
.portal-nav--fold .portal-menu > summary::-webkit-details-marker { display: none; }
.portal-nav--fold .portal-menu > summary::marker { content: ""; }
.portal-nav--fold .portal-menu > summary:hover { background: var(--act-wash); color: var(--act-hover); }
.portal-nav--fold .portal-menu > summary:focus-visible { outline: none; box-shadow: var(--ring); }
.portal-nav--fold .portal-menu__label { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
.portal-nav--fold .portal-menu__here {
	font-family: var(--font-body); font-weight: 650; color: var(--act);
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.portal-nav--fold .portal-menu__chev { margin-left: auto; display: flex; transition: transform 0.2s ease; }
.portal-nav--fold .portal-menu__chev svg { width: 16px; height: 16px; }
.portal-nav--fold .portal-menu[open] > summary .portal-menu__chev { transform: rotate(90deg); }
.portal-nav--fold .portal-menu > .portal-nav__tabs { margin-top: var(--sp-3); }

/* Wide screens: show the tabs inline and drop the toggle */
.portal-nav--fold.is-wide .portal-menu > summary { display: none; }
.portal-nav--fold.is-wide .portal-menu > .portal-nav__tabs { margin-top: 0; }

/* ============================================================================
 * Homepage: concierge-led hero. The wall of equal mood chips becomes a living
 * concierge prompt plus a one-row mood swipe, so the hero fits one screen and
 * real content peeks up under the fold. Own class (.mood-hero), so the base
 * .hero used elsewhere is untouched.
 * ============================================================================ */

.mood-hero { background: linear-gradient(160deg, #153138 0%, var(--bg-ink, #10282C) 72%); color: var(--ink-on-dark, #F2F7F6); position: relative; overflow: hidden; }
.mood-hero::after { content: ""; position: absolute; right: -120px; top: -120px; width: 520px; height: 520px; border-radius: 50%; background: radial-gradient(circle, rgba(240, 167, 44, 0.28) 0%, rgba(240, 167, 44, 0.10) 45%, transparent 70%); pointer-events: none; }
.mood-hero > .wrap { position: relative; padding-top: var(--sp-8); padding-bottom: var(--sp-10); }
.mood-hero h1 { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-hero); line-height: 1.03; letter-spacing: -0.025em; margin: 0; text-wrap: balance; }
.mood-hero__lead { color: var(--ink-on-dark-soft, #A9C0BD); font-size: var(--fs-md); line-height: 1.5; margin: var(--sp-3) 0 0; max-width: 36ch; }

/* The ask hero (v9.16): one block, three asks. The concierge pill and the
   mood swipe retired with the old hero markup in the same release; the hero
   band and its citrus orb above are inherited from .mood-hero unchanged.
   The [hidden] overrides exist because .ask-card and .ask-field set display,
   and a display rule on the class beats the user agent's [hidden] default. */
.ask-hero .wrap { text-align: center; }
.ask-hero h1 { max-width: 20ch; margin: 0 auto; }
.ask-hero .mood-hero__lead { margin: var(--sp-3) auto 0; max-width: 54ch; }
.ask-block { max-width: 880px; margin: var(--sp-7) auto 0; }
.ask-tabs { display: flex; justify-content: flex-start; gap: 6px; padding-left: 18px; }
.ask-tab { display: inline-flex; align-items: center; gap: 8px; border: 1px solid rgba(255, 255, 255, 0.16); border-bottom: 0; background: rgba(255, 255, 255, 0.08); color: var(--ink-on-dark-soft, #A9C0BD); font: inherit; font-size: var(--fs-base); font-weight: 700; padding: 11px 22px 13px; border-radius: var(--r-md) var(--r-md) 0 0; cursor: pointer; }
.ask-tab .cb-ico { width: 18px; height: 18px; }
.ask-tab.is-on { background: var(--bg-card); color: var(--ink); border-color: var(--bg-card); }
.ask-tab.is-on .cb-ico { color: var(--act); }
.ask-tab:not(.is-on):hover { background: rgba(255, 255, 255, 0.12); color: #fff; }
.ask-card { display: flex; align-items: stretch; background: var(--bg-card); border-radius: var(--r-lg); box-shadow: var(--shadow-pop); padding: 10px; text-align: left; }
.ask-card[hidden] { display: none; }
.ask-card:focus-within { box-shadow: var(--shadow-pop), 0 0 0 3px rgba(240, 167, 44, 0.25); }
/* The CARD is the focus indicator (the citrus halo above), so the fields
   inside it must not draw a second ring of their own: the global
   :focus-visible rule in public.css was boxing the bare input inside the
   already-glowing card, two rings for one focus. Scoped here on purpose;
   everywhere else on the site the field's own ring IS the focus indicator
   and stays (keyboard users need one visible focus, WCAG). */
.ask-card .ask-input:focus, .ask-card .ask-input:focus-visible { outline: none; box-shadow: none; border-radius: 0; }
.ask-field { display: flex; flex-direction: column; gap: 3px; justify-content: center; padding: 8px 18px; border-left: 1px solid var(--line); min-width: 0; }
.ask-field:first-child { border-left: 0; }
.ask-field[hidden] { display: none; }
.ask-field--grow { flex: 1; }
.ask-card--even .ask-field { flex: 1; }
.ask-label { font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-faint); }
.ask-input { border: 0; outline: none; background: transparent; font: inherit; font-size: var(--fs-md); font-weight: 600; color: var(--ink); padding: 0; width: 100%; appearance: none; }
.ask-input::placeholder { color: var(--ink-soft); font-weight: 500; transition: opacity 0.25s ease; }
.ask-card.is-cycling .ask-input::placeholder { opacity: 0; }
select.ask-input { background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236E8482' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right center; background-size: 14px; padding-right: 20px; }
.ask-go { flex: none; align-self: center; margin-left: var(--sp-3); background: var(--act); color: #fff; border: 0; font: inherit; font-size: var(--fs-base); font-weight: 700; padding: 14px 26px; border-radius: var(--r-pill); cursor: pointer; transition: background 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease; white-space: nowrap; }
.ask-go:hover { background: var(--act-hover); transform: translateY(-1px); box-shadow: 0 6px 16px -6px rgba(14, 110, 104, 0.55); }
.ask-go:active { transform: translateY(0); box-shadow: none; }
.ask-foot { margin-top: var(--sp-3); font-size: var(--fs-sm); color: var(--ink-on-dark-soft, #A9C0BD); }
.ask-foot__link { color: var(--sun, #F0A72C); font-weight: 650; text-decoration: none; }
.ask-foot__link:hover { text-decoration: underline; }

/* ============================================================================
 * The 5-second screen (v9.46). Eyebrow over the headline, a tighter hero, and
 * the quick-action bar straddling the hero's lower edge: a light ledge half in
 * the dark band, half out, so the four primary journeys sit AT the fold and
 * read as part of the hero without being a second voice above it.
 * ============================================================================ */

.mood-hero__eyebrow { margin: 0 0 var(--sp-2); font-size: var(--fs-sm); font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--sun, #F0A72C); }
/* The one sentence allowed to be loudest, lifted to full white inside the lead. */
.mood-hero__zero { color: var(--ink-on-dark, #F2F7F6); font-weight: 700; }
/* Tighter band; the straddling bar hands back the breathing room below. */
.ask-hero > .wrap { padding-top: var(--sp-7); padding-bottom: calc(var(--sp-8) + 40px); }

.quick-act { position: relative; z-index: 2; }
/*
 * THE PULL BELONGS TO THE SEAM, NOT TO THE BAR (v10.75).
 *
 * This row was pulled up 46px unconditionally so it straddled the hero's lower
 * edge. That is right in the one place it was born in and wrong everywhere
 * else: the block is reorderable now, and anywhere further down the page a
 * fixed negative margin drags it up into whatever section is above it. It is
 * the same collision the district strip caused when it was put in this seam.
 *
 * So the pull is expressed as adjacency instead of as a constant. Directly
 * after the hero it straddles; moved anywhere else the selector stops matching
 * and the bar simply sits where it was put. Nothing to remember, nothing to
 * switch, and it cannot be got wrong from the builder.
 */
.quick-act__row { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-3); }
.mood-hero + .quick-act .quick-act__row { margin-top: -46px; }
.quick-act__item {
	display: flex; flex-direction: column; align-items: flex-start; gap: 2px; min-width: 0;
	background: var(--bg-card); border: 1px solid var(--line); border-radius: var(--r-lg);
	padding: var(--sp-4); text-align: left; text-decoration: none; color: inherit;
	font: inherit; cursor: pointer; box-shadow: var(--shadow-card);
	transition: transform 0.14s ease, box-shadow 0.14s ease;
}
.quick-act__item:hover { transform: translateY(-2px); box-shadow: var(--shadow-pop); }
.quick-act__item:focus-visible { outline: none; box-shadow: var(--shadow-card), var(--ring); }
.quick-act__ic { display: grid; place-items: center; width: 38px; height: 38px; border-radius: var(--r-md); background: var(--act-wash); color: var(--act); margin-bottom: var(--sp-2); }
.quick-act__ic .cb-ico { width: 19px; height: 19px; }
.quick-act__item b { font-family: var(--font-display); font-weight: 750; font-size: var(--fs-base); letter-spacing: -0.01em; text-wrap: balance; overflow-wrap: break-word; }
.quick-act__item > span:last-child { font-size: var(--fs-xs); color: var(--ink-faint); font-weight: 550; overflow-wrap: break-word; }

/* ---- The price-quote sheet ---- */
.sheet[hidden] { display: none; }
.sheet { position: fixed; inset: 0; z-index: 95; display: grid; place-items: center; padding: var(--sp-4); }
.sheet__scrim { position: absolute; inset: 0; background: rgba(16, 40, 44, 0.55); }
.sheet__card { position: relative; width: min(460px, 100%); max-height: min(84vh, 640px); overflow: auto; background: var(--bg-card); border-radius: var(--r-xl); box-shadow: var(--shadow-pop); padding: var(--sp-5); }
.sheet__head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.sheet__head h3 { margin: 0; font-family: var(--font-display); font-weight: 800; font-size: var(--fs-lg); letter-spacing: -0.015em; }
.sheet__x { display: grid; place-items: center; width: 34px; height: 34px; flex: none; border: 0; border-radius: 50%; background: var(--bg-dip); color: var(--ink-soft); cursor: pointer; }
.sheet__x:hover { background: var(--wash-100); color: var(--ink); }
.sheet__sub { margin: var(--sp-2) 0 var(--sp-4); font-size: var(--fs-sm); color: var(--ink-soft); text-wrap: pretty; }
.sheet__rows { display: flex; flex-direction: column; gap: 6px; }

/* THE TABLE SHEET (v17.11). Two routes to a table in one panel: a name if they
   have one, a few chips if they do not. Deliberately no heading above the
   search field: it is the first thing in the panel and focused, which says
   what it is for more clearly than a label would. */
.ts { display: flex; flex-direction: column; gap: var(--sp-3); }
.ts__q { width: 100%; padding: 13px 15px; font: inherit; border: 1px solid var(--line); border-radius: var(--r-md, 12px); background: var(--bg-card, #fff); color: var(--ink); }
.ts__q:focus-visible { outline: none; box-shadow: var(--ring); }
/* Capped and scrollable: six matches is plenty, and a long list must not push
   the filters below the fold of a phone. */
.ts__hits { display: flex; flex-direction: column; gap: 2px; max-height: 240px; overflow-y: auto; border: 1px solid var(--line); border-radius: var(--r-md, 12px); padding: 4px; }
.ts__hit { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; width: 100%; padding: 9px 11px; text-align: left; background: none; border: 0; border-radius: 9px; cursor: pointer; font: inherit; }
.ts__hit:hover, .ts__hit:focus-visible { background: var(--bg-soft, #F4F7F6); outline: none; }
.ts__hit b { font-weight: 700; }
.ts__hit span { font-size: var(--fs-sm); color: var(--ink-soft); }
.ts__nohit { margin: 0; padding: 10px 11px; font-size: var(--fs-sm); color: var(--ink-soft); }
.ts__or { margin: var(--sp-1) 0 0; font-size: var(--fs-sm); color: var(--ink-faint); }
/* Explicit two columns rather than auto-fit, so the pair never collapses into
   one wide select with a gap beside it. */
.ts__filters { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2); }
.ts__sel { width: 100%; min-width: 0; padding: 11px 13px; font: inherit; border: 1px solid var(--line); border-radius: var(--r-md, 12px); background: var(--bg-card, #fff); color: var(--ink); }
.ts__moods { display: flex; flex-wrap: wrap; gap: 6px; }
.ts__mood { padding: 7px 13px; font: inherit; font-size: var(--fs-sm); border: 1px solid var(--line); border-radius: 999px; background: var(--bg-card, #fff); color: var(--ink); cursor: pointer; }
.ts__mood[aria-pressed="true"] { background: var(--act); border-color: var(--act); color: #fff; }
.ts__go { width: 100%; margin-top: var(--sp-1); }
@media (max-width: 420px) { .ts__filters { grid-template-columns: 1fr; } }

/* THE TABLE REQUEST FORM, WHEREVER IT IS RENDERED (moved here v17.11).
   It lived in a style block inside reserve.php, which dressed the page and left
   the copy fetched into the curtain with no styles at all: six full-width boxes
   where a compact grid was meant to be. */
.rv-wishes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); }
.rv-wishes .mood-chip { display: flex; align-items: center; justify-content: flex-start; gap: 10px; text-align: left; line-height: 1.25; }
/* The browser gives a checkbox its own margin (3px 3px 3px 4px), and flex
   centres the MARGIN box, not the control: that asymmetric margin left the box
   sitting three pixels above the middle of every chip, and once seen it cannot
   be unseen. Zeroed here so align-items actually centres what the eye sees. */
.rv-wishes .mood-chip input[type="checkbox"] { margin: 0; flex: none; }

/* AND COMPACT INSIDE THE DRAWER.
   The form was drawn for a 1040px page with a column beside it. In a panel
   between 500 and 780px the same spacing reads as bulky: tall fields, a lot of
   air, and a scroll for what should fit. Everything below only tightens; none
   of it changes the page. */
#vpeek .rv-peekhead { margin-bottom: var(--sp-4); }
#vpeek .rv-peekhead__eyebrow { display: block; font-size: var(--fs-xs); font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--act); }
#vpeek .rv-peekhead__name { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-lg); line-height: 1.15; margin: 4px 0 0; }
#vpeek .rv-peekhead__where { margin: 2px 0 0; font-size: var(--fs-sm); color: var(--ink-soft); }
#vpeek .form-stack { display: flex; flex-direction: column; gap: var(--sp-3); }
/* NOT the wish chips (v17.18). This said "label" and a wish chip IS a label,
   so it beat .rv-wishes .mood-chip on specificity and turned every chip from a
   flex row back into a block: align-items had nothing left to centre, which is
   why the page looked right and the drawer did not. */
#vpeek .form-stack label:not(.mood-chip) { font-size: var(--fs-sm); font-weight: 600; margin-bottom: 3px; display: block; }
#vpeek .form-stack input:not([type="checkbox"]), #vpeek .form-stack textarea, #vpeek .form-stack select { padding: 9px 11px; font-size: var(--fs-sm); }
#vpeek .form-stack textarea { min-height: 64px; }
/* Chips rather than rows: six full-width boxes cost 280px of a panel that has
   a send button to fit as well. */
#vpeek .rv-wishes { gap: 6px; }
#vpeek .rv-wishes .mood-chip { padding: 7px 10px; font-size: var(--fs-sm); gap: 8px; }
#vpeek .qt-chip { padding: 7px 11px; font-size: var(--fs-sm); }
@media (max-width: 560px) { #vpeek .rv-wishes { grid-template-columns: 1fr; } }

/* The request action, inside the card on its traits row (v17.15). It began as
   a full-width bar under each card and was louder than the venue it offered;
   pushed to the end of the row it reads as part of the card rather than an
   advertisement stapled beneath it. */
.dna--withaction { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.r-act { margin-left: auto; padding: 6px 13px; font: inherit; font-size: var(--fs-xs); font-weight: 700; color: #fff; background: var(--act); border: 0; border-radius: 999px; cursor: pointer; white-space: nowrap; }
.r-act:hover { filter: brightness(1.06); }
.r-act:focus-visible { outline: none; box-shadow: var(--ring); }
/* On a narrow drawer the traits wrap; the action then takes its own line
   rather than being squeezed against a chip. */
@media (max-width: 560px) { .r-act { margin-left: 0; width: 100%; text-align: center; } }
.fp__list { display: flex; flex-direction: column; gap: var(--sp-4); }

/* The confirmation, in the drawer (v17.15). Calm rather than celebratory: the
   venue has not answered yet, and a screen that cheers before the answer is a
   screen that lied to somebody by the time it arrives. */
.rsent { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-3); padding-top: var(--sp-2); }
.rsent__tick { display: flex; align-items: center; justify-content: center; width: 46px; height: 46px; border-radius: 50%; background: rgba(14, 110, 104, .10); color: var(--act); }
.rsent__title { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-lg); line-height: 1.2; margin: 0; }
.rsent__sub { margin: 0; font-size: var(--fs-sm); color: var(--ink-soft); line-height: 1.6; }
.rsent__acts { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-2); }

/* SIGNING IN INSIDE THE DRAWER (v17.19). Deliberately plainer than the booking
   form beside it: this is a gate, not a thing to enjoy, and the faster it is
   read the sooner they are through it. */
.apeek { display: flex; flex-direction: column; gap: var(--sp-2); }
.apeek__eyebrow { font-size: var(--fs-xs); font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--act); }
.apeek__title { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-lg); line-height: 1.15; margin: 0; }
.apeek__sub { margin: 0 0 var(--sp-2); font-size: var(--fs-sm); color: var(--ink-soft); line-height: 1.55; }
.apeek__ok { margin: 0; padding: 8px 11px; border-radius: var(--r-md, 12px); background: var(--act-wash); color: var(--act); font-size: var(--fs-sm); }
.apeek__form { display: flex; flex-direction: column; gap: 4px; }
.apeek__form label { font-size: var(--fs-sm); font-weight: 600; margin-top: var(--sp-2); }
.apeek__form input { width: 100%; padding: 10px 12px; font: inherit; font-size: var(--fs-sm); border: 1px solid var(--line); border-radius: var(--r-md, 12px); background: var(--bg-card, #fff); color: var(--ink); }
.apeek__form input:focus-visible { outline: none; box-shadow: var(--ring); }
.apeek__go { width: 100%; margin-top: var(--sp-3); }
.apeek__resend { margin-top: var(--sp-2); }
.apeek__foot { margin: var(--sp-3) 0 0; font-size: var(--fs-sm); color: var(--ink-soft); }
/* A button that reads as a link: the two ways out of this step are choices,
   not actions, and should not compete with the one real button above. */
.apeek__link { padding: 0; font: inherit; font-size: var(--fs-sm); color: var(--act); background: none; border: 0; text-decoration: underline; cursor: pointer; }
.apeek__link:focus-visible { outline: none; box-shadow: var(--ring); border-radius: 4px; }
.sheet__row { display: flex; align-items: center; gap: var(--sp-3); padding: 11px var(--sp-3); border-radius: var(--r-md); text-decoration: none; color: inherit; }
.sheet__row:hover, .sheet__row:focus-visible { background: var(--act-wash); outline: none; }
.sheet__ic { display: grid; place-items: center; width: 38px; height: 38px; flex: none; border-radius: var(--r-md); background: var(--wash-100); color: var(--petrol-600, var(--act)); }
.sheet__ic .cb-ico { width: 19px; height: 19px; }
.sheet__tx { display: flex; flex-direction: column; min-width: 0; }
.sheet__tx b { font-weight: 700; font-size: var(--fs-base); }
.sheet__tx span { font-size: var(--fs-xs); color: var(--ink-faint); }

/* ---- The shared rail: sliding as a first-class habit, desktop included.
   Scroll-snap plus a peeking partial card as the affordance, a right-edge
   fade as the cue, arrow buttons for the mouse. Seeded from the concierge
   venue rail and generalised, so later sections stop inventing private
   carousels. ---- */
.rail {
	display: flex; align-items: stretch; gap: var(--sp-4);
	overflow-x: auto; overflow-y: hidden;
	scroll-snap-type: x proximity;
	padding: 4px 2px var(--sp-3);
	scrollbar-width: none;
	-webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 64px), transparent);
	mask-image: linear-gradient(90deg, #000 calc(100% - 64px), transparent);
}
.rail::-webkit-scrollbar { display: none; }
.rail:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--r-md); }
/* Three cards and a visible slice of the fourth at 1080: the slice IS the
   invitation to slide. Explicit basis, never auto-fit (the grid rule). */
.rail__item { flex: 0 0 clamp(240px, 30%, 300px); min-width: 0; scroll-snap-align: start; display: flex; }
.rail__item > * { width: 100%; }
.rail.is-end { -webkit-mask-image: none; mask-image: none; }

/* Sits after the .more link in the section head; align-self centres the round
   buttons against the baseline-aligned text row. */
.rail-nav { display: inline-flex; gap: 6px; align-self: center; }
.rail-nav__btn { display: grid; place-items: center; width: 32px; height: 32px; border: 1px solid var(--line-strong); border-radius: 50%; background: var(--bg-card); color: var(--ink-soft); cursor: pointer; transition: color 0.12s ease, border-color 0.12s ease, opacity 0.12s ease; }
.rail-nav__btn:hover { color: var(--act); border-color: var(--act); }
.rail-nav__btn:focus-visible { outline: none; box-shadow: var(--ring); }
.rail-nav__btn.is-off { opacity: 0.35; pointer-events: none; }
/* Touch screens slide by thumb; the buttons are mouse furniture. */
@media (hover: none) { .rail-nav { display: none; } }

/* ============================================================================
 * The member homepage shelves (v9.49): the continue strip, the available-now
 * tabs, the mini venue card, the browse tiles and the honest scope chip. All
 * of it rides the shared .rail, so sliding feels identical shelf to shelf.
 * ============================================================================ */

/* One rhythm for every shelf head; a head with a subtitle binds tighter to it
   (space inside a group smaller than space around it). */
.home-desktop .section-head { margin-bottom: var(--sp-4); }
.home-desktop .section-head:has(+ .section-sub) { margin-bottom: var(--sp-2); }

.scope-chip { display: inline-flex; align-items: center; padding: 3px 11px; border-radius: var(--r-pill); background: var(--act-wash); color: var(--act-hover); font-size: var(--fs-xs); font-weight: 700; align-self: center; }

.cont-strip { display: grid; gap: var(--sp-3); }
.cont-card {
	display: flex; align-items: center; gap: var(--sp-3); min-width: 0;
	background: var(--bg-card); border: 1px solid var(--line); border-left: 3px solid var(--act);
	border-radius: var(--r-lg); padding: var(--sp-3) var(--sp-4);
	text-decoration: none; color: inherit; box-shadow: var(--shadow-card);
	transition: transform 0.14s ease;
}
.cont-card:hover { transform: translateY(-2px); }
.cont-card--hot { border-left-color: var(--sun, #F0A72C); background: linear-gradient(100deg, var(--sun-wash) 0%, var(--bg-card) 55%); }
.cont-card--hot .cont-card__ic { background: var(--sun-wash); color: #b9791a; }
.cont-card__ic { display: grid; place-items: center; width: 36px; height: 36px; flex: none; border-radius: var(--r-md); background: var(--act-wash); color: var(--act); }
.cont-card__ic .cb-ico { width: 18px; height: 18px; }
.cont-card__tx { flex: 1; min-width: 0; font-size: var(--fs-sm); font-weight: 600; overflow-wrap: break-word; }
.cont-card__go { flex: none; font-size: var(--fs-sm); color: var(--act); white-space: nowrap; }

/* THE IN-FLIGHT INDICATOR IN THE HEADER (v17.16).
   The same colour language as the cards it replaces: a 3px left edge, teal for
   things merely in progress and amber for the ones wanting the member NOW. It
   is the fastest thing on the row to read, which is the point of an indicator
   somebody glances at rather than studies. */
.flight { position: relative; }
.flight__btn { display: inline-flex; align-items: center; gap: 6px; padding: 7px 10px; background: var(--sun-wash); border: 1px solid transparent; border-radius: 999px; color: #b9791a; cursor: pointer; font: inherit; }
.flight__btn:hover { border-color: var(--sun, #F0A72C); }
.flight__btn:focus-visible { outline: none; box-shadow: var(--ring); }
.flight__btn .cb-ico { width: 16px; height: 16px; }
.flight__n { font-size: var(--fs-xs); font-weight: 800; line-height: 1; }
.flight__panel { display: none; position: absolute; right: 0; top: calc(100% + 8px); z-index: 60; width: min(340px, calc(100vw - 32px)); padding: var(--sp-2); background: var(--bg-card, #fff); border: 1px solid var(--line); border-radius: var(--r-lg, 18px); box-shadow: var(--shadow-pop, 0 18px 40px rgba(16, 40, 44, .16)); }
.flight.is-open .flight__panel { display: block; }
.flight__head { margin: 4px 6px 8px; font-size: var(--fs-xs); font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-faint); }
.flight__item { display: flex; align-items: center; gap: var(--sp-2); padding: 9px 10px; margin-bottom: 4px; border-left: 3px solid var(--act); border-radius: var(--r-md, 12px); background: var(--bg-soft, #F4F7F6); text-decoration: none; color: inherit; }
.flight__item:last-child { margin-bottom: 0; }
.flight__item:hover { background: var(--act-wash); }
.flight__item--hot { border-left-color: var(--sun, #F0A72C); background: var(--sun-wash); }
.flight__item--hot:hover { filter: brightness(.98); }
.flight__ic { display: grid; place-items: center; width: 28px; height: 28px; flex: none; border-radius: var(--r-md, 12px); background: var(--act-wash); color: var(--act); }
.flight__item--hot .flight__ic { background: rgba(240, 167, 44, .22); color: #b9791a; }
.flight__ic .cb-ico { width: 15px; height: 15px; }
.flight__tx { min-width: 0; display: flex; flex-direction: column; gap: 1px; font-size: var(--fs-sm); }
.flight__tx span { font-weight: 600; overflow-wrap: break-word; }
.flight__tx b { font-size: var(--fs-xs); font-weight: 700; color: var(--act); }

.avail-tabs { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: var(--sp-2); }
.avail-tab { display: inline-flex; align-items: center; gap: 7px; border: 1px solid var(--line-strong); background: var(--bg-card); color: var(--ink-soft); font: inherit; font-size: var(--fs-sm); font-weight: 700; padding: 8px 16px; border-radius: var(--r-pill); cursor: pointer; }
.avail-tab.is-on { background: var(--act); border-color: var(--act); color: #fff; }
.avail-tab:not(.is-on):hover { border-color: var(--act); color: var(--act); }
.avail-tab__n { font-size: var(--fs-xs); font-weight: 800; opacity: 0.75; }
.rail-head { display: flex; justify-content: flex-end; margin-bottom: var(--sp-1); }

.mini-card {
	display: flex; flex-direction: column; min-width: 0; height: 100%;
	background: var(--bg-card); border: 1px solid var(--line); border-radius: var(--r-lg);
	overflow: hidden; text-decoration: none; color: inherit; box-shadow: var(--shadow-card);
	transition: transform 0.14s ease, box-shadow 0.14s ease;
}
.mini-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-pop); }
.mini-card__img { display: block; width: 100%; height: 118px; object-fit: cover; transition: transform 0.35s ease; }
.mini-card:hover .mini-card__img { transform: scale(1.04); }
.mini-card:hover .mini-card__cta { color: var(--act-hover); text-decoration: underline; text-underline-offset: 3px; }
.mini-card__img--empty { background: linear-gradient(135deg, var(--wash-100, #DCE9E7), var(--wash-200, #B7D0CC)); }
.mini-card__body { display: flex; flex-direction: column; gap: 2px; padding: var(--sp-3); flex: 1; }
.mini-card__body b { font-family: var(--font-display); font-weight: 750; font-size: var(--fs-base); letter-spacing: -0.01em; overflow-wrap: break-word; }
.mini-card__meta { font-size: var(--fs-xs); color: var(--ink-faint); }
.mini-card__note { font-size: var(--fs-xs); color: var(--ink-soft); font-weight: 600; margin-top: 3px; overflow-wrap: break-word; }
.mini-card__note--offer { color: var(--act-hover); }
.mini-card__cta { margin-top: auto; padding-top: var(--sp-2); font-size: var(--fs-sm); font-weight: 700; color: var(--act); }

/* Browse and goody tiles: compact, icon-led, and honest about being buttons. */
.rail__item--type { flex: 0 0 clamp(180px, 22%, 220px); }
.type-tile {
	display: flex; flex-direction: column; align-items: flex-start; gap: 3px; width: 100%; height: 100%;
	background: var(--bg-card); border: 1px solid var(--line); border-radius: var(--r-lg);
	padding: var(--sp-4); text-align: left; text-decoration: none; color: inherit;
	font: inherit; cursor: pointer; transition: transform 0.14s ease, border-color 0.14s ease;
}
.type-tile:hover { transform: translateY(-2px); border-color: var(--act); }
.type-tile:focus-visible { outline: none; box-shadow: var(--ring); }
.type-tile__ic { display: grid; place-items: center; width: 36px; height: 36px; border-radius: var(--r-md); background: var(--wash-100); color: var(--petrol-600, var(--act)); margin-bottom: var(--sp-2); transition: background 0.14s ease, color 0.14s ease; }
.type-tile:hover .type-tile__ic { background: var(--act-wash); color: var(--act-hover); }
.type-tile__ic .cb-ico { width: 18px; height: 18px; }
.type-tile b { font-family: var(--font-display); font-weight: 750; font-size: var(--fs-base); letter-spacing: -0.01em; text-wrap: balance; overflow-wrap: break-word; }
.type-tile > span:last-child { font-size: var(--fs-xs); color: var(--ink-faint); font-weight: 550; overflow-wrap: break-word; }

/* ---- Shared tiled owner sub-pages (requests, pickup, opportunities, ...) ---- */

.tiled-home .th-page-head { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin: var(--sp-2) 0 var(--sp-5); }
.tiled-home .th-page-head h1 { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-xl); letter-spacing: -0.02em; margin: 0; line-height: 1.1; }
.tiled-home .th-page-head .th-page-sub { flex-basis: 100%; font-size: var(--fs-sm); color: var(--ink-soft); margin-top: var(--sp-1); }

/* Friendlier, bigger touch targets for every button on a tiled owner page */
.tiled-home .btn { min-height: 44px; padding: 11px 20px; border-radius: var(--r-pill); font-weight: 700; }
.tiled-home .btn-lg { min-height: 52px; }

/* Inputs on tiled owner pages: calm, comfortable, touch friendly */
.tiled-home input[type="text"], .tiled-home input[type="date"], .tiled-home input[type="time"],
.tiled-home input[type="tel"], .tiled-home input[type="number"], .tiled-home input:not([type]), .tiled-home select, .tiled-home textarea {
	font: inherit; font-size: var(--fs-sm); border: 1px solid var(--line-strong);
	border-radius: var(--r-md); padding: 11px 13px; min-height: 44px; background: var(--bg-card); color: var(--ink);
}

/* A calm highlight strip, e.g. tonight's bookings */
.tiled-home .th-strip { background: var(--act-wash); color: var(--act-hover); border-radius: var(--r-lg); padding: var(--sp-4) var(--sp-5); font-weight: 650; }
.tiled-home .th-strip b { font-family: var(--font-display); }

/* Disclosures (settings, insights) so the page leads with what needs action */
.tiled-home details.th-fold { background: var(--bg-card); border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--sp-3) var(--sp-4); }
.tiled-home details.th-fold[open] { padding-bottom: var(--sp-4); }
.tiled-home details.th-fold > summary { cursor: pointer; font-family: var(--font-display); font-weight: 700; font-size: var(--fs-base); list-style: none; display: flex; align-items: center; gap: 8px; }
.tiled-home details.th-fold > summary::-webkit-details-marker { display: none; }
.tiled-home details.th-fold > summary .th-fold__ic { width: 18px; height: 18px; color: var(--act); }
.tiled-home details.th-fold > summary .th-fold__ic svg { width: 18px; height: 18px; }

/* Section subheads within a tiled page */
.tiled-home .th-subhead { font-family: var(--font-display); font-weight: 750; font-size: var(--fs-md); margin: var(--sp-6) 0 var(--sp-3); letter-spacing: -0.01em; }
.tiled-home .th-subhead .th-count { color: var(--ink-faint); font-weight: 700; }

/* Action cards (a table request, a pickup order, ...) */
.tiled-home .th-card { background: var(--bg-card); border: 1px solid var(--line); border-radius: var(--r-xl); padding: var(--sp-4) var(--sp-5); box-shadow: var(--shadow-card); }
.tiled-home .th-card + .th-card { margin-top: var(--sp-3); }
.tiled-home .th-card__top { display: flex; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; }
.tiled-home .th-card__name { font-family: var(--font-display); font-weight: 750; font-size: var(--fs-md); letter-spacing: -0.01em; }
.tiled-home .th-card__meta { font-size: var(--fs-sm); color: var(--ink-soft); margin-top: 4px; line-height: 1.55; }
.tiled-home .th-card__meta a { color: var(--act); text-decoration: none; }
.tiled-home .th-card__quote { margin-top: 8px; font-size: var(--fs-sm); color: var(--ink); font-style: italic; }

/* The big-button action row */
.tiled-home .th-do { display: flex; gap: var(--sp-2); margin-top: var(--sp-4); flex-wrap: wrap; align-items: center; }
.tiled-home .th-do form { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.tiled-home .th-do .btn-danger { color: #B3261E; }

/* A compact history row */
.tiled-home .th-row { display: flex; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; align-items: center; padding: var(--sp-3) var(--sp-4); background: var(--bg-card); border: 1px solid var(--line); border-radius: var(--r-md); font-size: var(--fs-sm); }
.tiled-home .th-row + .th-row { margin-top: var(--sp-2); }

/* ==========================================================================
 * v9.59: the desktop stops sliding (the owner's rule: sliders are for
 * thumbs). Above 1080px every homepage rail lays out as a grid with explicit
 * columns and the arrow nav disappears; below, the touch rails live on
 * untouched. Scoped to .home-desktop so no other surface changes by accident.
 * ========================================================================== */
@media (min-width: 1081px) {
	.home-desktop .rail {
		display: grid;
		grid-template-columns: repeat(4, minmax(0, 1fr));
		gap: 12px;
		overflow: visible;
		scroll-snap-type: none;
		mask-image: none;
		-webkit-mask-image: none;
		padding-bottom: 0;
	}
	.home-desktop .rail--goodies { grid-template-columns: repeat(5, minmax(0, 1fr)); }
	.home-desktop .rail--cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
	.home-desktop .rail .rail__item { width: auto; min-width: 0; flex: none; scroll-snap-align: none; }
	.home-desktop .rail-nav { display: none; }
}

/* The cheerful tiles (v9.59): each feature card gets a tint family from the
 * island's own palette, cycled by position, so the shelf reads as a box of
 * sweets instead of a row of forms. Color arrives by CSS only. */
.rail--goodies .type-tile { border: 1px solid transparent; transition: transform .12s ease, box-shadow .12s ease; }
.rail--goodies .type-tile:hover { transform: translateY(-3px); box-shadow: 0 10px 22px rgba(16, 40, 44, .12); }
.rail--goodies .rail__item:nth-child(5n+1) .type-tile { background: #E3F1EE; }
.rail--goodies .rail__item:nth-child(5n+1) .type-tile__ic { color: #0E6E68; background: #CDE7E2; }
.rail--goodies .rail__item:nth-child(5n+2) .type-tile { background: #FCEBCF; }
.rail--goodies .rail__item:nth-child(5n+2) .type-tile__ic { color: #A66A0C; background: #F7DCAB; }
.rail--goodies .rail__item:nth-child(5n+3) .type-tile { background: #F7E3DA; }
.rail--goodies .rail__item:nth-child(5n+3) .type-tile__ic { color: #A85433; background: #F0CFC0; }
.rail--goodies .rail__item:nth-child(5n+4) .type-tile { background: #EBF0DA; }
.rail--goodies .rail__item:nth-child(5n+4) .type-tile__ic { color: #5F7F46; background: #DCE6C1; }
.rail--goodies .rail__item:nth-child(5n+5) .type-tile { background: #EFE6F2; }
.rail--goodies .rail__item:nth-child(5n+5) .type-tile__ic { color: #7C4E7E; background: #E2D2E6; }

/* The inline browse answer under the type tiles (v9.59). */
.browse-panel { margin-top: 14px; }
.browse-panel[hidden] { display: none; }
.browse-cards__grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
/*
 * THE NAME SITS ON THE PHOTOGRAPH (v10.78).
 *
 * Each card was a 110px photo above a 60px white block, eight of them on a
 * near-white page under white tiles and above white action cards. His words:
 * it is too much white. The photographs were the only colour on the screen and
 * they had only half of each card.
 *
 * So the card is the photograph, and the name and rating ride a scrim over the
 * bottom of it. The ink ground underneath matters: a venue with no photo still
 * needs something for white text to sit on.
 */
.browse-card { position: relative; display: block; text-decoration: none; color: #fff; background: var(--ink, #10282C); border: 0; border-radius: 12px; overflow: hidden; transition: transform .12s ease, box-shadow .12s ease; }
/* The colour has to be restated on hover and focus. These cards are links, and
   the sitewide link-hover colour repaints the venue name teal, which on a dark
   photograph is a name nobody can read. Only noticed once the drawer kept a
   card under the cursor for minutes at a time. */
.browse-card:hover, .browse-card:focus, .browse-card:focus-visible { color: #fff; }
.browse-card:hover { transform: translateY(-2px); box-shadow: 0 10px 22px rgba(16, 40, 44, .1); }
.browse-card__photo { width: 100%; height: 168px; object-fit: cover; display: block; background: var(--ink, #10282C); }
.browse-card__photo--empty { display: grid; place-items: center; color: rgba(255, 255, 255, 0.45); }
/* The scrim is part of the body rather than a separate layer, so there is
   nothing to keep in sync and nothing to sit at the wrong z-index. */
.browse-card__body { position: absolute; left: 0; right: 0; bottom: 0; display: flex; flex-direction: column; gap: 2px; padding: 28px 12px 12px; background: linear-gradient(to top, rgba(6, 20, 22, 0.92) 0%, rgba(6, 20, 22, 0.72) 45%, transparent 100%); }
.browse-card__body b { font-size: .92rem; line-height: 1.25; }
.browse-card__meta { font-size: .8rem; color: rgba(255, 255, 255, 0.82); }
.browse-card__meta em { font-style: normal; color: var(--sun, #F0A72C); margin-left: .35em; }
.browse-cards__empty { color: var(--ink-soft, #47605E); margin: 6px 0 0; }
/* Room to breathe: 12px left the controls hanging off the last row of
   photographs as though they belonged to it. */
/*
 * Room on BOTH sides. 12px above left the controls hanging off the last row of
 * photographs as though they belonged to it, and nothing below let the next
 * section start on top of them, so the bar read as a divider between two
 * things rather than as the end of this one. The shelf ends here: the space
 * beneath is larger than the space above, which is what says so.
 */
/*
 * THE LINE STAYS, THE BUTTON GOES. The hairline running across the foot of the
 * grid is what says the shelf ends here, and it earns its place. What did not
 * was the pill drawn around Show more: a third kind of control on a shelf that
 * already has cards and tiles.
 *
 * So the rule runs the width of the grid, Show more sits in it as plain text
 * with the line breaking either side, and Detailed search sits at the end in
 * exactly the same type. Two words, same weight, same colour, one line.
 *
 * Room on both sides of the row. 12px above left the controls hanging off the
 * last row of photographs as though they belonged to it, and nothing below let
 * the next section start on top of them. The space beneath is larger than the
 * space above, which is what says the shelf has finished.
 */
/*
 * CENTRED IN ITS OWN GAP (v16.6), on the owner's word: the line should sit in
 * the middle between the photographs above and the action tiles below.
 *
 * It was 20px above and 48px below, so it hung off the last row of pictures as
 * though it belonged to them. Equal space on both sides makes it a line in its
 * own right, which is what it is: the three other kinds and the door to the map.
 */
.browse-cards__foot { display: flex; align-items: center; gap: var(--sp-4); margin: var(--sp-8) 0; }
.browse-more,
.browse-all {
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-soft);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: color .12s ease;
}
/* The rule lives on Show more and breaks around its words: the gap in a flex
   row is real space, so nothing has to be painted over the line to hide it. */
.browse-more { flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--sp-4); }
.browse-more::before,
.browse-more::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.browse-more > span { flex: none; }
/*
 * THE THREE KINDS AND THE MAP, DRAWN AS CONTROLS (v16.6). They were bare text,
 * which on a line that also holds a rule and a Show more read as small print
 * rather than as the four places you can go next. Quiet pills with the type's
 * own icon: enough to look pressable, not so much that they compete with the
 * action tiles directly below, which are the loudest thing on this part of the
 * page and should stay that way.
 */
.browse-all {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 7px 13px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper, #fff);
}
.browse-all .cb-ico { width: 15px; height: 15px; flex: none; opacity: .75; }
.browse-all:hover { border-color: var(--act); background: var(--act-wash); }
.browse-all:hover .cb-ico { opacity: 1; }
/* The pill is the hover, so the text does not also need to move. */
.browse-all:hover > span { text-decoration: none; }
.browse-more:hover,
.browse-all:hover { color: var(--act); }
.browse-more:hover > span,
.browse-all:hover { text-decoration: underline; }
.browse-more:focus-visible,
.browse-all:focus-visible { outline: 2px solid var(--act); outline-offset: 3px; border-radius: 4px; }
/* With nothing more to show there is no Show more, so the rule comes from the
   row instead and Detailed search keeps its place at the end of it. */
/* A pill cannot stretch to fill the row, so it is pushed to the end instead. */
.browse-cards__foot > .browse-all:only-child { margin-left: auto; }
.browse-cards__foot > .browse-all:only-child::before { content: ""; }
@media (max-width: 1080px) { .browse-cards__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* The homepage video card (v9.59): renders only when home.video_url is set. */
.home-video { width: 100%; border-radius: 16px; display: block; background: #10282C; box-shadow: 0 16px 32px rgba(16, 40, 44, .18); }

.table-band { background: linear-gradient(160deg, #153138 0%, var(--bg-ink, #10282C) 72%); color: var(--ink-on-dark, #F2F7F6); }
.table-band__inner { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, .8fr); gap: clamp(1.5rem, 5vw, 3.5rem); align-items: center; padding-block: clamp(2.5rem, 6vw, 4rem); }
.table-band__eyebrow { margin: 0 0 var(--sp-2); font-size: var(--fs-sm); font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--sun, #F0A72C); }
.table-band h2 { font-family: var(--font-display); font-weight: 800; font-size: clamp(1.8rem, 3.6vw, 2.6rem); line-height: 1.05; letter-spacing: -.02em; margin: 0 0 .7rem; text-wrap: balance; }
.table-band__lead { color: var(--ink-on-dark-soft, #A9C0BD); max-width: 48ch; margin: 0 0 1.4rem; line-height: 1.55; }
.table-band__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; }
.table-band__list li { display: flex; gap: 12px; align-items: flex-start; }
.table-band__list .cb-ico { flex: none; width: 22px; height: 22px; color: var(--sun, #F0A72C); margin-top: 2px; }
.table-band__list b { display: block; margin-bottom: 2px; }
.table-band__list span { color: var(--ink-on-dark-soft, #A9C0BD); line-height: 1.5; }
.table-band__list b { color: var(--ink-on-dark, #F2F7F6); }
.table-band__side { display: flex; flex-direction: column; gap: 16px; align-items: center; }
.table-band__video { width: 100%; border-radius: 14px; display: block; background: #0B1E21; }
.table-band__qr { background: #fff; border-radius: 14px; padding: 16px; display: flex; flex-direction: column; gap: 10px; align-items: center; text-align: center; color: var(--ink, #10282C); max-width: 220px; }
.table-band__qr span { font-size: .8rem; font-weight: 600; line-height: 1.4; }
@media (max-width: 900px) { .table-band__inner { grid-template-columns: 1fr; } .table-band__side { align-items: flex-start; } }

@media (min-width: 1081px) {
	.home-desktop .rail--goodies { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}



/*
 * WHAT KIND OF PLACE (v10.75). The four tiles that used to be the quick
 * actions, and the answer underneath them.
 *
 * The point of the row is that the first click does not leave the homepage.
 * So the active tile has to look chosen rather than merely hovered: it takes
 * the card ground and a citrus underline, and the row reads as a set of
 * choices with one made, not as four links waiting.
 *
 * Four explicit columns. Never auto-fit: eight tiles across two rows of four
 * is the only arrangement of this shelf that cannot orphan one on its own line.
 */
.browse-top__row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--sp-3);
  /* Straddles the hero properly (v10.76). At -46 the section's own top padding
     ate all but 6px of the pull and the row sat clear of the dark edge. */
  /* Half the tile rides in the hero (v10.77). The tile is 64, so the row sits
     32px above the dark edge: -46 left only 6px of it overlapping. */
  margin-top: -76px;
  position: relative;
  z-index: 2;
}
/*
 * COMPACT (v10.75). Stacked, the icon sat above the words and left two thirds
 * of the card empty: his words were that one icon on the left is not saving
 * it. The answer is a smaller box rather than something found to fill it, so
 * the icon comes inline with the title and the box keeps only the height the
 * words need.
 */
.browse-top .type-tile {
  display: flex;
  /* The base .type-tile is a column; without this the icon goes back on top
     and the box grows to 127px again. */
  flex-direction: row;
  align-items: center;
  gap: var(--sp-3);
  min-width: 0;
  padding: var(--sp-3);
  border-radius: var(--r-lg);
  /*
   * NOT WHITE (v10.78). White worked against the dark half of the hero and
   * disappeared into the near-white page below it, which is where these tiles
   * spend half their height. A tint holds both grounds.
   *
   * And the chosen one is solid brand rather than a hairline underline. This
   * row is a selector: whichever tile is lit is the reason the venues below it
   * are the ones showing, so it has to be unmistakable rather than tasteful.
   */
  background: var(--bg-dip);
  border: 1px solid transparent;
  /*
   * The tile straddles two grounds (v10.78): a dark hero above and a near
   * white page below. White reads fine against the dark half and vanishes
   * against the light one, which is what he saw. The shadow is what gives it
   * an edge on the page without changing what it looks like on the hero.
   */
  box-shadow: var(--shadow-card);
  text-decoration: none;
  color: var(--ink);
  transition: border-color 120ms ease, transform 120ms ease;
}
.browse-top .type-tile:hover { transform: translateY(-2px); border-color: var(--act); box-shadow: var(--shadow-pop); }
.browse-top .type-tile.is-on:hover { border-color: var(--act); }
/*
 * The chosen tile, stated properly (v10.79). Two things were left behind when
 * the background went solid: the title kept a muted colour from the base tile
 * rule, so it read dimmer than its own caption, and the icon plate stayed pale
 * with a white stroke on it, which is an invisible icon.
 */
/*
 * citrus-100 with a citrus-500 edge, not citrus-500 solid (v10.79).
 *
 * Both are in the palette, but the weight matters: citrus-500 is the brand's
 * emphasis colour, the hero keyline and the one link in the hero. Spending it
 * on which list you are looking at makes a state indicator shout louder than
 * the things people are meant to click, directly above eight photographs it
 * then competes with. The 100 says chosen without taking the emphasis.
 */
.browse-top .type-tile.is-on { background: var(--citrus-100, #FCF0DA); border-color: var(--citrus-500, #F0A72C); color: var(--ink, #10282C); }
.browse-top .type-tile.is-on b { color: var(--ink, #10282C); }
/* Ink on citrus, not white: white on #F0A72C is about 2:1 and fails to be
   readable at caption size. The dark text is also what the brand does on this
   colour everywhere else. */
.browse-top .type-tile.is-on .type-tile__text > span { color: rgba(16, 40, 44, 0.78); }
.browse-top .type-tile.is-on .type-tile__ic { background: rgba(240, 167, 44, 0.28); }
.browse-top .type-tile.is-on .cb-ico { color: #A66A0C; }
/*
 * Centred by flex, not by a spanned grid cell (v10.76). Spanning two rows put
 * the icon 13px from the top and 23 from the bottom, because the second row
 * carries the subtitle's line-height and the area it centred in was never
 * symmetric. A flex row cannot get this wrong whatever the words do.
 */
/*
 * The base icon carries margin-bottom 8px from the stacked layout, where it
 * sat above the words. Beside them that margin is what pushed it 10px off
 * centre and what made the box 92px instead of 72 (v10.76).
 */
.browse-top .type-tile__ic { flex: none; margin: 0; align-self: center; }
.browse-top .type-tile__text { display: flex; flex-direction: column; min-width: 0; }
.browse-top .type-tile b { font-weight: 700; overflow-wrap: anywhere; }
/*
 * NO SUBTITLE UP HERE (v10.76). Restaurants, Cafes, Bars and Beaches explain
 * themselves; the line under them was a caption on a word. It also cost real
 * height: with the icon beside the text rather than above it the column is
 * 48px narrower, so Cocktails, wine and the night wrapped to two lines and
 * grid stretch pushed every tile to match the tallest, 92px for four words.
 *
 * The full shelf below keeps its subtitles, where the types are less obvious
 * and the tiles have the room.
 */
/*
 * The caption is back (v10.78), pinned to one line. It was removed because the
 * narrower text column made "Cocktails, wine and the night" wrap and grid
 * stretch pushed every tile to match the tallest. nowrap keeps the row a fixed
 * height whatever the words do, in any language, which matters here: Greek and
 * German run half again as long as English.
 */
.browse-top .type-tile__text > span {
  display: block;
  color: var(--ink-soft);
  font-size: var(--fs-sm);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/*
 * THE CAPTION GOES RATHER THAN BREAKS WHILE THE DRAWER IS PUSHING. Four tiles
 * in the room left beside the curtain are about 215px each, and every caption
 * truncates: "Tavernas to fine din...". A truncated line reads as broken, which
 * is why v10.78 shortened the bar caption rather than let it clip.
 *
 * Restaurants, Cafes, Bars and Beaches explain themselves, so losing the
 * caption costs nothing, while keeping all four tiles visible is the entire
 * point of pushing the page. The captions come back the moment it closes.
 */
html.vpeek-push .browse-top .type-tile__text > span { display: none; }
.browse-top .browse-panel { margin-top: var(--sp-7, 32px); }
@media (max-width: 900px) { .browse-top__row { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: 0; } }

/*
 * THE CURTAIN (v10.82). A venue read without leaving the list.
 *
 * The list stays visible behind a light veil rather than a blackout: the point
 * is that the reader has not gone anywhere, and a heavy scrim says they have.
 *
 * Transform rather than width or right, so opening is one composited property
 * and cannot reflow the page behind it. Below the tablet width it becomes a
 * full sheet, because a 480px drawer on a 390px phone is a modal pretending
 * to be a drawer.
 */
/*
 * TWO WIDTHS, ONE FOR EACH MODE.
 *
 * Overlaid, the drawer can be generous because it is covering a page nobody is
 * reading at that moment. PUSHING, it cannot: whatever it takes comes straight
 * out of the list beside it, and CSS media queries measure the viewport rather
 * than the squeezed column, so the page keeps rendering its full desktop
 * layout in whatever room is left. Take 860px out of 1440 and four cards get
 * crammed into the space of two. 520 leaves the list about 920, near enough
 * its natural 1080 that it still looks like itself.
 */
:root {
  --vpeek-w: min(max(580px, 52vw), 860px);
  /*
   * Pushing, the drawer takes what is LEFT OVER rather than a share of the
   * screen. The list is given its natural width first and the drawer gets the
   * rest, so a wide monitor spends its extra pixels on the venue instead of on
   * empty margins. Floor 500 so it never becomes a column, ceiling 780 so it
   * never becomes the page. A fixed 580 cap left a third of a 1900px screen
   * doing nothing.
   *
   * DERIVED, NOT FROZEN (v17.1). This said 1120px, which was --page-max plus
   * its gutters written out as a number, and it was right for exactly as long
   * as the page was 1080 wide. Widening the site to 1340 would have left the
   * list squeezed to 1120 with the drawer open, cramming four cards into the
   * room for three, and nothing would have pointed at this line as the cause.
   * It now reads the token, so the page keeps its real width whatever that
   * becomes and this never needs revisiting again.
   */
  --vpeek-push-w: clamp(500px, calc(100vw - var(--page-max) - (2 * var(--sp-4))), 780px);
}
/* The container spans the viewport so the panel can sit against its edge, but
   it must not swallow a single click: everything under it stays live, which is
   the entire reason the drawer exists. Only the panel takes pointer events. */
.vpeek { position: fixed; inset: 0; z-index: 120; pointer-events: none; }

/*
 * PUSH MODE. The page is inset by exactly the drawer's width, so the list
 * reflows into what is left instead of hiding under it and both columns are
 * live at once: scroll the left, click the next venue, read it on the right,
 * never close anything.
 *
 * The transition lives on body unconditionally so the page slides back when
 * the class is removed, not just when it is added.
 */
body { transition: padding-right 220ms cubic-bezier(.22, .61, .36, 1); }
/* The inset is the panel PLUS a gutter (v17.14). Insetting by exactly the
   panel width left the page's content container touching the drawer's edge
   with nothing between them, so the two read as one crowded surface instead of
   a page and a panel beside it. */
html.vpeek-push body { padding-right: calc(var(--vpeek-push-w) + var(--sp-4)); }
html.vpeek-push .vpeek__panel { width: var(--vpeek-push-w); }
/* Nothing is covered any more, so nothing should be shaded. */
html.vpeek-push .vpeek__scrim { opacity: 0; }
/*
 * The launchers are pinned to the viewport, not to the page, so the inset does
 * not move them and they would float over the drawer. The two admin links
 * carry their position inline, which is the only reason for the important
 * here: there is no other way to reach an inline style.
 */
html.vpeek-push #cb-assistant { right: calc(18px + var(--vpeek-push-w)); }
html.vpeek-push body > a[style*="position:fixed"] { right: calc(18px + var(--vpeek-push-w)) !important; }
#cb-assistant, body > a[style*="position:fixed"] { transition: right 220ms cubic-bezier(.22, .61, .36, 1); }
.vpeek[hidden] { display: none; }
/* NOT A VEIL. An earlier build dimmed the whole page, which said the list was
   disabled at the exact moment we most want it clicked. This is a short shade
   at the panel's edge, so the drawer reads against a busy page and nothing
   else changes. */
.vpeek__scrim {
  position: absolute;
  top: 0;
  right: 0;
  height: 100%;
  width: 100%;
  background: linear-gradient(to right, rgba(16, 40, 44, 0) 55%, rgba(16, 40, 44, 0.14) 100%);
  opacity: 0;
  transition: opacity 180ms ease;
}
.vpeek.is-open .vpeek__scrim { opacity: 1; }
.vpeek__panel {
  position: absolute;
  top: 0;
  right: 0;
  height: 100%;
  width: min(var(--vpeek-w), 100%);
  pointer-events: auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--bg-page, #F2F5F4);
  box-shadow: -18px 0 48px -24px rgba(16, 40, 44, 0.5);
  transform: translateX(100%);
  transition: transform 220ms cubic-bezier(.22, .61, .36, 1);
}
.vpeek.is-open .vpeek__panel { transform: translateX(0); }
/* Which card the drawer is holding. Once the list stays clickable, a visitor
   working through ten of them needs to see where they are without reading. */
.browse-card.is-peeking, .r-card.is-peeking { outline: 2px solid var(--act); outline-offset: 2px; border-radius: 12px; }
.vpeek__inner { padding: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-4); }
.vpeek__head { display: flex; align-items: flex-start; gap: var(--sp-3); }
.vpeek__titles { flex: 1; min-width: 0; }
.vpeek__name { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-lg); margin: 0; overflow-wrap: anywhere; }
.vpeek__meta { margin: 4px 0 0; color: var(--ink-soft); font-size: var(--fs-sm); overflow-wrap: anywhere; }
.vpeek__rating { color: #A66A0C; margin-left: .4em; }
.vpeek__rating span { color: var(--ink-faint); }
/* The way out has to be findable at a glance. A hairline circle on a white
   panel was one more faint thing among several; this is filled, so it reads as
   a control the moment the drawer opens. */
.vpeek__x {
  flex: none;
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: 50%;
  background: var(--ink, #10282C);
  color: #fff;
  font-size: 24px;
  font-weight: 400;
  line-height: 1;
  cursor: pointer;
  transition: background .12s ease, transform .12s ease;
}
.vpeek__x:hover { background: var(--act); transform: scale(1.06); }
.vpeek__x:focus-visible { outline: 2px solid var(--act); outline-offset: 3px; }
/* A mosaic whose shape follows the photograph count, so there is never a gap
   and never a picture sliced off at the panel edge. */
.vpeek__shots { display: grid; gap: 6px; }
.vpeek__shots--one { grid-template-columns: 1fr; height: 260px; }
.vpeek__shots--two { grid-template-columns: 1fr 1fr; height: 220px; }
/* Big one on the left, two stacked beside it. The first photograph is nearly
   always the front of the building, which is what somebody needs to recognise
   the place from the street. */
.vpeek__shots--many { grid-template-columns: 1.9fr 1fr; grid-template-rows: 1fr 1fr; height: 280px; }
.vpeek__shots--many .vpeek__shot:first-child { grid-row: 1 / span 2; }
.vpeek__shot { position: relative; overflow: hidden; border-radius: var(--r-md); background: var(--wash-100, #E7EDEB); }
.vpeek__shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* The count of what is not shown, on the tile it is hidden behind. */
.vpeek__shot-more {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgba(6, 20, 22, 0.52);
  color: #fff;
  font-weight: 800;
  font-size: 1.05rem;
}
.vpeek__blurb { margin: 0; color: var(--ink-soft); line-height: 1.55; }
/* The full description, closed. Quieter than the hours row because it is an
   invitation to read rather than an answer to a question. */
.vpeek__more { margin-top: calc(var(--sp-4) * -1 + 6px); }
.vpeek__more > summary { display: inline-block; cursor: pointer; list-style: none; color: var(--act); font-size: var(--fs-sm); font-weight: 700; }
.vpeek__more > summary::-webkit-details-marker { display: none; }
.vpeek__more > summary:hover { text-decoration: underline; }
.vpeek__prose { margin-top: var(--sp-2); color: var(--ink-soft); line-height: 1.6; font-size: var(--fs-sm); }
.vpeek__prose p { margin: 0 0 var(--sp-2); }
.vpeek__prose p:last-child { margin-bottom: 0; }
/* Hours, shut by default. The summary row carries the whole answer most
   people need, and the week only exists for the person who opens it. */
.vpeek__hours { border: 1px solid var(--line); border-radius: var(--r-md); background: var(--bg-card, #fff); }
.vpeek__hours > summary {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 12px var(--sp-3);
  cursor: pointer;
  list-style: none;
  font-size: var(--fs-sm);
}
/* Safari puts a disclosure triangle here whatever list-style says. */
.vpeek__hours > summary::-webkit-details-marker { display: none; }
.vpeek__state {
  font-weight: 700;
  color: var(--ink-soft);
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--wash-100, #E7EDEB);
}
/* Open is the only state that gets colour. A closed venue is not an error and
   should not be painted like one. */
.vpeek__state.is-open-now { color: var(--good-600, #2F7D4F); background: var(--good-100, #E2F2E7); }
.vpeek__until { color: var(--ink-soft); }
.vpeek__hours-more { margin-left: auto; color: var(--act); }
.vpeek__hours[open] .vpeek__hours-more { visibility: hidden; }
.vpeek__week { padding: 0 var(--sp-3) 12px; }
.vpeek__day { display: flex; justify-content: space-between; gap: var(--sp-3); padding: 5px 0; font-size: var(--fs-sm); color: var(--ink-soft); border-top: 1px solid var(--line); }
.vpeek__day.is-today { color: var(--ink); font-weight: 700; }
/* Side by side now the drawer is wide: two stacked full-bleed bars at 700px
   read as a form rather than as a choice between two doors. */
.vpeek__acts { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); }
.vpeek__acts .btn { flex: 1 1 190px; justify-content: center; }
/* Where it is. Quiet, because somebody who wants the address wants it exact,
   not emphasised. */
.vpeek__where { display: flex; flex-wrap: wrap; gap: 4px var(--sp-3); margin: 0; font-size: var(--fs-sm); color: var(--ink-soft); }
.vpeek__where a { color: var(--act); }
/* The only things in the drawer that expire. */
.vpeek__now { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.vpeek__now li { display: flex; align-items: baseline; gap: var(--sp-2); font-size: var(--fs-sm); overflow-wrap: anywhere; }
.vpeek__now em { font-style: normal; color: var(--ink-faint); }
.vpeek__tag {
  flex: none;
  font-size: .72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  padding: 2px 8px;
  border-radius: 999px;
  color: #A66A0C;
  background: var(--citrus-100, #FCF0DA);
}
.vpeek__tag--event { color: var(--teal-700, #0B5A55); background: var(--teal-100, #DCEDEB); }
/* The claim ask sits apart from the actions: it is addressed to a different
   person than everything above it. */
.vpeek__claim { display: flex; align-items: flex-start; gap: var(--sp-2); margin: 0; padding: 10px var(--sp-3); border: 1px dashed var(--line); border-radius: var(--r-md); font-size: var(--fs-sm); color: var(--ink-soft); }
.vpeek__claim svg { flex: none; width: 18px; height: 18px; margin-top: 1px; }
.vpeek__claim a { color: var(--act); font-weight: 700; }
.vpeek__full { display: inline-block; color: var(--act); font-size: var(--fs-sm); text-decoration: none; }
.vpeek__full:hover { text-decoration: underline; }
@media (max-width: 700px) {
  .vpeek__panel { width: 100%; }
  /* Shorter on a narrow panel, but the same shapes. These rules used to size a
     sliding strip that no longer exists. */
  .vpeek__shots--one { height: 190px; }
  .vpeek__shots--two { height: 160px; }
  .vpeek__shots--many { height: 200px; }
}

/* ============================================================
   EVERYTHING CYPRUSBITES DOES: the street that builds itself
   ============================================================
   Seven pieces wait in a row under an empty street. Click one and it travels
   to where it belongs, its part of the drawing arrives underneath it, and its
   explanation opens. By the seventh the street is full.

   It is not a puzzle: nothing is scrambled, no move is wrong, and the words
   are given whether or not anybody cares about the picture. The assembly is
   the consequence of reading, not a task standing in front of it. */
.scene { padding: var(--sp-10) 0; background: var(--bg-page, #F2F5F4); }
.scene__head { margin-bottom: var(--sp-6); }
.scene__title { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-2xl); margin: 0; }
.scene__sub { margin: 6px 0 0; color: var(--ink-soft); }

/* The stage holds its shape while the picture inside it changes, so nothing
   below jumps as pieces are placed. */
/*
 * SIZED TO THE WINDOW, NOT TO ITSELF. A fixed 12:7 of a 1080 column is about
 * 630px tall, so with the heading above it the section could not fit on a
 * laptop screen: you had to scroll up and down hunting for a position where
 * the whole picture was visible, which is no way to look at a picture.
 *
 * Height now comes from the viewport, and the drawing scales inside it. The
 * markers are positioned from measured screen rectangles, so they follow
 * wherever the drawing lands, letterboxed or not.
 */
.scene__stage { position: relative; height: min(58vh, 560px); min-height: 320px; border-radius: var(--r-lg, 18px); overflow: hidden; background: var(--wash-100, #E7EDEB); }
.scene__art, .scene__art svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

/* THE SEVEN, HELD BACK. The stage groups are untouched, so a visitor who
   never clicks still sees a street rather than an empty box. */
.scene__art [id^="hs-"] { opacity: 0; transform: translateY(14px) scale(.96); transform-origin: center; transition: opacity .5s ease, transform .5s cubic-bezier(.22, .61, .36, 1); }
.scene.is-placed-scooter [id="hs-scooter"],
.scene.is-placed-guest [id="hs-guest"],
.scene.is-placed-till [id="hs-till"],
.scene.is-placed-table [id="hs-table"],
.scene.is-placed-friends [id="hs-friends"],
.scene.is-placed-pass [id="hs-pass"],
.scene.is-placed-owner [id="hs-owner"] { opacity: 1; transform: none; }

.scene__points { list-style: none; margin: 0; padding: 0; position: absolute; inset: 0; }
/* A piece waits at left/top and travels to the two custom properties. The
   transition is on position rather than transform because the two ends are
   percentages of the stage, which a transform cannot express. Seven elements
   moving once each is well within budget. */
.scene__point { position: absolute; left: var(--sx); top: var(--sy); transform: translate(-50%, -50%); transition: left .62s cubic-bezier(.34, 1.3, .5, 1), top .62s cubic-bezier(.34, 1.3, .5, 1); }
.scene__point.is-home { left: var(--px); top: var(--py); }

.scene__mark {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 13px 7px 9px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--bg-card, #fff);
  color: var(--ink-soft);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: 0 6px 18px -10px rgba(16, 40, 44, .5);
  transition: color .16s ease, border-color .16s ease, background .16s ease, box-shadow .16s ease;
}
.scene__ico { font-size: 20px; flex: none; }
.scene__mark:hover { color: var(--act); border-color: var(--act); }
.scene__mark:focus-visible { outline: 2px solid var(--act); outline-offset: 3px; }
/*
 * PLACED, NOT BLACKED OUT. This was a solid ink disc, which on a pale,
 * sun-bleached drawing read as a hole punched through the picture, and the
 * glyph inside it disappeared. A mark on a light scene has to be light.
 *
 * So it stays the same white pill it was, keeps a soft ring so it is still
 * clearly a control, and takes the brand colour on its glyph. The picture
 * shows through instead of being covered.
 */
.scene__point.is-home .scene__mark { background: rgba(255, 255, 255, 0.94); border-color: rgba(16, 40, 44, 0.14); color: var(--act); box-shadow: 0 4px 14px -8px rgba(16, 40, 44, .6); }
.scene__point.is-home .scene__mark:hover { color: #fff; border-color: var(--act); background: var(--act); }
/* The one being read. */
.scene__point.is-current .scene__mark { background: var(--act); border-color: var(--act); color: #fff; }

/*
 * THE WAY BACK (v12.3). Under the picture, on the left, where the explanation
 * starts: a reader's eye is already returning to that corner every time a
 * piece lands, so it is found without being advertised.
 *
 * Deliberately not a button. This section offers seven things and a reset is
 * not one of them, so it carries no fill, no border and no weight: it reads as
 * an afterthought until somebody wants it, which is exactly what it is.
 */
.scene__reset {
	appearance: none;
	background: none;
	border: 0;
	display: block;
	margin: var(--sp-3) 0 0;
	padding: 4px 2px;
	font: inherit;
	font-size: .82rem;
	color: var(--ink-faint, #7A8A8C);
	text-decoration: underline;
	text-underline-offset: 3px;
	text-decoration-color: rgba(122, 138, 140, .45);
	cursor: pointer;
}
.scene__reset:hover { color: var(--act); text-decoration-color: currentColor; }
.scene__reset:focus-visible { outline: 2px solid var(--act); outline-offset: 3px; border-radius: 4px; }

/* A piece that has not been placed breathes, slowly and one at a time, so the
   row reads as something to touch without anybody having to hunt for it. */
/* Waiting pills are smaller and staggered over two rows. Seven at full size in
   one line collided, and a German label is half again as long as an English
   one, so a single row could never hold them. */
.scene__point:not(.is-home) .scene__mark { padding: 5px 11px 5px 8px; font-size: .82rem; max-width: 168px; }
/* Long labels wrap rather than truncate. "Coming back is worth something" on
   one line is wide enough to collide with its neighbour, and a clipped label
   reads as broken, which is why v10.78 shortened a caption instead. */
.scene__point:not(.is-home) .scene__label { white-space: normal; line-height: 1.25; }
.scene__point:not(.is-home) .scene__ico { font-size: 17px; }
@keyframes scene-breathe { 0%, 88%, 100% { transform: translateY(0); } 94% { transform: translateY(-4px); } }
.scene__point:not(.is-home) .scene__mark { animation: scene-breathe 4.5s ease-in-out infinite; animation-delay: calc(var(--i, 0) * .45s); }

/* THE WORDS ARE THE SECTION. On a wide screen one shows at a time, beside the
   picture that explains it. Everywhere else, and to Google, they are simply a
   list of seven things, all present, all readable. */
/*
 * THE WORDS SIT UNDER THE PICTURE, in the open (v10.91).
 *
 * They were tried in three places. Stacked under a 630px stage they fell below
 * the fold, so a click changed nothing you could see. Beside it meant shrinking
 * the drawing, which ruins the drawing and still crowds the text. Floating over
 * the scene as a card covered the very thing being explained and read as a
 * pop-up on a picture.
 *
 * The real fault was the height of the stage, not the position of the words.
 * With the picture sized to the window, underneath is simply where an
 * explanation belongs: no box, no glass, no shadow, just the paragraph.
 */
.scene__body { position: relative; }
.scene__says { margin-top: var(--sp-5); min-height: 8.5em; }
.scene__say { max-width: 62ch; }
.scene__say h3 { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-lg); margin: 0 0 6px; }
.scene__say p { margin: 0; color: var(--ink-soft); line-height: 1.6; }
/* Only once the script is running do the six that are not being read stand
   down. Without JavaScript every one of them stays on the page. */
.scene.is-live .scene__say { display: none; }
.scene.is-live .scene__say.is-open { display: block; }

@media (max-width: 900px) {
  /* NO SECOND IMPLEMENTATION. The stage steps back and the seven explainers
     become what they always were underneath: a plain readable sequence. */
  /* One column again: below this width there is no room for two, and the
     explainers become the whole section as they always were underneath. */
  .scene__body { grid-template-columns: minmax(0, 1fr); }
  .scene__stage { display: none; }
  /* With no picture there is nothing to put back, so the way back goes too. */
  .scene__reset { display: none; }
  .scene.is-live .scene__say { display: block; margin-bottom: var(--sp-5); }
}
@media (prefers-reduced-motion: reduce) {
  .scene__point { transition: none; }
  .scene__art [id^="hs-"] { transition: opacity .2s linear; transform: none; }
  .scene__point:not(.is-home) .scene__mark { animation: none; }
}
/* A pill centred on an object near the frame's edge hangs off it. Near an edge
   it swings inward, so the mark still sits on its object and the words stay in
   the picture. */
.scene__point.at-right { transform: translate(-100%, -50%); }
.scene__point.at-right .scene__mark { flex-direction: row-reverse; padding: 7px 9px 7px 13px; }
.scene__point.at-left { transform: translate(0, -50%); }
/* A piece that has been read keeps its place but gives up its words: seven
   labels at once crowd each other and bury the picture they are pointing at.
   The one being read keeps its label, and hovering any of them brings it back. */
.scene__point.is-home:not(.is-current) .scene__label { display: none; }
.scene__point.is-home:not(.is-current) .scene__mark { padding: 8px; }
.scene__point.is-home:not(.is-current) .scene__mark:hover .scene__label,
.scene__point.is-home:not(.is-current) .scene__mark:focus-visible .scene__label { display: inline; }
.scene__go { display: inline-block; margin-top: 10px; color: var(--act); font-size: var(--fs-sm); font-weight: 700; text-decoration: none; }
.scene__go:hover { text-decoration: underline; }
/* The heart sits beside the way out, both of them flush with the venue's name. */
.vpeek__fav { flex: none; width: 40px; height: 40px; display: grid; place-items: center; border: 1px solid var(--line); border-radius: 50%; background: var(--bg-card, #fff); color: var(--ink-soft); cursor: pointer; }
.vpeek__fav:hover { color: var(--bloom-600, #B0407A); border-color: currentColor; }
.vpeek__fav[aria-pressed="true"] { color: var(--bloom-600, #B0407A); border-color: currentColor; }
/* What the venue actually offers. Quiet: these are facts, not offers of their
   own, and the buttons underneath are what a reader is meant to reach for. */
.vpeek__facts { list-style: none; display: flex; flex-wrap: wrap; gap: 6px var(--sp-2); margin: 0; padding: 0; }
.vpeek__facts li { display: inline-flex; align-items: center; gap: 6px; padding: 5px 11px; border-radius: var(--r-pill); background: var(--bg-dip, #E7EDEB); color: var(--ink-soft); font-size: var(--fs-sm); }
.vpeek__facts svg { width: 15px; height: 15px; flex: none; }

/* The map under the venue shelf. Sized to the window like the scene, for the
   same reason: a map you have to scroll to see all of is not a map you can
   read. */
/*
 * THE SHUT MAP TAKES NO ROOM (v16.7).
 *
 * This padding was unconditional, so a map nobody had opened still reserved
 * 40px under itself while showing nothing at all: its head and its key are both
 * display:none until it opens. That empty band sat between the browse line and
 * the four action tiles, which is exactly why the line looked off-centre with
 * 50px above it and 90px below, even though its own margins were equal.
 *
 * The padding belongs to the OPEN map, so it is stated there rather than
 * narrowed afterwards with a second rule. Shut, the section contributes nothing
 * and the line sits centred in a gap that is now genuinely symmetrical.
 */
.homemap { padding: 0; }
.homemap.is-open { padding: 0 0 var(--sp-10); }
.homemap__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-4); margin-bottom: var(--sp-4); }
.homemap__title { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-xl); margin: 0; }
.homemap__all { flex: none; color: var(--ink-soft); font-size: var(--fs-sm); font-weight: 600; text-decoration: none; }
.homemap__all:hover { color: var(--act); }
/*
 * CLOSED UNTIL "SHOW ON THE MAP" (v13.2, the owner's call). The map stays on
 * the homepage and stays fully functional; it simply does not spend half a
 * scroll on a picture of Cyprus before anybody has asked for one.
 *
 * BOTH height AND min-height collapse: a min-height of 300 beats a height of 0
 * and left a 300px hole with nothing in it. The border goes too, or the shut
 * section shows an empty outlined box.
 */
.homemap__frame { position: relative; height: 0; min-height: 0; border-radius: var(--r-lg, 18px); overflow: hidden; border: 0; transition: height .28s ease; }
/*
 * 56vh with a cap, NOT min(56vh, 520px) (v13.2). A height transition cannot
 * interpolate towards a min() in every engine: the declaration was dropped,
 * the frame stayed at its starting 0 and only min-height dragged it to 300, so
 * the map opened at little over half the height it was written for. Same
 * result, expressed in something that animates.
 */
/*
 * THE SAME ZOOM AS /map (v14.2). Both maps fit the same island bounds with the
 * same padding, so what made them look different was this box: /map gives it
 * min(70vh, 640px) and this gave it 56vh capped at 520. fitBounds scales the
 * island into whatever box it is handed, so matching the height IS matching
 * the zoom. Change one and change the other.
 */
.homemap.is-open .homemap__frame { height: min(70vh, 640px); min-height: 300px; border: 1px solid var(--line); }
.homemap__canvas { position: absolute; inset: 0; }
/* Above Leaflet's own panes, which claim z-index up to 800. */
.homemap__close {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 900;
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: 50%;
  background: var(--ink, #10282C);
  color: #fff;
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
}
.homemap__close:hover { background: var(--act); }
.browse-map { background: none; border: 0; font: inherit; }

/*
 * THE ONE MOVING THING IN THE STREET (v10.98).
 *
 * The scooter idles. Not a drift across the picture and back, which was the
 * first idea and does not survive contact with the rest of this section: the
 * marker that opens "What delivery takes" is positioned from where the scooter
 * actually is, measured once, so a scooter that travels leaves its own label
 * standing in the road. A vertical idle moves nothing horizontally and keeps
 * the two together.
 *
 * It is also the better joke. A scooter crossing the frame is a scooter doing
 * its job; a scooter sitting with its engine running outside a full taverna,
 * going nowhere, is the argument this whole section exists to make.
 *
 * Everything else in the picture stays still. One moving thing reads as life;
 * seven read as a screensaver.
 */
@keyframes scene-idle {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  25%      { transform: translateY(-1.6px) rotate(-0.14deg); }
  60%      { transform: translateY(0.9px) rotate(0.1deg); }
}
/*
 * The animation hangs off is-lit rather than being switched off before it,
 * because an id selector outweighs an attribute-and-class one: the tidier
 * "suppress until lit" rule lost the cascade and the scooter idled invisibly
 * from page load, fighting the arrival transform for a second.
 */
.scene__art #hs-scooter.is-lit {
  transform-box: fill-box;
  transform-origin: 50% 90%;
  animation: scene-idle 3.4s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  .scene__art #hs-scooter.is-lit { animation: none; }
}
/* The key to the pin colours. A key, not a filter: the shelf above already
   decides which type is shown, and a second set of controls saying the same
   thing differently is how two surfaces start disagreeing. */
/*
 * THE KEY IS THE FILTER (v13.2). Same quiet row it was as a legend, so the
 * section did not get louder by gaining a function: what changed is that the
 * words now do something when pressed.
 */
/*
 * TIGHT ENOUGH FOR ONE ROW (v14.6). Stays was falling to a second line on its
 * own, which reads as an afterthought rather than the ninth of nine. The gap
 * and the padding both come in a few pixels so the whole key closes up into a
 * single line. It still wraps if it must, on a narrow window or in a language
 * with longer words: one line is the intent, not a promise the layout keeps at
 * any cost.
 */
.homemap__key { display: flex; flex-wrap: wrap; gap: 5px var(--sp-2); margin: 0 0 var(--sp-3); padding: 0; }
.homemap__filter {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 4px 9px;
	border: 1px solid transparent;
	border-radius: var(--r-pill);
	background: none;
	font: inherit;
	font-size: var(--fs-sm);
	color: var(--ink-soft);
	cursor: pointer;
	transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.homemap__filter:hover { background: var(--wash-100, #E7EDEB); color: var(--ink); }
/*
 * EACH FILTER IN ITS OWN COLOUR (v13.2, asked for directly). The chip carries
 * the exact colour its pins are drawn in, handed down per button as --chip, so
 * choosing Bars turns the control the same purple the bars on the map are. The
 * control and the thing it controls are the same colour, which is the whole
 * reason a coloured key exists at all.
 *
 * White text on every one of the nine: they were picked as pin fills against a
 * pale basemap, so all are dark enough to carry it.
 */
.homemap__filter.is-on { background: var(--chip, var(--act)); color: #fff; border-color: var(--chip, var(--act)); font-weight: 700; }
/* Unchosen, the colour stays as the dot, so the row still reads as a key. */
.homemap__filter:not(.is-on):hover { border-color: var(--chip, var(--act)); }
.homemap__filter:focus-visible { outline: 2px solid var(--act); outline-offset: 2px; }
.homemap__swatch { width: 11px; height: 11px; border-radius: 50%; border: 1.5px solid var(--ink, #10282C); flex: none; }
/*
 * The count is quieter than the name (v13.3): the name is what you are looking
 * for, the number is only how much of it there is. tabular-nums so a row of
 * chips does not jitter as the digits change.
 */
/* The count sits closer to its name now that the chips are tighter, so the
   pair still reads as one thing rather than two. */
.homemap__n { font-size: var(--fs-xs); opacity: .7; font-variant-numeric: tabular-nums; margin-left: -1px; }
/* Present, so the key stays complete, but plainly not a control. */
.homemap__filter.is-empty { opacity: .45; cursor: default; }
.homemap__filter.is-empty:hover { background: none; color: var(--ink-soft); border-color: transparent; }
/* All has no single colour, so it shows the brand rather than pretending. */
.homemap__swatch--all { background: var(--act); }
.homemap__filter.is-on .homemap__swatch { border-color: rgba(255, 255, 255, .85); }

/*
 * THE FINALE (v11.6). Every piece home, the street full, and the delivery
 * scooter pulls out and rides off with nothing in its box. It holds at the end
 * rather than looping back, because the point is that it left.
 *
 * The idle stops the moment the ride starts: two transforms on one element and
 * the later rule silently wins, which is not a fight worth having.
 */
@keyframes scene-ride {
  0%   { transform: translateX(0); }
  12%  { transform: translateX(-14px) rotate(-1deg); }
  100% { transform: translateX(1500px) rotate(0deg); }
}
.scene.is-complete .scene__art #hs-scooter.is-lit {
  animation: scene-ride 3.6s cubic-bezier(.5, 0, .75, .35) 0.5s forwards;
}
/* Its mark goes with it. The label has been read by now, and a mark left
   hovering over an empty road points at nothing. */
.scene.is-complete .scene__point[data-scene-piece="scooter"] {
  opacity: 0;
  pointer-events: none;
  transition: opacity .5s ease .6s;
}
@media (prefers-reduced-motion: reduce) {
  .scene.is-complete .scene__art #hs-scooter.is-lit { animation: none; }
  .scene.is-complete .scene__point[data-scene-piece="scooter"] { opacity: 1; pointer-events: auto; }
}

/* ---------- Tables waiting for an answer (v12.7) ---------- */

/*
 * This replaced a full-width dark band carrying one huge numeral, stacked
 * directly under another full-width dark band. Two banners in a row is the
 * thing the calm doctrine exists to prevent, and a whole band to report the
 * number one is out of proportion to what it says.
 *
 * The bell does the noticing and the cards do the telling. Nothing here is
 * bigger than what it reports.
 */
.tiled-home .th-waits { margin: var(--sp-4) 0 var(--sp-5); }
.tiled-home .th-waits__head {
	display: flex;
	align-items: center;
	gap: var(--sp-3);
	margin: 0 0 var(--sp-3);
	font-weight: 700;
	font-size: var(--fs-md);
	color: var(--ink);
}

/* The bell, and the count riding on it where a count belongs. */
.tiled-home .th-bell__ico { position: relative; display: inline-flex; flex: none; color: var(--bad-600, #C0392B); }
.tiled-home .th-bell__ico svg { width: 22px; height: 22px; display: block; transform-origin: 50% 4px; }
.tiled-home .th-bell__n {
	position: absolute;
	top: -5px;
	right: -7px;
	min-width: 16px;
	height: 16px;
	padding: 0 4px;
	border-radius: 999px;
	background: var(--bad-600, #C0392B);
	color: #fff;
	font-size: 10px;
	font-weight: 800;
	line-height: 16px;
	text-align: center;
	font-variant-numeric: tabular-nums;
}

/*
 * It rings, then rests. A bell that never stops is a bell somebody turns off in
 * their head after a minute, and this one has to still work on the tenth visit
 * of the day. Two shakes in eight seconds is enough to catch an eye crossing
 * the page and little enough to sit beside reading.
 */
@keyframes th-ring {
	0%, 74%, 100% { transform: rotate(0); }
	76% { transform: rotate(13deg); }
	78% { transform: rotate(-11deg); }
	80% { transform: rotate(9deg); }
	82% { transform: rotate(-7deg); }
	84% { transform: rotate(4deg); }
	86% { transform: rotate(0); }
}
.tiled-home .th-bell__ico svg { animation: th-ring 8s ease-in-out infinite; }

.tiled-home .th-waits__grid {
	display: grid;
	/* Explicit tracks, never auto-fit: one waiting table must not stretch into
	   a full-width slab, which is the banner all over again. */
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--sp-3);
}
.tiled-home .th-wait {
	display: block;
	padding: var(--sp-3) var(--sp-4);
	border: 1px solid var(--line);
	border-left: 3px solid var(--bad-600, #C0392B);
	border-radius: var(--r-md);
	background: var(--bg-card, #fff);
	color: inherit;
	text-decoration: none;
	transition: border-color .15s ease, transform .15s ease;
	/* A long venue name breaks rather than pushing the grid sideways. */
	min-width: 0;
	overflow-wrap: anywhere;
}
.tiled-home .th-wait:hover { border-color: var(--act); transform: translateY(-1px); }
.tiled-home .th-wait:focus-visible { outline: 2px solid var(--act); outline-offset: 2px; }
.tiled-home .th-wait__when { display: block; font-size: var(--fs-md); }
.tiled-home .th-wait__who { display: block; margin-top: 2px; font-size: var(--fs-sm); color: var(--ink-soft); }
.tiled-home .th-wait__tag {
	display: inline-block;
	margin-top: 6px;
	padding: 1px 8px;
	border-radius: 999px;
	background: var(--wash-100, #E7EDEB);
	font-size: var(--fs-xs);
	font-weight: 700;
	color: var(--act);
}
.tiled-home .th-waits__more { display: inline-block; margin-top: var(--sp-3); font-size: var(--fs-sm); }

/* Nothing waiting deserves no furniture at all: one quiet line, no band. */
.tiled-home .th-clear {
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	margin: var(--sp-4) 0 var(--sp-5);
	font-size: var(--fs-sm);
	color: var(--ink-soft);
}
.tiled-home .th-clear svg { width: 16px; height: 16px; flex: none; color: var(--act); }

@media (max-width: 900px) {
  .tiled-home .th-waits__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .tiled-home .th-waits__grid { grid-template-columns: minmax(0, 1fr); }
}
@media (prefers-reduced-motion: reduce) {
  /* The red and the count still say it; only the movement goes. */
  .tiled-home .th-bell__ico svg { animation: none; }
  .tiled-home .th-wait:hover { transform: none; }
}

/*
 * NEW MESSAGES ON A REQUEST CARD (v12.7). Sits under the head, above the
 * accept and decline controls, because a card is read from the top and the
 * thread it points at is at the bottom.
 *
 * A dot rather than a bell here: this one appears inside a card that may
 * already be beside two others, and three ringing bells is a fire alarm.
 */
.th-new {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	margin: var(--sp-3) 0 0;
	padding: 5px 12px 5px 10px;
	border-radius: 999px;
	background: var(--bad-50, #FBE9E7);
	color: var(--bad-600, #C0392B);
	font-size: var(--fs-sm);
	font-weight: 700;
	text-decoration: none;
}
.th-new:hover { text-decoration: underline; }
.th-new__dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; flex: none; animation: th-pulse 2.4s ease-in-out infinite; }
@keyframes th-pulse {
	0%, 100% { opacity: 1; transform: scale(1); }
	50% { opacity: .45; transform: scale(.82); }
}
@media (prefers-reduced-motion: reduce) {
  .th-new__dot { animation: none; }
}

/*
 * THE HOMEPAGE MAP, SHUT BY DEFAULT (v13.0).
 *
 * The target is that a visitor sees and learns everything here in two scrolls.
 * An always-open map spent most of one of them on a picture of Cyprus, above
 * the sections that actually explain the place. Shut, this whole section is a
 * heading and a button; open, it is the same map it always was, in place, with
 * the reader still on the homepage.
 *
 * Collapsed by HEIGHT rather than display:none, because Leaflet has to be able
 * to measure the box it is going into. A map built inside a hidden element
 * comes up grey and half-tiled, which is the fault this avoids.
 */
/* The close button is the pair of the open one, and only exists once open. */
.homemap__close { display: none; }
.homemap.is-open .homemap__close { display: block; }
/*
 * SHUT, THE WHOLE SECTION IS SILENT (v14.2). The heading and the filters were
 * still standing there with nothing under them, announcing a map that was not
 * on the page. The link that opens it lives with the venues above; until it is
 * pressed this section has nothing to say.
 */
.homemap:not(.is-open) .homemap__key,
.homemap:not(.is-open) .homemap__head { display: none; }

@media (prefers-reduced-motion: reduce) {
  .homemap__frame { transition: none; }
}

/*
 * THE TYPE ROW (v13.0). Modelled on the Show more / Show on the map line under
 * the shelf, which the owner singled out as the one that reads as relaxing:
 * hairline rule, generous space, low-contrast text, nothing boxed.
 *
 * Eight of these fit at --page-max where eight tiles never could, which is what
 * lets one row hold every type instead of four here and four further down.
 */
.type-row {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--sp-1, 4px) var(--sp-4);
	padding: var(--sp-3) 0;
	border-bottom: 1px solid var(--line);
}
.type-link {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	padding: 6px 2px;
	font-size: var(--fs-sm);
	font-weight: 600;
	color: var(--ink-soft);
	text-decoration: none;
	border-bottom: 2px solid transparent;
	transition: color .12s ease, border-color .12s ease;
}
.type-link__ic { display: inline-flex; }
.type-link__ic svg { width: 17px; height: 17px; }
.type-link:hover { color: var(--ink); }
/*
 * The chosen one is the only thing in the row with weight. An underline rather
 * than a filled pill: it marks the row it belongs to without becoming a button
 * competing with the venues below.
 */
.type-link.is-on { color: var(--act); border-bottom-color: var(--act); font-weight: 800; }
.type-link:focus-visible { outline: 2px solid var(--act); outline-offset: 3px; border-radius: 4px; }

@media (max-width: 900px) {
  .type-row { gap: var(--sp-1, 4px) var(--sp-3); }
  .type-link { font-size: var(--fs-xs); }
}

/*
 * SHOW LESS (v14.8). The quieter of the pair: Show more is the wide bar that
 * reads as the list continuing, and this is the way back, so it should not
 * compete with it. Same shape, less weight.
 */
.browse-less { font-weight: 600; opacity: .72; }
.browse-less:hover { opacity: 1; }
