/* CanniGrow's own typefaces, self-hosted. No external requests. */
@font-face{font-family:'Open Sans';font-style:normal;font-weight:300 800;font-display:swap;
  src:url(/assets/fonts/open-sans.woff2) format('woff2')}
@font-face{font-family:'Open Sans';font-style:italic;font-weight:300 800;font-display:swap;
  src:url(/assets/fonts/open-sans-italic.woff2) format('woff2')}
@font-face{font-family:'Passion One';font-style:normal;font-weight:700;font-display:swap;
  src:url(/assets/fonts/passion-one-700.woff2) format('woff2')}
@font-face{font-family:'Passion One';font-style:normal;font-weight:900;font-display:swap;
  src:url(/assets/fonts/passion-one-900.woff2) format('woff2')}

/* ============================================================ tokens */
:root{
  /* tells the browser we genuinely support both, so it renders the things we
     do not style — scrollbars, the <select> on the contact page, form control
     chrome, the address bar — to match instead of always light */
  color-scheme:light dark;
  --brand:#0cb76d; --brand-lo:#079a5b; --brand-hi:#38d68d;
  /* Small green text only. The brand green is a fill colour — at 2.4:1 on the
     cream it is unreadable as type, so labels, links and chips use this darker
     cut instead (5.4:1 on --paper, 5.0:1 on a chip). Never used for buttons,
     rules or anything sitting over photography. */
  --brand-txt:#087344;
  --forest:#04281a;
  --paper:#f7f5ee; --paper-2:#efece2; --surface:#fffefa;
  --ink:#0d1512; --ink-2:#3d4b43; --muted:#6d7c73;
  --line:#e0dcd0; --line-2:#cfc9b9;
  --sh:0 1px 2px rgba(13,21,18,.04),0 12px 34px -12px rgba(13,21,18,.16);
  --sh-lg:0 2px 4px rgba(13,21,18,.05),0 30px 60px -22px rgba(13,21,18,.26);
  --f-body:'Open Sans',ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  --f-head:'Inter Tight','Inter',ui-sans-serif,system-ui,-apple-system,'Segoe UI Variable Display',
           'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;
  --f-disp:'Passion One',var(--f-head);
  --wrap:min(1240px,90vw); --narrow:min(760px,90vw);
  --r:18px; --r-lg:24px;
  --ease:cubic-bezier(.22,.72,.24,1);
}
@media (prefers-color-scheme:dark){:root:not([data-theme=light]){
  --paper:#080c0a; --paper-2:#0d1210; --surface:#111815;
  --ink:#e9efe9; --ink-2:#bdcac1; --muted:#8c9b91;
  --line:#1d2822; --line-2:#2a3830;
  --brand:#21cd80; --brand-lo:#12b46e; --brand-hi:#5ee6a9; --brand-txt:#21cd80;
  --sh:0 1px 2px rgba(0,0,0,.5),0 14px 34px -12px rgba(0,0,0,.7);
  --sh-lg:0 2px 6px rgba(0,0,0,.55),0 34px 66px -24px rgba(0,0,0,.8);
}}
:root[data-theme=light]{color-scheme:light}
:root[data-theme=dark]{
  color-scheme:dark;
  --paper:#080c0a; --paper-2:#0d1210; --surface:#111815;
  --ink:#e9efe9; --ink-2:#bdcac1; --muted:#8c9b91;
  --line:#1d2822; --line-2:#2a3830;
  --brand:#21cd80; --brand-lo:#12b46e; --brand-hi:#5ee6a9; --brand-txt:#21cd80;
  --sh:0 1px 2px rgba(0,0,0,.5),0 14px 34px -12px rgba(0,0,0,.7);
  --sh-lg:0 2px 6px rgba(0,0,0,.55),0 34px 66px -24px rgba(0,0,0,.8);
}

/* ============================================================= base */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{margin:0;background:var(--paper);color:var(--ink);font-family:var(--f-body);
  font-size:17px;line-height:1.68;-webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;overflow-x:hidden}
img{max-width:100%;height:auto;display:block}
a{color:inherit;text-decoration-thickness:1px;text-underline-offset:3px}
h1,h2,h3,h4{font-family:var(--f-head);font-weight:800;letter-spacing:-.032em;line-height:1.06}
::selection{background:var(--brand);color:#03130c}
:focus-visible{outline:2px solid var(--brand-txt);outline-offset:3px;border-radius:4px}
.wrap{width:var(--wrap);margin-inline:auto}
.narrow{width:var(--narrow);margin-inline:auto}
.section{padding-block:clamp(2.3rem,4.2vw,3.8rem)}
.muted{color:var(--muted)}
.mt{margin-top:clamp(1rem,2.4vw,2rem)}
.skip{position:absolute;left:-9999px}
.skip:focus{left:1rem;top:1rem;z-index:200;background:var(--surface);color:var(--ink);
  padding:.7rem 1.1rem;border-radius:10px;box-shadow:var(--sh)}

/* ========================================================== header */
.nav{position:fixed;inset:0 0 auto 0;z-index:100;display:flex;align-items:center;gap:clamp(1rem,3vw,2.4rem);
  padding:.85rem clamp(1rem,4vw,2.6rem);--nav-ink:#fff;color:var(--nav-ink);
  border-bottom:1px solid transparent;transition:background .35s var(--ease),
  padding .35s var(--ease),border-color .35s var(--ease),backdrop-filter .35s}
.nav.stuck{--nav-ink:var(--ink);padding-block:.5rem;border-bottom-color:var(--line);
  background:color-mix(in srgb,var(--paper) 84%,transparent);
  -webkit-backdrop-filter:blur(16px) saturate(150%);backdrop-filter:blur(16px) saturate(150%)}
/* pages with no hero photograph behind the header: solid bar from the start */
body.plain .nav{--nav-ink:var(--ink);border-bottom-color:var(--line);
  background:color-mix(in srgb,var(--paper) 84%,transparent);
  -webkit-backdrop-filter:blur(16px) saturate(150%);backdrop-filter:blur(16px) saturate(150%)}
/* Clears the fixed bar, which is logo + 2 x .85rem padding — so roughly 65px
   at the small end of the logo clamp and 75px at the large. It was already
   within 3px of tucking under the old 30px logo; a bigger mark would have put
   the first line of every legal page and blog post behind the header. */
body.plain main{padding-top:clamp(4.8rem,6vw,5.8rem)}
.brand{display:flex;align-items:center;gap:.72rem;text-decoration:none;font-family:var(--f-disp);
  font-weight:900;font-size:1.52rem;letter-spacing:.012em;text-transform:uppercase;line-height:1}
/* The mark is 105px square at source, so this is still downscaling it. It sets
   the height of the whole bar — anything that has to clear a fixed header has
   to move with it, which on this site is body.plain main's padding-top. */
.brand img{flex:none;width:clamp(38px,3.6vw,48px);height:clamp(38px,3.6vw,48px);object-fit:contain;
  filter:drop-shadow(0 2px 6px rgba(0,0,0,.4))}
.nav nav{display:flex;gap:clamp(.9rem,2.1vw,1.9rem);margin-left:auto}
.nav nav a{text-decoration:none;font-size:.83rem;font-weight:600;letter-spacing:.11em;
  text-transform:uppercase;opacity:.82;padding:.4rem 0;position:relative;white-space:nowrap}
.nav nav a::after{content:"";position:absolute;left:0;right:100%;bottom:0;height:2px;
  background:var(--brand);transition:right .35s var(--ease)}
.nav nav a:hover{opacity:1}
.nav nav a:hover::after,.nav nav a.on::after{right:0}
.nav nav a.on{opacity:1}
.nav-tail{display:flex;align-items:center;gap:.7rem}
/* The switch by the door, and it is lit. This one control changes the whole
   page, and as a grey outline in a header it was easy to walk straight past —
   so it carries the same green as the Flood / Lights on buttons, all the time
   rather than only under the cursor. Steady, not breathing: a pulse was tried
   and cut. */
/* A glow works by adding light, and on the cream theme there is almost no
   headroom left to add any — so the light skin carries it on fill and border
   instead, and the dark skin lets the glow do the work. */
.theme{position:relative;background:rgba(12,183,109,.16);border:1px solid rgba(8,115,68,.62);
  color:var(--brand-txt);width:36px;height:36px;border-radius:50%;display:grid;place-items:center;
  cursor:pointer;flex:none;box-shadow:0 0 14px rgba(12,183,109,.34);
  transition:border-color .25s,background .25s,box-shadow .25s,color .25s}
@media (prefers-color-scheme:dark){
  .theme{background:rgba(12,183,109,.1);border-color:rgba(12,183,109,.55);
    box-shadow:0 0 16px rgba(12,183,109,.34)}
}
:root[data-theme=dark] .theme{background:rgba(12,183,109,.1);
  border-color:rgba(12,183,109,.55);box-shadow:0 0 16px rgba(12,183,109,.34)}
.theme:hover{background:rgba(12,183,109,.2);border-color:var(--brand);color:var(--brand);
  box-shadow:0 0 26px rgba(12,183,109,.55)}
.theme svg{width:18px;height:18px}
.theme .moon{display:none}
:root[data-theme=dark] .theme .sun{display:none}
:root[data-theme=dark] .theme .moon{display:block}
@media (prefers-color-scheme:dark){
  :root:not([data-theme=light]) .theme .sun{display:none}
  :root:not([data-theme=light]) .theme .moon{display:block}
}
.cta{text-decoration:none;font-size:.8rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;
  background:var(--brand);color:#03130c;padding:.62rem 1.15rem;border-radius:999px;white-space:nowrap;
  transition:background .25s,transform .25s var(--ease)}
.cta:hover{background:var(--brand-hi);transform:translateY(-1px)}
.cta-m{display:none}          /* menu-only twin, shown at the mobile breakpoint */
.burger{display:none;background:none;border:0;color:inherit;width:38px;height:38px;
  cursor:pointer;padding:9px 7px;flex:none}
.burger span{display:block;height:2px;background:currentColor;border-radius:2px;
  transition:transform .3s var(--ease),opacity .3s}
.burger span+span{margin-top:6px}
.nav.open .burger span:first-child{transform:translateY(4px) rotate(45deg)}
.nav.open .burger span+span{transform:translateY(-4px) rotate(-45deg)}

/* ============================================================ hero */
.hero{position:relative;isolation:isolate;overflow:hidden;color:#fff;display:grid;align-items:end;
  padding-block:9rem clamp(3rem,7vh,5.5rem)}
.hero.tall{min-height:clamp(600px,93svh,940px)}
.hero.short{min-height:clamp(400px,60svh,600px);padding-block:7.6rem clamp(2.4rem,5vh,3.8rem)}
.hero.short h1{font-size:clamp(2.6rem,7.4vw,5.6rem);line-height:.88;max-width:14ch}
.hero.short .lede{font-size:clamp(1rem,1.5vw,1.2rem);margin-top:1.2rem}
.hero-bg{position:absolute;inset:0;z-index:-2;background-size:cover;background-position:center;
  animation:drift 26s var(--ease) infinite alternate}
@keyframes drift{from{transform:scale(1.02)}to{transform:scale(1.13) translate3d(0,-1.5%,0)}}
/* The heavy foot (.72/.94) is deliberate. It was eased to .5/.74 on 08-06 to
   show more of the photograph and Uriel reverted it the same day — the dark
   base under the type is the look. Don't lighten it again. */
.hero::after{content:"";position:absolute;inset:0;z-index:-1;background:
  linear-gradient(180deg,rgba(3,10,6,.62) 0%,rgba(3,10,6,.22) 32%,rgba(3,10,6,.72) 76%,rgba(3,10,6,.94) 100%),
  radial-gradient(120% 80% at 15% 100%,rgba(4,40,26,.6),transparent 70%)}
.hero-in{position:relative}
.kicker{font-family:var(--f-disp);font-weight:700;text-transform:uppercase;letter-spacing:.2em;
  font-size:1rem;margin:0 0 1rem;color:var(--brand-hi);display:flex;align-items:center;gap:.75rem}
.kicker::before{content:"";width:2.4rem;height:2px;background:currentColor;flex:none}
.kicker.dark{color:var(--brand)}
.kicker a{color:inherit}
.hero h1{font-family:var(--f-disp);font-weight:900;text-transform:uppercase;
  font-size:clamp(3.2rem,11.5vw,9.5rem);line-height:.83;letter-spacing:-.005em;margin:0;
  max-width:16ch;text-wrap:balance;text-shadow:0 6px 40px rgba(0,0,0,.35)}
.hero h1 .hl{color:var(--brand-hi);display:block}
.hero .lede{font-size:clamp(1.05rem,1.7vw,1.32rem);max-width:46ch;margin:1.5rem 0 0;
  color:#e7efe8;line-height:1.6}

/* ======================================================== typography */
.eyebrow{display:flex;align-items:center;gap:.75rem;font-family:var(--f-disp);font-weight:700;
  text-transform:uppercase;letter-spacing:.19em;font-size:.98rem;color:var(--brand-txt);margin:0 0 1.1rem}
.eyebrow .n{font-size:.78rem;letter-spacing:.1em;opacity:.6}
.eyebrow::after{content:"";height:1px;flex:1;background:var(--line);max-width:9rem}
.shead{font-size:clamp(2rem,4.4vw,3.5rem);margin:0 0 1.2rem;max-width:19ch;text-wrap:balance}
.shead.sm{font-size:clamp(1.6rem,2.8vw,2.3rem);max-width:22ch}
.sec-head{display:flex;align-items:flex-end;justify-content:space-between;gap:2rem;flex-wrap:wrap}
.sec-head .shead{margin-bottom:1.6rem}
.lede-2{font-size:clamp(1.02rem,1.35vw,1.16rem);color:var(--ink-2);margin:0;max-width:56ch}
.lede-xl{font-size:clamp(1.25rem,2.4vw,1.85rem);line-height:1.42;letter-spacing:-.018em;
  font-family:var(--f-head);font-weight:500;color:var(--ink);max-width:30ch;margin:0}
.lead-in{padding-bottom:0}

/* ============================================================ intro */
.intro-grid{display:grid;gap:clamp(1.2rem,3vw,3.5rem);grid-template-columns:1fr;
  align-items:end;margin-bottom:clamp(2.2rem,5vw,4rem)}
@media(min-width:900px){.intro-grid{grid-template-columns:1.15fr .85fr}}
.crafts{display:grid;gap:1px;background:var(--line);border-block:1px solid var(--line);
  grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}
.craft{background:var(--paper);padding:clamp(1.6rem,2.6vw,2.4rem) clamp(1.2rem,2vw,2rem)}
.craft-n{font-family:var(--f-disp);font-weight:900;font-size:1.1rem;letter-spacing:.14em;
  color:var(--brand-txt);margin:0 0 .7rem}
.craft h3{font-family:var(--f-disp);font-weight:900;text-transform:uppercase;letter-spacing:.01em;
  font-size:clamp(1.7rem,2.6vw,2.2rem);margin:0 0 .55rem;line-height:1}
.craft p{margin:0;color:var(--ink-2);font-size:.97rem}

/* ========================================================== pillars */
.pillars{display:grid;gap:clamp(.9rem,1.6vw,1.4rem);
  grid-template-columns:repeat(auto-fit,minmax(258px,1fr))}
.pillar{position:relative;overflow:hidden;background:var(--surface);border:1px solid var(--line);
  border-radius:var(--r);padding:1.7rem 1.6rem 1.9rem;
  transition:transform .4s var(--ease),box-shadow .4s var(--ease),border-color .4s}
.pillar::before{content:"";position:absolute;left:0;bottom:0;height:3px;width:0;
  background:linear-gradient(90deg,var(--brand),var(--brand-hi));transition:width .5s var(--ease)}
.pillar:hover{transform:translateY(-5px);box-shadow:var(--sh);border-color:var(--line-2)}
.pillar:hover::before{width:100%}
.pill-n{font-family:var(--f-disp);font-weight:700;font-size:.9rem;letter-spacing:.16em;
  color:var(--brand-txt);margin:0 0 .8rem}
.pillar h3{font-size:1.22rem;margin:0 0 .5rem;letter-spacing:-.02em}
.pillar p{margin:0;font-size:.94rem;color:var(--ink-2)}

/* ============================================================ tiers */
.tiers{display:grid;gap:clamp(.9rem,1.7vw,1.5rem);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,290px),1fr))}
.tier{position:relative;display:block;border-radius:var(--r-lg);overflow:hidden;
  aspect-ratio:4/5;color:#fff;text-decoration:none;isolation:isolate;background:var(--paper-2)}
.tier img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:-2;
  transition:transform .9s var(--ease)}
.tier::after{content:"";position:absolute;inset:0;z-index:-1;transition:opacity .5s;
  background:linear-gradient(180deg,rgba(3,12,7,.06) 0%,rgba(3,12,7,.34) 34%,
    rgba(3,12,7,.78) 62%,rgba(3,12,7,.95) 84%,rgba(3,12,7,.97) 100%)}
.tier:hover img{transform:scale(1.07)}
.tier:hover::after{opacity:.9}
.t-body{position:absolute;inset:auto 0 0 0;padding:clamp(1.4rem,2.4vw,2rem)}
.t-body h3{font-family:var(--f-disp);font-weight:900;text-transform:uppercase;
  font-size:clamp(2rem,3.4vw,2.7rem);line-height:.95;margin:.55rem 0 .5rem;letter-spacing:.005em}
.t-body p{margin:0 0 1rem;font-size:.94rem;color:#dfe8e1;max-width:32ch}
.chip{display:inline-block;align-self:flex-start;font-size:.7rem;font-weight:700;letter-spacing:.15em;
  text-transform:uppercase;padding:.34rem .7rem;border-radius:999px;
  background:color-mix(in srgb,var(--brand) 16%,transparent);color:var(--brand-txt);
  border:1px solid color-mix(in srgb,var(--brand) 35%,transparent)}
:root[data-theme=dark] .chip{color:var(--brand-hi)}
@media (prefers-color-scheme:dark){:root:not([data-theme=light]) .chip{color:var(--brand-hi)}}
.chip.light{background:rgba(255,255,255,.14);color:#fff;border-color:rgba(255,255,255,.3);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.more{font-size:.79rem;font-weight:700;letter-spacing:.13em;text-transform:uppercase;color:var(--brand-txt)}
.tier .more{color:var(--brand-hi)}
.more.lg{font-size:.86rem;text-decoration:none;white-space:nowrap}
.more.lg:hover{text-decoration:underline}

/* ========================================================= services */
.svcs{display:grid;gap:clamp(.9rem,1.6vw,1.35rem);
  grid-template-columns:repeat(auto-fit,minmax(310px,1fr));margin-top:2rem}
.svc{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:1.7rem 1.65rem;transition:transform .4s var(--ease),box-shadow .4s var(--ease),border-color .4s}
.svc:hover{transform:translateY(-4px);box-shadow:var(--sh);border-color:var(--line-2)}
.svc-head{display:flex;align-items:baseline;justify-content:space-between;gap:1rem;margin-bottom:.7rem}
.svc h3{font-size:1.16rem;margin:0;letter-spacing:-.02em}
.svc p{margin:0;font-size:.94rem;color:var(--ink-2)}
.tier-badge{font-family:var(--f-disp);font-weight:900;font-size:1.05rem;letter-spacing:.06em;
  color:var(--brand-txt);flex:none}
.legend{font-size:.84rem;color:var(--muted);margin:1.6rem 0 0;max-width:60ch}

/* =========================================================== split */
.split{display:grid;gap:clamp(1.5rem,4vw,4rem);align-items:center;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,320px),1fr))}
.split p{color:var(--ink-2)}
.framed{margin:0;border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--sh-lg)}
.framed img{width:100%}

/* ========================================================= gallery */
.gallery-sec{padding-bottom:clamp(3rem,7vw,6rem)}
.gallery-sec .shead{margin-bottom:2.4rem}
.marquee{--mq-dur:78s;overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 5%,#000 95%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 5%,#000 95%,transparent)}
.mq-track{display:flex;gap:clamp(.7rem,1.3vw,1.1rem);width:max-content;
  animation:mq var(--mq-dur) linear infinite}
/* the button is the only thing that stops the strip — hovering does not, so
   moving the cursor across the photographs (or the night-walk light) never
   changes what the gallery is doing */
.marquee.paused .mq-track{animation-play-state:paused}
@keyframes mq{to{transform:translate3d(-50%,0,0)}}

/* speed control */
.mq-ctl{display:flex;align-items:center;justify-content:center;gap:.3rem;margin:1.5rem auto 0;
  padding:.32rem;width:fit-content;border:1px solid var(--line);border-radius:999px;
  background:var(--surface)}
.mq-ctl button{font:inherit;font-size:.78rem;font-weight:700;letter-spacing:.09em;
  color:var(--muted);background:none;border:0;cursor:pointer;border-radius:999px;
  padding:.42rem .82rem;line-height:1;display:grid;place-items:center;
  transition:background .22s,color .22s}
.mq-ctl button:hover{color:var(--ink);background:var(--paper-2)}
.mq-ctl button.on{background:var(--brand);color:#03130c}
.mq-ctl button svg{width:15px;height:15px;display:block}
.mq-ctl .i-play{display:none}
.mq-ctl button[data-mq].on .i-pause{display:none}
.mq-ctl button[data-mq].on .i-play{display:block}
.mq-sep{width:1px;height:18px;background:var(--line);flex:none}

/* night walk — the strip alone goes dark and you walk the rows by headlamp,
   while the rest of the page stays lit. Scoped to .marquee, which already
   forms a stacking context because of its edge mask, so the blended layer
   stays inside the strip instead of tinting the page. */
.marquee{position:relative;--nw-r:clamp(130px,15vmin,200px)}
.nw-dark,.nw-hue{position:absolute;inset:0;pointer-events:none;
  opacity:0;visibility:hidden;transition:opacity .45s ease,visibility .45s}
.marquee.night .nw-dark,.marquee.night .nw-hue{opacity:1;visibility:visible}
/* the strip's soft edge mask would fade the blackout too, which reads as pale
   smudges at both ends on a light page */
.marquee.night{-webkit-mask-image:none;mask-image:none}
.nw-dark{z-index:3;background:#000;
  -webkit-mask-image:radial-gradient(circle var(--nw-r) at var(--nx,50%) var(--ny,50%),
    rgba(0,0,0,.04) 0%,rgba(0,0,0,.28) 45%,rgba(0,0,0,.9) 80%,#000 100%);
  mask-image:radial-gradient(circle var(--nw-r) at var(--nx,50%) var(--ny,50%),
    rgba(0,0,0,.04) 0%,rgba(0,0,0,.28) 45%,rgba(0,0,0,.9) 80%,#000 100%)}
.nw-hue{z-index:4;mix-blend-mode:color;
  background:radial-gradient(circle var(--nw-r) at var(--nx,50%) var(--ny,50%),
    rgba(12,183,109,.96) 0%,rgba(12,183,109,.8) 58%,transparent 88%)}
.marquee.night .mq-track figcaption{opacity:0;transition:opacity .3s}
/* The strip gets the same torch, but only where there is a cursor to replace.
   On a phone the night walk is left exactly as it is — a torch small enough to
   sit in a 200px strip fights the thumb for the same space, and the page-wide
   one already carries the idea. */
/* Its own width and angle, not the page-wide ones: the strip is a ~200px
   window, and a touchscreen laptop must not hand it the thumb pose. The
   fallback is 0px rather than 50% because the box is 0x0 and a percentage of
   nothing is nothing — JS sets real pixels the moment night walk turns on. */
.nw-lamp{display:none;position:absolute;left:0;top:0;width:0;height:0;z-index:5;
  --lo-lamp-w:clamp(118px,11vmin,158px);--lo-lamp-rot:38deg;
  pointer-events:none;opacity:0;visibility:hidden;
  transform:translate3d(var(--nx,0px),var(--ny,0px),0);
  transition:opacity .35s ease,visibility .35s}
.nw-lamp::before{content:"";position:absolute;left:-2.5px;top:-2.5px;
  width:5px;height:5px;border-radius:50%;
  background:#e8fff4;box-shadow:0 0 12px 2px rgba(24,224,140,.85)}
@media (hover:hover) and (pointer:fine){
  .nw-lamp{display:block}
  .marquee.night .nw-lamp{opacity:1;visibility:visible}
  /* the arrow would be a second pointer inside a strip that already has one */
  .marquee.night,.marquee.night *{cursor:none}
}
.nw-btn{font:inherit;font-size:.78rem;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:var(--muted);background:none;border:0;cursor:pointer;
  border-radius:999px;padding:.42rem .82rem;display:inline-flex;align-items:center;
  gap:.4rem;line-height:1;transition:background .22s,color .22s}
.nw-btn:hover{color:var(--ink);background:var(--paper-2)}
.nw-btn[aria-pressed=true]{background:var(--brand);color:#03130c}
.nw-btn svg{width:15px;height:15px;flex:none}
/* with the whole room already blacked out, a second flashlight is meaningless */
:root.js.lightsout .nw-btn,:root.js.lightsout .mq-ctl .mq-sep:last-of-type{display:none}
/* the same fight as lights out, in a smaller room: a finger inspecting the
   strip should not also be scrolling the strip off the screen */
:root.js .marquee.night{touch-action:none;touch-action:pinch-zoom}
.mq-track figure{position:relative;margin:0;flex:none;width:clamp(240px,27vw,380px);
  aspect-ratio:3/2;border-radius:var(--r);overflow:hidden;background:var(--paper-2)}
.mq-track img{width:100%;height:100%;object-fit:cover;transition:transform .8s var(--ease)}
.mq-track figure:hover img{transform:scale(1.06)}
.mq-track figcaption{position:absolute;inset:auto 0 0 0;padding:1.6rem .95rem .8rem;
  font-size:.76rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:#fff;
  background:linear-gradient(to top,rgba(3,12,7,.85),transparent)}

/* ========================================================= partners */
.partners-sec .sec-head{align-items:flex-start;gap:1.4rem}
.partners-sec .lede-2{max-width:40ch}
.plogos{display:grid;gap:clamp(.7rem,1.2vw,1rem);margin-top:2.4rem;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,168px),1fr))}
.plogo{display:grid;place-items:center;background:#fff;border:1px solid var(--line);
  border-radius:14px;padding:1.1rem 1.3rem;min-height:104px;
  transition:transform .35s var(--ease),border-color .35s,box-shadow .35s}
/* Grey-until-hover is the original site's own `.client-logo` behaviour. The
   Gorilla mark is light art on transparency, so it needs the contrast bump to
   hold its weight next to five dark-on-white logos. */
.plogo img{width:100%;max-width:150px;height:auto;object-fit:contain;
  filter:grayscale(1) contrast(1.15);opacity:.72;transition:filter .35s,opacity .35s}
.plogo:hover{transform:translateY(-3px);border-color:var(--brand);box-shadow:var(--sh)}
/* A logo with nowhere to go. It stays on the wall, but it must not behave like
   a link — no lift, no pointer, no focus stop. */
.plogo.off,.plogo.off:hover{transform:none;border-color:var(--line);box-shadow:none;cursor:default}
.plogo:hover img{filter:none;opacity:1}
/* The cards stay white in the dark theme too. A black-card treatment (raster
   inverted to white-on-black) went in on 08-06 and Uriel reverted it the same
   day — the white wall is the intended look on both themes. */

/* ============================================================ posts */
.posts{display:grid;gap:clamp(.9rem,1.7vw,1.5rem);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,330px),1fr))}
.post-card{text-decoration:none;background:var(--surface);border:1px solid var(--line);
  border-radius:var(--r-lg);overflow:hidden;display:flex;flex-direction:column;
  transition:transform .4s var(--ease),box-shadow .4s var(--ease),border-color .4s}
.post-card:hover{transform:translateY(-5px);box-shadow:var(--sh);border-color:var(--line-2)}
.pc-img{overflow:hidden;aspect-ratio:3/2;background:var(--paper-2)}
.pc-img img{width:100%;height:100%;object-fit:cover;transition:transform .8s var(--ease)}
.post-card:hover .pc-img img{transform:scale(1.05)}
.pc-body{padding:1.3rem 1.35rem 1.5rem;display:flex;flex-direction:column;gap:.6rem;flex:1}
.post-card h3{font-size:1.28rem;margin:0;line-height:1.2}
.post-card p{margin:0;font-size:.92rem;color:var(--ink-2);flex:1}
.feature{display:grid;gap:0;text-decoration:none;background:var(--surface);
  border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;
  grid-template-columns:1fr;transition:transform .4s var(--ease),box-shadow .4s var(--ease)}
@media(min-width:860px){.feature{grid-template-columns:1.1fr .9fr}}
.feature:hover{transform:translateY(-4px);box-shadow:var(--sh-lg)}
.f-img{overflow:hidden;min-height:260px;background:var(--paper-2)}
.f-img img{width:100%;height:100%;object-fit:cover;transition:transform .9s var(--ease)}
.feature:hover .f-img img{transform:scale(1.05)}
.f-body{padding:clamp(1.6rem,3vw,3rem);display:flex;flex-direction:column;gap:.85rem;
  align-items:flex-start;justify-content:center}
.f-body h2{font-size:clamp(1.7rem,3.2vw,2.6rem);margin:0}
.f-body p{margin:0;color:var(--ink-2);max-width:44ch}

/* ============================================================= post */
.post-head{padding-top:clamp(1.6rem,4vw,3rem)}
.post h1{font-size:clamp(2.1rem,5vw,3.6rem);margin:.25em 0 .4em;text-wrap:balance}
.post .dek{font-size:1.16rem;color:var(--muted);margin:0;max-width:52ch}
figure.wide{width:var(--wrap);margin:clamp(1.8rem,4vw,3rem) auto;border-radius:var(--r-lg);
  overflow:hidden;box-shadow:var(--sh-lg)}
figure.wide img{width:100%;max-height:min(66vh,620px);object-fit:cover}
.prose{font-size:1.06rem}
.prose h2,.prose h3,.prose h4{margin:2.4rem 0 .7rem;letter-spacing:-.025em}
/* Article subheads. These are the author's own sentence-length lines, so they
   keep the Passion One treatment they had as h4s — the levels changed, the
   look did not. */
.prose h2,.prose h3,.prose h4{font-family:var(--f-disp);font-weight:700;letter-spacing:.005em;
  color:var(--brand-txt);line-height:1.2}
.prose h2{font-size:1.5rem}.prose h3{font-size:1.3rem}.prose h4{font-size:1.18rem}
.prose p{margin:0 0 1.2rem;color:var(--ink-2)}
.prose a{color:var(--brand-txt);font-weight:600}
.prose figure{margin:2.2rem 0;border-radius:var(--r);overflow:hidden}
.prose ul{padding-left:1.15rem;color:var(--ink-2)}
.prose li{margin:.35rem 0}
.prose li::marker{color:var(--brand-txt)}
.post-note{font-size:.9rem;color:var(--ink-2);background:var(--paper-2);
  border:1px solid var(--line);border-left:3px solid var(--brand);
  border-radius:0 var(--r) var(--r) 0;padding:.95rem 1.15rem;margin:0 0 2rem}
.legal{font-size:.98rem}
.legal h1{font-size:clamp(1.9rem,4vw,2.8rem);margin:.2em 0 .6rem}
.legal .updated{font-size:.82rem;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted);margin:0 0 2.4rem}
.legal .big{font-size:1.16rem;line-height:1.6;color:var(--ink);
  border-left:3px solid var(--brand);padding-left:1.1rem;margin-bottom:2.4rem}
.legal h2{font-size:1.3rem;margin-top:2.6rem}
.legal code{font-size:.9em;background:var(--paper-2);border:1px solid var(--line);
  border-radius:5px;padding:.1em .38em}

/* ============================================================ band */
.band{position:relative;overflow:hidden;background:var(--forest);color:#e9f5ee;
  padding-block:clamp(3.4rem,8vw,6.5rem);text-align:center}
/* Flat --forest, no glow. There was a green uplight in here and it is gone —
   the fade that carries this section into the footer is not its job and never
   was: it lives at the top of .foot, where --forest gives way to the soil. Both
   sides meeting on one flat colour is exactly why that transition works. */
.band h2{font-family:var(--f-disp);font-weight:900;text-transform:uppercase;
  font-size:clamp(2.4rem,7vw,5rem);line-height:.92;margin:0 0 .5rem;color:#fff}
.band p{max-width:54ch;margin:0 auto 2.2rem;color:#c3dccd}
.btn{display:inline-block;background:var(--brand);color:#03130c;text-decoration:none;
  padding:.9rem 1.9rem;border-radius:999px;font-weight:700;font-size:.88rem;letter-spacing:.09em;
  text-transform:uppercase;border:0;cursor:pointer;font-family:var(--f-body);
  transition:background .25s,transform .25s var(--ease),box-shadow .25s}
.btn:hover{background:var(--brand-hi);transform:translateY(-2px);
  box-shadow:0 12px 30px -10px rgba(12,183,109,.6)}
.btn.big{padding:1.05rem 2.4rem;font-size:.94rem}
.btn.ghost{background:none;color:var(--ink);border:1px solid var(--line-2)}
.btn.ghost:hover{background:var(--paper-2);box-shadow:none}

/* ========================================================= contact */
.contact-grid{display:grid;gap:clamp(1.6rem,4vw,4rem);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,320px),1fr));align-items:start}
.form{display:grid;gap:1.05rem;margin-top:1.8rem;max-width:34rem}
.form label{display:grid;gap:.42rem;font-size:.76rem;font-weight:700;letter-spacing:.13em;
  text-transform:uppercase;color:var(--muted)}
.form input,.form select,.form textarea{font:inherit;font-size:1rem;color:var(--ink);
  background:var(--surface);border:1px solid var(--line);border-radius:12px;padding:.8rem .95rem;
  width:100%;transition:border-color .25s,box-shadow .25s}
.form input:focus,.form select:focus,.form textarea:focus{outline:0;border-color:var(--brand-txt);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--brand) 22%,transparent)}
.form textarea{resize:vertical}
.form .btn{justify-self:start}
.form-note{font-size:.82rem;color:var(--muted);margin:0}

/* ---- smoke session request ----------------------------------------- */
/* Same machinery as the contact form: it composes an email and hands it to the
   visitor's own mail client. Nothing is submitted, stored or booked here —
   the copy says so, because a form that looks like a live calendar and is not
   would be a lie. */
.btn.sm{font-size:.76rem;padding:.6rem 1.05rem;margin-top:1.1rem}
.sched{display:grid;gap:.85rem;margin-top:1.1rem;padding-top:1.1rem;
  border-top:1px solid var(--line)}
.sched[hidden]{display:none}
/* end-aligned so a two-line label never drags its field out of line with the
   one beside it */
.sched-row{display:grid;gap:.85rem;grid-template-columns:1fr 1fr;align-items:end}
.sched label{display:grid;gap:.4rem;font-size:.72rem;font-weight:700;letter-spacing:.13em;
  text-transform:uppercase;color:var(--muted)}
.sched .tz{font-weight:600;letter-spacing:.06em;opacity:.75}
.sched input,.sched select,.sched textarea{font:inherit;font-size:.95rem;color:var(--ink);
  background:var(--paper);border:1px solid var(--line-2);border-radius:12px;
  padding:.62rem .75rem;width:100%;text-transform:none;letter-spacing:normal;font-weight:400}
.sched textarea{resize:vertical}
/* the age affirmation reads as a sentence, not as a field label */
.sched .check{display:flex;align-items:center;gap:.6rem;font-size:.85rem;font-weight:400;
  letter-spacing:normal;text-transform:none;color:var(--ink-2)}
.sched .check input{width:auto;accent-color:var(--brand);flex:none;margin:0;padding:0}
.sched input:focus,.sched select:focus,.sched textarea:focus{outline:0;
  border-color:var(--brand-txt);box-shadow:0 0 0 3px color-mix(in srgb,var(--brand) 22%,transparent)}
@media (max-width:560px){.sched-row{grid-template-columns:1fr}}
.contact-side{display:grid;gap:1rem}
.card-quiet{background:var(--paper-2);border:1px solid var(--line);border-radius:var(--r-lg);
  padding:1.6rem 1.65rem}
.card-lead{position:relative;overflow:hidden;border-radius:var(--r-lg);padding:1.6rem 1.65rem;
  background:var(--surface);border:1px solid color-mix(in srgb,var(--brand) 42%,var(--line))}
.card-lead::before{content:"";position:absolute;inset:0 auto 0 0;width:4px;
  background:linear-gradient(180deg,var(--brand),var(--brand-hi))}
.cl-head{display:flex;align-items:center;justify-content:space-between;gap:1rem;margin-bottom:.5rem}
.cl-head .lbl{margin:0}
.card-lead h3{font-family:var(--f-disp);font-weight:900;text-transform:uppercase;
  font-size:clamp(1.5rem,2.6vw,2rem);line-height:1;margin:0 0 .6rem}
.card-lead p{margin:0;color:var(--ink-2);font-size:.95rem}
.card-quiet .big{font-size:1.16rem;font-weight:700;margin:.2rem 0 .8rem;word-break:break-word}
.card-quiet .big a{color:var(--brand-txt);text-decoration:none}
.card-quiet .big a:hover{text-decoration:underline}
.card-quiet p:last-child{margin-bottom:0}
.lbl{font-family:var(--f-disp);font-weight:700;font-size:.85rem;letter-spacing:.19em;
  text-transform:uppercase;color:var(--brand-txt);margin:0 0 .55rem}
.soc-row{display:flex;align-items:center;gap:.8rem;padding:.72rem 0;text-decoration:none;
  border-top:1px solid var(--line);font-weight:600;font-size:.96rem}
.soc-row:first-of-type{border-top:0}
.soc-row svg{width:20px;height:20px;color:var(--brand-txt);flex:none}
.soc-row .arw{margin-left:auto;color:var(--muted);transition:transform .3s var(--ease)}
.soc-row:hover .arw{transform:translateX(4px);color:var(--brand-txt)}

/* ============================================================= 404 */
.nf{padding-top:clamp(2rem,6vw,4rem);min-height:56svh}
.nf h1{font-size:clamp(2rem,5.4vw,3.4rem);margin:.2em 0 .6em;max-width:16ch}
.nf p{color:var(--ink-2)}
.nf-btns{display:flex;gap:.7rem;flex-wrap:wrap;margin-top:2rem}

/* ========================================================== footer */
/* The soil is the whole footer now, not a fill inside the wordmark.
   On the photograph itself: it is genuinely this dark — mean rgb 47,44,40,
   17% luminance, 15% saturation, a warm 37deg hue. Nothing was draining it.
   What made it read grey was the 30% pale-mint wash the wordmark laid over it,
   which lifted it to 40% luminance AND pushed green past red, turning warm
   near-black soil into cold green-grey. The wash is gone; this is the original.
   The scrim over it is NEUTRAL, not green. A green wash was what made the
   photograph read grey in the first place, and a fainter one over the whole
   footer did the same thing more quietly — black darkens the soil without
   touching its colour, so it stays warm near-black earth rather than turning
   into a green field. The forest at the very top is the only exception and it
   is not decoration: it is the two or three percent it takes to meet the band
   above on the same value, so the seam has nothing to show. */
/* The forest at the top exists ONLY to meet the green CTA band, and most pages
   do not end with one — blog, contact, the legal pages, the posts, the 404. On
   those it arrived as a green stripe from nowhere, which is exactly how Uriel
   found it. So the default is to open straight onto the soil, and the cap is
   put back by `body:has(.band)`, which is self-maintaining: add a band to a
   page and its footer fades to meet it, drop the band and the fade goes too.
   Nothing to remember to set per page. Without :has() support every page gets
   the capless version, which is the one that is right nearly everywhere. */
.foot{position:relative;isolation:isolate;background:var(--forest);color:#eef6f0;
  padding-top:clamp(3rem,7vw,5.5rem);overflow:hidden;
  --foot-cap:rgba(0,0,0,.62);--foot-cap-2:rgba(0,0,0,.6)}
body:has(.band) .foot{--foot-cap:var(--forest);--foot-cap-2:rgba(4,40,26,.8)}
.foot::before{content:"";position:absolute;inset:0;z-index:-1;background:
  linear-gradient(to bottom,var(--foot-cap) 0,var(--foot-cap-2) 3%,rgba(0,0,0,.6) 11%,
    rgba(0,0,0,.66) 58%,rgba(0,0,0,.76) 100%),
  url(/assets/img/2018/09/Soil.jpg) center/cover}
.foot-top{display:grid;gap:clamp(2rem,5vw,4rem);grid-template-columns:1fr}
@media(min-width:900px){.foot-top{grid-template-columns:1fr 1.1fr}}
.foot h2{font-family:var(--f-disp);font-weight:900;text-transform:uppercase;color:#fff;
  font-size:clamp(1.7rem,3.1vw,2.5rem);line-height:.96;margin:0 0 1rem}
.foot .eyebrow{color:var(--brand-hi)}
.foot .eyebrow::after{background:rgba(255,255,255,.16)}
/* White throughout, which is what these were only reaching on hover. The muted
   greens were tuned against flat forest; over a photograph they sit too close
   to the grain to read. Hover moves to brand green now, since white is taken. */
.foot-lede{max-width:46ch;margin:0 0 1.9rem;color:#eef6f0}
.foot-cols{display:grid;gap:2rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,168px),1fr));
  align-content:start}
.foot .lbl{color:var(--brand-hi)}
.fnav{display:flex;flex-direction:column;gap:.55rem;margin:0}
.fnav a{text-decoration:none;font-size:.94rem;color:#fff;width:fit-content;
  transition:color .2s,transform .25s var(--ease)}
.fnav a:hover{color:var(--brand-hi);transform:translateX(3px)}
.fsocial{display:flex;gap:.45rem;margin:0;flex-wrap:wrap}
.fsocial a{width:34px;height:34px;border-radius:50%;display:grid;place-items:center;
  border:1px solid rgba(255,255,255,.18);color:#d5e5da;
  transition:background .25s,color .25s,transform .25s var(--ease),border-color .25s}
.fsocial svg{width:19px;height:19px}
.fsocial a:hover{background:var(--brand);color:#03130c;border-color:var(--brand);transform:translateY(-2px)}
/* Solid white on the soil. Went outline, then white, then brand green, and back
   to white on a side-by-side — green sat back as furniture, white owns the foot
   of the page. Do not return it to an outline: a photograph eats a hairline,
   the grain runs straight over it and the letterforms stop resolving. */
.wordmark{font-family:var(--f-disp);font-weight:900;text-transform:uppercase;
  font-size:min(16.2vw,13.8rem);line-height:.8;margin:clamp(2rem,5vw,3.5rem) 0 0;
  color:#fff;letter-spacing:-.01em;user-select:none;white-space:nowrap}
.foot-bar{display:flex;justify-content:space-between;gap:1rem;flex-wrap:wrap;
  border-top:1px solid rgba(255,255,255,.12);margin-top:clamp(1.4rem,3vw,2.2rem);
  padding-block:1.2rem 1.6rem;font-size:.82rem;color:#eef6f0}
.foot-bar p{margin:0}
.foot-bar a{text-decoration:none;color:#fff}
.foot-bar a:hover{color:var(--brand-hi)}

/* ======================================================= lights out */
/* The dark period has to be total. The cursor becomes the green work light,
   because green is the one wavelength that will not pull a plant out of
   flower. Three stacked layers: darkness with a hole punched in it, a hue
   layer that greens whatever the hole reveals, and a soft bloom for the
   lamp itself. All three read one pair of coordinates, --lo-x / --lo-y. */
/* The three layers are siblings at body level, NOT wrapped: a wrapper with a
   z-index would form a stacking context, and the blended layers would then
   blend only with each other instead of with the page underneath. */
:root{--lo-x:50%; --lo-y:44%; --lo-r:clamp(155px,17vmin,250px)}
/* Every rule that blacks the page out is gated on `js`, which the head script
   sets on parse and takes back off after 2.5s unless site.js has checked in.
   Without that gate a stored `cg-lights` plus a script that never arrives is a
   black page with a beam nobody can move — and now that the arrow is hidden
   too, one with no visible cursor either. A dead script must cost the visitor
   an effect, never the page. */
/* `inset:0` is not the whole screen on a phone. iOS Safari sizes fixed elements
   to the viewport with its toolbar showing, but keeps painting page content
   into the taller area the toolbar uncovers — so a strip along the bottom
   stayed lit while everything above it went dark. Desktop never shows it,
   because nothing there retracts.
   Deliberately overshot rather than fitted. `vh` on iOS is already the toolbar-
   retracted height, so 125vh clears the uncovered strip and the rubber-band
   overscroll under it as well, and no viewport unit can come up short the way a
   fitted one can. It costs nothing: these layers are pointer-events:none and
   the viewport clips whatever hangs past it.
   It has to be a HEIGHT growing down from top:0 — never a negative `bottom`,
   never a shifted top — because the beam is placed by --lo-y, which is measured
   from the viewport's top edge. Move the top and the light stops tracking. */
.lo-dark,.lo-hue,.lo-bloom{position:fixed;inset:0;pointer-events:none;
  height:125vh;
  opacity:0;visibility:hidden;transition:opacity .55s ease,visibility .55s}
:root.js.lightsout .lo-dark,:root.js.lightsout .lo-hue,:root.js.lightsout .lo-bloom{
  opacity:1;visibility:visible}
.lo-dark{z-index:9990;background:#000;
  -webkit-mask-image:radial-gradient(circle var(--lo-r) at var(--lo-x) var(--lo-y),
    rgba(0,0,0,.05) 0%,rgba(0,0,0,.26) 44%,rgba(0,0,0,.88) 78%,#000 100%);
  mask-image:radial-gradient(circle var(--lo-r) at var(--lo-x) var(--lo-y),
    rgba(0,0,0,.05) 0%,rgba(0,0,0,.26) 44%,rgba(0,0,0,.88) 78%,#000 100%)}
.lo-hue{z-index:9991;mix-blend-mode:color;
  background:radial-gradient(circle var(--lo-r) at var(--lo-x) var(--lo-y),
    rgba(12,183,109,.96) 0%,rgba(12,183,109,.82) 58%,rgba(12,183,109,0) 88%)}
.lo-bloom{z-index:9992;mix-blend-mode:screen;
  background:radial-gradient(circle calc(var(--lo-r) * 1.15) at var(--lo-x) var(--lo-y),
    rgba(24,224,140,.16) 0%,rgba(12,183,109,.07) 40%,transparent 72%)}

/* Flood: the whole room under green work light. The beam re-centres so the
   falloff stays even, and it is the readable way to sit in the dark. There is
   no beam left to aim, so flood also hands back the arrow, the scroll and the
   torch — it is ordinary browsing that happens to be green. */
:root.lo-flood{--lo-x:50%;--lo-y:50%;--lo-r:165vmax}

/* The lamp. Two poses: held out in front of you for a mouse, stood up on end
   for a thumb, where the tail has to reach all the way back down to the
   fingertip. Positioned with a transform rather than left/top because it moves
   on every frame the beam does. */
/* --lo-hot is where along the sprite the beam actually lands, as a share of
   its width: 14% is out in the throw, well clear of the lens at 42%. Because
   it is a percentage, translate() and the dot below both resolve it against
   the sprite's own width, so the two poses stay in register at any size.
   The touch width is not a taste call — 110px is what puts the tail of the
   torch at the fingertip, TOUCH_LIFT below the beam. */
/* Two poses off one sprite: held out in front of you for a mouse, stood on end
   for a thumb. The touch width is not a taste call — 110px is what puts the
   tail of the sprite at the fingertip, TOUCH_LIFT below the beam. */
:root{--lo-hot:14%;--lo-lamp-w:clamp(146px,14vmin,196px);--lo-lamp-rot:38deg}
:root.lo-touch{--lo-lamp-w:110px;--lo-lamp-rot:80deg}
.lo-lamp{position:fixed;left:0;top:0;width:0;height:0;z-index:10000;
  pointer-events:none;opacity:0;visibility:hidden;
  transform:translate3d(var(--lo-px,50vw),var(--lo-py,44vh),0);
  transition:opacity .4s ease,visibility .4s}
:root.js.lightsout:not(.lo-flood) .lo-lamp{opacity:1;visibility:visible}
/* The angle lives on its own box, the position on the parent. Never transition
   this: it composes with the parent's tracking transform, so any easing here
   smears the beam's own movement, which is the one thing it cannot afford. */
.lo-arm,.nw-arm{position:absolute;left:0;top:0;width:var(--lo-lamp-w);
  transform-origin:0 0;
  transform:rotate(var(--lo-lamp-rot)) translate(calc(var(--lo-hot) * -1),-50%)}
.lo-arm svg,.nw-arm svg{display:block;width:100%;height:auto;
  filter:drop-shadow(0 0 9px rgba(20,224,140,.45))}
/* The hot spot, sitting exactly where the pointer is. The lens is held back
   off the aim point so the torch never covers what you are pointing at, which
   leaves the aim point itself unmarked — and with the arrow gone, unmarked
   means links get harder to hit. This is the mark. It hangs off the outer box,
   not the arm, so the pickup swing never drags the aim point around with it. */
.lo-lamp::before{content:"";position:absolute;left:-2.5px;top:-2.5px;
  width:5px;height:5px;border-radius:50%;
  background:#e8fff4;box-shadow:0 0 12px 2px rgba(24,224,140,.85)}

/* With a torch drawn on screen the arrow is redundant, and two pointers is one
   too many. The panel keeps a real cursor: the way out of a blacked-out room
   has to behave like a control. */
:root.js.lightsout:not(.lo-flood) body,
:root.js.lightsout:not(.lo-flood) body *{cursor:none}
:root.js.lightsout:not(.lo-flood) .lo-panel,
:root.js.lightsout:not(.lo-flood) .lo-panel *,
:root.js.lightsout:not(.lo-flood) .theme,
:root.js.lightsout:not(.lo-flood) .theme *{cursor:pointer}

/* Lights out on a phone: the light drives the scroll, because the two gestures
   were fighting over one finger — the drag aimed the beam and the browser
   scrolled the page out from under it at the same time. Holding the page still
   is half of that fix; site.js supplies the other half. `pinch-zoom` keeps the
   pinch alive, and the `none` in front of it is the fallback for engines that
   do not know the keyword. */
:root.js.lightsout:not(.lo-flood),
:root.js.lightsout:not(.lo-flood) body{touch-action:none;touch-action:pinch-zoom}

/* The page scrolls smoothly for anchor links, which is wrong for a stick: every
   frame's scrollBy would start its own eased animation and the next frame would
   retarget it, so the page crawls at a fraction of the speed asked for and
   scrollY stops answering synchronously — which in turn breaks the end-of-page
   check and takes the cue down with it. Instant while a finger is driving. */
:root.lo-driving{scroll-behavior:auto}

/* Scroll cue. Opacity tracks the throttle, so leaving the neutral band shows
   up immediately and full deflection is unmistakable. */
:root:not(.js) .lo-edge,:root:not(.lightsout) .lo-edge{display:none}
/* The chevron rides the INNER edge of the band, not the outer one: at the
   outer edge it lands underneath the panel, which sits in the same corner of
   a phone screen. The glow has to be strong to read at all — on a black page
   a fifth of an alpha is invisible, which is what the first pass shipped. */
.lo-edge{position:fixed;left:0;right:0;z-index:9993;height:min(26vh,200px);
  display:flex;justify-content:center;pointer-events:none;opacity:0;
  transition:opacity .12s linear}
.lo-edge.up{top:0;align-items:flex-end;padding-bottom:.35rem;
  background:linear-gradient(to bottom,rgba(24,224,140,.5),
    rgba(24,224,140,.15) 46%,rgba(24,224,140,0))}
.lo-edge.dn{bottom:0;align-items:flex-start;padding-top:.35rem;
  background:linear-gradient(to top,rgba(24,224,140,.5),
    rgba(24,224,140,.15) 46%,rgba(24,224,140,0))}
.lo-edge svg{width:34px;height:34px;stroke:#eafff4;stroke-width:2.4;
  stroke-linecap:round;stroke-linejoin:round;
  filter:drop-shadow(0 0 9px rgba(24,224,140,.9))}

/* The switch by the door. Above the darkness, and glowing, because a control
   you cannot find in a blacked-out room is not a control. */
/* The container takes no hits, only the buttons do. Its box spans the note, the
   gap and the buttons — on a phone that is the bottom quarter of the screen —
   and while it was hit-testable it swallowed every touch in that band, which is
   exactly where your finger has to sit to drive the light downward. */
.lo-panel{position:fixed;z-index:10001;display:none;flex-direction:column;align-items:flex-end;
  gap:.7rem;right:clamp(.9rem,3vw,2rem);bottom:clamp(.9rem,3vw,2rem);max-width:min(92vw,26rem);
  pointer-events:none}
:root.js.lightsout .lo-panel{display:flex}
.lo-btns{display:flex;gap:.5rem}
.lo-btn{pointer-events:auto}
.lo-btn{display:inline-flex;align-items:center;gap:.5rem;font:inherit;font-size:.78rem;
  font-weight:700;letter-spacing:.1em;text-transform:uppercase;cursor:pointer;
  padding:.72rem 1.05rem;border-radius:999px;color:#8df3bd;
  background:rgba(5,22,14,.88);border:1px solid rgba(20,224,140,.45);
  -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
  box-shadow:0 0 22px rgba(20,224,140,.28),0 0 0 6px rgba(20,224,140,.05);
  transition:background .25s,color .25s,box-shadow .25s,border-color .25s}
.lo-btn:hover{background:rgba(9,40,25,.95);color:#c6ffe0;box-shadow:0 0 30px rgba(20,224,140,.45)}
.lo-btn svg{width:16px;height:16px;flex:none}
.lo-btn[aria-pressed=true]{background:var(--brand);border-color:var(--brand);color:#03130c;
  box-shadow:0 0 34px rgba(20,224,140,.55)}
.lo-note{margin:0;font-size:.85rem;line-height:1.5;color:#b4efd0;text-align:right;
  background:rgba(4,18,11,.9);border:1px solid rgba(20,224,140,.3);border-radius:16px;
  padding:.85rem 1.05rem;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
  opacity:0;transform:translateY(8px);pointer-events:none;
  transition:opacity .5s ease,transform .5s ease}
.lo-note.show{opacity:1;transform:none}
.lo-note strong{color:#eafff3;font-weight:700}
.lo-hint{display:block;margin-top:.45rem;color:#7fd7a8;font-size:.8rem}
@media (max-width:560px){
  .lo-panel{left:clamp(.9rem,3vw,2rem);align-items:stretch}
  .lo-note{text-align:left}
  .lo-btns{justify-content:center}
  .lo-btn{flex:1;justify-content:center}
}
@media print{.lo-dark,.lo-hue,.lo-bloom,.lo-lamp,.lo-edge,.lo-panel{display:none!important}}

/* ========================================================== motion */
/* Hiding is gated on the `js` class, which the head script sets on parse and
   takes back off if site.js has not checked in within 2.5 seconds. Blocked,
   throttled or cached-corrupt script means no animation; it never means no
   content. Divi made exactly this mistake and the restoration had to undo it. */
.js .reveal{opacity:0;transform:translateY(22px);
  transition:opacity .8s var(--ease),transform .8s var(--ease)}
.reveal.in{opacity:1;transform:none}
.reveal:nth-child(2){transition-delay:.07s}
.reveal:nth-child(3){transition-delay:.14s}
.reveal:nth-child(4){transition-delay:.21s}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important;scroll-behavior:auto!important}
  .js .reveal{opacity:1;transform:none}
  .hero-bg{animation:none}
  /* the marquee can't scroll, so lay the gallery out as a static grid and
     drop the speed control rather than stranding half the photographs */
  .marquee{-webkit-mask-image:none;mask-image:none}
  .mq-track{width:100%;flex-wrap:wrap}
  .mq-track figure{width:calc(20% - 1rem)}
  .mq-track figure:nth-of-type(n+11){display:none}
  /* the playback controls have nothing left to control, but night walk is
     direct manipulation rather than motion, so it stays */
  .mq-ctl button[data-mq],.mq-sep{display:none}
}

/* ========================================================== mobile */
@media (max-width:900px){
  .nav nav{position:fixed;inset:0 0 auto 0;top:0;padding:5.2rem clamp(1.2rem,6vw,2.4rem) 2rem;
    flex-direction:column;gap:0;background:var(--paper);color:var(--ink);
    border-bottom:1px solid var(--line);transform:translateY(-101%);
    transition:transform .42s var(--ease);z-index:-1;margin:0}
  .nav.open nav{transform:none;box-shadow:var(--sh-lg)}
  .nav nav a{font-size:1.05rem;letter-spacing:.05em;padding:.95rem 0;
    border-bottom:1px solid var(--line);opacity:1;width:100%}
  .nav nav a::after{display:none}
  .nav nav a.on{color:var(--brand)}
  .burger{display:block}
  .nav-tail{margin-left:auto}
  .cta{display:none}
  /* the bar has no room for it, so the call to action moves inside the menu
     rather than disappearing on phones altogether */
  .nav nav a.cta-m{display:block;margin-top:1.6rem;border-bottom:0;text-align:center;
    color:#03130c;background:var(--brand);padding:.85rem 1.15rem;font-size:.82rem;
    letter-spacing:.15em;width:auto}
  .hero h1{font-size:clamp(2.9rem,14vw,5rem)}
  .wordmark{-webkit-text-stroke-width:1px}
}
@media (max-width:520px){
  body{font-size:16px}
  .theme{width:34px;height:34px}
  .brand{font-size:1.28rem;gap:.55rem}
}
