// Layout shell shared by the public gallery page (GalleryClient) and its
// loading placeholder (GallerySkeleton). Column count, gaps, radii and
// container padding are defined once here, so the skeleton's geometry can
// never drift from the grid it stands in for.

export function GalleryHeroFrame({
  children,
  backdrop,
}: {
  children: React.ReactNode;
  /** Cover image + scrim, absolutely positioned behind the text. */
  backdrop?: React.ReactNode;
}) {
  return (
    <div className="relative bg-brand-navy overflow-hidden">
      {backdrop}
      <div className="relative container-page px-4 pt-20 pb-8 md:pt-32 md:pb-12">{children}</div>
    </div>
  );
}

export function GalleryContainer({ children }: { children: React.ReactNode }) {
  return <div className="container-page px-2 sm:px-4 py-4 md:py-8">{children}</div>;
}

export function MasonryGrid({ children }: { children: React.ReactNode }) {
  return (
    <div className="columns-2 sm:columns-3 lg:columns-4 gap-2 md:gap-3 [column-fill:_balance]">
      {children}
    </div>
  );
}

// Per-tile geometry. Deliberately carries no background so callers can pick
// one (photo tiles: bg-gray-100, skeleton tiles: the skeleton surface) without
// two `bg-*` utilities fighting over CSS order.
export const masonryTileClass = 'mb-2 md:mb-3 break-inside-avoid overflow-hidden rounded-xl';

/**
 * Reserves the tile's aspect ratio up front so the image can load into a box
 * that is already the right size — late arrivals never reflow the columns.
 * Returns undefined when the photo has no stored dimensions.
 */
export function aspectStyle(width?: number, height?: number): React.CSSProperties | undefined {
  return width && height ? { aspectRatio: `${width} / ${height}` } : undefined;
}
