/* ============================================================
 * TES Event Page — Basel-style two-column hero.
 *
 * Modelled on baselarea.swiss/events/*. Structure:
 *
 *   1. Full-bleed dark hero band:
 *        left:  breadcrumb / title / inline icon meta / dual CTA
 *        right: image inside a white "polaroid" card
 *   2. Body content section below on the theme's natural background.
 *
 * Theme integration: the body section uses `color: inherit` and
 * `background: transparent`, so it picks up the active theme's
 * page surface (whatever background the active theme uses). The
 * dark hero is the only piece that asserts its own surface — it
 * also breaks out of the theme's container to span 100vw.
 *
 * Scoped under .tes-event so nothing leaks.
 * ========================================================= */

.tes-event {
    /* —— Color tokens —— */
    --tes-accent-soft: color-mix(in srgb, var(--tes-accent), white 36%);
    --tes-hero-bg: #0e0e12;
    --tes-hero-ink: #f5f5f7;
    --tes-hero-ink-soft: rgba(245, 245, 247, 0.70);
    --tes-hero-ink-faint: rgba(245, 245, 247, 0.42);
    --tes-image-frame: #ffffff;
    --tes-image-radius: 16px;

    /* —— Type stack —— */
    --tes-font: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', 'Segoe UI Variable', 'Segoe UI', system-ui, sans-serif;

    /* —— Spacing —— */
    --tes-s-1: 8px;
    --tes-s-2: 16px;
    --tes-s-3: 24px;
    --tes-s-4: 40px;
    --tes-s-5: 64px;
    --tes-s-6: 96px;

    /* —— Motion —— */
    --tes-ease: cubic-bezier(0.2, 0, 0.2, 1);

    box-sizing: border-box;
    color: inherit;
    font-family: var(--tes-font);
    font-size: 17px;
    line-height: 1.5;
    letter-spacing: -0.003em;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}
.tes-event *,
.tes-event *::before,
.tes-event *::after { box-sizing: inherit; }

/* Wrapper our template emits between get_header() / get_footer().
 * Transparent so the theme's page background shows above + below
 * the dark hero band. */
.tes-event-main {
    display: block;
    background: transparent;
    padding: 0;
    margin: 0;
}

/* =============================================================
 * Hero band — full-bleed dark
 * =============================================================
 * `width: 100vw; left: 50%; right: 50%; margin-left: -50vw`
 * is the canonical "break out of constrained parent" trick. The
 * inner wrapper restores a centered max-width for the grid. */
.tes-event-hero {
    position: relative;
    /* z-index promotes the entire hero (and its positioned descendants
     * like the Add-to-calendar popover) above subsequent siblings —
     * specifically .tes-event-body-section, which otherwise paints on
     * top because it comes later in document order. Without this, an
     * open popover that drops below the hero gets covered by the body. */
    z-index: 1;
    width: 100vw;
    left: 50%;
    right: 50%;
    margin-left: -50vw;
    margin-right: -50vw;
    background: var(--tes-hero-bg);
    color: var(--tes-hero-ink);
    padding: clamp(48px, 7vw, 96px) clamp(20px, 4vw, 48px);
    /* No overflow:hidden — that previously clipped the Add-to-calendar
     * popover at the hero's bottom edge, hiding the lower options
     * (Apple Calendar / .ics file disappeared off the bottom). */
}

.tes-event-hero-inner {
    max-width: 1180px;
    margin: 0 auto;
}

.tes-event-hero-grid {
    display: grid;
    grid-template-columns: 1.05fr 1fr;
    gap: clamp(40px, 6vw, 72px);
    align-items: center;
}

.tes-event-hero-col--content {
    display: flex;
    flex-direction: column;
    gap: var(--tes-s-3);
    animation: tes-fade-up 800ms var(--tes-ease) both;
}

/* —— Breadcrumbs —— */
.tes-event-breadcrumbs {
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.10em;
    text-transform: uppercase;
    color: var(--tes-hero-ink-soft);
}
.tes-event-breadcrumbs a {
    color: inherit;
    text-decoration: none;
    transition: color 160ms var(--tes-ease);
}
.tes-event-breadcrumbs a:hover { color: var(--tes-hero-ink); }
.tes-event-breadcrumb-sep {
    margin: 0 10px;
    color: var(--tes-hero-ink-faint);
}

/* —— Title —— */
.tes-event-title {
    margin: 0;
    max-width: 14ch;
    font-family: var(--tes-font);
    font-size: clamp(36px, 5.4vw, 58px);
    font-weight: 600;
    line-height: 1.05;
    letter-spacing: -0.025em;
    color: var(--tes-hero-ink);
    text-wrap: balance;
}

/* —— Icon meta list —— Basel-style wrapping: date + time inline on
 * the top row, location forced onto its own full-width row below
 * (since locations are usually long enough that wrapping mid-flex
 * looks like an accident rather than a layout choice). */
.tes-event-hero-meta {
    list-style: none;
    margin: var(--tes-s-1) 0 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 14px 32px;
}
.tes-event-hero-meta-item {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    font-size: 16px;
    font-weight: 500;
    letter-spacing: -0.008em;
    color: var(--tes-hero-ink);
    margin: 0;
    padding: 0;
}
.tes-event-hero-meta-item--location {
    flex-basis: 100%;       /* push to its own row */
    margin-top: 2px;
}
.tes-event-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    flex-shrink: 0;
    color: color-mix(in srgb, var(--tes-accent), white 55%);
}
.tes-event-icon svg { width: 19px; height: 19px; display: block; stroke-width: 1.8; }
.tes-event-icon-label { line-height: 1.3; }

/* —— CTA — bubble merge via SVG goo filter ——
 *
 * Two-layer structure: a FILTERED blob layer underneath the
 * unfiltered content layer.
 *
 *   .tes-event-cta-blobs — absolute, two accent-colored circular
 *                          shapes laid out with flex+gap and the
 *                          `url(#tes-cta-goo)` filter on top. The
 *                          filter is a Gaussian blur + threshold
 *                          color matrix — when two shapes' blur
 *                          halos overlap, the threshold rebuilds
 *                          sharp edges INCLUDING the overlap, so
 *                          they appear merged with a smooth liquid
 *                          bridge.
 *   .tes-event-cta-label  — text on top of the blobs, NOT filtered
 *   .tes-event-cta-icon   — arrow on top of the blobs, NOT filtered
 *
 * Synchronized animation keeps the layout invariant (circle never
 * moves) AND drives the bubble merge:
 *
 *   container gap      10 → 0  (drives the merge — blobs close)
 *   blobs layer gap    10 → 0  (must match parent's gap)
 *   label padding-r    32 → 42 (label grows so total width stays
 *                                constant — circle keeps its spot)
 *
 * The label's growth + the gap's collapse cancel each other, so
 * .cta-btn's total width never changes. The blob behind the label
 * uses `flex: 1 0 auto` so its width tracks the label's at every
 * frame. The merge effect comes entirely from the goo filter
 * reading the closing gap. */
.tes-event-cta-row { margin-top: var(--tes-s-2); }

.tes-event-cta-btn {
    display: inline-flex;
    align-items: stretch;
    position: relative;
    gap: 10px;
    text-decoration: none;
    color: #fff;
    font-family: var(--tes-font);
    transition: gap 420ms cubic-bezier(0.4, 0, 0.2, 1);
}
.tes-event-cta-btn:hover,
.tes-event-cta-btn:focus-visible {
    gap: 0;
    color: #fff;
    text-decoration: none;
    outline: none;
}

/* Filtered blob layer. Mirrors the content layer's flex setup so
 * blob widths track label/icon widths at every transition frame. */
.tes-event-cta-blobs {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: stretch;
    gap: 10px;
    pointer-events: none;
    filter: url(#tes-cta-goo);
    transition: gap 420ms cubic-bezier(0.4, 0, 0.2, 1);
}
.tes-event-cta-btn:hover .tes-event-cta-blobs,
.tes-event-cta-btn:focus-visible .tes-event-cta-blobs {
    gap: 0;
}
.tes-event-cta-blob {
    background: var(--tes-accent);
    border-radius: 999px;
    transition: filter 200ms var(--tes-ease);
}
.tes-event-cta-blob--label { flex: 1 0 auto; }
.tes-event-cta-blob--icon  { flex: 0 0 52px; }
.tes-event-cta-btn:hover .tes-event-cta-blob,
.tes-event-cta-btn:focus-visible .tes-event-cta-blob {
    filter: brightness(1.08);
}

/* Unfiltered content layer — text + arrow stay crisp. The label
 * grows its right padding to cancel the parent's gap collapse so
 * .cta-btn width stays invariant. */
.tes-event-cta-label {
    position: relative;
    display: inline-flex;
    align-items: center;
    height: 52px;
    padding: 0 32px;
    color: #fff;
    font-size: 15px;
    font-weight: 500;
    letter-spacing: -0.005em;
    line-height: 1.2;
    transition: padding-right 420ms cubic-bezier(0.4, 0, 0.2, 1);
}
.tes-event-cta-btn:hover .tes-event-cta-label,
.tes-event-cta-btn:focus-visible .tes-event-cta-label {
    padding-right: 42px;
}

.tes-event-cta-icon {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    flex-shrink: 0;
    color: #fff;
}
.tes-event-cta-icon svg {
    width: 14px;
    height: 14px;
    display: block;
    transition: transform 360ms var(--tes-ease);
}
.tes-event-cta-btn:hover .tes-event-cta-icon svg,
.tes-event-cta-btn:focus-visible .tes-event-cta-icon svg {
    transform: rotate(45deg);
}

.tes-event-cta-btn:active .tes-event-cta-blob {
    filter: brightness(1.04);
    transition-duration: 80ms;
}
/* Focus ring uses outline rather than box-shadow so it stays
 * outside the goo filter's compositing region. */
.tes-event-cta-btn:focus-visible {
    outline: 3px solid color-mix(in srgb, var(--tes-accent), white 70%);
    outline-offset: 3px;
    border-radius: 999px;
}

/* —— Add-to-calendar widget — native <details> dropdown ——
 *
 * Sits below the Register CTA in the hero column. Closed state is a
 * subtle icon + label row; open state pops a small white card with
 * Google / Outlook / .ics options. No JS — <details>/<summary>
 * handles the toggle. */
.tes-event-cal-add {
    margin-top: var(--tes-s-3);
    font-size: 13px;
    font-weight: 500;
    line-height: 1.2;
    display: inline-block;
    position: relative;
    color: var(--tes-hero-ink-soft);
}
.tes-event-cal-add summary {
    list-style: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 6px 0;
    color: var(--tes-hero-ink-soft);
    border-bottom: 1px solid transparent;
    transition: color 160ms var(--tes-ease), border-color 160ms var(--tes-ease);
}
.tes-event-cal-add summary::-webkit-details-marker { display: none; }
.tes-event-cal-add summary::marker { content: ''; }
.tes-event-cal-add summary:hover { color: var(--tes-hero-ink); border-bottom-color: rgba(255, 255, 255, 0.25); }
.tes-event-cal-add[open] summary { color: var(--tes-hero-ink); border-bottom-color: rgba(255, 255, 255, 0.30); }
.tes-event-cal-add-icon {
    display: inline-flex;
    width: 16px;
    height: 16px;
    color: color-mix(in srgb, var(--tes-accent), white 55%);
}
.tes-event-cal-add-icon svg { width: 16px; height: 16px; display: block; }
.tes-event-cal-add-menu {
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    /* Belt-and-suspenders: high z-index in case the hero's stacking
     * context is competing with sticky/fixed theme chrome below. */
    z-index: 100;
    min-width: 220px;
    padding: 6px;
    background: #fff;
    border-radius: 12px;
    box-shadow: 0 20px 50px -20px rgba(0, 0, 0, 0.55),
                0 4px 12px -4px rgba(0, 0, 0, 0.35);
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.tes-event-cal-add-menu a {
    display: block;
    padding: 9px 12px;
    border-radius: 8px;
    color: #1d1d1f;
    text-decoration: none;
    font-size: 14px;
    font-weight: 500;
    transition: background 140ms var(--tes-ease), color 140ms var(--tes-ease);
}
.tes-event-cal-add-menu a:hover { background: rgba(0, 0, 0, 0.05); color: var(--tes-accent); }

/* —— Add-to-calendar popover animations ——
 * Entry + exit are configured independently from Settings →
 * Event Page. EventPageRenderer stamps four data-* attrs on the
 * .tes-event root:
 *   data-cal-anim-in        — entry style (none|fade|slide-{down,up,left,right}|scale)
 *   data-cal-anim-out       — exit style  (same options)
 *   data-cal-anim-speed-in  — entry speed (fast|normal|slow)
 *   data-cal-anim-speed-out — exit speed  (fast|normal|slow)
 * and one CSS custom property:
 *   --tes-cal-scale-from    — starting scale for the "scale" option
 *                             (e.g. 0.92 = 92%; admin picks as a
 *                             whole-number percentage).
 *
 * EventPageRenderer's inline JS toggles .is-closing on the
 * <details> to drive the exit keyframe before stripping [open],
 * so the user actually sees the exit animation play.
 *
 * `none` deliberately defines no @keyframes for that side —
 * <details>'s native instant open/close stays in effect for
 * the entry, and the JS skips the animated-close path entirely
 * for the exit.
 *
 * Slide direction = direction of motion. e.g. "slide-down" on
 * entry drops in from above (Y: -8 → 0); on exit it drops out
 * the bottom (Y: 0 → 8). Mix and match in/out for effects like
 * "scale-in + slide-up-out".
 *
 * prefers-reduced-motion is honored two ways: the JS short-
 * circuits to a hard close, and the @media rule at the bottom
 * nukes all keyframes in case any are still trying to play
 * (e.g. opening, which never goes through the JS path). */
.tes-event {
    --tes-cal-anim-dur-in: 240ms;
    --tes-cal-anim-dur-out: 240ms;
    /* Fallback for the scale keyframe. Real value rides on the
     * .tes-event inline style from the admin's percentage choice. */
    --tes-cal-scale-from: 0.92;
}
.tes-event[data-cal-anim-speed-in="fast"]    { --tes-cal-anim-dur-in: 160ms; }
.tes-event[data-cal-anim-speed-in="normal"]  { --tes-cal-anim-dur-in: 240ms; }
.tes-event[data-cal-anim-speed-in="slow"]    { --tes-cal-anim-dur-in: 400ms; }
.tes-event[data-cal-anim-speed-out="fast"]   { --tes-cal-anim-dur-out: 160ms; }
.tes-event[data-cal-anim-speed-out="normal"] { --tes-cal-anim-dur-out: 240ms; }
.tes-event[data-cal-anim-speed-out="slow"]   { --tes-cal-anim-dur-out: 400ms; }

/* Entry rules use :not(.is-closing) so the entry + exit selectors
 * are mutually exclusive — no specificity duel, no risk of the
 * browser keeping the entry animation while we ask for the exit. */

/* ---- Entry animations ---- */
.tes-event[data-cal-anim-in="fade"] .tes-event-cal-add[open]:not(.is-closing) .tes-event-cal-add-menu {
    animation: tes-cal-fade-in var(--tes-cal-anim-dur-in) var(--tes-ease) both;
}
.tes-event[data-cal-anim-in="slide-down"] .tes-event-cal-add[open]:not(.is-closing) .tes-event-cal-add-menu {
    animation: tes-cal-slide-down-in var(--tes-cal-anim-dur-in) var(--tes-ease) both;
}
.tes-event[data-cal-anim-in="slide-up"] .tes-event-cal-add[open]:not(.is-closing) .tes-event-cal-add-menu {
    animation: tes-cal-slide-up-in var(--tes-cal-anim-dur-in) var(--tes-ease) both;
}
.tes-event[data-cal-anim-in="slide-left"] .tes-event-cal-add[open]:not(.is-closing) .tes-event-cal-add-menu {
    animation: tes-cal-slide-left-in var(--tes-cal-anim-dur-in) var(--tes-ease) both;
}
.tes-event[data-cal-anim-in="slide-right"] .tes-event-cal-add[open]:not(.is-closing) .tes-event-cal-add-menu {
    animation: tes-cal-slide-right-in var(--tes-cal-anim-dur-in) var(--tes-ease) both;
}
.tes-event[data-cal-anim-in="scale"] .tes-event-cal-add[open]:not(.is-closing) .tes-event-cal-add-menu {
    transform-origin: top left;
    animation: tes-cal-scale-in var(--tes-cal-anim-dur-in) var(--tes-ease) both;
}

/* ---- Exit animations ---- */
.tes-event[data-cal-anim-out="fade"] .tes-event-cal-add.is-closing .tes-event-cal-add-menu {
    animation: tes-cal-fade-out var(--tes-cal-anim-dur-out) var(--tes-ease) both;
}
.tes-event[data-cal-anim-out="slide-down"] .tes-event-cal-add.is-closing .tes-event-cal-add-menu {
    animation: tes-cal-slide-down-out var(--tes-cal-anim-dur-out) var(--tes-ease) both;
}
.tes-event[data-cal-anim-out="slide-up"] .tes-event-cal-add.is-closing .tes-event-cal-add-menu {
    animation: tes-cal-slide-up-out var(--tes-cal-anim-dur-out) var(--tes-ease) both;
}
.tes-event[data-cal-anim-out="slide-left"] .tes-event-cal-add.is-closing .tes-event-cal-add-menu {
    animation: tes-cal-slide-left-out var(--tes-cal-anim-dur-out) var(--tes-ease) both;
}
.tes-event[data-cal-anim-out="slide-right"] .tes-event-cal-add.is-closing .tes-event-cal-add-menu {
    animation: tes-cal-slide-right-out var(--tes-cal-anim-dur-out) var(--tes-ease) both;
}
.tes-event[data-cal-anim-out="scale"] .tes-event-cal-add.is-closing .tes-event-cal-add-menu {
    transform-origin: top left;
    animation: tes-cal-scale-out var(--tes-cal-anim-dur-out) var(--tes-ease) both;
}

/* Travel distance baked into keyframes (8 px). Small constant —
 * the popover sits right under the summary, so a long slide
 * would overshoot the summary and look weird. */
@keyframes tes-cal-fade-in         { from { opacity: 0;                                  } to { opacity: 1;                                  } }
@keyframes tes-cal-fade-out        { from { opacity: 1;                                  } to { opacity: 0;                                  } }
@keyframes tes-cal-slide-down-in   { from { opacity: 0; transform: translateY(-8px);     } to { opacity: 1; transform: translateY(0);         } }
@keyframes tes-cal-slide-down-out  { from { opacity: 1; transform: translateY(0);        } to { opacity: 0; transform: translateY(8px);       } }
@keyframes tes-cal-slide-up-in     { from { opacity: 0; transform: translateY(8px);      } to { opacity: 1; transform: translateY(0);         } }
@keyframes tes-cal-slide-up-out    { from { opacity: 1; transform: translateY(0);        } to { opacity: 0; transform: translateY(-8px);      } }
@keyframes tes-cal-slide-left-in   { from { opacity: 0; transform: translateX(8px);      } to { opacity: 1; transform: translateX(0);         } }
@keyframes tes-cal-slide-left-out  { from { opacity: 1; transform: translateX(0);        } to { opacity: 0; transform: translateX(-8px);      } }
@keyframes tes-cal-slide-right-in  { from { opacity: 0; transform: translateX(-8px);     } to { opacity: 1; transform: translateX(0);         } }
@keyframes tes-cal-slide-right-out { from { opacity: 1; transform: translateX(0);        } to { opacity: 0; transform: translateX(8px);       } }
@keyframes tes-cal-scale-in        { from { opacity: 0; transform: scale(var(--tes-cal-scale-from, 0.92)); } to { opacity: 1; transform: scale(1); } }
@keyframes tes-cal-scale-out       { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(var(--tes-cal-scale-from, 0.92)); } }

@media (prefers-reduced-motion: reduce) {
    .tes-event .tes-event-cal-add-menu,
    .tes-event .tes-event-cal-add[open] .tes-event-cal-add-menu,
    .tes-event .tes-event-cal-add.is-closing .tes-event-cal-add-menu {
        animation: none !important;
    }
}

/* —— Image card (right column) —— */
.tes-event-hero-col--media {
    display: flex;
    align-items: center;
    justify-content: center;
    animation: tes-fade-up 900ms 100ms var(--tes-ease) both;
}
.tes-event-hero-figure {
    width: 100%;
    margin: 0;
    background: var(--tes-image-frame);
    border-radius: var(--tes-image-radius);
    padding: 14px;
    box-shadow:
        0 1px 0 rgba(255, 255, 255, 0.08) inset,
        0 30px 70px -20px rgba(0, 0, 0, 0.55);
}
.tes-event-hero-image {
    width: 100%;
    aspect-ratio: 4 / 3;
    background-size: cover;
    background-position: center;
    background-color: #fafafa;
    border-radius: calc(var(--tes-image-radius) - 6px);
}

/* =============================================================
 * Body section — content + tags, transparent so theme bg shows
 * ============================================================= */
.tes-event-body-section {
    padding: clamp(40px, 6vw, 80px) clamp(20px, 4vw, 48px);
}
.tes-event-body-inner {
    max-width: 760px;
    margin: 0 auto;
}

.tes-event-content {
    font-size: 18px;
    line-height: 1.7;
    letter-spacing: -0.005em;
    color: inherit;
}
.tes-event-content > *:first-child { margin-top: 0; }
.tes-event-content > *:last-child  { margin-bottom: 0; }
.tes-event-content p { margin: 1em 0; }
.tes-event-content a {
    color: var(--tes-accent);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
    transition: opacity 160ms var(--tes-ease);
}
.tes-event-content a:hover { opacity: 0.7; }
.tes-event-content h2,
.tes-event-content h3 {
    margin: 1.6em 0 0.4em;
    line-height: 1.2;
    letter-spacing: -0.015em;
    font-weight: 600;
}
.tes-event-content h2 { font-size: clamp(24px, 2.6vw, 30px); }
.tes-event-content h3 { font-size: clamp(19px, 2vw, 23px); }
.tes-event-content blockquote {
    border-left: 3px solid var(--tes-accent);
    padding: 4px 0 4px 20px;
    margin: 1.4em 0;
    color: inherit;
    opacity: 0.85;
    font-style: italic;
}
.tes-event-content ul,
.tes-event-content ol { padding-left: 1.4em; margin: 1em 0; }
.tes-event-content li { margin: 0.4em 0; }

/* —— Tag row at bottom —— */
.tes-event-tags-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: var(--tes-s-4);
    padding-top: var(--tes-s-3);
    border-top: 1px solid currentColor;
    border-top-color: rgba(0, 0, 0, 0.08);
}
.tes-event-tag {
    display: inline-flex;
    align-items: center;
    height: 32px;
    padding: 0 14px;
    font-size: 13px;
    font-weight: 500;
    color: var(--tes-accent);
    background: transparent;
    border: 1px solid var(--tes-accent);
    border-radius: 999px;
    text-decoration: none;
    transition: background 160ms var(--tes-ease), color 160ms var(--tes-ease);
}
.tes-event-tag:hover {
    background: var(--tes-accent);
    color: #fff;
    text-decoration: none;
}

/* =============================================================
 * Hero layout — single full-image overlay variant (legacy)
 * ============================================================= */
.tes-event--hero .tes-event-back {
    padding: 0 clamp(20px, 4vw, 48px);
    margin: var(--tes-s-3) 0;
}
.tes-event--hero .tes-event-back a {
    color: var(--tes-accent);
    text-decoration: none;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}
.tes-event--hero .tes-event-hero-img {
    position: relative;
    width: 100vw;
    left: 50%;
    right: 50%;
    margin-left: -50vw;
    margin-right: -50vw;
    min-height: 520px;
    background-size: cover;
    background-position: center;
    overflow: hidden;
    display: flex;
    align-items: flex-end;
    animation: tes-fade-up 900ms var(--tes-ease) both;
}
.tes-event--hero .tes-event-hero-img::before {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(14, 14, 18, 0.85) 0%, rgba(14, 14, 18, 0.30) 50%, rgba(14, 14, 18, 0) 85%);
}
.tes-event--hero .tes-event-hero-overlay {
    position: relative;
    padding: clamp(28px, 4vw, 56px);
    color: #fff;
    width: 100%;
    max-width: 1180px;
    margin: 0 auto;
}
.tes-event--hero .tes-event-title {
    color: #fff;
    max-width: 18ch;
    margin: 0 0 12px;
}
.tes-event--hero .tes-event-hero-when {
    margin: 0;
    font-size: 17px;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.92);
}

/* =============================================================
 * Sidebar layout — title hero + content/details two-col
 * ============================================================= */
.tes-event--sidebar .tes-event-hero {
    padding-bottom: clamp(40px, 6vw, 64px);
}
.tes-event--sidebar .tes-event-hero-inner > * { animation: tes-fade-up 800ms var(--tes-ease) both; }
.tes-event--sidebar .tes-event-sidebar-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.8fr) minmax(280px, 1fr);
    gap: clamp(32px, 5vw, 64px);
    align-items: start;
}
.tes-event--sidebar .tes-event-aside {
    position: sticky;
    top: 24px;
    display: flex;
    flex-direction: column;
    gap: var(--tes-s-3);
    padding: var(--tes-s-3);
    background: rgba(0, 0, 0, 0.025);
    border: 1px solid rgba(0, 0, 0, 0.08);
    border-radius: var(--tes-image-radius);
}
.tes-event--sidebar .tes-event-aside .tes-event-hero-image {
    aspect-ratio: 4 / 3;
    border-radius: 10px;
    background-color: rgba(0, 0, 0, 0.04);
}
.tes-event--sidebar .tes-event-aside .tes-event-hero-meta {
    flex-direction: column;
    gap: var(--tes-s-2);
}
.tes-event--sidebar .tes-event-aside .tes-event-hero-meta-item {
    color: inherit;
    font-size: 14px;
}
.tes-event--sidebar .tes-event-aside .tes-event-icon {
    color: var(--tes-accent);
}

/* =============================================================
 * Responsive
 * ============================================================= */
@media (max-width: 820px) {
    .tes-event-hero-grid {
        grid-template-columns: 1fr;
        gap: var(--tes-s-4);
    }
    .tes-event-hero-col--media {
        order: -1;  /* image above title on narrow screens */
    }
    .tes-event-title { font-size: clamp(28px, 7vw, 40px); }
    .tes-event-hero-meta { gap: 10px 22px; }
    .tes-event-hero-meta-item { font-size: 14.5px; }
    .tes-event-content { font-size: 17px; line-height: 1.65; }
    .tes-event--sidebar .tes-event-sidebar-grid { grid-template-columns: 1fr; }
    .tes-event--sidebar .tes-event-aside { position: static; }
}

/* =============================================================
 * Motion
 * ============================================================= */
@keyframes tes-fade-up {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .tes-event-hero-col--content,
    .tes-event-hero-col--media,
    .tes-event--hero .tes-event-hero-img,
    .tes-event--sidebar .tes-event-hero-inner > * {
        animation: none !important;
    }
    .tes-event-breadcrumbs a,
    .tes-event-cta-btn,
    .tes-event-cta-blobs,
    .tes-event-cta-blob,
    .tes-event-cta-label,
    .tes-event-cta-icon,
    .tes-event-cta-icon svg,
    .tes-event-tag,
    .tes-event-content a {
        transition: none !important;
    }
}
