/* Literal port of the moodboard-mockup HTML/CSS — class names match the
   mockup files exactly (spec §14), not an approximation of them. */

/* This plugin builds a genuinely standalone <body> for its three
   model-facing pages (see print_doc_open()/print_hero() in
   class-frontend.php) — not relying on the theme's own base reset for
   something this fundamental. Belt-and-braces against the browser's
   default ~8px body margin, in case a persistent gap below the hero
   turns out not to be caused by the .site-main rule below (0.24.3)
   after all. */
body.mb-standalone { margin:0; }

.visually-hidden { position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0; }

/* 0.24.5: renamed from .site-main to .mb-site-main. The actual cause
   of the persistent grey band below the hero (0.24.3/0.24.4 didn't fix
   it) was a class-name COLLISION, not caching or a code mistake in
   this rule: the active theme's own stylesheet independently defines
   a `.site-main { margin-top:20px }` rule (a generic, common WP class
   name for the main content wrapper) which this plugin happened to
   reuse verbatim. Both rules apply — margin and padding are different
   properties, so the cascade doesn't pick one stylesheet over the
   other, it just adds them together — meaning the theme's own
   margin-top:20px was there the entire time, untouched by any change
   made here, sitting outside our white background regardless of what
   this rule said. Confirmed via the person's own DevTools Styles
   panel showing both rules from their two distinct source files.
   Renaming our wrapper to a plugin-namespaced class removes the
   collision outright, rather than continuing to patch individual
   leaked properties as they surface one at a time. */
.mb-site-main { padding:20px 40px 0; background:#fff; margin:0; }

/* Hero/cover block (0.23.5, fixed 0.23.6) — self-contained, no theme
   nav. A flat dark overlay covers the whole photo so the centered white
   name/button stay readable regardless of how bright the source photo
   is — a bottom-up gradient (0.23.5) only darkened the lower edge,
   which didn't hold up once the text moved to the middle of the image
   (confirmed via screenshot on a bright photo). */
.mb-hero { position:relative; }
.mb-hero img { width:100%; aspect-ratio:1.56/1; object-fit:cover; display:block; }
.mb-hero-scrim { position:absolute; inset:0; background:rgba(0,0,0,.2); pointer-events:none; }
.mb-hero-content { position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center; padding:0 40px; color:#fff; text-align:center; }
.mb-hero-name { margin:0 0 20px; font-size:34px; font-weight:600; letter-spacing:.04em; text-transform:uppercase; }
.mb-hero-cta { background:transparent; border:1px solid rgba(255,255,255,.7); color:#fff; padding:11px 26px; font-size:12px; letter-spacing:.12em; text-transform:uppercase; cursor:pointer; }
.mb-hero-cta:hover { background:rgba(255,255,255,.12); }
.mb-hero-brand { position:absolute; left:0; right:0; bottom:22px; text-align:center; font-size:11px; letter-spacing:.15em; text-transform:uppercase; color:rgba(255,255,255,.75); }

/* Board nav strip — board tabs + download + log out, shown below the
   hero on every board page (added per direct request, modeled on
   Client Gallery's own equivalent strip). */
.board-nav { display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap; gap:14px; padding:18px 40px; border-bottom:1px solid #ececec; }
.board-nav-tabs { display:flex; gap:26px; flex-wrap:wrap; }
.board-nav-tab { font-size:12px; letter-spacing:.05em; color:#999; text-decoration:none; padding-bottom:6px; border-bottom:2px solid transparent; }
.board-nav-tab.active { color:#111; border-bottom-color:#111; }
.board-nav-tab:hover { color:#111; }
.board-nav-actions { display:flex; align-items:center; gap:18px; }
.board-nav-download { display:flex; align-items:center; gap:6px; font-size:13px; color:#333; text-decoration:none; }
.board-nav-download-icon { font-size:12px; }
.board-nav-logout { font-size:13px; color:#999; text-decoration:none; padding-left:18px; border-left:1px solid #ddd; }
.board-nav-logout:hover { color:#333; }
/* 0.32.1: thin vertical dividers between action groups — only visible
   on mobile's centered actions row; desktop's inline layout uses the
   existing border-left on .board-nav-logout and gap spacing instead. */
.board-nav-divider { display:none; }

.boardlist-wrap { position:relative; }
.boardlist-logout { position:absolute; top:0; right:20px; border-left:none; padding-left:0; }

/* Password gate — literal port of model-1-password.html */
.gate-wrap { display:flex; align-items:center; justify-content:center; padding:50px 20px; }
.gate-card { background:#fff; border-radius:6px; padding:44px 40px; max-width:380px; width:100%; box-shadow:0 10px 40px rgba(0,0,0,.06); text-align:center; }
.gate-card h2 { font-weight:400; font-size:22px; margin:0 0 6px; }
.gate-card p.sub { color:#666; font-size:13.5px; margin:0 0 26px; }
.gate-card .field { text-align:left; margin-bottom:14px; }
.gate-card label { display:block; font-size:11px; letter-spacing:.08em; text-transform:uppercase; color:#666; margin-bottom:5px; }
.gate-card input { width:100%; padding:12px 14px; border:1px solid rgba(17,17,17,.12); border-radius:4px; font-family:inherit; font-size:14px; }
.gate-card button, .gate-card a.button { display:block; width:100%; padding:13px; background:#111; color:#fff; border:none; border-radius:4px; font-size:13px; letter-spacing:.1em; text-transform:uppercase; cursor:pointer; margin-top:10px; text-decoration:none; text-align:center; }
.gate-error { color:#b3261e; font-size:13px; margin:-4px 0 14px; text-align:left; }

/* Board list — literal port of model-2-boards.html */
.boardlist-wrap { max-width:760px; margin:0 auto; padding:60px 20px 100px; }
.boardlist-wrap h1 { font-weight:400; font-size:26px; text-align:center; margin-bottom:8px; }
.boardlist-wrap p.sub { text-align:center; color:#666; font-size:14px; margin-bottom:44px; }
.boardlist-grid { display:grid; grid-template-columns:1fr 1fr; gap:26px; }
@media (max-width:600px){ .boardlist-grid{ grid-template-columns:1fr; } }
.boardlist-card { background:#fff; border-radius:6px; overflow:hidden; box-shadow:0 6px 24px rgba(0,0,0,.06); text-decoration:none; color:inherit; display:block; transition:transform .15s; }
.boardlist-card:hover { transform:translateY(-3px); }
.boardlist-card img { width:100%; aspect-ratio:1.4/1; object-fit:cover; }
.boardlist-card .bl-body { padding:16px 18px; }
.boardlist-card .bl-title { font-size:17px; margin:0 0 4px; }
.boardlist-card .bl-meta { font-size:12px; color:#666; }

/* Board page shoot-details — literal port of model-3-golden-hour.html */
.shoot-details { max-width:720px; margin:0 auto 36px; padding:8px 0 28px; border-bottom:1px solid rgba(17,17,17,.12); }
.shoot-details h1 { font-size:30px; font-weight:400; margin:0 0 22px; }
.detail-row { display:grid; grid-template-columns:140px 1fr; gap:16px; padding:9px 0; font-size:15px; }
.detail-row .label { font-size:11px; letter-spacing:.15em; text-transform:uppercase; color:#666; font-weight:500; padding-top:2px; }
.detail-row .value { color:#222; }


/* Board grid — 0.24.2: every tile is now a FIXED 5:7 portrait box
   (aspect-ratio, not row-stretch-derived), so every photo in the board
   renders at the same size regardless of its neighbours or its own
   natural aspect — fixing the inconsistency across the board flagged
   in the 0.24.0/0.24.1 screenshots (row-stretch sizing meant a tile's
   height depended on its row's tallest sibling, so identical-width
   photos came out different heights board-wide).
   - Photos NARROWER than 5:7 (more elongated portrait) crop to fill
     (object-fit:cover) — some of the top/bottom is cut off.
   - Photos WIDER than 5:7 (square-ish or landscape) letterbox inside
     the box (object-fit:contain) with the blurred backdrop filling
     the leftover space.
   Which of the two applies is a per-photo decision (depends on that
   photo's own natural aspect vs 5:7) that CSS alone cannot make, so
   frontend.js compares naturalWidth/naturalHeight on load and toggles
   .mb-fit-cover accordingly — see mbLoadImage().
   Mobile (≤520px, 1 column): the fixed ratio is dropped entirely and
   photos render at their own native height — no crop, no letterbox,
   no backdrop needed. */
.board-grid { display:grid; grid-template-columns:repeat(4,1fr); gap:16px; max-width:1400px; margin:0 auto; padding-bottom:40px; }
@media (max-width:1100px){ .board-grid{ grid-template-columns:repeat(3,1fr); } }
@media (max-width:800px) { .board-grid{ grid-template-columns:repeat(2,1fr); } }
@media (max-width:520px) { .board-grid{ grid-template-columns:1fr; } }

.board-item { position:relative; }
.photo-wrap { position:relative; aspect-ratio:5/7; border-radius:6px; overflow:hidden; background:#000; }

/* Blurred backdrop: absolutely positioned oversize copy of the same
   photo behind the foreground image, shown in the letterbox case.
   The negative inset + calc size grow the blurred copy past the tile
   edge so blur(20px) has clean pixels to sample from all the way to
   the rounded corners. */
.tile-bg { position:absolute; top:-10px; left:-10px; right:-10px; bottom:-10px; width:calc(100% + 20px); height:calc(100% + 20px); object-fit:cover; filter:blur(20px) brightness(0.9); z-index:0; display:block; }
.tile-fg-wrap { position:relative; z-index:1; height:100%; display:flex; align-items:center; justify-content:center; }
/* Default is letterbox (contain) — the safe assumption before JS has
   measured the photo's real aspect ratio, since contain can never
   crop content the visitor hasn't seen crop before. frontend.js adds
   .mb-fit-cover once naturalWidth/naturalHeight confirms this photo
   is narrower than 5:7, switching it to object-fit:cover to fill the
   box (see mbLoadImage() in frontend.js for the ratio check). */
.tile-fg { width:100%; height:100%; display:block; position:relative; z-index:1; object-fit:contain; }
.tile-fg.mb-fit-cover { object-fit:cover; }
/* Only the foreground gets the loading placeholder — the backdrop can
   stay transparent (tile background is #000) until it decodes. */
.tile-fg.mb-lazy-photo[data-mb-src] { min-height:180px; background:#eee; }

@media (min-width:521px) { .tile-fg-wrap { cursor:pointer; } }
/* Mobile: 1-column, native height, no crop/letterbox/backdrop. */
@media (max-width:520px) {
	.photo-wrap { aspect-ratio:auto; }
	.tile-fg-wrap { height:auto; }
	.tile-fg { height:auto; object-fit:initial; }
	.tile-bg { display:none; }
}

.board-item .item-actions { position:absolute; top:10px; right:10px; display:flex; gap:6px; z-index:2; }
.icon-btn { width:32px; height:32px; border-radius:50%; background:rgba(255,255,255,.9); display:flex; align-items:center; justify-content:center; cursor:pointer; border:none; color:#333; padding:0; }
.icon-btn.liked { color:#e0455f; }
/* Top-left slot: mutually exclusive — the uploader sees the × to remove
   their own photo (they don't need to be told they added it), everyone
   else sees the "Added by …" tag. */
.own-tag { position:absolute; top:10px; left:10px; background:rgba(17,17,17,.75); color:#fff; font-size:10px; letter-spacing:.08em; text-transform:uppercase; padding:4px 8px; border-radius:3px; z-index:2; }
.photo-tags { position:absolute; bottom:10px; left:10px; display:flex; flex-direction:column; gap:6px; align-items:flex-start; z-index:2; }
.admin-liked-tag { display:flex; align-items:center; gap:5px; background:rgba(17,17,17,.75); color:#fff; font-size:10.5px; padding:4px 9px; border-radius:3px; }
.admin-liked-tag svg { color:#e0455f; flex-shrink:0; }
.fav-tag { display:flex; align-items:center; gap:6px; background:rgba(255,255,255,.92); color:#333; font-size:12.5px; padding:5px 10px; border-radius:3px; }
.fav-tag svg { color:#e0455f; flex-shrink:0; }
/* Delete-X moves from bottom-right (now occupied by .count-pill) to
   top-left, displacing .own-tag — see photo-wrap above for the
   mutual-exclusion rule enforced in board-item.php. */
.delete-x { position:absolute; top:10px; left:10px; width:28px; height:28px; border-radius:50%; background:rgba(17,17,17,.75); color:#fff; border:none; font-size:14px; cursor:pointer; display:flex; align-items:center; justify-content:center; z-index:2; }

/* Count-pill in bottom-right opens the shared comments overlay. Empty
   thread reads "Add comment"; otherwise "N comment[s]". */
.count-pill { position:absolute; bottom:10px; right:10px; background:rgba(17,17,17,.75); color:#fff; font-size:11px; padding:4px 9px; border-radius:12px; cursor:pointer; border:none; z-index:2; font-family:inherit; }
.count-pill:hover { background:rgba(17,17,17,.9); }

/* Hidden per-photo thread data — the overlay grabs this element's
   innerHTML on open. Kept in the DOM (not a WP data attr) so the
   already-escaped .msg / .empty-note markup rendered by PHP flows
   straight into the overlay body untouched. */
.mb-thread-data { display:none; }

/* Shared comments overlay — one instance per page, populated on
   count-pill click. Reply-row styling matches the old inline
   .comment-thread .reply-row exactly (which is now gone) so the input
   feel is unchanged. */
/* z-index:100000 — see the matching note on .mb-lightbox below; same
   reasoning applies here (deliberately above WP core's #wpadminbar,
   z-index:99999). */
.mb-comments-overlay { display:none; position:fixed; inset:0; background:rgba(0,0,0,.55); align-items:center; justify-content:center; z-index:100000; padding:20px; }
.mb-comments-overlay.open { display:flex; }
.mb-comments-box { background:#fff; border-radius:8px; width:440px; max-width:100%; max-height:80vh; display:flex; flex-direction:column; padding:22px; }
.mb-comments-box h3 { margin:0 0 14px; font-size:15px; font-weight:600; }
.mb-comments-close { float:right; border:none; background:none; font-size:13px; cursor:pointer; color:#888; padding:0; font-family:inherit; }
.mb-comments-close:hover { color:#333; }
.mb-comments-body { overflow-y:auto; flex:1; min-height:60px; margin-bottom:4px; }
.mb-comments-body .msg { margin-bottom:12px; font-size:13.5px; }
.mb-comments-body .msg:last-child { margin-bottom:0; }
.mb-comments-body .who { font-weight:600; font-size:12px; }
.mb-comments-body .who.you { color:#2c3542; }
.mb-comments-body .when { font-weight:400; color:#666; margin-left:6px; font-size:11px; }
.mb-comments-body .text { margin-top:2px; color:#333; }
.mb-comments-body .empty-note { color:#666; font-size:12.5px; font-style:italic; margin:0; }
.mb-comments-overlay .reply-row { display:flex; gap:8px; margin-top:14px; }
.mb-comments-overlay .reply-row input { flex:1; border:1px solid rgba(17,17,17,.12); border-radius:20px; padding:7px 14px; font-size:13px; font-family:inherit; }
.mb-comments-overlay .reply-row button { border:none; background:#111; color:#fff; border-radius:20px; padding:7px 16px; font-size:12px; text-transform:uppercase; cursor:pointer; font-family:inherit; }

/* Desktop-only lightbox (0.24.6) — the grid thumbnails are small and,
   unlike mobile, there's no pinch-to-zoom, so clicking a photo opens a
   larger view of the SAME already-loaded 1000px preview image (see
   MB_Images::PREVIEW_PX in class-images.php) with the like button and
   full comment thread alongside it. Wrapped entirely in this min-width
   media query — belt-and-braces alongside the JS-side viewport check
   in frontend.js, so it structurally cannot render/open below the same
   520px "mobile" breakpoint the rest of the grid already treats as the
   line between the two. White background throughout, per spec, rather
   than the usual dark lightbox backdrop. */
/* 0.32.1: the lightbox HTML is always in the DOM (board-page.php) but
   ALL its styling lived inside the min-width:521px gate below, so on
   mobile (≤520px) the div was unstyled — not hidden — and its raw
   content (Close button, ‹/› arrows, comments sidebar) rendered as
   visible page artifacts below the grid. Base-level display:none
   ensures it's hidden everywhere; the 521px block overrides to
   display:none + .open display:block as before. */
.mb-lightbox { display:none; }

@media (min-width:521px) {
	/* z-index:100000 — deliberately above WP core's #wpadminbar, which
	   is always z-index:99999 (a long-stable WP core value, not
	   theme-specific). Without this the admin bar's opaque background
	   sat on top of the lightbox, cropping its top edge — visible only
	   to Owen viewing a live board while logged into wp-admin; a real
	   model never has that bar at all, which is why this only ever
	   showed up for him. */
	.mb-lightbox { display:none; position:fixed; inset:0; background:#fff; z-index:100000; }
	.mb-lightbox.open { display:block; }
	.mb-lightbox-close { position:absolute; top:20px; right:24px; border:none; background:none; font-size:13px; letter-spacing:.05em; text-transform:uppercase; color:#666; cursor:pointer; z-index:3; }
	.mb-lightbox-close:hover { color:#111; }
	.mb-lightbox-nav { position:absolute; top:50%; transform:translateY(-50%); width:44px; height:44px; border-radius:50%; border:1px solid rgba(17,17,17,.12); background:#fff; color:#333; font-size:22px; line-height:1; cursor:pointer; display:flex; align-items:center; justify-content:center; z-index:3; }
	.mb-lightbox-nav:hover { background:#f4f4f4; }
	.mb-lightbox-prev { left:24px; }
	.mb-lightbox-next { right:24px; }

	.mb-lightbox-stage { display:flex; height:100%; }
	.mb-lightbox-image-area { flex:1 1 auto; min-width:0; display:flex; align-items:center; justify-content:center; padding:60px 90px; }
	/* inline-flex so this box shrinks to the rendered image's own size
	   (object-fit:contain can otherwise leave letterbox space inside a
	   block-level wrap) — the corner badges below are positioned
	   against this box, so they need to hug the actual photo, not an
	   oversized container. min-width/min-height is a defensive floor:
	   without it, a genuinely failed image load collapses this box
	   toward zero, stranding the overlaid badges in a small disconnected
	   cluster with no visible photo around them. */
	.mb-lightbox-photo-wrap { position:relative; display:inline-flex; max-width:100%; max-height:100%; min-width:200px; min-height:200px; }
	.mb-lightbox-img { display:block; max-width:100%; max-height:calc(100vh - 120px); object-fit:contain; }

	/* Same corner placements as the grid tile (.own-tag/.delete-x
	   top-left, .photo-tags bottom-left, like button top-right) — see
	   frontend.js openLightbox() for how each slot gets populated from
	   the clicked .board-item's own already-rendered markup. */
	/* Not position:absolute itself — .own-tag and .delete-x (whichever
	   ends up inside) already self-position with top:10px;left:10px
	   against their nearest positioned ancestor. Since
	   .mb-lightbox-photo-wrap is that ancestor (position:relative), this
	   wrapper needs to stay a plain, non-positioned pass-through, or the
	   child's own offset would stack on top of this one's. */
	/* .mb-lightbox-top-left itself is intentionally unstyled — see comment above. */
	.mb-lightbox-tags { position:absolute; bottom:10px; left:10px; display:flex; flex-direction:column; gap:6px; align-items:flex-start; z-index:2; }
	.mb-lightbox-like-btn { position:absolute; top:10px; right:10px; z-index:2; }

	.mb-lightbox-sidebar { width:360px; flex:0 0 360px; border-left:1px solid rgba(17,17,17,.1); display:flex; flex-direction:column; padding:28px 24px; }
	.mb-lightbox-comments-title { margin:0 0 16px; font-size:15px; font-weight:600; }
	.mb-lightbox-comments-body { flex:1; overflow-y:auto; margin-bottom:4px; }
	.mb-lightbox-comments-body .msg { margin-bottom:12px; font-size:13.5px; }
	.mb-lightbox-comments-body .msg:last-child { margin-bottom:0; }
	.mb-lightbox-comments-body .who { font-weight:600; font-size:12px; }
	.mb-lightbox-comments-body .who.you { color:#2c3542; }
	.mb-lightbox-comments-body .when { font-weight:400; color:#666; margin-left:6px; font-size:11px; }
	.mb-lightbox-comments-body .text { margin-top:2px; color:#333; }
	.mb-lightbox-comments-body .empty-note { color:#666; font-size:12.5px; font-style:italic; margin:0; }
	.mb-lightbox .reply-row { display:flex; gap:8px; margin-top:14px; flex-shrink:0; }
	.mb-lightbox .reply-row input { flex:1; border:1px solid rgba(17,17,17,.12); border-radius:20px; padding:7px 14px; font-size:13px; font-family:inherit; min-width:0; }
	.mb-lightbox .reply-row button { border:none; background:#111; color:#fff; border-radius:20px; padding:7px 16px; font-size:12px; text-transform:uppercase; cursor:pointer; font-family:inherit; }
}

/* Upload widget matches the fixed 5:7 tile size (see .photo-wrap) so
   it sits consistently in the grid rather than at its own min-height. */
.upload-widget { aspect-ratio:5/7; border:2px dashed #b8bcc0; border-radius:6px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:6px; color:#666; background:rgba(255,255,255,.4); cursor:pointer; }
.upload-widget .plus { font-size:28px; font-weight:300; line-height:1; }
.upload-widget .cap { font-size:11.5px; color:#666; }
.upload-widget input[type="file"] { display:none; }
.upload-cap-note { grid-column:1/-1; color:#666; font-size:12.5px; text-align:center; padding:20px 0; }
@media (max-width:520px) { .upload-widget { aspect-ratio:auto; min-height:160px; } }

.mb-empty { text-align:center; color:#666; padding:60px 0; }

/* 0.29.0: unseen like/comment badges — board tabs + board-list cards
   only. Red = "something new" (icon differentiates like vs comment,
   matching the mockup convention rather than color-coding by type).
   Board-level granularity — these clear the instant the whole board
   page is opened, nothing more granular than that. */
/* 0.32.7: dots on tabs everywhere (not just mobile). The detailed
   per-board badge pills were replaced with a simple red dot on tabs —
   the activity icons row on the current board still shows full counts.
   Badges hidden, dot shown, both gated by .mb-has-unseen class. */
.mb-unseen-badges { display:none; gap:4px; margin-left:6px; vertical-align:middle; }
.board-nav-tab.mb-has-unseen .mb-unseen-badges { display:none; }
.mb-tab-dot { display:none; }
.board-nav-tab.mb-has-unseen .mb-tab-dot {
	display:inline-block; width:6px; height:6px; border-radius:50%;
	background:#d63638; margin-left:6px; vertical-align:middle;
}
.mb-unseen-badge {
	display:inline-flex; align-items:center; gap:3px; background:#d63638; color:#fff;
	font-size:10px; font-weight:600; border-radius:10px; padding:2px 6px; line-height:1;
}
.mb-unseen-badge svg { display:block; }
.board-nav-tab .mb-unseen-badges { margin-left:6px; }
.mb-tab-dot { display:none; }
.boardlist-card { position:relative; }
.mb-unseen-badges-corner { position:absolute; top:10px; right:10px; margin:0; gap:5px; }
.mb-unseen-badges-corner .mb-unseen-badge { font-size:11px; padding:3px 8px; box-shadow:0 1px 4px rgba(0,0,0,.2); }

/* 0.31.0: activity icon row (nav strip) + feed panel. Icons live inside
   a single <button class="mb-activity-icons"> so the whole cluster is
   ONE click target — clicking any icon opens the same panel, per the
   design (they don't operate independently). Muted grey when nothing's
   unseen; individual icons switch to red-active only for the category
   with something new. */
.board-nav-actions { display:flex; gap:16px; align-items:center; }
.mb-activity-icons {
	display:flex; gap:12px; align-items:center; background:none; border:none; padding:0;
	cursor:pointer; color:#999;
}
.mb-activity-icons:hover { color:#111; }
.mb-activity-icon { display:inline-flex; align-items:center; gap:3px; font-size:12px; }
.mb-activity-icon.active { color:#d63638; font-weight:600; }
.mb-activity-icon .mb-activity-count { font-size:11px; }
.mb-activity-icon svg { display:block; }

.mb-activity-panel {
	position:fixed; right:24px; top:80px; width:380px; max-height:70vh;
	background:#fff; border-radius:10px; box-shadow:0 8px 32px rgba(0,0,0,.15);
	z-index:9600; display:flex; flex-direction:column; overflow:hidden;
}
.mb-activity-panel-inner { display:flex; flex-direction:column; min-height:0; flex:1; }
.mb-activity-panel-head { display:flex; justify-content:space-between; align-items:center; padding:14px 18px; border-bottom:1px solid #eee; flex-shrink:0; }
.mb-activity-panel-title { font-weight:500; font-size:14px; }
.mb-activity-panel-close { background:none; border:none; font-size:22px; cursor:pointer; color:#666; padding:0; line-height:1; }
.mb-activity-panel-body { flex:1; overflow-y:auto; min-height:0; }
.mb-activity-empty { padding:24px; color:#666; text-align:center; font-size:13px; margin:0; }
.mb-activity-row {
	display:flex; gap:12px; align-items:center; padding:12px 18px;
	border-bottom:1px solid #f0f0f0; cursor:pointer; text-decoration:none; color:inherit;
}
.mb-activity-row:hover { background:#fafafa; }
.mb-activity-row.unseen { background:#fdeaea; }
.mb-activity-row.unseen:hover { background:#fbdcdc; }
.mb-activity-row-icon {
	width:32px; height:32px; border-radius:50%; background:#f5f5f5;
	display:flex; align-items:center; justify-content:center; flex-shrink:0; color:#666;
}
.mb-activity-row.unseen .mb-activity-row-icon { background:#fff; color:#d63638; }
.mb-activity-row-body { flex:1; min-width:0; }
.mb-activity-row-body p { margin:0; font-size:13px; }
.mb-activity-row-body .mb-activity-row-body-excerpt { color:#666; }
.mb-activity-row-time { font-size:11px; color:#999; margin-top:2px !important; }
.mb-activity-row-thumb { width:36px; height:36px; border-radius:5px; background-size:cover; background-position:center; flex-shrink:0; background-color:#eee; }

/* Handle drawer, hidden by default (only visible on mobile). */
.mb-activity-panel-handle { display:none; }

/* Mobile: bottom sheet, not a floating panel. The mobile boundary
   uses the same 521px threshold the .mb-lightbox stylesheet gates
   itself on, so "no lightbox mode" and "bottom-sheet activity feed"
   agree — see lbIsDesktop() in frontend.js. Previously (0.31.0/0.31.1)
   used 600px which drifted from that. */
@media (max-width:520px) {
	.mb-activity-panel {
		right:0; left:0; top:auto; bottom:0; width:auto; height:60vh;
		min-height:180px; max-height:92vh;
		border-radius:16px 16px 0 0;
		padding-bottom:env(safe-area-inset-bottom); /* iOS home bar */
	}
	/* 0.32.0: touch-action was 'none' on the whole panel, which meant
	   the OS blocked native scroll gestures anywhere inside — including
	   the feed list, which needs to scroll. Scope 'none' to the handle
	   only (drag-to-resize captures the touch); everywhere else uses
	   the default so pan-y scrolling the list works. */
	/* 0.32.2: the drag handle's visible bar is deliberately small
	   (44×5px) for aesthetics, but the TOUCH TARGET needs to be much
	   bigger or it's nearly impossible to grab on a phone. The handle
	   div itself is enlarged to a generous tap area with padding, and
	   the visible bar is drawn via ::after so it stays visually small.
	   touch-action:none stays on the handle only (not the whole sheet)
	   — that was the 0.32.0 CSS fix for feed-list scrolling. */
	.mb-activity-panel-handle {
		display:block; width:100%; height:32px;
		cursor:ns-resize; touch-action:none;
		background:transparent; margin:0; border-radius:0;
		position:relative;
	}
	.mb-activity-panel-handle::after {
		content:''; position:absolute;
		top:50%; left:50%; transform:translate(-50%,-50%);
		width:44px; height:5px; border-radius:3px; background:#ccc;
	}
	.mb-activity-panel-head { padding-top:4px; }
	/* 0.32.1: mobile nav redesign — stacked two-row layout instead of
	   cramming tabs + actions onto one wrapped line. Row 1 is the board
	   tabs (horizontal-scroll so long names like BEACH PHOTOSHOOT don't
	   truncate), row 2 is the actions centered with thin dividers
	   between download / activity icons / log-out. */
	.board-nav {
		flex-direction:column; align-items:stretch; gap:0;
		padding:0; border-bottom:1px solid #ececec;
	}
	.board-nav-tabs {
		overflow-x:auto; -webkit-overflow-scrolling:touch;
		flex-wrap:nowrap; gap:20px; padding:12px 16px 0;
		scrollbar-width:none;
	}
	.board-nav-tabs::-webkit-scrollbar { display:none; }
	.board-nav-tab { white-space:nowrap; flex-shrink:0; font-size:11px; padding-bottom:10px; }
	/* 0.32.7: dot styles are now global (see above), so the mobile block
	   only needs to hide badges (already hidden globally too, but kept
	   for specificity safety). */
	.board-nav-tab.mb-has-unseen .mb-unseen-badges { display:none; }
	.board-nav-actions {
		justify-content:center; gap:16px; padding:8px 16px;
		border-top:1px solid #f0f0f0;
	}
	.board-nav-download-label { display:none; }
	.board-nav-download-icon { font-size:16px; }
	.board-nav-download { color:#666; }
	.board-nav-logout { font-size:12px; padding-left:0; border-left:none; }
	.board-nav-divider { display:inline-block; width:1px; height:18px; background:#ddd; flex-shrink:0; }
	.mb-activity-icons { gap:12px; }
	.mb-activity-icon svg { width:16px; height:16px; }

	/* Slide-up entrance so the sheet doesn't just appear. Matches
	   iOS/Android's standard sheet motion. */
	.mb-activity-panel { animation: mbSheetIn .22s ease-out; }
	@keyframes mbSheetIn { from { transform: translateY(100%); } to { transform: translateY(0); } }
}

/* 0.32.0: same flash-highlight used by the admin side for cases where
   a lightbox doesn't apply — used here for feed-row clicks on mobile
   1-column mode (below 521px the lightbox isn't rendered; see the
   comment near window.mbOpenLightboxByImageId in frontend.js). */
/* 0.32.3: scroll-margin-top gives scrollIntoView({ block:'start' })
   breathing room so the target photo isn't jammed against the very
   top of the viewport (or hidden behind any fixed headers). Only
   needed on mobile where feed-row clicks use scrollIntoView; on
   desktop the lightbox opens instead. */
@media (max-width:520px) { .board-item { scroll-margin-top:12px; } }

.board-item.mb-flash-highlight {
	box-shadow:0 0 0 3px #d63638;
	transition:box-shadow .3s;
}
