/* ─── Global stylesheet ────────────────────────────────────────────────
 *
 * Loaded once via layout.twig. Manifests the global modules every page
 * needs: design tokens → reset → typography → site chrome → shared
 * components. Per-page CSS (books.css, spectacle.css, …) is loaded by
 * each route's `{% block stylesheets %}` and may use the tokens too.
 *
 * Hierarchy:
 *   base/       — tokens, reset, typography (no .classes besides resets)
 *   layout/     — site chrome (header, …; footer in components/ for now)
 *   components/ — reusable blocks (buttons, posters, cards, modal, …)
 */

/* ─── Base ─────────────────────────────────────────────────────── */
/* @import ./base/tokens.css */
/* ─── Design tokens ────────────────────────────────────────────────────
 *
 * Theme variables consumed by everything in /css/. Loaded first via
 * styles.css so it's available to every page-specific and component
 * stylesheet. When introducing a new color/spacing/radius/transition,
 * add it here first and reference it via var(--…).
 */

:root {
    /* ─── Typography ─────────────────────────────────────────────── */
    --font-body:    'Roboto', -apple-system, BlinkMacSystemFont, sans-serif;
    --font-heading: 'Roboto', -apple-system, BlinkMacSystemFont, sans-serif;

    --line-tight:   1.2;
    --line-base:    1.5;
    --line-relaxed: 1.7;

    --tracking-tight: 0.05em;
    --tracking-wide:  0.08em;
    --tracking-caps:  0.1em;

    /* ─── Surface (backgrounds) ──────────────────────────────────── */
    --color-bg:        #fff;
    --color-bg-soft:   #fafafa;
    --color-bg-muted:  #f5f5f5;
    --color-bg-tint:   #f0f0f0;
    --color-bg-strong: #000;

    /* ─── Text ───────────────────────────────────────────────────── */
    --color-text:         #000;
    --color-text-darker:  #1a1a1a;
    --color-text-strong:  #222;
    --color-text-medium:  #333;
    --color-text-mute:    #555;
    --color-text-muted:   #666;
    --color-text-soft:    #999;
    --color-text-faint:   #ccc;
    --color-text-on-dark: #fff;

    /* ─── Borders / dividers ─────────────────────────────────────── */
    --color-border:        #eee;
    --color-border-soft:   #f0f0f0;
    --color-border-strong: #ddd;

    /* ─── Accents ────────────────────────────────────────────────── */
    --color-accent-red:    #ff5252; /* poster "ПРЕМЬЕРА" tag */
    --color-action-red:    #d40000; /* admin destructive / call-to-action */
    --color-action-red-dk: #b00000;
    --color-link:          #0072BF; /* inline links inside prose */

    /* ─── Spacing scale (rem, 4 px base) ─────────────────────────── */
    --space-3xs: 0.125rem;
    --space-2xs: 0.25rem;
    --space-xs:  0.5rem;
    --space-sm:  0.75rem;
    --space-md:  1rem;
    --space-lg:  1.5rem;
    --space-xl:  2rem;
    --space-2xl: 3rem;
    --space-3xl: 4rem;

    /* ─── Container widths ───────────────────────────────────────── *
     *
     * Pick the cap that matches the content density:
     *   --container-xs   tight text columns / single-card narrow forms
     *   --container-sm   short articles / dialog bodies
     *   --container-md   long reading content / image-text mixes
     *   --container-lg   default page content (legacy "narrow")
     *   --container-xl   wide listings / playbill (legacy "wide")
     *   --container-2xl  generous listings on FHD+ displays
     *   --container-3xl  flagship displays / 4K editorial layouts
     *
     * For most page wrappers prefer `var(--container)` — a viewport-
     * aware cap that lifts itself on FHD / QHD / 4K screens via the
     * @media stops below.
     */
    --container-xs:     480px;
    --container-sm:     720px;
    --container-md:     960px;
    --container-lg:    1280px;
    --container-xl:    1600px;
    --container-2xl:   1920px;
    --container-3xl:   2400px;

    /* Legacy aliases */
    --container-narrow: var(--container-lg);
    --container-wide:   var(--container-xl);

    /* Adaptive default container — grows with the viewport. Override
       by setting a specific --container-* on the wrapper when you need
       to pin a width. */
    --container:        var(--container-xl);

    /* ─── Breakpoints (reference values, also driven by @media stops
     *     below — keep these in sync if you change either) ────────── */
    --bp-xs:       480px;
    --bp-sm:       768px;
    --bp-md:      1024px;
    --bp-lg:      1280px;
    --bp-xl:      1600px;
    --bp-2xl:     1920px;
    --bp-3xl:     2560px;

    /* ─── Radii ──────────────────────────────────────────────────── */
    --radius-sm:   4px;
    --radius-md:   6px;
    --radius-full: 9999px;

    /* ─── Transitions ────────────────────────────────────────────── */
    --t-fast: 0.15s ease;
    --t-base: 0.2s ease;
    --t-slow: 0.3s ease;

    /* ─── Z-index scale ──────────────────────────────────────────── */
    --z-base:    1;
    --z-overlay: 10;
    --z-sticky:  100;
    --z-modal:   1000;
}

/* ─── Adaptive container — lift the default cap on larger displays.
 *
 * Anything that uses `var(--container)` for its max-width automatically
 * grows on FHD / QHD / 4K so we stop wasting half the screen on
 * widescreen monitors. Page-specific wrappers that need a fixed cap
 * (e.g. a narrow article column) should hardcode `var(--container-md)`
 * or similar instead. ─────────────────────────────────────────────── */

@media (min-width: 1920px) {
    :root { --container: var(--container-2xl); }
}

@media (min-width: 2560px) {
    :root { --container: var(--container-3xl); }
}

/* ─── Breakpoint reference (custom properties don't work inside the
 *     @media expression itself; use these literal values when writing
 *     new queries, and update the --bp-* tokens in lockstep) ───────
 *
 *   xs / small:    480px   ─ phones in portrait
 *   sm / mobile:   768px   ─ large phones / small tablets
 *   md / tablet:  1024px   ─ tablets / small laptops
 *   lg / desktop: 1280px   ─ baseline desktop
 *   xl / wide:    1600px   ─ widescreen monitors
 *   2xl / FHD:    1920px   ─ Full HD
 *   3xl / QHD+:   2560px   ─ QHD / 4K
 */

/* @import ./base/reset.css */
/* ─── Reset / element defaults ─────────────────────────────────────────
 *
 * Minimal, opinionated reset. Keeps things consistent without nuking
 * native form/heading behaviour the way classic resets do.
 */

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    font-family: var(--font-body);
    color: var(--color-text);
    background: var(--color-bg);
    line-height: var(--line-base);
    overflow-x: hidden;
}

a {
    color: inherit;
    text-decoration: none;
}

img,
svg {
    display: block;
    max-width: 100%;
}

button {
    font: inherit;
}

/* @import ./base/typography.css */
/* ─── Typography ───────────────────────────────────────────────────────
 *
 * @font-face + default heading rules. Tokens (var(--font-*)) live in
 * base/tokens.css.
 */

@font-face {
    font-family: 'Roboto';
    src: url('/fonts/Roboto-Variable.ttf') format('truetype-variations'),
         url('/fonts/Roboto-Variable.ttf') format('truetype');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}

h1,
h2,
h3,
.poster-title,
.perf-card-title,
.card-carousel-title,
.playbill-item-title,
.day-playbill-date-num {
    font-family: var(--font-heading);
    font-weight: 700;
}

/* ─── Prose links ──────────────────────────────────────────────────────
 *
 * Inline links inside editorial / long-form copy get the blue link colour
 * with an underline that only appears on hover. Scoped to a small set of
 * "text-block" containers so it doesn't leak into navigation, cards, or
 * any element where the parent surface already styles its own <a>s.
 *
 * Add new container classes here when a fresh content surface appears.
 */
.page-body a,
.page-blocks a,
.page-item a,
.article-content a,
.bl-text a,
.bl-paragraph a,
.bl-quote a,
.person-bio-text a,
.spectacle-about a,
.spectacle-hero-about a,
.history-chapter a,
.history-page .marginalia a,
.history-intermission a,
.detail-subtitle a,
.detail-author a,
.media-item-body a,
.contacts-intro a,
.contact-card a,
.theatre-intro a {
    color: var(--color-link);
    text-decoration: none;
    transition: color .15s ease, text-decoration-color .15s ease;
}

.page-body a:hover,
.page-blocks a:hover,
.page-item a:hover,
.article-content a:hover,
.bl-text a:hover,
.bl-paragraph a:hover,
.bl-quote a:hover,
.person-bio-text a:hover,
.spectacle-about a:hover,
.spectacle-hero-about a:hover,
.history-chapter a:hover,
.history-page .marginalia a:hover,
.history-intermission a:hover,
.detail-subtitle a:hover,
.detail-author a:hover,
.media-item-body a:hover,
.contacts-intro a:hover,
.contact-card a:hover,
.theatre-intro a:hover {
    text-decoration: underline;
    text-underline-offset: 2px;
}


/* ─── Layout ───────────────────────────────────────────────────── */
/* @import ./layout/header.css */
/* ─── Site header ──────────────────────────────────────────────────────
 *
 * Two-row layout: top utility row (Safe Travels, department logo, lang
 * switcher) + nav row (main menu + search). Renders via the partial
 * templates/partials/header.twig.
 */

.site-header {
    padding: var(--space-lg) var(--space-xl);
    background: var(--color-bg);
}

.header-inner {
    display: flex;
    align-items: stretch;
    gap: var(--space-xl);
    /* Full-width rule under the header, matching the old site. */
    border-bottom: 2px solid var(--color-text);
}

.header-row-top {
    margin-bottom: var(--space-lg);
}

.site-logo {
    flex-shrink: 0;
    display: flex;
    align-items: center;
}

.site-logo-mark {
    width: 310px;
    height: auto;
    display: block;
}

.header-right {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    /* lets the flex children shrink properly */
    min-width: 0;
}

/* ─── Utility row (right side of top header) ───────────────────────── */

.header-row-utility {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-lg);
    margin-bottom: var(--space-lg);
}

.header-utility-block {
    display: flex;
    align-items: center;
}

.header-safetravels {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    font-size: 0.7rem;
    line-height: 1.3;
    color: var(--color-text-medium);
}

.header-safetravels-mark {
    display: inline-block;
    width: 36px;
    height: 36px;
    background: url(/images/wst.png) center / contain no-repeat;
    flex-shrink: 0;
}

.header-safetravels-text {
    max-width: 12em;
}

.header-depcult {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    max-width: 18em;
    font-size: 0.75rem;
    line-height: var(--line-tight);
    color: inherit;
    text-decoration: none;
}

.header-depcult::before {
    content: '';
    flex-shrink: 0;
    width: 34px;
    height: 40px;
    background: url(/images/gerb_moskvy.svg) center / contain no-repeat;
}

.header-depcult:hover {
    color: var(--color-text-mute);
}

/* ─── Nav row ──────────────────────────────────────────────────────── */

.header-row-nav {
    display: flex;
    align-items: center;
    justify-content: end;
    gap: var(--space-xl);
    border-top: 0;
}

.header-row-nav .menu {
    flex: 1;
}

/* ─── Search form — dropdown below the button ────────────────────────
 * The button sits inline in the nav row. The input is absolutely
 * positioned just below it (dropdown style) and toggles in/out on
 * `.is-open`. That way the open state doesn't displace menu items
 * (which it did when the input was an inline flex neighbor — at
 * intermediate widths the menu wrapped or got truncated).
 * /js/header-search.js wires the toggle, Esc close, click-outside. */
.header-search {
    position: relative;
    flex-shrink: 0;
    display: flex;
    align-items: center;
}

.header-search-input {
    /* Resting state — dropdown collapsed above the button. */
    position: absolute;
    top: calc(100% + 0.25rem);
    right: 0;
    width: 280px;
    max-width: calc(100vw - var(--space-xl) * 2);
    padding: 0.7rem 0.9rem;
    border: 1px solid var(--color-text);
    background: var(--color-bg);
    font: inherit;
    font-size: 0.95rem;
    color: var(--color-text);
    outline: none;
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.08);
    opacity: 0;
    pointer-events: none;
    transform: translateY(-6px);
    transition:
        opacity 0.18s ease,
        transform 0.18s ease;
    z-index: 60;
}

.header-search.is-open .header-search-input {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0);
}

.header-search-input::placeholder {
    color: var(--color-text-mute, #999);
    font-style: italic;
}

.header-search-btn {
    flex-shrink: 0;
    background: transparent;
    border: none;
    padding: var(--space-xs);
    cursor: pointer;
    color: var(--color-text);
    display: flex;
    align-items: center;
}

.header-search-btn:hover {
    color: var(--color-text-muted);
}

/* ─── Main menu ────────────────────────────────────────────────────── */

.menu {
    display: flex;
    align-items: center;
    justify-content: end;
    /* Base 1rem; shrinks fluidly toward 0.4rem before items would wrap. */
    gap: clamp(0.4rem, 0.6vw + 0.2rem, 1rem);
    list-style: none;
    margin: 0;
    padding: 0;
    /* Wrap is the last-resort safety net — scaling below should keep one row. */
    flex-wrap: wrap;
}

.menu-item a {
    display: inline-block;
    padding: var(--space-md) 0;
    /* Type shrinks continuously from 1.2rem → 0.85rem with viewport. */
    font-size: clamp(0.85rem, 0.45vw + 0.75rem, 1.2rem);
    font-weight: 700;
    /* Tracking eases off on narrow screens so items reclaim a few px each. */
    letter-spacing: clamp(0.02em, 0.05vw + 0.01em, 0.08em);
    text-transform: uppercase;
    color: var(--color-text);
    border-bottom: 3px solid transparent;
    transition: border-color var(--t-fast);
    white-space: nowrap;
}

.menu-item a:hover {
    color: var(--color-text-muted);
}

.menu-item.is-active a {
    border-bottom-color: var(--color-text);
}

/* ─── Responsive ───────────────────────────────────────────────────── */
/*
 * Most of the header's shrink behaviour lives in clamp()s above. These
 * media queries handle structural drops that can't be done fluidly:
 * hiding text labels, collapsing utility blocks, etc.
 */

@media (max-width: 1024px) {
    .header-safetravels-text {
        display: none;
    }
    .header-utility {
        gap: var(--space-md);
    }
}

/* ─── Hamburger + drawer ────────────────────────────────────────────
 *
 * Mode switch is driven by a class — `.site-header.is-narrow` — set
 * by /js/header-menu.js when the inline menu's natural width would
 * exceed the available nav-row space. Wrap detection (content-based)
 * fires the switch instead of a hard px breakpoint, so the hamburger
 * shows up at whatever width the actual menu needs. */

.header-menu-btn {
    display: none;
    flex-shrink: 0;
    background: transparent;
    border: 0;
    padding: var(--space-xs);
    color: var(--color-text);
    cursor: pointer;
    align-items: center;
}
.header-menu-btn:hover {
    color: var(--color-text-muted);
}
.header-menu-btn-line {
    transition: transform .2s ease, opacity .15s ease;
    transform-origin: center;
}
.header-menu-btn.is-open .header-menu-btn-line-1 {
    transform: translateY(5px) rotate(45deg);
}
.header-menu-btn.is-open .header-menu-btn-line-2 {
    opacity: 0;
}
.header-menu-btn.is-open .header-menu-btn-line-3 {
    transform: translateY(-5px) rotate(-45deg);
}

/* Narrow mode — collapse the inline menu into a drawer, show the
 * hamburger. The menu must stay measurable when not narrow, so we
 * never use `display: none`; we toggle visibility via opacity +
 * pointer-events + a transform that pushes it out of the way. */
.site-header.is-narrow .header-menu-btn {
    display: inline-flex;
}

.site-header.is-narrow .header-row-nav {
    position: relative;
    gap: var(--space-md);
}

.site-header.is-narrow .menu {
    position: absolute;
    top: calc(100% + var(--space-md));
    left: calc(var(--space-md) * -1);
    right: calc(var(--space-md) * -1);
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 0;
    padding: var(--space-md) 0;
    background: var(--color-bg);
    border-top: 1px solid var(--color-text);
    border-bottom: 1px solid var(--color-text);
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.08);
    z-index: 50;
    opacity: 0;
    pointer-events: none;
    transform: translateY(-6px);
    transition: opacity .15s ease, transform .15s ease;
}
.site-header.is-narrow .menu.is-open {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0);
}

.site-header.is-narrow .menu-item a {
    display: block;
    padding: var(--space-md) var(--space-lg);
    font-size: 1rem;
    letter-spacing: 0.06em;
    border-bottom: 1px solid #eee;
}
.site-header.is-narrow .menu-item:last-child a {
    border-bottom: 0;
}
.site-header.is-narrow .menu-item.is-active a {
    border-bottom: 1px solid var(--color-text);
    background: #f7f7f7;
}

@media (max-width: 768px) {
    .site-header {
        padding: var(--space-md);
    }
    .header-safetravels {
        display: none;
    }
}


/* ─── Global components ────────────────────────────────────────── */
/* @import ./components/buttons.css */
/* ─── Buttons ──────────────────────────────────────────────────────────
 *
 * Three shared variants used across the public site:
 *   .btn          — base sizing/typography, transparent background
 *   .btn-lang     — black pill (language switcher in header)
 *   .btn-outline  — bordered "see all / read more" link
 *
 * Buy-button variants (mos.ru iframe, Timepad) get their own classes
 * applied via partials/buy-button.twig and live in their host CSS
 * (poster-actions, electro-card-buy, etc.).
 */

.btn {
    display: inline-block;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    padding: 0.85rem var(--space-lg);
    border: 1px solid transparent;
    cursor: pointer;
    background: transparent;
    color: inherit;
    transition: background var(--t-base),
                color var(--t-base),
                border-color var(--t-base);
}

.btn-lang {
    background: var(--color-bg-strong);
    color: var(--color-text-on-dark);
    padding: 0.85rem 1.25rem;
}

.btn-lang:hover {
    background: var(--color-text-medium);
}

.btn-outline {
    display: inline-block;
    padding: 0.7rem var(--space-lg);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    text-decoration: none;
    border: 1px solid var(--color-text);
    color: var(--color-text);
    background: var(--color-bg);
    cursor: pointer;
    transition: background var(--t-base), color var(--t-base);
    white-space: nowrap;
    font-family: inherit;
}

.btn-outline:hover {
    background: var(--color-text);
    color: var(--color-text-on-dark);
}

/* @import ./components/top-banner.css */
/* ─── Top banner ───────────────────────────────────────────────────────
 *
 * Sitewide announcement strip rendered above the header. Closeable;
 * dismissal state lives in localStorage (public/js/top-banner.js).
 */

.top-banner {
    color: var(--color-text-on-dark);
    background-color: var(--color-bg-strong);
    text-align: center;
    padding: var(--space-lg) 0;
    /* Red separator under the banner — visually anchors the strip to
       the header below and matches the site's accent palette. */
    border-bottom: 0.4rem solid #d6132a;
}

.top-banner-inner {
    display: inline-block;
    max-width: 50vw;
}

.top-banner-text {
    font-size: 0.9rem;
    font-weight: 700;
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
}

.top-banner-close {
    position: absolute;
    top: var(--space-xl);
    right: 22vw;
    display: inline-flex;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--color-text-on-dark);
    cursor: pointer;
    opacity: 0.7;
    transition: opacity var(--t-base), transform var(--t-slow);
}

.top-banner-close:hover {
    opacity: 1;
    transform: scale(1.12) rotate(90deg);
}

.top-banner-close:active {
    transform: scale(0.95) rotate(90deg);
}

.top-banner-close svg {
    display: block;
}

/* @import ./components/footer.css */
.site-footer {
    background: #000;
    color: #fff;
    padding: 4rem 3rem 2rem;
}

.footer-inner {
    max-width: var(--container);
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: 3.5rem;
}

/* ─── Main row: brand sidebar (left) | nav block (right) ────────────── */

.footer-main {
    display: grid;
    /* Brand column gets a fixed comfortable width; nav takes the rest
       but is capped + right-aligned via the .footer-nav rule below, so
       the 3 menu cols stay tight rather than fanning out across 2/3 of
       the screen. */
    grid-template-columns: minmax(25rem, 0.4fr) minmax(0, 1fr);
    gap: 3rem;
    align-items: start;
}

.footer-brand-column {
    display: flex;
    flex-direction: column;
    gap: 2.5rem;
    min-width: 0;
}

.footer-brand {
    display: flex;
    gap: 1.5rem;
    align-items: flex-start;
}

.footer-logo-link {
    line-height: 0;
    flex-shrink: 0;
}

.footer-logo {
    width: 96px;
    height: auto;
    display: block;
}

.footer-contacts {
    font-size: 0.875rem;
    line-height: 1.6;
}

.footer-contacts a {
    color: inherit;
    text-decoration: underline;
}

.footer-contacts a:hover {
    text-decoration: none;
}

.footer-contacts-all {
    display: inline-block;
    margin-top: 0.5rem;
}

/* Newsletter (overrides the centered partial styling when in the
   footer's left column — title left-aligned, full-width form). */
.footer-newsletter {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.footer-newsletter .newsletter {
    align-items: flex-start;
    gap: 1rem;
    width: 100%;
}

.footer-newsletter .newsletter-title {
    text-align: left;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 0.85rem;
}

.footer-newsletter .newsletter-form {
    max-width: none;
    width: 100%;
}

.footer-newsletter .footer-social {
    margin-top: 1rem;
}

/* ─── Nav: 3 visual columns, auto-balanced via CSS columns ─────────── */

.footer-nav {
    min-width: 0;
    /* Cap the nav and push it to the right edge so the menu columns
       stay readable instead of stretching to a third of the screen. */
    max-width: 720px;
    width: 100%;
    margin-left: auto;
}

.footer-nav-cols {
    column-count: 3;
    column-gap: 2.5rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.footer-nav-col {
    break-inside: avoid;
    margin-bottom: 2.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
}

.footer-nav-col:last-child {
    margin-bottom: 0;
}

.footer-nav-heading {
    font-size: 1rem;
    font-weight: 700;
    color: #fff;
    text-decoration: none;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

a.footer-nav-heading:hover {
    text-decoration: underline;
}

.footer-nav-sub {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.footer-nav-sub a {
    color: rgba(255, 255, 255, 0.85);
    font-size: 0.95rem;
    text-decoration: none;
    line-height: 1.4;
}

.footer-nav-sub a:hover {
    color: #fff;
    text-decoration: underline;
}

/* ─── Newsletter form base styles (used by partials/newsletter-form) ── */

.newsletter {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
    width: 100%;
}

.newsletter-title {
    font-size: 0.95rem;
    font-weight: 700;
    margin: 0;
    text-align: center;
}

.newsletter-form {
    position: relative;
    display: flex;
    align-items: stretch;
    width: 100%;
    max-width: 420px;
    background: transparent;
    border: 2px solid #fff;
}

.newsletter-email {
    flex: 1;
    padding: 0.85rem 1.25rem;
    background: transparent;
    border: none;
    color: #fff;
    font: inherit;
    font-size: 0.95rem;
    outline: none;
    min-width: 0;
}

.newsletter-email::placeholder {
    color: rgba(255, 255, 255, 0.5);
}

.newsletter-email:focus {
    background: rgba(255, 255, 255, 0.05);
}

.newsletter-submit {
    flex-shrink: 0;
    width: 56px;
    background: #fff;
    color: #000;
    border: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s;
}

.newsletter-submit:hover {
    background: #ddd;
}

.newsletter-thanks,
.newsletter-error {
    position: absolute;
    top: calc(100% + 0.5rem);
    left: 0;
    right: 0;
    text-align: left;
    font-size: 0.85rem;
}

.newsletter-thanks { color: #6f6; }
.newsletter-error  { color: #f66; }

.footer-social {
    display: flex;
    gap: 1.25rem;
    align-items: center;
}

.footer-social a {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: #fff;
    color: #000;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s, color 0.15s;
}

.footer-social a:hover {
    background: #ddd;
}

.footer-social svg {
    width: 20px;
    height: 20px;
}

/* ─── Bottom strip: copyright | fund | extras ──────────────────────── */

.footer-row-bottom {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: center;
    gap: 2rem;
    padding-top: 2.5rem;
    border-top: 1px solid rgba(255, 255, 255, 0.15);
}

.footer-copyright {
    font-size: 0.85rem;
    color: rgba(255, 255, 255, 0.75);
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    justify-self: start;
}

.footer-copyright svg {
    flex-shrink: 0;
}

.footer-fund {
    justify-self: center;
}

.footer-fund img {
    height: 3.5rem;
    width: auto;
    display: block;
}

.footer-extras {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    justify-self: end;
}

.footer-video {
    width: 140px;
    height: 80px;
    object-fit: cover;
    display: block;
    flex-shrink: 0;
}

.footer-badges {
    display: flex;
    gap: 0.75rem;
    align-items: center;
}

.footer-badge {
    display: flex;
    align-items: center;
}

.footer-badge img {
    height: 44px;
    width: auto;
    display: block;
}

/* ─── Responsive ────────────────────────────────────────────────────── */

@media (max-width: 1280px) {
    .footer-main { gap: 2.5rem; }
    .footer-nav-cols { column-gap: 2rem; }
    .footer-video { width: 120px; height: 70px; }
    .footer-badge img { height: 38px; }
}

@media (max-width: 1024px) {
    /* Top: brand on the left, newsletter+social on the right (2 cols).
       Nav drops below as its own row but stays at 3 columns. */
    .footer-main {
        grid-template-columns: 1fr;
        gap: 3rem;
    }
    .footer-brand-column {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        gap: 2.5rem;
        align-items: start;
    }
    .footer-nav {
        max-width: none;
        margin-left: 0;
    }
    /* Stays at column-count: 3 here — the user wants 3 cols at medium. */
}

@media (max-width: 768px) {
    .site-footer { padding: 2.5rem 1.5rem 1.5rem; }
    .footer-inner { gap: 2.5rem; }
    .footer-brand-column { grid-template-columns: 1fr; gap: 2rem; }
    .footer-brand { flex-direction: column; gap: 1rem; }
    .footer-logo { width: 80px; }
    .footer-nav-cols { column-count: 2; }
    .footer-row-bottom {
        grid-template-columns: 1fr;
        gap: 1.75rem;
        justify-items: center;
        text-align: center;
    }
    .footer-copyright,
    .footer-fund,
    .footer-extras {
        justify-self: center;
    }
    .footer-extras { flex-direction: column; gap: 1rem; }
    .footer-video { width: 100%; max-width: 280px; height: auto; aspect-ratio: 16 / 9; }
}

@media (max-width: 480px) {
    .footer-nav-cols { column-count: 1; }
}

/* @import ./components/poster.css */
/* ─── Full-width poster block (editorial page content) ──────────────
 *
 * A hero-style image with an optional caption absolutely positioned in
 * the bottom-right corner. Used in editorial page content only — legacy
 * page bodies, legacy .page-item sections, and .poster divs that survive
 * inside `embed` blocks of the block system.
 *
 * IMPORTANT: every rule is scoped to a page-content container. The
 * homepage slideshow cards also use the `.poster` class (styled by
 * components/posters.css); a bare `.poster` selector here would leak its
 * width/height/background onto them and break the slideshow.
 *
 * Heights step up with viewport. Background image set inline via
 * `style="background-image: url(...)"` from the CMS.
 */

.page-body .poster,
.page-item .poster,
.page-blocks .poster {
    position: relative;
    width: 100%;
    height: 480px;
    background: center / cover no-repeat #000;
}

@media (min-width: 1280px) {
    .page-body .poster,
    .page-item .poster,
    .page-blocks .poster { height: 580px; }
}

@media (min-width: 1600px) {
    .page-body .poster,
    .page-item .poster,
    .page-blocks .poster { height: 735px; }
}

/* Slightly shorter when used directly in the page body
   (legacy used 464px here instead of 480px) */
.page-body .poster {
    height: 464px;
}

@media (min-width: 1280px) {
    .page-body .poster { height: 580px; }
}

@media (min-width: 1600px) {
    .page-body .poster { height: 735px; }
}

/* ─── Caption ───────────────────────────────────────────────────────── */

.page-body .poster .caption,
.page-item .poster .caption,
.page-blocks .poster .caption {
    position: absolute;
    right: 1.5rem;
    bottom: 1.5rem;
    max-width: 40vw;
    color: #fff;
    font-size: 1rem;
    text-align: right;
    text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
}

@media (max-width: 768px) {
    .page-body .poster,
    .page-item .poster,
    .page-blocks .poster {
        height: 280px;
    }
    .page-body .poster .caption,
    .page-item .poster .caption,
    .page-blocks .poster .caption {
        right: 1rem;
        bottom: 1rem;
        max-width: 80vw;
        font-size: 0.85rem;
    }
}

/* ─── Photographer credit overlay ────────────────────────────────────
 *
 * Small bottom-right caption used by the spectacle hero, homepage
 * poster slideshow, and playbill detail takeover. The credit text is
 * extracted from `pictures.about` / `images.alt` in PictureRepository
 * (anything starting with "Фото", "Фотограф", or "Photo").
 *
 * Each parent (.spectacle-hero-poster, .poster, .detail-poster) is
 * already position-relative/absolute, so this absolutely-positioned
 * overlay anchors to whichever surface contains it.
 */
.poster-credit {
    position: absolute;
    right: clamp(0.75rem, 1.4vw, 1.5rem);
    bottom: clamp(0.75rem, 1.4vw, 1.5rem);
    z-index: 4;
    max-width: 60%;
    color: rgba(255, 255, 255, 0.85);
    font-size: clamp(0.7rem, 0.85vw, 0.85rem);
    line-height: 1.3;
    text-align: right;
    letter-spacing: 0.02em;
    text-shadow: 0 1px 6px rgba(0, 0, 0, 0.55);
    pointer-events: none;
}

/* @import ./components/second-menu.css */
/* ─── Second-level navigation ──────────────────────────────────────── */

.second-menu {
    background: #000;
    text-align: center;
    white-space: nowrap;
}

.second-menu-inner {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0;
}

.second-menu-item {
    display: inline-block;
    padding: 19px 17px 18px;
    font-size: 1rem;
    color: #fff;
    text-decoration: none;
    border-bottom: 4px solid #000;
    transition: border-color 0.15s;
}

.second-menu-item:hover {
    color: #fff;
    border-bottom-color: #fff;
}

.second-menu-item.is-active {
    font-weight: 700;
    border-bottom-color: #fff;
}

@media (max-width: 768px) {
    .second-menu {
        overflow-x: auto;
        scrollbar-width: none;
    }
    .second-menu::-webkit-scrollbar { display: none; }
    .second-menu-inner {
        flex-wrap: nowrap;
        justify-content: flex-start;
        padding: 0 1rem;
    }
    .second-menu-item {
        padding: 14px 12px;
        font-size: 0.9rem;
    }
}
/* @import ./components/sticky-nav.css */
/* ─── Shared section nav ─────────────────────────────────────────────
 *
 * Single sticky nav design used by every long-form public page —
 * spectacle, history, organizer, etc. Visual reference: the history
 * page's `history-sticky-nav` (white-paper default, palette flips to
 * black-on-paper when pinned to the viewport top).
 *
 * Markup is built by templates/partials/sticky-nav.twig and behaviour
 * is wired by /js/sticky-nav.js (scroll-spy + is-stuck detection +
 * smooth scroll).
 */

.site-nav {
    position: sticky;
    top: 0;
    z-index: 50;
    background: #ffffff;
    color: #0d0d0c;
    border-bottom: 1px solid #0d0d0c;
    transition: background .25s ease,
                color .25s ease,
                border-color .25s ease,
                box-shadow .25s ease;
}

/* Full-bleed when the nav lives inside a width-constrained container
   like <article class="page"> (which is 75% wide). The negative-margin
   trick stretches it to the viewport edges without breaking the
   sticky positioning of the parent. Same pattern as the breadcrumbs
   strip. Applies on any page where the nav is a direct child of
   .page / article.page-content.

   The vertical-margin tweak pulls the bar up close to the site
   header (the `.page` wrapper's `padding: 2rem` left too big a
   gap above) and gives the content below proper breathing room. */
.page > .site-nav,
.page-content .page > .site-nav {
    width: 100vw;
    margin: -1.5rem calc(50% - 50vw) 2rem;
}

/* Visit-page custom — the bottom rule lives on the inner so it visually
 * matches the header's `border-bottom` (which is constrained by the
 * header-inner content box, NOT full-bleed). When the nav pins to the
 * top via `.is-stuck`, the rule snaps back to the outer for a
 * conventional full-width pinned-bar look. The transparent shifts
 * keep them mutually exclusive — only one rule is visible at any
 * given scroll position. Match the header's `2px solid var(--color-text)`
 * exactly so the two rules line up as a single typographic system. */
.page > .site-nav {
    border-bottom-width: 2px;
    border-bottom-color: transparent;
}
.page > .site-nav .site-nav-inner {
    border-bottom: 1px solid var(--color-text);
}
.page > .site-nav.is-stuck {
    border-bottom-color: var(--color-text);
}
.page > .site-nav.is-stuck .site-nav-inner {
    border-bottom-color: transparent;
}

.site-nav.is-stuck {
    background: #0d0d0c;
    color: #f3ede0;
    border-bottom-color: #0d0d0c;
    box-shadow: 0 4px 24px rgba(0, 0, 0, 0.25);
}

.site-nav-inner {
    /* Match `.page` (page.css) — same 75% / 2rem container so the
       anchor labels line up with the headings + blocks below. The
       `.page` rule drops to 100% / 1rem below 768px; mirror that in
       the @media block at the bottom of this file. */
    max-width: 75%;
    margin: 0 auto;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: clamp(20px, 2.4vw, 36px);
    padding: clamp(12px, 1.4vw, 18px) 2rem;
    font-family: var(--font-body);
    font-size: clamp(11px, 0.95vw, 14px);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    font-weight: 500;
}

.site-nav-links {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: clamp(20px, 2.4vw, 36px);
    /* Allow long nav lists to scroll horizontally on narrow viewports
       rather than wrapping into multiple rows of differing heights. */
    overflow-x: auto;
    scrollbar-width: none;
}
.site-nav-links::-webkit-scrollbar { display: none; }

.site-nav-inner a {
    color: inherit;
    text-decoration: none;
    padding: 4px 0;
    border-bottom: 1px solid transparent;
    transition: border-color .2s ease, color .2s ease;
    white-space: nowrap;
}

.site-nav-inner a:hover,
.site-nav-inner a.is-active {
    color: #d6132a;
    border-bottom-color: #d6132a;
}

/* When pinned/dark, hover & active use the paper colour for contrast. */
.site-nav.is-stuck .site-nav-inner a:hover,
.site-nav.is-stuck .site-nav-inner a.is-active {
    color: #ffffff;
    border-bottom-color: #ffffff;
}

/* ─── Right slot (e.g. age badge + buy-tickets button) ─────────────── */

.site-nav-right {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-shrink: 0;
}

/* Mobile parity with `.page` (max-width: 768px → 100% / 1rem) so the
   sticky nav and the content below stay flush across breakpoints. */
@media (max-width: 768px) {
    .site-nav-inner {
        max-width: 100%;
        padding: clamp(10px, 1.4vw, 14px) 1rem;
    }
}

/* @import ./components/breadcrumbs.css */
/* ─── Breadcrumbs ────────────────────────────────────────────────────
 *
 * Unified breadcrumb strip for the whole site. Every page's back-nav
 * uses the convention `<nav class="{section}-back">` (article-back,
 * person-back, news-back, …) and they all get the same minimal look:
 * a thin inline row of muted labels, no background, no full-bleed.
 *
 * Markup contract:
 *   <nav class="{section}-back">
 *     <a href="/parent/">Parent</a>
 *     <span class="{section}-back-sep">/</span>
 *     <span aria-current="page">Current</span>
 *   </nav>
 *
 * The element+attribute selector (`nav[class$="-back"]`) outranks any
 * single-class rule in a per-page stylesheet, so this is the canonical
 * styling — page CSS files can drop their copies.
 */

nav[class$="-back"] {
    /* Explicit resets — some per-page stylesheets used to set
       background / border / width for a full-bleed bar. The unified
       rule outranks them on its declared properties (element+attr =
       (0,1,1) beats a single .class), so listing these here strips
       the bar even without touching the older CSS files. */
    margin: 0;
    padding: 1rem 0;
    background: transparent;
    border: 0;
    width: auto;
    max-width: none;
    text-align: left;
    white-space: normal;
    overflow: visible;
    font-size: 0.85rem;
    line-height: 1.4;
    color: #777;
}

nav[class$="-back"] a {
    display: inline;
    padding: 0;
    color: inherit;
    text-decoration: underline;
    text-decoration-color: rgba(0, 0, 0, 0.2);
    text-underline-offset: 2px;
    transition: color 0.15s, text-decoration-color 0.15s;
}

nav[class$="-back"] a:hover {
    color: #000;
    text-decoration-color: #000;
}

/* Separator — visually quiet so the crumbs read as a path, not as
 * three same-weight chips. */
nav[class$="-back"] [class$="-back-sep"] {
    margin: 0 0.4rem;
    color: #c4c4c4;
}

/* Terminal "current page" crumb — non-link span, slightly darker so
 * the eye lands on where you are. */
nav[class$="-back"] > [aria-current="page"] {
    color: #111;
}

/* @import ./components/ticket-modal.css */
/* ─── Ticket modal ───────────────────────────────────────────────────
 * In-page iframe modal for the mos.ru ticket widget (js/ticket.js).
 */

.ticket-modal {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    background: rgba(0, 0, 0, 0.6);
}

.ticket-modal-box {
    position: relative;
    width: min(900px, 100%);
    height: min(88vh, 780px);
    background: #fff;
    border-radius: 6px;
    overflow: hidden;
    box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.4);
}

.ticket-modal-frame {
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
}

.ticket-modal-close {
    position: absolute;
    top: 10px;
    right: 10px;
    z-index: 2;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
    transition: background 0.15s;
}

.ticket-modal-close:hover {
    background: #000;
}

/* @import ./components/inline-pic.css */
/* ─── Inline picture (with caption) ────────────────────────────────────
 *
 * Wraps a picture + optional caption inside rich content blocks. Markup
 * is generated by src/HtmlEnricher.php and can appear in articles, page
 * bodies, news, etc., so it's loaded site-wide.
 */

.inlinePic .caption,
.inlinePic img {
    width: 100%;
}

.inlinePic .caption {
    padding: 10px 0;
    font-size: 13px;
}

/* @import ./components/photoswipe.css */
/* ─── PhotoSwipe lightbox ──────────────────────────────────────────────
 *
 * Visible caption rendered from each slide's `alt` text. PhotoSwipe is
 * lazy-loaded by gallery JS (spectacle.js, article.js).
 */

.pswp__custom-caption {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    padding: var(--space-md) 1.25rem;
    background: linear-gradient(transparent, rgba(0, 0, 0, 0.78));
    color: var(--color-text-on-dark);
    font-size: 0.9rem;
    line-height: 1.45;
    text-align: center;
}

/* @import ./components/scroll-to-top.css */
/* ─── Scroll-to-top button ────────────────────────────────────────────
 *
 * Floats on the right edge of the viewport once you're more than ~1.5
 * screen heights down the page. When the footer scrolls up far enough
 * to intrude on the button's resting spot, /js/scroll-to-top.js sets
 * an inline `bottom: <calc>` so the button parks just above the
 * footer with a small gap instead of overlapping it.
 *
 * Default state is hidden (opacity 0 + pointer-events none) — the JS
 * toggles `.is-visible` past the threshold. Pure CSS handles the
 * fade so toggling it on/off doesn't jolt the layout.
 */

.scroll-to-top {
    position: fixed;
    right: 2rem;
    bottom: 2rem;
    z-index: 60;

    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;

    background: #0d0d0c;
    color: #f3ede0;
    border: 1px solid #0d0d0c;
    border-radius: 50%;
    text-decoration: none;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.22);

    opacity: 0;
    pointer-events: none;
    transform: translateY(8px);
    transition:
        opacity .25s ease,
        transform .25s ease,
        background-color .15s ease,
        color .15s ease,
        bottom .15s ease;
}

.scroll-to-top.is-visible {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0);
}

.scroll-to-top:hover {
    background: #f3ede0;
    color: #0d0d0c;
}

.scroll-to-top svg {
    display: block;
}

@media (max-width: 768px) {
    .scroll-to-top {
        right: 1rem;
        bottom: 1rem;
        width: 40px;
        height: 40px;
    }
}

/* @import ./components/newsletter-modal.css */
/* ─── Newsletter popup ───────────────────────────────────────────────
 *
 * Cookie-gated modal that fires 30s into a session via /js/newsletter.js.
 * Markup lives in templates/partials/newsletter-popup.twig as an inert
 * <template>; the JS clones it into the DOM and toggles `.is-open`
 * (rAF-deferred so the transition runs).
 *
 * Visual language matches the rest of the site: black ink on paper,
 * thick black border, fat serif heading paragraph. The form inside
 * the modal needs explicit overrides — the base `.newsletter-form`
 * rules in components/footer.css are designed for the dark footer
 * (white border, transparent bg, white text) which would render as
 * invisible ink on the paper-coloured dialog.
 */

.newsletter-modal {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    pointer-events: none;
    transition: opacity .25s ease;
}
.newsletter-modal.is-open {
    opacity: 1;
    pointer-events: auto;
}

.newsletter-modal-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    cursor: pointer;
}

.newsletter-modal-dialog {
    position: relative;
    width: min(92vw, 520px);
    max-height: calc(100vh - 4rem);
    overflow-y: auto;
    padding: 2.5rem 2.25rem 2rem;
    background: #f3ede0;          /* paper */
    color: #0d0d0c;               /* ink   */
    border: 2px solid #0d0d0c;
    box-shadow: 0 12px 48px rgba(0, 0, 0, 0.35);
    text-align: center;

    transform: translateY(20px);
    transition: transform .25s ease;
}
.newsletter-modal.is-open .newsletter-modal-dialog {
    transform: translateY(0);
}

.newsletter-modal-close {
    position: absolute;
    top: 0.5rem;
    right: 0.75rem;
    width: 36px;
    height: 36px;
    padding: 0;
    line-height: 1;
    font-size: 1.5rem;
    font-weight: 300;
    background: transparent;
    border: 0;
    color: #0d0d0c;
    cursor: pointer;
    transition: color .15s ease;
}
.newsletter-modal-close:hover {
    color: #d6132a;
}

.newsletter-modal-icon {
    display: block;
    margin: 0 auto 1.25rem;
    width: 64px;
    height: 64px;
    object-fit: contain;
}

.newsletter-modal-text {
    margin: 0 0 1.5rem;
    font-size: 1.05rem;
    line-height: 1.5;
}

/* ─── Form inside the modal (light-bg variant) ────────────────────── */

.newsletter-modal-form {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    width: 100%;
    max-width: none;       /* override .newsletter-form max-width: 420px */
    border: 0;             /* the footer base sets a 2px outer border  */
    background: transparent;
}

.newsletter-modal-form .newsletter-email {
    padding: 0.85rem 1rem;
    color: #0d0d0c;
    background: #fff;
    border: 1px solid #0d0d0c;
    font: inherit;
    font-size: 0.95rem;
    width: 100%;
}
.newsletter-modal-form .newsletter-email::placeholder {
    color: rgba(0, 0, 0, 0.45);
}
.newsletter-modal-form .newsletter-email:focus {
    outline: 2px solid #d6132a;
    outline-offset: 1px;
    background: #fff;
}

.newsletter-modal-form .newsletter-submit {
    width: 100%;
    padding: 0.85rem 1rem;
    background: #0d0d0c;
    color: #f3ede0;
    border: 0;
    font: inherit;
    font-size: 0.85rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background .15s ease, color .15s ease;
}
.newsletter-modal-form .newsletter-submit:hover {
    background: #d6132a;
    color: #fff;
}
.newsletter-modal-form .newsletter-submit:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

.newsletter-modal-note {
    display: block;
    font-size: 0.78rem;
    color: rgba(0, 0, 0, 0.6);
    line-height: 1.4;
}

/* Override the absolute-positioned status text from the footer
 * variant — inside the modal we want inline flow so the dialog
 * doesn't outgrow its scroll area. */
.newsletter-modal-form .newsletter-thanks,
.newsletter-modal-form .newsletter-error {
    position: static;
    margin-top: 0.5rem;
    text-align: center;
    font-size: 0.9rem;
}
.newsletter-modal-form .newsletter-thanks { color: #0d0d0c; font-weight: 600; }
.newsletter-modal-form .newsletter-error  { color: #d6132a; }

@media (max-width: 480px) {
    .newsletter-modal-dialog {
        padding: 2rem 1.25rem 1.5rem;
    }
    .newsletter-modal-text {
        font-size: 0.95rem;
    }
}

