:root {
    --bg-deep: #10120F;
    --bg-panel: #181B16;
    --text-main: #EDEAE0;
    --text-muted: #9BA398;
    --river: #5C87A6;
    --forest: #5A6E4E;
    --clay: #9C5A3E;
    --hairline: rgba(237,234,224,0.14);

    /* One family throughout, Montserrat, matching jonahserfass.com. The roles
       are kept apart by weight, case and tracking instead of by typeface:
       titles light and widely spaced, headings regular in spaced capitals,
       labels medium in small spaced capitals, body regular. */
    --font-display: 'Montserrat', sans-serif;
    --font-label: 'Montserrat', sans-serif;
    --font-body: 'Montserrat', sans-serif;
}

* { margin:0; padding:0; box-sizing:border-box; }

/* Small spaced capitals (nav, crumbs, tags, labels) read thin at light weight. */
.site-nav-links a, .nav-mobile-menu a, .hero-nav, .work-card-label, .capability-tag,
.contact-label, .site-footer, .crumb, .section-link, .field label { font-weight:500; }

html, body {
    width:100%;
    font-family: var(--font-body);
    background-color: var(--bg-deep);
    color: var(--text-main);
    overflow-x:hidden;
    scroll-behavior:smooth;
}

a { color:inherit; }

a:focus-visible, button:focus-visible {
    outline: 2px solid var(--river);
    outline-offset: 3px;
    border-radius: 2px;
}

/* ---------------------------------
   SPRITE ICONS
--------------------------------- */
.icon-sprite { position:absolute; width:0; height:0; overflow:hidden; }
.work-card-icon { width:28px; height:28px; color: var(--text-muted); }

/* ---------------------------------
   SECTION BASE
--------------------------------- */
.section {
    position:relative;
    min-height:100vh;
    display:flex;
    align-items:center;
    justify-content:center;
    padding:120px 5% 100px;
    overflow:hidden;
}

.section-bg {
    position:absolute; inset:0; z-index:0;
    background-size:cover;
    background-position:center;
    /* A straight vertical fade at both ends, so adjacent sections meet in
       darkness rather than at a hard edge. */
    -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 15%, #000 62%, transparent 97%);
    mask-image: linear-gradient(to bottom, transparent 0%, #000 15%, #000 62%, transparent 97%);
}
.section-bg::after {
    content:'';
    position:absolute; inset:0;
    background: linear-gradient(to bottom, rgba(16,18,15,0.72), rgba(16,18,15,0.95));
}
/* Same background treatment everywhere a .section-bg appears (homepage
   sections and service-page headers alike), so a page opens on the image
   its homepage section used. */
.section-bg {
    filter: blur(5px);
    transform: scale(1.08);
}
#hero .section-bg { filter:none; transform:none; }

.content-container { position:relative; z-index:2; max-width:1200px; width:100%; }

/* ---------------------------------
   REVEAL ON SCROLL
--------------------------------- */
/* Content is visible by default. main.js adds .js-reveal to <html> only when it
   is actually going to animate, so the hidden state never exists unless script
   is there to undo it. If JS fails the page reads normally instead of blank.
   The entrance is now short and small, and only the service cards use it. */
/* An animation, not a transition, and deliberately so: .svc-card sets its own
   `transition` shorthand later in this file at equal specificity, which wiped
   the reveal's transition entirely. The cards snapped in with no fade and the
   stagger did nothing. An animation cannot be clobbered that way, and touching
   only opacity leaves the hover transform free to keep its own timing. */
.js-reveal .reveal { opacity: 0; }
.js-reveal .reveal.active {
    animation: revealIn .5s ease var(--reveal-delay, 0ms) forwards;
}
@keyframes revealIn { to { opacity: 1; } }

/* ---------------------------------
   TYPOGRAPHY
--------------------------------- */
.section-title {
    font-family: var(--font-display);
    font-weight:400;
    font-size:clamp(1.45rem, 2.6vw, 2rem);
    text-transform:uppercase;
    letter-spacing:.14em;
    line-height:1.3;
    color: var(--text-main);
    margin-bottom:20px;
}


.section-desc { font-size:1.1rem; line-height:1.8; color: var(--text-muted); max-width:640px; margin:0 auto; }

.section-header { margin-bottom:50px; text-align:center; }

/* ---------------------------------
   STICKY NAV
--------------------------------- */
.site-nav {
    position:fixed; top:0; left:0; width:100%;
    /* Opaque rather than frosted. At 0.95 the bar reads as chrome instead of
       an effect, and it does not depend on backdrop-filter support. */
    background: rgba(16,18,15,0.95);
    border-bottom:1px solid var(--hairline);
    transform: translateY(-100%);
    transition: transform .4s cubic-bezier(0.16,1,0.3,1);
    z-index:100;
}
.site-nav.visible { transform: translateY(0); }
.site-nav-inner {
    max-width:1200px; margin:0 auto; padding:14px 5%;
    display:flex; align-items:center; justify-content:space-between;
}
.site-nav-logo { font-family: var(--font-display); font-size:1rem; text-decoration:none; color: var(--text-main); font-weight:500; letter-spacing:.02em; }
.site-nav-links { display:flex; align-items:center; gap:26px; }
.site-nav-links a {
    font-family: var(--font-label); font-size:.72rem; letter-spacing:.06em;
    text-transform:uppercase; color: var(--text-muted); text-decoration:none;
    transition: color .3s ease;
}
.site-nav-links a:hover { color: var(--text-main); }
.site-nav-links .site-nav-cta {
    color: var(--bg-deep);
    background: var(--river);
    padding:8px 16px;
    border-radius:3px;
}
.site-nav-links .site-nav-cta:hover { color: var(--bg-deep); background: var(--text-main); }

.nav-toggle {
    display:none;
    background:none; border:none; padding:4px; margin:0; cursor:pointer;
    color: var(--text-main); line-height:0;
}
.nav-toggle-icon { width:22px; height:22px; }

.nav-mobile-menu {
    display:none;
    flex-direction:column;
    background: rgba(16,18,15,0.97);
    border-top:1px solid var(--hairline);
    padding:6px 5% 14px;
}
.nav-mobile-menu.open { display:flex; }
.nav-mobile-menu a {
    font-family: var(--font-label); font-size:.8rem; letter-spacing:.06em;
    text-transform:uppercase; color: var(--text-muted); text-decoration:none;
    padding:15px 0;
    border-bottom:1px solid var(--hairline);
}
.nav-mobile-menu a:last-child { border-bottom:none; }
.nav-mobile-menu a:hover { color: var(--text-main); }

/* ---------------------------------
   HERO
--------------------------------- */
#hero { padding:0; }

.hero-video {
    position:absolute; top:50%; left:50%;
    min-width:100%; min-height:100%;
    width:auto; height:auto;
    transform:translate(-50%,-50%);
    z-index:1;
    object-fit:cover;
}
.about-topo { position:absolute; inset:0; z-index:1; width:100%; height:100%; opacity:0.5; pointer-events:none; }
.topo-svg { width:100%; height:100%; }
.contour { fill:none; stroke-width:1.4; }
.contour:nth-child(odd) { stroke: var(--forest); opacity:0.35; }
.contour:nth-child(even) { stroke: var(--river); opacity:0.22; }

.hero-overlay {
    position:absolute; inset:0; z-index:2;
    /* The centre vignette added for the brighter "option 2" clip is gone with
       it. This footage is dark enough without it. The cream tagline stays:
       --text-muted measured 3.01:1 here, so it was under the floor on this
       clip too, not only on the bright one. */
    /* The last 14% runs to solid page colour, so whatever follows the hero
       meets it in darkness instead of at the clip's edge. Above 86% the ramp
       is exactly the old 0.35 to 0.92 line. */
    background: linear-gradient(to bottom,
        rgba(16,18,15,0.35) 0%,
        rgba(16,18,15,0.84) 86%,
        rgba(16,18,15,1) 100%);
    opacity:0;
    animation: overlayFadeIn 2s ease-in-out 0.6s forwards;
}

.hero-content {
    position:relative; z-index:3; text-align:center; padding:0 5%;
    opacity:0;
    animation: contentFadeIn 2s ease-in-out 0.6s forwards;
}

.hero-title {
    font-family: var(--font-display);
    font-weight:300;
    font-size:clamp(2.2rem, 6.4vw, 4.6rem);
    letter-spacing:.12em;
    margin-bottom:18px;
    text-shadow: 0 4px 20px rgba(0,0,0,0.5); text-transform:uppercase; line-height:1.12; }

.hero-tagline {
    font-family: var(--font-display);
    font-weight:300;
    letter-spacing:0.03em;
    font-size: clamp(1.05rem, 2vw, 1.3rem);
    color: rgba(237,234,224,0.88);
    margin-bottom:38px;
}

.hero-nav { display:flex; justify-content:center; align-items:center; gap:26px; font-family: var(--font-label); font-size:.95rem; letter-spacing:.14em; text-transform:uppercase; }
.hero-nav a { color: var(--text-main); text-decoration:none; transition: all .4s cubic-bezier(0.25,1,0.5,1); display:inline-block; }
.hero-nav a:hover { transform: scale(1.1); color: var(--river); text-shadow: 0 0 10px rgba(92,135,166,0.5); }
.hero-nav .divider { color: var(--forest); user-select:none; }

@keyframes overlayFadeIn { from{opacity:0;} to{opacity:1;} }
@keyframes contentFadeIn { from{opacity:0; transform:translateY(20px) scale(0.95);} to{opacity:1; transform:translateY(0) scale(1);} }

/* ---------------------------------
   SCROLL CUE
--------------------------------- */
.scroll-cue {
    position:absolute; bottom:28px; left:50%; transform:translateX(-50%);
    z-index:5;
    display:flex; align-items:center; justify-content:center;
    width:40px; height:40px;
    border-radius:50%;
    border:1px solid var(--hairline);
    color: var(--text-muted);
    transition: color .3s ease, border-color .3s ease;
    animation: scrollCueBounce 2.2s ease-in-out infinite;
}
.scroll-cue:hover { color: var(--text-main); border-color: var(--river); }
.scroll-cue-icon { width:18px; height:18px; }
@keyframes scrollCueBounce {
    0%, 100% { transform: translateX(-50%) translateY(0); }
    50% { transform: translateX(-50%) translateY(6px); }
}

/* ---------------------------------
   WORK GRID / PLACEHOLDER CARDS
--------------------------------- */
.work-grid {
    display:grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap:24px;
    align-items:start;
}

.work-card {
    position:relative;
    border:1px dashed var(--hairline);
    background: var(--bg-panel);
    border-radius:4px;
    display:flex;
    flex-direction:column;
    align-items:center;
    justify-content:center;
    gap:12px;
    padding:24px;
    aspect-ratio:16/9;
    text-align:center;
    transition: border-color .3s ease;
    cursor: crosshair;
}
.work-card:hover { border-color: var(--river); }
.work-card.work-card--portrait { aspect-ratio:9/16; }
.work-card.work-card--photo { aspect-ratio:4/3; }
.work-card.work-card--wide { grid-column: span 2; }

.work-card-label {
    font-family: var(--font-label);
    font-size:.7rem;
    letter-spacing:.08em;
    text-transform:uppercase;
    color: var(--text-main);
}
.work-card-hint { font-size:.78rem; color: var(--text-muted); }

.work-card::before, .work-card::after {
    content:''; position:absolute; width:14px; height:14px;
    border-color: var(--river); border-style:solid; border-width:0;
    opacity:0; transition:opacity .3s ease;
}
.work-card::before { top:8px; left:8px; border-top-width:2px; border-left-width:2px; }
.work-card::after { bottom:8px; right:8px; border-bottom-width:2px; border-right-width:2px; }
.work-card:hover::before, .work-card:hover::after { opacity:1; }

/* A dashed edge means "empty slot". Once a card holds real media it gets a
   solid one, visible only where the media is letterboxed rather than
   covering, but wrong to leave dashed either way. */
.work-card--media { padding:0; overflow:hidden; border-style: solid; }
.work-card--media video, .work-card--media img { width:100%; height:100%; object-fit:cover; display:block; }

.capability-row { display:flex; flex-wrap:wrap; justify-content:center; gap:10px; margin-top:22px; }
.capability-tag {
    font-family: var(--font-label); font-size:.68rem; letter-spacing:.05em; text-transform:uppercase;
    color: var(--text-muted); border:1px solid var(--hairline); border-radius:20px; padding:6px 14px;
}

/* ---------------------------------
   REAL ESTATE SHOWCASE
--------------------------------- */
.showcase-grid {
    display:grid;
    grid-template-columns: 1fr 1fr 1fr;
    grid-template-rows: repeat(3, 1fr);
    gap:16px;
    aspect-ratio: 7/4;
}
.showcase-video { grid-column:1; grid-row:1 / span 3; aspect-ratio:auto; }
.showcase-photo-1 { grid-column:2; grid-row:1; aspect-ratio:auto; }
.showcase-photo-2 { grid-column:2; grid-row:2; aspect-ratio:auto; }
.showcase-photo-3 { grid-column:2; grid-row:3; aspect-ratio:auto; }
.showcase-video-2 { grid-column:3; grid-row:1 / span 3; aspect-ratio:auto; }

/* ---------------------------------
   ABOUT / CONTACT
--------------------------------- */
.footer-grid { display:grid; grid-template-columns:1fr 1fr; gap:50px; }

.contact-box {
    /* hug its content: the grid's default stretch matched the bio column's
       height and left the panel half empty once the bio grew */
    align-self:start;
    background: var(--bg-panel);
    padding:40px;
    border-radius:8px;
    /* A quiet hairline on all four edges. The accent strip that used to sit on
       the top edge is the single most-cited giveaway of generated design. */
    border:1px solid var(--hairline);
}

.contact-label {
    font-family: var(--font-label);
    font-size:.68rem;
    letter-spacing:.08em;
    text-transform:uppercase;
    color: var(--text-muted);
    display:block;
    margin-bottom:2px;
}
.contact-line { margin-bottom:16px; font-size:1.05rem; }
.contact-line a { text-decoration:none; border-bottom:1px solid var(--hairline); transition: color .3s, border-color .3s; }
.contact-line a:hover { color: var(--river); border-color: var(--river); }

.btn-primary {
    display:inline-block;
    padding:15px 30px;
    background: var(--text-main);
    color: var(--bg-deep);
    text-decoration:none;
    font-weight:600;
    font-family: var(--font-display);
    letter-spacing:.14em;
    border-radius:4px;
    transition: background .3s; font-size:.8rem; text-transform:uppercase; }
.btn-primary:hover { background: var(--river); color: var(--text-main); }

.site-footer {
    text-align:center; padding:24px 5% 40px;
    font-family: var(--font-label); font-size:.7rem; letter-spacing:.05em;
    color: var(--text-muted); background: var(--bg-deep);
}

.grain-overlay {
    position:fixed; inset:0; z-index:9999; pointer-events:none;
    opacity:0.035; mix-blend-mode:overlay;
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    background-size:120px 120px;
}

/* ---------------------------------
   REDUCED MOTION
--------------------------------- */
@media (prefers-reduced-motion: reduce) {
    .reveal, .js-reveal .reveal { transition:none; animation:none; opacity:1; transform:none; }
    .hero-overlay, .hero-content { animation:none; opacity:1; transform:none; }
    .scroll-cue { animation:none; }
    .site-nav { transition:none; }
    .svc-card, .svc-card img { transition:none; }
    .svc-card:hover { transform:none; }
    html, body { scroll-behavior:auto; }
}

/* ---------------------------------
   RESPONSIVE
--------------------------------- */
@media (max-width:768px) {
    .hero-nav { flex-direction:column; gap:15px; }
    .hero-nav .divider { display:none; }
    .footer-grid { grid-template-columns:1fr; }
    .section { padding:100px 6% 80px; }
    .showcase-grid { grid-template-columns:1fr; grid-template-rows:none; aspect-ratio:auto; }
    .showcase-video { grid-column:1; grid-row:auto; aspect-ratio:9/16; }
    .showcase-photo-1, .showcase-photo-2, .showcase-photo-3 { grid-column:1; grid-row:auto; aspect-ratio:4/3; }
    .showcase-video-2 { grid-column:1; grid-row:auto; aspect-ratio:9/16; }
    .work-grid { grid-template-columns:1fr; }
    .work-card.work-card--wide { grid-column:span 1; }
}
@media (max-width:640px) {
    .site-nav-links a:not(.site-nav-cta) { display:none; }
    .nav-toggle { display:block; }
}
/* Montserrat is wide enough that logo, button and menu icon touched at 390px
   and below. Take the room out of the spacing first, then a little type. */
@media (max-width:480px) {
    .site-nav-links { gap:14px; }
    .site-nav-links .site-nav-cta { padding:7px 12px; }
    .site-nav-logo { font-size:.95rem; }
}
@media (max-width:380px) {
    .site-nav-links .site-nav-cta { font-size:.66rem; letter-spacing:.04em; padding:7px 10px; }
    .site-nav-logo { font-size:.88rem; }
}

/* ---------------------------------
   SUBPAGE HEADER
   Shorter than the homepage hero; service pages open on
   a statement, not a full-viewport video.
--------------------------------- */
.page-header {
    position:relative;
    min-height:58vh;
    display:flex;
    align-items:flex-end;
    padding:150px 5% 64px;
    overflow:hidden;
}
.page-header-inner { position:relative; z-index:2; max-width:1200px; margin:0 auto; width:100%; text-align:center; }
.crumb {
    font-family: var(--font-label);
    font-size:.72rem; letter-spacing:.14em; text-transform:uppercase;
    color: var(--text-muted); margin-bottom:16px;
}
.crumb a { color: var(--text-muted); text-decoration:none; }
.crumb a:hover { color: var(--river); }
.crumb span { opacity:.5; margin:0 8px; }
.page-title {
    font-family: var(--font-display); font-weight:300;
    font-size:clamp(2rem, 5.6vw, 3.8rem); line-height:1.15;
    color: var(--text-main); margin-bottom:18px; letter-spacing:.12em; text-transform:uppercase; }
.page-lede { font-size:1.15rem; line-height:1.75; color: var(--text-muted); max-width:62ch; margin:0 auto; }

/* Sections on a subpage flow at their natural height */
.section--flow { min-height:auto; padding:88px 5%; }


/* ---------------------------------
   HOMEPAGE SERVICE ROUTING
--------------------------------- */
.section-link {
    display:inline-flex; align-items:center; gap:9px; margin-top:34px;
    font-family: var(--font-label); font-size:.76rem; letter-spacing:.12em; text-transform:uppercase;
    color: var(--text-main); text-decoration:none;
    border-bottom:1px solid var(--river); padding-bottom:6px;
    transition: gap .25s ease, color .25s ease;
}
.section-link:hover { gap:15px; color: var(--river); }
.section-link svg { width:15px; height:15px; }

/* ---------------------------------
   CLOSING CTA BAND
--------------------------------- */
.cta-band { padding:96px 5%; text-align:center; border-top:1px solid var(--hairline); }
.cta-band-inner { max-width:640px; margin:0 auto; }
.cta-band h2 {
    font-family: var(--font-display); font-weight:400; font-size:clamp(1.45rem, 2.6vw, 2rem);
    color: var(--text-main); margin-bottom:16px; letter-spacing:.14em; text-transform:uppercase; line-height:1.3; }
.cta-band p { font-size:1.05rem; line-height:1.75; color: var(--text-muted); margin-bottom:30px; }

/* Vertical listing videos: capped so a 9:16 clip doesn't tower over the page. */
.work-grid--verticals {
    grid-template-columns: repeat(auto-fit, minmax(200px, 280px));
    justify-content: center;
}

/* One item in an auto-fit grid stretches to the full row, which turns a
   16:9 video into a slab. Cap and centre it instead. */
.work-grid--single {
    grid-template-columns: minmax(0, 760px);
    justify-content: center;
}

/* A work slot that is genuinely empty stays visibly empty. */
.work-card--pending { cursor:default; }
.work-card--pending:hover { border-color: var(--hairline); }

@media (max-width:900px) {
    .page-header { min-height:auto; padding:128px 5% 52px; }
    }

/* Current page in the nav */
.site-nav-links a.active,
.nav-mobile-menu a.active { color: var(--river); }


/* ---------------------------------
   CONTACT FORM
   Posts to Netlify Forms, with no backend. See PROJECT_NOTES.
--------------------------------- */
.form-layout {
    display:grid;
    grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
    gap:56px;
    align-items:start;
}
.form-grid { display:grid; grid-template-columns:1fr 1fr; gap:22px; }
.field { display:flex; flex-direction:column; gap:8px; }
.field--full { grid-column:1 / -1; }

.field label {
    font-family: var(--font-label);
    font-size:.7rem; letter-spacing:.1em; text-transform:uppercase;
    color: var(--text-muted);
}
.field .req { color: var(--river); margin-left:3px; }

.field input,
.field select,
.field textarea {
    font-family: var(--font-body);
    font-size:1rem;
    color: var(--text-main);
    background: var(--bg-panel);
    border:1px solid var(--hairline);
    border-radius:4px;
    padding:13px 14px;
    width:100%;
    transition: border-color .2s ease, background .2s ease;
    -webkit-appearance:none; appearance:none;
}
.field textarea { min-height:150px; resize:vertical; line-height:1.6; }

.field select {
    background-image:
      linear-gradient(45deg, transparent 50%, var(--text-muted) 50%),
      linear-gradient(135deg, var(--text-muted) 50%, transparent 50%);
    background-position: calc(100% - 19px) 50%, calc(100% - 14px) 50%;
    background-size: 5px 5px, 5px 5px;
    background-repeat:no-repeat;
    padding-right:40px;
    cursor:pointer;
}
.field select option { background: var(--bg-panel); color: var(--text-main); }

.field input:hover, .field select:hover, .field textarea:hover { border-color: rgba(237,234,224,0.28); }
.field input:focus, .field select:focus, .field textarea:focus {
    outline:none;
    border-color: var(--river);
    box-shadow: 0 0 0 3px rgba(92,135,166,0.18);
}
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible {
    outline:2px solid var(--river); outline-offset:2px;
}
.field input::placeholder, .field textarea::placeholder { color: rgba(155,163,152,0.6); }

/* Honeypot: visible only to bots. */
.form-hp { position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden; }

.form-actions { display:flex; align-items:center; justify-content:center; text-align:center; gap:22px; flex-wrap:wrap; margin-top:30px; }
.form-note { font-size:.85rem; color: var(--text-muted); margin:0; flex:1 1 240px; }

.form-submit {  border:none; cursor:pointer;  }

/* Direct-contact column beside the form */
.contact-aside { border-left:1px solid var(--hairline); padding-left:34px; text-align:center; }
.contact-aside h3 {
    font-family: var(--font-display); font-weight:500; font-size:1.05rem;
    color: var(--text-main); margin-bottom:12px; letter-spacing:.12em; text-transform:uppercase; }
.contact-aside p { font-size:.95rem; line-height:1.75; color: var(--text-muted); margin-bottom:26px; }
.contact-aside .contact-line { margin-bottom:14px; }

@media (max-width:900px) {
    .form-layout { grid-template-columns:1fr; gap:44px; }
    .contact-aside { border-left:none; border-top:1px solid var(--hairline); padding-left:0; padding-top:32px; }
}
@media (max-width:640px) {
    .form-grid { grid-template-columns:1fr; }
}

/* ---------------------------------
   CENTRE ALIGNMENT
   The site reads as one centred column throughout. Form field labels stay
   left-aligned inside their centred block, because centred labels above inputs
   are genuinely hard to scan.
--------------------------------- */
.footer-grid, .footer-grid > div { text-align:center; }
.contact-line { justify-content:center; }
.section--flow .section-header { text-align:center; }
.section--flow .section-desc { margin-left:auto; margin-right:auto; }
.crumb { text-align:center; }
.form-note { text-align:center; }
.field { text-align:left; }

/* ---------------------------------
   PANORAMA BAND
   Sits between sections as a direct child of <body>, so it is full width
   without negative margins or 100vw (which overflows by the scrollbar).
   The image keeps its own aspect ratio, and these are ~2.6:1 and cropping
   them would defeat the point of shooting a panorama.
--------------------------------- */
@media (max-width:640px) {
    /* a 2.6:1 strip is only ~150px tall on a phone; crop in a little so it reads */
    }

/* A work grid that centres a partial final row: five photos should read
   3 + 2 centred, not 4 + 1 orphaned against the left edge. */
.work-grid--center { display:flex; flex-wrap:wrap; justify-content:center; gap:24px; }
.work-grid--center > * { flex:0 1 calc(33.333% - 16px); min-width:240px; }
@media (max-width:820px) { .work-grid--center > * { flex:0 1 calc(50% - 12px); } }
@media (max-width:520px) { .work-grid--center > * { flex:1 1 100%; } }

/* ---------------------------------
   PANORAMA PAGE HEADERS
   Each service page opens on one of the aerial panoramas, shown sharp.
   These are the strongest photographs on the site and the blur that suits
   a background would waste them. A ~2.4:1 header against a ~2.6:1 image
   means almost no crop. The scrim is bottom-weighted so the sky stays
   open and the title lands on darkness rather than on cloud.
--------------------------------- */
.page-header { min-height:64vh; }

.page-header .section-bg {
    filter:none;
    transform:none;
    /* solid under the nav, fading out only at the foot of the header */
    -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 60%, transparent 96%);
    mask-image: linear-gradient(to bottom, #000 0%, #000 60%, transparent 96%);
}
.page-header .section-bg::after {
    background: linear-gradient(to bottom,
        rgba(16,18,15,0.68) 0%,
        rgba(16,18,15,0.34) 22%,
        rgba(16,18,15,0.66) 50%,
        rgba(16,18,15,0.91) 76%,
        rgba(16,18,15,0.98) 100%);
}

/* Cream type on a bright sky needs a real halo, not a soft drop shadow. The
   crumb sits highest in the header where the scrim is thinnest, so it takes the
   full ink colour rather than a faded one, measured rather than guessed; the earlier
   faded crumb sat at 1.97:1. See PROJECT_NOTES. */
.page-header .page-title { text-shadow: 0 2px 24px rgba(16,18,15,0.9), 0 1px 4px rgba(16,18,15,0.7); }
.page-header .page-lede  { color: var(--text-main); opacity:.92;
    text-shadow: 0 1px 14px rgba(16,18,15,0.9); }
.page-header .crumb, .page-header .crumb a { color: var(--text-main);
    text-shadow: 0 0 6px rgba(16,18,15,0.95), 0 0 15px rgba(16,18,15,0.9), 0 1px 3px rgba(16,18,15,0.95); }
.page-header .crumb a:hover { color: var(--river); }

@media (max-width:900px) {
    /* the header is content-height here, so a 2.6:1 image crops to a centre
       slice, so give it a floor so it still reads as a landscape */
    .page-header { min-height:52vh; }
    /* Here the header is short, so crumb and title land in the upper band that
       the desktop scrim leaves light to keep the sky open. Measured on phones
       before this, the crumb fell to 2.6:1 on Land & Mapping and below 4.5:1
       on all three service pages; desktop, where the type sits lower in a
       taller header, was always clear. So the upper band darkens only here. */
    .page-header .section-bg::after {
        background: linear-gradient(to bottom,
            rgba(16,18,15,0.72) 0%,
            rgba(16,18,15,0.66) 22%,
            rgba(16,18,15,0.80) 50%,
            rgba(16,18,15,0.92) 76%,
            rgba(16,18,15,0.98) 100%);
    }
}

/* ---------------------------------
   HOMEPAGE FLOW
   The homepage no longer stacks three full-viewport service sections. It
   opens on the hero, states who this is in one short block, then hands off
   to the three service pages as thumbnails. Sections below the hero size to
   their content instead of 100vh, so scrolling covers ground quickly.
--------------------------------- */
.section--short { min-height:auto; padding:104px 5% 96px; }
.section--flat  { background: var(--bg-deep); }

/* Short "who we are" block: a hook, not the whole story. The full bio
   lives further down in #about, which this links to. */
.intro-inner { max-width:760px; margin:0 auto; text-align:center; position:relative; z-index:2; }
.intro-body { font-size:1.05rem; line-height:1.8; color: var(--text-muted); margin-bottom:30px; }

/* ---------------------------------
   SERVICE THUMBNAILS
   Three cards; each one is the whole link. The image (or its hover clip)
   fills the card and the title sits on top of it, with no description block and
   no separate call-to-action, because the card itself is the call to action.
--------------------------------- */
.svc-grid {
    display:grid;
    grid-template-columns: repeat(3, 1fr);
    gap:26px;
    max-width:1200px;
    margin:0 auto;
}

.svc-card {
    position:relative;
    display:block;
    aspect-ratio:4/3;
    overflow:hidden;
    border-radius:6px;
    border:1px solid var(--hairline);
    background: var(--bg-panel);
    text-decoration:none;
    color:inherit;
    transition: border-color .35s ease, transform .35s cubic-bezier(0.16,1,0.3,1), box-shadow .35s ease;
}

.svc-card img,
.svc-card video {
    position:absolute; inset:0;
    width:100%; height:100%;
    object-fit:cover;
    display:block;
}
/* The clip sits above the poster and fades in only once it is genuinely
   playing, so a card never flashes an empty box while the video buffers. */
.svc-card video { opacity:0; transition: opacity .45s ease; }
.svc-card.is-playing video { opacity:1; }
.svc-card img { transition: transform .6s cubic-bezier(0.16,1,0.3,1); }

/* The title sits on photography, so it carries its own ground rather than
   depending on whatever happens to be in frame at that moment. */
.svc-card::after {
    content:'';
    position:absolute; inset:0; z-index:2;
    background:
        radial-gradient(ellipse 82% 66% at 50% 50%,
            rgba(16,18,15,0.82) 0%, rgba(16,18,15,0.58) 58%, rgba(16,18,15,0.26) 100%),
        linear-gradient(to top, rgba(16,18,15,0.44) 0%, rgba(16,18,15,0.12) 60%);
}

.svc-card-title {
    position:absolute; inset:0; z-index:3;
    display:flex; align-items:center; justify-content:center;
    margin:0; padding:0 16px;
    text-align:center;
    font-family: var(--font-display);
    font-weight:500;
    font-size:clamp(1.15rem, 1.9vw, 1.55rem);
    line-height:1.35;
    letter-spacing:.12em;
    color: var(--text-main);
    text-shadow: 0 2px 16px rgba(16,18,15,0.9), 0 1px 4px rgba(16,18,15,0.7); text-transform:uppercase; }

/* Hover only where hovering exists. On touch these latch on tap. */
@media (hover: hover) {
    .svc-card:hover {
        border-color: var(--river);
        transform: translateY(-6px);
        box-shadow: 0 18px 40px rgba(0,0,0,0.45);
    }
    .svc-card:hover img { transform: scale(1.06); }
}
.svc-card:focus-visible {
    outline:2px solid var(--river); outline-offset:3px;
    border-color: var(--river);
}

@media (max-width:900px) { .svc-grid { grid-template-columns:1fr 1fr; gap:20px; } }
@media (max-width:620px) { .svc-grid { grid-template-columns:1fr; } }

/* ---------------------------------
   ONE-WAY REVEAL
   Content unveils on the way down and stays put on the way back up. The
   observer unobserves after firing (see main.js). The stagger is a custom
   property set per item so a grid resolves in sequence rather than at once.
--------------------------------- */


/* ---------------------------------
   PAGE TRANSITIONS
   Cross-document view transitions: the browser cross-fades between pages
   instead of flashing white on every navigation. Where it is unsupported the
   at-rule is simply ignored and navigation behaves exactly as before, so
   there is nothing to feature-detect and no fallback to maintain.

   The outgoing page leaves faster than the incoming one arrives, which reads
   as the new page rising rather than the two pages trading places.
--------------------------------- */
@view-transition { navigation: auto; }

::view-transition-old(root) { animation: pageFadeOut 150ms cubic-bezier(0.4,0,1,1) both; }
::view-transition-new(root) { animation: pageFadeIn  320ms cubic-bezier(0.16,1,0.3,1) both; }

@keyframes pageFadeOut { to   { opacity:0; } }
@keyframes pageFadeIn  { from { opacity:0; transform: translateY(8px); } }

@media (prefers-reduced-motion: reduce) {
    ::view-transition-old(root), ::view-transition-new(root) { animation:none; }
}

/* ---------------------------------
   ZOOMABLE IMAGE CARDS + LIGHTBOX
   Photo cards are real <button>s rather than divs with a click handler, so
   they are keyboard-reachable and announce themselves; that means resetting
   the browser's own button styling.
--------------------------------- */
button.work-card {
    font: inherit;
    color: inherit;
    cursor: zoom-in;
    -webkit-appearance: none; appearance: none;
}

/* <dialog> supplies the focus trap, the Escape key and the backdrop, so the
   only work here is layout. It fills the viewport, which means the backdrop
   is never actually clickable. Closing on "clicked anything but the image"
   is handled in main.js instead. */
.lightbox {
    /* The UA stylesheet centres a dialog with margin:auto inside a shrink-to-fit
       box, which left it narrower than the viewport on a phone. Pin it. */
    position: fixed;
    inset: 0;
    margin: 0;
    width: 100vw;  max-width: 100vw;
    height: 100vh; max-height: 100vh;
    padding: 0;
    border: none;
    background: transparent;
    overflow: hidden;
}
.lightbox::backdrop { background: rgba(10,11,9,0.94); }

.lightbox-inner {
    width: 100%; height: 100%;
    display: flex; align-items: center; justify-content: center;
    padding: 56px 24px;
    cursor: zoom-out;
}
.lightbox img {
    max-width: min(1500px, 94vw);
    max-height: 84vh;
    width: auto; height: auto;
    object-fit: contain;
    border-radius: 3px;
    box-shadow: 0 30px 90px rgba(0,0,0,0.65);
    cursor: default;
}

.lightbox-close {
    position: fixed; top: 20px; right: 20px;
    width: 46px; height: 46px;
    display: flex; align-items: center; justify-content: center;
    background: rgba(16,18,15,0.72);
    border: 1px solid var(--hairline);
    border-radius: 50%;
    color: var(--text-main);
    cursor: pointer;
    transition: border-color .25s ease, background .25s ease;
}
.lightbox-close:hover { border-color: var(--river); background: rgba(16,18,15,0.9); }
.lightbox-close:focus-visible { outline: 2px solid var(--river); outline-offset: 3px; }
.lightbox-close svg { width: 20px; height: 20px; }

@media (max-width: 640px) {
    .lightbox-inner { padding: 64px 12px; }
    .lightbox img { max-height: 78vh; }
}

/* ---------------------------------
   VERTICAL RHYTHM ON SMALL SCREENS
   Section padding was a single desktop-scale value, so stacked sections
   added their padding together: 88 + 88 between two blocks, 88 + 96 before
   the closing band. At desktop widths that reads as deliberate spacing; on
   a phone, where the background has already faded to black, it reads as the
   page having ended. Declared last so it beats the earlier breakpoints that
   set these same properties.
--------------------------------- */
@media (max-width:768px) {
    .page-header    { padding:108px 5% 40px; }
    .section--flow  { padding:56px 5%; }
    .section--short { padding:64px 5% 56px; }
    .cta-band       { padding:60px 5%; }
    .section-header { margin-bottom:32px; }
}

/* A section that carries straight on from the page header with no heading of
   its own (the capability tags on Business & Brand Video). Section padding is
   there to separate one titled block from the next; with no title to
   introduce, it read as the page having ended. The header's own bottom padding
   is the only gap it needs. Two classes so it outranks the small-screen
   .section--flow rule declared above. */
.section--flow.section--continues { padding-top:0; }

/* ---------------------------------
   VIMEO REEL
   The reel is the same Vimeo player as jonahserfass.com rather than a native
   <video> streaming one 55 MB file from R2: Vimeo serves adaptive quality, so
   a phone on a weak signal gets a stream it can actually play. Framed the way
   that site frames it. Lazy, so the player script only loads near view.
--------------------------------- */
.reel-frame {
    position:relative;
    width:100%;
    aspect-ratio:16/9;
    border-radius:8px;
    overflow:hidden;
    background: var(--bg-panel);
    box-shadow: 0 10px 30px rgba(0,0,0,0.3);
}
.reel-frame iframe { position:absolute; inset:0; width:100%; height:100%; border:0; }
