/* ============================================================================
   Site-specific layout on top of the KateMade design system (design-system.css).
   Only page structure and a few components the DS does not ship live here;
   everything else uses the --km-* tokens and .km-* classes.
   ========================================================================== */

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

.skip-link {
    position: absolute; left: 16px; top: -56px; z-index: 100;
    background: var(--km-champagne); color: var(--km-ink-900);
    padding: 10px 16px; border-radius: 0 0 var(--km-r-md) var(--km-r-md);
    text-decoration: none; transition: top var(--km-ease);
}
.skip-link:focus { top: 0; }

/* --- sticky translucent bar wrapping the DS header --- */
.site-topbar {
    position: sticky; top: 0; z-index: 50;
    background: rgba(20, 17, 14, 0.72);
    backdrop-filter: saturate(140%) blur(10px);
    border-bottom: 1px solid var(--km-ink-600);
}
.site-topbar .km-header { border-bottom: 0; }
.km-nav .km-btn { text-transform: none; letter-spacing: .02em; }

/* --- hero --- */
.hero { padding-block: var(--km-space-8); }
.hero-inner {
    display: grid; grid-template-columns: 1.05fr .95fr;
    gap: var(--km-space-7); align-items: center;
}
.hero-media img {
    width: 100%; height: auto;
    border-radius: var(--km-r-xl);
    box-shadow: var(--km-shadow-lg);
}

/* --- section heading block --- */
.section-head { max-width: 62ch; margin-bottom: var(--km-space-6); }

/* --- gallery: fixed-size DS cards riding the DS carousel --- */
.gallery-card {
    width: 300px;
    height: 520px;
    display: flex;
    flex-direction: column;
}
.gallery-thumb {
    display: block; width: 100%; height: 375px; flex: none;
    padding: 0; border: 0; cursor: zoom-in;
    overflow: hidden;
    /* background-color, not the shorthand: while the photo loads this element also
       carries .km-skeleton, and the shorthand would reset its gradient to none. */
    background-color: var(--km-ink-800);
}
/* Fade the photo in over the shimmer, the same swap the large preview does.
   Applies to every frame marked data-skeleton, not just the cards. */
[data-skeleton] img { transition: opacity 240ms ease; }
/* transition: none on the way in, so a photo that had already started painting is
   hidden at once rather than fading out first and then back in. Only the arrival
   is animated. */
[data-skeleton].km-skeleton img { opacity: 0; transition: none; }
/* The placeholder has to match the shape it stands in for, or the swap pops: the
   hero and the portrait are --km-r-xl with a shadow, while .km-skeleton defaults to
   --km-r-lg and none. */
.hero-media.km-skeleton, .about-media.km-skeleton {
    border-radius: var(--km-r-xl);
    box-shadow: var(--km-shadow-lg);
}
/* The card already clips its own top corners, and the thumb's bottom corners sit
   against the card body, so a radius here would show as two notches. */
.gallery-thumb.km-skeleton { border-radius: 0; }
.gallery-thumb picture { display: block; width: 100%; height: 100%; }
.gallery-thumb img {
    width: 100%; height: 100%; object-fit: contain;
    transition: transform var(--km-ease);
}
.km-card--interactive:hover .gallery-thumb img { transform: scale(1.04); }
/* Body takes the leftover strip so the tag can sit on the bottom edge. */
.gallery-card .km-card__body { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.gallery-card .km-card__title {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden;
}
.gallery-card .km-card__meta { margin-top: auto; }
/* The hover lift would clip against the rail's edges, so give the track room. */
.gallery-carousel .km-carousel__track { padding-block: var(--km-space-3); }

/* --- about --- */
.about-inner {
    display: grid; grid-template-columns: .9fr 1.1fr;
    gap: var(--km-space-7); align-items: center;
}
.about-media img { width: 100%; height: auto; border-radius: var(--km-r-xl); box-shadow: var(--km-shadow-lg); }
.about-copy p { color: var(--km-muted); }
.about-copy p:last-child { margin-bottom: 0; }

/* --- contact --- */
.contact .km-container { max-width: 720px; text-align: center; }
.contact-actions { display: flex; gap: var(--km-space-3); justify-content: center; flex-wrap: wrap; margin-top: var(--km-space-5); }
.contact .handle { margin-top: var(--km-space-4); }
.contact .handle a { color: var(--km-faint); letter-spacing: .06em; text-decoration: none; }
.contact .handle a:hover { color: var(--km-champagne); }

/* --- lightbox (built by site.js) --- */
.lightbox {
    position: fixed; inset: 0; z-index: 100; border: 0; padding: 0; margin: 0;
    width: 100%; height: 100%; max-width: 100%; max-height: 100%;
    background: rgba(10, 8, 6, 0.94); align-items: center; justify-content: center;
}
.lightbox[open] { display: flex; }
.lightbox::backdrop { background: rgba(10, 8, 6, 0.94); }
/* Sizing lives on .lightbox-frame now; this only dresses the photo. */
.lightbox img { border-radius: var(--km-r-lg); box-shadow: var(--km-shadow-lg); }
.lightbox-figure { margin: 0; text-align: center; }
/* Skeleton and photo occupy the same cell, so the swap cannot shift the caption.
   The skeleton is sized by site.js from the thumbnail's own width and height
   attributes, which is why the frame never resizes when the photo lands. */
.lightbox-frame { position: relative; max-width: 92vw; max-height: 82vh; }
/* Absolutely positioned so both boxes resolve straight against the frame, which
   removes the reopen window where the skeleton could still take the previous
   photo's ratio. The explicit 100% is not redundant: inset alone leaves a
   replaced element (the img) at its intrinsic size and ignores the insets. */
.lightbox-frame > * { position: absolute; inset: 0; width: 100%; height: 100%; }
.lightbox-frame img { object-fit: contain; opacity: 0; transition: opacity 240ms ease; }
.lightbox.is-loaded .lightbox-frame img { opacity: 1; }
.lightbox.is-loaded .lightbox-skeleton { display: none; }
.lightbox-cap { color: var(--km-champagne); margin-top: var(--km-space-3); font-family: var(--km-font-display); font-style: italic; }
.lightbox-close {
    position: absolute; top: 16px; right: 16px; width: 48px; height: 48px; border-radius: 50%;
    border: 1px solid var(--km-ink-600); background: rgba(244, 237, 223, 0.08);
    color: var(--km-champagne); font-size: 1.6rem; cursor: pointer;
}
.lightbox-close:hover { background: rgba(244, 237, 223, 0.18); }

/* --- footer bits (DS .km-footer is centered) --- */
.footer-logo { display: inline-block; }
.footer-wordmark { font-family: var(--km-font-display); font-size: var(--km-fs-lg); color: var(--km-champagne); margin: var(--km-space-3) 0 0; }
.footer-tagline { margin: var(--km-space-2) 0 0; }
.footer-links { margin: var(--km-space-3) 0 0; }
.footer-meta { margin: var(--km-space-4) 0 0; font-size: var(--km-fs-xs); }

/* --- error page --- */
.error-page { text-align: center; padding-block: var(--km-space-9); }

@media (max-width: 860px) {
    .hero-inner, .about-inner { grid-template-columns: 1fr; }
    .hero-media { order: -1; max-width: 460px; }
    .about-media { max-width: 420px; }
}

@media (max-width: 560px) {
    /* The sections drop to 48px on a phone but the hero kept its desktop 64px, so
       it read as loose next to everything below it. */
    .hero { padding-block: var(--km-space-6); }
    /* .hero-actions is a plain block, so once the two buttons no longer fit on one
       line they stack at their own text widths, with no gap and edges that do not
       line up. Stack them deliberately instead. */
    .hero-actions { display: grid; gap: var(--km-space-3); }
    .hero-actions .km-btn { width: 100%; justify-content: center; }
    .contact-actions .km-btn { width: 100%; }
}
