/* ==========================================================================
   waterhouse — mikewaterhouse.com
   Type: Aldrich (wordmark) · Montserrat 500 (headings) · Jost (body)
   All faces self-hosted; no third-party font request.
   ========================================================================== */

@font-face{font-family:"Aldrich";src:url("../fonts/aldrich400.woff2") format("woff2");
           font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"Montserrat";src:url("../fonts/montserrat500.woff2") format("woff2");
           font-weight:500;font-style:normal;font-display:swap}
@font-face{font-family:"Jost";src:url("../fonts/jost400.woff2") format("woff2");
           font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"Jost";src:url("../fonts/jost500.woff2") format("woff2");
           font-weight:500;font-style:normal;font-display:swap}

/* --------------------------------------------------------------- tokens -- */
:root{
  --ground:#ffffff;
  --ink:#1c1c1e;
  --muted:#5f6470;      /* 5.9:1 on white. Replaces the old #999 at 2.85:1 (failed WCAG AA). */
  --faint:#8b909b;
  --rule:#e5e6ea;
  --shade:#f7f7f9;
  --focus:#1c1c1e;
  --ring:rgba(28,28,30,.30);

  --measure:38rem;      /* running text */
  --wide:60rem;         /* images that break the text column */
  --shell:1180px;       /* page shell */
}
@media (prefers-color-scheme:dark){
  :root{
    --ground:#0f1013; --ink:#e8e9ec; --muted:#a2a8b4; --faint:#787e8a;
    --rule:#26282f; --shade:#16181d; --focus:#e8e9ec; --ring:rgba(232,233,236,.34);
  }
}
:root[data-theme="dark"]{
  --ground:#0f1013; --ink:#e8e9ec; --muted:#a2a8b4; --faint:#787e8a;
  --rule:#26282f; --shade:#16181d; --focus:#e8e9ec;
  --ring:rgba(232,233,236,.34);
}
:root[data-theme="light"]{
  --ground:#ffffff; --ink:#1c1c1e; --muted:#5f6470; --faint:#8b909b;
  --rule:#e5e6ea; --shade:#f7f7f9; --focus:#1c1c1e;
  --ring:rgba(28,28,30,.30);
}

/* ---------------------------------------------------------------- base --- */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--ground);color:var(--ink);
  font-family:"Jost",system-ui,-apple-system,sans-serif;
  font-size:17px;line-height:1.65;letter-spacing:.01em;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
}
img{display:block;max-width:100%;height:auto}
a{color:inherit}
/* Browsers ship `figure { margin: 1em 40px }`. Left unchecked that pushed the
   full-width feature image 40px past the viewport on both edges (horizontal
   scroll) and squeezed every in-content photograph by 80px. */
figure{margin:0}
:focus-visible{outline:2px solid var(--focus);outline-offset:3px}
.visually-hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.skip-link{position:absolute;left:-9999px;top:0;background:var(--ground);color:var(--ink);
  padding:.7rem 1rem;z-index:100;border:1px solid var(--rule)}
.skip-link:focus{left:1rem;top:1rem}

h1,h2,h3,h4{font-family:"Montserrat",sans-serif;font-weight:500;margin:0;text-wrap:balance}

.shell{max-width:var(--shell);margin:0 auto;padding:0 1.5rem}

/* --------------------------------------------------------------- header -- */
/* Sticky on every breakpoint. The bar spans the viewport while its contents
   stay inside .shell, so the background never stops short on wide screens.
   safe-area-inset-top keeps the links clear of the iPhone Dynamic Island —
   it only resolves to a real value because of viewport-fit=cover. */
.site-head{position:sticky;top:0;z-index:100;background:var(--ground);
           border-bottom:1px solid var(--rule);
           padding-top:env(safe-area-inset-top,0px)}
.topbar{display:flex;align-items:baseline;gap:1.6rem;flex-wrap:wrap;padding:1.1rem 0 1rem}
.wordmark{font-family:"Aldrich",sans-serif;font-size:20px;letter-spacing:5.2px;
          text-transform:lowercase;text-decoration:none;white-space:nowrap;color:var(--ink)}
.wordmark img{max-height:28px;width:auto}
.tagline{color:var(--faint);font-size:14px;letter-spacing:.06em}
/* The flex child is the <nav> wrapper, not the <ul> inside it — the auto
   margin has to go here or the nav sits next to the wordmark with dead space
   to its right. */
.topbar nav{margin-left:auto}
.nav{display:flex;gap:1.5rem;flex-wrap:wrap;font-size:15px;
     letter-spacing:.04em;color:var(--muted);list-style:none;margin-block:0;padding:0}
@media (max-width:720px){
  .topbar nav{margin-left:0;width:100%}
}
.nav a{text-decoration:none;padding-bottom:2px;border-bottom:1px solid transparent;display:inline-block}
.nav a:hover,.nav a:focus-visible{color:var(--ink);border-bottom-color:var(--ink)}
.nav .nav-current a{color:var(--ink);border-bottom-color:var(--ink)}

/* ------------------------------------------------------- mobile nav ----- */
.navtoggle{display:none;background:none;border:0;padding:.45rem;cursor:pointer;
           color:var(--ink);margin-left:auto;position:relative;z-index:200}
.navtoggle-bars{display:block;width:22px;height:13px;position:relative}
.navtoggle-bars span{position:absolute;left:0;right:0;height:1.5px;background:currentColor;
                     transition:transform .25s ease,opacity .18s ease}
.navtoggle-bars span:nth-child(1){top:0}
.navtoggle-bars span:nth-child(2){top:6px}
.navtoggle-bars span:nth-child(3){top:12px}
[data-nav-toggle][aria-expanded="true"] .navtoggle-bars span:nth-child(1){transform:translateY(6px) rotate(45deg)}
[data-nav-toggle][aria-expanded="true"] .navtoggle-bars span:nth-child(2){opacity:0}
[data-nav-toggle][aria-expanded="true"] .navtoggle-bars span:nth-child(3){transform:translateY(-6px) rotate(-45deg)}

@media (max-width:720px){
  /* Only once JS has taken over does the nav collapse behind the button. */
  html.js-nav .navtoggle{display:inline-flex}
  html.js-nav .topbar nav{
    position:fixed;inset:0;z-index:150;margin:0;width:auto;
    padding-top:env(safe-area-inset-top,0px);
    background:var(--ground);display:flex;align-items:center;justify-content:center;
    opacity:0;visibility:hidden;transition:opacity .22s ease;
  }
  html.js-nav .topbar nav[data-open="true"]{opacity:1;visibility:visible}
  /* The panel is a focus target for management only — it should not paint a
     ring of its own. Individual links keep theirs for keyboard users. */
  html.js-nav .topbar nav:focus{outline:none}
  html.js-nav .topbar nav .nav{
    flex-direction:column;align-items:center;gap:1.7rem;text-align:center;
    font-family:"Montserrat",sans-serif;font-weight:500;font-size:1rem;
    letter-spacing:.2em;text-transform:uppercase;color:var(--ink);
  }
  html.js-nav .topbar nav .nav a{border-bottom-width:1px;padding-bottom:4px}
  body.nav-open{overflow:hidden}
}

/* ----------------------------------------------------------------- hero -- */
.hero{position:relative;margin-top:.5rem}
/* Full-bleed: spans the viewport regardless of the page shell. */
.hero--full{margin-top:0;width:100%}
/* 16:9 would be ~1440px tall on a 2560px display, pushing the caption below
   the fold. Cap the height to the viewport minus the header so the whole hero
   — caption included — always lands on the first screen. */
.hero img{width:100%;aspect-ratio:16/9;object-fit:cover;background:var(--shade);
          max-height:calc(100vh - 5.5rem);max-height:calc(100svh - 5.5rem)}
.hero-cap{position:absolute;left:0;right:0;bottom:1.6rem;text-align:center;
          padding:0 1rem;z-index:1}

/* The tagline sits directly on the photograph rather than in a box. That only
   works because the sky behind it is bright and even; a scrim carries the
   contrast instead. Three colour stops, not two — a straight fade to
   transparent leaves a visible edge over an even sky, and the midpoint
   dissolves it. Added only when there is a caption to carry. */
.hero--scrim::after{content:"";position:absolute;inset:auto 0 0 0;height:56%;
                    pointer-events:none;
                    background:linear-gradient(to top,rgba(0,0,0,.84),
                                               rgba(0,0,0,.44) 45%,transparent)}
/* Montserrat, matching every heading on the site, so the most prominent line on
   the homepage speaks in the same voice as the rest rather than in body text. */
.hero-tag{color:#fff;font-family:"Montserrat",sans-serif;font-weight:500;
          text-transform:uppercase;text-wrap:balance;
          font-size:clamp(.8rem,.68rem + .55vw,1.02rem);
          letter-spacing:.14em;line-height:1.45}

@media (max-width:640px){
  .hero img{aspect-ratio:4/3}
  /* The 4:3 crop is taller, so a percentage scrim would cover proportionally
     less of it — hence its own height here rather than an inherited one. */
  .hero--scrim::after{height:68%}
  /* Sits low, but clear of the home indicator. */
  .hero-cap{bottom:calc(.55rem + env(safe-area-inset-bottom,0px));padding:0 1.25rem}
  /* Hold the measure so tracked uppercase breaks into even lines instead of
     wrapping raggedly across the full width of a phone. */
  .hero-tag{display:block;max-width:17rem;margin:0 auto;
            font-size:.9rem;letter-spacing:.11em;line-height:1.55}
}

/* ---------------------------------------------------------------- cards -- */
.rowhead{display:flex;align-items:baseline;justify-content:space-between;gap:1rem;
         margin-top:4rem;padding-bottom:.8rem;border-bottom:1px solid var(--rule)}
.rowhead h2{font-size:.78rem;letter-spacing:.19em;text-transform:uppercase;color:var(--muted)}
.rowhead a{font-size:.8rem;color:var(--muted);text-decoration:none;letter-spacing:.06em;
           border-bottom:1px solid var(--rule)}
.rowhead a:hover,.rowhead a:focus-visible{color:var(--ink);border-bottom-color:var(--ink)}

.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:1.5rem;margin-top:2.6rem}
.card{display:flex;flex-direction:column;gap:.7rem;text-decoration:none;color:inherit}
.card .frame{position:relative;overflow:hidden;background:var(--shade)}

/* "Feature this post", surfaced as a mark rather than as ordering. Takes the
   hero box's identity — black ground, white text, held in both themes because
   it sits on a photograph rather than on the page. This is now the only place
   the black-on-image mark survives — the hero dropped its box for a scrim. */
.card-badge{position:absolute;top:0;left:0;z-index:1;pointer-events:none;
            background:#000;color:#fff;
            font-family:"Montserrat",sans-serif;font-weight:500;
            font-size:.62rem;letter-spacing:.16em;text-transform:uppercase;
            padding:.36rem .62rem;line-height:1}
.card img{width:100%;aspect-ratio:3/2;object-fit:cover;
          transition:transform .5s cubic-bezier(.2,.6,.2,1)}
.card:hover img,.card:focus-visible img{transform:scale(1.03)}
.card:focus-visible{outline:2px solid var(--focus);outline-offset:4px}
.card .t{font-family:"Montserrat",sans-serif;font-weight:500;font-size:.86rem;
         letter-spacing:.1em;text-transform:uppercase;line-height:1.5}
.card .d{font-size:.8rem;color:var(--muted);letter-spacing:.06em}
.card .noimg{aspect-ratio:3/2;display:flex;align-items:center;justify-content:center;
             background:var(--shade);color:var(--faint);font-size:.8rem;letter-spacing:.1em;
             text-transform:uppercase}

/* --------------------------------------------------------------- single -- */
.article-head{max-width:44rem;margin:0 auto;padding:3rem 1.5rem 2rem;
              display:flex;flex-direction:column;gap:.9rem}
.h-page{font-size:clamp(1.15rem,1rem + 1vw,1.5rem);letter-spacing:.16em;
        text-transform:uppercase;text-align:center;line-height:1.45}

.postmeta{display:flex;align-items:center;justify-content:center;gap:.7rem;flex-wrap:wrap;
          font-family:"Montserrat",sans-serif;font-weight:500;font-size:.68rem;
          letter-spacing:.19em;text-transform:uppercase;color:var(--muted)}
.postmeta .sep{opacity:.5}

.feature{width:100%}
.feature img{width:100%;max-height:78vh;object-fit:cover;background:var(--shade)}
.feature figcaption{max-width:var(--wide);margin:.7rem auto 0;padding:0 1.5rem;
                    font-size:.83rem;color:var(--muted)}

/* ---------------------------------------------------------------- prose -- */
/* The content column is WIDE so photographs get room; running text is pulled
   back to a readable measure inside it. Images therefore default to large,
   which is the point of a photography site. */
.content{max-width:var(--wide);margin:0 auto;padding:2.4rem 1.5rem 0}

/* These two rules own the vertical rhythm.
   IMPORTANT: element rules below must never set the `margin` shorthand.
   `.content p` (0,1,1) beats `.content > * + *` (0,1,0) and would silently
   cancel all spacing. Set padding, colour, borders — and only the individual
   margin-left/right longhands — here. */
.content > *{margin-top:0;margin-bottom:0}
.content > * + *{margin-top:1.4rem}

/* Text returns to a comfortable measure; figures keep the full width. */
.content > p,
.content > ul,
.content > ol,
.content > h2,
.content > h3,
.content > blockquote,
.content > hr{max-width:var(--measure);margin-left:auto;margin-right:auto}

/* Photographs and Koenig cards get more air than consecutive paragraphs. */
.content > * + figure,
.content > figure + *,
.content > * + .kg-card,
.content > .kg-card + *{margin-top:2.6rem}

/* Headings deliberately out-specify the flow rule to open a new section. */
.content h2{font-size:1rem;letter-spacing:.14em;text-transform:uppercase;margin-top:2.9rem}
.content h3{font-size:.85rem;letter-spacing:.14em;text-transform:uppercase;
            color:var(--muted);margin-top:2.2rem}

.content a{color:var(--ink);text-decoration:underline;text-underline-offset:3px;
           text-decoration-thickness:1px;text-decoration-color:var(--faint)}
.content a:hover,.content a:focus-visible{text-decoration-color:var(--ink)}
.content ul,.content ol{padding-left:1.2rem}
.content li + li{margin-top:.5rem}
.content blockquote{padding-left:1.2rem;border-left:2px solid var(--rule);color:var(--muted)}
.content hr{border:0;border-top:1px solid var(--rule)}
/* figcaption sits inside <figure>, not a child of .content, so the flow rule
   does not reach it and its own margin is safe. */
.content figcaption{font-size:.83rem;line-height:1.55;color:var(--muted);
                    margin-top:.7rem;text-align:left;max-width:var(--measure)}
/* Imported captions are "<strong>Title</strong>Description" — give the title
   its own line so the two don't run together. */
.content figcaption strong,
.lightbox-cap strong{display:block;color:var(--ink);font-weight:500;margin-bottom:.15rem}
.lightbox-cap strong{color:#fff}
.content img{width:100%}

/* Ghost card widths */
.kg-width-wide{max-width:var(--wide)}
.kg-width-full{width:100vw;max-width:100vw;margin-left:calc(50% - 50vw)}
.kg-width-full img{width:100%}
.kg-gallery-container{display:flex;flex-direction:column;gap:.8rem}
.kg-gallery-row{display:flex;gap:.8rem}
/* main.js overwrites this flex with each image's true aspect ratio; without it
   a portrait beside two landscapes would be cropped to match their width. */
.kg-gallery-image{flex:1 1 0;min-width:0}
.kg-gallery-image img{width:100%;height:100%;object-fit:cover}
.kg-embed-card{display:flex;justify-content:center}
.kg-embed-card iframe{max-width:100%}
@media (max-width:700px){ .kg-gallery-row{flex-direction:column} }

/* ------------------------------------------------------------- lightbox -- */
/* Every photograph in post/page content becomes clickable. Enhancement only:
   without JS the images are simply static, exactly as before. */
.content img.is-zoomable{cursor:zoom-in;
    transition:box-shadow .25s ease, filter .25s ease}
.content img.is-zoomable:hover,
.content img.is-zoomable:focus-visible{box-shadow:0 0 0 3px var(--ring);
    filter:brightness(1.04);outline:none}

.lightbox{position:fixed;inset:0;z-index:200;display:flex;flex-direction:column;
          align-items:center;justify-content:center;gap:1.1rem;
          padding:4.6rem 1.5rem calc(1.6rem + env(safe-area-inset-bottom,0px));
          background:rgba(8,9,11,.94);
          opacity:0;visibility:hidden;transition:opacity .2s ease}
.lightbox[data-open="true"]{opacity:1;visibility:visible}

/* The photograph and its caption stack, so nothing is ever laid over the image
   — a portrait shot used to have its lower third hidden behind the caption. */
/* Sized to fill whatever the chrome leaves. The calc() subtracts the top bar,
   caption and metadata panel so the stack can never overflow on a short window;
   the vh cap only takes over on very tall ones. Measured chrome is ~14rem. */
.lightbox img{max-width:min(90vw,2400px);
              max-height:min(86vh,calc(100vh - 14rem));
              max-height:min(86vh,calc(100svh - 14rem));
              width:auto;height:auto;
              object-fit:contain;
              box-shadow:0 0 0 1px rgba(255,255,255,.16),
                         0 0 60px rgba(255,255,255,.06),
                         0 24px 70px rgba(0,0,0,.65)}

/* Top bar: counter left, page title centred, close right. */
.lightbox-top{position:absolute;top:0;left:0;right:0;z-index:2;
              display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:1rem;
              padding:calc(.9rem + env(safe-area-inset-top,0px)) 1.1rem .9rem;
              background:linear-gradient(to bottom,rgba(8,9,11,.85),rgba(8,9,11,0))}
.lightbox-title{margin:0;text-align:center;color:#9aa0a9;
                font-family:"Montserrat",sans-serif;font-weight:500;font-size:.7rem;
                letter-spacing:.18em;text-transform:uppercase;
                overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:60vw}
.lightbox-count{color:#9ea3ac;font-size:.78rem;letter-spacing:.14em;
                font-variant-numeric:tabular-nums;justify-self:start}
.lightbox-top .lightbox-close{justify-self:end}

.lightbox-close,.lightbox-nav{background:none;border:0;color:#fff;
              cursor:pointer;padding:.6rem;line-height:0;opacity:.75}
.lightbox-close:hover,.lightbox-nav:hover,
.lightbox-close:focus-visible,.lightbox-nav:focus-visible{opacity:1}
.lightbox svg{width:26px;height:26px;fill:none;stroke:currentColor;stroke-width:1.6}

/* Desktop: arrows sit in the margin beside the photograph (the image is capped
   at 86vw, leaving room), so they never cover it either. */
.lightbox-stage{display:contents}
.lightbox-controls{display:contents}
.lightbox-dots{display:none}
.lightbox-nav{position:absolute;top:50%;transform:translateY(-50%)}
.lightbox-prev{left:.4rem}
.lightbox-next{right:.4rem}

.lightbox-meta{display:flex;flex-direction:column;gap:.55rem;align-items:center;
               max-width:min(86vw,52rem)}
.lightbox-cap{margin:0;text-align:center;color:#e4e6ea;font-size:.88rem;
              line-height:1.5;letter-spacing:.02em}

/* Shot data from the originals' EXIF: when, what it was shot on, then how. */
/* The shot data sits in its own bordered panel so it reads as a distinct
   block rather than more caption text. */
/* A class selector's `display` beats the UA's [hidden]{display:none}, so these
   need an explicit rule or the empty bordered panel still renders. */
.lightbox-exif[hidden],
.lightbox-taken[hidden],
.lightbox-gear[hidden],
.lightbox-meta-toggle[hidden]{display:none}

/* Collapse mechanism, all breakpoints. Desktop opens expanded (main.js adds
   .meta-open); phones start collapsed. */
.lightbox .lightbox-exif{display:none}
.lightbox.meta-open .lightbox-exif{display:flex}
/* MUST out-specify the .meta-open rule above (0,3,0) or a photograph with no
   EXIF renders as an empty bordered box. This is the second time a later
   `display` rule has beaten [hidden]; keep these two adjacent. */
.lightbox .lightbox-exif[hidden],
.lightbox.meta-open .lightbox-exif[hidden]{display:none}
.lightbox .lightbox-meta[hidden],
.lightbox.meta-open .lightbox-meta[hidden]{display:none}

.lightbox-meta-toggle{display:inline-block;
    font-family:"Montserrat",sans-serif;font-weight:500;font-size:.6rem;
    letter-spacing:.2em;text-transform:uppercase;color:#9aa0a9;
    background:none;border:1px solid rgba(255,255,255,.22);
    padding:.5rem 1rem;cursor:pointer;margin-top:.2rem}
.lightbox-meta-toggle:hover,.lightbox-meta-toggle:focus-visible{color:#fff;
    border-color:rgba(255,255,255,.5)}
.lightbox.meta-open .lightbox-meta-toggle{display:none}

.lightbox-exif-close{display:flex;position:absolute;top:.3rem;right:.3rem;
    background:none;border:0;color:#8a9099;padding:.4rem;cursor:pointer;line-height:0}
.lightbox-exif-close svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:2}
.lightbox-exif-close:hover,.lightbox-exif-close:focus-visible{color:#fff}
.lightbox-exif{display:flex;flex-direction:column;align-items:center;gap:.3rem;
               margin:.2rem 0 0;padding:.85rem 1.5rem .95rem;
               border:1px solid rgba(255,255,255,.16);
               background:rgba(255,255,255,.035)}
.lightbox-exif-label{margin:0 0 .15rem;color:#8a9099;
                     font-family:"Montserrat",sans-serif;font-weight:500;font-size:.58rem;
                     letter-spacing:.24em;text-transform:uppercase}
.lightbox-taken{color:#b9bec6;font-size:.74rem;letter-spacing:.08em;margin:0}
.lightbox-gear{color:#9aa0a9;font-size:.72rem;letter-spacing:.1em;
               text-transform:uppercase;margin:0}
.lightbox-shot{display:flex;gap:.3rem .55rem;flex-wrap:wrap;justify-content:center;
               margin:0;padding:0;list-style:none;
               color:#cfd3d9;font-size:.76rem;letter-spacing:.08em;
               font-variant-numeric:tabular-nums}
.lightbox-shot li{white-space:nowrap;display:flex;align-items:center;gap:.55rem}
.lightbox-shot li + li::before{content:"";width:3px;height:3px;border-radius:50%;
                               background:#5c626b;display:inline-block}
/* Desktop: the photograph is centred in the viewport, full stop. The metadata
   is taken out of the flow and pinned to the lower-right, so it can never push
   the image off-centre. Because it may now sit over a wide photograph it gets
   a solid scrim rather than the faint translucent fill used elsewhere. */
@media (min-width:900px){
  .lightbox{flex-direction:column;align-items:center;justify-content:center;
            padding:5.2rem 1.6rem 2rem}
  .lightbox img{max-width:min(92vw,2400px);
                max-height:calc(100vh - 7.6rem);
                max-height:calc(100svh - 7.6rem);
                width:auto;height:auto}
  .lightbox-meta{position:absolute;right:1.8rem;bottom:1.8rem;
                 width:20rem;max-width:20rem;
                 align-items:flex-start;text-align:left;
                 padding:1rem 1.1rem;background:rgba(8,9,11,.78);
                 border:1px solid rgba(255,255,255,.10);
                 backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
  /* Collapsed, the panel shrinks to just the button. */
  .lightbox:not(.meta-open) .lightbox-meta{width:auto;max-width:20rem;
                 background:none;border:0;backdrop-filter:none;padding:0}
  .lightbox:not(.meta-open) .lightbox-cap{display:none}
  .lightbox-cap{text-align:left}
  /* The panel already provides the frame, so the inner block drops its own. */
  .lightbox-exif{align-items:flex-start;border:0;background:none;padding:.2rem 0 0}
  .lightbox-shot{justify-content:flex-start}
}

/* Landscape below 900px: the panel is wide but short, so gear and exposure
   share one line. Above 900px the panel is a narrow side column and this is
   overridden back to stacked rows. */
@media (min-width:641px) and (max-width:899px){
.lightbox.is-landscape .lightbox-exif{flex-direction:row;flex-wrap:wrap;
                                      justify-content:center;align-items:center;
                                      gap:.3rem .6rem}
.lightbox.is-landscape .lightbox-exif-label{flex:0 0 100%;text-align:center}
.lightbox.is-landscape .lightbox-taken{flex:0 0 100%;text-align:center}
.lightbox.is-landscape .lightbox-gear{order:1}
.lightbox.is-landscape .lightbox-shot{order:2}
/* separator between the gear and the exposure values */
.lightbox.is-landscape .lightbox-shot::before{content:"";width:3px;height:3px;border-radius:50%;
                                              background:#5c626b;display:inline-block;
                                              margin-right:.25rem;flex:0 0 auto}
}
@media (max-width:640px){
  /* Too narrow for one line — let it wrap back to stacked rows. */
  .lightbox.is-landscape .lightbox-exif{flex-direction:column}
  .lightbox.is-landscape .lightbox-shot::before{display:none}
}

body.lightbox-open{overflow:hidden}

@media (max-width:640px){
  /* On phones the panel anchors the close button itself. */
  .lightbox.meta-open .lightbox-exif{position:relative;padding-top:1.5rem}
  .lightbox .lightbox-meta-toggle:active{background:rgba(255,255,255,.12);color:#fff}

  /* The STAGE has the fixed height, so every photograph occupies the same block
     and the dots never shift. The image inside sizes to the picture itself,
     which keeps the highlight ring tight around it rather than around the
     letterboxed area. */
  /* flex-shrink:0 matters — as a flex item the stage was being squeezed by
     longer captions, which moved the dots between photographs. */
  .lightbox-stage{display:flex;order:1;align-items:center;justify-content:center;
                  width:100%;flex:0 0 auto;
                  height:min(78vh,calc(100vh - 11.5rem));
                  height:min(78vh,calc(100svh - 11.5rem))}
  .lightbox.meta-open .lightbox-stage{height:min(58vh,calc(100vh - 20rem));
                                      height:min(58vh,calc(100svh - 20rem))}
  .lightbox-stage img{max-width:100%;max-height:100%;width:auto;height:auto;
                      object-fit:contain}

  /* Arrows move out from beside the photograph into their own row beneath it,
     since at this width there is no margin to sit in. */
  /* Top-anchored, not centred: centring re-positioned everything (including the
     dots) whenever a caption's height changed. */
  .lightbox{justify-content:flex-start;gap:.85rem;
            padding:4rem .8rem calc(1rem + env(safe-area-inset-bottom,0px))}

  /* Swipe is the interaction; the dots just show where you are, as on
     Instagram. The arrows remain focusable for assistive tech and appear if
     they ever receive keyboard focus. */
  .lightbox-controls{display:flex;order:2;align-items:center;justify-content:center;
                     position:relative;min-height:1.1rem}
  .lightbox-nav{position:absolute;opacity:0;pointer-events:none;width:1px;height:1px;
                padding:0;overflow:hidden}
  .lightbox-nav:focus-visible{opacity:1;pointer-events:auto;width:2.6rem;height:2.6rem;
                position:static;background:rgba(255,255,255,.14);border-radius:50%;
                display:flex;align-items:center;justify-content:center;margin:0 .6rem}
  /* Window over a track that slides — the movement animates rather than the
     list being re-drawn. DOT_PITCH in main.js must match 6px dot + 6px gap. */
  .lightbox-dots{display:block;overflow:hidden;height:8px}
  .lightbox-dots-track{display:flex;align-items:center;gap:6px;width:max-content;
                       transition:margin-left .34s cubic-bezier(.25,.8,.3,1)}
  .lightbox-dot{flex:0 0 6px;width:6px;height:6px;border-radius:50%;
                background:rgba(255,255,255,.36);
                transition:background .25s ease,transform .32s cubic-bezier(.25,.8,.3,1)}
  .lightbox-dot.is-active{background:#fff}
  .lightbox svg{width:20px;height:20px}

  /* Caption is clamped so its height cannot vary enough to shift the layout;
     the full text is still in the DOM for screen readers. */
  .lightbox-cap{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;
                overflow:hidden}
  .lightbox-meta{flex:0 1 auto;min-height:0}

  /* Smaller metadata type — it is a footnote on a phone, not the content. */
  .lightbox .lightbox-meta-toggle{font-size:.56rem;letter-spacing:.18em;padding:.45rem .9rem}
  .lightbox-cap{font-size:.76rem}
  .lightbox-exif{padding:.7rem 1.1rem .75rem}
  .lightbox-exif-label{font-size:.5rem;letter-spacing:.18em}
  .lightbox-taken{font-size:.64rem}
  .lightbox-gear{font-size:.62rem}
  .lightbox-shot{font-size:.66rem}
  .lightbox-meta{order:3;max-width:100%}
  .lightbox-title{font-size:.6rem;max-width:52vw}
}


/* -------------------------------------------------------------- resume --- */
/* Replaces Squarespace's fake columns (runs of &nbsp; tuned to one font).
   Real grid: alignment no longer depends on the typeface, and it stacks. */
.resume{max-width:46rem;margin:0 auto;padding:2.4rem 1.5rem 0}
.resume-role{display:grid;grid-template-columns:minmax(9.5rem,auto) 1fr minmax(8rem,auto);
             gap:.35rem 2rem;font-variant-numeric:tabular-nums;margin-top:2.2rem}
.resume-role .r-when{color:var(--ink)}
.resume-role .r-where{color:var(--ink)}
.resume-role .r-city{color:var(--muted);text-align:right}
.resume-role .r-title{grid-column:1/-1;color:var(--muted)}
.resume-role ul{grid-column:1/-1;margin:.5rem 0 0;padding-left:1.2rem}
.resume-role li + li{margin-top:.4rem}
@media (max-width:680px){
  .resume-role{grid-template-columns:1fr;gap:.1rem}
  .resume-role .r-city{text-align:left}
  .resume-role .r-title{margin-top:.25rem}
}

/* --------------------------------------------------------------- share --- */
.sharewrap{position:relative;display:inline-flex}
.sharebtn{font:inherit;letter-spacing:inherit;text-transform:inherit;color:var(--muted);
          background:none;border:0;border-bottom:1px solid var(--rule);padding:0 0 2px;
          cursor:pointer;display:inline-flex;align-items:center;gap:.4rem}
.sharebtn:hover,.sharebtn:focus-visible{color:var(--ink);border-bottom-color:var(--ink)}
.sharebtn svg{width:12px;height:12px;fill:none;stroke:currentColor;stroke-width:1.8}
.sharemenu{position:absolute;top:calc(100% + .7rem);left:50%;
           transform:translateX(-50%) translateY(-4px);background:var(--ground);
           border:1px solid var(--rule);padding:.4rem;display:flex;flex-direction:column;
           min-width:12rem;z-index:20;opacity:0;visibility:hidden;
           transition:opacity .16s ease,transform .16s ease;box-shadow:0 6px 24px rgba(0,0,0,.12)}
.sharemenu[data-open="true"]{opacity:1;visibility:visible;transform:translateX(-50%) translateY(0)}
.sharemenu button,.sharemenu a{font-family:"Jost",sans-serif;font-size:.82rem;letter-spacing:.04em;
           text-transform:none;font-weight:400;color:var(--ink);background:none;border:0;
           text-align:left;padding:.5rem .6rem;cursor:pointer;text-decoration:none;white-space:nowrap}
.sharemenu button:hover,.sharemenu a:hover,
.sharemenu button:focus-visible,.sharemenu a:focus-visible{background:var(--shade)}
.share-note{color:var(--muted);font-size:.78rem;padding:.5rem .6rem;letter-spacing:.04em;
            font-family:"Jost",sans-serif;text-transform:none}

/* ------------------------------------------------------------ pagination -- */
.pagination{display:flex;justify-content:center;gap:1.5rem;margin-top:3.5rem;
            font-family:"Montserrat",sans-serif;font-weight:500;font-size:.72rem;
            letter-spacing:.16em;text-transform:uppercase;color:var(--muted)}
.pagination a{text-decoration:none;border-bottom:1px solid var(--rule)}
.pagination a:hover,.pagination a:focus-visible{color:var(--ink);border-bottom-color:var(--ink)}

/* --------------------------------------------------------------- footer -- */
.site-foot{border-top:1px solid var(--rule);margin-top:4.5rem;padding:2.2rem 0 3rem;
           display:flex;gap:1rem;flex-wrap:wrap;justify-content:space-between;
           color:var(--muted);font-size:.85rem}
.site-foot a{text-decoration:none;border-bottom:1px solid var(--rule)}
.site-foot a:hover{color:var(--ink);border-bottom-color:var(--ink)}

/* Social marks. Filled brand glyphs read better than outlines at this size;
   currentColor keeps them correct in both themes. */
.social{display:flex;gap:1.15rem;align-items:center;list-style:none;margin:0;padding:0}
.social a{display:block;color:var(--muted);border-bottom:0;line-height:0;
          transition:color .2s ease}
.social a:hover,.social a:focus-visible{color:var(--ink);border-bottom:0}
.social svg{width:18px;height:18px;fill:currentColor}
@media (max-width:600px){
  .site-foot{gap:1.1rem}
  .social{order:-1}
}

/* --------------------------------------------------------------- misc ---- */
.error-page{max-width:38rem;margin:0 auto;padding:6rem 1.5rem;text-align:center;
            display:flex;flex-direction:column;gap:1.2rem}
.error-code{font-family:"Montserrat",sans-serif;font-weight:500;font-size:3rem;letter-spacing:.1em}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{transition:none!important;animation:none!important;scroll-behavior:auto!important}
}

/* ---------------------------------------------------------------- intro -- */
/* Portrait + one-sentence introduction, sitting between the hero and the
   featured row. Stacks and centres on narrow screens. */
.intro{display:flex;align-items:center;justify-content:center;gap:2.4rem;
       margin-top:3.4rem;padding-bottom:.5rem}
/* Round crop. aspect-ratio:1 matters — border-radius:50% on a 4:5 photo
   would give an ellipse, not a circle. */
.intro-portrait{width:clamp(140px,20vw,210px);aspect-ratio:1;object-fit:cover;
                flex:0 0 auto;border-radius:50%;background:var(--shade)}
.intro-body{display:flex;flex-direction:column;gap:1rem;max-width:44ch}
.intro-body p{margin:0;font-size:1.05rem;line-height:1.7}
.intro-link{align-self:flex-start;font-family:"Montserrat",sans-serif;font-weight:500;
            font-size:.72rem;letter-spacing:.16em;text-transform:uppercase;
            color:var(--muted);text-decoration:none;border-bottom:1px solid var(--rule);
            padding-bottom:3px}
.intro-link:hover,.intro-link:focus-visible{color:var(--ink);border-bottom-color:var(--ink)}
@media (max-width:700px){
  .intro{flex-direction:column;text-align:center;gap:1.4rem;margin-top:2.6rem}
  .intro-body{align-items:center}
  .intro-link{align-self:center}
}

/* ----------------------------------------------------------- contact -- */
.contact-form{display:flex;flex-direction:column;gap:1.1rem;max-width:var(--measure);
              margin:2rem auto 0}
.contact-form label{display:flex;flex-direction:column;gap:.4rem;
                    font-family:"Montserrat",sans-serif;font-weight:500;font-size:.68rem;
                    letter-spacing:.16em;text-transform:uppercase;color:var(--muted)}
.contact-form input,
.contact-form textarea{font-family:"Jost",sans-serif;font-size:1rem;letter-spacing:.01em;
                       color:var(--ink);background:var(--ground);
                       border:1px solid var(--rule);padding:.7rem .85rem;width:100%}
.contact-form textarea{min-height:9rem;resize:vertical;line-height:1.6}
.contact-form input:focus,.contact-form textarea:focus{outline:none;border-color:var(--ink)}
/* Honeypot: off-screen rather than display:none, which some bots skip. */
.contact-hp{position:absolute!important;left:-9999px;width:1px;height:1px;overflow:hidden}
.contact-form button{align-self:flex-start;font-family:"Montserrat",sans-serif;font-weight:500;
                     font-size:.72rem;letter-spacing:.16em;text-transform:uppercase;
                     color:var(--ink);background:none;border:1px solid var(--ink);
                     padding:.75rem 1.7rem;cursor:pointer;
                     transition:background .2s ease,color .2s ease}
.contact-form button:hover:not(:disabled){background:var(--ink);color:var(--ground)}
.contact-form button:disabled{opacity:.5;cursor:default}
.contact-status{margin:0;font-size:.92rem;line-height:1.6}
.contact-status[data-state="ok"]{color:var(--ink)}
.contact-status[data-state="error"]{color:#b4453c}
:root[data-theme="dark"] .contact-status[data-state="error"],
[data-theme="dark"] .contact-status[data-state="error"]{color:#e08a82}
@media (prefers-color-scheme:dark){
  .contact-status[data-state="error"]{color:#e08a82}
}

/* ------------------------------------------------------------- featured -- */
/* Lead item spans the full width; everything after sits two per row. Which
   item leads is decided here with :first-child rather than in the template,
   because the grid is filled by two separate Ghost queries (pages, then posts)
   and neither knows about the other. */
.featured{display:grid;grid-template-columns:repeat(2,1fr);gap:2.2rem 1.8rem;margin-top:2.4rem}
.featured > .card:first-child{grid-column:1/-1}
.featured > .card:first-child img{aspect-ratio:21/9}
.featured > .card:first-child .t{font-size:1.05rem;letter-spacing:.12em}
.featured > .card:first-child .d{font-size:.82rem}

/* Lead + two rows of two = five visible; the rest wait behind the button.
   They stay in the HTML so search engines still index them. */
.featured > .card:nth-child(n+6){display:none}
.featured.is-expanded > .card:nth-child(n+6){display:flex}

.featured-foot{display:flex;flex-direction:column;align-items:center;gap:1.4rem;margin-top:2.6rem}
.showmore{font-family:"Montserrat",sans-serif;font-weight:500;font-size:.72rem;
          letter-spacing:.16em;text-transform:uppercase;color:var(--muted);
          background:none;border:1px solid var(--rule);padding:.7rem 1.6rem;cursor:pointer;
          transition:color .2s ease,border-color .2s ease}
.showmore:hover,.showmore:focus-visible{color:var(--ink);border-color:var(--ink)}
.showmore[hidden]{display:none}

.rowlinks{display:flex;gap:1.8rem;flex-wrap:wrap;justify-content:center;
          font-family:"Montserrat",sans-serif;font-weight:500;font-size:.72rem;
          letter-spacing:.16em;text-transform:uppercase}
.rowlinks a{color:var(--muted);text-decoration:none;border-bottom:1px solid var(--rule);
            padding-bottom:2px}
.rowlinks a:hover,.rowlinks a:focus-visible{color:var(--ink);border-bottom-color:var(--ink)}

@media (max-width:760px){
  .featured{grid-template-columns:1fr;gap:1.8rem}
  .featured > .card:first-child img{aspect-ratio:3/2}
}

/* ------------------------------------------------------- about portrait -- */
/* The About page's single photograph gets the same round crop as the home
   introduction. aspect-ratio:1 is what makes it a circle rather than an
   ellipse, since the source is 4:5. */
body.page-about .content figure.kg-image-card{display:flex;justify-content:center}
body.page-about .content figure.kg-image-card img{
  width:min(300px,70%);aspect-ratio:1;object-fit:cover;border-radius:50%}
