/* site.css — mariewilde.com
   Dark, cinematic, her #78c5f1 accent. Colors come from CSS vars the renderer
   injects from config/site, so she can change the theme from the editor without
   touching this file.
   Mobile-first: every block is single-column by default and opens up at 700px. */

*, *::before, *::after { box-sizing: border-box; }

/* The browser's own [hidden] rule is display:none, but any author rule that
   sets display beats it — .btn{display:inline-block} was unhiding the stepped
   form's Back/Next/Send buttons. Make hidden actually mean hidden. */
[hidden] { display: none !important; }

:root {
  --accent: #78c5f1;
  --bg: #000;
  --fg: #fff;
  --muted: rgba(255,255,255,.62);
  --rule: rgba(120,197,241,.45);
  --surface: rgba(255,255,255,.05);
  --surface-2: rgba(255,255,255,.09);
  --radius: 10px;
  --pad: clamp(1rem, 4vw, 2.5rem);
  --measure: 68ch;
  /* Overridden per-site by the theme block the renderer injects. */
  --font: "Helvetica Neue", Helvetica, -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
}

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, video { max-width: 100%; height: auto; display: block; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ---------------------------------------------------------------- page bg */

.page-bg { position: fixed; inset: 0; z-index: -1; }
.page-bg video, .bg-still {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  background-size: cover; background-position: center;
}
.bg-veil { position: absolute; inset: 0; background: #000; }

/* ---------------------------------------------------------------- header */

.site-head {
  position: sticky; top: 0; z-index: 50;
  display: flex; align-items: center; gap: 1rem;
  padding: .85rem var(--pad);
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid rgba(255,255,255,.08);
}

.site-logo { flex: 0 0 auto; display: block; }
/* Height arrives as a variable so the mobile rule below can cap it — an
   inline height could not be overridden by this stylesheet. */
.site-logo img { height: var(--logo-h, clamp(28px, 5vw, 40px)); width: auto; }
.site-head.has-logo { gap: clamp(1rem, 3vw, 2rem); }

/* Centred logo: it stacks above centred navigation rather than sharing a row,
   which is the only arrangement that stays optically centred once the menu
   items change length. */
.site-head.logo-center { flex-wrap: wrap; justify-content: center; row-gap: .6rem; }
.site-head.logo-center .site-logo { flex: 1 0 100%; display: flex; justify-content: center; }
.site-head.logo-center .site-nav { flex: 1 0 100%; justify-content: center; }

.site-nav { display: flex; flex-wrap: wrap; gap: clamp(.75rem, 2.5vw, 1.75rem); }
.site-nav a {
  color: var(--fg); font-size: .8rem; letter-spacing: .1em; text-transform: uppercase;
  padding: .3rem 0; border-bottom: 1px solid transparent;
}
.site-nav a:hover, .site-nav a.active { color: var(--accent); border-bottom-color: var(--accent); text-decoration: none; }

.menu-toggle { display: none; background: none; border: 0; cursor: pointer; padding: .4rem; }
.menu-toggle span { display: block; width: 22px; height: 2px; background: var(--fg); margin: 4px 0; transition: .25s; }

@media (max-width: 700px) {
  .menu-toggle { display: block; margin-left: auto; }
  .site-head.has-logo { justify-content: space-between; }
  .site-logo img { height: min(var(--logo-h, 40px), 44px); }
  /* Centred: the logo keeps the middle and the menu button pins to the edge. */
  .site-head.logo-center { justify-content: center; }
  .site-head.logo-center .menu-toggle { position: absolute; right: var(--pad); top: .7rem; margin-left: 0; }
  .site-head.logo-center .site-logo { flex-basis: auto; }
  .site-nav {
    position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; gap: 0;
    background: var(--bg); border-bottom: 1px solid rgba(255,255,255,.1);
    max-height: 0; overflow: hidden; transition: max-height .3s ease;
  }
  .site-nav.open { max-height: 70vh; }
  .site-nav a { padding: .9rem var(--pad); border-bottom: 1px solid rgba(255,255,255,.06); }
}

/* Standalone pages (link-in-bio, recruitment forms) — no nav, no footer,
   content centred in a narrow column the way a landing page should read. */
body.standalone { --main-pad-top: clamp(2rem, 8vw, 4rem); }
body.standalone .blk { max-width: 560px; }
body.standalone .blk-links,
body.standalone .blk-donate { margin-inline: auto; }
body.standalone .blk-form { max-width: 560px; margin-inline: auto; }

/* ---------------------------------------------------------------- layout */

/* Top padding is a variable so the first-block banner can cancel it with the
   exact same value. Previously the padding and its cancelling margin were
   written out separately in three breakpoint variants each, and any drift
   between the two lists reappears as a gap above the banner — which is
   impossible now that both sides read one declaration. */
:root { --main-pad-top: clamp(1.5rem, 5vw, 3.5rem); }
main { padding: var(--main-pad-top) var(--pad) 4rem; }
.blk { margin: 0 auto clamp(1.5rem, 4vw, 2.75rem); max-width: 1100px; }
.blk:last-child { margin-bottom: 0; }

/* Width and text size arrive as variables so they can be reinterpreted per
   breakpoint. Set as plain inline styles they'd be unoverridable. */
.blk-text, .blk-image, .blk-video, .blk-embed { width: calc(var(--w, 100) * 1%); }
.blk-text { font-size: calc(var(--fs, 100) * 1%); }

@media (max-width: 700px) {
  /* Body text should stay readable, so only the amount she scaled ABOVE
     normal is damped — 100% stays 100%, 200% becomes 160%. Oversized
     headings are the actual problem on a phone, so those shrink separately. */
  .blk-text { font-size: calc((100 + (var(--fs, 100) - 100) * 0.6) * 1%); }
  .blk-text, .blk-video, .blk-embed { width: 100%; }
  .blk-image { width: calc(var(--w, 100) * 1%); }
}

.align-left   { text-align: left; }
.align-center { text-align: center; }
.align-right  { text-align: right; }

/* ---------------------------------------------------------------- text */

/* Sized in em so they scale with the block's own text-size slider — the two
   controls multiply instead of one overriding the other. */
.blk-text h1, .blk-text h2, .blk-text h3 { line-height: 1.15; margin: 0 0 .4em; font-weight: 600; }
.blk-text h1 { font-size: 2.4em; }
.blk-text h2 { font-size: 1.7em; }
.blk-text h3 { font-size: 1.25em; }
@media (max-width: 700px) {
  /* The previous caps here (1.75/1.45/1.2rem) assumed a block left at its
     default 100% text size. Press runs its headings at 85%, where the em
     side of min() always won and the cap never engaged — so nothing visibly
     changed there even though the rule was live. These are lower, so they
     bind at the sizes she is actually using, not just at 100%. */
  .blk-text h1 { font-size: min(1.7em, 1.55rem); }
  .blk-text h2 { font-size: min(1.35em, 1.3rem); }
  .blk-text h3 { font-size: min(1.15em, 1.1rem); }
  .blk-text h1, .blk-text h2, .blk-text h3 {
    letter-spacing: -0.01em; overflow-wrap: break-word;
  }
}
.blk-text p { margin: 0 0 1em; }
.blk-text p:last-child { margin-bottom: 0; }

/* ---------------------------------------------------------------- divider */

.blk-divider { display: flex; justify-content: center; }
.blk-divider span { display: block; height: 1px; background: var(--rule); }
.blk-divider.w-short span { width: 80px; }
.blk-divider.w-half span  { width: 50%; }
.blk-divider.w-full span  { width: 100%; }
.blk-divider.d-dots span  { height: 3px; background: none;
  background-image: radial-gradient(var(--rule) 1.5px, transparent 1.6px); background-size: 12px 3px; }
.blk-divider.d-glow span  { height: 2px; filter: blur(1px);
  background: linear-gradient(90deg, transparent, var(--rule), transparent); }
.blk-divider.d-space span { background: none; height: 0; }

/* ---------------------------------------------------------------- grid */

.blk-grid {
  display: grid; gap: var(--gap, 8px);
  grid-template-columns: repeat(var(--mcols, 1), 1fr);
}
@media (min-width: 700px) {
  .blk-grid { grid-template-columns: repeat(var(--cols, 3), 1fr); }
}
.blk-grid figure { margin: 0; }
.grid-item { display: block; width: 100%; padding: 0; border: 0; background: none; cursor: zoom-in; overflow: hidden; border-radius: 4px; }
.grid-item img { width: 100%; transition: transform .45s ease, opacity .3s; }
.grid-item:hover img { transform: scale(1.03); }

.crop-square    .grid-item img { aspect-ratio: 1;    object-fit: cover; }
.crop-portrait  .grid-item img { aspect-ratio: 2/3;  object-fit: cover; }
.crop-landscape .grid-item img { aspect-ratio: 3/2;  object-fit: cover; }

figcaption { font-size: .78rem; color: var(--muted); padding: .5rem 0; letter-spacing: .04em; }

@media (max-width: 700px) {
  /* At 3-4 across on a phone, full captions swamp the thumbnails. They stay in
     the DOM for screen readers and appear in the lightbox instead. */
  .blk-grid[style*="--mcols:3"] figcaption,
  .blk-grid[style*="--mcols:4"] figcaption { display: none; }
  .blk-grid { --gap: 4px; }
}

/* ---------------------------------------------------------------- image */

.blk-image img { width: 100%; border-radius: 4px; }
.blk-video video { width: 100%; }

/* ---------------------------------------------------------------- banner

   Full-bleed page header. No rounded corners, no border, no text-shadow —
   the legibility comes from a directional gradient behind the words, which
   reads as photography rather than as a template. The text column is capped
   well short of the full width; a headline running 1600px wide is the single
   clearest sign of a stretched theme. */

.blk-banner {
  position: relative; max-width: none;
  margin-inline: calc(var(--pad) * -1);
  display: grid; overflow: hidden;
  isolation: isolate;
  /* svh alone means the same slider value maps to a different pixel height
     on every screen, which is fine for a hero but not for a strip meant to
     hold a specific logo or line of text — a floor in real units means the
     low end of the slider settles on a height that actually fits typical
     banner content (a small logo, a short heading) rather than requiring a
     screen-height guess that happens to work on one device and not another. */
  min-height: max(calc(var(--h, 70) * 1svh), 4.5rem);
}

/* A banner as the first block should meet the top of the page rather than
   float below it. Zeroing main's top padding is exact whatever that padding
   happens to be — the previous approach cancelled it with a negative margin
   that had to be kept numerically in step with three separate clamp values
   (default, standalone, standalone-mobile), and any drift or specificity
   loss between them reappears as a visible gap above the artwork. */
/* A banner as the first block meets the top of the page. This cancels exactly
   the padding applied above, whatever breakpoint set it, because both sides
   are the same variable. No :has() dependency and no numbers to keep in sync. */
/* A banner as the first block meets the top of the page. The nudge slider is
   added here rather than as an inline margin, so it adjusts from flush rather
   than replacing the cancellation and having to redo it per breakpoint. */
main > .blk-banner:first-child { margin-top: calc(var(--main-pad-top) * -1 + var(--nudge, 0px)); }
.blk-banner { margin-top: var(--nudge, 0px); }

/* A logo placed inside the banner: fixed pixel width, so it renders at the
   same size on every screen. Capped on narrow screens so it can never run
   wider than the phone it is on. */
.banner-logo img {
  width: var(--logo-w, 200px); max-width: 100%; height: auto; display: block;
}
@media (max-width: 700px) {
  .banner-logo img { width: min(var(--logo-w, 200px), 62vw); }
}
/* Inside a column it behaves like any other block. */
.blk-cols .blk-banner { margin-inline: 0; }

/* Standalone pages cap every block at 560px — a banner has to opt out or it
   would sit in a narrow letterbox. */
body.standalone .blk-banner { max-width: none; }

.banner-media, .banner-shade { position: absolute; inset: 0; }
.banner-media img, .banner-video, .banner-still {
  width: 100%; height: 100%; object-fit: cover;
  object-position: var(--fx, 50%) var(--fy, 50%);
  background-size: cover; background-position: var(--fx, 50%) var(--fy, 50%);
}
/* A logo or graphic on a colour card needs to be seen whole, not cropped to
   fill the box the way a photo is — "cover" was clipping the top of a mark
   at short heights and stretching empty background around it at tall ones,
   which is why the same slider value looked wrong on both desktop and
   mobile at once. "Contain" keeps the whole asset visible and centred,
   independent of how tall the surrounding strip is. */
.banner-media.fit-contain img {
  object-fit: contain;
}

/* "Match the image": for a ready-made banner graphic, where the artwork's own
   proportions should decide the height instead of the slider. The image sits
   in normal flow at full width so the section is exactly as tall as the
   artwork scaled to that width — identical proportions on every screen, which
   is what neither cover (crops the logo) nor contain (letterboxes it) could
   give. Overlays share the same grid cell so text still sits on top. */
.blk-banner.fit-natural { min-height: 0; }
.blk-banner.fit-natural > * { grid-area: 1 / 1; }
.blk-banner.fit-natural .banner-media { position: relative; }
.blk-banner.fit-natural .banner-media img {
  position: relative; width: 100%; height: auto; object-fit: fill;
}
.banner-video, .banner-still { position: absolute; inset: 0; }
.banner-video { z-index: 1; }

/* The gradient runs from the corner the text sits in, so the shade is
   heaviest exactly where it is needed and the photo stays clear elsewhere. */
.banner-shade { z-index: 2; opacity: var(--scrim, .55); pointer-events: none;
  background: linear-gradient(to top, #000 0%, rgba(0,0,0,.55) 32%, transparent 68%); }
.pos-top-left .banner-shade, .pos-top-center .banner-shade, .pos-top-right .banner-shade {
  background: linear-gradient(to bottom, #000 0%, rgba(0,0,0,.55) 32%, transparent 68%); }
.pos-middle-left .banner-shade, .pos-middle-center .banner-shade, .pos-middle-right .banner-shade {
  background: radial-gradient(120% 90% at var(--fx, 50%) 50%, rgba(0,0,0,.15) 0%, #000 100%); }
.media-none .banner-shade { background: none; }

.banner-copy {
  position: relative; z-index: 3;
  /* Padding follows the height slider: a full-screen hero gets a generous
     margin, a nav-sized strip gets just enough to breathe. */
  padding: clamp(.55rem, calc(var(--h, 70) * 0.06 * 1svh), 4rem) var(--pad);
  max-width: min(46rem, 100%);
  display: flex; flex-direction: column; align-items: flex-start; gap: .9rem;
}
.pos-top-left .banner-copy, .pos-top-center .banner-copy, .pos-top-right .banner-copy { align-self: start; }
.pos-middle-left .banner-copy, .pos-middle-center .banner-copy, .pos-middle-right .banner-copy { align-self: center; }
.pos-bottom-left .banner-copy, .pos-bottom-center .banner-copy, .pos-bottom-right .banner-copy { align-self: end; }
.pos-top-center .banner-copy, .pos-middle-center .banner-copy, .pos-bottom-center .banner-copy {
  justify-self: center; text-align: center; align-items: center; }
.pos-top-right .banner-copy, .pos-middle-right .banner-copy, .pos-bottom-right .banner-copy {
  justify-self: end; text-align: right; align-items: flex-end; }

.banner-kicker {
  margin: 0; font-size: .74rem; letter-spacing: .28em; text-transform: uppercase;
  color: var(--accent);
}
.banner-heading {
  margin: 0; line-height: 1.02; font-weight: 600;
  letter-spacing: -0.015em;
  font-size: calc(clamp(2.1rem, 6.2vw, 4.6rem) * var(--hs, 100) / 100);
}
.banner-sub {
  margin: 0; max-width: 46ch; white-space: pre-line;
  font-size: clamp(1rem, 1.6vw, 1.22rem); line-height: 1.5;
  color: color-mix(in srgb, var(--fg) 82%, transparent);
}
.blk-banner .btn { margin-top: .5rem; }

/* Drift is off by default and slow when on — anything faster looks like a
   screensaver rather than a title sequence. */
.blk-banner.kb .banner-media img { animation: banner-drift 28s ease-in-out infinite alternate; }
@keyframes banner-drift { from { transform: scale(1); } to { transform: scale(1.08); } }

@media (max-width: 700px) {
  /* A hero sized for a laptop is overwhelming on a phone, so tall banners are
     capped — but a strip she set deliberately keeps the height she chose. */
  .blk-banner { min-height: min(calc(var(--h, 70) * 1svh), 72svh); }
  .banner-heading { font-size: calc(clamp(1.9rem, 10vw, 3rem) * var(--hs, 100) / 100); }
  .banner-sub { font-size: 1rem; }
  .blk-banner .banner-copy { gap: .7rem; }
}

/* ---------------------------------------------------------------- hero */

.blk-hero { position: relative; max-width: none; margin-inline: calc(var(--pad) * -1);
  display: grid; place-items: center; overflow: hidden; }
.blk-hero.h-medium { min-height: 45vh; }
.blk-hero.h-large  { min-height: 68vh; }
.blk-hero.h-full   { min-height: 100svh; }
.hero-video, .hero-still { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; background-size: cover; background-position: center; }
.hero-veil { position: absolute; inset: 0; background: #000; }
.hero-copy { position: relative; text-align: center; padding: var(--pad); max-width: 60ch; }
.hero-copy h1 { font-size: clamp(2rem, 7vw, 4rem); line-height: 1.05; margin: 0 0 .4em; }
.hero-copy p  { font-size: clamp(1rem, 2.4vw, 1.3rem); color: var(--muted); margin: 0 0 1.5em; }

/* ---------------------------------------------------------------- video / embed */

.blk-video video { width: 100%; border-radius: var(--radius); background: #111; }

.blk-embed { position: relative; }
.blk-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; border-radius: var(--radius); }
.ar-16x9 { aspect-ratio: 16/9; }
.ar-9x16 { aspect-ratio: 9/16; max-width: 420px; margin-inline: auto; }
.ar-1x1  { aspect-ratio: 1; }
.ar-4x3  { aspect-ratio: 4/3; }

/* ---------------------------------------------------------------- buttons */

.blk-buttons { display: flex; flex-wrap: wrap; gap: .75rem; }
.blk-buttons.align-center { justify-content: center; }
.blk-buttons.align-right  { justify-content: flex-end; }
.blk-buttons.stack-column { flex-direction: column; align-items: stretch; }

@media (max-width: 700px) {
  /* Two buttons stacking full width down a phone screen wastes the fold and
     reads as a form, not a pair of choices — so keep them side by side.
     A fixed flex-basis guessed in rem loses the race against real text: a
     longer label in a wider display font can wrap inside its own pill while
     its neighbour stays on one line, making the row lopsided instead of two
     matched capsules (seen with "Casting Networks" in a serif face). Sizing
     from content and forbidding wrap avoids the guess entirely — each button
     is exactly as wide as its label needs, never taller than the other. */
  .blk-buttons:not(.stack-column) { flex-wrap: nowrap; gap: .5rem; }
  .blk-buttons:not(.stack-column) .btn {
    flex: 1 1 0; min-width: 0;
    padding-inline: .7rem;
    font-size: clamp(.58rem, 2.6vw, .72rem); letter-spacing: .05em;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  /* A lone button keeps its natural width rather than stretching edge to edge. */
  .blk-buttons:not(.stack-column) .btn:only-child { flex: 0 1 auto; white-space: normal; }
  /* Three or more no longer fit on one row without truncating badly, so past
     two, drop to two per row instead of shrinking text further. */
  .blk-buttons:not(.stack-column) .btn:nth-child(3) { flex-basis: 100%; }
}

.btn {
  display: inline-block; padding: .8rem 1.6rem; border-radius: 999px;
  font-size: .8rem; letter-spacing: .12em; text-transform: uppercase;
  border: 1px solid var(--accent); transition: .2s; cursor: pointer; text-align: center;
}
.btn:hover { text-decoration: none; transform: translateY(-1px); }
.btn-solid   { background: var(--accent); color: #06202e; font-weight: 600; }
.btn-solid:hover { background: color-mix(in srgb, var(--accent) 85%, #fff); }
.btn-outline { background: transparent; color: var(--accent); }
.btn-outline:hover { background: color-mix(in srgb, var(--accent) 15%, transparent); }
.btn-ghost   { background: none; border-color: transparent; color: var(--accent); }

/* ---------------------------------------------------------------- social */

.blk-social { display: flex; gap: 1.1rem; }
.blk-social.align-center { justify-content: center; }
.blk-social.align-right  { justify-content: flex-end; }
.blk-social a { display: grid; place-items: center; color: var(--fg); opacity: .75; transition: .2s; }
.blk-social a:hover { opacity: 1; color: var(--accent); transform: translateY(-2px); }
.blk-social svg { fill: currentColor; }
.size-small  svg { width: 20px; height: 20px; }
.size-medium svg { width: 26px; height: 26px; }
.size-large  svg { width: 34px; height: 34px; }

/* ---------------------------------------------------------------- links */

.blk-links { display: grid; gap: .75rem; max-width: 640px; margin-inline: auto; }

.link-row {
  position: relative; display: flex; align-items: stretch;
  background: var(--surface); border: 1px solid rgba(255,255,255,.1);
  border-radius: var(--radius); transition: .2s; overflow: hidden;
}
.link-row:hover { background: var(--surface-2); border-color: var(--accent); transform: translateY(-2px); }
.link-row.featured { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }

.link-card {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: .9rem;
  padding: .8rem 1rem; color: var(--fg);
}
.link-text strong { font-size: .98rem; line-height: 1.25; }

@media (max-width: 700px) {
  /* A phone has no width to spare. The balancing spacer opposite the thumbnail
     costs ~40px, which is the difference between a title fitting on one line
     and wrapping — so it's dropped here and the title takes the space instead.
     The share control is narrow enough that the result still reads as centred. */
  .blk-links { gap: .5rem; }
  .link-card { padding: .55rem .6rem; gap: .55rem; }
  .link-card .link-end { display: none; }
  .link-text strong { font-size: .92rem; letter-spacing: -0.01em; }
  .link-card .thumb { flex-basis: min(var(--thumb, 46px), 44px); }
  .link-card .thumb img { width: min(var(--thumb, 46px), 44px); height: min(var(--thumb, 46px), 44px); }
  .link-share { flex-basis: 34px; border-left: 0; }
  .link-share svg { width: 15px; height: 15px; }

  /* Cards run closer to the screen edge, as a link-in-bio page should. */
  body.standalone { --main-pad-top: 1.25rem; }
  body.standalone main { padding-inline: .75rem; }
  /* …so the banner's bleed has to match that narrower padding here. */
  body.standalone .blk-banner { margin-inline: -.75rem; }
  body.standalone .blk { margin-bottom: 1.1rem; }
}
.link-card:hover { text-decoration: none; }

/* Thumbnail and the reserved slot opposite it are the same width, which keeps
   the title optically centred whether or not this link has artwork. */
.link-card .thumb,
.link-card .link-end { flex: 0 0 var(--thumb, 46px); }
.link-card .thumb img {
  width: var(--thumb, 46px); height: var(--thumb, 46px);
  object-fit: cover; border-radius: 6px; display: block;
}
.blk-links[style*="--thumb:0px"] .thumb,
.blk-links[style*="--thumb:0px"] .link-end { display: none; }

.link-text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.link-text strong { overflow: hidden; text-overflow: ellipsis; }
.link-text small { color: var(--muted); font-size: .8rem; }
.title-center .link-text { text-align: center; align-items: center; }
.title-left   .link-text { text-align: left; }

.link-share {
  flex: 0 0 44px; display: grid; place-items: center;
  background: none; border: 0; border-left: 1px solid rgba(255,255,255,.08);
  color: var(--muted); cursor: pointer; transition: .15s;
}
.link-share:hover { color: var(--accent); background: rgba(255,255,255,.05); }
.link-share svg { width: 17px; height: 17px; }
.link-share.done { color: var(--accent); }

.style-pill .link-row    { border-radius: 999px; }
.style-minimal .link-row { background: none; border: 0;
  border-bottom: 1px solid rgba(255,255,255,.12); border-radius: 0; }
.style-minimal .link-row:hover { transform: none; background: rgba(255,255,255,.03); }

/* ---------------------------------------------------------------- audio */

.blk-audio h2 { font-size: 1.4rem; margin: 0 0 1rem; }
.audio-body { display: grid; gap: 1.5rem; }
@media (min-width: 700px) { .audio-body.has-art { grid-template-columns: 200px 1fr; } }
.audio-art img { border-radius: var(--radius); }
.track-list { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
.track { display: flex; gap: .9rem; align-items: flex-start; padding: .75rem;
  background: var(--surface); border-radius: var(--radius); }
.track.playing { background: color-mix(in srgb, var(--accent) 14%, transparent); }
.track-play { flex: 0 0 38px; height: 38px; border-radius: 50%; border: 1px solid var(--accent);
  background: none; cursor: pointer; display: grid; place-items: center; }
.ico-play { width: 0; height: 0; margin-left: 3px; border-left: 9px solid var(--accent);
  border-top: 6px solid transparent; border-bottom: 6px solid transparent; }
.playing .ico-play, .ab-toggle.playing .ico-play {
  width: 9px; height: 11px; margin: 0; border: 0;
  border-left: 3px solid var(--accent); border-right: 3px solid var(--accent); }
.track-meta strong { display: block; }
.track-meta time { font-size: .75rem; color: var(--muted); }
.track-meta p { margin: .3rem 0 0; font-size: .85rem; color: var(--muted); }

.audio-bar { position: sticky; bottom: 0; display: flex; align-items: center; gap: .75rem;
  margin-top: 1rem; padding: .7rem 1rem; background: var(--surface-2);
  backdrop-filter: blur(12px); border-radius: var(--radius); }
.ab-toggle { background: none; border: 0; cursor: pointer; display: grid; place-items: center; }
.ab-title { flex: 1; font-size: .85rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ab-seek { flex: 2; accent-color: var(--accent); }
.ab-time { font-size: .75rem; color: var(--muted); font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------- book */

.blk-book { max-width: 760px; border-radius: var(--radius); padding: clamp(1.25rem, 4vw, 2.5rem); }
.blk-book.theme-sepia { background: #f4ecd8; color: #3b3229; }
.blk-book.theme-light { background: #fff; color: #1a1a1a; }
.blk-book.theme-dark  { background: #141414; color: #e8e8e8; }
.book-head { display: flex; gap: 1.25rem; align-items: center; margin-bottom: 1.5rem; }
.book-cover img { width: 110px; border-radius: 4px; box-shadow: 0 6px 24px rgba(0,0,0,.35); }
.book-head h2 { margin: 0; font-size: 1.5rem; }
.book-body { font-size: 1.05rem; line-height: 1.85; font-family: Georgia, "Times New Roman", serif; }
.book-body p { margin: 0 0 1.2em; }
.book-body p.gated { display: none; }
.book-gate { margin-top: 1.5rem; padding-top: 1.5rem; border-top: 1px solid currentColor; text-align: center; }
.book-gate p { margin: 0 0 1rem; }

/* ---------------------------------------------------------------- form */

.blk-form { max-width: 640px; }
.blk-form h2 { font-size: 1.5rem; margin: 0 0 .75rem; }
.field { margin-bottom: 1.1rem; }
.field label { display: block; font-size: .78rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted); margin-bottom: .4rem; }
.req { color: var(--accent); }
.field input, .field textarea, .field select {
  width: 100%; padding: .8rem 1rem; font: inherit; font-size: .95rem;
  color: var(--fg); background: var(--surface);
  border: 1px solid rgba(255,255,255,.16); border-radius: var(--radius);
  transition: border-color .2s;
}
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none; border-color: var(--accent);
}
.field textarea { resize: vertical; min-height: 120px; }
.field select option {
  background: #14141a; color: #fff;   /* options don't inherit; set explicitly */
}
.field.type-checkbox { display: flex; align-items: center; gap: .6rem; }
.field.type-checkbox input { width: auto; }
.field.type-checkbox label { margin: 0; }
.field.invalid input, .field.invalid textarea, .field.invalid select { border-color: #ff6b6b; }
.field .err { display: block; margin-top: .35rem; font-size: .78rem; color: #ff8a8a;
  text-transform: none; letter-spacing: 0; }

/* check all that apply */
fieldset.type-checkboxes { border: 0; margin: 0 0 1.1rem; padding: 0; }
fieldset.type-checkboxes legend {
  padding: 0 0 .5rem; font-size: .78rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted);
}
.check {
  display: flex; align-items: center; gap: .7rem; padding: .6rem .8rem;
  margin-bottom: .4rem; background: var(--surface);
  border: 1px solid rgba(255,255,255,.14); border-radius: var(--radius);
  cursor: pointer; transition: .15s;
}
.check:hover { border-color: var(--accent); }
.check input { width: 18px; height: 18px; accent-color: var(--accent); flex: 0 0 auto; }
.check span { font-size: .95rem; }
fieldset.invalid legend { color: #ff8a8a; }

/* stepped forms */
.fstep-title { font-size: 1.1rem; margin: 0 0 1rem; }
.fnav { display: flex; gap: .75rem; margin-top: .5rem; }
.fprogress { display: flex; align-items: center; gap: .75rem; margin-top: 1rem;
  height: 3px; background: rgba(255,255,255,.12); border-radius: 999px; position: relative; }
.fprogress span { display: block; height: 3px; background: var(--accent);
  border-radius: 999px; transition: width .3s ease; }
.fprogress em { position: absolute; right: 0; top: .6rem; font-style: normal;
  font-size: .75rem; color: var(--muted); }

.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.form-status { margin: 1rem 0 0; font-size: .9rem; min-height: 1.4em; }
.form-status.error { color: #ff8a8a; }
.form-status.ok { color: var(--accent); }
form.sent { opacity: .5; pointer-events: none; }

/* ---------------------------------------------------------------- donate */

.blk-donate { max-width: 640px; text-align: center; }
.blk-donate.style-cards { max-width: 920px; }
.blk-donate h2 { font-size: 1.5rem; margin: 0 0 .6rem; }
.donate-intro { color: var(--muted); margin-bottom: 1.25rem; }
.donate-goal { margin: 1rem 0 0; font-size: .85rem; color: var(--muted); }

.pay-list { display: grid; gap: .6rem; }

/* Cards style: a real grid with its own column count, not the buttons layout
   forced into two columns. Falls back to the buttons' flat gap when style is
   "buttons" so nothing changes there. */
.style-cards .pay-list {
  gap: 1rem;
  grid-template-columns: repeat(1, 1fr);
}
@media (min-width: 560px) {
  .style-cards .pay-list { grid-template-columns: repeat(min(var(--cols, 3), 2), 1fr); }
}
@media (min-width: 860px) {
  .style-cards .pay-list { grid-template-columns: repeat(var(--cols, 3), 1fr); }
}

.pay {
  display: flex; flex-direction: column; align-items: center; gap: .15rem;
  padding: .9rem 1.1rem; background: var(--surface);
  border: 1px solid rgba(255,255,255,.12); border-radius: var(--radius);
  color: var(--fg); transition: .2s;
}
.pay:hover { border-color: var(--accent); text-decoration: none; transform: translateY(-2px); }
.pay-name { font-size: .74rem; letter-spacing: .12em; text-transform: uppercase; color: var(--accent); }
.pay-handle { font-size: 1.05rem; }
.pay small { color: var(--muted); font-size: .78rem; }

/* Cards get real presence: a taller card, a coloured mark that identifies
   the brand at a glance, and a top accent bar instead of a plain border —
   the "real column layout" ask was for cards that read as cards, not the
   flat pill from the buttons style dropped into a two-column grid. */
.style-cards .pay {
  padding: 1.5rem 1.25rem; gap: .5rem; position: relative; overflow: hidden;
  border-color: rgba(255,255,255,.08);
}
.style-cards .pay::before {
  content: ''; position: absolute; inset: 0 0 auto; height: 3px;
  background: var(--pay-tint, var(--accent));
}
.style-cards .pay-mark {
  width: 2.75rem; height: 2.75rem; border-radius: 50%; margin-bottom: .3rem;
  display: grid; place-items: center; font-weight: 700; font-size: 1.15rem;
  color: #06202e; background: var(--pay-tint, var(--accent));
}
.style-cards .pay-name { font-size: .7rem; }
.style-cards .pay-handle { font-size: 1.15rem; font-weight: 600; }
.style-cards .pay-copy {
  font-size: 1.05rem; font-weight: 600;
  flex-direction: column; gap: .5rem; width: 100%;
}
.style-cards .pay-copy > span {
  overflow-wrap: break-word; word-break: break-word; max-width: 100%;
  text-align: center; font-size: .95rem;
}

/* One tint per brand so a row of cards reads as distinct services rather
   than four identical grey boxes, without depending on traced logo art. */
.pay-cashapp { --pay-tint: #00d64f; }
.pay-venmo   { --pay-tint: #3d95ce; }
.pay-zelle   { --pay-tint: #6d1ed4; }
.pay-paypal  { --pay-tint: #ffc439; }
.pay-other   { --pay-tint: var(--accent); }

.pay-copy {
  display: flex; align-items: center; gap: .6rem; margin-top: .1rem;
  background: none; border: 0; color: var(--fg); font: inherit;
  font-size: 1.05rem; cursor: pointer;
}
.pay-copy em { font-style: normal; font-size: .7rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted); border: 1px solid rgba(255,255,255,.2);
  border-radius: 999px; padding: .15rem .5rem; }
.pay-copy:hover em { color: var(--accent); border-color: var(--accent); }
.pay-copy.copied em { color: var(--accent); }

/* ---------------------------------------------------------------- press */

.blk-press { display: flex; gap: 1.25rem; padding: 1.25rem 0;
  border-bottom: 1px solid rgba(255,255,255,.08); margin-bottom: 0; }
.blk-press.layout-stacked { flex-direction: column; }
.blk-press.layout-text .press-img { display: none; }
.press-img { flex: 0 0 clamp(80px, 20vw, 150px); }
.press-img img { border-radius: 4px; }
.blk-press h3 { margin: 0 0 .3rem; font-size: 1.15rem; line-height: 1.35; }
.press-meta { margin: 0 0 .5rem; font-size: .8rem; color: var(--muted);
  letter-spacing: .06em; text-transform: uppercase; }
.blk-press blockquote { margin: 0; padding-left: 1rem; border-left: 2px solid var(--rule);
  color: var(--muted); font-style: italic; }

/* ---------------------------------------------------------------- columns */

.blk-cols { display: flex; gap: var(--gap, 24px); }
.blk-cols .col { min-width: 0; }
.blk-cols .col > .blk { margin-bottom: 1rem; max-width: none; }
.blk-cols .col > .blk:last-child { margin-bottom: 0; }
.valign-middle { align-items: center; }
.valign-bottom { align-items: flex-end; }
@media (max-width: 700px) { .blk-cols.stackable { flex-direction: column; } }

/* ---------------------------------------------------------------- lightbox */

.lightbox { position: fixed; inset: 0; z-index: 100; display: grid; place-items: center;
  background: rgba(0,0,0,.94); padding: var(--pad); }
@media (max-width: 700px) {
  .lightbox { padding: 0; }
  .lightbox img { max-height: 100svh; max-width: 100vw; border-radius: 0; }
  .lightbox figcaption { position: absolute; left: 0; right: 0; bottom: 0;
    padding: 1rem; background: linear-gradient(transparent, rgba(0,0,0,.8)); }
  .lb-close { top: .5rem; right: .75rem; z-index: 1;
    text-shadow: 0 1px 6px rgba(0,0,0,.9); }
}
.lightbox[hidden] { display: none; }
.lightbox figure { margin: 0; max-width: 100%; max-height: 100%; text-align: center; }
.lightbox img { max-height: 85vh; width: auto; margin-inline: auto; border-radius: 4px; }
.lb-close { position: absolute; top: 1rem; right: 1.25rem; font-size: 2.4rem; line-height: 1;
  background: none; border: 0; color: var(--fg); cursor: pointer; opacity: .8; }
.lb-close:hover { opacity: 1; }

/* ---------------------------------------------------------------- footer */

.site-foot { padding: 2.5rem var(--pad); text-align: center;
  border-top: 1px solid rgba(255,255,255,.08); color: var(--muted); font-size: .8rem; }
.site-foot p { margin: 0; }

/* ---------------------------------------------------------------- motion */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
  .page-bg video, .hero-video, .banner-video { display: none; }
  /* Not just "instant" — the drift should not happen at all, or the image
     would snap straight to its zoomed-in end state. */
  .blk-banner.kb .banner-media img { animation: none !important; transform: none !important; }
}
