/* ============================================================
   Vision Marketing & Solutions
   "Aurora" — a dark-first, depth-driven system.
   Live WebGL field behind everything, glass surfaces floating
   above it, 3D tilt on the cards, choreographed scroll motion.
   ============================================================ */

/* ---------- 1. Tokens ------------------------------------- */
:root {
    --green:        #35a668;
    --green-lit:    #5fe39b;
    --green-deep:   #1e6b43;
    --grad:         linear-gradient(135deg, #35a668 0%, #5fe39b 100%);
    --grad-soft:    linear-gradient(135deg, rgba(53,166,104,.16), rgba(95,227,155,.06));

    /* The wordmark is set in a light geometric sans with wide tracking —
       Futura-adjacent. Jost is the closest free match, so the display voice
       and the logo are now the same typeface rather than a serif fighting it. */
    --ff-display: 'Jost', 'Futura', 'Century Gothic', system-ui, sans-serif;
    --ff-body:    'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
    /* The giant display voice: same family, set light and tracked out like the
       "MARKETING & SOLUTIONS" line under the mark. */
    --ff-tall:    'Jost', 'Futura', 'Century Gothic', system-ui, sans-serif;

    /* Secondary accent. The palette stays entirely green — this is the
       brighter spring tone that lifts eyebrows, tags and hover states away
       from the base brand green without introducing a second hue. */
    --lime:      #8fe36a;
    --lime-lit:  #b9f58f;
    --lime-soft: rgba(143, 227, 106, .14);
    --lime-line: rgba(143, 227, 106, .32);

    --step--1: clamp(.82rem, .8rem + .1vw, .88rem);
    --step-0:  clamp(1rem, .97rem + .16vw, 1.07rem);
    --step-1:  clamp(1.18rem, 1.09rem + .42vw, 1.45rem);
    --step-2:  clamp(1.6rem, 1.35rem + 1.15vw, 2.5rem);
    --step-3:  clamp(2.2rem, 1.6rem + 2.8vw, 4.2rem);
    --step-4:  clamp(2.9rem, 1.7rem + 5.4vw, 7rem);
    --step-mega: clamp(3.4rem, .2rem + 15vw, 15rem);   /* the ghost headline */

    --gutter:  clamp(1.2rem, .8rem + 1.8vw, 3rem);
    --section: clamp(4.5rem, 2.5rem + 7vw, 9.5rem);

    --r-sm: 12px;
    --r:    20px;
    --r-lg: 28px;
    --r-xl: 40px;
    --pill: 999px;

    /* The sticky header sits in normal flow, so anything that wants the full
       viewport has to pull back up by exactly this much. */
    --header-h: calc(66px + 1.7rem);

    --ease:     cubic-bezier(.22, .68, .32, 1);
    --ease-out: cubic-bezier(.16, 1, .3, 1);
}

:root,
[data-theme="dark"] {
    --bg:        #050607;
    --bg-2:      #0b0e11;
    --glass:     rgba(18, 24, 26, .58);
    --glass-2:   rgba(24, 32, 34, .72);
    --glass-hi:  rgba(255, 255, 255, .07);
    --line:      rgba(255, 255, 255, .09);
    --line-2:    rgba(255, 255, 255, .05);
    --text:      #eef2f0;
    --muted:     #a4a9a7;
    --faint:     #6b736f;
    --accent:      var(--green-lit);
    --accent-soft: rgba(95, 227, 155, .13);
    --accent-line: rgba(95, 227, 155, .3);
    --on-accent:   #04140b;
    --ring:      rgba(95, 227, 155, .32);
    --shadow:    0 32px 80px -20px rgba(0, 0, 0, .8);
    --shadow-sm: 0 8px 28px -10px rgba(0, 0, 0, .7);
    --glow:      0 0 0 1px rgba(95,227,155,.26), 0 30px 70px -24px rgba(53,166,104,.5);
    --lift:      inset 0 1px 0 rgba(255, 255, 255, .08);
    --sheen:     rgba(255, 255, 255, .1);
    color-scheme: dark;
}

/* Unused on the public site, which is pinned to dark in the document head.
   Kept because the tokens are the reference for the admin panel's light theme
   and because deleting a whole palette to save 20 lines is a bad trade. */
[data-theme="light"] {
    --bg:        #f5f7f3;
    --bg-2:      #eef1ec;
    --glass:     rgba(255, 255, 255, .72);
    --glass-2:   rgba(255, 255, 255, .86);
    --glass-hi:  rgba(255, 255, 255, .9);
    --line:      rgba(13, 20, 17, .1);
    --line-2:    rgba(13, 20, 17, .06);
    --text:      #0b1210;
    --muted:     #55645c;
    --faint:     #87958c;
    --accent:      #1d7d4a;
    --accent-soft: rgba(53, 166, 104, .12);
    --accent-line: rgba(53, 166, 104, .3);
    /* The bright spring green is unreadable on a pale background, so the
       light theme darkens it while keeping the same hue. #3d7a22 clears
       4.5:1 against --bg; the earlier, lighter pick only reached 3.6:1. */
    --lime:      #3d7a22;
    --lime-lit:  #5a9c3a;
    --lime-soft: rgba(61, 122, 34, .12);
    --lime-line: rgba(61, 122, 34, .3);
    --on-accent:   #ffffff;
    --ring:      rgba(53, 166, 104, .3);
    --shadow:    0 32px 70px -24px rgba(13, 20, 17, .22);
    --shadow-sm: 0 8px 26px -12px rgba(13, 20, 17, .16);
    --glow:      0 0 0 1px rgba(53,166,104,.28), 0 28px 60px -26px rgba(53,166,104,.42);
    --lift:      inset 0 1px 0 rgba(255, 255, 255, .95);
    --sheen:     rgba(255, 255, 255, .75);
    color-scheme: light;
}

/* ---------- 2. Base --------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
    margin: 0;
    font-family: var(--ff-body);
    font-size: var(--step-0);
    line-height: 1.66;
    color: var(--text);
    background: var(--bg);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;
}

/* The WebGL field and its CSS understudy. */
#aurora {
    position: fixed; inset: 0; z-index: -2;
    width: 100%; height: 100%;
    pointer-events: none;
    background:
        radial-gradient(70vw 60vh at 12% -10%, rgba(53,166,104,.20), transparent 62%),
        radial-gradient(60vw 55vh at 92% 6%,  rgba(38,128,145,.14), transparent 60%),
        radial-gradient(80vw 65vh at 55% 110%, rgba(95,227,155,.12), transparent 65%);
}
#aurora.is-live { background: none; }   /* shader took over */

[data-theme="light"] #aurora {
    background:
        radial-gradient(70vw 60vh at 12% -10%, rgba(53,166,104,.16), transparent 62%),
        radial-gradient(60vw 55vh at 92% 6%,  rgba(38,128,145,.10), transparent 60%),
        radial-gradient(80vw 65vh at 55% 110%, rgba(95,227,155,.14), transparent 65%);
}
[data-theme="light"] #aurora.is-live { background: none; }

/* Grain over the whole page so the large soft fields never band. */
body::after {
    content: ""; position: fixed; inset: 0; z-index: -1;
    pointer-events: none; opacity: .4;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='4'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.04'/%3E%3C/svg%3E");
}

h1, h2 {
    font-family: var(--ff-display);
    font-weight: 400;
    letter-spacing: -.018em;
    line-height: 1.02;
    color: var(--text);
    margin: 0 0 .4em;
    text-wrap: balance;
}
h3, h4, h5, h6 {
    font-family: var(--ff-body);
    font-weight: 600;
    letter-spacing: -.02em;
    line-height: 1.25;
    margin: 0 0 .5em;
    text-wrap: balance;
}
h1 { font-size: var(--step-4); }
h2 { font-size: var(--step-3); }
h3 { font-size: var(--step-2); }
h4 { font-size: var(--step-1); }

em, .accent-em {
    font-family: var(--ff-display);
    font-style: italic;
    background: var(--grad);
    -webkit-background-clip: text; background-clip: text; color: transparent;
}

p { margin: 0 0 1rem; text-wrap: pretty; }
a { color: inherit; text-decoration: none; }
img, svg, video { max-width: 100%; height: auto; display: block; }
hr { border: 0; border-top: 1px solid var(--line); margin: 3rem 0; }
::selection { background: var(--green); color: #fff; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: var(--r-sm); }

::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--line); border-radius: 99px; border: 3px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-thumb:hover { background: var(--accent-line); background-clip: content-box; }

.skip-link {
    position: absolute; left: -999px; top: 0; z-index: 300;
    background: var(--accent); color: var(--on-accent);
    padding: .85rem 1.5rem; border-radius: var(--pill); font-weight: 600;
}
.skip-link:focus { left: .75rem; top: .75rem; }

/* ---------- 3. Layout ------------------------------------- */
.shell { width: min(100% - (var(--gutter) * 2), 1280px); margin-inline: auto; }
.shell-narrow { width: min(100% - (var(--gutter) * 2), 760px); margin-inline: auto; }
.section { padding-block: var(--section); position: relative; }
.section-tight { padding-block: calc(var(--section) * .6); position: relative; }

.eyebrow {
    display: inline-flex; align-items: center; gap: .6rem;
    font-size: .74rem; font-weight: 600; letter-spacing: .14em; text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 1.4rem;
    padding: .45rem .95rem .45rem .75rem;
    border-radius: var(--pill);
    background: var(--accent-soft);
    border: 1px solid var(--accent-line);
    backdrop-filter: blur(10px);
}
.eyebrow::before {
    content: ""; width: 6px; height: 6px; border-radius: 50%; flex: none;
    background: var(--accent);
    box-shadow: 0 0 0 4px var(--accent-soft);
    animation: pulse 2.6s var(--ease) infinite;
}
@keyframes pulse {
    0%, 100% { box-shadow: 0 0 0 3px var(--accent-soft); }
    50%      { box-shadow: 0 0 0 7px transparent; }
}
@media (prefers-reduced-motion: reduce) { .eyebrow::before { animation: none; } }
.eyebrow--plain { background: none; border: 0; padding: 0; backdrop-filter: none; }
.eyebrow--plain::before { animation: none; }

.section-head { margin-bottom: clamp(2.5rem, 1rem + 4vw, 4.5rem); }
.section-head.row-between h2 { margin-bottom: 0; }
.section-head p { color: var(--muted); max-width: 54ch; font-size: var(--step-1); line-height: 1.6; }

.lead { font-size: var(--step-1); line-height: 1.65; color: var(--muted); max-width: 56ch; }
.muted { color: var(--muted); }
.mono { font-size: .74rem; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--faint); }

/* ---------- 4. Glass surface ------------------------------ */
.glass {
    position: relative;
    background: var(--glass);
    backdrop-filter: blur(22px) saturate(150%);
    -webkit-backdrop-filter: blur(22px) saturate(150%);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--lift), var(--shadow-sm);
}

/* ---------- 5. Buttons ------------------------------------ */
.btn-v {
    position: relative; isolation: isolate;
    display: inline-flex; align-items: center; gap: .6rem;
    padding: .95rem 1.8rem;
    font-family: var(--ff-body); font-size: .94rem; font-weight: 600;
    color: var(--text);
    background: var(--glass-2);
    backdrop-filter: blur(14px);
    border: 1px solid var(--line); border-radius: var(--pill);
    cursor: pointer; white-space: nowrap;
    overflow: hidden;
    transition: color .35s var(--ease), border-color .35s var(--ease),
                box-shadow .35s var(--ease), transform .2s var(--ease);
}
/* Fill sweeps in from the left on hover. */
.btn-v::before {
    content: ""; position: absolute; inset: 0; z-index: -1;
    background: var(--grad);
    transform: translateX(-101%);
    transition: transform .5s var(--ease-out);
}
.btn-v:hover { color: var(--on-accent); border-color: transparent; box-shadow: 0 14px 36px -12px rgba(53,166,104,.7); }
.btn-v:hover::before { transform: none; }
.btn-v:active { transform: scale(.975); }
.btn-v i, .btn-v svg { flex: none; transition: transform .35s var(--ease); }
.btn-v:hover i.bi-arrow-right { transform: translateX(4px); }

.btn-v.is-brand { background: var(--grad); color: var(--on-accent); border-color: transparent; box-shadow: 0 14px 38px -14px rgba(53,166,104,.75); }
.btn-v.is-brand::before { background: linear-gradient(135deg, #2b9159 0%, #47d68c 100%); }
.btn-v.is-brand:hover { box-shadow: 0 20px 50px -14px rgba(53,166,104,.9); }

.btn-v.is-line { background: transparent; }
.btn-v.is-sm { padding: .58rem 1.2rem; font-size: .86rem; }
.btn-v.is-lg { padding: 1.12rem 2.3rem; font-size: 1rem; }
.btn-v.is-block { display: flex; width: 100%; justify-content: center; }

.link-v {
    display: inline-flex; align-items: center; gap: .5rem;
    font-weight: 600; color: var(--accent);
    transition: gap .35s var(--ease);
}
.link-v:hover { gap: .9rem; }

/* ---------- 6. Cursor ------------------------------------- */
.cursor-ring {
    position: fixed; top: 0; left: 0; z-index: 9999;
    width: 30px; height: 30px; border-radius: 50%;
    border: 1px solid var(--accent-line);
    background: var(--accent-soft);
    pointer-events: none;
    opacity: 0;
    transition: width .3s var(--ease), height .3s var(--ease),
                opacity .3s var(--ease), background .3s var(--ease), border-color .3s var(--ease);
    mix-blend-mode: difference;
}
.cursor-ring.is-on { opacity: 1; }
.cursor-ring.is-lg { width: 62px; height: 62px; background: transparent; border-color: var(--accent); }
.cursor-ring.is-down { width: 22px; height: 22px; }
@media (pointer: coarse) { .cursor-ring { display: none; } }

/* ---------- 7. Header ------------------------------------- */
.site-header {
    position: sticky; top: 0; z-index: 60;
    padding-block: .85rem;
    transition: padding .4s var(--ease);
}
.site-header__bar {
    display: flex; align-items: center; gap: 1rem;
    height: 66px; padding-inline: 1.15rem;
    border-radius: var(--pill);
    border: 1px solid transparent;
    transition: background .4s var(--ease), border-color .4s var(--ease),
                box-shadow .4s var(--ease), backdrop-filter .4s var(--ease);
}
.site-header.is-stuck { padding-block: .55rem; }
.site-header.is-stuck .site-header__bar {
    background: var(--glass-2);
    backdrop-filter: blur(20px) saturate(170%);
    -webkit-backdrop-filter: blur(20px) saturate(170%);
    border-color: var(--line);
    box-shadow: var(--lift), var(--shadow-sm);
}

.brand { display: flex; align-items: center; flex: none; }
.brand img { height: 32px; width: auto; transition: transform .4s var(--ease); }
.brand:hover img { transform: scale(1.05); }
/* Every place the lockup appears swaps on one rule. A hardcoded white mark
   was invisible on the light theme, and a lockup that is not listed here
   renders both files stacked on top of each other. */
[data-theme="light"] .brand img.logo-dark,
[data-theme="light"] .foot-brand img.logo-dark,
[data-theme="light"] .pauth__logo img.logo-dark { display: none; }
:root:not([data-theme="light"]) .brand img.logo-light,
:root:not([data-theme="light"]) .foot-brand img.logo-light,
:root:not([data-theme="light"]) .pauth__logo img.logo-light { display: none; }

.site-nav { display: flex; align-items: center; gap: .2rem; margin-left: auto; }
.site-nav a.navlink {
    position: relative;
    padding: .58rem 1.05rem; border-radius: var(--pill);
    font-size: .93rem; font-weight: 500; color: var(--muted);
    transition: color .3s var(--ease);
}
.site-nav a.navlink::before {
    content: ""; position: absolute; inset: 0; z-index: -1;
    border-radius: var(--pill); background: var(--glass-hi);
    opacity: 0; transform: scale(.85);
    transition: opacity .3s var(--ease), transform .3s var(--ease);
}
.site-nav a.navlink:hover { color: var(--text); }
.site-nav a.navlink:hover::before { opacity: 1; transform: none; }
.site-nav a.navlink.is-active { color: var(--text); font-weight: 600; }
.site-nav a.navlink.is-active::before { opacity: 1; transform: none; background: var(--accent-soft); }

.header-tools { display: flex; align-items: center; gap: .45rem; flex: none; }

.icon-btn {
    width: 44px; height: 44px; flex: none;
    display: inline-grid; place-items: center;
    background: var(--glass-2); color: var(--text);
    backdrop-filter: blur(12px);
    border: 1px solid var(--line); border-radius: 50%;
    cursor: pointer; font-size: 1rem;
    transition: border-color .3s var(--ease), color .3s var(--ease), transform .3s var(--ease);
}
.icon-btn:hover { border-color: var(--accent-line); color: var(--accent); transform: translateY(-2px); }

.lang-switch { position: relative; }
.lang-switch__btn {
    display: inline-flex; align-items: center; gap: .45rem;
    height: 44px; padding: 0 1.1rem;
    font-family: var(--ff-body); font-size: .84rem; font-weight: 600; letter-spacing: .05em;
    background: var(--glass-2); color: var(--text); backdrop-filter: blur(12px);
    border: 1px solid var(--line); border-radius: var(--pill);
    cursor: pointer; transition: border-color .3s var(--ease), color .3s var(--ease);
}
.lang-switch__btn:hover { border-color: var(--accent-line); color: var(--accent); }
.lang-switch__menu {
    position: absolute; right: 0; top: calc(100% + .6rem);
    min-width: 168px; padding: .45rem;
    background: var(--glass-2); backdrop-filter: blur(22px) saturate(160%);
    border: 1px solid var(--line); border-radius: var(--r);
    box-shadow: var(--shadow);
    opacity: 0; transform: translateY(-10px) scale(.96); pointer-events: none;
    transition: opacity .28s var(--ease), transform .28s var(--ease);
    z-index: 70;
}
.lang-switch.is-open .lang-switch__menu { opacity: 1; transform: none; pointer-events: auto; }
.lang-switch__menu a {
    display: flex; align-items: center; justify-content: space-between; gap: .5rem;
    padding: .6rem .85rem; border-radius: var(--r-sm);
    font-size: .9rem; color: var(--muted);
    transition: background .2s var(--ease), color .2s var(--ease);
}
.lang-switch__menu a:hover { background: var(--glass-hi); color: var(--text); }
.lang-switch__menu a.is-active { color: var(--accent); font-weight: 600; }
.lang-switch__menu a span { font-size: .7rem; letter-spacing: .1em; opacity: .65; }

.nav-toggle { display: none; }

.mobile-nav {
    position: fixed; inset: 92px .8rem auto; z-index: 55;
    padding: 1.4rem; border-radius: var(--r-lg);
    background: var(--glass-2);
    backdrop-filter: blur(26px) saturate(170%);
    border: 1px solid var(--line);
    box-shadow: var(--shadow);
    max-height: calc(100dvh - 110px); overflow-y: auto;
    opacity: 0; transform: translateY(-16px) scale(.97); pointer-events: none;
    transition: opacity .32s var(--ease), transform .32s var(--ease);
}
.mobile-nav.is-open { opacity: 1; transform: none; pointer-events: auto; }
.mobile-nav a.m-link {
    display: flex; align-items: center; gap: 1rem;
    padding: .9rem .7rem; border-radius: var(--r);
    font-family: var(--ff-display); font-size: 1.7rem; color: var(--text);
    transition: background .25s var(--ease), padding-left .25s var(--ease);
}
.mobile-nav a.m-link:hover { background: var(--glass-hi); padding-left: 1.1rem; }
.mobile-nav a.m-link span { font-family: var(--ff-body); font-size: .68rem; font-weight: 600; color: var(--faint); letter-spacing: .1em; }
.mobile-nav a.m-link.is-active { color: var(--accent); }

@media (max-width: 991px) {
    .site-nav { display: none; }
    .nav-toggle { display: inline-grid; }
    /* The nav carried the `margin-left: auto` that pushed the tools to the
       right edge. With the nav hidden nothing did, so the whole bar bunched
       against the logo with dead space beside it. */
    .header-tools { margin-left: auto; }
}

.scroll-line {
    position: fixed; inset: 0 0 auto 0; z-index: 61;
    height: 2px; background: var(--grad);
    transform: scaleX(0); transform-origin: 0 50%;
    box-shadow: 0 0 14px rgba(95,227,155,.7);
    pointer-events: none;
}

/* ---------- 8. Hero --------------------------------------- */
.hero {
    position: relative;
    padding-block: clamp(3.5rem, 1rem + 8vw, 8rem) clamp(3.5rem, 1.5rem + 6vw, 7rem);
}
.hero > .shell { position: relative; z-index: 1; }
.hero__grid {
    display: grid;
    grid-template-columns: minmax(0, 1.04fr) minmax(0, .96fr);
    gap: clamp(2.5rem, 1rem + 5vw, 5.5rem);
    align-items: center;
}
.hero h1 { font-size: var(--step-4); line-height: .97; margin-bottom: 1.6rem; }
.hero__actions { display: flex; flex-wrap: wrap; gap: .85rem; margin-top: 2.5rem; }

/* Floating 3D card stack */
.hero__media { position: relative; perspective: 1400px; }
.hero__stack {
    position: relative;
    transform-style: preserve-3d;
    transform: rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
    transition: transform .5s var(--ease);
}
.hero__card {
    position: relative;
    aspect-ratio: 4 / 3.3;
    border-radius: var(--r-xl);
    overflow: hidden;
    border: 1px solid var(--line);
    box-shadow: var(--shadow);
    transform: translateZ(0);
}
.hero__card img,
.hero__card .slide {
    position: absolute; inset: 0;
    width: 100%; height: 100%; object-fit: cover;
    opacity: 0; transform: scale(1.06);
    transition: opacity 1.2s var(--ease), transform 8s linear;
}
.hero__card .slide.is-active { opacity: 1; transform: scale(1); }
.hero__card::after {
    content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
    border-radius: inherit;
    box-shadow: var(--lift);
    background: linear-gradient(200deg, transparent 45%, rgba(6, 9, 10, .62));
}
[data-theme="light"] .hero__card::after { background: linear-gradient(200deg, transparent 55%, rgba(6, 9, 10, .3)); }

/* Halo bloom behind the stack */
.hero__media::before {
    content: ""; position: absolute; inset: 10% -8% -10% 8%; z-index: -1;
    border-radius: var(--r-xl);
    background: var(--grad); filter: blur(70px); opacity: .32;
    animation: bloom 9s var(--ease) infinite alternate;
}
@keyframes bloom { to { opacity: .5; transform: scale(1.06) translateY(-10px); } }
@media (prefers-reduced-motion: reduce) { .hero__media::before { animation: none; } }

.hero__dots { position: absolute; left: 1.5rem; bottom: 1.5rem; z-index: 3; display: flex; gap: .45rem; }
.hero__dots button {
    width: 8px; height: 8px; padding: 0; border: 0; border-radius: 50%; cursor: pointer;
    background: rgba(255, 255, 255, .38);
    transition: width .4s var(--ease), background .4s var(--ease);
}
.hero__dots button.is-active { width: 30px; border-radius: var(--pill); background: #fff; }

/* Floating chips that orbit the card */
.hero__chip {
    position: absolute; z-index: 4;
    display: flex; align-items: center; gap: .6rem;
    padding: .8rem 1.15rem; border-radius: var(--pill);
    background: var(--glass-2); backdrop-filter: blur(18px) saturate(160%);
    border: 1px solid var(--line); box-shadow: var(--shadow-sm);
    font-size: .85rem; font-weight: 600;
    transform: translateZ(60px);
    animation: float 6s var(--ease) infinite alternate;
}
.hero__chip i { color: var(--accent); }
.hero__chip.is-a { top: 8%;  left: -8%;  animation-delay: -1s; }
.hero__chip.is-b { bottom: 22%; right: -6%; animation-delay: -3s; }
@keyframes float { to { transform: translateZ(60px) translateY(-14px); } }
@media (prefers-reduced-motion: reduce) { .hero__chip { animation: none; } }

.hero__badge {
    /* The negative offset gives the badge its overhang on desktop, but past
       the shell gutter it pushes the document wider than the viewport. */
    position: absolute; right: min(-1.2rem, 0px); bottom: -1.2rem; z-index: 5;
    display: grid; gap: .1rem;
    padding: 1.15rem 1.6rem; border-radius: var(--r);
    background: var(--glass-2); backdrop-filter: blur(20px) saturate(160%);
    border: 1px solid var(--line); box-shadow: var(--shadow);
    transform: translateZ(80px);
}
.hero__badge b {
    font-family: var(--ff-display); font-size: 2.1rem; font-weight: 400; line-height: 1;
    background: var(--grad); -webkit-background-clip: text; background-clip: text; color: transparent;
}
.hero__badge span { font-size: .68rem; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--faint); }

@media (max-width: 900px) {
    .hero__grid { grid-template-columns: 1fr; }
    .hero__media { order: -1; }
    .hero__card { aspect-ratio: 16 / 11; }
    .hero__chip.is-a { left: -2%; }
    .hero__chip.is-b { right: -2%; }
    .hero__badge { right: 0; bottom: -1.4rem; }
}
@media (max-width: 560px) {
    .hero__chip { display: none; }
}

/* ---------- 9. Split text --------------------------------- */
.is-split .w {
    display: inline-block;
    overflow: hidden;
    vertical-align: bottom;
    /* Room for descenders — the reveal needs overflow:hidden, but a clip box
       sized to the line height shears the tails off p, j and q. */
    padding: .12em .02em .22em;
    margin: -.12em -.02em -.22em;
}
.is-split .w__i {
    display: inline-block;
    transform: translateY(105%) rotate(4deg);
    opacity: 0;
    transition: transform .95s var(--ease-out), opacity .95s var(--ease-out);
}
.is-split.is-shown .w__i { transform: none; opacity: 1; }
@media (prefers-reduced-motion: reduce) {
    .is-split .w__i { transform: none; opacity: 1; transition: none; }
}

/* ---------- 10. Stats ------------------------------------- */
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; }
.stats > div {
    position: relative; overflow: hidden;
    padding: 1.9rem 1.7rem;
    border-radius: var(--r-lg);
    background: var(--glass);
    backdrop-filter: blur(20px) saturate(150%);
    border: 1px solid var(--line);
    box-shadow: var(--lift);
    transition: transform .45s var(--ease), box-shadow .45s var(--ease), border-color .45s var(--ease);
}
.stats > div::before {
    content: ""; position: absolute; inset: auto 0 0 0; height: 2px;
    background: var(--grad); transform: scaleX(0); transform-origin: 0 50%;
    transition: transform .6s var(--ease-out);
}
.stats > div:hover { transform: translateY(-6px); border-color: var(--accent-line); box-shadow: var(--glow); }
.stats > div:hover::before { transform: none; }
.stats b {
    display: block;
    font-family: var(--ff-display); font-weight: 400;
    font-size: clamp(2.3rem, 1.5rem + 2.6vw, 3.6rem); line-height: 1;
    background: var(--grad); -webkit-background-clip: text; background-clip: text; color: transparent;
    font-variant-numeric: tabular-nums;
}
.stats span { display: block; margin-top: .7rem; font-size: .82rem; font-weight: 500; color: var(--muted); }
@media (max-width: 780px) { .stats { grid-template-columns: repeat(2, 1fr); } }

/* ---------- 11. Marquee ----------------------------------- */
.marquee {
    overflow: hidden; padding-block: 1.15rem;
    border-block: 1px solid var(--line);
    background: var(--glass);
    backdrop-filter: blur(14px);
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
            mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
}
.marquee__track { display: flex; gap: 3.2rem; width: max-content; animation: marquee 46s linear infinite; }
.marquee span { display: inline-flex; align-items: center; gap: 3.2rem; font-size: .88rem; font-weight: 500; color: var(--muted); }
.marquee span::after { content: ""; width: 5px; height: 5px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 10px var(--accent); }
@keyframes marquee { to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .marquee__track { animation: none; } }

/* ---------- 12. Cards ------------------------------------- */
.card-v {
    background: var(--glass);
    backdrop-filter: blur(20px) saturate(150%);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--lift);
    overflow: hidden;
}

/* 3D-tiltable surface shared by .svc / .work / .perk */
[data-tilt] {
    transform-style: preserve-3d;
    transform: perspective(1000px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
    transition: transform .55s var(--ease), box-shadow .45s var(--ease), border-color .45s var(--ease);
}
[data-tilt].is-tilting { transition: box-shadow .45s var(--ease), border-color .45s var(--ease); }

/* Sheen tracks the pointer across tilted cards. */
[data-sheen]::after {
    content: ""; position: absolute; inset: 0; z-index: 3; pointer-events: none;
    border-radius: inherit;
    background: radial-gradient(340px circle at var(--mx, 50%) var(--my, 50%), var(--sheen), transparent 62%);
    opacity: 0; transition: opacity .45s var(--ease);
}
[data-sheen]:hover::after { opacity: .5; }

.svc {
    position: relative; display: flex; flex-direction: column; height: 100%;
    padding: clamp(1.7rem, 1rem + 1.6vw, 2.5rem);
    background: var(--glass);
    backdrop-filter: blur(20px) saturate(150%);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--lift);
    overflow: hidden;
}
.svc::before {
    content: ""; position: absolute; inset: -50% 45% 55% -45%;
    background: var(--grad); filter: blur(80px);
    opacity: 0; transition: opacity .6s var(--ease); pointer-events: none;
}
.svc:hover { border-color: var(--accent-line); box-shadow: var(--glow); }
.svc:hover::before { opacity: .2; }
.svc > * { position: relative; z-index: 2; transform: translateZ(28px); }
.svc__idx { font-size: .74rem; font-weight: 700; letter-spacing: .14em; color: var(--faint); margin-bottom: 1.9rem; }
.svc__icon {
    width: 56px; height: 56px; margin-bottom: 1.35rem;
    display: grid; place-items: center; border-radius: var(--r-sm);
    color: var(--accent);
    background: var(--accent-soft);
    border: 1px solid var(--accent-line);
    transition: transform .5s var(--ease), box-shadow .5s var(--ease);
}
.svc:hover .svc__icon { transform: translateZ(40px) scale(1.06); box-shadow: 0 12px 30px -10px rgba(53,166,104,.6); }
.svc__icon svg { width: 25px; height: 25px; }
.svc h3 { font-size: var(--step-1); margin-bottom: .6rem; }
.svc p { color: var(--muted); font-size: .96rem; margin-bottom: 1.5rem; }
.svc .link-v { margin-top: auto; font-size: .9rem; }

.work {
    position: relative; display: block; height: 100%;
    background: var(--glass);
    backdrop-filter: blur(20px) saturate(150%);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--lift);
    overflow: hidden;
}
.work:hover { border-color: var(--accent-line); box-shadow: var(--glow); }
.work__img { position: relative; aspect-ratio: 16 / 10; overflow: hidden; background: var(--bg-2); }
.work__img img { width: 100%; height: 100%; object-fit: cover; transition: transform 1.1s var(--ease-out), filter .6s var(--ease); }
.work:hover .work__img img { transform: scale(1.08); }
.work__img::after {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(180deg, transparent 45%, rgba(6,9,10,.55));
    opacity: 0; transition: opacity .5s var(--ease);
}
.work:hover .work__img::after { opacity: 1; }
.work__body { padding: 1.5rem 1.7rem 1.85rem; position: relative; z-index: 2; transform: translateZ(26px); }
.work__client { font-size: .75rem; font-weight: 700; letter-spacing: .11em; text-transform: uppercase; color: var(--accent); margin-bottom: .55rem; }
.work h3 { font-size: var(--step-1); margin-bottom: .55rem; }
.work p { color: var(--muted); font-size: .94rem; margin-bottom: 1.1rem; }
.work__go {
    position: absolute; right: 1.25rem; top: 1.25rem; z-index: 4;
    width: 46px; height: 46px; display: grid; place-items: center; border-radius: 50%;
    background: var(--glass-2); backdrop-filter: blur(14px);
    border: 1px solid var(--line); color: var(--text);
    opacity: 0; transform: translateY(-10px) rotate(-35deg) translateZ(50px);
    transition: opacity .45s var(--ease), transform .45s var(--ease), background .45s var(--ease), color .45s var(--ease);
}
.work:hover .work__go { opacity: 1; transform: translateZ(50px); background: var(--grad); color: var(--on-accent); border-color: transparent; }

.chips { display: flex; flex-wrap: wrap; gap: .45rem; }
.chip {
    display: inline-flex; align-items: center; gap: .35rem;
    font-size: .73rem; font-weight: 500;
    padding: .35rem .85rem; border-radius: var(--pill);
    background: var(--glass-hi); color: var(--muted);
    border: 1px solid var(--line);
}

.status-pill {
    position: absolute; left: 1.25rem; top: 1.25rem; z-index: 4;
    display: inline-flex; align-items: center; gap: .45rem;
    font-size: .72rem; font-weight: 600;
    padding: .42rem .95rem; border-radius: var(--pill);
    background: var(--glass-2); backdrop-filter: blur(14px);
    border: 1px solid var(--line); color: var(--text);
    transform: translateZ(40px);
}
.status-pill::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
/* "In progress" is a state, not a warning, so it reads in the brighter
   spring green rather than an alert colour — the dot shape and the label
   carry the distinction from "completed". */
.status-pill.is-completed { color: var(--accent); }
.status-pill.is-progress  { color: var(--lime); }
.status-pill.is-planned   { color: var(--faint); }

/* ---------- 13. Grids ------------------------------------- */
.grid { display: grid; gap: clamp(1.1rem, .6rem + 1.2vw, 1.8rem); }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 980px) { .grid-3, .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px) { .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; } }

.split { display: grid; grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr); gap: clamp(2.5rem, 1rem + 4.5vw, 5rem); align-items: start; }
.split.is-reverse { grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); }
@media (max-width: 900px) { .split, .split.is-reverse { grid-template-columns: 1fr; } }

/* ---------- 14. Process ----------------------------------- */
.numbered { list-style: none; margin: 0; padding: 0; display: grid; gap: .9rem; }
.numbered li {
    position: relative; overflow: hidden;
    display: grid; grid-template-columns: auto 1fr; gap: 1.4rem;
    padding: 1.6rem 1.8rem;
    border-radius: var(--r);
    background: var(--glass);
    backdrop-filter: blur(16px);
    border: 1px solid var(--line);
    transition: border-color .4s var(--ease), transform .4s var(--ease), background .4s var(--ease);
}
.numbered li::before {
    content: ""; position: absolute; inset: 0 auto 0 0; width: 3px;
    background: var(--grad); transform: scaleY(0); transform-origin: 50% 0;
    transition: transform .5s var(--ease-out);
}
.numbered li:hover { border-color: var(--accent-line); transform: translateX(6px); }
.numbered li:hover::before { transform: none; }
.numbered li b {
    font-family: var(--ff-display); font-size: 1.5rem; font-weight: 400; line-height: 1;
    background: var(--grad); -webkit-background-clip: text; background-clip: text; color: transparent;
    padding-top: .1rem;
}
.numbered li h4 { margin-bottom: .35rem; font-size: var(--step-1); }
.numbered li p { margin: 0; color: var(--muted); font-size: .95rem; }

/* ---------- 15. Team -------------------------------------- */
.member { text-align: left; }
.member__photo {
    position: relative; aspect-ratio: 3 / 3.6; overflow: hidden;
    border-radius: var(--r-lg); background: var(--bg-2);
    border: 1px solid var(--line);
    margin-bottom: 1.2rem;
    transition: box-shadow .5s var(--ease), transform .5s var(--ease), border-color .5s var(--ease);
}
.member:hover .member__photo { transform: translateY(-8px); box-shadow: var(--glow); border-color: var(--accent-line); }
.member__photo img {
    width: 100%; height: 100%; object-fit: cover;
    filter: saturate(.35) contrast(1.06);
    transition: filter .6s var(--ease), transform .9s var(--ease-out);
}
.member:hover .member__photo img { filter: none; transform: scale(1.06); }
.member__photo::after {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(180deg, transparent 50%, rgba(6,9,10,.6));
    opacity: .5; transition: opacity .5s var(--ease);
}
.member:hover .member__photo::after { opacity: .15; }
.member h3 { font-size: var(--step-1); margin-bottom: .25rem; }
.member span { font-size: .85rem; font-weight: 500; color: var(--accent); }

/* ---------- 16. Forms ------------------------------------- */
.field { margin-bottom: 1.3rem; }
.field > label, .form-label {
    display: block; margin-bottom: .55rem;
    font-size: .8rem; font-weight: 600; letter-spacing: .03em; color: var(--muted);
}
.input, .form-control, .form-select, textarea.form-control {
    width: 100%;
    padding: 1rem 1.2rem;
    font-family: var(--ff-body); font-size: .96rem; color: var(--text);
    background: var(--glass);
    backdrop-filter: blur(12px);
    border: 1px solid var(--line); border-radius: var(--r);
    transition: border-color .3s var(--ease), box-shadow .3s var(--ease), background .3s var(--ease);
}
.input::placeholder, .form-control::placeholder { color: var(--faint); }
.input:focus, .form-control:focus, .form-select:focus {
    outline: none; border-color: var(--accent);
    box-shadow: 0 0 0 4px var(--ring);
    background: var(--glass-2);
}
.form-select {
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%2393a49c' stroke-width='1.7' stroke-linecap='round'%3E%3Cpath d='M4 6.5l4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 1.1rem center; background-size: 16px;
    padding-right: 2.8rem;
}
textarea.input, textarea.form-control { min-height: 150px; resize: vertical; }
.help { font-size: .84rem; color: var(--faint); }
.form-card { padding: clamp(1.7rem, 1rem + 1.8vw, 2.7rem); }
input[type="file"].input { padding: .8rem 1.1rem; border-style: dashed; cursor: pointer; }

/* ---------- 17. Alerts ------------------------------------ */
.flash-stack { display: grid; gap: .75rem; margin-block: 1.75rem; }
.flash {
    display: flex; align-items: flex-start; gap: .9rem;
    padding: 1.1rem 1.4rem;
    border: 1px solid var(--line); border-radius: var(--r);
    background: var(--glass-2); backdrop-filter: blur(18px);
    box-shadow: var(--lift), var(--shadow-sm);
    font-size: .94rem;
}
.flash i { color: var(--accent); margin-top: .12rem; font-size: 1.1rem; }
.flash.is-success { border-color: var(--accent-line); }
.flash.is-danger  { border-color: rgba(226, 94, 70, .4); } .flash.is-danger i  { color: #e25e46; }
.flash.is-warning { border-color: rgba(224, 164, 55, .4); } .flash.is-warning i { color: #e0a437; }
.flash.is-info    { border-color: rgba(88, 156, 224, .4); } .flash.is-info i    { color: #589ce0; }
.flash button { margin-left: auto; background: none; border: 0; color: var(--faint); cursor: pointer; font-size: 1.2rem; line-height: 1; padding: 0; }

/* ---------- 18. Pagination -------------------------------- */
.pager { display: flex; justify-content: center; gap: .45rem; margin-top: 4rem; flex-wrap: wrap; }
.pager a, .pager span {
    min-width: 48px; height: 48px; padding: 0 .9rem;
    display: inline-grid; place-items: center;
    border: 1px solid var(--line); border-radius: var(--pill);
    background: var(--glass); backdrop-filter: blur(12px);
    font-size: .92rem; font-weight: 500; color: var(--muted);
    transition: border-color .3s var(--ease), color .3s var(--ease), transform .3s var(--ease);
}
.pager a:hover { border-color: var(--accent-line); color: var(--accent); transform: translateY(-3px); }
.pager .is-current { background: var(--grad); border-color: transparent; color: var(--on-accent); font-weight: 700; }
.pager .is-disabled { opacity: .3; pointer-events: none; }

/* ---------- 19. CTA band ---------------------------------- */
.cta-band {
    position: relative; overflow: hidden;
    padding: clamp(3rem, 1.5rem + 5vw, 6rem);
    border-radius: var(--r-xl);
    background: var(--glass-2);
    backdrop-filter: blur(26px) saturate(160%);
    border: 1px solid var(--line);
    box-shadow: var(--lift), var(--shadow);
}
.cta-band::before {
    content: ""; position: absolute; inset: -60% -20% 40% -20%;
    background: var(--grad); filter: blur(100px); opacity: .22; pointer-events: none;
    animation: bloom 11s var(--ease) infinite alternate;
}
.cta-band::after {
    content: ""; position: absolute; right: -6%; top: -40%;
    width: 48%; aspect-ratio: 1;
    background: url("/public/images/mark-white.png") center / contain no-repeat;
    opacity: .06; pointer-events: none;
}
[data-theme="light"] .cta-band::after { background-image: url("/public/images/mark.png"); opacity: .08; }
.cta-band > * { position: relative; }
.cta-band h2 { max-width: 17ch; }
.cta-band p { color: var(--muted); max-width: 50ch; font-size: var(--step-1); }

/* ---------- 20. Footer ------------------------------------ */
.site-footer {
    position: relative;
    margin-top: clamp(3rem, 1rem + 4vw, 5rem);
    padding-block: clamp(4rem, 2rem + 4vw, 6rem) 2.25rem;
    border-top: 1px solid var(--line);
    background: var(--glass);
    backdrop-filter: blur(18px);
}
.site-footer__grid { display: grid; grid-template-columns: 1.7fr repeat(3, 1fr); gap: clamp(2rem, 1rem + 2.5vw, 3.5rem); }
.site-footer h5 { font-size: .76rem; font-weight: 700; letter-spacing: .13em; text-transform: uppercase; color: var(--faint); margin-bottom: 1.35rem; }
.site-footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .7rem; font-size: .96rem; }
.site-footer a { color: var(--muted); transition: color .25s var(--ease), padding-left .25s var(--ease); }
.site-footer a:hover { color: var(--accent); padding-left: 4px; }
.site-footer .foot-brand img { height: 32px; margin-bottom: 1.3rem; }
.site-footer .foot-brand p { color: var(--muted); font-size: .96rem; max-width: 34ch; }
[data-theme="light"] .site-footer .foot-brand img { content: url("/public/images/Vision-light.png"); }

.social { display: flex; gap: .55rem; margin-top: 1.5rem; }
.social a {
    width: 46px; height: 46px; display: grid; place-items: center;
    border: 1px solid var(--line); border-radius: 50%;
    background: var(--glass-hi); color: var(--muted); font-size: 1.05rem;
    transition: transform .35s var(--ease), border-color .35s var(--ease), color .35s var(--ease);
}
.social a:hover { transform: translateY(-4px); border-color: var(--accent-line); color: var(--accent); padding-left: 0; }

.site-footer__base {
    display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between; align-items: center;
    margin-top: 3.25rem; padding-top: 1.9rem;
    border-top: 1px solid var(--line);
    font-size: .84rem; color: var(--faint);
}
@media (max-width: 880px) { .site-footer__grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .site-footer__grid { grid-template-columns: 1fr; } }

.partner { margin-top: 2rem; }
.partner__label { display: block; margin-bottom: .75rem; font-size: .72rem; font-weight: 700; letter-spacing: .13em; text-transform: uppercase; color: var(--faint); }
.partner img { border-radius: var(--r-sm); background: var(--glass-hi); border: 1px solid var(--line); padding: .5rem .65rem; transition: border-color .3s var(--ease); }
.partner a:hover img { border-color: var(--accent-line); }
.partner__chat {
    display: inline-flex; align-items: center; gap: .5rem; margin-top: .85rem;
    background: none; border: 0; padding: 0; cursor: pointer;
    font-family: var(--ff-body); font-size: .9rem; font-weight: 500; color: var(--muted);
}
.partner__chat:hover { color: var(--accent); }

/* ---------- 21. Article ----------------------------------- */
.prose { font-size: 1.1rem; line-height: 1.85; color: var(--muted); }
.prose > * + * { margin-top: 1.2em; }
.prose h2 { font-size: var(--step-2); margin-top: 1.9em; color: var(--text); }
.prose h3 { font-size: var(--step-1); margin-top: 1.7em; color: var(--text); }
.prose strong { color: var(--text); }
.prose a { color: var(--accent); text-decoration: underline; text-underline-offset: 4px; }
.prose img { border-radius: var(--r-lg); margin-block: 2em; }
.prose blockquote {
    margin: 2em 0; padding: 1.8rem 2rem;
    border-radius: var(--r); border: 1px solid var(--accent-line);
    background: var(--accent-soft);
    font-family: var(--ff-display); font-size: var(--step-1); font-style: italic; color: var(--text);
}
.prose ul, .prose ol { padding-left: 1.5rem; }
.prose li + li { margin-top: .5em; }

.breadcrumbs { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; font-size: .84rem; color: var(--faint); margin-bottom: 2rem; }
.breadcrumbs a:hover { color: var(--accent); }
.breadcrumbs .sep { opacity: .4; }

/* ---------- 22. Gallery ----------------------------------- */
.gallery { display: grid; gap: .9rem; }
.gallery__main {
    aspect-ratio: 16 / 10; overflow: hidden;
    border-radius: var(--r-lg); background: var(--bg-2);
    border: 1px solid var(--line); box-shadow: var(--shadow-sm);
}
.gallery__main img { width: 100%; height: 100%; object-fit: cover; }
.gallery__thumbs { display: grid; grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); gap: .6rem; }
.gallery__thumbs button {
    aspect-ratio: 1; padding: 0; overflow: hidden; cursor: pointer; opacity: .45;
    border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--bg-2);
    transition: opacity .3s var(--ease), border-color .3s var(--ease), transform .3s var(--ease);
}
.gallery__thumbs button img { width: 100%; height: 100%; object-fit: cover; }
.gallery__thumbs button:hover { opacity: 1; transform: translateY(-3px); }
.gallery__thumbs button.is-active { border-color: var(--accent); opacity: 1; }

/* ---------- 23. Contact list ------------------------------ */
.contact-lines { display: grid; gap: .8rem; margin-block: 2.5rem; }
.contact-lines > a, .contact-lines > div {
    display: flex; align-items: center; gap: 1.1rem;
    padding: 1.15rem 1.4rem; border-radius: var(--r);
    background: var(--glass); backdrop-filter: blur(14px);
    border: 1px solid var(--line); color: var(--text);
    transition: border-color .3s var(--ease), transform .3s var(--ease);
}
.contact-lines > a:hover { border-color: var(--accent-line); transform: translateX(6px); }
.contact-lines i { color: var(--accent); font-size: 1.15rem; width: 26px; flex: none; }
.contact-lines small { display: block; font-size: .74rem; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--faint); }

/* ---------- 24. Empty ------------------------------------- */
.empty {
    text-align: center; padding: clamp(3.5rem, 2rem + 4vw, 6rem) 1.5rem;
    border: 1px dashed var(--line); border-radius: var(--r-lg);
    background: var(--glass); backdrop-filter: blur(12px);
    color: var(--muted);
}
.empty i { font-size: 2.6rem; color: var(--accent); display: block; margin-bottom: 1.1rem; opacity: .7; }

/* ---------- 25. Filters ----------------------------------- */
.filters { display: flex; flex-wrap: wrap; gap: .7rem; align-items: center; }
.filters .form-control, .filters .form-select { width: auto; min-width: 175px; padding-block: .82rem; }
@media (max-width: 660px) {
    .filters { display: grid; grid-template-columns: 1fr 1fr; }
    .filters .form-control, .filters .form-select, .filters .btn-v { width: 100%; min-width: 0; }
    .filters > *:first-child, .filters .btn-v { grid-column: 1 / -1; }
    .filters .btn-v { justify-content: center; }
}

/* ---------- 26. Reveal & page transition ------------------ */
[data-reveal] {
    opacity: 0; transform: translateY(28px);
    transition: opacity .9s var(--ease-out), transform .9s var(--ease-out);
    will-change: opacity, transform;
}
[data-reveal].is-in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { [data-reveal] { opacity: 1; transform: none; transition: none; } }

[data-parallax] { transform: translateY(var(--py, 0)); will-change: transform; }

body { opacity: 1; transition: opacity .26s var(--ease); }
body.page-leaving { opacity: 0; }
@media (prefers-reduced-motion: reduce) { body, body.page-leaving { opacity: 1; transition: none; } }

/* ---------- 27. Logo wall --------------------------------- */
.logos-band { padding-block: clamp(3rem, 2rem + 2vw, 4.5rem); }
.logos-band__head { margin-bottom: 2.5rem; }
.logos-band__head h2 { font-size: var(--step-2); margin: 0; }
.logos-band__head.center { text-align: center; }
.logos-band__head.center .eyebrow { justify-content: center; }
.logos {
    overflow: hidden;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
            mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.logos__track { display: flex; align-items: center; width: max-content; gap: clamp(2.5rem, 1rem + 3.5vw, 5.5rem); animation: logos-scroll 52s linear infinite; }
.logos:hover .logos__track { animation-play-state: paused; }
@keyframes logos-scroll { to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .logos__track { animation: none; flex-wrap: wrap; width: 100%; justify-content: center; } }
.logos__item { flex: none; display: grid; place-items: center; height: 58px; }
.logos__item img {
    max-height: 100%; max-width: 170px; width: auto; object-fit: contain;
    opacity: .4; transition: opacity .4s var(--ease), transform .4s var(--ease), filter .4s var(--ease);
}
:root:not([data-theme="light"]) .logos__item img { filter: grayscale(1) brightness(2.6) contrast(.75); }
:root:not([data-theme="light"]) .logos__item:hover img { filter: brightness(1.1); }
[data-theme="light"] .logos__item img { filter: grayscale(1); }
[data-theme="light"] .logos__item:hover img { filter: none; }
.logos__item:hover img { opacity: 1; transform: scale(1.07); }
.logos-grid { display: grid; gap: clamp(1.5rem, .6rem + 2vw, 3rem); grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); align-items: center; justify-items: center; }

/* ---------- 28. Careers ----------------------------------- */
.perk {
    position: relative; overflow: hidden;
    padding: clamp(1.7rem, 1rem + 1.3vw, 2.3rem);
    border: 1px solid var(--line); border-radius: var(--r-lg);
    background: var(--glass); backdrop-filter: blur(18px);
    box-shadow: var(--lift);
}
.perk:hover { border-color: var(--accent-line); box-shadow: var(--glow); }
.perk > * { position: relative; z-index: 2; transform: translateZ(24px); }
.perk i {
    display: grid; place-items: center; width: 52px; height: 52px; margin-bottom: 1.25rem;
    font-size: 1.3rem; color: var(--accent);
    background: var(--accent-soft); border: 1px solid var(--accent-line); border-radius: var(--r-sm);
}
.perk h3 { font-size: var(--step-1); margin-bottom: .5rem; }
.perk p { color: var(--muted); font-size: .96rem; margin: 0; }

.dept-block { margin-block: clamp(2.5rem, 1.5rem + 2.5vw, 4rem) clamp(2rem, 1.5rem + 2vw, 3.25rem); }
.dept-block + .dept-block { margin-top: 0; }
.dept-head { display: flex; align-items: baseline; gap: 1rem; margin-bottom: 1.15rem; }
.dept-head h2 { font-size: var(--step-2); margin: 0; }
.dept-head .mono { margin-left: auto; }

.job-list { list-style: none; margin: 0; padding: 0; display: grid; gap: .9rem; }
.job-list a {
    display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: 1.5rem;
    padding: 1.7rem 1.9rem;
    border: 1px solid var(--line); border-radius: var(--r-lg);
    background: var(--glass); backdrop-filter: blur(16px);
    box-shadow: var(--lift);
    transition: transform .4s var(--ease), border-color .4s var(--ease), box-shadow .4s var(--ease);
}
.job-list a:hover { transform: translateY(-5px); border-color: var(--accent-line); box-shadow: var(--glow); }
.job-list h3 { font-size: var(--step-1); margin: 0 0 .35rem; transition: color .3s var(--ease); }
.job-list a:hover h3 { color: var(--accent); }
.job-list p { margin: 0; color: var(--muted); font-size: .95rem; max-width: 56ch; }
.job-list__meta { display: flex; flex-wrap: wrap; gap: .45rem; justify-content: flex-end; }
.job-list__go {
    width: 50px; height: 50px; flex: none; display: grid; place-items: center; border-radius: 50%;
    border: 1px solid var(--line); background: var(--glass-hi); color: var(--muted);
    transition: background .4s var(--ease), color .4s var(--ease), border-color .4s var(--ease), transform .4s var(--ease);
}
.job-list a:hover .job-list__go { background: var(--grad); border-color: transparent; color: var(--on-accent); transform: translateX(5px); }
@media (max-width: 760px) {
    .job-list a { grid-template-columns: 1fr auto; grid-template-areas: "main go" "meta meta"; gap: 1rem; padding: 1.4rem 1.5rem; }
    .job-list__main { grid-area: main; }
    .job-list__go   { grid-area: go; align-self: start; }
    .job-list__meta { grid-area: meta; justify-content: flex-start; }
}

.ticks { list-style: none; margin: 1.4rem 0 0; padding: 0; display: grid; gap: .9rem; }
.ticks li { display: grid; grid-template-columns: auto 1fr; gap: .9rem; align-items: start; color: var(--muted); }
.ticks li::before {
    content: "\F26E"; font-family: "bootstrap-icons"; font-size: .82rem;
    display: grid; place-items: center; width: 24px; height: 24px; border-radius: 50%;
    background: var(--accent-soft); color: var(--accent); border: 1px solid var(--accent-line);
}

/* ---------- 29. Utilities --------------------------------- */
.stack { display: grid; gap: 1rem; }
.row-between { display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between; align-items: flex-end; }
.center { text-align: center; }
.mt-auto { margin-top: auto; }
@media (max-width: 640px) { .hide-sm { display: none !important; } }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }

/* Split-text carries its own decoration: the wrapper element can't paint
   gradient glyphs that live in a child, so the class lands on the inner span. */
.is-split .w__i--em,
.is-split .w__i--i {
    font-family: var(--ff-display); font-style: italic;
    background: var(--grad);
    -webkit-background-clip: text; background-clip: text; color: transparent;
}
.is-split .w__i--strong, .is-split .w__i--b { font-weight: 700; }

/* ============================================================
   30. Cinematic layer — ghost display type, 3D card stack
   ------------------------------------------------------------
   The scroll-driven pieces are all fed by CSS custom properties
   that motion.js writes (--p = 0..1 progress, --d = depth), so
   the fallback with JS disabled is a plain, readable stack.
   ============================================================ */

/* ---------- 30.1 Ghost display type ---------- */

.ghost {
    font-family: var(--ff-tall);
    font-weight: 300;
    font-size: calc(var(--step-mega) * .58);
    line-height: .95;
    letter-spacing: .06em;
    text-transform: uppercase;
    text-align: center;
    margin: 0;
    /* Sits just above the page black — legible as shape, not as text. */
    color: rgba(255, 255, 255, .055);
    -webkit-text-stroke: 1px rgba(255, 255, 255, .05);
    user-select: none;
    white-space: nowrap;
}
[data-theme="light"] .ghost {
    color: rgba(11, 18, 16, .07);
    -webkit-text-stroke-color: rgba(11, 18, 16, .06);
}

/* A brighter copy is clipped to a travelling window so the words catch a
   sweep of light as the hero settles, instead of sitting flat. */
/* Full-bleed, behind the hero content, never in flow — it must not add
   height or the headline gets squeezed out of its box. */
.ghost-wrap {
    position: absolute;
    inset: 0;
    z-index: 0;
    display: grid;
    place-items: center;
    overflow: hidden;
    pointer-events: none;
}
.ghost-wrap > .ghost { grid-area: 1 / 1; }
.ghost-wrap .ghost--lit {
    grid-area: 1 / 1;
    color: transparent;
    /* A narrow band only — at full strength it out-shouts the headline
       that sits on top of it. */
    opacity: .3;
    background: linear-gradient(100deg,
        transparent 42%,
        var(--accent) 48%,
        var(--lime-lit) 52%,
        transparent 58%);
    background-size: 320% 100%;
    background-position: var(--sweep, 120%) 0;
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-stroke: 0;
    animation: ghost-sweep 9s var(--ease) infinite;
}
@keyframes ghost-sweep {
    0%, 12%  { background-position: 130% 0; }
    58%, 100% { background-position: -40% 0; }
}

/* ---------- 30.2 Section eyebrow with the turn-down arrow ---------- */

/* The arrow is part of the text run, not a flex sibling. As a flex container
   the label stretched to the full column and stranded the arrow at the far
   left whenever the text wrapped or was centred. */
.eyebrow-x {
    display: block;
    font-family: var(--ff-body);
    font-size: var(--step--1);
    font-weight: 600;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--lime);
    margin-bottom: 1rem;
}
.eyebrow-x::before {
    content: '↳';
    display: inline-block;
    margin-right: .5rem;
    font-size: 1.15em;
    line-height: 1;
    opacity: .85;
    transform: translateY(-.05em);
}

/* ---------- 30.3 The 3D sticky card stack ---------- */

.stack {
    /* Each slot is one viewport tall; the card inside sticks while the
       next one climbs over it. Perspective on the rail gives real depth
       rather than a flat scale. */
    perspective: 1600px;
    perspective-origin: 50% 42%;
}
.stack__item {
    position: sticky;
    top: max(6vh, 4.5rem);
    height: min(78vh, 720px);
    margin-bottom: clamp(2rem, 6vh, 5rem);
    transform-style: preserve-3d;
    will-change: transform;
}
/* --d is how far this card has been buried by the ones after it (0 = front). */
.stack__item {
    transform:
        translate3d(0, calc(var(--d, 0) * -1.6rem), calc(var(--d, 0) * -120px))
        rotateX(calc(var(--d, 0) * 3.2deg))
        scale(calc(1 - var(--d, 0) * .045));
    transition: transform .1s linear;
}

.stack__card {
    position: relative;
    height: 100%;
    border-radius: var(--r-lg);
    overflow: hidden;
    background: var(--bg-2);
    box-shadow: 0 40px 90px -30px rgba(0, 0, 0, .9), 0 0 0 1px var(--line);
    isolation: isolate;
}
.stack__card img {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    object-fit: cover;
    /* Pushed back and over-sized so the parallax never exposes an edge. */
    transform: scale(1.12) translate3d(0, calc(var(--p, 0) * -3%), 0);
    transition: transform .1s linear;
}
/* Two stacked scrims: a global dim, then a heavier foot so the title reads. */
.stack__card::before {
    content: ''; position: absolute; inset: 0; z-index: 1;
    background:
        linear-gradient(to top, rgba(0,0,0,.94) 0%, rgba(0,0,0,.6) 40%, rgba(0,0,0,.25) 74%),
        rgba(0, 0, 0, .46);
}
/* Buried cards fade toward black so depth reads on a dark screen. */
.stack__card::after {
    content: ''; position: absolute; inset: 0; z-index: 2;
    background: #000;
    opacity: calc(var(--d, 0) * .32);
    transition: opacity .1s linear;
    pointer-events: none;
}

.stack__body {
    position: absolute; z-index: 3;
    left: clamp(1.4rem, 4vw, 3.4rem);
    right: clamp(1.4rem, 4vw, 3.4rem);
    bottom: clamp(1.6rem, 4vw, 3rem);
    display: grid; gap: .7rem;
}
.stack__title {
    font-family: var(--ff-tall);
    font-weight: 300;
    font-size: clamp(1.6rem, .8rem + 3.4vw, 3.6rem);
    line-height: 1.04;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: #fff;
    margin: 0;
    text-shadow: 0 4px 40px rgba(0, 0, 0, .6);
}
.stack__tags {
    position: absolute; z-index: 3;
    top: clamp(1.2rem, 3vw, 2.2rem);
    right: clamp(1.4rem, 4vw, 3.4rem);
    display: flex; flex-wrap: wrap; justify-content: flex-end;
    gap: .5rem .9rem;
    max-width: 70%;
}
.stack__tag {
    font-size: var(--step--1);
    letter-spacing: .05em;
    color: rgba(255, 255, 255, .62);
}
.stack__tag + .stack__tag { border-left: 1px solid rgba(255,255,255,.2); padding-left: .9rem; }

.stack__go {
    display: inline-flex; align-items: center; gap: .55rem;
    justify-self: start;
    font-size: var(--step--1); font-weight: 600; letter-spacing: .05em;
    text-transform: uppercase;
    color: #fff; text-decoration: none;
    padding: .6rem 1.1rem;
    border: 1px solid rgba(255, 255, 255, .3);
    border-radius: var(--pill);
    backdrop-filter: blur(8px);
    background: rgba(255, 255, 255, .06);
    transition: background .3s var(--ease), border-color .3s var(--ease), gap .3s var(--ease);
}
.stack__card:hover .stack__go { background: var(--lime); border-color: var(--lime); color: #04140b; gap: .9rem; }

/* The whole card is the link; the pill is just the affordance. */
.stack__link { position: absolute; inset: 0; z-index: 4; }

/* ---------- 30.4 3D logo cylinder ---------- */

.cyl {
    perspective: 900px;
    overflow: hidden;
    padding-block: 1.5rem;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
            mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.cyl__track {
    display: flex; align-items: center; gap: clamp(2.5rem, 6vw, 6rem);
    width: max-content;
    transform-style: preserve-3d;
    /* Bowed slightly away from the viewer so the row reads as a surface. */
    transform: rotateX(9deg);
    animation: cyl-roll 44s linear infinite;
}
.cyl:hover .cyl__track { animation-play-state: paused; }
@keyframes cyl-roll { to { transform: rotateX(9deg) translate3d(-50%, 0, 0); } }
.cyl__item {
    flex: none;
    filter: grayscale(1) brightness(1.55);
    opacity: .62;
    transition: opacity .35s var(--ease), filter .35s var(--ease), transform .35s var(--ease);
}
.cyl__item img { height: clamp(30px, 4vw, 52px); width: auto; display: block; }
.cyl__item:hover { opacity: 1; filter: none; transform: translateZ(40px); }

/* ---------- 30.5 Reduced motion & coarse pointers ---------- */

@media (prefers-reduced-motion: reduce) {
    .ghost-wrap .ghost--lit { animation: none; }
    .cyl__track { animation: none; transform: none; }
    .stack__item {
        position: static; height: auto; transform: none;
        margin-bottom: clamp(1.2rem, 3vh, 2rem);
    }
    .stack__card { height: min(60vh, 460px); }
    /* Drop the parallax and the depth scrim, but keep the photo visible —
       opacity:0 here previously blanked the project image entirely. */
    .stack__card img { transform: scale(1.02); }
    .stack__card::after { opacity: 0; }
}

@media (max-width: 900px) {
    .hero__badge { right: .5rem; bottom: .5rem; padding: .8rem 1.1rem; }
    .hero__badge b { font-size: 1.6rem; }
}

@media (max-width: 720px) {
    /* The sticky slide is the point of this section, so it runs on a phone
       too. What changes is the geometry: a shorter slot, a smaller stick
       offset and display type that fits the width. */
    .stack { perspective: 900px; }
    .stack__item {
        top: max(4vh, 3.5rem);
        height: min(62svh, 460px);
        margin-bottom: clamp(1.2rem, 5vh, 2.4rem);
    }
    .stack__item {
        transform:
            translate3d(0, calc(var(--d, 0) * -1rem), calc(var(--d, 0) * -70px))
            rotateX(calc(var(--d, 0) * 2.4deg))
            scale(calc(1 - var(--d, 0) * .035));
    }
    .stack__title { font-size: clamp(1.5rem, 1rem + 5vw, 2.6rem); }
    .stack__tags { max-width: 100%; gap: .35rem .7rem; }
    .stack__body {
        left: clamp(1rem, 4vw, 1.6rem);
        right: clamp(1rem, 4vw, 1.6rem);
        bottom: clamp(1.1rem, 4vw, 1.6rem);
    }
    .stack__go { padding: .5rem .9rem; font-size: .74rem; }
}

/* ---------- 30.6 3D lift for grid cards ---------- */

/* The archive keeps a dense grid — filters and pagination need it — so the
   depth comes from a real perspective lift instead of the sticky stack. */
.grid-3, .grid-2 { perspective: 1400px; }

.work, .svc {
    transform-style: preserve-3d;
    transition:
        transform .55s var(--ease-out),
        box-shadow .55s var(--ease-out),
        border-color .4s var(--ease);
}
.work:hover, .svc:hover {
    transform: translate3d(0, -10px, 42px);
    box-shadow: 0 44px 90px -34px rgba(0, 0, 0, .92), var(--glow);
}
/* Inner layers rise at different rates so the card reads as a solid object
   rather than a flat plane that happens to scale. */
.work__img { transform: translateZ(0); transition: transform .55s var(--ease-out); }
.work:hover .work__img { transform: translateZ(28px); }
.work__body { transform: translateZ(0); transition: transform .55s var(--ease-out); }
.work:hover .work__body { transform: translateZ(16px); }
.svc__icon { transition: transform .55s var(--ease-out); }
.svc:hover .svc__icon { transform: translateZ(38px) scale(1.06); }
.svc__idx  { transition: transform .55s var(--ease-out), opacity .4s var(--ease); }
.svc:hover .svc__idx { transform: translateZ(52px); opacity: .9; }

/* Condensed display titles tie the cards to the stack's voice. */
.work h3 {
    font-family: var(--ff-tall);
    font-weight: 400;
    font-size: clamp(1.1rem, .95rem + .55vw, 1.45rem);
    line-height: 1.2;
    letter-spacing: .06em;
    text-transform: uppercase;
}

@media (prefers-reduced-motion: reduce) {
    .work, .svc, .work__img, .work__body, .svc__icon, .svc__idx { transition: none; }
    .work:hover, .svc:hover { transform: none; }
    .work:hover .work__img, .work:hover .work__body,
    .svc:hover .svc__icon, .svc:hover .svc__idx { transform: none; }
}

/* ============================================================
   31. Portfolio index — hover-reveal project list
   ------------------------------------------------------------
   Rows of large project names; pointing at one floats its image
   under the cursor. The image layer is a single reused element,
   not one per row, so a 40-project page still costs one node.
   ============================================================ */

.folio { position: relative; border-top: 1px solid var(--line); }

.folio__row {
    position: relative;
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: clamp(1rem, 3vw, 2.5rem);
    padding: clamp(1.4rem, 3.2vw, 2.6rem) 0;
    border-bottom: 1px solid var(--line);
    text-decoration: none;
    color: inherit;
    isolation: isolate;
    transition: padding-left .5s var(--ease-out);
}
/* A wash sweeps in from the left on hover so the active row reads even
   before the image catches up with the cursor. */
.folio__row::before {
    content: '';
    position: absolute; inset: 0 -2vw; z-index: -1;
    background: linear-gradient(90deg, var(--accent-soft), transparent 65%);
    opacity: 0;
    transform: scaleX(.86);
    transform-origin: 0 50%;
    transition: opacity .45s var(--ease), transform .55s var(--ease-out);
}
.folio__row:hover::before,
.folio__row:focus-visible::before { opacity: 1; transform: scaleX(1); }
.folio__row:hover { padding-left: clamp(.6rem, 1.6vw, 1.6rem); }

.folio__idx {
    font-family: var(--mono, var(--ff-body));
    font-size: var(--step--1);
    color: var(--faint);
    font-variant-numeric: tabular-nums;
    transition: color .4s var(--ease);
}
.folio__row:hover .folio__idx { color: var(--lime); }

.folio__main { min-width: 0; }
.folio__cats {
    display: block;
    font-size: var(--step--1);
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: .45rem;
}
.folio__name {
    font-family: var(--ff-tall);
    font-weight: 300;
    font-size: clamp(1.4rem, .8rem + 2.6vw, 3.1rem);
    line-height: 1.08;
    letter-spacing: .07em;
    text-transform: uppercase;
    margin: 0;
    color: var(--text);
    transition: color .4s var(--ease), transform .55s var(--ease-out);
}
.folio__row:hover .folio__name { color: var(--accent); }

.folio__go {
    display: inline-flex; align-items: center; gap: .5rem;
    font-size: var(--step--1); font-weight: 600;
    letter-spacing: .06em; text-transform: uppercase;
    color: var(--muted);
    white-space: nowrap;
    opacity: 0;
    transform: translateX(-12px);
    transition: opacity .45s var(--ease), transform .5s var(--ease-out), color .4s var(--ease);
}
.folio__row:hover .folio__go,
.folio__row:focus-visible .folio__go { opacity: 1; transform: none; color: var(--accent); }
.folio__go i { transition: transform .4s var(--ease-out); }
.folio__row:hover .folio__go i { transform: translate(3px, -3px); }

/* ---- the floating preview ---- */
.folio__peek {
    position: fixed;
    top: 0; left: 0;
    z-index: 40;
    width: clamp(220px, 22vw, 380px);
    aspect-ratio: 4 / 3;
    border-radius: var(--r);
    overflow: hidden;
    pointer-events: none;
    opacity: 0;
    box-shadow: 0 40px 80px -28px rgba(0, 0, 0, .85);
    /* JS writes --x/--y (cursor) and --rx/--ry (tilt from pointer velocity). */
    transform:
        translate3d(calc(var(--x, 0px) - 50%), calc(var(--y, 0px) - 50%), 0)
        perspective(800px)
        rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg))
        scale(var(--s, .82));
    transition: opacity .35s var(--ease), scale .45s var(--ease-out);
    will-change: transform, opacity;
}
.folio__peek.is-on { opacity: 1; }
.folio__peek img {
    width: 100%; height: 100%; object-fit: cover; display: block;
    opacity: 0; transition: opacity .3s var(--ease);
}
.folio__peek img.is-shown { opacity: 1; }

/* The list is the primary nav on this page, so give keyboard users the
   same emphasis the pointer gets. */
.folio__row:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: var(--r-sm); }

@media (hover: none), (max-width: 720px) {
    /* No hover to reveal with — show a thumbnail inline instead. */
    .folio__peek { display: none; }
    .folio__row { grid-template-columns: auto 1fr; }
    .folio__go { display: none; }
    .folio__thumb {
        display: block;
        grid-column: 1 / -1;
        margin-top: 1rem;
        aspect-ratio: 16 / 9;
        border-radius: var(--r-sm);
        overflow: hidden;
    }
    .folio__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
}
.folio__thumb { display: none; }

@media (prefers-reduced-motion: reduce) {
    .folio__row, .folio__row::before, .folio__name, .folio__go, .folio__peek { transition: none; }
    .folio__row:hover { padding-left: 0; }
    .folio__peek { display: none; }
}

/* ---------- 31. Intro preloader ---------------------------- */
/* The overlay only exists while <html data-preload> is set. That attribute is
   written by a head script and torn down either by motion.js or by its own
   failsafe timer, so no path through the page can leave it stuck on screen. */

.preload { display: none; }

[data-preload] body { overflow: hidden; }

[data-preload] .preload {
    display: grid;
    place-items: center;
    position: fixed;
    inset: 0;
    z-index: 9999;
    background: var(--bg);
    /* The wipe is driven by a class rather than a transition on `display`,
       which cannot animate. */
    transition: opacity .5s var(--ease-out), transform .7s var(--ease-out);
}

.preload__inner {
    display: grid;
    justify-items: center;
    gap: 1.6rem;
    transition: opacity .45s var(--ease-out), transform .6s var(--ease-out);
}

.preload__dial {
    position: relative;
    width: clamp(96px, 24vw, 150px);
    aspect-ratio: 1;
    display: grid;
    place-items: center;
}

.preload__ring {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    /* -90deg puts the arc's origin at 12 o'clock instead of 3. */
    transform: rotate(-90deg);
    overflow: visible;
}
.preload__ring circle {
    fill: none;
    stroke-width: 1.5;
    stroke-linecap: round;
}
.preload__track { stroke: var(--line); }
.preload__arc {
    stroke: var(--accent);
    /* r=54 -> circumference 339.29. The dash is the full circle and the
       offset is what JS animates from full (empty) down to 0 (complete). */
    stroke-dasharray: 339.29;
    stroke-dashoffset: 339.29;
    filter: drop-shadow(0 0 6px var(--accent-soft));
}

.preload__mark {
    font-family: var(--ff-display);
    font-size: clamp(2.4rem, 7vw, 3.6rem);
    line-height: 1;
    color: var(--text);
    /* The serif V sits slightly low inside a circle; nudge it back to centre. */
    transform: translateY(-.04em);
}

.preload__meta {
    display: grid;
    justify-items: center;
    gap: .5rem;
    text-align: center;
}
.preload__word {
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .28em;
    text-transform: uppercase;
    color: var(--faint);
}
.preload__num {
    display: flex;
    align-items: baseline;
    gap: .12em;
    font-family: var(--ff-tall);
    font-weight: 300;
    line-height: 1;
    letter-spacing: .06em;
    /* Tabular figures stop the counter jittering sideways as it climbs. */
    font-variant-numeric: tabular-nums;
    /* The per-cent sign is punctuation, not part of the number — it stays
       small and quiet so the digits carry the reading. */
    font-size: clamp(.95rem, 2.4vw, 1.2rem);
    color: var(--faint);
}
.preload__num i {
    font-style: normal;
    font-size: clamp(1.9rem, 6vw, 3rem);
    color: var(--text);
}

/* Exit: the dial drops away first, then the whole sheet lifts off. */
[data-preload] .preload.is-done .preload__inner {
    opacity: 0;
    transform: translateY(-12px) scale(.96);
}
[data-preload] .preload.is-done {
    opacity: 0;
    transform: translateY(-2%);
    pointer-events: none;
}

/* A visitor who asks for less motion never arms the overlay at all, but keep
   the rule so a forced `data-preload` still degrades to a plain fade. */
@media (prefers-reduced-motion: reduce) {
    [data-preload] .preload,
    .preload__inner { transition: opacity .2s linear; }
    [data-preload] .preload.is-done { transform: none; }
    [data-preload] .preload.is-done .preload__inner { transform: none; }
}

/* ---------- 32. Services depth accordion ------------------- */
/* Rows sit on a shared stage. Pointing at one pushes its neighbours back in
   Z and tips them away, so the list reads as a physical stack of plates
   rather than a flat menu. Depth is pure CSS; JS only toggles the panels. */

.accord {
    perspective: 1600px;
    perspective-origin: 50% 40%;
    display: grid;
    gap: .55rem;
}

.accord__row {
    transform-style: preserve-3d;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: var(--glass);
    backdrop-filter: blur(16px);
    box-shadow: var(--lift);
    overflow: hidden;
    transition:
        transform .5s var(--ease-out),
        opacity .4s var(--ease),
        border-color .4s var(--ease),
        box-shadow .5s var(--ease);
}

/* The un-pointed rows recede. Scoped to :hover on the container so nothing
   moves until the visitor is actually interacting with the list. */
.accord:hover .accord__row {
    transform: translate3d(0, 0, -42px) rotateX(4.5deg);
    opacity: .5;
}
.accord:hover .accord__row:hover,
.accord .accord__row:focus-within {
    transform: translate3d(0, 0, 34px) rotateX(0deg);
    opacity: 1;
    border-color: var(--accent-line);
    box-shadow: var(--glow);
}
/* An open row stays forward even while a sibling is hovered, otherwise the
   panel someone is reading sinks away under their own cursor. */
.accord:hover .accord__row.is-open { opacity: .82; }
.accord__row.is-open { border-color: var(--line); }

.accord__h { margin: 0; font-size: inherit; font-weight: inherit; }

.accord__head {
    width: 100%;
    display: grid;
    grid-template-columns: auto auto 1fr auto;
    align-items: center;
    gap: clamp(.9rem, 2.4vw, 1.6rem);
    padding: clamp(1.1rem, 2.6vw, 1.7rem) clamp(1.2rem, 3vw, 2rem);
    background: none;
    border: 0;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.accord__idx {
    font-family: var(--ff-tall);
    font-size: 1rem;
    font-weight: 400;
    letter-spacing: .14em;
    color: var(--faint);
    font-variant-numeric: tabular-nums;
    transition: color .35s var(--ease);
}
.accord__row.is-open .accord__idx,
.accord__row:hover .accord__idx { color: var(--accent); }

.accord__icon {
    width: 38px; height: 38px;
    display: grid; place-items: center;
    border-radius: var(--r-sm);
    color: var(--accent);
    background: var(--accent-soft);
    border: 1px solid var(--accent-line);
    /* Lifted off the row's own plane so the depth reads on the icon too. */
    transform: translateZ(18px);
}
.accord__icon svg { width: 19px; height: 19px; }

.accord__name {
    font-family: var(--ff-tall);
    font-size: clamp(1.05rem, .85rem + 1vw, 1.6rem);
    font-weight: 400;
    line-height: 1.2;
    letter-spacing: .085em;
    text-transform: uppercase;
    color: var(--text);
    transform: translateZ(26px);
}

/* A plus that becomes a minus — cheaper and crisper than rotating a glyph. */
.accord__chev {
    position: relative;
    width: 34px; height: 34px;
    border-radius: 50%;
    border: 1px solid var(--line);
    flex: none;
    transform: translateZ(18px);
    transition: border-color .35s var(--ease), background .35s var(--ease);
}
.accord__chev::before,
.accord__chev::after {
    content: "";
    position: absolute;
    inset: 50% 25% auto;
    height: 1.5px;
    background: currentColor;
    border-radius: 2px;
    transform: translateY(-50%);
    transition: transform .45s var(--ease-out), opacity .3s var(--ease);
}
.accord__chev::after { transform: translateY(-50%) rotate(90deg); }
.accord__row.is-open .accord__chev { border-color: var(--accent-line); background: var(--accent-soft); color: var(--accent); }
.accord__row.is-open .accord__chev::after { transform: translateY(-50%) rotate(0deg); opacity: 0; }

/* 0fr -> 1fr animates a panel of unknown height without measuring it in JS.
   `overflow: hidden` belongs on the panel, not only on the child: a collapsed
   track is 0 tall but the child's own padding still overflows it, which would
   leave a band of dead space under every closed row. */
.accord__panel {
    display: grid;
    grid-template-rows: 0fr;
    overflow: hidden;
    transition: grid-template-rows .5s var(--ease-out);
}
.accord__row.is-open .accord__panel { grid-template-rows: 1fr; }
/* The collapsed track is only truly zero-height when the grid item carries no
   padding of its own: padding sits inside the box and cannot be clipped away
   by that same box's overflow, so it would leave a strip under every closed
   row. Spacing therefore lives on the children as margins, which do get
   clipped. */
.accord__panel-in {
    min-height: 0;
    opacity: 0;
    transition: opacity .4s var(--ease) .05s;
}
.accord__row.is-open .accord__panel-in { opacity: 1; }
.accord__panel-in > * {
    /* Lines the copy up under the service name rather than the index. */
    margin-left: clamp(3.6rem, 9vw, 6.2rem);
    margin-right: clamp(1.2rem, 3vw, 2rem);
}
.accord__panel-in > :last-child { margin-bottom: clamp(1.2rem, 2.6vw, 1.8rem); }
.accord__panel-in p {
    margin-top: 0;
    margin-bottom: 1rem;
    color: var(--muted);
    max-width: 62ch;
}

@media (max-width: 720px) {
    .accord__head { grid-template-columns: auto 1fr auto; gap: .8rem; }
    .accord__icon { display: none; }
    .accord__panel-in > * { margin-left: clamp(1.2rem, 3vw, 2rem); }
}

/* Flat everything: no stage, no recession, no plus-to-minus sweep. The
   disclosure still opens and closes — it just does it instantly. */
@media (prefers-reduced-motion: reduce) {
    .accord { perspective: none; }
    .accord__row,
    .accord:hover .accord__row,
    .accord:hover .accord__row:hover,
    .accord .accord__row:focus-within { transform: none; opacity: 1; transition: none; }
    .accord__icon, .accord__name, .accord__chev { transform: none; }
    .accord__panel { transition: none; }
    .accord__chev::before, .accord__chev::after { transition: none; }
    .accord__panel-in { transition: none; }
}

/* ---------- 33. About — layered parallax diorama ----------- */
/* Three plates on one perspective stage. Each carries its own Z offset and
   its own scroll rate, so the near plate overtakes the far one as the band
   passes the viewport — the depth is real, not a drop shadow. */

.diorama__stage {
    position: relative;
    perspective: 1500px;
    perspective-origin: 55% 45%;
    /* A fixed ratio keeps the absolutely-positioned plates from collapsing
       the section to zero height. */
    aspect-ratio: 16 / 8.4;
    max-height: 620px;
}

.diorama__plate {
    position: absolute;
    margin: 0;
    border-radius: var(--r-lg);
    overflow: hidden;
    border: 1px solid var(--line);
    background: var(--glass-2);
    box-shadow: var(--shadow);
    /* --py is written by the shared parallax module; --z and the tilt are
       per-plate so each one sits on its own plane. */
    transform:
        translate3d(0, var(--py, 0px), var(--z, 0px))
        rotateY(var(--ry, 0deg))
        rotateX(var(--rx, 0deg));
    will-change: transform;
}
.diorama__plate img {
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
}
/* A darker wash on the deepest plate so it reads as further away than its
   size alone would suggest. */
.diorama__plate.is-back::after {
    content: "";
    position: absolute; inset: 0;
    background: linear-gradient(180deg, rgba(5,10,8,.18), rgba(5,10,8,.62));
}

.diorama__plate.is-back {
    inset: 0 8% 14% 0;
    --z: -190px;
    --ry: 3.2deg;
}
.diorama__plate.is-mid {
    inset: 22% 0 0 34%;
    --z: -40px;
    --ry: -2.4deg;
    --rx: 1.4deg;
}
.diorama__plate.is-front {
    inset: 42% 46% 6% 8%;
    --z: 90px;
    --ry: 4deg;
    --rx: -2deg;
    box-shadow: var(--shadow), var(--glow);
}

.diorama__chip {
    position: absolute;
    top: 8%;
    left: 46%;
    display: grid;
    gap: .2rem;
    padding: .85rem 1.2rem;
    border-radius: var(--pill);
    background: var(--glass-2);
    backdrop-filter: blur(18px);
    border: 1px solid var(--accent-line);
    box-shadow: var(--lift);
    transform: translate3d(0, var(--py, 0px), 150px);
    white-space: nowrap;
}
.diorama__chip-k {
    font-size: .64rem;
    font-weight: 700;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--accent);
}
.diorama__chip-v { font-size: .88rem; font-weight: 600; color: var(--text); }

/* Below the split the overlap gets cramped and the plates start to hide each
   other's subjects, so the stage flattens into a simple offset pair. */
@media (max-width: 860px) {
    .diorama__stage { aspect-ratio: 4 / 3.4; perspective: none; }
    .diorama__plate.is-back  { inset: 0 0 30% 0;  --z: 0px; --ry: 0deg; }
    .diorama__plate.is-mid   { display: none; }
    .diorama__plate.is-front { inset: 40% 8% 0 12%; --z: 0px; --ry: 0deg; --rx: 0deg; }
    .diorama__chip { top: 4%; left: auto; right: 4%; transform: translate3d(0, var(--py, 0px), 0); }
}

@media (prefers-reduced-motion: reduce) {
    .diorama__stage { perspective: none; }
    .diorama__plate,
    .diorama__chip { transform: none; will-change: auto; }
    /* Without the depth cue the plates need honest separation instead. */
    .diorama__plate.is-back  { inset: 0 0 34% 0; }
    .diorama__plate.is-mid   { display: none; }
    .diorama__plate.is-front { inset: 44% 6% 0 10%; }
}

/* ---------- 34. Blog — hinged hover-reveal list ------------ */
/* Each row is one link. The cover hangs on a hinge at its right edge and
   swings open when the row is pointed at or focused, so the depth cue comes
   from the rotation itself rather than a shadow. */

.postlist {
    perspective: 1400px;
    border-top: 1px solid var(--line);
}

.post {
    position: relative;
    display: grid;
    /* date | title | meta | cover hinge | arrow — five children, five tracks,
       otherwise the arrow wraps onto an implicit second row. */
    grid-template-columns: auto 1fr auto auto auto;
    align-items: center;
    gap: clamp(1rem, 3vw, 2.4rem);
    padding: clamp(1.3rem, 3vw, 2.1rem) 0;
    border-bottom: 1px solid var(--line);
    text-decoration: none;
    color: inherit;
    transform-style: preserve-3d;
    transition: padding-left .45s var(--ease-out);
}
/* A wash that wipes in from the left behind the row. */
.post::before {
    content: "";
    position: absolute;
    inset: 0 -1.2rem;
    border-radius: var(--r);
    background: var(--glass);
    opacity: 0;
    transform: scaleX(.96);
    transform-origin: left center;
    transition: opacity .4s var(--ease), transform .5s var(--ease-out);
    z-index: -1;
}
.post:hover::before,
.post:focus-visible::before { opacity: 1; transform: scaleX(1); }
.post:hover,
.post:focus-visible { padding-left: 1.2rem; outline: none; }
.post:focus-visible { box-shadow: 0 0 0 2px var(--accent) inset; border-radius: var(--r); }

.post__date {
    font-family: var(--ff-tall);
    font-size: .9rem;
    font-weight: 400;
    letter-spacing: .14em;
    color: var(--faint);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    transition: color .35s var(--ease);
}
.post:hover .post__date { color: var(--lime); }

.post__title {
    margin: 0;
    font-family: var(--ff-tall);
    font-size: clamp(1.1rem, .85rem + 1.3vw, 1.85rem);
    font-weight: 400;
    line-height: 1.18;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--text);
    transition: transform .5s var(--ease-out);
}
.post:hover .post__title { transform: translateZ(30px); }

.post__meta {
    font-size: .78rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--muted);
    white-space: nowrap;
}

/* The hinge. Width animates alongside the rotation so the row's other
   columns are not shoved sideways by a box that is already there. */
.post__cover {
    display: block;
    width: 0;
    aspect-ratio: 16 / 10;
    border-radius: var(--r-sm);
    overflow: hidden;
    transform: perspective(900px) rotateY(-82deg);
    transform-origin: right center;
    opacity: 0;
    transition:
        width .5s var(--ease-out),
        transform .55s var(--ease-out),
        opacity .3s var(--ease);
}
.post:hover .post__cover,
.post:focus-visible .post__cover {
    width: clamp(120px, 15vw, 210px);
    transform: perspective(900px) rotateY(0deg);
    opacity: 1;
}
.post__cover img { width: 100%; height: 100%; object-fit: cover; display: block; }

.post__go {
    width: 40px; height: 40px;
    display: grid; place-items: center;
    border-radius: 50%;
    border: 1px solid var(--line);
    color: var(--muted);
    flex: none;
    transition: transform .45s var(--ease-out), background .35s var(--ease),
                color .35s var(--ease), border-color .35s var(--ease);
}
.post:hover .post__go,
.post:focus-visible .post__go {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
    transform: translateZ(40px) rotate(45deg);
}

/* Touch: there is no hover to reveal anything, so the cover is simply part of
   the row and the hinge is dropped. */
@media (max-width: 780px) {
    .post {
        grid-template-columns: 1fr auto;
        grid-template-areas:
            "date  go"
            "title title"
            "cover cover"
            "meta  meta";
        gap: .55rem 1rem;
    }
    .post__date  { grid-area: date; }
    .post__go    { grid-area: go; }
    .post__title { grid-area: title; }
    .post__meta  { grid-area: meta; }
    .post__cover {
        grid-area: cover;
        width: 100%;
        opacity: 1;
        transform: none;
        margin-top: .35rem;
    }
    .post:hover, .post:focus-visible { padding-left: 0; }
    .post:hover .post__title { transform: none; }
    .post:hover .post__go, .post:focus-visible .post__go { transform: rotate(45deg); }
}

@media (prefers-reduced-motion: reduce) {
    .postlist { perspective: none; }
    .post, .post::before, .post__title, .post__cover, .post__go, .post__date { transition: none; }
    .post:hover, .post:focus-visible { padding-left: 0; }
    .post:hover .post__title { transform: none; }
    .post__cover { transform: none; }
    .post:hover .post__cover, .post:focus-visible .post__cover { transform: none; }
    .post:hover .post__go, .post:focus-visible .post__go { transform: rotate(45deg); }
}

/* ---------- 35. Contact — depth stage + posed form card ---- */
/* The generic [data-tilt] rule already supplies the perspective and the
   pointer-driven rotation; all that is added here is per-child Z so the
   lines separate into planes instead of tilting as one flat sheet. */

.contact-lines.is-3d { transform-style: preserve-3d; }
.contact-lines.is-3d > a,
.contact-lines.is-3d > div {
    transform: translateZ(var(--cz, 0px));
    transition: border-color .3s var(--ease), transform .45s var(--ease-out),
                box-shadow .45s var(--ease);
}
.contact-lines.is-3d > :nth-child(1) { --cz: 46px; }
.contact-lines.is-3d > :nth-child(2) { --cz: 32px; }
.contact-lines.is-3d > :nth-child(3) { --cz: 18px; }
.contact-lines.is-3d > :nth-child(4) { --cz: 6px; }
/* The two links keep their own hover, now expressed in Z so it reads as
   coming toward the reader rather than sliding sideways. */
.contact-lines.is-3d > a:hover {
    border-color: var(--accent-line);
    transform: translateZ(calc(var(--cz, 0px) + 34px));
    box-shadow: var(--glow);
}

/* The form sits slightly turned at rest, then squares up the moment someone
   starts filling it in — a posed card is decoration, a moving one is an
   obstacle. */
.form-stage { perspective: 1600px; }
.form-card.is-3d {
    transform-style: preserve-3d;
    transform: rotateY(-3.4deg) rotateX(1.2deg);
    transition: transform .7s var(--ease-out), box-shadow .6s var(--ease);
}
.form-card.is-3d:focus-within,
.form-card.is-3d:hover {
    transform: rotateY(0deg) rotateX(0deg);
    box-shadow: var(--glow);
}
/* Lift the call to action off the card face so the turn is legible. */
.form-card.is-3d .btn-v { transform: translateZ(38px); }
.form-card.is-3d .field { transform: translateZ(12px); }

@media (max-width: 900px) {
    /* Portrait widths put the form full-bleed; a turned card would clip
       against the gutter, so both effects flatten. */
    .form-stage { perspective: none; }
    .form-card.is-3d,
    .form-card.is-3d:focus-within,
    .form-card.is-3d:hover { transform: none; }
    .form-card.is-3d .btn-v,
    .form-card.is-3d .field { transform: none; }
    .contact-lines.is-3d > a,
    .contact-lines.is-3d > div { transform: none; }
    .contact-lines.is-3d > a:hover { transform: translateX(6px); }
}

@media (prefers-reduced-motion: reduce) {
    .form-stage { perspective: none; }
    .form-card.is-3d,
    .form-card.is-3d:focus-within,
    .form-card.is-3d:hover { transform: none; transition: box-shadow .2s linear; }
    .form-card.is-3d .btn-v,
    .form-card.is-3d .field { transform: none; }
    .contact-lines.is-3d > a,
    .contact-lines.is-3d > div { transform: none; transition: border-color .2s linear; }
    .contact-lines.is-3d > a:hover { transform: none; }
}

/* ---------- 36. Fullscreen project deck -------------------- */
/* Without JS this is a run of full-bleed sections that scrolls like any other
   page. `.is-live` — set by motion.js only after it has successfully taken
   over — stacks them into a one-at-a-time deck. Nothing here hides content
   before that class exists, so a script failure degrades to a long page
   rather than a blank one. */

.deck {
    position: relative;
    /* <main> is already full width; 100vw would add the scrollbar and push
       the page sideways. */
    width: 100%;
}

.deck__slide {
    position: relative;
    min-height: min(94svh, 900px);
    display: grid;
    place-items: center;
    overflow: hidden;
    isolation: isolate;
}

.deck__bg { position: absolute; inset: 0; z-index: 0; }
.deck__bg img {
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
    /* Slight overscale leaves room for the parallax drift without exposing
       an edge — and, once blurred, for the soft edge the blur creates. */
    transform: scale(1.1) translate3d(0, var(--bgy, 0px), 0);
    /* Project shots are often website screenshots full of their own type.
       A shallow blur turns them into a depth-of-field backdrop instead of a
       second headline competing with the name on top. */
    filter: blur(4px) saturate(1.15);
    transition: transform 1.2s var(--ease-out);
}

.deck__scrim {
    position: absolute; inset: 0; z-index: 1;
    /* Project imagery is unpredictable — screenshots come in bright and busy —
       so the scrim has to be strong enough that white display type always
       lands, not merely tasteful over a dark photo. */
    background:
        radial-gradient(115% 85% at 50% 52%, rgba(3,7,5,.55), rgba(3,7,5,.93) 74%),
        linear-gradient(180deg, rgba(3,7,5,.86), rgba(3,7,5,.62) 42%, rgba(3,7,5,.94));
}

/* The outline circle the content sits inside. */
.deck__ring {
    position: absolute;
    z-index: 2;
    top: 50%; left: 50%;
    width: min(74vh, 62vw);
    aspect-ratio: 1;
    border: 1px solid rgba(255,255,255,.16);
    border-radius: 50%;
    transform: translate(-50%, -50%) scale(var(--ringscale, 1));
    transition: transform 1.1s var(--ease-out), opacity .8s var(--ease);
    pointer-events: none;
}

.deck__content {
    position: relative;
    z-index: 3;
    display: grid;
    justify-items: center;
    gap: 1.15rem;
    text-align: center;
    padding: clamp(4rem, 12vh, 8rem) var(--gutter);
    max-width: 1100px;
    transform-style: preserve-3d;
}

.deck__cats {
    margin: 0;
    font-size: clamp(.7rem, 1.4vw, .82rem);
    font-weight: 600;
    letter-spacing: .24em;
    text-transform: uppercase;
    color: rgba(255,255,255,.72);
}

.deck__name {
    margin: 0;
    font-family: var(--ff-tall);
    font-size: clamp(1.5rem, .7rem + 3.4vw, 3.8rem);
    font-weight: 300;
    line-height: 1.1;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: #fff;
    /* Long project names must not grow into a wall that swallows the ring. */
    max-width: 15ch;
    text-wrap: balance;
    transform: translateZ(60px);
}

.deck__cta {
    display: inline-flex;
    align-items: center;
    gap: .6rem;
    margin-top: .8rem;
    padding: .85rem 1.9rem;
    border-radius: var(--pill);
    border: 1px solid rgba(255,255,255,.42);
    color: #fff;
    text-decoration: none;
    font-size: .86rem;
    font-weight: 600;
    letter-spacing: .04em;
    backdrop-filter: blur(6px);
    transform: translateZ(90px);
    transition: background .35s var(--ease), color .35s var(--ease),
                border-color .35s var(--ease), gap .35s var(--ease);
}
.deck__cta:hover,
.deck__cta:focus-visible {
    background: var(--green-lit);
    border-color: var(--green-lit);
    color: #04140b;
    gap: 1.1rem;
}

/* ---- live deck: one slide on screen at a time ---- */

.deck.is-live {
    height: 100svh;
    /* Slide up under the sticky header so the stage is a true full screen;
       the header then floats over the imagery like the reference does. */
    margin-top: calc(var(--header-h) * -1);
    overflow: hidden;
    /* The stage every slide rotates on. */
    perspective: 1800px;
}
/* …and push the content back down so the header never covers the title. */
.deck.is-live .deck__content { padding-top: calc(var(--header-h) + clamp(1rem, 4vh, 3rem)); }
.deck.is-live .deck__viewport { position: relative; height: 100%; transform-style: preserve-3d; }

.deck.is-live .deck__slide {
    position: absolute;
    inset: 0;
    min-height: 0;
    opacity: 0;
    visibility: hidden;
    transform: translate3d(0, 0, -420px) rotateX(9deg);
    transition:
        opacity .75s var(--ease-out),
        transform 1s var(--ease-out),
        visibility 0s linear .95s;
}
.deck.is-live .deck__slide.is-active {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition:
        opacity .7s var(--ease-out),
        transform 1s var(--ease-out),
        visibility 0s;
}
/* Slides already passed fall away upward instead of back, so the direction of
   travel is legible. */
.deck.is-live .deck__slide.is-past {
    transform: translate3d(0, -14%, 220px) rotateX(-11deg);
}

/* The name and button arrive a beat after the plate settles. */
.deck.is-live .deck__slide .deck__cats,
.deck.is-live .deck__slide .deck__name,
.deck.is-live .deck__slide .deck__cta {
    opacity: 0;
    transform: translate3d(0, 30px, 0);
    transition: opacity .6s var(--ease-out), transform .8s var(--ease-out);
}
.deck.is-live .deck__slide.is-active .deck__cats { opacity: 1; transform: none; transition-delay: .18s; }
.deck.is-live .deck__slide.is-active .deck__name { opacity: 1; transform: translateZ(60px); transition-delay: .26s; }
.deck.is-live .deck__slide.is-active .deck__cta  { opacity: 1; transform: translateZ(90px); transition-delay: .36s; }

.deck.is-live .deck__slide .deck__ring { opacity: 0; transform: translate(-50%, -50%) scale(.82); }
.deck.is-live .deck__slide.is-active .deck__ring { opacity: 1; transform: translate(-50%, -50%) scale(1); }

/* ---- chrome ---- */

.deck__ui {
    position: absolute;
    inset: 0;
    z-index: 6;
    pointer-events: none;
}
.deck__ui > * { pointer-events: auto; }

.deck__arrow {
    position: absolute;
    top: 50%;
    width: 60px; height: 60px;
    display: grid;
    place-items: center;
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    transform: translateY(-50%);
    transition: opacity .3s var(--ease);
}
.deck__arrow.is-prev { left: clamp(.6rem, 2.5vw, 2.4rem); }
.deck__arrow.is-next { right: clamp(.6rem, 2.5vw, 2.4rem); }
.deck__arrow[disabled] { opacity: .28; cursor: default; }
.deck__arrow svg {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    fill: none;
    stroke: rgba(255,255,255,.4);
    stroke-width: 1;
    transition: stroke .35s var(--ease), transform .5s var(--ease-out);
}
.deck__arrow:hover:not([disabled]) svg { stroke: var(--green-lit); transform: scale(1.08); }
/* A chevron drawn from two borders — no icon font needed for the deck. */
.deck__arrow-tip {
    width: 11px; height: 11px;
    border-top: 1.5px solid #fff;
    border-right: 1.5px solid #fff;
    transition: transform .4s var(--ease-out);
}
.deck__arrow.is-next .deck__arrow-tip { transform: translateX(-2px) rotate(45deg); }
.deck__arrow.is-prev .deck__arrow-tip { transform: translateX(2px)  rotate(-135deg); }
.deck__arrow.is-next:hover:not([disabled]) .deck__arrow-tip { transform: translateX(3px) rotate(45deg); }
.deck__arrow.is-prev:hover:not([disabled]) .deck__arrow-tip { transform: translateX(-3px) rotate(-135deg); }

.deck__dots {
    position: absolute;
    left: 50%;
    bottom: clamp(1.4rem, 4vh, 2.8rem);
    transform: translateX(-50%);
    display: flex;
    gap: .55rem;
    align-items: center;
}
.deck__dot {
    width: 8px; height: 8px;
    padding: 0;
    border-radius: 50%;
    border: 1px solid rgba(255,255,255,.5);
    background: none;
    cursor: pointer;
    transition: width .45s var(--ease-out), background .35s var(--ease),
                border-color .35s var(--ease);
}
.deck__dot.is-on {
    width: 30px;
    border-radius: var(--pill);
    background: var(--green-lit);
    border-color: var(--green-lit);
}

.deck__count {
    position: absolute;
    right: clamp(1rem, 3vw, 2.6rem);
    bottom: clamp(1.4rem, 4vh, 2.8rem);
    display: flex;
    align-items: center;
    gap: .7rem;
    font-family: var(--ff-tall);
    font-size: 1rem;
    font-weight: 400;
    letter-spacing: .2em;
    color: rgba(255,255,255,.85);
}
.deck__count-bar { width: 34px; height: 1px; background: rgba(255,255,255,.4); }
.deck__count-total { color: rgba(255,255,255,.5); }

.deck__hint {
    position: absolute;
    left: clamp(1rem, 3vw, 2.6rem);
    bottom: clamp(1.4rem, 4vh, 2.8rem);
    margin: 0;
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .2em;
    text-transform: uppercase;
    color: rgba(255,255,255,.45);
}

/* The filter panel sits under the deck; on the live deck it is a normal
   section the visitor reaches by scrolling past, so it needs its own top
   spacing to clear the 100svh stage. */
body.is-deck .deck-filters-wrap { padding-top: clamp(3rem, 7vw, 6rem); }

@media (max-width: 900px) {
    .deck__hint { display: none; }
    .deck__arrow { width: 46px; height: 46px; }
    .deck__count { font-size: .9rem; }
    .deck__ring { width: min(60vh, 84vw); }
}
@media (max-width: 640px) {
    /* A long dot row runs into the counter and gives 8px tap targets nobody
       can hit. On a phone the arrows, the swipe and the counter are the
       navigation; the dots add nothing but collision. */
    .deck__dots { display: none; }
    .deck__count { left: 50%; right: auto; transform: translateX(-50%); }
}

/* No deck at all: the sections keep their natural flow and the chrome stays
   hidden, so a visitor gets a readable list of full-bleed projects. */
@media (prefers-reduced-motion: reduce) {
    .deck__bg img { transform: scale(1.02); transition: none; }
    .deck__slide { min-height: min(70svh, 640px); }
    .deck__name, .deck__cta { transform: none; }
    .deck__ring { transition: none; }
}

/* ---------- 37. Wordmark hero ------------------------------ */
/* Full-bleed stage with the brand mark set as the largest thing on the page.
   The two words sit on separate depth planes and drift against the pointer,
   so the 3D lives in the type rather than in a box drawn around it. */

.mark-hero {
    position: relative;
    min-height: 100svh;
    margin-top: calc(var(--header-h) * -1);
    display: grid;
    place-items: center;
    overflow: hidden;
    isolation: isolate;
    perspective: 1400px;
}

.mark-hero__bg { position: absolute; inset: 0; z-index: 0; }
.mark-hero__bg img {
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
    transform: scale(1.08) translate3d(0, var(--bgy, 0px), 0);
    filter: blur(3px) saturate(1.1);
}
.mark-hero__scrim {
    position: absolute; inset: 0; z-index: 1;
    background:
        radial-gradient(110% 80% at 50% 42%, rgba(3,7,5,.5), rgba(3,7,5,.94) 76%),
        linear-gradient(180deg, rgba(3,7,5,.88), rgba(3,7,5,.55) 45%, var(--bg));
}

.mark-hero__inner {
    position: relative;
    z-index: 2;
    display: grid;
    justify-items: center;
    text-align: center;
    gap: 1.1rem;
    padding-top: calc(var(--header-h) + clamp(1rem, 4vh, 3rem));
    padding-bottom: clamp(3rem, 9vh, 6rem);
    transform-style: preserve-3d;
}

/* The hero is the first viewport, so its entrance plays on load rather than
   on an IntersectionObserver. A scroll observer here is both pointless — the
   content is already on screen — and fragile: one element missing its
   callback leaves a button permanently invisible. */
.mark-hero__kick,
.mark-hero__sub,
.mark-hero__desc,
.mark-hero__actions {
    animation: hero-rise .9s var(--ease-out) both;
}
.mark-hero__kick    { margin-bottom: .2rem; animation-delay: .12s; }
.mark-hero__sub     { animation-delay: .30s; }
.mark-hero__desc    { animation-delay: .40s; }
.mark-hero__actions { animation-delay: .50s; }

@keyframes hero-rise {
    from { opacity: 0; transform: translateY(26px); }
    to   { opacity: 1; transform: none; }
}

.mark-hero__mark {
    margin: 0;
    display: grid;
    gap: 0;
    font-family: var(--ff-tall);
    font-weight: 300;
    /* The mark is meant to touch both gutters — it is the page's widest
       element, not a heading that happens to be large. Tracked out to match
       the spacing of the wordmark in the logo file. */
    font-size: clamp(2.1rem, .4rem + 8.4vw, 9rem);
    line-height: 1.02;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--text);
    transform-style: preserve-3d;
}
.mark-hero__word {
    display: block;
    /* --mx/--my come from the pointer; --w staggers the planes so the second
       word trails the first instead of moving in lockstep. */
    transform: translate3d(
        calc(var(--mx, 0) * (1px + var(--w) * 6px)),
        calc(var(--my, 0) * (1px + var(--w) * 4px)),
        calc(var(--w) * 55px)
    );
    transition: transform .5s var(--ease-out);
}
/* The lockup mirrors the logo file: the name large, the descriptor small and
   tracked out beneath it, carrying the brand gradient. */
.mark-hero__word:last-child {
    font-size: clamp(.62rem, .18rem + 1.5vw, 1.55rem);
    font-weight: 400;
    letter-spacing: .42em;
    /* The wide tracking adds a trailing space on the right; pull it back so
       the descriptor stays optically centred under the name. */
    text-indent: .42em;
    line-height: 1.6;
    background: linear-gradient(100deg, var(--green) 0%, var(--green-lit) 46%, var(--lime) 100%);
    -webkit-background-clip: text; background-clip: text;
    color: transparent;
}

.mark-hero__sub {
    margin: .6rem 0 0;
    font-family: var(--ff-display);
    font-size: clamp(1.15rem, .9rem + 1.2vw, 2rem);
    line-height: 1.25;
    color: var(--text);
    max-width: 24ch;
}
.mark-hero__sub em { font-style: italic; color: var(--accent); }

.mark-hero__desc {
    margin: 0;
    max-width: 56ch;
    color: var(--muted);
    font-size: var(--step-0);
}

.mark-hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: .8rem;
    justify-content: center;
    margin-top: 1rem;
}

/* Scroll cue: a line that falls through a slot, on a loop. */
.mark-hero__scroll {
    position: absolute;
    left: 50%;
    bottom: clamp(1.1rem, 3.5vh, 2.2rem);
    z-index: 3;
    width: 1px;
    height: 46px;
    background: var(--line);
    overflow: hidden;
    transform: translateX(-50%);
}
.mark-hero__scroll span {
    position: absolute;
    inset: 0 auto auto 0;
    width: 100%;
    height: 40%;
    background: var(--accent);
    animation: scroll-cue 2.2s var(--ease) infinite;
}
@keyframes scroll-cue {
    0%       { transform: translateY(-100%); }
    55%,100% { transform: translateY(250%); }
}

@media (max-width: 720px) {
    .mark-hero { min-height: 92svh; }
    .mark-hero__sub { max-width: 20ch; }
}

@media (prefers-reduced-motion: reduce) {
    .mark-hero__word { transform: none; transition: none; }
    .mark-hero__bg img { transform: scale(1.02); }
    .mark-hero__scroll span { animation: none; transform: translateY(30%); }
    .mark-hero__kick,
    .mark-hero__sub,
    .mark-hero__desc,
    .mark-hero__actions { animation: none; opacity: 1; transform: none; }
}

/* ---------- 38. Figures (label / number / unit) ------------ */

.big-lead {
    margin: clamp(1.5rem, 4vw, 3rem) 0 clamp(2rem, 5vw, 3.5rem);
    max-width: 32ch;
    font-family: var(--ff-display);
    font-size: clamp(1.5rem, 1rem + 2.4vw, 3.4rem);
    line-height: 1.16;
    color: var(--text);
}

.figures {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: clamp(1.2rem, 3vw, 2.4rem);
    border-top: 1px solid var(--line);
    padding-top: clamp(1.6rem, 4vw, 2.6rem);
}
.figure {
    display: grid;
    justify-items: start;
    gap: .15rem;
}
.figure__k,
.figure__u {
    font-size: .74rem;
    font-weight: 600;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--faint);
}
.figure__n {
    font-family: var(--ff-tall);
    font-size: clamp(2.4rem, 1.3rem + 3.2vw, 4.6rem);
    font-weight: 300;
    line-height: 1;
    letter-spacing: .02em;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}
.figure__u { color: var(--accent); }

/* ---------- 39. Pill link (section action) ----------------- */

.pill-link {
    display: inline-flex;
    align-items: center;
    gap: .55rem;
    padding: .68rem 1.35rem;
    border-radius: var(--pill);
    border: 1px solid var(--line);
    background: var(--glass);
    backdrop-filter: blur(14px);
    color: var(--text);
    text-decoration: none;
    font-size: .82rem;
    font-weight: 600;
    letter-spacing: .03em;
    white-space: nowrap;
    transition: background .35s var(--ease), color .35s var(--ease),
                border-color .35s var(--ease), gap .35s var(--ease);
}
.pill-link:hover,
.pill-link:focus-visible {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
    gap: .95rem;
}

/* The featured bands run to the gutters instead of the text column, which is
   what makes them read as full-bleed imagery rather than large cards. */
.stack-wrap { padding-inline: var(--gutter); }

/* ---------- 40. Service plates (numbered, with sub-list) ---- */
/* One stage, four plates. Pointing at one brings it forward and pushes the
   rest back — the same depth grammar as the services accordion, so the two
   pages feel like one system. */

.plates {
    display: grid;
    /* 270px keeps the shell at four columns rather than collapsing to five
       and leaving an orphan on a second row. */
    grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
    gap: clamp(.8rem, 1.6vw, 1.2rem);
    perspective: 1500px;
}

.plate {
    position: relative;
    display: grid;
    align-content: start;
    gap: .75rem;
    padding: clamp(1.4rem, 2.6vw, 2.1rem);
    min-height: clamp(230px, 26vw, 320px);
    border-radius: var(--r);
    border: 1px solid var(--line);
    background: var(--glass);
    backdrop-filter: blur(16px);
    box-shadow: var(--lift);
    transform-style: preserve-3d;
    transition: transform .55s var(--ease-out), opacity .4s var(--ease),
                border-color .4s var(--ease), box-shadow .5s var(--ease);
}
.plates:hover .plate { transform: translateZ(-46px); opacity: .52; }
.plates:hover .plate:hover,
.plates .plate:focus-within {
    transform: translateZ(38px);
    opacity: 1;
    border-color: var(--accent-line);
    box-shadow: var(--glow);
}

.plate__idx {
    font-family: var(--ff-tall);
    font-size: 1.05rem;
    font-weight: 400;
    letter-spacing: .14em;
    color: var(--faint);
    transform: translateZ(14px);
    transition: color .35s var(--ease);
}
.plate:hover .plate__idx { color: var(--accent); }

.plate__icon {
    width: 34px; height: 34px;
    display: grid; place-items: center;
    color: var(--accent);
    transform: translateZ(22px);
}
.plate__icon svg { width: 22px; height: 22px; }

.plate__name {
    margin: 0;
    font-family: var(--ff-tall);
    font-size: clamp(1rem, .82rem + .85vw, 1.35rem);
    font-weight: 400;
    line-height: 1.25;
    text-transform: uppercase;
    letter-spacing: .095em;
    color: var(--text);
    transform: translateZ(30px);
}

.plate__list {
    margin: .2rem 0 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: .42rem;
    transform: translateZ(12px);
}
.plate__list li {
    position: relative;
    padding-left: 1rem;
    font-size: .85rem;
    line-height: 1.4;
    color: var(--muted);
}
.plate__list li::before {
    content: "";
    position: absolute;
    left: 0; top: .58em;
    width: 5px; height: 1px;
    background: var(--accent);
}

/* The whole plate is the hit area; the label lives on the heading. */
.plate__link { position: absolute; inset: 0; border-radius: inherit; }
.plate__link:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

@media (prefers-reduced-motion: reduce) {
    .plates { perspective: none; }
    .plate,
    .plates:hover .plate,
    .plates:hover .plate:hover,
    .plates .plate:focus-within { transform: none; opacity: 1; transition: none; }
    .plate__idx, .plate__icon, .plate__name, .plate__list { transform: none; }
}

/* ---------- 41. Dark zones -------------------------------- */
/* Sections built on full-bleed photography keep light-on-dark text in both
   themes — a photograph does not get lighter because the theme did. Rather
   than writing a second set of rules for every component inside them, the
   zone re-declares the surface tokens and everything below inherits. */

.zone-dark {
    --text:        #eef2f0;
    --muted:       #a4a9a7;
    --faint:       #7d8582;
    --line:        rgba(255, 255, 255, .12);
    --line-2:      rgba(255, 255, 255, .06);
    --glass:       rgba(18, 24, 26, .58);
    --glass-2:     rgba(24, 32, 34, .72);
    --glass-hi:    rgba(255, 255, 255, .07);
    --accent:      var(--green-lit);
    --accent-soft: rgba(95, 227, 155, .13);
    --accent-line: rgba(95, 227, 155, .3);
    --on-accent:   #04140b;
    --lime:        #8fe36a;
    --lime-lit:    #b9f58f;
    --sheen:       rgba(255, 255, 255, .1);
    --lift:        inset 0 1px 0 rgba(255, 255, 255, .08);
    color: var(--text);
}

/* The sticky header floats over the hero and the deck. While it is up there
   it is inside a dark zone even though the page below may be light, so it
   borrows the same tokens — and the inverted lockup — until it sticks. */
body.has-dark-top .site-header:not(.is-stuck) {
    --text:  #eef2f0;
    --muted: rgba(255, 255, 255, .74);
    --faint: rgba(255, 255, 255, .5);
    --line:  rgba(255, 255, 255, .14);
    --glass:   rgba(18, 24, 26, .5);
    --glass-2: rgba(24, 32, 34, .66);
    --accent:      var(--green-lit);
    --accent-soft: rgba(95, 227, 155, .16);
    --accent-line: rgba(95, 227, 155, .34);
    --on-accent:   #04140b;
    color: var(--text);
}
[data-theme="light"] body.has-dark-top .site-header:not(.is-stuck) .brand img.logo-light,
body.has-dark-top .site-header:not(.is-stuck) .brand img.logo-light { display: none; }
[data-theme="light"] body.has-dark-top .site-header:not(.is-stuck) .brand img.logo-dark,
body.has-dark-top .site-header:not(.is-stuck) .brand img.logo-dark { display: block; }

/* The footer is a dark plate in both themes, which gives the page a
   deliberate close rather than fading out into the background. */
[data-theme="light"] .site-footer { background: #0b1210; border-top-color: rgba(255,255,255,.1); }

/* The exit from the showcase into the searchable archive. Sits above the
   scroll hint so the two reading directions never overlap. */
.deck__all {
    position: absolute;
    left: 50%;
    bottom: clamp(3.6rem, 9vh, 5.6rem);
    transform: translateX(-50%);
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem 1.15rem;
    border-radius: var(--pill);
    border: 1px solid rgba(255,255,255,.28);
    background: rgba(8, 14, 11, .42);
    backdrop-filter: blur(10px);
    color: rgba(255,255,255,.86);
    text-decoration: none;
    font-size: .74rem;
    font-weight: 600;
    letter-spacing: .12em;
    text-transform: uppercase;
    white-space: nowrap;
    transition: background .3s var(--ease), color .3s var(--ease),
                border-color .3s var(--ease), gap .3s var(--ease);
}
.deck__all:hover,
.deck__all:focus-visible {
    background: var(--green-lit);
    border-color: var(--green-lit);
    color: #04140b;
    gap: .85rem;
}
@media (max-width: 640px) {
    /* The dots are gone at this width, so the button takes their place. */
    .deck__all { bottom: clamp(1.3rem, 4vh, 2.6rem); }
    .deck__count { bottom: auto; top: calc(var(--header-h) + .4rem); }
}

/* ---------- 42. Filter chips ------------------------------- */
/* A row of one-click filters. Links rather than buttons, so each state is a
   real URL that can be shared, bookmarked and crawled. */

.chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
}
.chip-btn {
    display: inline-flex;
    align-items: center;
    padding: .5rem 1.05rem;
    border-radius: var(--pill);
    border: 1px solid var(--line);
    background: var(--glass);
    color: var(--muted);
    text-decoration: none;
    font-size: .8rem;
    font-weight: 600;
    letter-spacing: .04em;
    white-space: nowrap;
    transition: background .3s var(--ease), color .3s var(--ease),
                border-color .3s var(--ease), transform .3s var(--ease-out);
}
.chip-btn:hover,
.chip-btn:focus-visible {
    color: var(--text);
    border-color: var(--accent-line);
    transform: translateY(-2px);
}
.chip-btn.is-on {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
}

/* ---------- 43. Touch target sizing ------------------------ */
/* Inline footer and list links are ~19px tall, which is fine for a cursor and
   awkward for a thumb. On coarse pointers they become blocks with enough
   vertical padding to clear a ~44px target without changing the layout's
   rhythm — the gap shrinks by the same amount the padding adds. */
@media (pointer: coarse) {
    .site-footer ul { gap: 0; }
    .site-footer ul a {
        display: block;
        padding-block: .68rem;
    }
    .link-v { padding-block: .45rem; }
    .contact-lines > a,
    .contact-lines > div { min-height: 56px; }
    /* The logo carousel is decorative; its links still need a real target. */
    .cyl__item { min-height: 44px; }
}

/* ---------- 44. Client portal ------------------------------ */
/* Front-of-house: clients see progress and outcomes. The visual language is
   the public site's, so signing in does not feel like leaving the brand. */

/* ---- sign in ---- */
.portal-gate__inner {
    display: grid;
    grid-template-columns: 1.05fr .95fr;
    gap: clamp(2rem, 5vw, 4.5rem);
    align-items: center;
}
.portal-gate__title { font-size: var(--step-3); margin: .2rem 0 1rem; }
.portal-gate__list {
    list-style: none;
    margin: 2rem 0 0;
    padding: 0;
    display: grid;
    gap: .8rem;
}
.portal-gate__list li {
    display: flex;
    align-items: center;
    gap: .8rem;
    font-size: .95rem;
    color: var(--muted);
}
.portal-gate__list i { color: var(--accent); font-size: 1.1rem; }
.portal-gate__form { align-self: start; }

.portal-alert {
    display: flex;
    align-items: center;
    gap: .6rem;
    margin: 0 0 1.1rem;
    padding: .8rem 1rem;
    border-radius: var(--r-sm);
    border: 1px solid rgba(226, 94, 70, .4);
    background: rgba(226, 94, 70, .1);
    color: #e8897a;
    font-size: .88rem;
}

/* ---- shell ---- */
.portal__head {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    align-items: center;
    justify-content: space-between;
    margin-bottom: clamp(1.6rem, 4vw, 2.6rem);
}
.portal__id { display: flex; align-items: center; gap: 1rem; }
.portal__logo {
    width: 56px; height: 56px;
    flex: none;
    display: grid;
    place-items: center;
    border-radius: var(--r-sm);
    border: 1px solid var(--line);
    background: var(--glass);
    overflow: hidden;
}
.portal__logo img { width: 100%; height: 100%; object-fit: contain; padding: .35rem; }
.portal__logo--letter {
    font-family: var(--ff-display);
    font-size: 1.5rem;
    color: var(--accent);
}
.portal__hi {
    display: block;
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--faint);
}
.portal__name { margin: .15rem 0 0; font-size: clamp(1.4rem, 1rem + 1.4vw, 2.2rem); }

.portal__tabs {
    display: flex;
    gap: .4rem;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    border-bottom: 1px solid var(--line);
    margin-bottom: clamp(1.6rem, 4vw, 2.4rem);
}
.portal__tabs::-webkit-scrollbar { display: none; }
.portal__tab {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .9rem 1.1rem;
    color: var(--muted);
    text-decoration: none;
    font-size: .9rem;
    font-weight: 600;
    white-space: nowrap;
    transition: color .3s var(--ease);
}
.portal__tab::after {
    content: "";
    position: absolute;
    left: 1.1rem; right: 1.1rem; bottom: -1px;
    height: 2px;
    background: var(--accent);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform .35s var(--ease-out);
}
.portal__tab:hover { color: var(--text); }
.portal__tab.is-on { color: var(--text); }
.portal__tab.is-on::after { transform: scaleX(1); }
.portal__badge {
    min-width: 20px;
    padding: 0 .4rem;
    border-radius: var(--pill);
    background: var(--accent);
    color: var(--on-accent);
    font-size: .7rem;
    line-height: 20px;
    text-align: center;
}

.portal__h {
    font-size: var(--step-1);
    margin: clamp(2rem, 5vw, 3rem) 0 1.1rem;
}

/* ---- at-a-glance cards ---- */
.portal-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: clamp(.8rem, 1.6vw, 1.2rem);
}
.pcard {
    padding: clamp(1.2rem, 2.4vw, 1.7rem);
    border-radius: var(--r);
    border: 1px solid var(--line);
    background: var(--glass);
    backdrop-filter: blur(16px);
    box-shadow: var(--lift);
}
.pcard__k {
    display: block;
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--faint);
    margin-bottom: .6rem;
}
.pcard__v {
    display: block;
    font-family: var(--ff-tall);
    font-size: clamp(1.9rem, 1.2rem + 2vw, 2.9rem);
    font-weight: 300;
    line-height: 1;
    letter-spacing: .02em;
    color: var(--text);
}
.pcard__v i { font-style: normal; font-size: .5em; color: var(--faint); margin-left: .1em; }
.pcard__v--muted { color: var(--faint); }
/* A balance is a sentence, not a headline number — it must not overflow. */
.pcard__v--money { font-size: clamp(1.05rem, .8rem + .7vw, 1.35rem); line-height: 1.35; }
.pcard__sub { display: block; margin-top: .4rem; font-size: .8rem; color: var(--muted); }

/* ---- progress bar ---- */
.pbar {
    height: 5px;
    border-radius: var(--pill);
    background: var(--line);
    overflow: hidden;
    margin-top: .8rem;
}
.pbar span {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: var(--grad);
    /* Grows from nothing on load so the value registers as a measurement. */
    animation: pbar-fill 1s var(--ease-out) both;
    transform-origin: left;
}
@keyframes pbar-fill { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* ---- project rows ---- */
.prow-list { display: grid; gap: .7rem; }
.prow {
    display: grid;
    grid-template-columns: 1fr minmax(140px, 240px);
    gap: 1.2rem;
    align-items: center;
    padding: clamp(1rem, 2vw, 1.35rem) clamp(1.1rem, 2.4vw, 1.6rem);
    border-radius: var(--r);
    border: 1px solid var(--line);
    background: var(--glass);
    transition: border-color .3s var(--ease), transform .35s var(--ease-out);
}
.prow:hover { border-color: var(--accent-line); transform: translateX(4px); }
.prow__title { margin: .35rem 0 0; font-size: clamp(1rem, .9rem + .5vw, 1.25rem); }
.prow__bar { display: flex; align-items: center; gap: .8rem; }
.prow__bar .pbar { flex: 1; margin-top: 0; }
.prow__bar b { font-family: var(--ff-tall); font-weight: 400; font-size: .95rem; letter-spacing: .06em; }

.prow__status {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--faint);
}
.prow__status::before {
    content: "";
    width: 6px; height: 6px;
    border-radius: 50%;
    background: currentColor;
}
.prow__status.is-progress  { color: var(--lime); }
.prow__status.is-completed { color: var(--accent); }
.prow__status.is-over      { color: #e8897a; }

/* ---- project cards ---- */
.pgrid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: clamp(1rem, 2vw, 1.5rem);
}
.pcase {
    border-radius: var(--r);
    border: 1px solid var(--line);
    background: var(--glass);
    overflow: hidden;
    transition: border-color .3s var(--ease), transform .4s var(--ease-out), box-shadow .4s var(--ease);
}
.pcase:hover { border-color: var(--accent-line); transform: translateY(-4px); box-shadow: var(--glow); }
.pcase__img { position: relative; aspect-ratio: 16 / 10; overflow: hidden; }
.pcase__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pcase__img .prow__status {
    position: absolute;
    left: .9rem; top: .9rem;
    padding: .35rem .7rem;
    border-radius: var(--pill);
    background: rgba(6, 12, 9, .72);
    backdrop-filter: blur(10px);
}
.pcase__body { padding: clamp(1.1rem, 2.2vw, 1.5rem); }
.pcase__body h3 { margin: 0 0 .5rem; font-size: 1.1rem; }
.pcase__body p { margin: 0; font-size: .88rem; color: var(--muted); }
.pcase__meta {
    display: flex;
    flex-wrap: wrap;
    gap: .8rem;
    align-items: center;
    margin-top: .7rem;
    font-size: .76rem;
    color: var(--faint);
}
.pcase__meta .spacer { flex: 1; }

/* ---- invoices ---- */
.ptable-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.ptable { width: 100%; border-collapse: collapse; font-size: .92rem; }
.ptable th {
    text-align: left;
    padding: .7rem 1rem;
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--faint);
    border-bottom: 1px solid var(--line);
    white-space: nowrap;
}
.ptable td { padding: 1rem; border-bottom: 1px solid var(--line-2); vertical-align: middle; }
.ptable .r { text-align: right; }
.ptable tr:hover td { background: var(--glass); }
.pinv__no {
    display: block;
    font-family: var(--ff-tall);
    font-weight: 400;
    letter-spacing: .1em;
    margin-bottom: .25rem;
}
.pill-link.is-sm { padding: .45rem .85rem; font-size: .76rem; }

/* ---- chat ---- */
.pchat {
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: var(--glass);
    overflow: hidden;
}
.pchat__log {
    display: grid;
    gap: 1rem;
    padding: clamp(1.1rem, 2.4vw, 1.8rem);
    max-height: min(58vh, 520px);
    overflow-y: auto;
}
.pchat__empty {
    margin: 0;
    padding: 2.5rem 1rem;
    text-align: center;
    color: var(--muted);
}
.pchat__empty i { display: block; font-size: 2rem; color: var(--accent); opacity: .7; margin-bottom: .8rem; }

.pmsg { max-width: min(75%, 560px); }
.pmsg.is-mine { justify-self: end; }
.pmsg__who {
    display: flex;
    gap: .5rem;
    align-items: baseline;
    margin-bottom: .35rem;
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .06em;
    color: var(--faint);
}
.pmsg.is-mine .pmsg__who { justify-content: flex-end; }
.pmsg__who time { font-weight: 400; opacity: .8; }
.pmsg__body {
    padding: .8rem 1.05rem;
    border-radius: var(--r-sm);
    border: 1px solid var(--line);
    background: var(--glass-2);
    font-size: .93rem;
    line-height: 1.55;
    overflow-wrap: anywhere;
}
.pmsg.is-mine .pmsg__body {
    background: var(--accent-soft);
    border-color: var(--accent-line);
}

.pchat__form {
    display: flex;
    gap: .7rem;
    align-items: flex-end;
    padding: clamp(.9rem, 2vw, 1.2rem);
    border-top: 1px solid var(--line);
}
.pchat__form textarea { flex: 1; resize: vertical; min-height: 48px; }

.portal-nudge {
    display: inline-flex;
    align-items: center;
    gap: .7rem;
    margin-top: 1.6rem;
    padding: .85rem 1.3rem;
    border-radius: var(--pill);
    border: 1px solid var(--accent-line);
    background: var(--accent-soft);
    color: var(--text);
    text-decoration: none;
    font-size: .88rem;
    font-weight: 600;
    transition: gap .3s var(--ease);
}
.portal-nudge:hover { gap: 1.1rem; }

@media (max-width: 860px) {
    .portal-gate__inner { grid-template-columns: 1fr; }
    .prow { grid-template-columns: 1fr; gap: .8rem; }
    .pmsg { max-width: 88%; }
}

/* The invoice table collapses to stacked rows rather than scrolling sideways. */
@media (max-width: 640px) {
    .ptable thead { display: none; }
    .ptable, .ptable tbody, .ptable tr, .ptable td { display: block; width: 100%; }
    .ptable tr {
        border: 1px solid var(--line);
        border-radius: var(--r-sm);
        margin-bottom: .7rem;
        padding: .3rem 0;
    }
    .ptable td { border: 0; padding: .5rem 1rem; text-align: left; }
    .ptable td.r { text-align: left; }
    .ptable td[data-label]:not([data-label=""])::before {
        content: attr(data-label);
        display: block;
        font-size: .66rem;
        font-weight: 700;
        letter-spacing: .12em;
        text-transform: uppercase;
        color: var(--faint);
        margin-bottom: .2rem;
    }
}

@media (prefers-reduced-motion: reduce) {
    .pbar span { animation: none; }
    .prow, .pcase, .portal__tab::after { transition: none; }
    .prow:hover, .pcase:hover { transform: none; }
}

/* ---------- 45. Chat attachments & booking ----------------- */

.pmsg__file {
    display: block;
    margin-top: .5rem;
    border-radius: var(--r-sm);
    border: 1px solid var(--line);
    background: var(--glass-2);
    overflow: hidden;
    text-decoration: none;
    color: inherit;
    transition: border-color .3s var(--ease);
}
.pmsg__file:hover { border-color: var(--accent-line); }
.pmsg__file img { width: 100%; max-height: 240px; object-fit: cover; display: block; }
.pmsg__file-row {
    display: flex;
    align-items: center;
    gap: .55rem;
    padding: .6rem .8rem;
    font-size: .82rem;
}
.pmsg__file-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pmsg__file-size { margin-left: auto; color: var(--faint); font-size: .74rem; white-space: nowrap; }

.pchat__clip {
    display: grid;
    place-items: center;
    width: 44px; height: 44px;
    flex: none;
    border-radius: var(--r-sm);
    border: 1px solid var(--line);
    background: var(--glass);
    color: var(--muted);
    cursor: pointer;
    transition: color .25s var(--ease), border-color .25s var(--ease);
}
.pchat__clip:hover { color: var(--accent); border-color: var(--accent-line); }
.pchat__picked {
    margin: 0;
    padding: .5rem clamp(.9rem, 2vw, 1.2rem) .9rem;
    font-size: .8rem;
    color: var(--muted);
}

/* ---- booking ---- */
.book {
    display: grid;
    grid-template-columns: minmax(280px, 360px) 1fr;
    gap: clamp(1.2rem, 3vw, 2.2rem);
    align-items: start;
}
.book__cal, .book__slots {
    padding: clamp(1.1rem, 2.4vw, 1.6rem);
    border-radius: var(--r);
    border: 1px solid var(--line);
    background: var(--glass);
}
.book__cal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .6rem;
    margin-bottom: 1rem;
}
.book__cal-head b { font-size: 1rem; }
.book__nav {
    width: 34px; height: 34px;
    display: grid; place-items: center;
    border-radius: 50%;
    border: 1px solid var(--line);
    color: var(--muted);
    transition: color .25s var(--ease), border-color .25s var(--ease);
}
.book__nav:hover { color: var(--accent); border-color: var(--accent-line); }

.book__dow, .book__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.book__dow span {
    text-align: center;
    font-size: .66rem;
    font-weight: 700;
    letter-spacing: .1em;
    color: var(--faint);
    padding-bottom: .4rem;
}
.book__cell {
    aspect-ratio: 1;
    display: grid;
    place-items: center;
    border-radius: var(--r-sm);
    font-size: .85rem;
    color: var(--text);
    text-decoration: none;
    border: 1px solid transparent;
    transition: background .2s var(--ease), border-color .2s var(--ease), color .2s var(--ease);
}
a.book__cell:hover { background: var(--accent-soft); border-color: var(--accent-line); }
.book__cell.is-blank { visibility: hidden; }
.book__cell.is-past { color: var(--faint); opacity: .4; }
/* A closed day is struck through rather than merely dimmed, so it reads as
   "not available" instead of "past". */
.book__cell.is-closed {
    color: var(--faint);
    background: repeating-linear-gradient(135deg,
        transparent, transparent 4px,
        rgba(255,255,255,.05) 4px, rgba(255,255,255,.05) 8px);
    cursor: not-allowed;
}
.book__cell.is-today { border-color: var(--accent-line); font-weight: 700; }
.book__cell.is-picked { background: var(--accent); color: var(--on-accent); font-weight: 700; }

.book__hours, .book__legend {
    margin: 1rem 0 0;
    font-size: .78rem;
    color: var(--muted);
    display: flex;
    align-items: center;
    gap: .5rem;
}
.book__legend { margin-top: .4rem; }
.book__dot {
    width: 12px; height: 12px;
    border-radius: 3px;
    display: inline-block;
    background: repeating-linear-gradient(135deg,
        transparent, transparent 3px, rgba(255,255,255,.16) 3px, rgba(255,255,255,.16) 6px);
    border: 1px solid var(--line);
}

.book__hint {
    margin: 0;
    padding: 2.5rem 1rem;
    text-align: center;
    color: var(--muted);
    font-size: .9rem;
}
.book__hint i { display: block; font-size: 1.8rem; color: var(--accent); opacity: .7; margin-bottom: .7rem; }

.book__closed { text-align: center; padding: 1.5rem .5rem; }
.book__closed b { display: block; margin-bottom: .6rem; }
.book__closed p { color: var(--muted); font-size: .9rem; max-width: 44ch; margin: 0 auto 1.2rem; }

.book__day { display: block; margin-bottom: .9rem; font-size: 1.05rem; }
.book__times {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(74px, 1fr));
    gap: .4rem;
    margin-bottom: 1.4rem;
}
.book__time input { position: absolute; opacity: 0; pointer-events: none; }
.book__time span {
    display: grid;
    place-items: center;
    padding: .55rem .3rem;
    border-radius: var(--r-sm);
    border: 1px solid var(--line);
    font-size: .84rem;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
    transition: background .2s var(--ease), border-color .2s var(--ease), color .2s var(--ease);
}
.book__time:hover span { border-color: var(--accent-line); }
.book__time input:checked + span { background: var(--accent); border-color: var(--accent); color: var(--on-accent); font-weight: 700; }
.book__time input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }
.book__time.is-taken span { opacity: .32; text-decoration: line-through; cursor: not-allowed; }

@media (max-width: 780px) {
    .book { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
    .book__cell, .book__time span, .pmsg__file { transition: none; }
}

/* ---------- 46. Portal application shell ------------------- */
/* The portal is its own app on its own host. It keeps the public site's
   palette and type so signing in does not feel like leaving the brand, but
   none of the marketing chrome — no aurora canvas, no nav, no big footer. */

body.is-portal-app {
    display: flex;
    flex-direction: column;
    min-height: 100svh;
    background:
        radial-gradient(60vw 50vh at 82% -8%, rgba(53,166,104,.10), transparent 60%),
        radial-gradient(45vw 45vh at 5% 105%, rgba(38,128,145,.08), transparent 58%),
        var(--bg);
}

.papp__bar {
    position: sticky;
    top: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: .85rem clamp(1rem, 3vw, 2.2rem);
    border-bottom: 1px solid var(--line);
    background: color-mix(in srgb, var(--bg) 82%, transparent);
    backdrop-filter: blur(18px) saturate(160%);
}
.papp__brand { display: flex; align-items: center; gap: .7rem; }
.papp__brand img { height: 26px; width: auto; }
.papp__tag {
    font-size: .58rem;
    font-weight: 700;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--green-lit);
    background: rgba(95,227,155,.12);
    border: 1px solid rgba(95,227,155,.24);
    border-radius: var(--pill);
    padding: .18rem .5rem;
}
.papp__tools { margin-left: auto; display: flex; align-items: center; gap: .5rem; }
.papp__out {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .6rem 1rem;
    border-radius: var(--pill);
    border: 1px solid var(--line);
    color: var(--muted);
    text-decoration: none;
    font-size: .84rem;
    font-weight: 600;
    transition: color .25s var(--ease), border-color .25s var(--ease);
}
.papp__out:hover { color: var(--text); border-color: var(--accent-line); }

.papp__flash {
    width: min(100% - 2rem, 1180px);
    margin: 1rem auto 0;
    display: grid;
    gap: .6rem;
}

.papp__main { flex: 1; }
.papp__wrap {
    width: min(100% - 2rem, 1180px);
    margin-inline: auto;
    padding-block: clamp(1.6rem, 4vw, 2.8rem);
}

.papp__foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem;
    width: min(100% - 2rem, 1180px);
    margin: 2rem auto 0;
    padding: 1.4rem 0;
    border-top: 1px solid var(--line);
    font-size: .82rem;
    color: var(--faint);
}
.papp__foot .spacer { flex: 1; }
.papp__foot a { color: var(--muted); }
.papp__foot a:hover { color: var(--accent); }

/* ---- sign-in ---- */
.papp-gate {
    display: grid;
    place-items: center;
    padding: clamp(2rem, 7vw, 5rem) 1rem;
}
.papp-gate__inner {
    width: min(100%, 1000px);
    display: grid;
    grid-template-columns: 1.05fr .95fr;
    gap: clamp(2rem, 5vw, 4rem);
    align-items: center;
}
.papp-gate__title { font-size: var(--step-3); margin: .2rem 0 1rem; }
.papp-gate__form { align-self: start; }

@media (max-width: 820px) {
    .papp-gate__inner { grid-template-columns: 1fr; }
}

/* ---------- 47. Portal auth card --------------------------- */
/* Same shape as the admin sign-in: one centred panel, logo at the top middle,
   everything stacked under it. */

.pauth {
    min-height: calc(100svh - 160px);
    display: grid;
    place-items: center;
    padding: clamp(1.5rem, 5vw, 3rem) 1rem;
}
.pauth__card {
    width: min(100%, 440px);
    padding: clamp(1.75rem, 1rem + 2.5vw, 2.6rem);
    border-radius: var(--r-lg);
    border: 1px solid var(--line);
    background: var(--glass-2);
    backdrop-filter: blur(18px);
    box-shadow: var(--lift), var(--shadow);
    text-align: center;
}
.pauth__logo { display: grid; place-items: center; margin-bottom: 1.6rem; }
.pauth__logo img { height: 34px; width: auto; }

.pauth__card h1 {
    font-family: var(--ff-display);
    font-weight: 400;
    font-size: 1.9rem;
    margin: 0 0 .4rem;
}
.pauth__sub {
    margin: 0 0 1.7rem;
    font-size: .89rem;
    color: var(--muted);
}

/* The form itself reads left-aligned even though the card is centred. */
.pauth__card form { text-align: left; }
.pauth__card .field { margin-bottom: 1rem; }

.pauth__list {
    list-style: none;
    margin: 1.6rem 0 0;
    padding: 1.3rem 0 0;
    border-top: 1px solid var(--line);
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: .7rem;
    text-align: left;
}
.pauth__list li {
    display: flex;
    align-items: center;
    gap: .55rem;
    font-size: .82rem;
    color: var(--muted);
}
.pauth__list i { color: var(--accent); font-size: .95rem; }

.pauth__foot {
    margin: 1.2rem 0 0;
    font-size: .78rem;
    color: var(--faint);
}

/* ---- theme button in the portal bar ---- */
.papp__icon {
    width: 40px; height: 40px;
    display: grid; place-items: center;
    border-radius: 50%;
    border: 1px solid var(--line);
    background: var(--glass);
    color: var(--muted);
    cursor: pointer;
    transition: color .25s var(--ease), border-color .25s var(--ease);
}
.papp__icon:hover { color: var(--accent); border-color: var(--accent-line); }

/* ---- the portal in light mode ----
   The app shell borrows the public site's tokens, which are tuned for dark.
   These are the few places that need a light-surface value instead. */
[data-theme="light"] body.is-portal-app {
    background:
        radial-gradient(60vw 50vh at 82% -8%, rgba(53,166,104,.10), transparent 60%),
        radial-gradient(45vw 45vh at 5% 105%, rgba(38,128,145,.07), transparent 58%),
        var(--bg);
}
[data-theme="light"] .papp__bar { background: color-mix(in srgb, var(--bg) 86%, transparent); }
[data-theme="light"] .pauth__card,
[data-theme="light"] .pcard,
[data-theme="light"] .prow,
[data-theme="light"] .pcase,
[data-theme="light"] .pchat,
[data-theme="light"] .book__cal,
[data-theme="light"] .book__slots { background: #fff; }
[data-theme="light"] .pmsg__body { background: var(--bg-2); }
[data-theme="light"] .pmsg.is-mine .pmsg__body { background: var(--accent-soft); }
/* The closed-day hatch is drawn in white, which vanishes on a pale surface. */
[data-theme="light"] .book__cell.is-closed {
    background: repeating-linear-gradient(135deg,
        transparent, transparent 4px,
        rgba(13,20,17,.07) 4px, rgba(13,20,17,.07) 8px);
}
[data-theme="light"] .book__dot {
    background: repeating-linear-gradient(135deg,
        transparent, transparent 3px, rgba(13,20,17,.18) 3px, rgba(13,20,17,.18) 6px);
}
