/* The photo-collage builder.

   Everything is scoped under .cb so nothing here can leak into the rest of the
   site, and nothing in the site stylesheet needs to change for this page to
   exist. The page is standalone - no header.php, no site nav - so the reset at
   the top only has to cope with the browser's defaults.

   One stylesheet serves phones and desktops. The previous builder had a
   fixed-width desktop page and a second, separately maintained mobile page;
   the two had already drifted apart. */

.cb {
	--cb-accent:      #2b7fa3;
	--cb-accent-soft: #60b5da;
	--cb-accent-wash: #eaf4f9;
	--cb-ink:         #1b2b34;
	--cb-ink-soft:    #55707f;
	--cb-ink-faint:   #8299a6;
	--cb-line:        #d8e3e9;
	--cb-line-soft:   #eef3f6;
	--cb-surface:     #f6f9fb;
	--cb-ground:      #ffffff;
	--cb-well:        #26333b;
	--cb-well-deep:   #1a242a;
	--cb-err:         #b23b28;
	--cb-ok:          #2c6f52;
	--cb-radius:      10px;
	--cb-panel-w:     380px;

	/* The height of the action bar, which is fixed to the bottom of the
	   viewport. Reserved as padding at the foot of the scrolling column so the
	   bar never covers the last control. */
	--cb-bar-h:       74px;

	color: var(--cb-ink);
	background: var(--cb-surface);
	font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
	-webkit-font-smoothing: antialiased;
	box-sizing: border-box;
	min-height: 100vh;
	/* Belt and braces. Several strips here are single-line by design - the
	   title, the price, the hint - and a long one must clip rather than widen
	   the document and set the whole page sliding sideways on a phone. */
	overflow-x: hidden;
}
.cb *, .cb *::before, .cb *::after { box-sizing: inherit; }
.cb h1, .cb h2, .cb h3, .cb p, .cb ul, .cb figure { margin: 0; }
.cb ul { list-style: none; padding: 0; }
.cb button { font: inherit; color: inherit; }
.cb img { display: block; max-width: 100%; }

/* ---------- top bar ---------- */

.cb-top {
	display: flex;
	align-items: center;
	gap: 14px;
	padding: 12px 18px;
	background: var(--cb-ground);
	border-bottom: 1px solid var(--cb-line);
	position: sticky;
	top: 0;
	z-index: 40;
}
.cb-top h1 {
	flex: 1 1 auto;
	min-width: 0;
	font-size: 1.05rem;
	font-weight: 650;
	letter-spacing: -0.01em;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.cb-top .cb-sub {
	color: var(--cb-ink-faint);
	font-size: 0.85rem;
	margin-left: auto;
	white-space: nowrap;
	flex: none;
}
@media (max-width: 520px) {
	/* The size and edge are both a tap away in the panel, and the price line
	   at the foot repeats them. */
	.cb-top .cb-sub { display: none; }
}
.cb-close {
	margin-left: 8px;
	width: 36px;
	height: 36px;
	display: grid;
	place-items: center;
	border-radius: 50%;
	border: 1px solid var(--cb-line);
	background: var(--cb-ground);
	color: var(--cb-ink-soft);
	text-decoration: none;
	cursor: pointer;
	flex: none;
}
.cb-close:hover { background: var(--cb-surface); color: var(--cb-ink); }

/* ---------- shell ---------- */

.cb-shell {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	align-items: start;
}
@media (min-width: 1000px) {
	.cb-shell {
		grid-template-columns: minmax(0, 1fr) var(--cb-panel-w);
		height: calc(100vh - 61px);
	}
	.cb-work { height: 100%; }
	.cb-panel {
		height: 100%;
		overflow-y: auto;
		border-left: 1px solid var(--cb-line);
		border-top: 0;
	}
}

/* ---------- the stage ---------- */

.cb-work {
	background: var(--cb-well);
	background-image:
		radial-gradient(ellipse at 50% 0%, rgba(255,255,255,0.06), transparent 70%);
	/* On a phone the panel is what ends the page, and it carries the allowance
	   for the fixed action bar. Here the stage only needs its own padding. */
	padding: 22px 18px;
	display: flex;
	flex-direction: column;
	gap: 14px;
	min-width: 0;
}
@media (min-width: 1000px) {
	/* Side by side, the stage column is its own full-height region and the bar
	   lies across the foot of it, so the centring has to allow for the bar. */
	.cb-work {
		padding-bottom: calc(var(--cb-bar-h) + 22px);
		justify-content: center;
	}
}

.cb-stage-wrap {
	width: 100%;
	max-width: 900px;
	margin: 0 auto;
}
.cb-stage {
	position: relative;
	width: 100%;
	/* 3:2, the aspect of every collage print size. aspect-ratio with a padding
	   fallback for older Safari, which this site still sees. */
	aspect-ratio: 3 / 2;
	background: #ffffff;
	box-shadow: 0 18px 50px rgba(0,0,0,0.45), 0 2px 6px rgba(0,0,0,0.3);
	overflow: hidden;
	/* A finger on an empty slot still scrolls the page. Only a filled photo -
	   which is the one thing a drag is meant to move - takes the gesture. */
	touch-action: pan-y;
}
@supports not (aspect-ratio: 3 / 2) {
	.cb-stage { height: 0; padding-bottom: 66.6667%; }
}

.cb-cell { position: absolute; }

/* The frame carries the geometry and the hover; the crop inside it is what
   clips. They were one element, and the overflow that has to hide the
   overhanging parts of a photograph was also cutting off the toolbar in any
   cell narrower than the toolbar - which is why the buttons appeared over some
   photos and not others. */
.cb-frame {
	position: absolute;
	inset: 0;
	cursor: pointer;
}
.cb-crop {
	position: absolute;
	inset: 0;
	overflow: hidden;
	background: var(--cb-line-soft);
}
.cb-cell.is-filled .cb-frame { cursor: grab; touch-action: none; }
.cb-cell.is-filled .cb-crop { background: #dfe7ec; }
.cb-cell.is-filled .cb-frame:active { cursor: grabbing; }
/* The hovered cell sits above its neighbours, so a toolbar reaching past a
   narrow cell is drawn over them rather than under. */
.cb-cell:hover, .cb-cell.is-active { z-index: 10; }
.cb-crop img {
	position: absolute;
	max-width: none;
	transform-origin: 50% 50%;
	user-select: none;
	-webkit-user-drag: none;
	pointer-events: none;
}

/* Empty slot. The whole frame is the drop target and the whole frame opens the
   file picker - the previous builder had a 100px "Select Image" button whose
   position was recalculated in JavaScript on every layout change. */
.cb-empty {
	position: absolute;
	inset: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 6px;
	color: var(--cb-ink-faint);
	text-align: center;
	padding: 6px;
	border: 1px dashed #b9c9d2;
	transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.cb-empty svg { width: 26px; height: 26px; opacity: 0.75; }
.cb-empty span { font-size: 0.78rem; letter-spacing: 0.01em; }
.cb-frame:hover .cb-empty { background: var(--cb-accent-wash); color: var(--cb-accent); border-color: var(--cb-accent-soft); }
.cb-cell.is-over .cb-empty,
.cb-cell.is-over .cb-frame { background: var(--cb-accent-wash); }
.cb-cell.is-over { outline: 2px solid var(--cb-accent-soft); outline-offset: -2px; }

/* A filled cell has no placeholder. Both the wording and the dashed outline
   would otherwise sit on top of the photograph. */
.cb-cell.is-filled .cb-empty { display: none; }

/* Cells with no room for the wording show the icon alone. */
.cb-cell.is-tight .cb-empty span { display: none; }

/* Per-photo tools. Shown on hover, and always on touch - where there is no
   hover - via .cb-touch on the root. */
.cb-tools {
	position: absolute;
	left: 50%;
	bottom: 6px;
	transform: translateX(-50%);
	display: flex;
	gap: 2px;
	padding: 3px;
	border-radius: 999px;
	background: rgba(20,28,33,0.82);
	-webkit-backdrop-filter: blur(6px);
	backdrop-filter: blur(6px);
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.15s;
	z-index: 5;
	white-space: nowrap;
}
.cb-cell.is-filled:hover .cb-tools,
.cb-cell.is-filled .cb-tools:hover,
/* Touch has no hover: tapping a photo makes it the active one. Every toolbar
   used to be shown at once, which on a nine-photo collage buried the collage. */
.cb-cell.is-filled.is-active .cb-tools { opacity: 1; pointer-events: auto; }
.cb-tools button {
	width: 30px;
	height: 30px;
	display: grid;
	place-items: center;
	border: 0;
	border-radius: 50%;
	background: transparent;
	color: #fff;
	cursor: pointer;
	padding: 0;
}
.cb-tools button:hover { background: rgba(255,255,255,0.18); }
.cb-tools button svg { width: 16px; height: 16px; }

/* Narrower cells drop the buttons that have another way to reach them: zooming
   is also the scroll wheel and a pinch, and swapping is also a drag. Replace,
   rotate and remove have no other route, so they are the last to go. */
.cb-tools.is-sm { bottom: 4px; }
.cb-tools.is-sm button { width: 27px; height: 27px; }
.cb-tools.is-sm button svg { width: 15px; height: 15px; }
.cb-tools.is-sm [data-act="zoomin"],
.cb-tools.is-sm [data-act="zoomout"] { display: none; }

.cb-tools.is-xs { bottom: 3px; padding: 2px; }
.cb-tools.is-xs button { width: 24px; height: 24px; }
.cb-tools.is-xs button svg { width: 14px; height: 14px; }
.cb-tools.is-xs [data-act="zoomin"],
.cb-tools.is-xs [data-act="zoomout"],
.cb-tools.is-xs [data-act="move"] { display: none; }

/* Dragging a photo from one slot to another swaps them. */
.cb-cell.is-swap-target { outline: 3px solid var(--cb-accent-soft); outline-offset: -3px; }
.cb-cell.is-dragging .cb-frame { opacity: 0.45; }

/* ---------- stage footer: hint + quick actions ---------- */

.cb-stage-bar {
	max-width: 900px;
	margin: 0 auto;
	width: 100%;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 10px;
	color: rgba(255,255,255,0.62);
	font-size: 0.82rem;
}
.cb-stage-bar .cb-hint { flex: 1 1 240px; min-width: 0; }
@media (max-width: 700px) {
	/* Below the width where it can sit beside the buttons, the hint takes its
	   own line rather than pushing them off the screen. */
	.cb-stage-bar .cb-hint { flex-basis: 100%; text-align: left; }
	.cb-stage-bar .cb-spacer { margin-left: 0; }
}
.cb-ghost {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	padding: 8px 14px;
	border-radius: 999px;
	border: 1px solid rgba(255,255,255,0.22);
	background: rgba(255,255,255,0.06);
	color: #fff;
	font-size: 0.85rem;
	cursor: pointer;
}
.cb-ghost:hover { background: rgba(255,255,255,0.14); }
.cb-ghost svg { width: 15px; height: 15px; }
.cb-ghost[disabled] { opacity: 0.4; cursor: default; }
.cb-stage-bar .cb-spacer { margin-left: auto; }

/* ---------- side panel ---------- */

.cb-panel {
	background: var(--cb-ground);
	border-top: 1px solid var(--cb-line);
	padding-bottom: calc(var(--cb-bar-h) + 12px);
}
.cb-tabs {
	display: flex;
	position: sticky;
	top: 0;
	background: var(--cb-ground);
	border-bottom: 1px solid var(--cb-line);
	z-index: 5;
}
.cb-tabs button {
	flex: 1;
	padding: 13px 4px 11px;
	background: none;
	border: 0;
	border-bottom: 2px solid transparent;
	color: var(--cb-ink-soft);
	font-size: 0.85rem;
	font-weight: 550;
	cursor: pointer;
}
.cb-tabs button[aria-selected="true"] { color: var(--cb-accent); border-bottom-color: var(--cb-accent); }

.cb-tabpanel { padding: 18px; display: none; }
.cb-tabpanel.is-active { display: block; }
.cb-tabpanel > h2 {
	font-size: 0.78rem;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--cb-ink-faint);
	font-weight: 600;
	margin-bottom: 10px;
}
.cb-tabpanel > h2:not(:first-child) { margin-top: 24px; }
.cb-note { color: var(--cb-ink-soft); font-size: 0.85rem; margin-top: 10px; }

/* Photo-count filter chips */
.cb-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.cb-chip {
	padding: 5px 12px;
	border-radius: 999px;
	border: 1px solid var(--cb-line);
	background: var(--cb-ground);
	color: var(--cb-ink-soft);
	font-size: 0.82rem;
	cursor: pointer;
}
.cb-chip:hover { border-color: var(--cb-accent-soft); color: var(--cb-accent); }
.cb-chip[aria-pressed="true"] {
	background: var(--cb-accent);
	border-color: var(--cb-accent);
	color: #fff;
}

/* Layout picker. The thumbnails are SVG drawn from the same cell fractions the
   stage uses, so a new layout in config_collage_layouts.php appears here on its
   own - there is no icon file to make. */
.cb-layouts {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
	gap: 10px;
}
.cb-layout {
	border: 1px solid var(--cb-line);
	border-radius: 8px;
	background: var(--cb-ground);
	padding: 7px 7px 5px;
	cursor: pointer;
	text-align: center;
	transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s;
}
.cb-layout:hover { border-color: var(--cb-accent-soft); transform: translateY(-2px); }
.cb-layout[aria-pressed="true"] {
	border-color: var(--cb-accent);
	box-shadow: 0 0 0 2px var(--cb-accent-wash);
}
.cb-layout svg { width: 100%; height: auto; display: block; }
.cb-layout .cb-layout-name {
	display: block;
	margin-top: 5px;
	font-size: 0.68rem;
	line-height: 1.25;
	color: var(--cb-ink-soft);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.cb-layout[aria-pressed="true"] .cb-layout-name { color: var(--cb-accent); font-weight: 600; }
.cb-layout .cb-layout-cell { fill: #c9d7de; }
.cb-layout[aria-pressed="true"] .cb-layout-cell { fill: var(--cb-accent-soft); }

/* Option lists: sizes, edges, spacing */
.cb-options { display: flex; flex-direction: column; gap: 8px; }
.cb-option {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 12px 14px;
	border: 1px solid var(--cb-line);
	border-radius: 8px;
	cursor: pointer;
	background: var(--cb-ground);
}
.cb-option:hover { border-color: var(--cb-accent-soft); }
.cb-option input { position: absolute; opacity: 0; width: 0; height: 0; }
.cb-option .cb-dot {
	width: 18px;
	height: 18px;
	border-radius: 50%;
	border: 2px solid var(--cb-line);
	flex: none;
	position: relative;
}
.cb-option input:checked ~ .cb-dot { border-color: var(--cb-accent); }
.cb-option input:checked ~ .cb-dot::after {
	content: "";
	position: absolute;
	inset: 3px;
	border-radius: 50%;
	background: var(--cb-accent);
}
.cb-option input:focus-visible ~ .cb-dot { box-shadow: 0 0 0 3px var(--cb-accent-wash); }
.cb-option:has(input:checked) { border-color: var(--cb-accent); background: var(--cb-accent-wash); }
.cb-option .cb-option-body { flex: 1; min-width: 0; }
.cb-option .cb-option-title { font-weight: 550; font-size: 0.95rem; }
.cb-option .cb-option-meta { font-size: 0.82rem; color: var(--cb-ink-soft); }
.cb-option .cb-was { text-decoration: line-through; color: var(--cb-ink-faint); margin-right: 6px; }
.cb-option .cb-now { color: var(--cb-ok); font-weight: 600; }
.cb-option img { width: 46px; height: 46px; border-radius: 6px; flex: none; object-fit: cover; }

/* Segmented control - spacing amount and border colour */
.cb-seg { display: flex; gap: 6px; flex-wrap: wrap; }
.cb-seg button {
	flex: 1 1 auto;
	min-width: 64px;
	padding: 9px 10px;
	border: 1px solid var(--cb-line);
	border-radius: 8px;
	background: var(--cb-ground);
	color: var(--cb-ink-soft);
	font-size: 0.85rem;
	cursor: pointer;
}
.cb-seg button:hover { border-color: var(--cb-accent-soft); }
.cb-seg button[aria-pressed="true"] {
	border-color: var(--cb-accent);
	background: var(--cb-accent-wash);
	color: var(--cb-accent);
	font-weight: 600;
}
.cb-swatch {
	display: inline-block;
	width: 14px;
	height: 14px;
	border-radius: 3px;
	border: 1px solid rgba(0,0,0,0.15);
	vertical-align: -2px;
	margin-right: 7px;
}

/* ---------- action bar ---------- */

.cb-bar {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 50;
	display: flex;
	align-items: center;
	gap: 14px;
	padding: 12px 18px;
	background: rgba(255,255,255,0.96);
	-webkit-backdrop-filter: blur(8px);
	backdrop-filter: blur(8px);
	border-top: 1px solid var(--cb-line);
}
.cb-bar .cb-total { line-height: 1.25; min-width: 0; flex: 1 1 auto; }
.cb-bar .cb-total-price, .cb-bar .cb-total-meta {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.cb-bar .cb-total-price { font-size: 1.3rem; font-weight: 650; letter-spacing: -0.02em; }
.cb-bar .cb-total-meta { font-size: 0.8rem; color: var(--cb-ink-soft); }
.cb-bar .cb-progress { margin-left: auto; font-size: 0.85rem; color: var(--cb-ink-soft); white-space: nowrap; }
.cb-cta {
	padding: 13px 26px;
	border: 0;
	border-radius: 8px;
	background: var(--cb-accent);
	color: #fff;
	font-size: 0.98rem;
	font-weight: 600;
	cursor: pointer;
	white-space: nowrap;
}
.cb-cta:hover { background: #236b8b; }
.cb-cta[disabled] { background: #b4c6ce; cursor: default; }
@media (max-width: 560px) {
	.cb-bar { gap: 10px; padding: 10px 12px; }
	.cb-bar .cb-progress { display: none; }
	.cb-cta { padding: 13px 18px; flex: 1; }
}

/* ---------- overlays ---------- */

.cb-loader {
	position: fixed;
	inset: 0;
	z-index: 100;
	display: none;
	place-items: center;
	background: rgba(16,24,29,0.72);
	color: #fff;
	text-align: center;
}
.cb-loader.is-on { display: grid; }
.cb-loader .cb-spin {
	width: 42px;
	height: 42px;
	margin: 0 auto 14px;
	border: 3px solid rgba(255,255,255,0.25);
	border-top-color: #fff;
	border-radius: 50%;
	animation: cb-spin 0.8s linear infinite;
}
@keyframes cb-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
	.cb-loader .cb-spin { animation-duration: 2.4s; }
	.cb-layout { transition: none; }
}

.cb-toast {
	position: fixed;
	left: 50%;
	bottom: calc(var(--cb-bar-h) + 16px);
	transform: translateX(-50%) translateY(10px);
	z-index: 90;
	max-width: min(420px, calc(100vw - 32px));
	padding: 12px 18px;
	border-radius: 8px;
	background: var(--cb-ink);
	color: #fff;
	font-size: 0.9rem;
	box-shadow: 0 10px 30px rgba(0,0,0,0.28);
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.2s, transform 0.2s;
}
.cb-toast.is-on { opacity: 1; transform: translateX(-50%) translateY(0); }
.cb-toast.is-err { background: var(--cb-err); }

.cb-sr {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
}
