/* ============================================================
   CRITICAL: everything the first screen needs, and nothing else.

   These rules are not a copy. They were moved here out of
   pages.css and theme.css, so this file is the only place any
   of them lives; edit them here.

   index.html inlines this file verbatim, between the
   critical:start and critical:end markers, so the homepage can
   paint without waiting for a stylesheet request. Every other
   page links it. After editing, run:

     python tools/build_critical.py

   which re-pastes it into index.html. The pre-commit hook runs
   the same thing with --check and blocks the commit if the two
   have drifted, so this cannot go stale silently.

   Load order matters and is the same everywhere: this file
   first, then pages.css, then theme.css. That is the order the
   rules were in before they were moved.
   ============================================================ */

/* ---------- moved from pages.css ---------- */
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{font-family:var(--body);background:var(--bg);color:var(--ink);font-size:17.5px;line-height:1.7;-webkit-font-smoothing:antialiased;
  -webkit-user-select:none;user-select:none}
img{display:block;max-width:100%;-webkit-user-drag:none;-webkit-touch-callout:none}
/* selection returns where a guest genuinely copies things; pages.css repeats this */
input,textarea,select,.allow-copy,.allow-copy *{-webkit-user-select:text;user-select:text}
a{color:inherit;text-decoration:none}
button{font:inherit;cursor:pointer;border:none;background:none;color:inherit}
:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:2px}
::selection{background:var(--accent);color:var(--accent-ink)}
.kicker{font-family:var(--label);font-size:11.5px;letter-spacing:.28em;text-transform:uppercase;color:var(--kicker-c)}
h1,h2,h3{font-family:var(--display);font-weight:var(--display-weight,400);line-height:1.15;text-wrap:balance}
.btn{display:inline-block;background:var(--btn-bg);color:var(--btn-ink);padding:14px 26px;border-radius:var(--btn-radius);
  font-family:var(--label);font-size:13px;letter-spacing:var(--btn-track,.1em);text-transform:var(--btn-case,uppercase);font-weight:600;text-align:center}
.btn:hover{background:var(--btn-bg-h)}
.btn.ghost{background:none;border:1px solid var(--accent);color:var(--accent)}
.btn.ghost:hover{background:var(--accent);color:var(--accent-ink)}
/* reveal. Visible is the default and JS opts into hiding, via the .js class set by the
   inline head script. The animation is decoration, so it must never be what the text
   depends on: nearly every element on the site is .rv, and the old opacity:0 default
   meant a failed script, or a print, rendered the page as blank space. */
.rv{opacity:1;transform:none}
html.js .rv{opacity:0;transform:translateY(18px);transition:opacity .7s ease,transform .7s ease}
html.js .rv.in{opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){
html{scroll-behavior:auto}
html.js .rv{opacity:1;transform:none;transition:none}
}
@media print{
html.js .rv{opacity:1;transform:none;transition:none}
}
/* ---------- header ---------- */
.site-head{position:sticky;top:0;z-index:60;display:flex;align-items:center;gap:28px;
  padding:10px 40px;background:var(--head-bg);border-bottom:1px solid var(--head-line);
  -webkit-backdrop-filter:var(--head-blur);backdrop-filter:var(--head-blur)}
.brand{display:block;font-family:var(--display);color:var(--head-ink);line-height:1.1}
.brand small{display:block;font-family:var(--label);font-size:9px;letter-spacing:.3em;text-transform:uppercase;opacity:.7;margin-top:2px}
/* The header's link home is a drawn house, not the wordmark. The page it leads
   to opens on the wordmark at full size, so the corner was saying the same
   thing twice, and on a phone the word was competing with the menu button for
   the same 40px. The footer keeps the wordmark: nothing there repeats it. */
/* 30px, the height of the Sole/Luna pill and the Menu button beside it, and
   36px where those two grow to 36. Matching them is not only how it looks
   right: below 1061px the nav is hidden and those buttons are the tallest
   things in the bar, so an icon any taller than them would set the header's
   height, and the hero parks its waterline one measured header-height down the
   screen (see --head-h further down). Level with the pills, it costs nothing.
   The padding is horizontal for the same reason. Room to the sides is free;
   room above and below moves the horizon on every phone. */
.brand.home-link{display:flex;align-items:center;padding:0 4px;margin-left:-4px;opacity:.85}
.brand.home-link svg{display:block;width:30px;height:30px;fill:none;stroke:currentColor;
  stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}
.brand.home-link:hover{opacity:1}
.site-nav{display:flex;gap:22px;margin-left:auto;font-size:13.5px;color:var(--head-ink)}
/* Home belongs to the collapsed menu alone. Where the menu is a row, the house
   at the far left is already that link, and listing it twice in one line reads
   as a mistake. */
.site-nav .nav-home{display:none}
/* header items must never wrap: a squeezed flex row broke "The Lakehouse" and the
   CTA label onto two lines between the mobile breakpoint and full desktop */
.site-nav a{opacity:.82;padding:6px 0;border-bottom:2px solid transparent;white-space:nowrap}
.site-head .brand,.site-head .head-cta,.site-head .season-toggle{white-space:nowrap}
.site-head .head-cta,.site-head .season-toggle{flex:0 0 auto}
.site-nav a:hover{opacity:1;border-bottom-color:var(--accent)}
.head-cta{margin-left:6px;padding:11px 20px;font-size:12px}
.site-head .season-toggle,.site-head .head-cta{height:30px;padding-top:0;padding-bottom:0}
.site-head .head-cta{line-height:28px}
.nav-toggle{display:none;margin-left:auto;font-family:var(--label);font-size:12px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--head-ink);border:1px solid var(--head-line);padding:0 14px;height:30px;line-height:28px;border-radius:var(--btn-radius)}
.season-toggle{display:flex;align-items:center;gap:8px;font-family:var(--label);font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;
  border:1px solid var(--head-line);border-radius:99px;padding:8px 16px;color:var(--head-ink)}
.season-toggle svg{width:15px;height:15px;fill:var(--accent)}
.season-toggle:hover{border-color:var(--accent)}
/* fixed-width label so the pill doesn't resize between "Sole" and "Luna" */
.st-label{display:inline-block;min-width:38px;text-align:center}
@media(max-width:1060px){
.site-nav{display:none;position:absolute;top:100%;left:0;right:0;background:var(--bg);border-bottom:1px solid var(--line);
    flex-direction:column;gap:0;padding:10px 40px 20px}
.site-nav a{padding:12px 0;border-bottom:1px solid var(--line);opacity:1}
.site-head.open .site-nav{display:flex;color:var(--ink)}
.site-nav .nav-home{display:block}
.nav-toggle{display:block}
.head-cta{display:none}
.site-head{gap:14px}
.season-toggle{margin-left:auto}
.nav-toggle{margin-left:0}
}
@media(max-width:620px){
.site-head{padding-left:22px;padding-right:22px;gap:12px}
.site-nav{padding-left:22px;padding-right:22px}
.site-head .season-toggle{padding:0 12px;gap:6px}
}
/* desktop: a taller header (~30% bigger than the compact default), with the
   text, nav and buttons scaled up to match */
/* the enlarged header needs ~1130px to lay out on one line, so it starts here;
   between the mobile breakpoint and this width the compact sizes above apply */
@media(min-width:1160px){
.site-head{padding-top:12px;padding-bottom:12px}
.site-head .brand{font-size:26px}
.site-head .brand.home-link svg{width:36px;height:36px}
.site-head .site-nav{font-size:16px}
.site-head .site-nav a{padding:7.5px 0}
.site-head .season-toggle,.site-head .head-cta{height:36px}
.site-head .season-toggle{font-size:13px;letter-spacing:.08em;padding-left:19px;padding-right:19px}
.site-head .season-toggle svg{width:18px;height:18px}
.site-head .st-label{min-width:46px}
.site-head .head-cta{line-height:34px;font-size:13px;padding-left:24px;padding-right:24px}
}
.page-foot .brand{color:var(--foot-head)}

/* ---------- moved from theme.css ---------- */
/* Brand fonts, matching casolena.ca */
@font-face{
  font-family:'Brown Sugar';
  font-style:normal; font-weight:400; font-display:swap;
  src:url('../fonts/brown-sugar.woff2') format('woff2');
}
@font-face{
  font-family:'Eyesome Script';
  font-style:normal; font-weight:400; font-display:swap;
  src:url('../fonts/eyesome-script.woff2') format('woff2');
}
/* Jost + Josefin Sans (SIL Open Font License). 400/500/600 upright plus a real
   italic each, so no weight or slant is ever synthesized:
     Jost 400  body copy · 500 mid-weight · 600 buttons, labels, <strong>
     Jost italic  <em> inside body text
     Josefin Sans 400  headings · 600 heavier headings
     Josefin Sans italic  pull-quotes, room subtitles, .prose em */
@font-face{font-family:'Jost';font-style:normal;font-weight:400;font-display:swap;src:url('../fonts/jost-400.woff2') format('woff2')}
@font-face{font-family:'Jost';font-style:normal;font-weight:500;font-display:swap;src:url('../fonts/jost-500.woff2') format('woff2')}
@font-face{font-family:'Jost';font-style:normal;font-weight:600;font-display:swap;src:url('../fonts/jost-600.woff2') format('woff2')}
@font-face{font-family:'Josefin Sans';font-style:normal;font-weight:400;font-display:swap;src:url('../fonts/josefin-sans-400.woff2') format('woff2')}
@font-face{font-family:'Josefin Sans';font-style:normal;font-weight:600;font-display:swap;src:url('../fonts/josefin-sans-600.woff2') format('woff2')}
@font-face{font-family:'Josefin Sans';font-style:italic;font-weight:400;font-display:swap;src:url('../fonts/josefin-sans-400-italic.woff2') format('woff2')}
:root{
  --bg:#FAF8F1; --bg-alt:#F1EDE0; --surface:#FFFFFF;
  --ink:#26322E; --ink-soft:#54615B; --line:#E5DFCC;
  --accent:#25717E; --accent-ink:#FFFFFF;
  --btn-bg:#25717E; --btn-ink:#FFFFFF; --btn-bg-h:#1E5C66;
  --kicker-c:#B0812F;
  --brand:'Brown Sugar','Sitka Heading',Georgia,serif;
  /* Self-hosted webfonts, so these render identically on every device.
     The system fonts after them cover the swap-in moment and the handful of
     decorative glyphs (★ → ← ✕) that the Latin subsets don't include. */
  --display:'Josefin Sans','Segoe UI',system-ui,-apple-system,sans-serif;
  --body:'Jost','Segoe UI',system-ui,-apple-system,Arial,sans-serif;
  --label:'Jost','Segoe UI',system-ui,sans-serif;
  --radius:8px; --btn-radius:99px; --btn-track:.08em;
  --maxw:1200px; --display-weight:400;
  /* The header is frosted glass, not a panel: the tint is deliberately thin so
     backdrop-filter has something to show. --head-bg-solid is the old opaque
     value, kept for browsers with no backdrop-filter, where a thin tint would
     leave the nav sitting on raw page content. */
  --head-bg:#FAF8F173; --head-bg-solid:#FAF8F1F0;
  --head-blur:saturate(1.4) blur(18px);
  --head-ink:#26322E; --head-line:#E5DFCC;
  --foot-bg:#26322E; --foot-ink:#AEBCB2; --foot-head:#F1EDE0; --foot-line:#FFFFFF1F; --foot-field:#33413C;
  --hero-tint:#12252A66;
}
html[data-season="luna"]{
  --bg:#111A24; --bg-alt:#0D141C; --surface:#1A2530;
  --ink:#EAF0F2; --ink-soft:#A9B8BE; --line:#FFFFFF1F;
  --accent:#D9A04A; --accent-ink:#141A22;
  --btn-bg:#D9A04A; --btn-ink:#141A22; --btn-bg-h:#E8B15C;
  --kicker-c:#8FB6BE;
  --head-bg:#111A248C; --head-bg-solid:#111A24E6;
  --head-ink:#EAF0F2; --head-line:#FFFFFF1F;
  --foot-bg:#0D141C; --foot-ink:#8494A0; --foot-head:#EAF0F2; --foot-line:#FFFFFF14; --foot-field:#1A2530;
  --hero-tint:#0B121AB3;
}
body,.site-head,.page-foot,.sec,.card,.demo-form,.callout,.c4-life figure{transition:background-color .5s ease,color .5s ease,border-color .5s ease}
/* The header's blur has to ease in on the same clock as its tint. Without this
   the glass snaps on while the colour fades over half a second, which reads as
   a glitch now that desktop frosts on the first pixel of scroll. Declared here,
   above the reduced-motion block, so that block still switches it off. */
.site-head{transition:background-color .5s ease,color .5s ease,border-color .5s ease,
  -webkit-backdrop-filter .5s ease,backdrop-filter .5s ease}
@media (prefers-reduced-motion:reduce){
body,.site-head,.page-foot,.sec,.card,.demo-form,.callout,.c4-life figure{transition:none}
}
.brand{font-family:var(--brand);font-size:20px;letter-spacing:.04em}
.brand small{letter-spacing:.22em}
.btn{font-weight:600}
.head-cta{background:var(--accent);color:var(--accent-ink)}
/* seasonal copy visibility */
[data-show]{display:none}
html[data-season="sole"] [data-show="sole"]{display:revert}
html[data-season="luna"] [data-show="luna"]{display:revert}
/* ---------- homepage ---------- */
/* magazine-cover hero: "Casolena · lakehouse" masthead top, cover line bottom */
.c4-hero{position:relative;min-height:100vh;min-height:100svh;display:flex;overflow:hidden;
  --head-h:50px}
/* The horizon carries the header. Both hero photos put the waterline at 8.9% of
   their height, and this parks that line exactly one header-height down the
   screen, so the gap under the Sole/Luna pill reads as the gap above it. The
   buttons are centred in the header, which is why X + 2Y and the header height
   are the same number. --head-h is raised at 1061px and again at 1160px as the
   header grows, and the masthead's 2.5x rule reads the same variable, so the
   two can never disagree about where the header ends.

   cover cannot do this, because it derives the scale from the viewport and
   leaves the waterline wherever it falls. So the scale is solved for instead:
     waterline = top offset + 0.089 * height  ->  offset = LINE - 0.089 * H
   and H is the smallest height that still covers the box on all three counts,
     LINE/0.089         keeps the offset negative, so no gap opens at the top
     (100svh-LINE)/.911 reaches the bottom edge
     100vw * 9/16       reaches both sides at 16:9
   Taking the smallest keeps the crop as light as the constraint allows. On a
   1920x1080 screen that is a 2.8% zoom and 31px trimmed off the sky.

   This lives on the base rule so every width that draws the landscape photo is
   solved the same way. Only the phone's portrait crop opts out, further down,
   with its own constants. Horizontal framing stays a variable: below 901px the
   16:9 photo is far wider than the box and the crop is hand-placed per season,
   so --hx carries that instead of a hard-coded position. */
.c4-hero-bg{position:absolute;inset:0;transition:opacity .6s ease;
  --hl:var(--head-h);         /* one header height down, = X + 2Y */
  --hf:.089; --hfr:.911;      /* horizon's share of the file, and 1 minus it */
  --hw:.5625;                 /* 9/16: turns 100vw into the height that covers it */
  --hx:center;                /* horizontal framing; narrow screens override it */
  --hs:max(calc(var(--hl) / var(--hf)),calc((100svh - var(--hl)) / var(--hfr)),calc(100vw * var(--hw)));
  background-size:auto var(--hs);
  background-position:var(--hx) calc(var(--hl) - var(--hf) * var(--hs))}
/* The hero photo lives here rather than on the element, so the browser fetches
   exactly one: a rule that does not apply never loads its image. Inline styles
   could not do that, and the season swap used to hand every winter visitor the
   summer hero first and the winter one after.
   Three cuts of each hero, narrowest to widest: the portrait phone crop further
   down, this 1440px copy for the middle, and the 1920px master on desktop in
   the min-width:1061px block. This one covers landscape phones and tablets. */
.c4-hero-bg{background-image:url('../assets/img/hero/dji-20260424111444-0036-d-web.jpg')}
html[data-season="luna"] .c4-hero-bg{background-image:url('../assets/img/hero/dji-20260124181135-0059-d-web.jpg')}
/* LOCAL EXPERIMENT: the phone scrim at every width, with the original desktop
   darkening restored over the top 10% alone, where the nav sits. The 900px rule
   further down replaces this whole background, so phones keep the bare phone
   scrim and their clear sky behind the header.
   original desktop, to restore:
     linear-gradient(to bottom,#0b131a8c 0%,#0b131a00 22%,#0b131a00 52%,#0b131ae6 100%),
     radial-gradient(120% 80% at 50% 108%,var(--hero-tint) 0%,#0000 60%) */
/* Both scrims run their stops all the way to 100%, and the last stop is one
   step of alpha off the one before it. That looks like a typo and is not.
   A gradient whose stops stop early does not paint the rest of the box from
   the stop list. The renderer clamps, holding the final colour over whatever
   is left, and on the GPU path Firefox 115 lays a 1px dark rule at the line
   where the clamp takes over. Reported on Windows 8.1 at a window height of
   704px: one rule at 70px and another at 352px, exactly the 10% and 50% where
   these two used to end. It only shows at some window heights, so a quick
   resize is not proof it has gone.
   Carrying the same colour on to 100% does not help, because Gecko drops
   trailing stops that repeat the colour before them and lands back on the
   clamp. One step of alpha, 1 in 255, is under half a percent of black over a
   photograph and cannot be seen, but it is a different colour, so the stop
   survives, the gradient line covers the whole box, and there is no clamp
   left to draw a line at. Do not round these last stops to #0000. */
.c4-hero::after{content:"";position:absolute;inset:0;background:
  linear-gradient(to bottom,#0b131a8c 0%,#0b131a00 10%,#0b131a01 100%),
  linear-gradient(to bottom,#00000029 0%,#00000030 3%,#0000006E 20%,#0000 50%,#00000001 100%)}
/* The masthead sits 2.5 header-heights down, the same --head-h the waterline
   uses, so the two move together. What stands above it inside the copy is the
   kicker's line box plus its 10px margin; the line-height is the inherited 1.7,
   so the box is 1.7 x the font size, and the font size is the kicker's own
   clamp. Spelling that out rather than baking in a constant matters below 928px,
   where 1.4vw stops being pinned to 13px.
   This is the base rule, not a desktop one: every layout that draws the
   landscape photo wants the same relationship to the header. Only the portrait
   phone view opts out, further down. */
.c4-hero-copy{position:relative;z-index:2;width:100%;display:flex;flex-direction:column;align-items:center;text-align:center;
  padding:calc(2.5 * var(--head-h) - 1.7 * clamp(11px,1.4vw,13px) - 10px) 24px clamp(20px,3.5vh,36px);
  color:#FCFDFC}
.c4-mast-kicker{font-family:'Jost',sans-serif;font-weight:500;font-size:clamp(11px,1.4vw,13px);
  letter-spacing:.28em;text-transform:uppercase;color:#FFFFFFE0;margin-bottom:10px}
.c4-mast{font-family:var(--brand);font-weight:400;font-size:clamp(58px,11vw,90px);line-height:.9;letter-spacing:.1em;
  text-shadow:0 4px 40px #0b121a70}
.c4-mast-sub{display:block;font-family:'Eyesome Script',cursive;font-size:clamp(38px,6.6vw,64px);line-height:.52;
  color:#FFE6B0;letter-spacing:0;text-transform:none;margin-top:4px;text-shadow:0 3px 26px #0b121a80}
.c4-hero-foot{margin-top:auto;display:flex;flex-direction:column;align-items:center;gap:20px}
.c4-hero-actions{display:flex;gap:18px;align-items:center;flex-wrap:wrap;justify-content:center}
.c4-hero .btn.ghost{border-color:#FFFFFFB3;color:#fff}
.c4-hero .btn.ghost:hover{background:#FFFFFF22;color:#fff}
/* The cover fills the screen and finishes cleanly at the bottom edge, which
   reads as a whole page rather than the first screen of one, and visitors were
   stopping there. This is the smallest answer to that: a word and a chevron at
   the foot of the cover, dipping once every couple of seconds so the eye picks
   it up, gone for good on the first scroll (site.js), by which point it has
   said everything it had to say.
   Below 1061px the button sits centred at the foot as well, so the cue stays in
   the flow of .c4-hero-foot and lifts the button by its own height rather than
   landing on it. From 1061px the button moves to the left, the centre comes
   free, and the cue takes it absolutely, against .c4-hero-copy, sharing the
   button's bottom margin so the two sit on one line. That is also the only
   width where the word appears; under it there is no room for it beside the
   button, so the chevron travels alone and aria-label carries the name. */
.c4-cue{display:flex;flex-direction:column;align-items:center;gap:6px;
  color:#FCFDFC;text-shadow:0 2px 14px #0b121a99,0 0 4px #0b121a80;opacity:.88;
  transition:opacity .5s ease,visibility .5s ease}
.c4-cue:hover{opacity:1}
.c4-cue .cue-word{display:none;font-family:var(--label);font-size:11px;font-weight:500;
  letter-spacing:.28em;text-transform:uppercase}
/* text-shadow does not reach an SVG stroke, and the foot of the Sole photo is
   pale gravel, so the chevron carries its own shadow or it disappears there. */
.c4-cue svg{display:block;width:22px;height:13px;fill:none;stroke:currentColor;stroke-width:1.6;
  stroke-linecap:round;stroke-linejoin:round;filter:drop-shadow(0 2px 7px #0b121aa6);
  animation:c4-cue-dip 2.6s ease-in-out infinite}
.c4-cue.gone{opacity:0;visibility:hidden;pointer-events:none}
@keyframes c4-cue-dip{0%,100%{transform:translateY(0)}50%{transform:translateY(5px)}}
@media(prefers-reduced-motion:reduce){
.c4-cue svg{animation:none}
}
/* The cue's target. The header is fixed over the hero, so a jump that lands the
   section at y=0 puts its kicker under the glass. */
.c4-intro{scroll-margin-top:96px}
/* --head-h, set on .c4-hero above, is the one measured number the whole hero
   hangs off. The header changes height twice on the way up, and the waterline
   and the masthead both follow it:
     up to 1060  50.00px   Sole/Luna + Menu + the home icon, all 30px
     1061-1159   56.94px   nav links appear and set the height
     1160+       68.19px   pages.css enlarges the type and the buttons
   Measured, because CSS cannot read the header. Re-measure if its type moves.
   These exclude the header's 1px bottom border, so a browser reports one more
   than each. The first is the one to watch: nothing up there is taller than
   30px, so anything given more than that, padding included, moves the horizon
   on every phone. */
/* desktop: keep the masthead centred, but drop the cover line + button to the
   left as a block; the two stay centred on a shared vertical axis */
@media(min-width:1061px){
.c4-hero{--head-h:56.94px}
.c4-hero-copy{padding-left:clamp(44px,5vw,80px);padding-right:clamp(44px,5vw,80px)}
.c4-hero-foot{align-self:flex-start}
.c4-cue{position:absolute;left:50%;bottom:clamp(20px,3.5vh,36px);transform:translateX(-50%)}
.c4-cue .cue-word{display:block}
/* Desktop gets the untouched 1920px master. The 1440px copy was supposed to
     be invisible behind the scrim and it is not: put side by side at desktop
     size the softening reads plainly, and a photo that fills the whole screen
     is the one on the site that cannot afford it. Any laptop with a 2x display
     was stretching 1440px across close to 2880 device pixels.
     770 KB against 366 KB, and only here. Everything narrower keeps the light
     copies, so phones, where the bytes actually cost something, are unchanged,
     and so is the Lighthouse mobile run.
     The masters have no WebP sibling on purpose: casolena_grade.py leaves them
     JPEG-only so og:image can never be negotiated into a format some link
     preview scrapers will not read. Nothing swaps these, so this is the
     original file. */
.c4-hero-bg{background-image:url('../assets/img/hero/dji-20260424111444-0036-d.jpg')}
html[data-season="luna"] .c4-hero-bg{background-image:url('../assets/img/hero/dji-20260124181135-0059-d.jpg')}
}
/* pages.css grows the header here, so both distances grow with it: the
   waterline moves to 68.19px and the masthead to 170.48px */
@media(min-width:1160px){
.c4-hero{--head-h:68.19px}
}
.c4-moon-dial .season-toggle{align-self:flex-start;border-color:var(--line);color:var(--ink)}
/* One ratio for both seasons, so the block keeps its height when the season
   flips and the photo and the text beside it stay put. The sole file is already
   3:4 (800x1067); the luna file is 800x1111, so cover trims 4% of it, anchored
   to the bottom so the slice comes off the top sky and the lit house stays. */
.c4-split img{aspect-ratio:3/4}
html[data-season="luna"] .c4-split img{object-position:50% 100%}
@media (max-width:900px){
.c4-hero{align-items:flex-start}
/* align-items:flex-start stops the copy stretching to the hero's height, and
     without a height of its own there is no free space for .c4-hero-foot's
     margin-top:auto to absorb, so the cover line and the button ride up under
     the masthead instead of sitting at the foot of the screen. The min-height
     gives that space back. This used to be declared only under 620px, which is
     why the fault appeared in a band rather than everywhere below 900px. */
/* Only the side padding and the height are this band's business. The top came
     from a flat 156px and the bottom from a flat 44px, which is what made 900px
     jump: just above it the masthead sits at 2.5 x the header and the foot at
     clamp(40px,7vh,72px), so crossing the line moved the masthead 62px down and
     the cover line 19px up in one step. Both now carry on from the band above
     and only change at 700px, where the phone layout starts. */
.c4-hero-copy{padding-left:26px;padding-right:26px;min-height:100svh}
/* Narrow boxes take a huge horizontal bite out of a 16:9 photo, so the crop is
     hand-placed per season. These are the same numbers the old rule used; only
     the vertical is different, and that now comes from the horizon solve.
     The luna rule used to add background-size:auto 120% on top, a flat 20% zoom
     that the solve cannot see. It fought the solve and pushed the waterline to
     roughly 0.089 * 1.2 * viewport height, so the photo jumped in and the line
     sat far too low the moment this band was entered. */
.c4-hero-bg{--hx:70%}
html[data-season="luna"] .c4-hero-bg{--hx:60%}
}
/* Where the phone layout actually begins, and it must be the SAME condition as
   the portrait crop below, not just the same width. Scoped to max-width alone,
   a short window (a laptop browser under ~700px tall) enters this block while
   still landscape, so it took the phone's spacing and phone's scrim while the
   photo was still the landscape one: the shading behind the header vanished and
   the masthead dropped 60px with nothing else changing to explain it.
   The scrim: let the sky read as the header's backdrop, barely-there tint up
   top, gentle darkening only where the headline sits. On a phone the header is
   a wordmark and a hamburger, far less ink to protect than a full nav row, so
   it can afford to stay clear where the wide layout cannot. */
@media (max-width:700px) and (orientation:portrait){
.c4-hero-copy{padding-top:156px;padding-bottom:22px}
.c4-hero::after{background:linear-gradient(to bottom,#00000029 0%,#00000030 3%,#0000006E 20%,#0000 50%,#00000001 100%)}
}
/* Phones get the portrait cuts. A landscape hero under background-size:cover on
   a tall screen is scaled to fit the height, so a phone drew the 1440px file
   about 1372px wide in a 412px viewport and threw ~70% of it away. These are cut
   to the shape of the screen instead, and sharper with it, since the crop comes
   off a 1080px original rather than the 1440px copy.
   These two are hand-cut in Photoshop, not machine-cut from the master, so
   HERO_MOBILE_FRAME does not describe them: they are listed in
   HERO_MOBILE_SUPPLIED in casolena_grade.py and rebuilt with its hero-mobile
   command. To move the vertical framing, re-cut the portrait and re-run that.
   The horizontal stays on center; only the vertical is solved for below.
   These are 9:15.3, taller than a hero but wider than a phone, so roughly 25%
   comes off the sides on a 9:20 handset. Portrait only: a landscape or tablet
   viewport is better off with the wide file above.
   600px wide since Aug 2026, down from 900. The cap lives in casolena_grade.py
   as HERO_MOBILE_MAX_W and the reasoning sits with it; the short version is
   that the box draws these about 550 CSS px wide, so any cap under ~1100 is
   already an upscale on a 2x screen, and the smaller file halves the bytes on
   the one device where they cost anything. */
@media (max-width:700px) and (orientation:portrait){
.c4-hero-bg{background-image:url('../assets/img/hero/dji-20260424111444-0036-d-mobile.jpg')}
html[data-season="luna"] .c4-hero-bg{background-image:url('../assets/img/hero/dji-20260124181135-0059-d-mobile.jpg')}
/* The horizon carries the header here too, same solve as the desktop block,
     same variables, different constants. X + 2Y is a flat 50px on every phone
     size: the Sole/Luna pill and the Menu button are both 30px at 10px down,
     and Check availability is display:none below 1061px, so Menu is the button
     that stands in for it.
     Both seasons sit at 7.5%, owner's call. Detection was measured per file and
     gave sole 7.456% and luna 9.281%, but the winter number was wrong: snow and
     ice give the water no contrast to sit against, so the detector found the
     edge of an ice sheet below the waterline rather than the waterline. Sole is
     the reliable one and the two crops are the same framing, so the summer
     figure carries both, rounded.
     --hw stays per-season, and is 1/ratio rather than 9/16 because these are
     portrait: the files are 600x1019 and 600x1020. Re-measure if they are
     ever recut, and trust the eye over the detector on the winter one. */
.c4-hero-bg{
    --hl:50px;
    --hf:.075; --hfr:.925;
    --hw:1.69833;
    --hs:max(calc(var(--hl) / var(--hf)),calc((100svh - var(--hl)) / var(--hfr)),calc(100vw * var(--hw)));
    background-size:auto var(--hs);
    background-position:center calc(var(--hl) - var(--hf) * var(--hs))}
/* The size and position are repeated here, not just the constants. The 900px
     block above sets background-size:auto 120% on this very selector, which
     outranks the plain .c4-hero-bg rule, so declaring only the custom properties
     leaves the winter phone hero on the old 120% framing. */
html[data-season="luna"] .c4-hero-bg{
    --hw:1.7;
    background-size:auto var(--hs);
    background-position:center calc(var(--hl) - var(--hf) * var(--hs))}
}
@media (max-width:620px){
.c4-hero .kicker{display:none}
}
/* immersive header on the homepage: sticky over the hero, transparent at the top,
   filling with colour once the hero has been scrolled past (both seasons) */
/* The rule is 1px solid transparent, not none. border-bottom:none resets the
   border colour to currentColor, and width and style are discrete, so the line
   used to pop in at full width wearing the header's ink colour and only then
   ease to --head-line: a dark flash in sole, a bright one in luna. Holding a
   transparent 1px border here means only the colour ever changes, which is the
   one part that can animate. */
body.home .site-head{position:fixed;top:0;left:0;right:0;background:transparent;border-bottom:1px solid transparent;backdrop-filter:none;--head-ink:#FCFDFC}
body.home .site-head .site-nav a:hover{border-bottom-color:#FFFFFFAA}
body.home .site-head .head-cta{background:transparent;border:1px solid #FFFFFFB3;color:#fff}
body.home .site-head .head-cta:hover{background:#fff;color:#26322E}
body.home .site-head .nav-toggle{border-color:#FFFFFF80}
body.home .site-head .season-toggle{border-color:#FFFFFF66}
body.home .site-head .season-toggle svg{fill:#fff}
/* filled state: after scrolling off the hero, or when the mobile menu is open */
body.home .site-head.scrolled,body.home .site-head.open{background:var(--head-bg);border-bottom:1px solid var(--head-line);
  -webkit-backdrop-filter:var(--head-blur);backdrop-filter:var(--head-blur);--head-ink:var(--ink)}
/* Without backdrop-filter the thin tint is just a see-through bar over whatever
   scrolls under it, so those browsers get the old opaque header instead. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
.site-head,body.home .site-head.scrolled,body.home .site-head.open{background:var(--head-bg-solid)}
}
body.home .site-head.scrolled .site-nav a:hover,body.home .site-head.open .site-nav a:hover{border-bottom-color:var(--accent)}
body.home .site-head.scrolled .season-toggle,body.home .site-head.open .season-toggle{border-color:var(--head-line)}
body.home .site-head.scrolled .season-toggle svg,body.home .site-head.open .season-toggle svg{fill:var(--accent)}
body.home .site-head.scrolled .nav-toggle{border-color:var(--head-line)}
body.home .site-head.scrolled .head-cta{background:var(--accent);border:1px solid transparent;color:var(--accent-ink)}
body.home .site-head.scrolled .head-cta:hover{background:var(--btn-bg-h)}
