/* =====================================================
   Vojin Stojanovic — site overrides & additions
   Loaded AFTER style.css / responsive.css.
   Nothing in the vendor stylesheets is modified.
   ===================================================== */

:root {
    /* One family, deliberately. Pairing a display serif italic with a geometric
       sans kept reading as two unrelated voices stuck together. Hierarchy here
       comes from weight, size, tracking and colour instead, which is what makes
       a product page feel coherent. Both template variables point at the same
       face so every existing rule follows. */
    --font_arapey: "Inter Tight", "Helvetica Neue", Arial, sans-serif;
    --font_urbanist: "Inter Tight", "Helvetica Neue", Arial, sans-serif;

    /* The template's greys were too dark to read on a phone in daylight. */
    --secondary: #a8a8a8;
    --tertiary: #8f8f8f;
    --vs-line: #2b2b2b;
    --vs-dim: #8f8f8f;
    --vs-bright: #c9c9c9;

    --glass-bg: rgba(255, 255, 255, 0.055);
    --glass-brd: rgba(255, 255, 255, 0.14);
}

/* Nothing is set in italic any more, and display sizes get optical tracking. */
.section-title.section-title2,
.hero-sec .hero-bottom h2,
.contact-sec .contact-content h3,
.next-project h3,
.hero-sec .hero-bottom h2 em,
.section-title.section-title2 span,
.contact-sec .contact-content h3 span {
    font-family: var(--font_urbanist);
    font-style: normal;
}
.section-title.section-title2,
.contact-sec .contact-content h3,
.next-project h3 {
    font-weight: 500;
    letter-spacing: -0.035em;
}
/* The accent word carries weight contrast rather than a change of face. */
.section-title.section-title2 span,
.contact-sec .contact-content h3 span {
    font-weight: 200;
}

/* ---------- Hero title ----------
   Every page's headline used to be two <h2> elements with no <h1> anywhere on
   the site. It is now a single <h1> holding two display lines as spans, which
   is what the page is actually about and what a screen reader announces first.

   The vendor stylesheets style these by tag (.hero-bottom h2), so the sizing
   below is restated against the spans instead. The values are the vendor's own,
   read back off the rendered page so the design is byte-for-byte unchanged:
   96px base, 74px under 1440, 52px under 810. */

.hero-sec .hero-bottom .hero-title {
    margin: 0;
    padding: 0;
    font-weight: inherit;
    background: none;
}
.hero-sec .hero-bottom .hero-title > span {
    display: block;
    /* Each line shrink-wraps its own text, exactly as the old block-level <h2>
       did inside the flex column. It matters because these are gradient fills
       clipped to the glyphs: a wider box stretches the ramp and changes the
       colour the word ends on. */
    width: fit-content;
    font-size: 96px;
    line-height: 96px;
    letter-spacing: -0.04em;
    font-family: var(--font_urbanist);
    font-style: normal;
    padding: 14px;
    margin: -14px;
    background-clip: text;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
}
/* Inner pages: one tone for both lines, as the template had it. */
.hero-sec .hero-bottom .hero-title > .hero-line {
    font-weight: 400;
    background-image: linear-gradient(90deg, #ffffff 209.19%, #4d4d4d 123.19%);
}
/* Home: the setup line is light and recessed, the promise heavy and pure white. */
.hero-sec .hero-bottom .hero-title > .hero-l1 {
    font-weight: 200;
    background-image: linear-gradient(90deg, #8e8e8e 0%, #5c5c5c 90%);
}
.hero-sec .hero-bottom .hero-title > .hero-l2 {
    font-weight: 600;
    background: none;
    -webkit-text-fill-color: #fff;
    color: #fff;
}
@media (max-width: 1440px) {
    .hero-sec .hero-bottom .hero-title > span { font-size: 74px; line-height: 74px; }
    .hero-sec .hero-bottom .hero-title > .hero-line { font-weight: 400; }
}
@media (max-width: 809px) {
    .hero-sec .hero-bottom .hero-title > span {
        font-size: 52px;
        line-height: 52px;
        padding: 7px;
        margin: -7px;
    }
}

/* ---------- Navigation: liquid glass pill ----------
   It floats over the hero animation, so the backdrop blur has real motion to
   refract rather than a flat colour.

   overflow:hidden is load-bearing, not tidiness. The specular sweep below is an
   inset:0 layer parked off to one side, and without a clip it was painting a
   loose diagonal glint out in the header next to the wordmark — a stray flash
   with nothing under it, which is the opposite of what glass should do. */

.header-menu-wrap .navbar {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    padding: 11px 32px;
    border-radius: 44px;
    background:
        linear-gradient(160deg,
            rgba(255, 255, 255, 0.11) 0%,
            rgba(255, 255, 255, 0.03) 45%,
            rgba(255, 255, 255, 0.07) 100%);
    backdrop-filter: blur(20px) saturate(165%);
    -webkit-backdrop-filter: blur(20px) saturate(165%);
    border: 1px solid rgba(255, 255, 255, 0.15);
    box-shadow:
        inset 0 1px 0 0 rgba(255, 255, 255, 0.24),
        inset 0 -1px 0 0 rgba(255, 255, 255, 0.05),
        0 18px 44px -20px rgba(0, 0, 0, 0.85);
    transition: border-color 0.5s, background 0.5s;
}

/* Real glass gathers light where you touch it. site.js feeds the pointer in as
   --mx/--my and this is the highlight that pools under it — no sweep, no timing,
   it only ever moves because the visitor did. */
.header-menu-wrap .navbar::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    border-radius: inherit;
    pointer-events: none;
    background: radial-gradient(160px circle at var(--mx, 50%) var(--my, 50%),
        rgba(255, 255, 255, 0.16) 0%,
        rgba(255, 255, 255, 0.05) 40%,
        transparent 72%);
    opacity: 0;
    transition: opacity 0.55s ease;
}
.header-menu-wrap .navbar:hover::before { opacity: 1; }

/* One slow specular pass as the pointer arrives, then it stays out of the way.
   Contained by the overflow:hidden above, so it reads as light travelling
   through the pill instead of a glare sitting on the page. */
.header-menu-wrap .navbar::after {
    content: "";
    position: absolute;
    inset: -40% -10%;
    z-index: 2;
    pointer-events: none;
    background: linear-gradient(105deg,
        transparent 38%,
        rgba(255, 255, 255, 0.13) 50%,
        transparent 62%);
    transform: translateX(-115%);
    transition: transform 1.1s cubic-bezier(0.16, 1, 0.3, 1);
}
.header-menu-wrap .navbar:hover::after { transform: translateX(115%); }
.header-menu-wrap .navbar:hover { border-color: rgba(255, 255, 255, 0.26); }

/* The droplet that glides between links. Positioned by site.js from the hovered
   item's own box, so it stretches to each label's width on the way. */
.header-menu-wrap .navbar .nav-liquid {
    position: absolute;
    z-index: 0;
    top: 50%;
    left: 0;
    height: 32px;
    width: 0;
    margin-top: -16px;
    border-radius: 32px;
    pointer-events: none;
    background: rgba(255, 255, 255, 0.11);
    box-shadow:
        inset 0 1px 0 0 rgba(255, 255, 255, 0.3),
        inset 0 -1px 0 0 rgba(255, 255, 255, 0.06);
    opacity: 0;
    transform: translateX(var(--x, 0px));
    transition:
        transform 0.55s cubic-bezier(0.22, 1.1, 0.36, 1),
        width 0.55s cubic-bezier(0.22, 1.1, 0.36, 1),
        opacity 0.35s ease;
}
.header-menu-wrap .navbar.is-liquid .nav-liquid { opacity: 1; }

.header-menu-wrap .navbar .menu { position: relative; z-index: 1; gap: 34px; }
.header-menu-wrap .navbar .menu > li { padding: 6px 0; }
.header-menu-wrap .navbar .menu li a {
    font-size: 13px;
    letter-spacing: 0.05em;
    color: var(--vs-bright);
    transition: color 0.35s ease;
}
.header-menu-wrap .navbar .menu li a:hover { color: #fff; }

/* ---------- Language switcher ----------
   Same glass as the nav pill, deliberately smaller: it is a utility, not a
   destination, and on a portfolio the work should always outrank the chrome.
   It fills the third column of the header grid, which until now was empty and
   was pushing the nav off optical centre. */

.lang-switch {
    position: relative;
    justify-self: end;
    z-index: 3;
}
.lang-current {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 8px 14px;
    border-radius: 40px;
    cursor: pointer;
    font-family: inherit;
    font-size: 11.5px;
    letter-spacing: 0.16em;
    color: var(--vs-bright);
    background: rgba(255, 255, 255, 0.05);
    backdrop-filter: blur(18px) saturate(160%);
    -webkit-backdrop-filter: blur(18px) saturate(160%);
    border: 1px solid rgba(255, 255, 255, 0.14);
    box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.18);
    transition: border-color 0.4s, color 0.4s, background 0.4s;
}
.lang-current:hover,
.lang-switch.is-open .lang-current {
    color: #fff;
    border-color: rgba(255, 255, 255, 0.28);
    background: rgba(255, 255, 255, 0.09);
}
.lang-caret {
    width: 5px;
    height: 5px;
    border-right: 1px solid currentColor;
    border-bottom: 1px solid currentColor;
    transform: translateY(-2px) rotate(45deg);
    transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.lang-switch.is-open .lang-caret { transform: translateY(1px) rotate(225deg); }

.lang-list {
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    min-width: 178px;
    margin: 0;
    padding: 7px;
    list-style: none;
    border-radius: 18px;
    background:
        linear-gradient(160deg,
            rgba(255, 255, 255, 0.10) 0%,
            rgba(255, 255, 255, 0.03) 45%,
            rgba(255, 255, 255, 0.07) 100%),
        rgba(10, 10, 11, 0.86);
    backdrop-filter: blur(26px) saturate(160%);
    -webkit-backdrop-filter: blur(26px) saturate(160%);
    border: 1px solid rgba(255, 255, 255, 0.14);
    box-shadow:
        inset 0 1px 0 0 rgba(255, 255, 255, 0.20),
        0 26px 60px -26px rgba(0, 0, 0, 0.95);
    /* Not display:none, so the panel can actually animate open. */
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px) scale(0.97);
    transform-origin: top right;
    transition: opacity 0.3s, transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), visibility 0.3s;
}
.lang-switch.is-open .lang-list {
    opacity: 1;
    visibility: visible;
    transform: translateY(0) scale(1);
}
.lang-list li { display: block; }
.lang-list a {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 9px 12px;
    border-radius: 12px;
    font-size: 14px;
    letter-spacing: -0.005em;
    color: var(--vs-bright);
    transition: background 0.3s, color 0.3s;
}
.lang-list a b {
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: 0.14em;
    color: var(--vs-dim);
    min-width: 22px;
    transition: color 0.3s;
}
.lang-list a:hover { background: rgba(255, 255, 255, 0.08); color: #fff; }
.lang-list a:hover b { color: #fff; }
.lang-list .is-current a { color: #fff; }
.lang-list .is-current a b { color: #fff; }

/* ---------- Language row in the pop-up menu ----------
   Below 1440px the header nav is hidden, so this is the only switcher there
   is. It sits with the social links rather than in the main list, because a
   language is a setting and Work / About / Contact are places. */

.header-sidebar-wrap .header-sidebar-bottom { display: grid; gap: 26px; }
.sidebar-langs .k {
    display: block;
    margin-bottom: 12px;
    font-size: 10.5px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--vs-dim);
}
/* These carry the full ancestor path because style.css styles every
   `.header-sidebar-bottom ul li a` as a 36px social circle. Without matching
   that specificity the language names render as stacked round icons. */
.header-sidebar-wrap .header-sidebar-content .header-sidebar-bottom .sidebar-langs ul {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin: 0;
    padding: 0;
    list-style: none;
}
.header-sidebar-wrap .header-sidebar-content .header-sidebar-bottom .sidebar-langs ul li {
    width: auto;
}
.header-sidebar-wrap .header-sidebar-content .header-sidebar-bottom .sidebar-langs ul li a {
    display: block;
    width: auto;
    height: auto;
    padding: 7px 13px;
    border-radius: 30px;
    font-size: 12px;
    letter-spacing: 0.04em;
    color: var(--vs-bright);
    border: 1px solid rgba(255, 255, 255, 0.13);
    background: rgba(255, 255, 255, 0.04);
    backdrop-filter: blur(14px) saturate(150%);
    -webkit-backdrop-filter: blur(14px) saturate(150%);
    transition: border-color 0.35s, background 0.35s, color 0.35s;
}
/* The code is only there for the header pill; in the panel the language's own
   name is the label and the abbreviation would just be noise. */
.sidebar-langs a b { display: none; }
.header-sidebar-wrap .header-sidebar-content .header-sidebar-bottom .sidebar-langs ul li a:hover {
    color: #fff;
    border-color: rgba(255, 255, 255, 0.3);
    background: rgba(255, 255, 255, 0.1);
}
.header-sidebar-wrap .header-sidebar-content .header-sidebar-bottom .sidebar-langs ul li.is-current a {
    color: #000;
    background: #fff;
    border-color: #fff;
}
/* Same reason as the language pills: style.css gives every li in here
   width:100%, which pushed the two icons to opposite ends of the panel. */
.header-sidebar-wrap .header-sidebar-content .header-sidebar-bottom .sidebar-socials {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 0;
    padding: 0;
    list-style: none;
}
.header-sidebar-wrap .header-sidebar-content .header-sidebar-bottom .sidebar-socials li {
    width: auto;
}

/* ---------- Liquid glass ----------
   A real backdrop blur plus a specular top edge and a sheen that sweeps on
   hover. It needs something behind it to refract, which is what .glow-bed
   provides on the sections that use it. */

.lg {
    position: relative;
    isolation: isolate;
    background:
        linear-gradient(160deg,
            rgba(255, 255, 255, 0.10) 0%,
            rgba(255, 255, 255, 0.028) 42%,
            rgba(255, 255, 255, 0.06) 100%);
    backdrop-filter: blur(22px) saturate(150%);
    -webkit-backdrop-filter: blur(22px) saturate(150%);
    border: 1px solid var(--glass-brd);
    border-radius: 24px;
    box-shadow:
        inset 0 1px 0 0 rgba(255, 255, 255, 0.20),
        inset 0 -1px 0 0 rgba(255, 255, 255, 0.05),
        0 24px 60px -24px rgba(0, 0, 0, 0.9);
    transition: border-color 0.45s, transform 0.45s cubic-bezier(0.16, 1, 0.3, 1);
}
.lg::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 4;
    border-radius: inherit;
    pointer-events: none;
    background: linear-gradient(105deg,
        transparent 34%,
        rgba(255, 255, 255, 0.13) 47%,
        transparent 61%);
    transform: translateX(-115%);
    transition: transform 0.95s cubic-bezier(0.16, 1, 0.3, 1);
}
.lg:hover {
    border-color: rgba(255, 255, 255, 0.26);
    transform: translateY(-3px);
}
.lg:hover::after { transform: translateX(115%); }

/* Something for the glass to actually refract. */
.glow-bed {
    position: absolute;
    inset: -12% -6%;
    z-index: 0;
    pointer-events: none;
    background:
        radial-gradient(40% 46% at 18% 20%, rgba(255, 255, 255, 0.10), transparent 70%),
        radial-gradient(36% 42% at 82% 30%, rgba(186, 202, 255, 0.075), transparent 70%),
        radial-gradient(48% 52% at 50% 92%, rgba(255, 255, 255, 0.055), transparent 70%);
    filter: blur(26px);
    animation: vsGlowDrift 26s ease-in-out infinite alternate;
}
@keyframes vsGlowDrift {
    from { transform: translate3d(-2%, -1%, 0) scale(1); }
    to   { transform: translate3d(2%, 2%, 0) scale(1.06); }
}

/* ---------- Wordmark (replaces template logo images) ---------- */

/* The header used to be logo / nav / contact-info under space-between. With the
   contact block gone, a 3-column grid keeps the nav optically centred instead
   of letting it drift to the right edge.

   Only above 1440px: responsive.css hides the nav links below that, and an
   empty middle column would squeeze the wordmark into a 1fr slot and wrap it. */
@media (min-width: 1440px) {
    .header-menu-wrap .custom-container .custom-row {
        display: grid;
        grid-template-columns: 1fr auto 1fr;
        align-items: center;
    }
}

.logo .wordmark {
    display: block;
    line-height: 1;
}
.logo .wordmark b {
    font-weight: 600;
    font-size: 15px;
    letter-spacing: 0.22em;
    color: #fff;
    text-transform: uppercase;
    white-space: nowrap;
}

.preloader-wordmark {
    text-align: center;
    line-height: 1;
}
.preloader-wordmark b {
    display: block;
    font-weight: 300;
    font-size: clamp(30px, 6.4vw, 78px);
    letter-spacing: -0.035em;
    color: #fff;
}
.preloader-wordmark i {
    display: block;
    margin-top: 14px;
    font-style: normal;
    font-size: 11px;
    letter-spacing: 0.42em;
    text-transform: uppercase;
    color: var(--vs-dim);
}

/* The template pinned .footer-bottom to 245px with overflow:hidden, and a
   0.86 line-height crops the glyph box, so the bottom of the letters was being
   shaved off. Auto height, a line-height above 1, and a smaller size. */
.footer-area .footer-bottom {
    height: auto;
    padding: 30px 0 52px;
    overflow: visible;
    /* Lets the name size itself off this box instead of the viewport. vw counts
       the scrollbar, which is exactly the sliver that was pushing the last
       letters past the edge. */
    container-type: inline-size;
}
.footer-area .footer-bottom .footer-wordmark {
    margin: 0;
    width: 100%;
    text-align: center;
    white-space: nowrap;
    font-family: var(--font_urbanist);
    font-weight: 600;
    font-size: 9.4vw;
    /* "VOJIN STOJANOVIC" set solid is 8.6em wide, so dividing the box by that
       (minus a 128px gutter) is the largest size that is guaranteed to fit.
       Whichever of the two is smaller wins, so the name can never run off the
       end of the page at any width. */
    font-size: min(9.4vw, calc((100cqw - 128px) / 8.6));
    line-height: 1.06;
    letter-spacing: -0.045em;
    text-transform: uppercase;
    /* The two words carry their own gradients, so the tonal step between the
       name and the surname is the split. */
    background: none;
    -webkit-text-fill-color: currentColor;
    color: #fff;
}
.footer-area .footer-bottom .footer-wordmark span {
    display: inline-block;
    background-clip: text;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
}
.footer-area .footer-bottom .footer-wordmark span:first-child {
    background-image: linear-gradient(180deg, #ffffff 6%, #dcdcdc 96%);
}
/* The surname used to bottom out at #3c3c3c, which on a black page meant the
   lower half of the letters simply disappeared. The tonal step between the two
   words is kept; the floor is just lifted to where it still reads. */
.footer-area .footer-bottom .footer-wordmark span:last-child {
    background-image: linear-gradient(180deg, #b4b4b4 6%, #767676 100%);
}

/* ---------- Hero ---------- */

/* The home hero carries no intro copy, so its single in-flow block sits at the
   bottom rather than being spaced out against nothing. */
.hero-sec:not(.about-hero-sec) .hero-inner {
    justify-content: flex-end;
}
.hero-lede {
    margin: 26px 0 0;
    font-size: 17px;
    line-height: 26px;
    letter-spacing: -0.01em;
    color: var(--vs-dim);
    max-width: 54ch;
}
.hero-kicker {
    display: inline-block;
    font-size: 11px;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: var(--vs-dim);
}
.about-hero-sec .hero-top {
    padding-top: 128px;
}
/* The template's 230px gap was sized for the old quote block. With just a
   kicker above the title it leaves a dead screen of space. */
.about-hero-sec .hero-inner {
    gap: 110px;
    padding-bottom: 80px;
}
@media (max-width: 767px) {
    .about-hero-sec .hero-inner { gap: 70px; padding-bottom: 50px; }
    .about-hero-sec .hero-top { padding-top: 104px; }
}

.hero-availability {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    font-size: 12px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--vs-dim);
    margin-bottom: 22px;
}
.hero-availability span.dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #7CFFB2;
    box-shadow: 0 0 0 0 rgba(124, 255, 178, 0.7);
    animation: vsPulse 2.4s infinite;
}
@keyframes vsPulse {
    70% { box-shadow: 0 0 0 9px rgba(124, 255, 178, 0); }
    100% { box-shadow: 0 0 0 0 rgba(124, 255, 178, 0); }
}

/* ---------- Fun facts: use real photographs as the overlay ---------- */

.funfact-box img.overlay {
    object-fit: cover;
    filter: grayscale(1) contrast(1.05);
    opacity: 0.55;
}
.funfact-box.active img.overlay,
.funfact-box:hover img.overlay {
    opacity: 0.75;
}

/* ---------- Services ----------

   Reads like a product tile: the transformation first, one supporting line,
   then the specifics as chips. The visual is generated artwork rather than a
   sample photo, so each category has an identity and nothing is ever served
   below its display size. See tools/make-fractal-glass.sh. */

.service-sec {
    position: relative;
    overflow: hidden;
    padding: 0 0 40px;
}
.service-sec .custom-container { position: relative; z-index: 1; }

.service-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 24px;
    margin-top: 66px;
}

.service-card {
    display: flex;
    flex-direction: column;
    padding: 14px 14px 32px;
    color: #fff;
    overflow: hidden;
}

/* The figure is layered: real work at the back, a readability veil, then the
   fractal-glass pane sitting physically in front of the photograph. The pane
   blurs what is behind it, so it reads as glass rather than as a sticker. */
.service-figure {
    position: relative;
    border-radius: 16px;
    overflow: hidden;
    aspect-ratio: 3 / 2;
    background: #0d0d0d;
    flex: none;
}
.service-shot {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    /* The hover zoom scales about the element's centre by default, which would
       push the top of a top-anchored crop out of the frame and shave the head
       off again on hover. Pinning the origin to the top holds the focal point
       wherever object-position put it. */
    transform-origin: 50% 0;
    transition: transform 1.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.service-card:hover .service-shot { transform: scale(1.05); }

.service-veil {
    position: absolute;
    inset: 0;
    z-index: 1;
    background: linear-gradient(180deg,
        rgba(0, 0, 0, 0.10) 0%,
        rgba(0, 0, 0, 0.02) 40%,
        rgba(0, 0, 0, 0.62) 100%);
}

.service-pane {
    position: absolute;
    z-index: 2;
    left: 16px;
    right: 16px;
    bottom: 16px;
    display: flex;
    align-items: center;
    min-height: 62px;
    padding: 0 20px;
    border-radius: 14px;
    overflow: hidden;
    border: 1px solid rgba(255, 255, 255, 0.28);
    background: rgba(12, 12, 14, 0.34);
    backdrop-filter: blur(16px) saturate(150%);
    -webkit-backdrop-filter: blur(16px) saturate(150%);
    box-shadow:
        inset 0 1px 0 0 rgba(255, 255, 255, 0.34),
        0 14px 34px -12px rgba(0, 0, 0, 0.75);
    transition: transform 0.55s cubic-bezier(0.16, 1, 0.3, 1);
}
/* The category's colour signature, tinting the pane rather than filling it. */
.service-pane > img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0.55;
    mix-blend-mode: screen;
    pointer-events: none;
}
.service-card:hover .service-pane { transform: translateY(-3px); }

.service-label {
    position: relative;
    z-index: 1;
    font-size: 12.5px;
    font-weight: 600;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: #fff;
    text-shadow: 0 1px 10px rgba(0, 0, 0, 0.6);
}

.service-copy {
    display: flex;
    flex-direction: column;
    flex: 1;
    padding: 28px 16px 0;
}
.service-headline {
    margin: 0;
    font-size: 30px;
    font-weight: 500;
    line-height: 1.16;
    letter-spacing: -0.032em;
    color: #fff;
    max-width: 19ch;
}
.service-sub {
    margin: 16px 0 0;
    font-size: 16px;
    line-height: 26px;
    color: var(--vs-bright);
    max-width: 42ch;
}

/* Chips instead of a dashed list: the old hyphen bullets read as filler. */
.service-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 24px;
}
.service-chips li {
    padding: 7px 14px;
    border-radius: 40px;
    font-size: 12.5px;
    letter-spacing: 0.01em;
    color: var(--vs-bright);
    border: 1px solid rgba(255, 255, 255, 0.16);
    background: rgba(255, 255, 255, 0.05);
    backdrop-filter: blur(12px) saturate(150%);
    -webkit-backdrop-filter: blur(12px) saturate(150%);
    box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.14);
}

.service-go {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin-top: auto;
    padding-top: 30px;
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: #fff;
}
.service-go img {
    width: 12px;
    transition: transform 0.45s cubic-bezier(0.16, 1, 0.3, 1);
}
.service-card:hover .service-go img { transform: translate(4px, -4px); }

/* Film & Motion leads to the showreel, so its tile reads as a film. */
.service-play {
    position: absolute;
    inset: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    transition: background 0.4s;
}
.service-play i {
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 34px;
    width: 62px;
    height: 62px;
    padding-left: 3px;
    font-size: 19px;
    border-radius: 50%;
    /* Dark fill rather than light, so it holds up over a bright frame too. */
    border: 1px solid rgba(255, 255, 255, 0.62);
    background: rgba(10, 10, 12, 0.42);
    backdrop-filter: blur(14px) saturate(160%);
    -webkit-backdrop-filter: blur(14px) saturate(160%);
    box-shadow: 0 10px 30px -8px rgba(0, 0, 0, 0.8);
    transition: transform 0.4s, background 0.4s, color 0.4s;
}
.service-card:hover .service-play i {
    transform: scale(1.09);
    background: #fff;
    color: #000;
}

/* ---------- Email / Instagram quick actions ---------- */

.quick-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    margin-bottom: 40px;
}
.quick-btn {
    display: inline-flex;
    align-items: center;
    gap: 14px;
    padding: 13px 22px 13px 16px;
    border-radius: 40px;
    border: 1px solid rgba(255, 255, 255, 0.22);
    background: #141414;
    color: #fff;
    transition: background 0.3s, border-color 0.3s, transform 0.3s;
}
.quick-btn:hover {
    background: #fff;
    border-color: #fff;
    color: #000;
    transform: translateY(-2px);
}
.quick-btn > i {
    font-size: 22px;
    line-height: 1;
    flex: none;
}
.quick-btn span {
    display: flex;
    flex-direction: column;
    gap: 2px;
    line-height: 1.25;
}
.quick-btn span b {
    font-size: 15px;
    font-weight: 500;
}
.quick-btn span i {
    font-style: normal;
    font-size: 12px;
    color: var(--vs-dim);
}
.quick-btn:hover span i { color: #555; }

/* The footer widget styles its anchors at 40px inline-block via
   `.footer-contact-infos .footer-widget-top a`, so these need to out-specify
   that rather than just restate the button styles. */
.footer-widget .quick-actions {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    margin-bottom: 0;
    width: 100%;
    max-width: 320px;
}
.footer-contact-infos .footer-widget-top .quick-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 15px;
    line-height: 1.25;
    text-align: left;
    overflow-wrap: normal;
    /* Label only down here, so it needs less vertical padding than the
       two-line buttons in the contact section. */
    padding: 15px 24px;
    gap: 12px;
}

/* ---------- Contact showcase (vertical work reel) ---------- */

.contact-showcase {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
    height: 620px;
    overflow: hidden;
    mask-image: linear-gradient(to bottom, rgba(0,0,0,0) 0%, #000 14%, #000 86%, rgba(0,0,0,0) 100%);
    -webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,0) 0%, #000 14%, #000 86%, rgba(0,0,0,0) 100%);
}
.showcase-col { overflow: hidden; }
/* Spacing is a margin on each tile rather than a `gap`, so half the track is
   exactly one copy of the list including its trailing space. With `gap` the
   final space is missing and the -50% loop drifts by half a gap every cycle. */
.showcase-track {
    display: flex;
    flex-direction: column;
    will-change: transform;
}
.showcase-up   .showcase-track { animation: vsScrollUp 46s linear infinite; }
.showcase-down .showcase-track { animation: vsScrollDown 46s linear infinite; }
.contact-showcase:hover .showcase-track { animation-play-state: paused; }

.showcase-track figure {
    margin: 0 0 20px;
    flex: none;
    border-radius: 14px;
    overflow: hidden;
    aspect-ratio: 4 / 5;
    background: #0d0d0d;
}
/* Full colour here. The horizontal marquee above it does the grey-to-colour
   reveal; by the time you reach the form the work should just be in colour. */
.showcase-track img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform 1s;
}
.showcase-track figure:hover img {
    transform: scale(1.05);
}

/* The track holds the list twice, so half of it is one full cycle. */
@keyframes vsScrollUp {
    from { transform: translateY(0); }
    to   { transform: translateY(-50%); }
}
@keyframes vsScrollDown {
    from { transform: translateY(-50%); }
    to   { transform: translateY(0); }
}

/* ---------- Showreel (vertical films) ---------- */

.showreel-sec {
    padding: 140px 0 40px;
}
.reel-lists {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 28px;
    margin-top: 70px;
    /* 9:16 at full container width makes towers — keep the films poster-sized. */
    max-width: 1020px;
    margin-left: auto;
    margin-right: auto;
}
.reel-card {
    position: relative;
    border-radius: 20px;
    overflow: hidden;
    background: linear-gradient(180deg, #1f1f1f 0%, #000 40%, #000 60%, #1f1f1f 100%);
    padding: 10px;
}
.reel-media {
    position: relative;
    border-radius: 14px;
    overflow: hidden;
    aspect-ratio: 9 / 16;
    background: #0a0a0a;
    cursor: pointer;
}
.reel-media video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.reel-media::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(0,0,0,0.35) 0%, transparent 30%, transparent 62%, rgba(0,0,0,0.75) 100%);
    pointer-events: none;
    transition: opacity 0.4s;
}
.reel-card.is-playing .reel-media::after { opacity: 0.35; }

.reel-controls {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 2;
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 12px;
    padding: 22px;
}
.reel-meta {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}
.reel-meta .reel-title {
    font-size: 20px;
    font-weight: 500;
    letter-spacing: -0.02em;
    color: #fff;
}
.reel-meta .reel-tag {
    font-size: 11px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: #b3b3b3;
}
.reel-btns { display: flex; gap: 10px; flex: none; }
.reel-btn {
    width: 44px;
    height: 44px;
    flex: none;
    border-radius: 50%;
    border: 1px solid rgba(255,255,255,0.35);
    background: rgba(20,20,20,0.55);
    backdrop-filter: blur(8px);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 17px;
    cursor: pointer;
    transition: 0.3s;
    padding: 0;
}
.reel-btn:hover {
    background: #fff;
    color: #000;
    border-color: #fff;
}
.reel-btn .icon-pause,
.reel-card.is-playing .reel-btn .icon-play { display: none; }
.reel-card.is-playing .reel-btn .icon-pause { display: block; }
.reel-btn .icon-unmute { display: none; }
.reel-card.is-unmuted .reel-btn .icon-unmute { display: block; }
.reel-card.is-unmuted .reel-btn .icon-mute { display: none; }

/* ---------- Photo marquee (real work, replaces stock testimonials) ---------- */

.photo-marquee-sec {
    padding: 40px 0 20px;
    overflow: hidden;
    mask-image: linear-gradient(to right, rgba(0,0,0,0) 0%, #000 10%, #000 90%, rgba(0,0,0,0) 100%);
    -webkit-mask-image: linear-gradient(to right, rgba(0,0,0,0) 0%, #000 10%, #000 90%, rgba(0,0,0,0) 100%);
}
/* Margin, not `gap`, for the same seamless-loop reason as the vertical reel. */
.photo-marquee {
    display: flex;
    width: max-content;
    animation: vsMarquee 60s linear infinite;
}
.photo-marquee:hover { animation-play-state: paused; }
.photo-marquee figure {
    margin: 0 20px 0 0;
    flex: none;
    width: 300px;
    height: 210px;
    border-radius: 14px;
    overflow: hidden;
}
.photo-marquee img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    filter: grayscale(1);
    transition: filter 0.5s, transform 0.9s;
}
.photo-marquee figure:hover img {
    filter: grayscale(0);
    transform: scale(1.06);
}
@keyframes vsMarquee {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}

/* ---------- Work index grid ---------- */

.work-grid-sec { padding: 40px 0 120px; }
.work-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 28px;
}
/* The whole card is the affordance. There used to be a 96px "View" disc that
   scaled in on hover, which meant nothing happened until you noticed a badge
   land on the photograph. A quiet lift and a lift in the image reads as the
   card responding, and it never covers the frame it is advertising. */
.work-card {
    position: relative;
    display: block;
    border-radius: 20px;
    overflow: hidden;
    background: #0d0d0d;
    transition: transform 0.55s cubic-bezier(0.16, 1, 0.3, 1);
}
.work-card:hover { transform: translateY(-4px); }
.work-card .work-media {
    position: relative;
    overflow: hidden;
    aspect-ratio: 16 / 10;
}
.work-card.is-tall .work-media { aspect-ratio: 4 / 5; }
.work-card img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transform: scale(1.02);
    transition: transform 1.1s cubic-bezier(0.16, 1, 0.3, 1), filter 0.6s;
}
.work-card:hover img { transform: scale(1.08); }
.work-card .work-info {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 20px;
    padding: 24px 28px 28px;
}
.work-card .work-info .name {
    font-size: 28px;
    font-weight: 400;
    letter-spacing: -0.03em;
    color: #fff;
    margin: 0 0 6px;
}
.work-card .work-info .cat {
    font-size: 11px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--vs-dim);
}
.work-card .work-info .year {
    font-size: 13px;
    color: var(--vs-dim);
    flex: none;
}

/* ---------- Project detail ---------- */

/* A project page opens on the title, the blurb and then the meta bar. The
   full-bleed cover slab that used to sit between them showed the same frame the
   visitor had just clicked to get here, and cost a screen of scrolling before
   the series itself started. */
.project-meta-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 40px 90px;
    padding: 0 72px 90px;
    border-bottom: 1px solid var(--vs-line);
    margin: 0 0 90px;
}
.project-meta-bar .meta {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.project-meta-bar .meta .k {
    font-size: 11px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--vs-dim);
}
.project-meta-bar .meta .v {
    font-size: 20px;
    color: #fff;
    letter-spacing: -0.01em;
}

/* Justified rows: each figure's flex-grow is its aspect ratio and flex-basis is
   0, so widths come out proportional to aspect and every image in a row lands
   on exactly the same height. No stretched boxes, no empty gaps, and portrait
   frames sit several across instead of one giant image per row. */
.gallery-sec { padding: 0 72px 120px; }
.gallery-grid {
    display: flex;
    flex-direction: column;
    gap: 24px;
}
.g-row {
    display: flex;
    gap: 24px;
}
/* A short trailing row keeps the height of the rows above it. */
.g-row.is-short { max-width: calc(100% * var(--fill, 1)); }

.g-row figure {
    margin: 0;
    flex: var(--a, 1.5) 1 0;
    min-width: 0;
    /* Width comes from flex-grow (= aspect); this turns that into a height.
       height = width / aspect, and since width is proportional to aspect,
       every figure in the row resolves to the same height. */
    aspect-ratio: var(--a, 1.5);
    border-radius: 16px;
    overflow: hidden;
    background: #0d0d0d;
}
.g-row img {
    width: 100%;
    height: 100%;
    display: block;
    object-fit: cover;
    transition: transform 1.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.g-row figure:hover img { transform: scale(1.03); }

.next-project {
    border-top: 1px solid var(--vs-line);
    padding: 90px 72px 110px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 30px;
    flex-wrap: wrap;
}
.next-project .label {
    font-size: 11px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--vs-dim);
    display: block;
    margin-bottom: 14px;
}
.next-project h3 {
    margin: 0;
    font-family: var(--font_arapey);
    font-weight: 300;
    font-size: clamp(38px, 6vw, 82px);
    line-height: 1;
    letter-spacing: -0.03em;
    color: #fff;
}
.next-project a:hover h3 { opacity: 0.7; transition: opacity 0.4s; }

/* ---------- Approach / process list ---------- */

.approach-list {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0;
    border-top: 1px solid var(--vs-line);
}
.approach-item {
    padding: 54px 44px 60px;
    border-bottom: 1px solid var(--vs-line);
    border-right: 1px solid var(--vs-line);
}
.approach-item:nth-child(3n) { border-right: none; }
/* Each stage is a floating glass object, moving in the same slow, weightless
   register as the hero animation so the two read as one system. Transform and
   opacity only, so it stays cheap on a phone. */
.approach-object {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 210px;
    margin-bottom: 26px;
}
.obj-halo {
    position: absolute;
    inset: 12% 14%;
    border-radius: 50%;
    background: radial-gradient(circle at 42% 38%,
        rgba(255, 255, 255, 0.16) 0%,
        rgba(150, 175, 255, 0.10) 42%,
        transparent 72%);
    filter: blur(20px);
    animation: vsObjHalo 9s ease-in-out infinite alternate;
}
.approach-object .obj-svg,
.approach-object .obj-render {
    position: relative;
    z-index: 1;
    width: 168px;
    height: 168px;
    object-fit: contain;
    display: block;
    filter: drop-shadow(0 18px 30px rgba(0, 0, 0, 0.6));
    animation: vsObjFloat 8s ease-in-out infinite alternate;
}
/* The generated forms turn slowly; a supplied render keeps its own orientation
   and only floats, so nothing looks like it is spinning on a flat plane. */
.approach-object .obj-svg .obj-body {
    transform-origin: 100px 100px;
    animation: vsObjTurn 34s linear infinite;
}
.approach-item:nth-child(2) .obj-svg,
.approach-item:nth-child(2) .obj-render { animation-delay: -2.6s; }
.approach-item:nth-child(3) .obj-svg,
.approach-item:nth-child(3) .obj-render { animation-delay: -5.2s; }
.approach-item:nth-child(2) .obj-halo { animation-delay: -3s; }
.approach-item:nth-child(3) .obj-halo { animation-delay: -6s; }

.approach-item:hover .obj-svg,
.approach-item:hover .obj-render { animation-play-state: paused; transform: scale(1.06); }

@keyframes vsObjFloat {
    from { transform: translate3d(0, -9px, 0) rotate(-2.5deg); }
    to   { transform: translate3d(0, 9px, 0) rotate(2.5deg); }
}
@keyframes vsObjTurn {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}
@keyframes vsObjHalo {
    from { opacity: 0.55; transform: scale(0.92); }
    to   { opacity: 1; transform: scale(1.08); }
}

.approach-item .num {
    position: absolute;
    left: 0;
    bottom: 4px;
    z-index: 2;
    font-size: 34px;
    font-weight: 200;
    letter-spacing: -0.03em;
    color: var(--vs-bright);
    line-height: 1;
}
.approach-item h4 {
    font-size: 24px;
    font-weight: 500;
    letter-spacing: -0.02em;
    color: #fff;
    margin: 0 0 14px;
}
.approach-item p {
    margin: 0;
    font-size: 15px;
    line-height: 24px;
    color: var(--vs-dim);
}

/* ---------- Contact ---------- */

.contact-sec .contact-form .form-note {
    font-size: 12px;
    color: var(--vs-dim);
    margin: 14px 0 0;
    line-height: 20px;
}
#result {
    margin-top: 18px;
    font-size: 14px;
    line-height: 22px;
    color: #fff;
    display: none;
}
/* main.js applies these two class names after a Web3Forms round trip. */
#result.text-green-500 { color: #7CFFB2; }
#result.text-red-500   { color: #FF8080; }

.contact-direct {
    display: flex;
    flex-wrap: wrap;
    gap: 14px 40px;
    margin-bottom: 40px;
}
.contact-direct a {
    color: #fff;
    font-size: 18px;
    letter-spacing: -0.01em;
}
.contact-direct .k {
    display: block;
    font-size: 11px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--vs-dim);
    margin-bottom: 8px;
}

/* ---------- Hero animation in an inner-page slot ---------- */

.hero-shape-video {
    position: absolute;
    right: -30px;
    /* Lifted clear of the CTA that sits on the hero's bottom-right. */
    bottom: 118px;
    width: 520px;
    height: 470px;
    object-fit: contain;
    z-index: -1;
    pointer-events: none;
}
@media (max-width: 991px) {
    .hero-shape-video { width: 340px; height: 320px; right: -60px; bottom: 150px; opacity: 0.75; }
}
@media (max-width: 767px) {
    .hero-shape-video { width: 260px; height: 250px; right: -50px; bottom: 190px; }
}

/* ---------- Off-canvas menu ----------
   Was a translucent panel with a photograph floating behind the links, which
   made them unreadable. Now solid glass, no image, and the links are the size
   they should be on a phone. */

.header-sidebar-wrap {
    background: rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}
.header-sidebar-wrap .header-sidebar-content {
    background:
        linear-gradient(165deg,
            rgba(34, 34, 37, 0.94) 0%,
            rgba(14, 14, 16, 0.97) 55%,
            rgba(8, 8, 10, 0.99) 100%);
    backdrop-filter: blur(30px) saturate(150%);
    -webkit-backdrop-filter: blur(30px) saturate(150%);
    border-left: 1px solid rgba(255, 255, 255, 0.12);
    gap: 48px;
    justify-content: center;
}
/* The panel gets the same glass as the header pill: one slow specular pass on
   open, contained, then still.

   Only the horizontal inset is negative. The panel already clips overflow-x, so
   the sweep is contained on the axis it travels, while staying inside the box
   vertically — widening it there would add scrollable height to the menu. */
.header-sidebar-wrap .header-sidebar-content::before {
    content: "";
    position: absolute;
    inset: 0 -30%;
    z-index: 0;
    pointer-events: none;
    background: linear-gradient(112deg,
        transparent 40%,
        rgba(255, 255, 255, 0.07) 50%,
        transparent 60%);
    transform: translateX(-110%);
    transition: transform 1.6s cubic-bezier(0.16, 1, 0.3, 1);
}
.header-sidebar-wrap.active .header-sidebar-content::before {
    transform: translateX(110%);
    transition-delay: 0.25s;
}
.header-sidebar-wrap .header-sidebar-content .sidebar-menu,
.header-sidebar-wrap .header-sidebar-content .header-sidebar-top,
.header-sidebar-wrap .header-sidebar-content .header-sidebar-bottom { position: relative; z-index: 1; }
.header-sidebar-wrap .header-sidebar-content .sidebar-menu ul { position: relative; z-index: 1; }
.header-sidebar-wrap .header-sidebar-content .close-header-sidebar { z-index: 2; }

.header-sidebar-wrap .header-sidebar-content .sidebar-menu ul { gap: 6px; }
.header-sidebar-wrap .header-sidebar-content .sidebar-menu ul li a {
    font-size: 44px;
    line-height: 1.3;
    color: #fff;
    letter-spacing: -0.02em;
    /* Room for the glass to sit behind the word without the text moving, and
       only as wide as the word itself so the droplet tracks the label rather
       than the full width of the panel. The inset has to stay inside the
       panel's own padding, which is 64px here and 25px on a phone. */
    --lg-inset: 26px;
    padding: 6px var(--lg-inset);
    margin-left: calc(var(--lg-inset) * -1);
    width: fit-content;
    border-radius: 999px;
    transition: color 0.4s ease, opacity 0.4s ease;
}
/* No dots. The template marked the hovered link with a bullet and shoved the
   word 20px sideways; the glass below carries that job now, and nothing jumps. */
.header-sidebar-wrap .header-sidebar-content .sidebar-menu ul li a:before {
    display: none;
}
.header-sidebar-wrap .header-sidebar-content .sidebar-menu ul li a:hover {
    color: #fff;
    opacity: 1;
    padding-left: var(--lg-inset);
}
@media (max-width: 991px) {
    .header-sidebar-wrap .header-sidebar-content .sidebar-menu ul li a { --lg-inset: 16px; }
}

/* Same droplet as the header, running vertically down the list. */
.header-sidebar-wrap .header-sidebar-content .sidebar-menu .menu-liquid {
    /* Sits before the list, so it paints under the links without needing a
       negative z-index (which would drop it behind the panel itself). */
    position: absolute;
    z-index: 0;
    inset: 0 auto auto 0;
    width: 0;
    height: 0;
    border-radius: 999px;
    pointer-events: none;
    background:
        linear-gradient(150deg,
            rgba(255, 255, 255, 0.13) 0%,
            rgba(255, 255, 255, 0.04) 55%,
            rgba(255, 255, 255, 0.09) 100%);
    backdrop-filter: blur(14px) saturate(160%);
    -webkit-backdrop-filter: blur(14px) saturate(160%);
    box-shadow:
        inset 0 1px 0 0 rgba(255, 255, 255, 0.26),
        inset 0 -1px 0 0 rgba(255, 255, 255, 0.05);
    opacity: 0;
    transform: translate(var(--x, 0px), var(--y, 0px));
    transition:
        transform 0.6s cubic-bezier(0.22, 1.1, 0.36, 1),
        width 0.6s cubic-bezier(0.22, 1.1, 0.36, 1),
        height 0.6s cubic-bezier(0.22, 1.1, 0.36, 1),
        opacity 0.35s ease;
}
.header-sidebar-wrap .header-sidebar-content .sidebar-menu.is-liquid .menu-liquid {
    opacity: 1;
}
/* The template laid this out as two flex columns 76px apart with a 95px label,
   which collapses into ragged wrapping on a phone. Stacked label-over-value
   works at every width. */
.header-sidebar-wrap .header-sidebar-content .header-sidebar-top ul { gap: 18px; }
.header-sidebar-wrap .header-sidebar-content .header-sidebar-top ul li {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
}
.header-sidebar-wrap .header-sidebar-content .header-sidebar-top ul li span {
    min-width: 0;
    font-size: 10.5px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--vs-dim);
}
.header-sidebar-wrap .header-sidebar-content .header-sidebar-top ul li a {
    font-size: 15px;
    line-height: 22px;
    color: #fff;
    overflow-wrap: anywhere;
}
.header-sidebar-wrap .header-sidebar-content .close-header-sidebar {
    width: 46px;
    height: 46px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, 0.22);
    background: rgba(255, 255, 255, 0.07);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
}

/* The hamburger itself gets the same glass treatment. */
.scroll-to-show-menu .hamburg-menu {
    background: rgba(255, 255, 255, 0.08);
    backdrop-filter: blur(16px) saturate(160%);
    -webkit-backdrop-filter: blur(16px) saturate(160%);
    border: 1px solid rgba(255, 255, 255, 0.2);
    box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.22);
}

/* ---------- Buttons: same glass language ---------- */

.theme-btn {
    background: rgba(255, 255, 255, 0.07);
    backdrop-filter: blur(18px) saturate(160%);
    -webkit-backdrop-filter: blur(18px) saturate(160%);
    border-color: rgba(255, 255, 255, 0.28);
    box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.18);
    letter-spacing: 0.01em;
}
.quick-btn {
    background: rgba(255, 255, 255, 0.06);
    backdrop-filter: blur(18px) saturate(160%);
    -webkit-backdrop-filter: blur(18px) saturate(160%);
    box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.16);
}
.reel-btn {
    backdrop-filter: blur(16px) saturate(170%);
    -webkit-backdrop-filter: blur(16px) saturate(170%);
    box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.2);
}
.hero-availability {
    padding: 8px 16px 8px 13px;
    border-radius: 40px;
    border: 1px solid rgba(255, 255, 255, 0.16);
    background: rgba(255, 255, 255, 0.05);
    backdrop-filter: blur(16px) saturate(160%);
    -webkit-backdrop-filter: blur(16px) saturate(160%);
    box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.16);
    color: var(--vs-bright);
}

/* ---------- The small labels ("legend") ---------- */

.section-subtitle {
    font-size: 12px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--vs-bright);
    gap: 14px;
}

/* ---------- Motion ---------- */

/* site.js sets this on the marquee / reel tracks while they are off screen. */
.is-paused { animation-play-state: paused !important; }

/* The magic cursor is a pointer affordance. On a touch screen it was rendering
   as a stray white dot floating over the page. */
@media (hover: none), (pointer: coarse) {
    #magic-cursor, #ball { display: none !important; }
}

/* The off-canvas menu image floats forever behind a hidden panel. */
.header-sidebar-wrap:not(.active) .sidebar-shape { animation: none; }

/* AOS ships a flat ease; this gives the gallery rows and cards a softer,
   less mechanical settle. */
[data-aos] {
    transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1) !important;
}
[data-aos="fade-up"] {
    transform: translate3d(0, 34px, 0);
}

@media (prefers-reduced-motion: reduce) {
    .photo-marquee,
    .showcase-track,
    .funfact-box img.overlay,
    .service-box .service-inner .service-img-box img {
        animation: none !important;
    }
    [data-aos] {
        transition-duration: 0.01ms !important;
        transform: none !important;
    }
}

/* ---------- Responsive ---------- */

@media (max-width: 1439px) {
    /* responsive.css hides the links below this width but leaves the pill
       standing, so an empty piece of glass was floating beside the wordmark
       with nothing in it and nothing to do. */
    .header-menu-wrap .navbar { display: none; }

    /* The header switcher would land on top of the fixed hamburger here. The
       pop-up menu carries the languages at these widths instead. */
    .lang-switch { display: none; }

    /* main.js only scales the hamburger up past 100px of scroll. That was
       survivable while the pill was at least visible; with it gone there would
       be no way into the menu at the top of the page. */
    .scroll-to-show-menu .hamburg-menu { transform: scale(1); }
}

@media (max-width: 1399px) {
    .project-meta-bar,
    .gallery-sec,
    .next-project { padding-left: 40px; padding-right: 40px; }
}

@media (max-width: 1399px) {
    .service-grid { gap: 20px; }
    .service-headline { font-size: 27px; }
}

@media (max-width: 1199px) {
    .reel-lists { grid-template-columns: repeat(3, 1fr); gap: 18px; }
    .approach-list { grid-template-columns: repeat(2, 1fr); }
    .approach-item:nth-child(3n) { border-right: 1px solid var(--vs-line); }
    .approach-item:nth-child(2n) { border-right: none; }
}

@media (max-width: 991px) {
    .service-grid { grid-template-columns: 1fr; }
    .service-headline { font-size: 29px; }
}

@media (max-width: 991px) {
    .work-grid { grid-template-columns: 1fr; }
    .reel-lists { grid-template-columns: 1fr; max-width: 420px; margin-left: auto; margin-right: auto; }
    .project-meta-bar { gap: 30px 50px; }
    .g-row { gap: 16px; }
    .gallery-grid { gap: 16px; }
}

@media (max-width: 991px) {
    /* Type on a phone was set at desktop's small end and in the template's
       darkest greys, which is why it was hard to read. Everything below is
       size and contrast, not decoration. */
    .logo .wordmark b { font-size: 19px; letter-spacing: 0.15em; }

    .section-header .section-title { font-size: 30px; line-height: 40px; letter-spacing: -0.01em; }
    .section-title.section-title2 { font-size: 46px; line-height: 1.06; }
    .section-header .section-desc { font-size: 15px; line-height: 24px; color: var(--vs-bright); }
    .section-subtitle { font-size: 12px; }

    .hero-sec .hero-bottom h2,
    .hero-sec .hero-bottom .hero-title > span { font-size: 52px; line-height: 1.04; }
    .hero-lede { font-size: 16px; line-height: 25px; color: var(--vs-bright); }
    .hero-availability { font-size: 11.5px; }

    .funfact-box .funfact-header .title { font-size: 15px; }
    .approach-item p { font-size: 15.5px; line-height: 25px; color: var(--vs-bright); }
    .project-single-content-wrap .section-header p,
    .project-single-content-wrap .section-header .section-desc { font-size: 16px; line-height: 26px; }
    .project-meta-bar .meta .v { font-size: 17px; }
    .contact-sec .contact-content > p { font-size: 15px; line-height: 24px; }
    .work-card .work-info .cat { font-size: 11.5px; }
    .footer-link ul li a { font-size: 14px; }
    .footer-widget .copyright { font-size: 13px; }
}

@media (max-width: 767px) {
    .service-card { padding: 12px 12px 26px; border-radius: 20px; }
    .service-copy { padding: 24px 10px 0; }
    .service-headline { font-size: 27px; max-width: none; }
    .service-sub { font-size: 15.5px; line-height: 25px; }
    .service-chips li { font-size: 12px; padding: 6px 12px; }

    /* Two lines so the name is prominent instead of being shaved off at the
       viewport edge by .footer-bottom's overflow:hidden. Stacked, the widest
       line is "STOJANOVIC" on its own at 5.85em, and 40px of gutter keeps it
       clear of both edges on the narrowest phone. */
    .footer-area .footer-bottom { height: auto; padding: 30px 0 40px; }
    .footer-area .footer-bottom .footer-wordmark {
        font-size: 15.6vw;
        font-size: min(15.6vw, calc((100cqw - 40px) / 5.85));
        line-height: 1.04;
    }
    .footer-area .footer-bottom .footer-wordmark span { display: block; }

    .showreel-sec { padding-top: 90px; }
    .project-meta-bar,
    .gallery-sec,
    .next-project { padding-left: 20px; padding-right: 20px; }
    /* Justified rows get too short to read on a phone, so each frame goes
       full width at its own natural aspect ratio. */
    .g-row { flex-direction: column; gap: 16px; }
    .g-row.is-short { max-width: 100%; }
    .g-row figure { flex: none; aspect-ratio: var(--a, 1.5); }

    .approach-list { grid-template-columns: 1fr; }
    .approach-item { border-right: none !important; padding: 40px 20px 44px; }
    .photo-marquee figure { width: 220px; height: 155px; }

    /* responsive.css hides .contact-sec .right on phones. The showcase is worth
       keeping, just shorter, and it sits below the form in source order.
       One column instead of two halves the number of tiles a phone has to
       decode and composite. */
    .contact-sec .right { display: block; }
    .contact-showcase {
        height: 380px;
        margin-top: 40px;
        grid-template-columns: 1fr;
    }
    .contact-showcase .showcase-down { display: none; }

    .quick-actions { flex-direction: column; align-items: stretch; }
    .quick-btn { justify-content: flex-start; }
    .hero-lede { font-size: 15px; line-height: 23px; margin-top: 18px; }
    .work-card .work-info { padding: 20px; }
    .work-card .work-info .name { font-size: 22px; }
    .contact-direct { gap: 20px 30px; }
}

/* The language row added a block to an off-canvas panel that was already sized
   to fill the screen. These live at the end of the file on purpose: the base
   .header-sidebar-content rules further up carry the same specificity, so an
   override placed beside them would lose on source order. */
@media (max-width: 991px) {
    .header-sidebar-wrap .header-sidebar-content { gap: 30px; }
    .header-sidebar-wrap .header-sidebar-content .header-sidebar-bottom {
        gap: 18px;
        padding-bottom: 34px;
    }
    .header-sidebar-wrap .header-sidebar-content .sidebar-menu ul li a {
        font-size: 36px;
        line-height: 1.2;
    }
}

/* Short phones in portrait, and anything in landscape. Below this the menu
   would need to scroll, which on an overlay reads as broken rather than long. */
@media (max-height: 720px) and (max-width: 991px) {
    .header-sidebar-wrap .header-sidebar-content { gap: 22px; }
    .header-sidebar-wrap .header-sidebar-content .sidebar-menu ul { gap: 2px; }
    .header-sidebar-wrap .header-sidebar-content .sidebar-menu ul li a {
        font-size: 28px;
        line-height: 1.18;
        padding-top: 4px;
        padding-bottom: 4px;
    }
    .header-sidebar-wrap .header-sidebar-content .header-sidebar-bottom {
        gap: 14px;
        padding-bottom: 26px;
    }
    .sidebar-langs .k { margin-bottom: 8px; }
    .header-sidebar-wrap .header-sidebar-content .header-sidebar-bottom .sidebar-langs ul { gap: 6px; }
    .header-sidebar-wrap .header-sidebar-content .header-sidebar-bottom .sidebar-langs ul li a {
        padding: 5px 11px;
        font-size: 11.5px;
    }
}
