/* ABOUTME: Core stylesheet for the Empathi site. Editorial register: mono for structure, sans for prose.
   ABOUTME: All colour comes from tokens; never hardcode a hex here or in a page. */

@import url("./tokens.css");
@import url("./dither.css");

/* ---------- reset ---------- */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0}
img,svg,canvas,video{display:block;max-width:100%}
button,input,select,textarea{font:inherit;color:inherit}
h1,h2,h3,h4,p,figure,blockquote,ul,ol{margin:0}
ul[class],ol[class]{list-style:none;padding:0}
:target{scroll-margin-top:calc(var(--header-clear) + 1rem)}

/* ---------- type + rhythm + system tokens ----------
   More air, quieter rules, slower motion. The restraint is the premium signal. */
:root{
  --font-mono:ui-monospace,"Cascadia Mono",Consolas,"SF Mono",Menlo,monospace;
  --font-sans:"Segoe UI Variable Display","Segoe UI",system-ui,-apple-system,"Helvetica Neue",Arial,sans-serif;

  --step--1:clamp(.80rem,.77rem + .13vw,.875rem);
  --step-0: clamp(1rem,.96rem + .18vw,1.08rem);
  --step-1: clamp(1.18rem,1.10rem + .38vw,1.42rem);
  --step-2: clamp(1.42rem,1.26rem + .78vw,2.0rem);
  --step-3: clamp(1.75rem,1.42rem + 1.6vw,2.9rem);
  --step-4: clamp(2.2rem,1.55rem + 3.1vw,4.4rem);
  --step-5: clamp(2.4rem,6.4vw,5.2rem);

  --gutter:clamp(1.25rem,4vw,2.5rem);
  --measure:62ch;
  --col:1240px;
  --band:clamp(4.5rem,10vw,9rem);

  /* mono-caps tracking: tight for controls, wide for labels */
  --track-tight:.06em;
  --track-wide:.12em;

  /* motion */
  --dur-fast:.18s;
  --dur-slow:.4s;
  --ease:cubic-bezier(.22,.61,.36,1);

  /* corners: components (buttons-to-cards) and panes (header, glass boxes) */
  --radius-comp:12px;
  --radius-pane:16px;

  /* liquid glass: blur/saturation recipe, fill and edge */
  --glass-blur:14px;
  --glass-sat:140%;
  --glass-bg:color-mix(in srgb,var(--e-bg-raised) 70%,transparent);
  --glass-border:color-mix(in srgb,var(--e-text) 12%,transparent);
  --glass-border-strong:color-mix(in srgb,var(--e-text) 26%,transparent);

  /* elevation: resting and lifted */
  --elev-1:0 1px 2px color-mix(in srgb,var(--e-ink-900) 6%,transparent),
           0 12px 32px -18px color-mix(in srgb,var(--e-ink-900) 30%,transparent);
  --elev-2:0 2px 4px color-mix(in srgb,var(--e-ink-900) 7%,transparent),
           0 26px 48px -20px color-mix(in srgb,var(--e-ink-900) 42%,transparent);
  /* The specular edge: a bright hairline, brightest at the centre. This is the
     detail that separates real glass from a blurred rectangle. */
  --specular:linear-gradient(90deg,transparent,color-mix(in srgb,#fff 55%,transparent),transparent);

  /* floating header: bar height and the clearance the page keeps under it */
  --header-h:60px;
  --header-clear:calc(var(--header-h) + clamp(20px,4vw,44px));
}

html{scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}

body{
  background:var(--e-bg);
  color:var(--e-text);
  font-family:var(--font-sans);
  font-size:var(--step-0);
  line-height:1.62;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  /* The ground: a faint ordered dot field, twice the plate grid. Present
     everywhere, noticed nowhere. Fixed, so the page scrolls over it. */
  background-image:radial-gradient(var(--e-rule) .5px,transparent .5px);
  background-size:calc(var(--e-dither-cell) * 2) calc(var(--e-dither-cell) * 2);
  background-position:0 0;
  background-attachment:fixed;
  /* The header floats, so content keeps clearance under it. */
  padding-top:var(--header-clear);
}

.wrap{width:100%;max-width:var(--col);margin-inline:auto;padding-inline:var(--gutter)}
.narrow{max-width:74ch}
.prose p+p{margin-top:1em}
.prose p{max-width:var(--measure)}

h1,h2,h3{text-wrap:balance;line-height:1.08;font-weight:640}
h1,h2{letter-spacing:-.028em}
h1{font-size:var(--step-4)}
h2{font-size:var(--step-3)}
h3{font-size:var(--step-1);letter-spacing:-.01em}
.lede{font-size:var(--step-1);line-height:1.46;color:var(--e-text-muted);max-width:56ch}

/* The one structural device: a mono eyebrow with a rule. Signals section, not
   decoration. The rule is a dot run, tying every section head to the logo's
   dissolving H. */
.eyebrow{
  font-family:var(--font-mono);font-size:var(--step--1);
  letter-spacing:var(--track-wide);text-transform:uppercase;color:var(--e-accent-text);
  display:flex;align-items:center;gap:.8rem;margin-bottom:1.4rem;
}
.eyebrow::after{
  content:"";flex:1;height:3px;min-width:2rem;
  background-image:radial-gradient(var(--e-rule) 1px,transparent 1px);
  background-size:var(--e-dither-cell) 3px;background-repeat:repeat-x;
}
.kicker{font-family:var(--font-mono);font-size:var(--step--1);letter-spacing:var(--track-wide);
  text-transform:uppercase;color:var(--e-text-muted)}
.muted{color:var(--e-text-muted)}

a{color:var(--e-accent-text);text-underline-offset:.18em;text-decoration-thickness:1px}
a:hover{text-decoration-thickness:2px}
:where(a,button,input,select,textarea,[tabindex]):focus-visible{
  outline:2px solid var(--e-accent);outline-offset:3px;border-radius:1px}

/* ---------- surfaces ---------- */
.band{padding-block:var(--band)}
/* Section rules are dotted, not solid - a one-pixel echo of the same grid. */
.band+.band > .wrap::before{
  content:"";display:block;height:1px;margin-bottom:var(--band);
  background-image:radial-gradient(var(--e-rule) .6px,transparent .6px);
  background-size:var(--e-dither-cell) 1px;background-repeat:repeat-x;
}
[data-surface="ink"]{
  background:var(--e-bg);color:var(--e-text);
  background-image:radial-gradient(var(--e-ink-600) .5px,transparent .5px);
  background-size:calc(var(--e-dither-cell) * 2) calc(var(--e-dither-cell) * 2);
}

/* ---------- buttons ---------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:.6rem;
  min-height:48px;padding:.75rem 1.35rem;
  font-family:var(--font-mono);font-size:var(--step--1);
  letter-spacing:var(--track-tight);text-transform:uppercase;font-weight:600;
  border:1px solid var(--e-accent);background:var(--e-accent);color:var(--e-on-accent);
  text-decoration:none;cursor:pointer;
  position:relative;overflow:hidden;isolation:isolate;
  transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease),
             border-color var(--dur-fast) var(--ease),transform var(--dur-fast) var(--ease);
}
.btn:hover{background:transparent;color:var(--e-accent-text);transform:translateY(-1px)}
.btn:active{transform:translateY(0)}
.btn--ghost{background:transparent;color:var(--e-text);border-color:var(--e-rule)}
.btn--ghost:hover{border-color:var(--e-text);color:var(--e-text);background:transparent}
.btn-row{display:flex;flex-wrap:wrap;gap:.75rem;margin-top:1.75rem}

/* Dither hover: the dot pattern is always present but scaled to nothing, and
   hover SWEEPS it across the element rather than snapping a texture on. */
.btn::before{
  content:"";position:absolute;inset:0;z-index:-1;
  background-image:radial-gradient(currentColor 1.1px,transparent 1.1px);
  background-size:var(--e-dither-cell) var(--e-dither-cell);
  opacity:0;
  transform:translateX(-12%);
  transition:opacity var(--dur-fast) ease,transform var(--dur-slow) var(--ease);
}
.btn:hover::before,.btn:focus-visible::before{opacity:.30;transform:none}
@media (prefers-reduced-motion:reduce){
  .btn::before{transition:none}
  .btn:hover{transform:none}
}

/* ---------- floating liquid-glass header ----------
   Detached from the viewport edge so the living background is visible above and
   around it, which is what makes it read as glass rather than as a solid bar.
   Note: transparency comes from rgba/color-mix, never from `opacity` - setting
   opacity on the element kills its own backdrop-filter. */
.site-header{
  --glass-blur:18px;
  --glass-sat:160%;
  --glass-bg:color-mix(in srgb,var(--e-bg) 55%,transparent);
  position:fixed;top:clamp(10px,1.6vw,20px);left:50%;transform:translateX(-50%);
  z-index:60;
  width:min(var(--col),calc(100% - clamp(16px,4vw,40px)));
  border:1px solid var(--glass-border);
  border-radius:var(--radius-pane);
  background:var(--glass-bg);
  backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-sat));
  -webkit-backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-sat));
  box-shadow:var(--elev-1),0 1px 0 color-mix(in srgb,#fff 24%,transparent) inset;
  overflow:hidden;isolation:isolate;
  transition:background var(--dur-slow) ease,box-shadow var(--dur-slow) ease,top var(--dur-slow) ease;
}
.site-header::before{
  content:"";position:absolute;top:0;left:0;right:0;height:1px;pointer-events:none;
  background:var(--specular);
}
/* A faint internal falloff so the pane has body rather than reading flat. */
.site-header::after{
  content:"";position:absolute;inset:0;pointer-events:none;z-index:-1;
  background:linear-gradient(to bottom,
    color-mix(in srgb,#fff 10%,transparent),transparent 60%);
}
.site-header .wrap{
  display:flex;align-items:center;gap:1.5rem;
  min-height:var(--header-h);padding-inline:clamp(14px,2vw,22px);
}
/* Condense once the page has moved, so it reads as floating rather than fixed. */
.site-header[data-scrolled="true"]{
  background:color-mix(in srgb,var(--e-bg) 78%,transparent);
  box-shadow:var(--elev-2),0 1px 0 color-mix(in srgb,#fff 24%,transparent) inset;
}
.nav__lockup{height:30px;width:auto}
.brandlink{display:inline-flex;align-items:center;text-decoration:none;flex:0 0 auto}
.nav{margin-left:auto;display:flex;align-items:center;gap:.4rem}
.nav a{
  font-family:var(--font-mono);font-size:var(--step--1);letter-spacing:var(--track-tight);
  text-transform:uppercase;color:var(--e-text);text-decoration:none;
  padding:.6rem .7rem;min-height:44px;display:inline-flex;align-items:center;
  border-bottom:2px solid transparent;
}
.nav a:hover{border-bottom-color:var(--e-rule)}
.nav a[aria-current="page"]{border-bottom-color:var(--e-accent);color:var(--e-accent-text)}
.nav .btn{margin-left:.6rem}
.navtoggle{display:none;margin-left:auto;min-height:44px;min-width:44px;
  border:1px solid var(--e-rule);background:transparent;cursor:pointer;
  font-family:var(--font-mono);font-size:var(--step--1);letter-spacing:var(--track-tight);text-transform:uppercase}
.skip{position:absolute;left:-9999px}
.skip:focus{left:var(--gutter);top:.5rem;z-index:100;background:var(--e-accent);
  color:var(--e-on-accent);padding:.7rem 1rem;font-family:var(--font-mono)}

/* Logged-in WordPress users have the admin bar pinned across the top; float the
   header below it. WordPress publishes the bar's height (32px, 46px on phones). */
.admin-bar .site-header{top:calc(var(--wp-admin--admin-bar--height,32px) + clamp(10px,1.6vw,20px))}
/* Under 600px WordPress lets the bar scroll away, which would leave a gap above
   the header; keep it pinned so the offset above stays true. */
@media (max-width:600px){ #wpadminbar{position:fixed} }

@media (max-width:900px){
  /* The header's transform makes it the containing block for the menu panel, and
     its overflow:hidden then clipped the open panel away entirely. Let the panel
     hang below the bar instead, and round the pane's inner layers by hand. */
  .site-header{border-radius:var(--radius-comp);overflow:visible}
  .site-header::after{border-radius:inherit}
  .site-header::before{left:var(--radius-comp);right:var(--radius-comp)}
  .navtoggle{display:inline-flex;align-items:center;justify-content:center}
  .nav{
    /* Nested inside the header's own backdrop blur, the panel cannot blur the page
       behind it, so it carries a near-opaque fill to stay readable. */
    position:absolute;inset:calc(100% + 8px) 0 auto;
    margin:0;flex-direction:column;align-items:stretch;gap:0;
    border:1px solid var(--glass-border);border-radius:var(--radius-pane);
    background:color-mix(in srgb,var(--e-bg) 96%,transparent);
    backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-sat));
    -webkit-backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-sat));
    padding:.5rem 1rem 1rem;
    transform:translateY(-8px);opacity:0;visibility:hidden;
    transition:opacity var(--dur-fast),transform var(--dur-fast);
  }
  .nav[data-open="true"]{transform:none;opacity:1;visibility:visible}
  .nav a{padding:.9rem 0;border-bottom:1px solid var(--e-rule-faint)}
  .nav .btn{margin:.9rem 0 0}
}
@media (prefers-reduced-motion:reduce){.nav{transition:none}}

/* ---------- hero ---------- */
.hero{position:relative;padding-block:clamp(3rem,7vw,6rem) var(--band)}
.hero__grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.05fr);
  gap:clamp(1.5rem,4vw,3.5rem);align-items:center}
.hero__plate{position:relative;border:1px solid var(--e-rule);background:var(--e-paper-200)}
.hero__plate canvas,.hero__plate img{width:100%;height:auto;aspect-ratio:3/2;object-fit:cover}
.hero h1{margin-bottom:.35em}
.hero .tagline{font-size:var(--step-2);line-height:1.14;letter-spacing:-.02em;
  font-weight:640;margin-bottom:.7em;text-wrap:balance}
@media (max-width:900px){.hero__grid{grid-template-columns:1fr}}

/* ---------- cards: glass panes over the living field ---------- */
.grid{display:grid;gap:clamp(1rem,2.2vw,1.6rem)}
.grid--4{grid-template-columns:repeat(4,minmax(0,1fr))}
.grid--3{grid-template-columns:repeat(3,minmax(0,1fr))}
.grid--2{grid-template-columns:repeat(2,minmax(0,1fr))}
@media (max-width:1000px){.grid--4{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:820px){.grid--3{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:640px){
  .grid--4,.grid--3,.grid--2{grid-template-columns:1fr}
}

.card{
  position:relative;display:flex;flex-direction:column;
  text-decoration:none;color:inherit;
  background:var(--glass-bg);
  backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-sat));
  -webkit-backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-sat));
  border:1px solid var(--glass-border);
  border-radius:var(--radius-comp);
  overflow:hidden;
  box-shadow:var(--elev-1);
  transition:transform var(--dur-slow) var(--ease),
             box-shadow var(--dur-slow) var(--ease),
             border-color var(--dur-slow) ease;
  isolation:isolate;
}
/* specular top edge - the detail that reads as glass */
.card::before{
  content:"";position:absolute;top:0;left:0;right:0;height:1px;z-index:4;
  background:var(--specular);
  pointer-events:none;
}
/* the pop-out */
a.card:hover,a.card:focus-visible{
  transform:translateY(-6px) scale(1.012);
  border-color:var(--glass-border-strong);
  box-shadow:var(--elev-2);
}
@media (prefers-reduced-motion:reduce){
  a.card:hover,a.card:focus-visible{transform:none}
}
.card__media{position:relative;overflow:visible;border:0;background:transparent}
.card__media img,.card__media canvas{width:100%;height:auto;aspect-ratio:3/2;object-fit:cover}
.card__media .plateimg{position:relative;z-index:1;aspect-ratio:3/2;object-fit:cover;
  border-radius:calc(var(--radius-comp) - 1px) calc(var(--radius-comp) - 1px) 0 0}
/* The scatter band: dither spreads OUT of the image, sitting below it and
   fading out before the heading. Same idea as the logo's H. */
.card__media::after{
  content:"";position:absolute;left:0;right:0;top:100%;height:52px;z-index:0;
  background-image:radial-gradient(var(--e-dither-dot) 1.5px,transparent 1.5px);
  background-size:calc(var(--e-dither-cell) * 2) calc(var(--e-dither-cell) * 2);
  -webkit-mask-image:linear-gradient(to bottom,#000 0%,transparent 68%);
          mask-image:linear-gradient(to bottom,#000 0%,transparent 68%);
  opacity:.42;
  transition:opacity var(--dur-slow) ease,height var(--dur-slow) var(--ease);
  pointer-events:none;
}
a.card:hover .card__media::after{opacity:.8;height:64px}
@media (pointer:coarse){ .card__media::after{opacity:.55} }
@media (prefers-reduced-motion:reduce){ .card__media::after{transition:none} }
.card__body{
  position:relative;z-index:1;
  display:flex;flex-direction:column;gap:.55rem;flex:1;
  padding:2.1rem 1.3rem 1.5rem;
}
.card__body h3{margin:0}
.card__body p{font-size:var(--step--1);color:var(--e-text-muted);line-height:1.6}
.card__body .tag{align-self:flex-start}
.card__more{margin-top:auto;padding-top:.6rem;font-family:var(--font-mono);
  font-size:var(--step--1);letter-spacing:var(--track-tight);text-transform:uppercase;color:var(--e-accent-text)}

/* ---------- claims ---------- */
.claims{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:0 clamp(1.5rem,4vw,3rem);counter-reset:claim}
@media (max-width:720px){.claims{grid-template-columns:1fr}}
.claims li{
  counter-increment:claim;display:grid;grid-template-columns:2.4rem 1fr;gap:.9rem;
  padding:1.05rem 0;border-bottom:1px solid var(--e-rule-faint);align-items:start;
}
.claims li::before{
  content:counter(claim,decimal-leading-zero);
  font-family:var(--font-mono);font-size:var(--step--1);color:var(--e-accent-text);
  letter-spacing:var(--track-tight);padding-top:.2em;
}

/* ---------- plate band ---------- */
.plate{position:relative;border-block:1px solid var(--e-rule);background:var(--e-paper-200);overflow:hidden}
.plate canvas,.plate>img{width:100%;height:auto;display:block}
.plate__src{display:none}

/* ---------- split ---------- */
.split{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(1.5rem,4vw,3.5rem);align-items:center}
@media (max-width:860px){.split{grid-template-columns:1fr}}
.split--wide-left{grid-template-columns:1.15fr 1fr}
@media (max-width:860px){.split--wide-left{grid-template-columns:1fr}}

/* ---------- pull quote ---------- */
.pull{border-left:3px solid var(--e-accent);
  padding:1rem 1.2rem 1rem clamp(1rem,2.5vw,1.75rem);
  background:color-mix(in srgb,var(--e-bg-raised) 55%,transparent);
  border-radius:0 var(--radius-comp) var(--radius-comp) 0}
.pull p{font-size:var(--step-2);line-height:1.26;letter-spacing:-.015em;font-weight:600;max-width:26ch}

/* ---------- tables / wide content ---------- */
.scroller{
  overflow-x:auto;
  border:1px solid var(--glass-border);
  border-radius:var(--radius-comp);
  background:var(--glass-bg);
  backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-sat));
  -webkit-backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-sat));
  box-shadow:var(--elev-1);
}
table{border-collapse:collapse;width:100%;min-width:600px;font-size:var(--step--1)}
th,td{text-align:left;padding:.75rem 1rem;border-bottom:1px solid var(--e-rule-faint);vertical-align:top}
th{font-family:var(--font-mono);font-size:var(--step--1);letter-spacing:var(--track-wide);
  text-transform:uppercase;color:var(--e-text-muted);background:var(--e-paper-200)}
tbody tr:last-child td{border-bottom:0}

/* ---------- forms ---------- */
.field{display:flex;flex-direction:column;gap:.4rem;margin-bottom:1.1rem}
.field label{font-family:var(--font-mono);font-size:var(--step--1);
  letter-spacing:var(--track-tight);text-transform:uppercase;color:var(--e-text-muted)}
.field input,.field textarea{
  min-height:48px;padding:.7rem .85rem;background:var(--e-bg-raised);
  border:1px solid var(--e-rule);color:var(--e-text);border-radius:var(--radius-comp);
}
.field textarea{min-height:150px;resize:vertical}
.field input:focus,.field textarea:focus{border-color:var(--e-accent);outline:none;
  box-shadow:0 0 0 2px color-mix(in srgb,var(--e-accent) 30%,transparent)}
.req{color:var(--e-accent-text)}
.hint{font-size:var(--step--1);color:var(--e-text-muted)}

/* ---------- footer ---------- */
.site-footer{border-top:2px solid var(--e-text);padding-block:var(--band) 2.5rem;margin-top:0}
.site-footer .cols{display:grid;grid-template-columns:1.4fr 1fr 1fr;
  gap:clamp(1.5rem,4vw,3rem);margin-bottom:2.5rem}
@media (max-width:820px){.site-footer .cols{grid-template-columns:1fr 1fr}}
@media (max-width:560px){.site-footer .cols{grid-template-columns:1fr}}
.site-footer h4{font-family:var(--font-mono);font-size:var(--step--1);letter-spacing:var(--track-wide);
  text-transform:uppercase;color:var(--e-text-muted);margin-bottom:.9rem;font-weight:600}
.site-footer ul{display:flex;flex-direction:column;gap:.55rem}
.site-footer a{color:var(--e-text);text-decoration:none}
.site-footer a:hover{text-decoration:underline}
.site-footer .blurb{max-width:42ch}
.site-footer .legal{border-top:1px solid var(--e-rule);padding-top:1.5rem;
  display:flex;flex-wrap:wrap;gap:1rem;justify-content:space-between;
  font-family:var(--font-mono);font-size:var(--step--1);color:var(--e-text-muted)}
address{font-style:normal;line-height:1.9}

/* footer sign-off */
.signoff{font-family:var(--font-mono);font-size:var(--step--1);letter-spacing:var(--track-tight);
  color:var(--e-accent-text);margin:.4rem 0 1rem}

/* ---------- section plate ----------
   A bordered media figure for a plate that sits inside a .split, between the
   card-sized .card__media and the full-bleed .plate band. */
.plate-frame{position:relative;margin:0;border:1px solid var(--e-rule);background:var(--e-paper-200)}
.plate-frame canvas,.plate-frame img{width:100%;height:auto;aspect-ratio:3/2;object-fit:cover}

/* ---------- utility ---------- */
.stack>*+*{margin-top:var(--stack,1.5rem)}
.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.tag{display:inline-block;font-family:var(--font-mono);font-size:var(--step--1);
  letter-spacing:var(--track-tight);text-transform:uppercase;color:var(--e-text-muted);
  border:1px solid var(--e-rule);padding:.2rem .55rem}
/* rhythm helpers: the gap after a heading, the gap before a grid */
.space-above{margin-top:1.2rem}
.space-below{margin-bottom:2.2rem}

/* ---------- staggered reveal ----------
   Applied by site.js only when motion is allowed. Elements are visible by
   default so the page is fully readable with JS off or broken. */
html.js-reveal [data-reveal]{
  opacity:0;
  transform:translateY(10px);
  transition:opacity calc(var(--dur-slow) * 2) var(--ease),transform calc(var(--dur-slow) * 2) var(--ease);
  will-change:opacity,transform;
}
html.js-reveal [data-reveal].is-in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){
  html.js-reveal [data-reveal]{opacity:1;transform:none;transition:none}
}

/* ---------- dithered edge dissolve ----------
   Plates dissolve into the paper instead of ending on a hard rectangular cut.
   The mask is a 1-bit dithered ramp, not a soft gradient: a feathered edge would
   read as an airbrush and fight the ordered dithering. This is the same move the
   logo makes where the H breaks into dots. */
.plate--dissolve canvas,
.plate--dissolve > img,
.plate--dissolve .plateimg{
  -webkit-mask-image:url("./images/mask-dither-bottom.png");
          mask-image:url("./images/mask-dither-bottom.png");
  -webkit-mask-size:cover; mask-size:cover;
  -webkit-mask-position:center; mask-position:center;
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
}
.plate--dissolve{border-block:0}

.hero__plate--dissolve canvas,
.hero__plate--dissolve img{
  -webkit-mask-image:url("./images/mask-dither-all.png");
          mask-image:url("./images/mask-dither-all.png");
  -webkit-mask-size:cover; mask-size:cover;
  -webkit-mask-position:center; mask-position:center;
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
}
.hero__plate--dissolve{border:0;background:transparent}

/* ============================================================
   DITHER AS THEME
   The photography is never dithered - the images already carry their own dot
   work, and re-quantising them destroys the subject. Dither lives in the site
   chrome instead: the ground, the rules, the edges, the states.
   ============================================================ */

/* Images ship exactly as generated. Only the EDGE dissolves, so a plate ends in
   dots rather than on a hard rectangular cut. */
.plateimg{width:100%;height:auto;display:block}
.plate .plateimg{aspect-ratio:auto}

/* ---------- hero: overlap layout, ambient motion ----------
   Type crosses the plate rather than sitting in a column beside it. The plate is
   full-bleed and dissolves on every edge, so the band never ends on a hard cut. */
.hero--overlap{
  position:relative;padding:0;isolation:isolate;overflow:hidden;
  margin-top:calc(var(--header-clear) * -1);padding-top:var(--header-clear);
}
.hero--overlap .hero__media{
  /* A defined glass pane floating on the fabric - not a full-bleed fade. Box
     kept near the 3:2 source aspect so the portrait sits almost uncropped. */
  position:absolute;inset:clamp(8px,2.5vw,28px) clamp(8px,2.5vw,28px) clamp(14px,3vw,34px) 36%;
  z-index:0;
  border-radius:var(--radius-pane);
  overflow:hidden;
  border:1px solid var(--glass-border);
  animation:heroGlow 6s ease-in-out infinite alternate;
}
/* faint breathing red glow - decorative, never carries information */
@keyframes heroGlow{
  from{box-shadow:0 18px 48px -20px color-mix(in srgb,var(--e-ink-900) 40%,transparent),
                  0 0 42px -14px color-mix(in srgb,var(--e-red-600) 34%,transparent)}
  to  {box-shadow:0 18px 48px -20px color-mix(in srgb,var(--e-ink-900) 40%,transparent),
                  0 0 78px -10px color-mix(in srgb,var(--e-red-600) 52%,transparent)}
}
@media (prefers-reduced-motion:reduce){
  .hero--overlap .hero__media{animation:none;
    box-shadow:0 18px 48px -20px color-mix(in srgb,var(--e-ink-900) 40%,transparent),
               0 0 60px -12px color-mix(in srgb,var(--e-red-600) 42%,transparent)}
}
/* specular top edge, same as the navbar */
.hero--overlap .hero__media::after{
  content:"";position:absolute;top:0;left:0;right:0;height:1px;z-index:2;pointer-events:none;
  background:var(--specular);
}
.hero--overlap .hero__media canvas{object-position:52% 42%}
.hero--overlap .hero__media canvas{width:100%;height:100%;display:block;object-fit:cover}
.hero--overlap .hero__inner{
  position:relative;z-index:1;
  min-height:clamp(460px,64vh,720px);
  display:flex;align-items:center;
}
.hero--overlap .hero__type{max-width:44ch;padding-block:clamp(3rem,7vw,6rem)}
.hero--overlap h1{font-size:var(--step-5);letter-spacing:-.035em;line-height:.98}
.hero--overlap .lede{margin-top:1.1rem;max-width:38ch}

/* The grid break: a red rule that runs off the left edge of the container. */
.hero--overlap .hero__type::before{
  content:"";position:absolute;left:calc(var(--gutter) * -1);top:clamp(3rem,7vw,6rem);
  width:clamp(28px,5vw,72px);height:3px;background:var(--e-accent);
}
/* Type sits on paper even where it crosses the plate, so contrast never depends
   on what the photograph happens to be doing behind it. */
.hero--overlap .hero__inner::before{
  content:"";position:absolute;inset:0 auto 0 0;width:min(66%,820px);z-index:-1;
  background:linear-gradient(to right,var(--e-bg) 0%,var(--e-bg) 46%,transparent 100%);
}
@media (max-width:860px){
  /* mobile keeps the glass pane - framed, rounded, glowing - not a washed
     edge-to-edge ghost. The face crops tighter but reads as an object. */
  .hero--overlap .hero__media{inset:8px 8px 12px 8px;border-radius:var(--radius-pane)}
  .hero--overlap .hero__inner::before{width:100%;
    background:linear-gradient(to bottom,color-mix(in srgb,var(--e-bg) 92%,transparent) 0%,color-mix(in srgb,var(--e-bg) 64%,transparent) 58%,transparent 100%)}
  .hero--overlap .hero__type{max-width:none}
}

/* ---------- subpage hero plate ----------
   A picture sitting in a neat rectangle beside a column of text is the WordPress
   two-column block, and no amount of styling inside the box fixes that. The plate
   escapes the container to the right viewport edge, runs taller than the text, and
   fades in from the left so it merges with the page rather than being placed on it. */
.hero__plate--bleed{
  margin:0;
  position:relative;
  margin-right:calc(50% - 50vw);
  align-self:stretch;
  min-height:clamp(340px,46vw,560px);
  border:0;background:transparent;overflow:hidden;
}
.hero__plate--bleed .plateimg{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:center;
  aspect-ratio:auto;
  -webkit-mask-image:linear-gradient(to right,transparent 0%,rgba(0,0,0,.6) 12%,#000 30%);
          mask-image:linear-gradient(to right,transparent 0%,rgba(0,0,0,.6) 12%,#000 30%);
}
.hero__grid:has(.hero__plate--bleed){grid-template-columns:minmax(0,1fr) minmax(0,1.25fr);align-items:stretch}
.hero:has(.hero__plate--bleed){overflow:visible}
@media (max-width:900px){
  .hero__plate--bleed{margin-right:calc(50% - 50vw);margin-left:calc(50% - 50vw);
    min-height:clamp(240px,58vw,380px)}
  .hero__plate--bleed .plateimg{
    -webkit-mask-image:linear-gradient(to bottom,#000 62%,transparent 100%);
            mask-image:linear-gradient(to bottom,#000 62%,transparent 100%)}
}

/* ---------- one duotone for every photograph ----------
   Images read as "stitched in" when each keeps its own colour identity. Putting
   them all through the same red/ink duotone makes them a family and makes them
   belong to the brand rather than to whatever generated them. `color` blending
   swaps hue and leaves luminance alone, so detail survives. */
.hero__plate--bleed,.card__media,.plate{position:relative;isolation:isolate}
/* A true duotone: desaturate first, then MULTIPLY the red. `color` blending takes
   luminance from the backdrop, so over a light photograph it washes everything to
   flat pink. Multiply over greyscale keeps blacks black and tints the rest. */
.hero__plate--bleed .plateimg,
.plate .plateimg{filter:grayscale(1) contrast(1.12)}
.hero__plate--bleed::after,
.plate::after{
  content:"";position:absolute;inset:0;pointer-events:none;z-index:3;
  background:var(--e-red-600);
  mix-blend-mode:multiply;
  opacity:.10;
}
/* Keep the existing bottom fade on cards working underneath the duotone. */
.plate::after{opacity:.08}

/* Solo hero: no plate, so the type gets the full measure instead of half a grid. */
.hero__grid--solo{grid-template-columns:1fr}
.hero__grid--solo > div{max-width:60ch}

/* ---------- living background ----------
   A fixed dither field sits behind everything. Because it is fixed, the page
   scrolls OVER it rather than dragging it along, so the motion stays stable while
   the content moves - the background belongs to the site, not to the section. */
#ambient{
  position:fixed;inset:0;z-index:-2;pointer-events:none;
  width:100%;height:100%;display:block;
}

/* Liquid-glass surfaces: content panels float over the living field with a real
   backdrop blur, so the dither is visible THROUGH the page rather than beside it. */
.band > .wrap,
.hero__inner{position:relative}

/* The fabric wash. Fixed, so content scrolls over it; under the ambient dot
   canvas (z -2), over the flat ground. If you can consciously see fabric, it is
   too strong - it is here to give the glass something to pick up. */
body::before{
  content:"";position:fixed;inset:0;z-index:-3;pointer-events:none;
  background:url("./images/bg-fabric.jpg") center/cover no-repeat;
  opacity:.42;
}
body[data-surface="ink"]::before{opacity:.08}

/* padlock lockup beside the privacy heading */
.secrets-head{display:flex;align-items:center;gap:clamp(1rem,2.5vw,1.8rem)}
.secrets-head canvas{width:clamp(84px,9vw,126px);height:auto;aspect-ratio:126/150;flex:0 0 auto}

/* ---------- leaf band: glass boxes over the artwork ----------
   The leaf is a background, not a figure. Text rides on frosted panes that
   BLUR what is behind them - the distortion is what makes them read as glass
   instead of a clear window. Fixed attachment gives the scroll effect: the
   leaf holds still while the panes travel over it. */
.leafband{
  position:relative;
  background:url("./images/11-sustainability-leaf.jpg") center 30%/cover no-repeat;
  background-attachment:fixed;
  padding-block:clamp(4rem,10vw,8rem);
}
@media (max-width:900px),(pointer:coarse){
  .leafband{background-attachment:scroll}   /* fixed bg janks on mobile */
}
.glassbox{
  --glass-blur:10px;
  --glass-bg:color-mix(in srgb,var(--e-bg) 46%,transparent);
  background:var(--glass-bg);
  backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-sat)) contrast(1.05);
  -webkit-backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-sat)) contrast(1.05);
  border:1px solid var(--glass-border);
  border-radius:var(--radius-pane);
  padding:clamp(1.2rem,2.5vw,2rem);
  max-width:56ch;
  box-shadow:var(--elev-2);
}
.glassbox+.glassbox{margin-top:clamp(1rem,2.5vw,1.6rem)}
.glassbox:nth-of-type(even){margin-left:auto}   /* panes stagger across the leaf */

/* neumorphic lock toggle, in paper - soft extrusion, no colour but the red */
.lockswitch{display:inline-flex;align-items:center;gap:.9rem;margin-top:1.2rem;cursor:pointer}
.lockswitch input{position:absolute;opacity:0;width:1px;height:1px}
.lockswitch__track{
  width:64px;height:34px;border-radius:17px;position:relative;flex:0 0 auto;
  background:var(--e-bg);
  box-shadow:inset 3px 3px 7px color-mix(in srgb,var(--e-ink-900) 16%,transparent),
             inset -3px -3px 7px color-mix(in srgb,#fff 85%,transparent);
  transition:background var(--dur-slow) ease;
}
.lockswitch__thumb{
  position:absolute;top:4px;left:4px;width:26px;height:26px;border-radius:50%;
  background:var(--e-accent);
  box-shadow:2px 3px 6px color-mix(in srgb,var(--e-ink-900) 30%,transparent);
  transition:left var(--dur-slow) var(--ease);
}
.lockswitch input:checked + .lockswitch__track .lockswitch__thumb{left:34px}
.lockswitch input:focus-visible + .lockswitch__track{outline:2px solid var(--e-accent);outline-offset:3px}
.lockswitch__label{font-family:var(--font-mono);font-size:var(--step--1);
  letter-spacing:var(--track-tight);text-transform:uppercase;color:var(--e-text-muted)}
@media (prefers-reduced-motion:reduce){.lockswitch__thumb{transition:none}}

/* batch-3 placements - each at whisper strength, content always in front */
.proofband{position:relative;isolation:isolate}
.proofband::before{
  content:"";position:absolute;inset:0;z-index:-1;opacity:.14;pointer-events:none;
  background:url("./images/38-proof-ledger-ground.jpg") center/cover no-repeat;
  -webkit-mask-image:linear-gradient(to bottom,transparent,#000 20%,#000 80%,transparent);
          mask-image:linear-gradient(to bottom,transparent,#000 20%,#000 80%,transparent);
}
.pull--handset{position:relative;overflow:hidden}
.pull--handset::before{
  content:"";position:absolute;inset:0;z-index:-1;opacity:.16;pointer-events:none;
  background:url("./images/39-quote-handset-waiting.jpg") right center/cover no-repeat;
}
.horizon{
  height:clamp(160px,24vw,300px);
  background:url("./images/40-footer-horizon.jpg") center 65%/cover no-repeat;
  -webkit-mask-image:linear-gradient(to bottom,transparent,#000 30%);
          mask-image:linear-gradient(to bottom,transparent,#000 30%);
  margin-top:var(--band);
}

/* subpage glass pane for plates that carry their own art direction */
.hero__pane{
  margin:0;position:relative;border-radius:var(--radius-pane);overflow:hidden;
  border:1px solid var(--glass-border);
  animation:heroGlow 6s ease-in-out infinite alternate;
}
.hero__pane .plateimg{aspect-ratio:3/2;object-fit:cover;width:100%}
.plateimg--own{filter:none !important}
@media (prefers-reduced-motion:reduce){.hero__pane{animation:none}}

/* Patti's thinking bubble - glass, with typing dots */
.patti-bubble{
  --glass-blur:10px;
  display:inline-flex;align-items:center;gap:.7rem;margin-top:1.3rem;
  padding:.8rem 1.1rem;border-radius:var(--radius-pane) var(--radius-pane) var(--radius-pane) 4px;
  background:var(--glass-bg);
  backdrop-filter:blur(var(--glass-blur));-webkit-backdrop-filter:blur(var(--glass-blur));
  border:1px solid var(--glass-border);
  font-family:var(--font-mono);font-size:var(--step--1);
  letter-spacing:var(--track-tight);text-transform:uppercase;color:var(--e-text-muted);
}
.patti-bubble__dots{display:inline-flex;gap:4px}
.patti-bubble__dots i{
  width:6px;height:6px;border-radius:50%;background:var(--e-accent);
  animation:pattiDot 1.3s ease-in-out infinite;
}
.patti-bubble__dots i:nth-child(2){animation-delay:.18s}
.patti-bubble__dots i:nth-child(3){animation-delay:.36s}
@keyframes pattiDot{0%,60%,100%{opacity:.25;transform:none}30%{opacity:1;transform:translateY(-3px)}}
@media (prefers-reduced-motion:reduce){.patti-bubble__dots i{animation:none;opacity:.6}}

/* the spider bots */
.spider-field{position:fixed;inset:0;pointer-events:none;z-index:40;overflow:hidden}
.spider{position:absolute;top:0;left:0;color:var(--e-ink-800);opacity:0;
  will-change:transform;transition:opacity var(--dur-slow) ease}
.spider--walking .legs--a{animation:legA .22s ease-in-out infinite alternate;transform-origin:center}
.spider--walking .legs--b{animation:legB .22s ease-in-out infinite alternate;transform-origin:center}
@keyframes legA{from{transform:rotate(6deg)}to{transform:rotate(-6deg)}}
@keyframes legB{from{transform:rotate(-6deg)}to{transform:rotate(6deg)}}

/* the :has() bleed rule outspecifies the 900px collapse - restate it for mobile */
@media (max-width:900px){
  .hero__grid:has(.hero__plate--bleed),
  .hero__grid:has(.hero__pane){grid-template-columns:1fr}
  .hero__plate--bleed,.hero__pane{order:2;min-height:clamp(220px,52vw,340px)}
  .hero__plate--bleed .plateimg{position:absolute}
}

/* transparent-cutout hero: no pane, no border - the object sits ON the paper
   and its own dissolve does the edgework. The strongest integration we have. */
.hero__stack{margin:0;position:relative}
.hero__stack .plateimg{width:100%;height:auto;
  filter:drop-shadow(0 24px 40px color-mix(in srgb,var(--e-ink-900) 35%,transparent))}

/* THE SPIDERS click toy */
.spiders-title{
  display:inline-flex;align-items:baseline;gap:.7rem;
  background:none;border:0;padding:.2rem .2rem;cursor:pointer;color:var(--e-text);
}
.spiders-title__word{
  font:inherit;display:inline-block;text-align:left;
}
.spiders-title:hover .spiders-title__word{color:var(--e-accent-text)}
.spiders-title.is-bounce .spiders-title__word{animation:spiderBounce .5s cubic-bezier(.28,2.2,.4,1)}
@keyframes spiderBounce{
  0%{transform:none}30%{transform:translateY(-9px) scale(1.05)}
  55%{transform:translateY(2px) scale(.98)}100%{transform:none}
}
@media (prefers-reduced-motion:reduce){.spiders-title.is-bounce .spiders-title__word{animation:none}}

/* Glass falls back to solid paper where backdrop-filter is unsupported. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .site-header,.nav{background:var(--e-bg)}
  .card,.scroller,.glassbox,.patti-bubble{background:var(--e-bg-raised)}
}
