/* Mosaic layout — masonry photo wall.
 *
 * Grid with row spans, not CSS columns. Columns were the first build and are the
 * cheaper masonry — real packing, no measuring pass — but they fill
 * top-to-bottom, one column at a time. That put the last tiles in the DOM down
 * the whole right-hand edge, so the host's own custom sections sat level with the
 * wifi password and "up top" meant nothing. This wall has a priority order (see
 * ORDER in mosaic.js) and has to read across.
 *
 * So: fixed 8px rows, and each tile spans however many of them its shape needs.
 * The span is measured in JS (`layout()`), because the height a tile wants is a
 * ratio of the column width, which CSS can't express as a row count. The classes
 * below carry a static span as a fallback, sized for a phone, so the wall is
 * never broken if that pass doesn't run. */

[data-layout="mosaic"] .guide-content {
	max-width: 860px !important;
	padding: 0 0 96px !important;
}
[data-layout="mosaic"] .guide-nav { display: none !important; }

/* ---- Header ---- */
.ms-head {
	position: relative;
	padding: 66px 18px 22px;
	background: var(--surface);
	border-bottom: 1px solid var(--border);
}
.ms-head--photo {
	background-size: cover;
	background-position: center;
	border-bottom: 0;
	padding: 96px 18px 30px;
}
.ms-head--photo::before {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(180deg, rgba(0, 0, 0, .28), rgba(0, 0, 0, .64));
}
.ms-head h1, .ms-head p { position: relative; z-index: 1; }
.ms-head h1 {
	margin: 0;
	font-size: clamp(1.6rem, 5.5vw, 2.1rem);
	font-weight: 800;
	letter-spacing: -.02em;
	color: var(--text);
}
.ms-head p { margin: .3rem 0 0; font-size: .95rem; color: var(--text-soft); }
.ms-head--photo h1 { color: #fff; }
.ms-head--photo p { color: rgba(255, 255, 255, .84); }

/* ---- The wall ----
 *
 * grid-auto-rows and the gap are read back by layout() in mosaic.js; changing
 * either here without changing it there puts the measured spans out by a row. */
.ms-grid {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	grid-auto-rows: 8px;
	gap: 10px;
	padding: 14px 12px 0;
}
@media (min-width: 700px) { .ms-grid { grid-template-columns: repeat(3, 1fr); } }

.ms-tile {
	grid-row: span var(--ms-span);
	position: relative;
	padding: 0;
	border: 0;
	border-radius: 16px;
	overflow: hidden;
	cursor: pointer;
	background: var(--chip);
	text-align: left;
	-webkit-tap-highlight-color: transparent;
}
/* Phone-sized fallbacks (~178px column): short 4:3, medium 1:1, tall 3:4.
 * layout() overwrites --ms-span with the measured value. */
.ms-tile--short { --ms-span: 8; }
.ms-tile--medium { --ms-span: 11; }
.ms-tile--tall { --ms-span: 14; }

.ms-art {
	position: absolute;
	inset: 0;
	display: block;
	background-size: cover;
	background-position: center;
}

/* A photo tile is two stacked copies of the same image (--ms-art):
 *
 *   .ms-art-fill  blown up and blurred, purely to fill
 *   .ms-art-img   the real thing, `cover`
 *
 * The fill only ever shows where the sharp layer can't reach — most often a host
 * avatar saved as a circle-cropped PNG, whose transparent corners otherwise let
 * the grey chip through and made the tile read as a cut-out rather than a photo.
 * 175% is sized off that worst case: the inscribed square of a circle is ~71% of
 * its diameter, so the circle has to be about 1.42x the tile before its solid
 * middle covers the corners. An ordinary opaque photo hides the fill entirely. */
.ms-art-fill, .ms-art-img {
	position: absolute;
	inset: 0;
	background-image: var(--ms-art);
	background-position: center;
}
.ms-art-img { background-size: cover; }
.ms-art-fill {
	background-size: 175%;
	filter: blur(18px) saturate(1.35);
	/* Blur samples past the edges and would fade them out; the scale pushes that
	 * soft margin outside the tile, which is clipped anyway. */
	transform: scale(1.15);
}

/* Flagged by markCutout(): the file is a shape on transparency, so `cover` still
 * leaves its corners empty and the shape's own edge reads as an outline. Zoom
 * until the solid middle covers the tile.
 *
 * 1.5 comes from the circle: `cover` makes its diameter the tile's longer side,
 * and the square that fits inside a circle is ~71% of the diameter, so it takes
 * ~1.42x before the corners are buried. Rounded up, since a portrait saved with
 * a little padding around the circle needs slightly more. */
.ms-art--cutout .ms-art-img { transform: scale(1.5); }

/* A whisper of the guide's accent over each photo, so host photography and the
 * accent-filled generated tiles read as one wall.
 *
 * This was 16% once and had to be removed: multiply at that strength recolours
 * the whole image, and with the old default red accent every photo, skin tones
 * included, came out pink. 8% is the strength where the wall ties together and
 * a face still looks like a face. It is also a far safer number now that the
 * accent comes from a theme rather than defaulting to brand red. */
.ms-art--photo::after {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--accent);
	mix-blend-mode: multiply;
	opacity: .08;
	pointer-events: none;
}

/* A generated filler is a full duotone: it has no photographic content to
 * protect, and the stronger treatment is what stops it reading as "missing
 * image". The icon is the artwork. */
.ms-art--made { background: var(--accent); }
/* Sheen, so a flat fill reads as a surface rather than a swatch. */
.ms-art--made::before {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(155deg, rgba(255, 255, 255, .26), rgba(0, 0, 0, .14));
}
/* Neighbouring fillers step in lightness only — same hue, one family. */
.ms-art--made[data-shade="1"]::after {
	content: "";
	position: absolute;
	inset: 0;
	background: rgba(0, 0, 0, .12);
}
.ms-art--made[data-shade="2"]::after {
	content: "";
	position: absolute;
	inset: 0;
	background: rgba(255, 255, 255, .16);
}

.ms-mark {
	position: absolute;
	right: -6%;
	bottom: -8%;
	opacity: .42;
	line-height: 1;
	z-index: 1;
}
.ms-mark i {
	font-size: 7rem;
	color: var(--on-accent);
}

/* ---- Caption ---- */
.ms-cap {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 2;
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 28px 12px 12px;
	background: linear-gradient(180deg, transparent, rgba(0, 0, 0, .72));
	color: #fff;
}
.ms-cap strong {
	font-size: .95rem;
	font-weight: 700;
	line-height: 1.25;
	text-shadow: 0 1px 3px rgba(0, 0, 0, .5);
	overflow: hidden;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
}
.ms-cap-ic i { font-size: 1.1rem; color: #fff; }

/* A generated tile is accent-coloured underneath, so a dark scrim would fight
 * it. Caption ink matches the accent's own contrast colour instead. */
.ms-tile:has(.ms-art--made) .ms-cap {
	background: none;
	color: var(--on-accent);
	padding-top: 12px;
}
.ms-tile:has(.ms-art--made) .ms-cap strong { text-shadow: none; }
.ms-tile:has(.ms-art--made) .ms-cap-ic i { color: var(--on-accent); }
/* Caption sits top-left on generated tiles — the watermark owns bottom-right. */
.ms-tile:has(.ms-art--made) .ms-cap { top: 0; bottom: auto; align-items: flex-start; }

/* ---- Sponsor band ----
 * Spans every column, so it reads as the seam between the guest's own guide
 * above and the host's custom sections below. layout() levels the tiles above
 * it so that seam is a straight line rather than a ragged masonry edge. */
.ms-ad {
	grid-column: 1 / -1;
	grid-row: span var(--ms-span, 20);
	border-radius: 16px;
	overflow: hidden;
}
.ms-ad .guide-banner {
	display: block;
	height: 100%;
	margin: 0 !important;
	border-radius: 0 !important;
	box-shadow: none !important;
}
/* `cover` absorbs the <=8px of row-rounding slack as an invisible crop rather
 * than letterboxing the creative. */
.ms-ad .guide-banner img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

/* ---- Places + host notes, below the wall ----
 * The carousel is the shared "wide" treatment (see data-recs in public.html);
 * this only gives it the gutter the grid above already has. */
.ms-recs { padding: 26px 12px 0; }
.ms-recs .rec-cats { padding: 0 4px !important; }
[data-layout="mosaic"] .hg-hostrecs { padding: 4px 0 8px; }
/* Host-rec rows sit directly on the wall, at the wall's own inset. */
[data-layout="mosaic"] { --sec-gutter: 12px; }
[data-layout="mosaic"] .ap-hostrec { margin-bottom: 12px; }
/* The paid section lives inside .ms-recs, which already insets by 12. Re-declare
   the gutter here rather than padding the heading by hand: it has to reach the
   carousel's padding AND its scroll-padding too, or snapping parks the first
   card a few pixels off the heading. */
[data-layout="mosaic"] .ms-recs { --sec-gutter: 16px; }
[data-layout="mosaic"] .ap-h {
	font-weight: 800;
	font-size: 1.15rem;
	color: var(--text);
	margin: 18px 16px 12px;
}

.ms-tile:active { transform: scale(.985); }

@media (prefers-reduced-motion: reduce) {
	.ms-tile:active { transform: none; }
}

/* ---- Weather tile ----
 * The no-ad case: the forecast is an ordinary square tile on the wall. Same card
 * as the band below, squeezed into a tile — type steps down, separator goes, and
 * the forecast is pinned to the bottom edge. */
.ms-tile--wx { --ms-span: 11; cursor: default; background: transparent; }
.ms-tile--wx:active { transform: none; }
.ms-tile--wx #weather.wx-card {
	position: absolute; inset: 0; margin: 0 !important;
	padding: 13px 14px 12px; border-radius: 0; box-shadow: none;
	display: flex; flex-direction: column;
}
.ms-tile--wx .wx-loc { font-size: .82rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ms-tile--wx .wx-now { align-items: center; margin-top: 2px; }
.ms-tile--wx .wx-temp { font-size: 2.3rem; }
.ms-tile--wx .wx-cond { font-size: .74rem; }
.ms-tile--wx .wx-hl { font-size: .7rem; }
.ms-tile--wx .wx-now-icon { width: 42px; height: 42px; margin: 0 -2px 0 6px; }
.ms-tile--wx .wx-sep { display: none; }
.ms-tile--wx .wx-days { margin-top: auto; gap: .3rem; }
.ms-tile--wx .wx-day:nth-child(n+4) { display: none; }
.ms-tile--wx .wx-day .d { font-size: .68rem; }
.ms-tile--wx .wx-day .ic { width: 21px; height: 21px; margin: 2px auto; }
.ms-tile--wx .wx-day .hi, .ms-tile--wx .wx-day .lo { font-size: .7rem; }
@media (min-width: 700px) {
	.ms-tile--wx #weather.wx-card { padding: 16px 18px 15px; }
	.ms-tile--wx .wx-loc { font-size: .95rem; }
	.ms-tile--wx .wx-temp { font-size: 3rem; }
	.ms-tile--wx .wx-now-icon { width: 62px; height: 62px; }
	.ms-tile--wx .wx-day .ic { width: 26px; height: 26px; }
	.ms-tile--wx .wx-day .d, .ms-tile--wx .wx-day .hi, .ms-tile--wx .wx-day .lo { font-size: .78rem; }
}

/* ---- Weather band ----
 *
 * Full width, under the ad. It used to be a square tile in the wall, which was
 * the source of most of the levelling trouble: it holds a live card rather than
 * a croppable photo, so it was the one thing the levelling pass could not resize,
 * and it ended up either stretched into a lake of empty gradient or forcing a
 * ragged seam. Wide is also simply the right shape for a forecast — the same
 * arrangement the app-menu layout uses.
 *
 * It brings its own sky gradient, repainted by condition, so it needs no accent
 * treatment to belong here. */
.ms-wx {
	grid-column: 1 / -1;
	grid-row: span var(--ms-span, 24);
	border-radius: 16px;
	overflow: hidden;
}
.ms-wx #weather.wx-card {
	/* Fills the band so the sky gradient reaches its rounded corners. layout()
	 * measures the card's natural height first (it unsets this for one frame),
	 * then sizes the band to it, so filling can never mean clipping. */
	height: 100%;
	margin: 0 !important;
	border-radius: 0;
	box-shadow: none;
	padding: 16px 22px 14px;
	display: grid;
	grid-template-columns: auto 1fr;
	column-gap: 22px;
	align-items: center;
}
.ms-wx .wx-loc { grid-column: 1; grid-row: 1; }
.ms-wx .wx-now { grid-column: 1; grid-row: 2; display: block; }
/* The big glyph duplicates the forecast row beside it; the row is more useful. */
.ms-wx .wx-now-icon { display: none !important; }
.ms-wx .wx-sep { display: none !important; }
.ms-wx .wx-temp { font-size: 3rem; }
.ms-wx .wx-days {
	grid-column: 2;
	grid-row: 1 / span 2;
	gap: .55rem;
	justify-content: flex-end;
}
.ms-wx .wx-day .ic { width: 30px; height: 30px; }

@media (max-width: 699.98px) {
	.ms-wx #weather.wx-card { padding: 15px 16px 14px; column-gap: 12px; }
	.ms-wx .wx-temp { font-size: 2.4rem; }
	.ms-wx .wx-loc { font-size: .95rem; }
	.ms-wx .wx-day .ic { width: 24px; height: 24px; }
	.ms-wx .wx-day .d, .ms-wx .wx-day .hi, .ms-wx .wx-day .lo { font-size: .78rem; }
	/* Three days is all that fits beside the temperature on a phone. */
	.ms-wx .wx-day:nth-child(n+5) { display: none; }
}
