/* ============================================
    Double Dash Creative - Main Stylesheet
   ============================================ */

/* Font Face Declarations */
@font-face {
    font-family: 'Big Shoulders';
    src: url('../assets/fonts/BigShoulders-VariableFont_opsz,wght.woff2') format('woff2');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Archivo';
    src: url('../assets/fonts/Archivo-VariableFont_wdth,wght.woff2') format('woff2');
    font-weight: 100 900;
    font-stretch: 62% 125%;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Archivo';
    src: url('../assets/fonts/Archivo-Italic-VariableFont_wdth,wght.woff2') format('woff2');
    font-weight: 100 900;
    font-stretch: 62% 125%;
    font-style: italic;
    font-display: swap;
}

@font-face {
    font-family: 'Instrument Serif';
    src: url('../assets/fonts/InstrumentSerif-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Instrument Serif';
    src: url('../assets/fonts/InstrumentSerif-Italic.woff2') format('woff2');
    font-weight: 400;
    font-style: italic;
    font-display: swap;
}

/* ============================================
   CSS Custom Properties (Design Tokens)
   ============================================ */
:root {
    /* Primary Colors */
    --color-red: #FC6935;    /* orange (primary accent) */
    --color-cream: #FAFAFF;  /* off-white (text on dark) */
    --color-pink: #2E2B8A;   /* indigo (secondary accent) */
    --color-black: #000000;
    --color-mint: #FAFAFF;

    /* Neutrals */
    --color-gray-placeholder: #1c1c1c;
    --color-gray-dark: #111111;

    /* Typography */
    --font-display: 'Big Shoulders', 'Archivo', sans-serif;
    --font-marker: 'Instrument Serif', Georgia, serif;
    --font-body: 'Archivo', sans-serif;

    /* Fluid type scale - tier 1 (display) to tier 6 (caption).
       Each clamp keeps a legible floor on small screens and a cap on
       large ones. Use these everywhere instead of ad-hoc vw / clamp.
       Rough sizes:            mobile ~375px   desktop ~1440px
         --fs-1  display          ~46px           ~100px
         --fs-2  page title       ~36px           ~64px
         --fs-3  section / card   ~28px           ~44px
         --fs-4  sub-head / lead  ~22px           ~30px
         --fs-5  body             ~17px           ~19px
         --fs-6  caption / label  ~13px           ~15px               */
    --fs-1: clamp(2.75rem, 1.5rem + 6vw, 6.25rem);
    --fs-2: clamp(2.15rem, 1.5rem + 3.2vw, 4rem);
    --fs-3: clamp(1.7rem, 1.35rem + 1.8vw, 2.75rem);
    --fs-4: clamp(1.3rem, 1.15rem + 0.9vw, 1.9rem);
    --fs-5: clamp(1.05rem, 1rem + 0.25vw, 1.2rem);
    --fs-6: clamp(0.82rem, 0.78rem + 0.18vw, 0.92rem);

    /* Spacing Scale */
    --space-xs: 0.5rem;
    --space-sm: 1rem;
    --space-md: 1.5rem;
    --space-lg: 2rem;
    --space-xl: 3rem;
    --space-2xl: 4rem;
    --space-3xl: 6rem;
    --space-4xl: 8rem;

    /* Container */
    --container-max: 1200px;
    --container-padding: 2rem;

    /* The left/right edge everything lines up on: the nav container's
       padding plus the logo's indent. Shrinks to a plain gutter on
       phones, where the nav drops the indent too. */
    --page-inset: calc(var(--space-xl) + clamp(0px, 6vw, 7rem));

    /* Transitions */
    --transition-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
    --transition-smooth: cubic-bezier(0.4, 0, 0.2, 1);

    /* Border Radius */
    --radius-sm: 4px;
    --radius-md: 8px;
    --radius-lg: 16px;
    --radius-full: 50px;
}

/* ============================================
   Reset & Base Styles
   ============================================ */
*,
*::before,
*::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

::selection {
  background: rgb(252, 105, 53, 0.7);
  color: var(--color-black);
}

html {
    scroll-behavior: smooth;
}

/* Lenis smooth (inertial) scrolling - required styles */
.lenis, .lenis body {
    height: auto;
}

.lenis.lenis-smooth {
    scroll-behavior: auto !important;
}

.lenis.lenis-smooth [data-lenis-prevent] {
    overscroll-behavior: contain;
}

.lenis.lenis-stopped {
    overflow: clip;
}

.lenis.lenis-smooth iframe {
    pointer-events: none;
}

body {
    font-family: var(--font-body);
    font-size: var(--fs-5);
    background-color: var(--color-black);
    color: var(--color-cream);
    line-height: 1.2;
    overflow-x: hidden;
}

.container,
.work-container {
    width: 100%;
    max-width: var(--container-max);
    margin: 0 auto;
    padding: 0 var(--container-padding);
}

@media (max-width: 640px) {

    .work-container {
        padding: 1rem;
    }

}

img {
    max-width: 100%;
    height: auto;
    display: block;
}

a {
    text-decoration: none;
    color: inherit;
    transition: color 0.3s var(--transition-smooth);
}

button {
    font-family: inherit;
    cursor: pointer;
    border: none;
    background: none;
}

/* ============================================
   Animation Keyframes
   ============================================ */
@keyframes bounceIn {
    0% {
        opacity: 0;
        transform: scale(0.3);
    }

    50% {
        transform: scale(1.05);
    }

    70% {
        transform: scale(0.9);
    }

    100% {
        opacity: 1;
        transform: scale(1);
    }
}

@keyframes slideInLeft {
    from {
        opacity: 0;
        transform: translateX(-50px);
    }

    to {
        opacity: 1;
        transform: translateX(0);
    }
}

@keyframes slideInRight {
    from {
        opacity: 0;
        transform: translateX(50px);
    }

    to {
        opacity: 1;
        transform: translateX(0);
    }
}

/* ============================================
   Typography
   ============================================ */
h1,
h2,
h3,
h4 {
    font-family: var(--font-display);
    font-weight: normal;
    line-height: 1.1;
    text-transform: uppercase;
}

.heading-lg {
    font-size: var(--fs-2);
}

/* ============================================
   Layout Utilities
   ============================================ */
.section {
    padding: var(--space-3xl) 0;
}

.sm-section {
    padding: none;
}

/* ============================================
   Portfolio Grid (Work Page)

@media (max-width: 576px) {

    .portfolio-grid.cols-3,

}

/* ============================================
   Navigation
   ============================================ */
.navbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1000;
    padding: 0.9rem 0;
    background-color: transparent;
    transition: transform 0.55s var(--transition-smooth),
        opacity 0.4s var(--transition-smooth);
}

/* Every page carries the black bar from the top. The homepage is the
   exception: it rides transparent over the liquid hero and pops the
   backdrop in when the "For Dreamers" divider passes the middle of the
   viewport (initHeroBgFade toggles .is-solid; initNavbar does it
   everywhere else). */
.navbar::before {
    content: '';
    position: absolute;
    inset: 0;
    background-color: var(--color-black);
    opacity: 1;
    /* background-color is in the list because [data-nav-tint] recolours it */
    transition: opacity 0.4s var(--transition-smooth),
        background-color 0.4s var(--transition-smooth);
    z-index: -1;
}

.page-home .navbar::before { opacity: 0; }
.page-home .navbar.is-solid::before { opacity: 1; }

.navbar.is-solid::before {
    opacity: 1;
}

.navbar .container {
    max-width: none;
    padding: 0 var(--space-xl);
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;

    /* a floor, so the bar keeps its shape if the logo ever fails to load */
    min-height: 3.25rem;
    align-content: center;
}

/* grid-row: 1 on every one of these. Without it, an item asking for a
   later column before one asking for an earlier column makes grid wrap
   the second onto a new row, because auto-placement never backtracks. */
.navbar .logo { grid-column: 1; grid-row: 1; justify-self: start; margin-left: clamp(0px, 6vw, 7rem); }
.navbar .nav-links { grid-column: 2; grid-row: 1; justify-self: center; }
.navbar .mobile-menu-toggle { grid-column: 3; grid-row: 1; justify-self: end; }

.logo {
    display: flex;
    align-items: center;
    gap: 0.1rem;
    text-decoration: none;
    color: var(--color-cream);
    transform: scale(1);
    transition: transform 0.1s ease-in-out,
        opacity 0.3s var(--transition-smooth);
}

.logo-mark {
    display: block;
    height: 66px;
    width: auto;
    /* filter, for the nav tint over a coloured band */
    transition: filter 0.4s var(--transition-smooth);
}

@media (max-width: 640px) {
    .logo-mark { height: 48px; }
}

.logo-and {
    color: var(--color-red);
}

.logo:hover {
    transform: scale(1.1);
    transition: transform 0.3s ease-in-out, color 0.5s ease;

    svg,
    .logo-and {
        color: var(--color-pink);
    }

    .logo-and {
        color: var(--color-pink);
    }
}

.logo svg {
    width: 40px;
    height: auto;
    color: var(--color-red);
}

/* Lottie Logo Styling */
#lottie-logo {
    width: 40px;
    height: 53px;
    display: flex;
    align-items: center;
    justify-content: center;
}

#lottie-logo svg {
    width: 100%;
    height: 100%;
}

/* Apply red color to Lottie animation paths */
#lottie-logo svg path {
    stroke: var(--color-red) !important;
    fill: var(--color-red) !important;
}

.logo:hover #lottie-logo svg path {
    stroke: var(--color-pink) !important;
    fill: var(--color-pink) !important;
}

.nav-links {
    display: flex;
    gap: var(--space-lg);
    list-style: none;
}

/* Text Cycling Animation for Nav Links */
.nav-link-cycle {
    font-family: var(--font-body);
    font-size: 0.8rem;
    text-transform: uppercase;
    color: var(--color-cream);
    text-decoration: none;
    position: relative;
    display: inline-block;
    overflow: hidden;
    transition: color 0.4s var(--transition-smooth);
}

.nav-link-cycle span {
    display: inline-block;
    position: relative;
    transition: transform 0.4s var(--transition-bounce);
}

.nav-link-cycle span::before {
    content: attr(data-text);
    position: absolute;
    top: 100%;
    left: 0;
}

.nav-link-cycle:hover span {
    transform: translateY(-100%);
}

/*.page-cream .nav-link-cycle {
    color: var(--color-black);
}

.page-cream .nav-link-cycle span::before {
    color: var(--color-red);
}*/

.nav-links a {
    font-family: var(--font-body);
    font-size: 0.875rem;
    text-transform: uppercase;
    color: var(--color-cream);
    text-decoration: none;
    position: relative;
}

.nav-links a:not(.nav-link-cycle)::after {
    content: '';
    position: absolute;
    bottom: -4px;
    left: 0;
    width: 0;
    height: 2px;
    background-color: var(--color-red);
    transition: width 0.3s var(--transition-bounce);
}

.nav-links a:not(.nav-link-cycle):hover::after {
    width: 100%;
}

/* Mobile Navigation */
.mobile-menu-toggle {
    display: none;
    flex-direction: column;
    gap: 5px;
    padding: 10px;
    background: none;
    border: none;
    cursor: pointer;
}

.mobile-menu-toggle span {
    width: 25px;
    height: 2px;
    background-color: var(--color-cream);
    transition: all 0.3s var(--transition-smooth);
}

.mobile-menu-toggle span:nth-child(1) {
    transform-origin: center;
}

.mobile-menu-toggle span:nth-child(2) {
    transform-origin: center;
}

.mobile-menu-toggle span:nth-child(3) {
    transform-origin: center;
}

.mobile-menu-toggle.active span:nth-child(1) {
    transform: translateY(7px) rotate(45deg);
}

.mobile-menu-toggle.active span:nth-child(2) {
    opacity: 0;
}

.mobile-menu-toggle.active span:nth-child(3) {
    transform: translateY(-7px) rotate(-45deg);
}

@media (max-width: 640px) {
    :root { --page-inset: var(--space-md); }

    .mobile-menu-toggle {
        display: flex;
        position: relative;
        z-index: 1001; /* stays above the overlay */
    }

    /* On phones the bar was lopsided: the logo sat at --space-xl (3rem)
       plus its own 6vw indent while the burger sat at --space-xl flat.
       Drop the indent and tighten the padding so both edges match. */
    .navbar .container { padding: 0 var(--space-md); }
    .navbar .logo { margin-left: 0; }
    /* the burger has 10px of its own padding, so pull it back out or its
       bars end up further from the edge than the logo is */
    .navbar .mobile-menu-toggle { margin-right: -10px; }

    /* brand mark stays visible on top of the open overlay */
    .navbar .logo {
        position: relative;
        z-index: 1001;
    }

    /* Full-screen takeover menu. Covers the viewport (inset: 0) - no
       off-screen transforms, so it can never widen the page. */
    .nav-links {
        position: fixed;
        inset: 0;
        width: 100%;
        z-index: 1000;
        margin: 0;
        background-color: rgba(0, 0, 0, 0.85);
        -webkit-backdrop-filter: blur(6px);
        backdrop-filter: blur(6px);
        flex-direction: column;
        align-items: stretch;      /* items span the full width */
        justify-content: center;
        gap: var(--space-md);
        padding: var(--space-4xl) var(--container-padding) var(--space-2xl);
        opacity: 0;
        visibility: hidden;
        pointer-events: none;
        transition: opacity 0.35s var(--transition-smooth),
            visibility 0s linear 0.35s;
    }

    .nav-links.active {
        opacity: 1;
        visibility: visible;
        pointer-events: all;
        transition: opacity 0.35s var(--transition-smooth);
    }

    .nav-links li {
        width: 100%;
    }

    .nav-links a,
    .nav-link-cycle {
        display: block;
        width: 100%;
        text-align: left;
        font-family: var(--font-marker);   /* Instrument Serif */
        font-weight: 400;
        text-transform: none;
        font-size: var(--fs-2);
    }

    /* lock the page behind the open menu */
    .menu-open,
    .menu-open body {
        overflow: hidden;
    }
}

/* ============================================
   Side rails - copyright (left) + social (right),
   built by initSocial in main.js. Both take up the
   exact same vertical footprint.
   ============================================ */
.side-rail {
    position: fixed;
    top: 50%;
    /* --slide is what carries the rails off-screen during the outro */
    transform: translateY(-50%) translateX(var(--slide, 0));
    transition: transform 0.65s var(--transition-smooth),
        opacity 0.45s var(--transition-smooth);
    z-index: 900;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
    color: var(--color-cream);
    pointer-events: none;
}

.side-rail--left  { left: var(--space-lg); }
.side-rail--right { right: var(--space-lg); }

/* equal-length lines above and below the content */
.side-rail__line {
    width: 1px;
    height: 64px;
    background: currentColor;
}

/* fixed height so the two rails match exactly */
.side-rail__body {
    height: 180px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-sm);
}

.side-rail__social a {
    pointer-events: auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    color: var(--color-cream);
    opacity: 1;
    transition: color 0.25s var(--transition-smooth),
        transform 0.25s var(--transition-smooth);
}

.side-rail__social a svg {
    filter: drop-shadow(0 1px 5px rgba(0, 0, 0, 0.55));
}

.side-rail__social a:hover {
    color: var(--color-red);
    transform: scale(1.18);
}

.side-rail__label {
    writing-mode: vertical-rl;
    text-orientation: mixed;
    font-family: var(--font-body);
    /* sentence case, so a touch larger than the old all-caps setting */
    font-size: 0.7rem;
    white-space: nowrap;
    text-shadow: 0 1px 5px rgba(0, 0, 0, 0.55);
}

/* copyright rail is desktop/tablet only */
@media (max-width: 640px) {
    .side-rail { display: none; }
}

/* Social icons inside the burger menu (mobile) */
.nav-social {
    display: none;
}

.nav-social a::after {
    display: none !important; /* kill the nav-link underline bar */
}

@media (max-width: 640px) {
    .nav-links .nav-social {
        display: flex;
        gap: var(--space-sm);
        margin-top: var(--space-sm);
        padding-top: var(--space-lg);
        border-top: 1px solid rgba(250, 250, 255, 0.15);
    }

    .nav-links .nav-social a {
        display: flex;
        color: var(--color-cream);
    }

    .nav-links .nav-social a svg {
        width: 30px;
        height: 30px;
    }
}

/* ============================================
   CTA Section

/* ============================================
   Buttons
   ============================================ */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 1rem 2.5rem;
    font-family: var(--font-body);
    font-size: 0.875rem;
    font-weight: 500;
    text-transform: uppercase;
    /* always-present border so the hover outline doesn't shift layout */
    border: thin solid transparent;
    transition: all 0.3s var(--transition-bounce);
}

.btn-primary {
    background-color: var(--color-cream);
    color: var(--color-black);
}

.btn-primary:hover {
    background-color: transparent;
    color: var(--color-cream);
    border-color: var(--color-cream);
}

/* ============================================
   Footer

/* ============================================
   Page: Work/Portfolio
   ============================================ */
.page-header {
    padding-top: 150px;
    padding-bottom: var(--space-xl);
}

.page-header h1 {
    margin-bottom: var(--space-xs);
}

.page-header .heading-accent {
    font-family: var(--font-marker);
    color: var(--color-pink);
}

/* ============================================
   Page: About

.about-intro .image-box {
    aspect-ratio: 3/4;
    background-color: var(--color-gray-placeholder);
}

.about-quote .image-box {
    aspect-ratio: 1;
    background-color: var(--color-gray-placeholder);
}

/* ============================================
   Page: Contact
   ============================================ */
.contact-section {
    padding-top: 150px;
}

.contact-layout {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3xl);
    align-items: start;
}

/* Honeypot wrapper on the contact form. Pushed off-screen rather than
   display:none or visibility:hidden, both of which the better bots test
   for and then skip. aria-hidden + tabindex="-1" on the markup keep it
   away from screen readers and the tab order. */
.hp-field {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

.contact-form h1 {
    margin-bottom: var(--space-xl);
}

.form-group {
    margin-bottom: var(--space-md);
}

.form-group label {
    display: block;
    font-size: 0.875rem;
    margin-bottom: var(--space-xs);
    color: var(--color-cream);
}

.form-group input,
.form-group select,
.form-group textarea {
    width: 100%;
    padding: 0.875rem 1rem;
    font-family: var(--font-body);
    font-size: 1rem;
    border: 2px solid var(--color-cream);
    background-color: transparent;
    color: var(--color-cream);
    transition: border-color 0.3s var(--transition-smooth);
}

.form-group input::placeholder,
.form-group textarea::placeholder {
    color: var(--color-red);
}

/* only the textarea is tall, and only it can be dragged taller */
.form-group textarea {
    min-height: 150px;
    resize: vertical;
}

.form-group select option {
    background-color: var(--color-black);
    color: var(--color-cream);
}

.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
    outline: none;
    border-color: var(--color-red);
}

.form-group select {
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23FAFAFF' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 1rem center;
    padding-right: 2.5rem;
}

/* Sticky Shark Animation */
.contact-shark {
    position: sticky;
    top: 150px;
    /* More space from navbar */
    height: fit-content;
    align-self: flex-start;
}

.contact-shark img {
    width: 100%;
    height: auto;
    display: block;
    animation: sharkBounce 3s ease-in-out infinite;
    transition: transform 0.4s var(--transition-bounce);
}

/* Gentle bounce animation */
@keyframes sharkBounce {

    0%,
    100% {
        transform: translateY(0);
    }

    50% {
        transform: translateY(-15px);
    }
}

/* Scale on hover while keeping bounce animation */
.contact-shark:hover img {
    transform: scale(1.1);
}

/* Mobile shark - same bounce animation */
@media (max-width: 640px) {
    .contact-layout {
        grid-template-columns: 1fr;
    }

    .contact-shark {
        position: static;
        /* Not sticky on mobile */
        display: block;
        margin: var(--space-xl) auto;
        max-width: 300px;
    }

    /* Same animation as desktop */
    .contact-shark img {
        animation: sharkBounce 3s ease-in-out infinite;
    }

    /*.contact-shark:hover img {
        filter: brightness(1.1);
    }*/
}

/* ============================================
   Page: Case Study
   ============================================ */
.case-study-hero {
    /* the inset lines it up with the nav, clear of the side rails */
    margin: 80px var(--page-inset) 0;
    overflow: hidden;
    border-radius: var(--radius-lg);
}

/* The Height field on the hero decides the shape, and SANITY does the
   crop, not this. That keeps it to one crop, so the hotspot is
   respected and a portrait shot set to "Whole image" is never cut.
   Height auto here means the file's own proportions are what show. */
.case-study-hero img,
.case-study-hero video {
    width: 100%;
    height: auto;
    display: block;
}

.case-study-intro {
    display: grid;
    padding: var(--space-3xl) 0;
}

/* Title and role centred, then the description across the full width
   beneath them. One column, so nothing sits beside anything. */
.case-study-intro-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-2xl);
}

.case-study-intro .title-section {
    text-align: center;
}

/* The project title is a page title, so it is set like every other one
   on the site - Instrument Serif, --fs-1, no uppercase - rather than
   inheriting the Big Shoulders caps from the global h1 rule. */
.case-study-intro .title-section h1 {
    font-family: var(--font-marker);
    font-size: var(--fs-1);
    font-weight: 400;
    line-height: 1;
    text-transform: none;
    color: var(--color-cream);
    margin-bottom: var(--space-sm);
}

/* the role line: the same small label the rest of the site uses */
.case-study-intro .meta {
    font-family: var(--font-body);
    font-size: var(--fs-6);
    text-transform: uppercase;
    color: var(--color-red);
}

.case-study-intro .description {
    font-size: var(--fs-5);
    line-height: 1.6;
}

.case-study-intro .description p {
    margin-bottom: var(--space-md);
}

.case-study-meta-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-lg);
    margin-top: var(--space-xl);
    padding-top: var(--space-xl);
    border-top: 1px solid rgba(0, 0, 0, 0.2);
}

.case-study-meta-grid .meta-item h3 {
    font-family: var(--font-body);
    font-size: 1rem;
    font-weight: 600;
    text-transform: uppercase;
    margin-bottom: var(--space-xs);
}

.case-study-meta-grid .meta-item p {
    font-size: 0.875rem;
    line-height: 1.6;
}

.case-study-images {
    margin: var(--space-sm);
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--space-sm)
}

.case-study-images .image-box {
    aspect-ratio: 4/5;
    overflow: hidden;
}

.case-study-images .image-box img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.case-study-mockups {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    overflow: hidden;
    gap: var(--space-sm);
    margin: var(--space-sm);
}

.case-study-mockups .image-box {
    aspect-ratio: 16/10;
    overflow: hidden;

    img {
        width: 100%;
        height: 100%;
        object-fit: cover;
        display: block;
    }
}

.case-study-solution {
    display: grid;
    grid-template-columns: 2fr 3fr;
    gap: var(--space-sm);
    margin: var(--space-sm);
    place-items: center;

    .content,
    .content-img {
        margin: var(--space-lg);
    }
}

.case-study-solution h2 {
    color: var(--color-pink);
    margin-bottom: var(--space-md);
}

.case-study-solution .image-box {
    width: 100%;
    overflow: hidden;
}

.case-study-solution .image-box img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.case-study-full-image {
    margin: var(--space-sm) var(--page-inset);
}

.case-study-full-image img {
    width: 100%;
}

/* ============================================
   CASE STUDY ROWS - 1 to 4 images per row

   Same idea as the work rows on the homepage: the row splits evenly by
   default, and --w on an item overrides that with a percentage. --n is
   the item count, set from the data-n the renderer writes, so each item
   can give back its share of the gaps and the row still totals 100%.
   ============================================ */
.cs-row {
    --cs-gap: var(--space-sm);
    display: flex;
    flex-wrap: wrap;
    gap: var(--cs-gap);
    margin: var(--cs-gap) var(--page-inset);
    /* Items in a row are often different heights, because "Whole image"
       keeps its own shape next to a cropped neighbour. Centred reads far
       better than hanging them all from the top. */
    align-items: center;
}

.cs-row[data-n="1"] { --n: 1; }
.cs-row[data-n="2"] { --n: 2; }
.cs-row[data-n="3"] { --n: 3; }
.cs-row[data-n="4"] { --n: 4; }

.cs-row__item {
    flex: 0 0 calc(
        var(--w, calc(100 / var(--n))) * 1%
        - var(--cs-gap) * (var(--n) - 1) / var(--n)
    );
    min-width: 0;
    overflow: hidden;
}

/* A lone image keeps its own shape; pairs get a landscape crop and
   3-4 up get a portrait one, which is what the hand-built pages did. */
.cs-row[data-n="1"] .cs-row__item { aspect-ratio: var(--ar, auto); }
.cs-row[data-n="2"] .cs-row__item { aspect-ratio: var(--ar, 16 / 10); }
.cs-row[data-n="3"] .cs-row__item,
.cs-row[data-n="4"] .cs-row__item { aspect-ratio: var(--ar, 4 / 5); }

/* Height "Whole image, no crop" in the Studio. Wins over the row's
   default ratio above, so a tall shot shows end to end instead of
   being squashed into the row's shape. */
/* .cs-row[data-n] is needed on all of these: without it they are LESS
   specific than the rules above and the row's default ratio still wins.

   natural  the whole image, no crop at all
   short    a wide, shallow crop
   tall     a deep, portrait crop
   (blank)  the row's default for its item count                       */
.cs-row[data-n] .cs-row__item[data-height="natural"] { aspect-ratio: auto; }

/* Short, Standard and Tall are a HEIGHT, not a ratio, so a card is the
   same depth whatever shape the image is and whatever else is in the
   row. aspect-ratio has to be cancelled or the count-based default above
   fights the height. The rem bounds stop it collapsing on a short laptop
   or towering on a tall monitor. */
.cs-row[data-n] .cs-row__item[data-height="short"] {
    aspect-ratio: auto;
    height: clamp(14rem, 40vh, 26rem);
}

.cs-row[data-n] .cs-row__item[data-height="default"] {
    aspect-ratio: auto;
    height: clamp(22rem, 65vh, 42rem);
}

/* 30% deeper than Standard */
.cs-row[data-n] .cs-row__item[data-height="tall"] {
    aspect-ratio: auto;
    height: clamp(29rem, 85vh, 55rem);
}

/* only "natural" releases the image itself; the two crops still fill
   their box the way every other row image does */
.cs-row[data-n] .cs-row__item[data-height="natural"] img,
.cs-row[data-n] .cs-row__item[data-height="natural"] video { height: auto; }

/* video sits in exactly the same box as an image */
.cs-row__item img,
.cs-row__item video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.cs-row[data-n="1"] .cs-row__item img,
.cs-row[data-n="1"] .cs-row__item video { height: auto; }

/* A sized preset must fill its box, or the crop never happens. This
   has to outrank the n="1" rule above, which would otherwise leave a
   lone image at its natural height inside a box it does not fill. */
.cs-row[data-n] .cs-row__item[data-height="short"] img,
.cs-row[data-n] .cs-row__item[data-height="short"] video,
.cs-row[data-n] .cs-row__item[data-height="default"] img,
.cs-row[data-n] .cs-row__item[data-height="default"] video,
.cs-row[data-n] .cs-row__item[data-height="tall"] img,
.cs-row[data-n] .cs-row__item[data-height="tall"] video {
    height: 100%;
    object-fit: cover;
}

/* the write-up bands stay full-bleed, their text takes the same inset
   instead of the 1200px cap, so copy and images share an edge */
.cs-band .container,
.case-study-intro .work-container {
    max-width: none;
    padding-inline: var(--page-inset);
}

.sm-section.cs-band { padding-inline: var(--page-inset); }
.cs-band .case-study-solution { margin-inline: 0; }

/* the dark write-up band, previously inline styles on each section */
.cs-band {
    background-color: var(--color-black);
    color: var(--color-cream);
}

.cs-band .case-study-solution h2 {
    font-family: var(--font-marker);
    font-size: var(--fs-2);
    font-weight: 400;
    line-height: 1;
    text-transform: none;
    color: var(--color-cream);
}

/* the hero and the beside-the-copy slot both take video too */
.case-study-hero video {
    width: 100%;
    object-fit: cover;
    display: block;
}

.case-study-solution .image-box video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* no ?p= slug, or one with no entry in PROJECTS */
.cs-missing {
    margin-top: 30vh;
    margin-bottom: var(--space-3xl);
    padding: 0 var(--space-xl);
    text-align: center;
    color: var(--color-cream);
}

.cs-missing a { color: var(--color-red); }

.cs-missing code {
    font-family: var(--font-body);
    background: rgba(255, 255, 255, 0.1);
    padding: 0.15em 0.4em;
    border-radius: 4px;
}

.cs-missing__list {
    list-style: none;
    padding: 0;
    margin: var(--space-md) 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-md);
    font-size: var(--fs-4);
}

@media (max-width: 640px) {
    /* one per row, like every other stacked section */
    .cs-row__item { flex-basis: 100%; }
    .cs-row { margin-block: var(--space-xs); }

    /* Every height and ratio is released here, on purpose.
       They exist only to make items sitting SIDE BY SIDE match each
       other. Stacked one per row there is nothing to match, so all they
       do is force a full-width phone image into a fixed box and let
       object-fit hack the top and bottom off it. Whole images instead.
       The selectors are this long to outrank the desktop rules, which
       are [data-n] + [data-height] specific. */
    .cs-row[data-n] .cs-row__item,
    .cs-row[data-n] .cs-row__item[data-height="short"],
    .cs-row[data-n] .cs-row__item[data-height="default"],
    .cs-row[data-n] .cs-row__item[data-height="tall"] {
        aspect-ratio: auto;
        height: auto;
    }

    .cs-row[data-n] .cs-row__item img,
    .cs-row[data-n] .cs-row__item video,
    .cs-row[data-n] .cs-row__item[data-height="short"] img,
    .cs-row[data-n] .cs-row__item[data-height="short"] video,
    .cs-row[data-n] .cs-row__item[data-height="default"] img,
    .cs-row[data-n] .cs-row__item[data-height="default"] video,
    .cs-row[data-n] .cs-row__item[data-height="tall"] img,
    .cs-row[data-n] .cs-row__item[data-height="tall"] video {
        height: auto;
        object-fit: fill;
    }
}

@media (max-width: 640px) {

    .case-study-intro,
    .case-study-images,
    .case-study-solution {
        grid-template-columns: 1fr;
        margin: var(--space-xs);
    }

    .case-study-full-image,
    .case-study-mockups {
        margin: var(--space-xs);
    }

    .case-study-solution {
        .content {
            margin: 0;
        }
    }

    .case-study-intro-grid {
        display: block
    }

    .case-study-intro-grid h1 {
        font-size: clamp(4rem, 7rem, 9rem);
    }

    .case-study-meta-grid {
        grid-template-columns: 1fr;
        gap: var(--space-md);
    }

    .case-study-solution {
        h2 {
            text-align: left;
            font-size: 3rem;
            margin: 0;
        }
    }

    .sm-section {
        h2 {
            margin-bottom: var(--space-lg);
        }
    }

    .case-study-images {
        margin: var(--space-xs);
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        gap: var(--space-xs)
    }

    .case-study-mockups {
        grid-template-columns: repeat(1, 1fr);
        gap: var(--space-xs)
    }
}

/* ============================================
   Utility Classes

/* ============================================
   NEW: Updated Hero Section
   ============================================ */

/* ============================================
   Portfolio grid (Homepage + Work page)
   ============================================ */
.portfolio-section {
    /* no background - the page-wide gradient behind it fades to black
       across this section (initHeroBgFade in main.js) */
    padding: 0 0 clamp(5rem, 12vw, 11rem);
}

/* All cards the SAME height. Widths follow a 10-card repeating pattern:
     row 1 (3 cards): 30 / 30 / 40
     row 2 (2 cards): 50 / 30   - inset 10% from each side
     row 3 (3 cards): 40 / 30 / 30
     row 4 (2 cards): 30 / 50   - inset 10% from each side          */
.work-scatter {
    --col-gap: clamp(1rem, 3vw, 3rem);
    /* left/right edge lines up with the "DOUBLE DASH" nav logo:
       .navbar .container padding (--space-xl) + .navbar .logo margin */
    margin: 0;
    padding: 0 var(--page-inset);
    display: flex;
    flex-wrap: wrap;
    column-gap: var(--col-gap);
    row-gap: clamp(4rem, 9vw, 18rem);
    align-items: flex-start;
}

.work-card {
    display: flex;
    flex-direction: column;
    width: calc(30% - var(--col-gap) * 2 / 3 - 0.5px);
    text-decoration: none;
    color: var(--color-cream);
    /* --py set per-card by initCardParallax in main.js */
    transform: translateY(var(--py, 0px));
    will-change: transform;
}

/* rows of 3: the 30% and 40% cards */
.work-card:nth-child(10n + 3),
.work-card:nth-child(10n + 6) {
    width: calc(40% - var(--col-gap) * 2 / 3 - 0.5px);
}

/* rows of 2: two cards, 10% margin on the leading one */
.work-card:nth-child(10n + 4) {
    width: calc(50% - var(--col-gap) / 2 - 0.5px);
    margin-left: 10%;
}

.work-card:nth-child(10n + 5),
.work-card:nth-child(10n + 9) {
    width: calc(30% - var(--col-gap) / 2 - 0.5px);
}

.work-card:nth-child(10n + 9) {
    margin-left: 10%;
}

.work-card:nth-child(10n + 10) {
    width: calc(50% - var(--col-gap) / 2 - 0.5px);
}

/* ==================================================================
   Homepage portfolio - ROW SYSTEM
   ==================================================================
   index.html wraps the grid in <div class="work-scatter work-scatter--rows">.
   Inside it, group the cards into rows:

       <div class="work-row">
           <a class="work-card" style="--w: 30"> ... </a>   1 to 3 per row
           <a class="work-card" style="--w: 40"> ... </a>
       </div>

   Each row is centred, so a row whose widths don't add up to 100%
   bundles toward the middle of the page on its own.

   Per-card knobs, set on the <a class="work-card">:
       style="--w: 40"              width, as a % of the row   (default 33)
       style="--v: center"          vertical align in the row:
                                      flex-start (top, default) | center |
                                      flex-end (bottom) | stretch
       style="--y: 3rem"            manual vertical nudge (down +, up -)
       style="--h: 26rem"           frame height (any length; default is
                                      clamp(20rem, 26vh, 30rem))
       style="--p: 0.12"            scroll-parallax drift rate (default is
                                      a preset that varies per card;
                                      0 = this card doesn't drift)
       class="... work-card--tall"   height preset - portrait
       class="... work-card--short"  height preset - letterbox
   Combine them: style="--w: 40; --v: flex-end; --h: 30rem; --p: 0.05"

   No per-row CSS to write. Below 760px the rows stack into one
   full-width column (each card keeps its own --h) and parallax is off.
   ================================================================== */
.work-scatter--rows {
    flex-direction: column;
}

.work-scatter--rows .work-row {
    display: flex;
    flex-wrap: wrap;
    column-gap: var(--col-gap);
    row-gap: var(--col-gap);
    justify-content: center;
    align-items: flex-start;
    width: 100%;
}

.work-scatter--rows .work-card {
    /* --w = this card's share of the row (%). One gap's worth is shaved
       off so a full 3-up row (e.g. 33 + 33 + 33) still fits on the line. */
    width: calc(var(--w, 33) * 1% - var(--col-gap) * 2 / 3);
    /* --v = where the card sits vertically within the row;
       --y = an extra manual nudge on top of that. */
    align-self: var(--v, flex-start);
    margin: 0;
    margin-top: var(--y, 0px);
}

@media (max-width: 760px) {
    .work-scatter--rows .work-row {
        flex-direction: column;
        row-gap: clamp(3rem, 11vw, 5rem);
    }

    .work-scatter--rows .work-card {
        width: 100%;
        align-self: auto;
        margin-top: 0;
    }
}

/* ==================================================================
   Work page - SQUISH ROWS
   ==================================================================
   3 equal cards per <div class="work-row">. Hovering one card grows
   it to 40% of the row and squishes the other two to 30% each
   (flex-grow 4 : 3 : 3). Same frame / image-swap / hover-video / meta
   as everywhere else. projects.html: <div class="work-scatter work-scatter--squish">
   Below 760px it stacks to one full-width column like the index rows.
   ================================================================== */
.work-scatter--squish {
    flex-direction: column;
    row-gap: clamp(3rem, 7vw, 6rem);
    /* --page-inset like every other page, rather than the 1680px cap and
       7vw gutter this used to carry - that was what made this page sit
       narrower than the rest of the site. */
    padding-inline: var(--page-inset);
}

/* The projects grid runs 15% taller than the shared default frame
   (20/26/30 -> 23/29.9/34.5). Scoped here so the homepage cards, which
   set their own --h inline, are untouched. An inline --h still wins. */
.work-scatter--squish .work-card__frame {
    height: var(--h, clamp(23rem, 29.9vh, 34.5rem));
}

.work-scatter--squish .work-row {
    /* the usable width once the two gutters are taken out */
    --span: calc(100% - 2 * var(--col-gap));

    display: flex;
    column-gap: var(--col-gap);
    align-items: flex-start;
    width: 100%;
}

/* Sized off a fixed one-third track rather than flex-grow, so a row
   holding one or two cards (after filtering) keeps the same column
   widths as a full row instead of stretching to fill. */
.work-scatter--squish .work-row > .work-card {
    flex: 0 0 calc(var(--span) / 3);
    width: auto;
    min-width: 0;             /* let the squished cards collapse */
    margin: 0;
    transition: flex-basis 0.5s var(--transition-smooth);
}

@media (hover: hover) {
    .work-scatter--squish .work-row:hover > .work-card {
        flex-basis: calc(var(--span) * 0.3);
    }
    .work-scatter--squish .work-row:hover > .work-card:hover {
        flex-basis: calc(var(--span) * 0.4);
    }
}

.work-scatter--squish .work-row:focus-within > .work-card {
    flex-basis: calc(var(--span) * 0.3);
}
.work-scatter--squish .work-row:focus-within > .work-card:focus-visible {
    flex-basis: calc(var(--span) * 0.4);
}

/* "In the works" filler tile */
.work-card--soon { cursor: default; }

.work-card--soon .work-card__frame {
    background: repeating-linear-gradient(-45deg,
        #1e1e1e, #1e1e1e 14px, #262626 14px, #262626 28px);
}

/* "In the works" tiles keep the normal title/category colours - the
   striped frame already reads as a placeholder */

@media (max-width: 760px) {
    .work-scatter--squish {
        max-width: none;
        padding-inline: var(--container-padding);
    }

    .work-scatter--squish .work-row {
        flex-direction: column;
        row-gap: clamp(2.5rem, 9vw, 4rem);
    }

    .work-scatter--squish .work-row > .work-card {
        flex: none;          /* stop the flex sizing - just stack full width */
        width: 100%;
    }
}

@media (prefers-reduced-motion: reduce) {
    .work-scatter--squish .work-row > .work-card { transition: none; }
}

.work-card__frame {
    display: block;
    position: relative;
    width: 100%;
    /* default height; --h (set inline, or by the presets below) wins */
    height: var(--h, clamp(20rem, 26vh, 30rem));
    overflow: hidden;
    border-radius: var(--radius-lg);
    background-color: var(--color-gray-placeholder);
}

/* portrait frame - good for vertically-oriented brands (~70% taller) */
.work-card--tall {
    --h: clamp(34rem, 44vh, 51rem);
}

/* letterbox frame - good for wide billboard / signage shots */
.work-card--short {
    --h: clamp(15rem, 19vh, 21rem);
}

/* empty (placeholder) frames - visible box on the black page */
.work-card__frame:empty {
    background: repeating-linear-gradient(-45deg,
        #1e1e1e, #1e1e1e 14px, #262626 14px, #262626 28px);
}

.work-card__img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.6s var(--transition-smooth),
        opacity 0.5s var(--transition-smooth);
}

.work-card:hover .work-card__img {
    transform: scale(1.05);
}

/* Second still that cross-fades in over the first on hover. Add a
   <img class="work-card__img work-card__img--hover"> as the LAST child
   of .work-card__frame to give any card this behaviour. */
.work-card__img--hover {
    opacity: 0;
}

.work-card:hover .work-card__img--hover {
    opacity: 1;
}

.work-card__meta {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.35rem;
    margin-top: var(--space-md);
    padding-top: var(--space-sm);
    border-top: 1px solid var(--color-cream);
}

.work-card__title {
    font-family: var(--font-marker); /* Instrument Serif */
    font-weight: 400;
    font-size: var(--fs-3);
    line-height: 1.05;
    transition: color 0.3s var(--transition-smooth);
}

/* reserve the italic footprint so the hover swap never reflows */
.work-card__title::after {
    content: attr(data-title);
    display: block;
    height: 0;
    overflow: hidden;
    font-style: italic;
    visibility: hidden;
}

.work-card:hover .work-card__title {
    font-style: italic;
    color: var(--color-red);
}

/* See more button under the grid */
.work-more {
    display: flex;
    justify-content: center;
    margin-top: clamp(3rem, 7vw, 6rem);
}

/* Phones: single full-width column, still all the same height */
@media (max-width: 760px) {
    .work-scatter {
        row-gap: clamp(3rem, 11vw, 5rem);
    }

    .work-scatter .work-card {
        width: 100%;
        margin-left: 0;
    }
}

@media (max-width: 640px) {
    .work-scatter {
        padding: 0 var(--container-padding);
    }
}

/* ============================================
   NEW: About Section (Home Page)
   ============================================ */
.about-section {
    /* no background - inherits the page-wide gradient, fully black by
       the time it scrolls into view */
}

/* Match the portfolio's gutters so the about block lines up with the
   work grid (and the "DOUBLE DASH" nav logo) instead of sitting in the
   narrower 1200px .container. */
.about-section > .container {
    max-width: none;
    padding-inline: var(--page-inset);
}

.about-content {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: clamp(2rem, 6vw, 5rem);
    align-items: stretch;     /* the text column matches the photo's height */
    justify-items: stretch;   /* was place-items:center, which stopped
                                 the image filling its column */
}

/* Two equal halves against the photo: the heading sits at the top of
   the image, the body starts level with its middle. */
.about-text {
    display: grid;
    grid-template-rows: 1fr 1fr;
}

.about-text > .about-greeting { align-self: start; margin-bottom: 0; }
.about-text > .about-body { align-self: start; }

.about-greeting {
    margin-bottom: var(--space-lg);
}

.greeting-hello {
    display: block;
    text-transform: none;
    font-family: var(--font-marker);
    font-weight: 700;
    font-style: italic;
    font-size: var(--fs-2);
    color: var(--color-red);
    line-height: 1;
}

.greeting-name {
    display: block;
    font-family: var(--font-display);
    font-size: var(--fs-4);
    text-transform: uppercase;
    margin-top: var(--space-xs);
}

/* the copy runs in two columns under the heading */
.about-description {
    columns: 2;
    column-gap: clamp(1.5rem, 3vw, 3rem);
}

.about-description p {
    font-size: var(--fs-5);
    font-weight: 100;
    line-height: 1.1;
    margin-bottom: var(--space-md);
    break-inside: avoid;   /* keep each paragraph whole in one column */
}

/* "Salam kenal" - the greeting leads in the serif */
.about-description .salam {
    font-family: var(--font-marker);   /* Instrument Serif */
    font-style: italic;
    font-weight: 400;                  /* it ships regular + italic only */
    font-size: calc(var(--fs-5) + 4px);
}

.about-description p:last-child {
    margin-bottom: 0;
}

.about-image {
    position: relative;
}

.about-image>img:last-child {
    width: 100%;
    height: auto;
    display: block;
    border-radius: var(--radius-lg);   /* matches the work card frames */
}

@media (max-width: 640px) {
    .about-section > .container {
        padding-inline: var(--container-padding);
    }

    .about-content {
        grid-template-columns: 1fr;
        gap: var(--space-xl);
    }

    /* stacked: normal top-down flow, no half-and-half split, one column */
    .about-text {
        display: block;
    }

    .about-description {
        columns: 1;
    }

    .about-text > .about-greeting {
        margin-bottom: var(--space-lg);
    }

    .about-image {
        order: -1;
    }

}

/* ============================================
   NEW: Services Section with Stickers

.sticker-branding.visible {
    transform: rotate(-8deg) translateY(20px) scale(1);
    opacity: 1;
}

.sticker-logo.visible {
    transform: rotate(10deg) translateY(-50px) scale(1);
    opacity: 1;
}

.sticker-print.visible {
    transform: rotate(-5deg) translateY(10px) scale(1);
    opacity: 1;
}

.sticker-illustrations.visible {
    transform: rotate(12deg) translateY(-20px) scale(1);
    opacity: 1;
}

@media (max-width: 640px) {

    .sticker-branding.visible {
        transform: rotate(-5deg) scale(1);
        opacity: 1;
    }

    .sticker-logo.visible {
        transform: rotate(8deg) scale(1);
        opacity: 1;
    }

    .sticker-print.visible {
        transform: rotate(-3deg) scale(1);
        opacity: 1;
    }

    .sticker-illustrations.visible {
        transform: rotate(10deg) scale(1);
        opacity: 1;
    }

}

/* ============================================
   NEW: Updated CTA Section

.cta-section .container {
    display: grid;
    grid-template-columns: 2fr 1fr;
    align-items: center;
}

.cta-section .btn {
    background-color: var(--color-black);
    color: var(--color-red);
    font-size: 1rem;
}

.cta-section .btn:hover {
    background-color: transparent;
    color: var(--color-black);
    border-color: var(--color-black);
}

@media (max-width: 640px) {

    .cta-section .container {
        display: flex;
        gap: var(--space-xl);
        align-items: center;
    }

    .cta-line1,

    .cta-section .container {
        flex-direction: column;
    }
}

/* ============================================
   NEW: Updated Footer

/* ==================================================================
   OUTRO - CTA band + full-screen footer
   ==================================================================
   Sits at the bottom of every page. When it scrolls into view the
   PAGE background itself turns brand orange, and the navbar + both
   side rails clear out of frame. initOutro() in main.js toggles
   .outro-active on <html>; everything below reacts to that.
   ================================================================== */

/* the page background is what changes - the outro block is see-through */
body {
    transition: background-color 0.8s var(--transition-smooth);
}

.outro-active body {
    background-color: var(--color-red);
}

.outro {
    --outro-gutter: clamp(1.5rem, 6vw, 7rem);
    --outro-ink: var(--color-black);
    --outro-accent: var(--color-pink);      /* indigo #2E2B8A */
    --outro-muted: var(--color-pink);   /* indigo, not a grey */
    --outro-line: rgba(0, 0, 0, 0.2);

    background-color: transparent;
    color: var(--outro-ink);
}

/* ── scroll parallax ──────────────────────────────────────── */
/* Any element with data-parallax="<rate>" drifts as it crosses the
   viewport; initParallax() in main.js sets --py. Higher rate = more
   lag. Off below 760px and under prefers-reduced-motion. */
[data-parallax] {
    transform: translateY(var(--py, 0px));
    will-change: transform;
}

/* ── CTA band ─────────────────────────────────────────────── */
/* the black rounded slab wraps the line AND the button */
.cta-band {
    --cta-pad-y: clamp(1.6rem, 4vw, 3rem);

    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: clamp(1.5rem, 5vw, 4rem);
    margin: clamp(2.5rem, 7vw, 5rem) var(--outro-gutter) clamp(3rem, 8vw, 6rem);
    padding-block: var(--cta-pad-y);
    padding-inline: clamp(1.9rem, 4.5vw, 3.5rem);
    border-radius: clamp(1rem, 2.5vw, 2rem);
    background-color: var(--color-pink);   /* indigo #2E2B8A on the orange */
    transition: padding-block 0.7s var(--transition-smooth);
}

/* Scrolled into view: the slab grows 30% of its resting height at the
   top and bottom, then settles back once it leaves. --cta-grow is that
   30% in px, measured by initCtaExpand() in main.js (percentage padding
   would resolve against width, not height). */
.cta-band.is-open {
    padding-block: calc(var(--cta-pad-y) + var(--cta-grow, 0px));
}

@media (prefers-reduced-motion: reduce) {
    .cta-band { transition: none; }
    .cta-band.is-open { padding-block: var(--cta-pad-y); }
}

.cta-band .btn {
    text-transform: none;       /* "Get in Touch!" reads as written */
}

.cta-band__box {
    margin: 0;
    color: var(--color-cream);
    font-family: var(--font-marker);        /* Instrument Serif */
    font-style: normal;                     /* "Ready to" stays upright */
    font-weight: 400;
    font-size: clamp(2.1rem, 6vw, 4.75rem);
    line-height: 1;
    text-transform: none;                   /* beat the global h1-h4 rule */
    text-wrap: balance;
}

/* ── hover gif pop ────────────────────────────────────────────
   Put .gif-pop on any element and drop an
   <img class="gif-pop__img"> inside it; hovering pops the image
   up above. Add .gif-pop--below to pop downward instead (used by
   the navbar logo, which has nothing above it).
   initCtaSpark() in main.js adds the cursor drift and removes the
   <img> if the file is missing. */
.gif-pop { position: relative; }

.gif-pop__img {
    position: absolute;
    left: 50%;
    bottom: calc(100% + 0.6rem);
    width: clamp(160px, 17vw, 260px);
    /* the global img{max-width:100%} would otherwise clamp this to the
       width of its trigger - tiny on the navbar logo */
    max-width: none;
    height: auto;
    border-radius: 12px;
    box-shadow: 0 18px 44px rgba(0, 0, 0, 0.55);
    transform: translate(calc(-50% + var(--gx, 0px)), 10px) rotate(var(--tilt, -5deg)) scale(0.9);
    opacity: 0;
    pointer-events: none;
    z-index: 60;
    transition: opacity 0.25s var(--transition-smooth),
        transform 0.4s var(--transition-bounce);
}

.gif-pop:hover .gif-pop__img {
    opacity: 1;
    transform: translate(calc(-50% + var(--gx, 0px)), 0) rotate(var(--tilt, -5deg)) scale(1);
}

.gif-pop--below .gif-pop__img {
    bottom: auto;
    top: calc(100% + 0.6rem);
    transform: translate(calc(-50% + var(--gx, 0px)), -10px) rotate(var(--tilt, -5deg)) scale(0.9);
}

.gif-pop--below:hover .gif-pop__img {
    transform: translate(calc(-50% + var(--gx, 0px)), 0) rotate(var(--tilt, -5deg)) scale(1);
}

/* a different lean per instance, so they don't all read as one asset */
.salam.gif-pop           { --tilt: -8deg; }
.tagline-strong.gif-pop  { --tilt: -3deg; }
.cta-spark               { --tilt: 6deg; }

/* no hover on touch - don't leave one stuck open after a tap */
@media (hover: none) {
    .gif-pop__img { display: none; }
}

/* "Rock & Roll" - hovering it pops a gif up above the words.
   Drop your clip in at assets/images/rock-and-roll.gif; if the file
   isn't there initCtaSpark() removes the <img> so nothing breaks. */
.cta-spark {
    position: relative;
    display: inline-block;
    font-style: italic;                     /* the italic marks it as the hot phrase */
    transition: color 0.3s var(--transition-smooth);
}

.cta-spark:hover { color: var(--color-red); }

.cta-spark__gif {
    position: absolute;
    left: 50%;
    bottom: calc(100% + 0.25em);
    width: clamp(150px, 19vw, 280px);
    max-width: none;
    height: auto;
    border-radius: 12px;
    box-shadow: 0 18px 44px rgba(0, 0, 0, 0.55);
    /* --gx is nudged by the cursor (initCtaSpark in main.js) */
    transform: translate(calc(-50% + var(--gx, 0px)), 10px) rotate(var(--tilt, -5deg)) scale(0.9);
    opacity: 0;
    pointer-events: none;
    z-index: 3;
    transition: opacity 0.25s var(--transition-smooth),
        transform 0.4s var(--transition-bounce);
}

.cta-spark:hover .cta-spark__gif {
    opacity: 1;
    transform: translate(calc(-50% + var(--gx, 0px)), 0) rotate(var(--tilt, -5deg)) scale(1);
}

@media (prefers-reduced-motion: reduce) {
    .cta-spark__gif { transition: opacity 0.2s linear; }
}

/* ── full-screen footer ───────────────────────────────────── */
.site-footer {
    min-height: 100svh;
    display: flex;
    flex-direction: column;
    gap: clamp(1rem, 2vw, 1.75rem);
    padding: clamp(2rem, 5vw, 4rem) var(--outro-gutter) 1.75rem;
    /* no top rule - the orange band is the divider */
}

/* the thanks + shark row soaks up all the leftover height, so the link
   row and copyright sit tight together at the bottom */
.footer-top {
    flex: 1;
    display: grid;
    /* the art is sized by height now, so let its column shrink to the
       image and hand every spare pixel to the thanks + wordmark. */
    grid-template-columns: 1fr auto;
    align-items: center;
    gap: clamp(2rem, 6vw, 5rem);
}

.footer-thanks {
    margin: 0;
    font-family: var(--font-marker);
    font-weight: 400;
    font-size: clamp(2.1rem, 5.6vw, 4.6rem);
    line-height: 1.02;
    text-transform: none;
    color: var(--outro-ink);
}

/* Landscape lockup, 429.58 x 141.56. Fills the widened text column;
   min() keeps it inside that column on narrower screens. */
.footer-logotype {
    display: block;
    width: min(100%, clamp(420px, 64vw, 900px));
    height: auto;
    margin-top: clamp(0.9rem, 2.4vw, 1.6rem);
    color: var(--outro-ink);        /* the wordmark inherits this */
}

/* The cross in the lockup spins on its own axis. transform-box: fill-box
   makes transform-origin resolve against the path's own bounding box
   rather than the whole svg's viewBox, so it turns in place. */
.footer-logotype .logo-plus {
    transform-box: fill-box;
    transform-origin: center;
    animation: logoPlusSpin 6s linear infinite;
}

@keyframes logoPlusSpin {
    to { transform: rotate(360deg); }
}

/* portrait illustration (599x1003), so drive it off HEIGHT and let the
   width follow - sizing by width would overflow the 100svh footer. */
.footer-art img {
    width: auto;
    max-width: 100%;
    height: clamp(420px, 72vh, 840px);
    margin-inline: auto 0;      /* pushed to the right edge of its column */
    display: block;
}

/* One short row: Portfolio | About | Contact | socials.
   Stacks only on mobile. */
/* just the socials now, pulled to the left edge */
.footer-links {
    display: flex;
    align-items: center;
    justify-content: flex-start;
}

/* social icons: initSocial() clones this into the right side rail
   and the burger menu */
.site-footer .footer-social {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: clamp(0.85rem, 2vw, 1.4rem);
}

.site-footer .footer-social a {
    display: inline-flex;
    align-items: center;
    width: fit-content;
    height: auto;
    padding: 0;
    background: none;
    color: var(--outro-ink);
    transition: color 0.3s var(--transition-smooth),
        transform 0.3s var(--transition-bounce);
}

.site-footer .footer-social a:hover {
    color: var(--outro-accent);
    transform: scale(1.15);
}

.site-footer .footer-social a svg {
    width: 28px;
    height: 28px;
    flex: none;
    color: inherit;
}

.footer-base {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem 2rem;
    padding-top: 0.9rem;
    font-size: var(--fs-6);
    color: var(--outro-muted);
}

.footer-base b { color: var(--outro-ink); font-weight: 600; }

.footer-base a {
    color: var(--outro-muted);
    text-decoration: none;
    transition: color 0.3s var(--transition-smooth);
}

.footer-base a:hover { color: var(--outro-accent); }

/* ── side rails rearrange while the outro is on screen ── */
/* the navbar stays put over the outro; both rails clear out */
.outro-active .side-rail--left { --slide: -180%; opacity: 0; }

.outro-active .side-rail--right { --slide: 180%; opacity: 0; }

@media (prefers-reduced-motion: reduce) {
    .navbar, .side-rail { transition: none; animation: none; }
    .logo-mark { transition: none; }
    .footer-logotype .logo-plus { animation: none; }
}

@media (max-width: 900px) {
    .footer-top { grid-template-columns: 1fr; }
    .footer-art { order: -1; }
    /* stacked: it shares the fold with the thanks + links, so less height -
       and it spans the full width now, so re-centre it. */
    .footer-art img { height: clamp(300px, 46vh, 520px); margin-inline: auto; }
}

/* smaller screens: stack the line above the button, both centred */
@media (max-width: 760px) {
    .cta-band {
        flex-direction: column;
        align-items: center;
        justify-content: center;
        text-align: center;
        gap: clamp(1.25rem, 5vw, 2rem);
    }

    .cta-band .btn { width: 100%; }

}

@media (max-width: 640px) {
    .footer-base { flex-direction: column; align-items: flex-start; }
}

/* ==================================================================
   PAGE LOADER - spinning mark, stepped to 12 fps
   ==================================================================
   Hidden by default so the site is never stuck behind it if JS fails.
   A one-line script in <head> adds .is-loading to <html> before first
   paint; initPageLoader() in main.js clears it on load and puts it
   back when you click through to another page.
   ================================================================== */
.page-loader {
    position: fixed;
    inset: 0;
    z-index: 9999;
    display: grid;
    place-items: center;
    background-color: var(--color-black);
    perspective: 800px;              /* the mark turns in depth, not flat */
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.45s var(--transition-smooth),
        visibility 0s linear 0.45s;
}

.is-loading .page-loader {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: opacity 0.25s var(--transition-smooth);
}

.page-loader__mark {
    width: clamp(84px, 12vw, 150px);
    height: auto;
    transform-style: preserve-3d;

    /* same soft shadow the hero mark uses */
    filter: drop-shadow(0 12px 40px rgba(0, 0, 0, 0.5));

    /* 12 discrete frames per turn, one turn per 1.2s */
    animation: ddLoaderSpin 1.2s steps(12, end) infinite;
}

/* Y-axis turn, same axis as the hero's extruded model, with a small
   fixed X tilt so the bevel catches. Runs 15deg -> 375deg rather than
   0 -> 360 so no frame lands exactly on 90 or 270, where a flat plane
   would be edge-on and vanish. */
@keyframes ddLoaderSpin {
    from { transform: rotateX(-10deg) rotateY(15deg); }
    to   { transform: rotateX(-10deg) rotateY(375deg); }
}

/* don't let the page scroll behind the overlay */
.is-loading body { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
    .page-loader__mark { animation: none; }
    .page-loader { transition: opacity 0.2s linear; }
}

/* ==================================================================
   WORK CATEGORY TAGS + FILTER BAR
   ==================================================================
   Both are generated from WORK_CATEGORIES in js/main.js. In the HTML
   you only ever set  data-cats="logo brand print"  on a .work-card.
   ================================================================== */

/* ── the pills under each card title ──────────────────────── */
.work-card__tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

.tag {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.3rem 0.5rem 0.3rem 0.65rem;
    border: 1px solid var(--color-red);
    border-radius: 999px;
    color: var(--color-red);
    font-family: var(--font-body);
    font-size: 0.68rem;
    line-height: 1;
    white-space: nowrap;
}

.tag svg {
    width: 13px;
    height: 13px;
    flex: none;
}

/* ── filter bar (projects.html only) ──────────────────────────── */
.work-filters {
    margin: 0 0 clamp(2rem, 5vw, 3.5rem);
    padding-inline: var(--page-inset);
}

.work-filters__list {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

/* the collapsed toggle is mobile-only */
.work-filters__toggle { display: none; }

.work-filter {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.55rem 0.8rem 0.55rem 1rem;
    border: 1px solid var(--color-cream);
    border-radius: 999px;
    background: none;
    color: var(--color-cream);
    font-family: var(--font-body);
    font-size: 0.78rem;
    line-height: 1;
    cursor: pointer;
    transition: background-color 0.25s var(--transition-smooth),
        color 0.25s var(--transition-smooth),
        border-color 0.25s var(--transition-smooth);
}

.work-filter svg {
    width: 15px;
    height: 15px;
    flex: none;
}

/* The padding above is lopsided on purpose - the trailing icon needs
   less optical space than a text edge. "All" has no icon, so it needs
   even padding or its label reads off centre. */
.work-filter[data-cat="all"] {
    padding-inline: 0.95rem;
}

.work-filter:hover {
    border-color: var(--color-red);
    color: var(--color-red);
}

.work-filter[aria-pressed="true"] {
    background-color: var(--color-red);
    border-color: var(--color-red);
    color: var(--color-black);
}

.work-filter:focus-visible {
    outline: 2px solid var(--color-red);
    outline-offset: 3px;
}

/* [hidden] needs restating - .work-empty sets no display of its own,
   but an author `display` would beat the UA's [hidden]{display:none}. */
.work-empty[hidden] {
    display: none !important;
}

/* Cards settle in after the rows are repacked by a filter change. */
@keyframes workCardIn {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: none; }
}

.work-card--enter {
    animation: workCardIn 0.45s var(--transition-smooth) both;
    animation-delay: calc(var(--i, 0) * 55ms);
}

@media (prefers-reduced-motion: reduce) {
    .work-card--enter { animation: none; }
}

/* nothing matched */
.work-empty {
    padding: clamp(2rem, 6vw, 4rem) var(--page-inset);
    font-family: var(--font-marker);
    font-size: var(--fs-3);
    color: var(--color-red);
}

@media (prefers-reduced-motion: reduce) {
    .work-filter { transition: none; }
}

@media (max-width: 640px) {
    .work-filters { padding-inline: var(--container-padding); }
    .work-empty { padding-inline: var(--container-padding); }

    /* ── mobile: the chips collapse into a dropdown ── */
    .work-filters__toggle {
        display: flex;
        align-items: center;
        gap: 0.6rem;
        width: 100%;
        padding: 0.85rem 1rem;
        border: 1px solid var(--color-cream);
        border-radius: var(--radius-md);
        background: none;
        color: var(--color-cream);
        font-family: var(--font-body);
        font-size: 0.85rem;
        line-height: 1;
        cursor: pointer;
    }

    .work-filters__state {
        margin-left: auto;
        color: var(--color-red);
    }

    .work-filters__chev {
        width: 16px;
        height: 16px;
        flex: none;
        transition: transform 0.3s var(--transition-smooth);
    }

    .work-filters.is-open .work-filters__chev { transform: rotate(180deg); }

    .work-filters.is-open .work-filters__toggle {
        border-bottom-left-radius: 0;
        border-bottom-right-radius: 0;
        border-bottom-color: transparent;
    }

    .work-filters__list {
        display: none;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        border: 1px solid var(--color-cream);
        border-top: 0;
        border-radius: 0 0 var(--radius-md) var(--radius-md);
        overflow: hidden;
    }

    .work-filters.is-open .work-filters__list { display: flex; }

    .work-filters__list .work-filter {
        justify-content: flex-start;
        border: 0;
        border-radius: 0;
        padding: 0.8rem 1rem;
        font-size: 0.85rem;
    }

    .work-filters__list .work-filter + .work-filter {
        border-top: 1px solid rgba(250, 250, 255, 0.18);
    }
}

@media (prefers-reduced-motion: reduce) {
    .work-filters__chev { transition: none; }
}

/* ── projects.html page title ─────────────────────────────────── */
.page-header__title {
    margin: 0;
    font-family: var(--font-marker);   /* Instrument Serif */
    font-weight: 400;
    font-size: var(--fs-1);
    line-height: 1;
    text-transform: none;              /* beat the global h1-h4 rule */
    color: var(--color-cream);
}

/* the title lines up with the filter bar and the card grid below it */
.page-header > .container {
    max-width: none;
    padding-inline: var(--page-inset);
}

/* ============================================
   ABOUT + CONTACT: match the width of everything else

   Both pages sat in the 1200px .container while the work grid, the
   case studies and the homepage about section all run to --page-inset.
   On a wide screen that read as a different site.
   ============================================ */
.about-opening > .container,
.about-reasoning > .container,
.services-section > .container,
.about-image-divider > .container,
.about-process > .container,
.contact-section > .container {
    max-width: none;
    padding-inline: var(--page-inset);
}

/* ============================================
   ABOUT PAGE (2026)

   Four blocks: what Double Dash is, who runs it, what it does, and
   how the work happens.

   House rules this follows:
     - sizes come from the --fs-1..6 tiers, never a raw clamp.
       fs-1 is the BIGGEST, fs-6 the smallest.
     - big display lines are Instrument Serif (--font-marker) with
       text-transform: none, to beat the global uppercase on h1-h4.
     - small labels are Archivo (--font-body) uppercase at --fs-6.
     - accent is --color-red, same as every other page.
   ============================================ */
.ab-inset { padding-inline: var(--page-inset); }

.ab-block { padding-block: var(--space-4xl); }

/* ── 1. what Double Dash is ──
   Opens on the orange ground, same pairing the outro uses at the other
   end of the site: black ink, indigo for the accent. Everything below
   it returns to the black page. */
.ab-open {
    background-color: var(--color-red);
    color: var(--color-black);
    /* Half the first screen. svh not vh, so a phone's collapsing URL bar
       cannot make it taller than intended. min-height, not height, so it
       still grows if the copy needs more room. */
    min-height: 50svh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    /* the top figure is the navbar clearance plus breathing room under it */
    padding-block: calc(var(--space-4xl) + var(--space-lg)) var(--space-2xl);
}

/* One line, always - it reads as a single phrase and breaking it in
   the middle spoils that. Since it cannot wrap, the type steps down a
   tier on narrow screens instead of running off the edge. */
.ab-statement {
    font-family: var(--font-marker);   /* Instrument Serif, real italic cut */
    font-style: italic;
    font-weight: 400;
    font-size: var(--fs-2);
    line-height: 1;
    text-transform: none;              /* beat the global h1-h4 rule */
    white-space: nowrap;
    margin: 0;
    color: var(--color-black);
}

@media (max-width: 480px) {
    .ab-statement { font-size: var(--fs-3); }
}

@media (max-width: 360px) {
    .ab-statement { font-size: var(--fs-4); }
}

/* Runs the full width, single measure. It sits above the headline, so
   the gap below it is what separates the two; the gap above is the air
   between it and the navbar. */
.ab-open__body {
    margin: var(--space-2xl) 0;
}

/* A lead size: --fs-4 is about half of --fs-2 at the top of its range
   (1.9rem against 4rem), and still well above body copy. */
.ab-open__body p {
    font-size: var(--fs-4);
    line-height: 1.3;
    margin: 0 0 0.6em;
}

.ab-open__body p:last-child { margin-bottom: 0; }

/* ── 2. who runs it ──
   The homepage about section's shape at a smaller size: the title sits
   level with the top of the photo, the body starts level with its
   middle. The two equal rows are what does that. */
.ab-me { padding-block: var(--space-4xl); }

.ab-me__grid {
    display: grid;
    /* the photo takes the smaller share - stretch is what keeps it the
       same height as the text, which is what puts the body level with
       its middle, so the width is the only thing to trade */
    grid-template-columns: 1.6fr 1fr;
    gap: var(--space-2xl);
    align-items: stretch;
}

.ab-me__text {
    display: grid;
    grid-template-rows: 1fr 1fr;
}

.ab-me__title {
    font-family: var(--font-marker);
    font-weight: 400;
    font-size: var(--fs-2);
    line-height: 1;
    text-transform: none;
    margin: 0;
    align-self: start;
}

.ab-me__title em {
    font-style: italic;
    color: var(--color-red);
}

.ab-me__body p {
    font-size: var(--fs-5);
    line-height: 1.55;
    margin: 0 0 1em;
}

.ab-me__body p:last-child { margin-bottom: 0; }

/* same treatment the homepage gives it */
.ab-me__body .salam {
    font-family: var(--font-marker);
    font-style: italic;
    font-weight: 400;
    font-size: calc(var(--fs-5) + 4px);
}

.ab-me__image img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: var(--radius-lg);
}

/* ── 3. services ──
   Heading on the left, six groups on the right: Logo & Brand /
   Illustration / Motion, then Web / Social / Print.

   Same track sizes and gap as .ab-me__grid above, so the groups start
   on the photo's left edge rather than floating on their own measure. */
.ab-services {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-2xl);
    align-items: start;
}

/* same setting as the other two section headings on this page */
.ab-label {
    font-family: var(--font-marker);
    font-size: var(--fs-2);
    font-weight: 400;
    text-transform: none;
    line-height: 1;
    margin: 0;
    color: var(--color-cream);
}

.ab-fields {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-lg);
}

.ab-field h3 {
    font-family: var(--font-body);
    font-size: var(--fs-6);
    font-weight: 600;
    text-transform: uppercase;
    line-height: 1.2;
    margin: 0 0 var(--space-sm);
    padding-bottom: 0.7rem;
    border-bottom: thin solid currentColor;
}

.ab-field ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

.ab-field li {
    font-size: var(--fs-5);
    line-height: 1.45;
    padding-block: 0.25rem;
}

/* ── 4. FORGE, five columns ── */
/* The same shape as the services list: the heading sits in the left
   column of .ab-services and the stages stack down the right. */
.forge {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-lg);
}

/* Name and description sit side by side, the same label-then-content
   shape the section itself uses. baseline so the big serif name lines
   up with the first line of the copy rather than its box. */
.forge__col {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
    gap: var(--space-md);
    align-items: baseline;
}

.forge__name {
    font-family: var(--font-marker);
    font-weight: 400;
    font-size: var(--fs-3);
    line-height: 1;
    text-transform: none;
    margin: 0;
}

.forge__col p {
    font-size: var(--fs-5);
    line-height: 1.55;
    margin: 0;
}

/* ── stacked ── */
@media (max-width: 1300px) {
    /* the service groups get tight before the page stacks */
    .ab-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 860px) {
    .ab-services {
        grid-template-columns: 1fr;
        gap: var(--space-md);
    }

    .ab-label { margin-bottom: var(--space-xs); }

    /* title, body, then photo - normal top-down reading order */
    .ab-me__grid {
        grid-template-columns: 1fr;
        gap: var(--space-lg);
    }

    .ab-me__text {
        display: block;   /* no half-and-half split once it is stacked */
    }

    .ab-me__title { margin-bottom: var(--space-md); }

    .ab-me__image img { height: auto; }


    .ab-block,
    .ab-me { padding-block: var(--space-3xl); }
}

@media (max-width: 560px) {
    .ab-fields { grid-template-columns: 1fr; }
}
/* ============================================
   FORGE PROCESS PAGE

   Frame / Onboard / Refine / Generate / Exhibit. One band per stage,
   with a rail down the left that tracks which one you are in.
   Same house rules as the about page above.
   ============================================ */
.fg-inset { padding-inline: var(--page-inset); }

/* the word set as five separate letters so they can be spread to the
   full measure - flex, not letter-spacing, which leaves a gap hanging

.fg-word__letter { display: block; }

/* ── stacked ── */
@media (max-width: 900px) {
    /* the rail needs a margin of its own to sit in, and there is not
       one any more */
    .fg-rail { display: none; }

    .fg-stage { padding-block: var(--space-3xl); }
}

/* ============================================
   NAV TINT

   A section marked [data-nav-tint] is a coloured band the bar should
   blend into while it is over it. The bar carries that colour, and
   switches to the site's black once the band scrolls out from under
   it. initNavTint in main.js does the toggling.

   The ink flips with it: the logo is a fixed-colour SVG loaded as an
   <img>, so it cannot inherit currentColor - brightness(0) gives it
   the same solid-black treatment the footer logotype gets on orange.
   ============================================ */
.navbar.is-tinted::before { background-color: var(--color-red); }

.navbar.is-tinted .nav-link-cycle { color: var(--color-black); }
.navbar.is-tinted .logo-mark { filter: brightness(0); }
.navbar.is-tinted .mobile-menu-toggle span { background-color: var(--color-black); }

/* the takeover menu puts a dark sheet behind the bar, so the black ink
   would vanish into it */
.menu-open .navbar.is-tinted .nav-link-cycle { color: var(--color-cream); }
.menu-open .navbar.is-tinted .logo-mark { filter: none; }
.menu-open .navbar.is-tinted .mobile-menu-toggle span { background-color: var(--color-cream); }

/* ============================================
   BODY COPY WEIGHT

   Archivo Thin, the weight the homepage About section has always used,
   applied to prose everywhere so the site reads consistently.

   Set per-selector rather than on body: nav links, form labels and
   inputs, the filter chips, the category tags, the side rail and the
   footer base all declare no weight of their own, so a global rule
   would thin those out too, which is not what is wanted.
   ============================================ */
.about-description p,
.ab-open__body p,
.ab-me__body p,
.ab-field li,
.forge__col p,
.case-study-intro .description,
.case-study-solution p,
.cs-missing p {
    font-weight: 100;
}

/* ============================================
   CASE STUDY INTRO: description + scope

   Two columns under the centred title. The scope column is dropped
   entirely when a project has none, and :only-child then lets the
   description take the full width on its own.
   ============================================ */
.case-study-body {
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: var(--space-3xl);
    align-items: start;
}

.case-study-body .description:only-child {
    grid-column: 1 / -1;
}

.case-study-scope__title {
    font-family: var(--font-body);
    font-size: var(--fs-6);
    font-weight: 500;
    text-transform: uppercase;
    line-height: 1.2;
    margin: 0 0 var(--space-sm);
    padding-bottom: 0.7rem;
    border-bottom: thin solid currentColor;
    color: var(--color-red);
}

.case-study-scope ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

.case-study-scope li {
    font-size: var(--fs-5);
    font-weight: 100;
    line-height: 1.5;
    padding-block: 0.3rem;
}

@media (max-width: 860px) {
    /* the scope reads as a footnote to the intro once stacked */
    .case-study-body {
        grid-template-columns: 1fr;
        gap: var(--space-lg);
    }
}

/* ============================================
   CASE STUDY INTRO, STACKED

   The title, the role line and the copy all sit in one column on a
   phone, so the role ends up sandwiched between two blocks of text with
   nothing separating it. Give it room on both sides.
   ============================================ */
@media (max-width: 860px) {
    .case-study-intro-grid {
        gap: var(--space-2xl);
    }

    .case-study-intro .title-section h1 {
        margin-bottom: var(--space-md);
    }

    .case-study-intro .meta {
        display: block;
        margin-bottom: var(--space-sm);
    }
}

/* ============================================
   MOTION TOGGLE

   Moved here from liquid-hero.css. It used to be a hero control, so
   it lived in the hero stylesheet - but the projects page does not
   load that file, so the button rendered there completely unstyled.
   ============================================ */
.motion-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.85rem;
    border: thin solid rgba(255, 253, 210, 0.4);
    border-radius: 999px;
    background: rgba(32, 29, 30, 0.35);
    color: var(--color-cream);
    font-family: var(--font-body);
    font-size: 0.7rem;
    text-transform: uppercase;
    cursor: pointer;
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    transition: background 0.3s var(--transition-smooth),
        border-color 0.3s var(--transition-smooth);
}

.motion-toggle:hover {
    background: rgba(32, 29, 30, 0.6);
    border-color: var(--color-cream);
}

.motion-toggle__icon {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--color-cream);
    animation: motionTogglePulse 1.6s ease-in-out infinite;
}

@keyframes motionTogglePulse {
    0%, 100% { opacity: 0.4; transform: scale(0.8); }
    50%      { opacity: 1;   transform: scale(1.2); }
}

.motion-toggle[aria-pressed="true"] .motion-toggle__icon {
    animation: none;
    opacity: 1;
    background: var(--color-red);
}

@media (prefers-reduced-motion: reduce) {
    .motion-toggle__icon { animation: none; }
}

/* ============================================
   NAV ACTIONS: motion toggle + burger

   The toggle keeps its own look (see .motion-toggle in liquid-hero.css),
   it has just moved out of the hero and into the bar so it is reachable
   from the projects page too.
   ============================================ */
.navbar .nav-actions {
    grid-column: 3;
    grid-row: 1;
    justify-self: end;
    display: flex;
    align-items: center;
    gap: var(--space-sm);
}

/* The bar's height is set by its tallest item, so this must stay well
   under it. nowrap matters: "Reduce Motion" wrapping to two lines is
   what makes the pill taller than the bar and pushes the nav down. */
.navbar .motion-toggle {
    padding: 0.3rem 0.7rem;
    font-size: 0.62rem;
    line-height: 1;
    white-space: nowrap;
    flex: none;
}

.navbar .motion-toggle__icon {
    width: 6px;
    height: 6px;
}

@media (max-width: 640px) {
    /* keep the words: a bare dot gives no clue what it does */
    .navbar .motion-toggle {
        padding: 0.28rem 0.55rem;
        font-size: 0.55rem;
        gap: 0.35rem;
    }

    /* Nothing on the projects page moves on a phone: the squish needs a
       cursor and the card parallax is already off below 760px. A control
       that changes nothing is worse than no control. */
    .page-projects .navbar .motion-toggle { display: none; }
}

/* ============================================
   REDUCED MOTION: the work grids

   .liquid-hero-reduced is set by the toggle and persists across pages.
   This is the distracting part: cards growing and shrinking under the
   cursor as you read down the grid.
   ============================================ */
.liquid-hero-reduced .work-scatter--squish .work-row:hover > .work-card,
.liquid-hero-reduced .work-scatter--squish .work-row:hover > .work-card:hover {
    flex-basis: calc(var(--span) / 3);
}

.liquid-hero-reduced .work-card,
.liquid-hero-reduced .work-card__frame,
.liquid-hero-reduced .work-card__img {
    transition: none;
}

/* the second still still swaps in, it just does not fade */
.liquid-hero-reduced .work-card__img--hover {
    transition: none;
}

/* parallax offsets are written as --py by initParallax; neutralise them */
.liquid-hero-reduced .work-card {
    --py: 0px;
    --p: 0;
}

@media (max-width: 560px) {
    /* no room for two columns inside a column: name over description */
    .forge__col {
        grid-template-columns: 1fr;
        gap: var(--space-xs);
    }
}

/* ============================================
   HIDE THE BAR ON THE WAY DOWN

   Nothing about the bar changes but this: it reuses the transform
   transition already declared on .navbar, so the backdrop, the tint,
   the compact outro state and everything else behave as before.
   ============================================ */
.navbar.is-hidden {
    transform: translateY(-100%);
}

/* The takeover menu is anchored to the bar and its close button lives
   in it, so sliding away mid-menu would strand the visitor. */
.menu-open .navbar.is-hidden {
    transform: none;
}

/* --------------------------------------------------------------------------
   404
   Borrows the page-header type and the standard button. Only the muted
   code above the heading and the stacking are new here.
   -------------------------------------------------------------------------- */
.notfound {
    min-height: 70svh;
    display: flex;
    align-items: center;
}

.notfound__code {
    margin: 0 0 var(--space-sm);
    font-family: var(--font-marker);
    font-size: var(--fs-2);
    line-height: 1;
    opacity: 0.45;
}

.notfound__body {
    max-width: 46ch;
    margin: var(--space-md) 0 var(--space-lg);
    font-weight: 100;
}

.notfound__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-md);
}

.notfound__home {
    text-decoration: underline;
    text-underline-offset: 0.25em;
}
