/* ==========================================================================
   Code Organa — site.css
   Hand-maintained stylesheet for codeorgana.com (static rebuild of the
   SquareSpace 7.1 site). Design tokens measured from the original site.
   ========================================================================== */

/* ---- Tokens ---------------------------------------------------------- */
:root {
  /* Color primitives (HSL triplets match the original SquareSpace palette) */
  --accent-hsl: 204.39, 79.49%, 38.24%;   /* Code Organa blue  #1470AF */
  --light-hsl: 240, 10.53%, 92.55%;       /* pale lavender-gray #EBEBF1 */
  --dark-hsl: 209.23, 52.7%, 70.98%;      /* soft slate blue    #8EB4DC */
  --white-hsl: 0, 0%, 100%;
  --black-hsl: 0, 0%, 0%;

  --accent: hsl(var(--accent-hsl));
  --heading-font: 'Inter Tight', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --body-font: 'Helvetica Neue', Helvetica, Arial, sans-serif;

  /* Type scale. Lifted verbatim from live's stylesheet (site.css?nocustom),
     which sizes type in TWO branches:

       @media (max-width: 767px) and (orientation: portrait)
         font-size: calc((k - 1) * calc(.012 * min(100vh, 900px)) + 1rem)
       @media (min-width: 768px), (orientation: landscape)
         font-size: min(calc((k - 1) * 1.2vw + 1rem),
                        max(calc((k - 1) * .012 * 1400px + 1rem),
                            calc(k * 1rem)))
     (1400px there is live's --maxPageWidth.)

     where k is live's size token: h1 6.37, h2 4.12, h3 2.74, h4 1.57,
     large-text 1.5, normal-text 1.1. Every K below is (k - 1) * 1.2, so the
     SAME K drives both branches — K per 1vw on the wide branch, K per 1% of
     min(100vh, 900px) in portrait — and the inner `max(...)` never wins for
     this site's k values, so the wide branch reduces to the min() below.

     This supersedes the earlier "it's vmax" reading, which was a coincidence
     of the viewports it was checked at: in portrait vmax IS vh, and 874 < 900
     so the cap never bit. It breaks in two places vmax cannot express —
     a portrait viewport taller than 900px (live stops growing, vmax does not:
     at 402x1032 live's h1 is 74.0px where vmax gives 82.5, enough to push
     "Expressive" past the Inkwork hero's 354px column and split the word),
     and portrait tablets >=768px, where live switches to the vw branch. */
  --fs-h1: min(calc(1rem + 6.444vw), calc(1rem + 6.444 * 14px));
  --fs-h2: min(calc(1rem + 3.744vw), calc(1rem + 3.744 * 14px));
  --fs-h3: min(calc(1rem + 2.088vw), calc(1rem + 2.088 * 14px));
  --fs-h4: min(calc(1rem + 0.684vw), calc(1rem + 0.684 * 14px));
  --fs-p: min(calc(1rem + 0.12vw), calc(1rem + 0.12 * 14px));
  --fs-lead: min(calc(1rem + 0.6vw), calc(1rem + 0.6 * 14px));
  --fs-small: 1rem;
  --fs-btn-sm: min(calc(1rem + 0.096vw), calc(1rem + 0.096 * 14px));

  --pad-section-v: clamp(3.2rem, 6.6vw, 6rem);
  --pad-section-h: clamp(1.5rem, 4vw, 3.2rem);
  --cw-narrow: 46vw;   /* live narrow text col = 588.8px @1280 */
  --cw-medium: 69vw;
  --cw-wide: 87.5rem;
  --radius-img: 8px;
  --radius-btn: 6.4px;
}

/* The portrait branch of live's type scale (see the note above): sized off the
   viewport HEIGHT, capped at 900px of it, and never off the width. */
@media screen and (max-width: 767px) and (orientation: portrait) {
  :root {
    --fs-h1: calc(1rem + 6.444 * min(1vh, 9px));
    --fs-h2: calc(1rem + 3.744 * min(1vh, 9px));
    --fs-h3: calc(1rem + 2.088 * min(1vh, 9px));
    --fs-h4: calc(1rem + 0.684 * min(1vh, 9px));
    --fs-p: calc(1rem + 0.12 * min(1vh, 9px));
    --fs-lead: calc(1rem + 0.6 * min(1vh, 9px));
    --fs-btn-sm: calc(1rem + 0.096 * min(1vh, 9px));
  }
}

@font-face {
  font-family: 'Inter Tight';
  src: url('../assets/fonts/InterTight-var.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* ---- Reset ------------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--body-font);
  font-size: var(--fs-p);
  line-height: 1.8;
  letter-spacing: 0.02em;          /* live body text: 0.35px @17.5px */
  color: #000;
  background: #fff;
  -webkit-font-smoothing: antialiased;
}
img, video { max-width: 100%; height: auto; display: block; }
/* Responsive images are <picture><source type=image/webp …><img></picture>
   (built by _reference/tools/build-media.py). display:contents keeps the
   <picture> out of layout so every existing `… img` rule and the lightbox
   keep working exactly as with a bare <img>. */
picture { display: contents; }
h1, h2, h3, h4 {
  font-family: var(--heading-font);
  font-weight: 700;
  line-height: 1.15;
  margin: 0 0 0.5em;
  overflow-wrap: break-word;
  /* Live sets --heading-font-letter-spacing: 0em against the body's .02em;
     without this the headings inherit the body's 0.341px and run wider than
     live's, which moves wrap points (the Inkwork hero measured 327.3/179 per
     line against live's 324.2/176.9 — exact once this is normal). */
  letter-spacing: normal;
}
/* SquareSpace leaves <strong> inside a heading at the heading's own weight
   (measured 700 on live). Without this the UA default `bolder` resolves 700
   to 900, which on the Inter Tight VARIABLE font renders a genuinely heavier
   cut — the Inkwork quote and both Contact headings looked over-bold. */
h1 strong, h2 strong, h3 strong, h4 strong,
h1 b, h2 b, h3 b, h4 b { font-weight: inherit; }
h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); line-height: 1.25; }
h3 { font-size: var(--fs-h3); line-height: 1.33; }
h4 { font-size: var(--fs-h4); line-height: 1.4; }
/* Heading levels with another level's look. Added in the SEO pass so every
   page carries exactly one <h1> (and the long-form guides a real h1 > h2
   outline) without touching the measured type scale: the element keeps the
   shared heading base above and the class supplies the size/leading of the
   level it stands in for. Tag-specific rules further down (.text-page h3,
   .help-page h4, .faq-cols h4) are mirrored for the classes. */
.as-h1 { font-size: var(--fs-h1); line-height: 1.15; }
.as-h2 { font-size: var(--fs-h2); line-height: 1.25; }
.as-h3 { font-size: var(--fs-h3); line-height: 1.33; }
.as-h4 { font-size: var(--fs-h4); line-height: 1.4; }
p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }
ul, ol { margin: 0 0 1em; padding-left: 1.4em; }
a { color: inherit; }
p a:not(.btn):not(.badge-btn), li a {
  color: var(--link, inherit);
  text-decoration: underline;
  text-underline-offset: 2px;
}
/* [href]-qualified: the credits page carries a few <a> with no href, for
   sources that have gone offline. They keep the link's colour and underline
   so the run of names stays even, but must not react to hover. */
p a[href]:hover, li a[href]:hover { opacity: 0.75; }

/* ---- Section themes ---------------------------------------------------
   Mirrors SquareSpace section themes: white / white-bold / light / bright /
   dark / black. Each sets background + ink + button colors.               */
.theme-white, .theme-white-bold {
  --bg: hsl(var(--white-hsl));
  --ink: #000;
  --link: var(--accent);
}
.theme-light {
  --bg: hsl(var(--light-hsl));
  --ink: #000;
  --link: var(--accent);
}
.theme-bright {
  --bg: var(--accent);
  --ink: #fff;
  --link: #fff;
}
.theme-dark {
  --bg: hsl(var(--dark-hsl));
  --ink: #000;
}
.theme-black {
  --bg: hsl(var(--black-hsl));
  --ink: #fff;
  --link: #fff;
}

/* ---- Sections ---------------------------------------------------------- */
.section {
  position: relative;
  display: flex;
  align-items: center;
  background: var(--bg, #fff);
  color: var(--ink, #000);
  padding: var(--pv, var(--pad-section-v)) var(--pad-section-h);
}
.section.h-lg { min-height: 100vh; min-height: 100svh; }
.section.h-md { min-height: 66vh; }
.section.h-sm { min-height: 33vh; }
.section.h-auto { min-height: 0; }
/* Per-section vertical padding scale, measured from the original site
   (values at a 1280px viewport): xl=128px heroes/quotes, default=84px,
   sm=51px galleries/newsletter, md=42px content cards, xs=26px compact
   text bands, 2xs=13px image bands. */
.section.pad-xl { --pv: clamp(4.5rem, 10vw, 8.5rem); }
.section.pad-lg { --pv: var(--pad-section-v); }
.section.pad-sm { --pv: clamp(2rem, 4vw, 3.2rem); }
.section.pad-md { --pv: clamp(1.8rem, 3.3vw, 2.8rem); }
.section.pad-xs { --pv: clamp(1.1rem, 2vw, 1.7rem); }
.section.pad-2xs { --pv: clamp(0.6rem, 1vw, 0.9rem); }
/* First section on pages with a dark (in-flow-looking) header: live pads the
   section by the header height (~161px + 17px block pad) */
/* Live offsets this section by its HEADER HEIGHT, which is not constant:
   160.8px on desktop but only 85.2px on phones (plus, on phones only, the
   17px block padding). Measured heading positions on live: y=245 @1280x800
   and y=160 @402x874. A single hardcoded 177.8px pushed phone headings
   66-130px too far down. */
.section.hdr-pad { padding-top: calc(var(--pv, var(--pad-section-v)) + 160.8px); }
@media (max-width: 767px) {
  .section.hdr-pad { padding-top: calc(var(--pv, var(--pad-section-v)) + 108.8px); }
}

.section > .content {
  position: relative;
  z-index: 2;
  width: 100%;
  margin: 0 auto;
}
.section .content.cw-narrow { max-width: var(--cw-narrow); }
.section .content.cw-medium { max-width: var(--cw-medium); }
.section .content.cw-wide { max-width: var(--cw-wide); }
@media (max-width: 767px) {
  .section .content.cw-narrow, .section .content.cw-medium { max-width: 100%; }
}
.section.align-center { text-align: center; }

/* Desktop-only width constraints (was an inline `max-width:NNvw`), used for the
   narrow intro paragraphs and the before/after sliders on the Pro pages. Those
   vw values are correct at desktop but collapse to ~181px on a phone, which
   squeezed the copy into a narrow ribbon down the middle. Live lets every one
   of them run the full content width (354px @402), so release them there. */
/* `.section` prefix so this outranks component rules that set their own
   max-width later in the file (notably `.ba-slider { max-width: 100% }`). */
.section .mw { max-width: var(--mw); margin-left: auto; margin-right: auto; }
.section .content.mw { max-width: var(--mw); }
@media (max-width: 767px) {
  .section .mw, .section .content.mw { max-width: 100%; }
}

/* A heading followed by a SquareSpace spacer block (About "Follow our work.").
   85px reproduces live's section height at 1280 (590px); on a phone the spacer
   collapses and live's gap is 34px, which likewise reproduces live's 651px.
   NB: measuring live's heading-to-first-image distance gives 70px at desktop,
   but that is not the same quantity — live's instagram block carries its own
   internal padding — so section height is the reliable target here. */
.mb-spacer { margin-bottom: 85px; }
@media (max-width: 767px) { .mb-spacer { margin-bottom: 34px; } }

/* A heading that live follows with one block gap instead of its own margin. */
.mb-17 { margin-bottom: 17px; }

/* Full-bleed background image / video behind content */
.section-bg {
  position: absolute;
  inset: 0;
  overflow: hidden;
  z-index: 0;
}
.section-bg img, .section-bg video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Background videos DO play on phones — live does, and iOS Safari will not
   autoplay an element that is display:none, so hiding it here previously
   killed mobile autoplay while still downloading the file. The poster image
   sits underneath and shows until the first frame decodes. */
/* Live dims video backgrounds with filter:brightness on the video container
   (not an overlay div); the poster image gets the same treatment. */
.section-bg.has-video img, .section-bg.has-video video {
  filter: brightness(var(--vid-brightness, 0.64));
}
.section-bg .overlay {
  position: absolute;
  inset: 0;
  background: var(--bg);
  opacity: 0.15;              /* per-section override via inline style */
}
/* Generative squiggle background (About intro) — replicates live's
   SquareSpace "generative images" canvas: brush3 sprites tinted lightAccent,
   drifting with a gentle wave motion */
.fx-squiggles { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

/* Inset (not full-bleed) background variant — the app testimonials and the
   About quote. Live keeps the SECTION transparent over the white page and
   puts the theme colour + image on a wrapper inset 4vw on all four sides
   (square corners), so a white frame surrounds the picture. */
.section.bg-inset { --pv: calc(var(--pad-section-v) * 0.6); background: #fff; }
.section.bg-inset .section-bg {
  inset: 4vw;
  background: var(--bg);
}

/* ---- Header ------------------------------------------------------------ */
.site-header {
  position: absolute;
  top: 0; left: 0; right: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.4rem clamp(1.5rem, 4vw, 3.2rem);
  color: #fff;                     /* over dark/bright heroes (default) */
}
.site-header.header-dark { color: #000; }  /* pages with a light first section */
.site-header a { text-decoration: none; }
.logo img { width: clamp(56px, 6.6vw, 84px); height: auto; border-radius: 14%; }
.site-nav { display: flex; align-items: center; gap: 1.5rem; font-size: var(--fs-p); }
/* `.nav-panel` only exists so the mobile overlay has something to slide; on
   desktop it is transparent to layout and `.site-nav`'s flex children are the
   links / folder / social row exactly as before. */
.nav-panel { display: contents; }
.site-nav .nav-panel > a, .site-nav .folder > button {
  color: inherit;
  background: none;
  border: 0;
  font: inherit;
  cursor: pointer;
  padding: 0.1em 0;
  opacity: 0.95;
}
.site-nav .nav-panel > a:hover, .site-nav .folder > button:hover { opacity: 0.7; }
/* Current page. The folder carries it too, on any page inside it — live
   underlines "Our Apps" throughout the app pages exactly as it underlines
   About on /about. The button is not a link, so it takes aria-current="true"
   ("current item in a set") rather than "page". */
.site-nav .nav-panel > a[aria-current="page"],
.site-nav .folder > .folder-btn[aria-current="true"] { text-decoration: underline; text-underline-offset: 5px; }
/* Overlay-only affordances (the folder chevron and its Back control). */
.nav-chevron, .folder-back { display: none; }

.folder { position: relative; }
/* Dropdown matches the original: accent-blue panel, white left-aligned items.
   The wrapper's padding-top bridges the hover gap so the menu doesn't close
   while the pointer travels from the button to the panel. */
.folder-menu {
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  padding-top: 0.6rem;
  display: none;
  z-index: 101;
}
.folder-menu-inner {
  background: var(--accent);
  color: #fff;
  border-radius: 6px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.18);
  padding: 0.55rem 0;
  text-align: left;
}
/* Desktop-only: these are `display: block` at (0,3,0), which would otherwise
   outrank the mobile sheet's panel rule and — via :focus-within, as soon as
   focus lands on Back — collapse the slide-over panel into a block flow. */
@media (min-width: 801px) {
  .folder.open .folder-menu, .folder:focus-within .folder-menu { display: block; }
}
@media (hover: hover) and (min-width: 801px) {
  .folder:hover .folder-menu { display: block; }
}
.folder-menu a {
  display: block;
  padding: 0.55rem 1.1rem;
  white-space: nowrap;
  font-size: 1.096rem;
}
.folder-menu a:hover { background: rgba(255, 255, 255, 0.12); }

.social-links { display: flex; align-items: center; gap: 0.9rem; margin-left: 0.4rem; }
.social-links svg { width: 18px; height: 18px; fill: currentColor; display: block; opacity: 0.95; }
.social-links a:hover svg { opacity: 0.7; }
/* Deliberate divergence from the live site (owner, 2026-08-20): no social
   icons in the desktop header — they remain in the mobile menu and footer. */
@media (min-width: 801px) {
  .site-header .social-links { display: none; }
}

/* ---- Mobile menu ------------------------------------------------------- *
   Rebuilt from live (measured at 402x874). Live's overlay is a white
   full-screen sheet with black links; the burger is a TWO-line hamburger that
   rotates into an X, and "Our Apps" slides a second panel over the first
   rather than expanding in place.

   Measured on live and reproduced below:
   - overlay: visibility .6s + opacity .4s cubic-bezier(.4,0,.2,1); the list
     rides up 20px and the social row 55px over .6s (same easing)
   - links: body font, 8.5vw (6.6vw above 640px — live switches scale there,
     it is NOT the h3 token: at 360px live's menu is 30.6px and its h3 34.25),
     weight 400, line-height 1, letter-spacing 0.409px, 3vw/5vw margins, so a
     58.29px pitch at 402 with 24.12px between the text boxes
   - social row: 55px tall, 40px icon pitch, 6vw off the bottom
   - burger: 35x35 box, two 35x1 bars 11px apart, transition transform/width
     .25s cubic-bezier(.2,.6,.3,1); open = 28px wide, translateX(3.5px) and
     rotate(-/+135deg). (Live's third `.patty` bar is scale(0) in BOTH states,
     so it is omitted here rather than reproduced as a no-op.)
   - folder: both panels translate one viewport left; the outgoing panel keeps
     the social row, and a Back control heads the incoming one.

   Two deliberate departures from live, both requested:
   - the items fade/rise in staggered (live moves them as one block)
   - `touch-action: manipulation` + a 44x44 tap target kill iOS's double-tap
     zoom near the burger. Live does neither (its viewport meta is plain and
     everything computes `touch-action: auto`), so this is an improvement on
     live, not parity. Pinch-zoom is untouched. */
.nav-toggle {
  display: none;
  background: none;
  border: 0;
  color: inherit;
  cursor: pointer;
  padding: 0;
  width: 44px;                       /* Apple HIG minimum tap target */
  height: 44px;
  place-items: center;
}
.nav-toggle .burger { position: relative; display: block; width: 35px; height: 35px; }
.nav-toggle .bun {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  margin: auto 0;                    /* centre the 1px bar in the 35px box */
  width: 35px;
  height: 1px;
  background: currentColor;
  transition: transform 0.25s cubic-bezier(0.2, 0.6, 0.3, 1),
              width 0.25s cubic-bezier(0.2, 0.6, 0.3, 1);
}
.nav-toggle .bun-top { transform: translateY(-5.5px); }
.nav-toggle .bun-bottom { transform: translateY(5.5px); }
.nav-toggle[aria-expanded="true"] .bun { width: 28px; }
/* The 3.5px nudge re-centres the shortened bar (it is anchored at left:0). */
.nav-toggle[aria-expanded="true"] .bun-top { transform: translateX(3.5px) rotate(-135deg); }
.nav-toggle[aria-expanded="true"] .bun-bottom { transform: translateX(3.5px) rotate(135deg); }

/* Kills iOS Safari's double-tap-to-zoom on things you tap, without touching
   pinch-zoom (which `user-scalable=no` would have broken). */
a, button, summary { touch-action: manipulation; }

.site-header a:focus-visible,
.site-header button:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 4px;
  border-radius: 2px;
}

@media (max-width: 800px) {
  /* Must track the header's own box (1.4rem padding + logo). The header is
     position:absolute, so its height feeds the overlay but no page geometry. */
  .site-header { --header-h: calc(2.8rem + clamp(56px, 6.6vw, 84px)); }
  .logo { position: relative; z-index: 2; }
  .nav-toggle { display: grid; position: relative; z-index: 2; }
  body.menu-open { overflow: hidden; }
  /* White sheet under a white overlay: force the header ink black like live. */
  body.menu-open .site-header { color: #000; }

  /* ---- the sheet ---- */
  .site-nav {
    position: fixed;
    inset: 0;
    z-index: 1;
    display: block;
    padding-top: var(--header-h);
    background: #fff;
    color: #000;
    overflow: hidden;
    visibility: hidden;
    opacity: 0;
    transition: visibility 0.6s cubic-bezier(0.4, 0, 0.2, 1),
                opacity 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  }
  .site-nav.open { visibility: visible; opacity: 1; }
  /* The panels are scripted focus targets (tabindex -1) for pointer users, so
     focus can leave a panel that is about to be hidden without ringing a link.
     They are containers — never show a ring on them. */
  .site-nav .nav-panel:focus,
  .site-nav .folder-menu:focus { outline: none; }

  /* ---- panel 1: the top-level list ---- */
  .site-nav .nav-panel {
    position: absolute;
    inset: var(--header-h) 0 0 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    transform: translate(0, 20px);
    transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1),
                visibility 0.6s cubic-bezier(0.4, 0, 0.2, 1);
  }
  .site-nav.open .nav-panel { transform: translate(0, 0); }
  /* Auto margins rather than justify-content:center: if the list is ever
     taller than the sheet the autos collapse to 0 and nothing is cut off the
     top, which centring would do. */
  .site-nav .nav-panel > a:first-child { margin-top: auto; }
  .site-nav .nav-panel > a:last-of-type { margin-bottom: auto; }

  /* ---- shared item type ---- */
  .site-nav .nav-panel > a,
  .site-nav .folder > .folder-btn,
  .site-nav .folder-back,
  .site-nav .folder-menu a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin: 3vw 5vw;
    padding: 0;
    font-family: inherit;            /* buttons do not inherit it */
    font-size: 8.5vw;
    line-height: 1;
    font-weight: 400;
    letter-spacing: 0.409px;
    color: #000;
    opacity: 1;
    text-align: center;
    text-decoration: none;
  }
  .site-nav .nav-panel > a[aria-current="page"],
  .site-nav .folder > .folder-btn[aria-current="true"] { text-decoration: none; }
  .site-nav .folder-menu a:hover,
  .site-nav .nav-panel > a:hover,
  .site-nav .folder > .folder-btn:hover { background: none; opacity: 1; }

  .site-nav .nav-chevron {
    display: block;
    flex: none;
    width: 1em;
    height: 1em;
    fill: none;
    stroke: currentColor;
    stroke-width: 0.5;
  }
  .site-nav .folder > .folder-btn .nav-chevron { margin-left: 0.15em; transform: rotate(-90deg); }
  .site-nav .folder-back .nav-chevron { margin-right: 0.15em; transform: rotate(90deg); }

  /* ---- staggered entrance (see note above — live moves these as one) ---- */
  .site-nav .nav-panel > a,
  .site-nav .folder > .folder-btn {
    opacity: 0;
    transform: translateY(12px);
    transition: opacity 0.35s cubic-bezier(0.4, 0, 0.2, 1),
                transform 0.45s cubic-bezier(0.4, 0, 0.2, 1);
  }
  .site-nav.open .nav-panel > a,
  .site-nav.open .folder > .folder-btn { opacity: 1; transform: none; }
  .site-nav.open .nav-panel > a:first-child { transition-delay: 0.06s; }
  .site-nav.open .folder > .folder-btn { transition-delay: 0.12s; }
  .site-nav.open .nav-panel > a:last-of-type { transition-delay: 0.18s; }

  /* ---- panel 2: "Our Apps" ---- */
  /* `.folder` goes static so the panel is positioned against `.nav-panel`
     (which is transformed, so it is the containing block) and the two line up
     exactly one viewport apart. */
  .folder { position: static; display: flex; flex-direction: column; align-items: center; }
  .site-nav .folder-menu {
    position: absolute;
    inset: 0;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    overflow-y: auto;
    padding: 0;
    /* Constant: it sits one panel-width right of `.nav-panel`, so when the
       root slides a viewport left this lands at 0. */
    transform: translateX(100%);
    visibility: hidden;
    transition: visibility 0.6s cubic-bezier(0.4, 0, 0.2, 1);
  }
  .site-nav .folder-menu-inner {
    display: contents;               /* drop the desktop dropdown's chrome */
  }
  .site-nav .folder-menu a:last-child { margin-bottom: auto; }
  .site-nav .folder-back {
    margin-top: auto;
    margin-bottom: calc(3vw + 10px);  /* live pads the Back row 10px extra */
    background: none;
    border: 0;
    cursor: pointer;
    /* Live renders Back grey, not black — the link is black but its row
       (.header-menu-controls) sits at opacity .5. At 34px it is large text,
       so 50% black on white still clears the 3:1 contrast minimum. */
    opacity: 0.5;
  }
  .site-nav.folder-open .nav-panel { transform: translate(-100%, 0); visibility: hidden; }
  .site-nav.folder-open .folder-menu { visibility: visible; }

  /* ---- social row, pinned to the bottom ---- */
  .site-nav .social-links {
    margin: 0 20px 6vw;
    height: 55px;
    gap: 19px;                       /* 21px icons -> live's 40px pitch */
    align-items: center;
    justify-content: center;
    color: #000;
    transform: translateY(55px);
    transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1);
  }
  .site-nav.open .social-links { transform: translateY(0); }
  .site-nav .social-links svg { width: 21px; height: 21px; opacity: 1; }
}

/* Live's overlay type switches scale at 640px; below it the links are 8.5vw. */
@media (min-width: 641px) and (max-width: 800px) {
  .site-nav .nav-panel > a,
  .site-nav .folder > .folder-btn,
  .site-nav .folder-back,
  .site-nav .folder-menu a { font-size: 6.6vw; }
}

@media (prefers-reduced-motion: reduce) {
  .site-nav,
  .site-nav .nav-panel,
  .site-nav .folder-menu,
  .site-nav .social-links,
  .site-nav .nav-panel > a,
  .site-nav .folder > .folder-btn,
  .nav-toggle .bun { transition: none; }
}

/* ---- Hero -------------------------------------------------------------- */
.hero .content { text-align: center; }
.hero p.lead { font-size: var(--fs-lead); margin: 0 auto; max-width: 40em; }

/* ---- Buttons ----------------------------------------------------------- */
/* Medium button (Learn More / See the full list) — measured on live:
   accent bg in every section theme, body font 400, fs 16px+0.12vw,
   padding 1.2em/2.004em, radius 8px */
.btn {
  display: inline-block;
  font-family: var(--body-font);
  font-weight: 400;
  font-size: calc(1rem + 0.12vw);
  line-height: normal;
  padding: 1.2em 2.004em;
  border: 0;
  border-radius: 8px;
  background: var(--accent);
  color: #fff;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.15s ease, opacity 0.15s ease;
}
/* Large secondary button (View on the … App Store) — Inter Tight 500,
   fs 16px+0.324vw, radius 6.4px */
.btn.btn-lg {
  font-family: var(--heading-font);
  font-weight: 500;
  font-size: calc(1rem + 0.324vw);
  border-radius: var(--radius-btn);
}
.btn:hover { opacity: 0.9; transform: scale(1.02); }

/* App Store badge rows */
.badge-row { display: flex; flex-wrap: wrap; gap: clamp(1rem, 2.6vw, 2.2rem); justify-content: center; align-items: center; margin-top: 16.5px; }
.badge-row img { height: 56.6px; width: auto; }
/* Badges under a paragraph that ends in an empty line: live keeps the blank
   line inside the text block, so the badges clear it plus the block padding —
   17px on desktop, and both blocks' 17px (34px) once the phone layout kicks in. */
.badge-row.after-blank-line { margin-top: calc(1.8em + 17px); }
@media (max-width: 767px) {
  .section > .content > .badge-row.after-blank-line { margin-top: calc(1.8em + 34px); }
}
.badge-row a:hover img { opacity: 0.85; }
/* 3-badge variant (Brushstroke Pro intro): live puts each badge centered in
   one of three equal columns of the 80.5vw content row */
.badge-row.badge-row-3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  justify-items: center;
  gap: 0;
  width: 80.5vw;
  margin-left: calc(50% - 40.25vw);   /* center even when wider than parent */
}
/* Phones: live stacks the three badges as three separate blocks, so they sit
   34px apart (17px of block padding each), not 1rem. */
@media (max-width: 767px) { .badge-row.badge-row-3 { display: flex; flex-wrap: wrap; gap: 34px; width: auto; } }

/* Single App Store badge in an image-card caption (app pages) */
.badge-btn { display: inline-block; margin-top: 1.2rem; }
.badge-btn img { height: 62px; width: auto; }
.badge-btn:hover img { opacity: 0.85; }

/* App Store rating line under a store badge (SEO phase 2). The numbers are
   filled in by _reference/tools/update-ratings.py from the App Store lookup
   API, which also writes the matching aggregateRating into the page's JSON-LD
   — Google only shows star snippets when the rating is visible on the page.
   Five stars, the last one fractionally filled via a text-clipped gradient. */
.store-rating {
  margin: 0.85rem 0 0;
  font-size: var(--fs-small);
  line-height: 1.5;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.15em 0.55em;
}
.img-card .caption .store-rating { justify-content: flex-start; }
.align-center .store-rating, .img-stack + .store-rating { justify-content: center; }
.store-rating .stars {
  --fill: calc(var(--rating, 5) / 5 * 100%);
  font-size: 1.05em;
  letter-spacing: 0.08em;
  line-height: 1;
  background: linear-gradient(90deg, var(--accent) var(--fill), rgba(128, 128, 128, 0.35) var(--fill));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.theme-black .store-rating .stars, .theme-bright .store-rating .stars {
  background: linear-gradient(90deg, #fff var(--fill), rgba(255, 255, 255, 0.35) var(--fill));
  -webkit-background-clip: text;
  background-clip: text;
}
.store-rating .rating-text { opacity: 0.72; }
.store-rating:empty { display: none; }
/* "Also available" line under a caption badge / store button */
.also-available { margin: 0.6rem 0 0; font-size: var(--fs-small); line-height: 1.5; opacity: 0.85; }
.fom-note { margin-top: -0.6rem; max-width: 28em; }
@media (max-width: 767px) { .img-card .caption .store-rating { justify-content: center; } }

/* Spacer blocks — live uses fixed-px SquareSpace spacer blocks. Local
   spacers also absorb the 17px vertical padding live text blocks carry:
   text sections (pad-xs): 51+17 above, 0 below (the last paragraph's 17.5px
   margin supplies live's trailing 17px block pad);
   grid sections (pad-md): 68+17+17 after the grid, 68+17-17.5 at the end.
   One-off heights come in as an inline `--sp` rather than an inline `height`,
   so the phone rules below can still override them. */
.spacer { height: var(--sp, 51px); }
.pad-xs .spacer { height: var(--sp, 68px); }
.pad-xs .spacer:last-child { height: var(--sp, 0px); }
.pad-md .spacer { height: var(--sp, 119px); }
.pad-md .spacer:last-child { height: var(--sp, 67.5px); }

/* Phones: live sets every spacer block to `display:none` below 768px, so the
   fixed desktop gaps above vanish. All that is left between two blocks is the
   17px vertical padding each block carries — 34px total — and 17px at the top
   and bottom of the section's content. Reproduce that block model: our markup
   flattens live's blocks, so the section content supplies the outer 17px and a
   spacer stands only for the pair of paddings it separates. Without this the
   Pro pages (the only pages using spacers) ran 43-230px tall per section. */
@media (max-width: 767px) {
  .section > .content { padding-block: 17px; }
  /* ...except galleries, logo rows and carousels: those are a different
     SquareSpace section type on live (a user-items-list, not a block layout)
     and measure a flat 0px of section and block padding on a phone. */
  .section > .content:has(> .gallery-grid),
  .section > .content:has(> .logo-row),
  .section > .content:has(> .ig-grid),
  .section > .content:has(> .palette-carousel) { padding-block: 0; }
  .section > .content > .spacer { height: 34px; }
  .section > .content > .spacer:first-child,
  .section > .content > .spacer:last-child { height: 0; }
  /* live zeroes the trailing margin of a block's last element; the padding
     above is the gap, so a text margin must not be counted a second time */
  .section > .content > :last-child,
  .section > .content > :has(+ .spacer) { margin-bottom: 0; }
  /* the App Store badge sits in a block of its own, so it gets the full 34px
     block gap from the paragraph above it */
  .section > .content > .badge-row { margin-top: 34px; }
}

/* 2x2 feature grid (Pro pages) — live: 225.5px text cols, 137.5px gutter,
   rows 68px apart (+17px block pad) at 1280. DOM order is column-major on
   live (cells read down the left column first). */
.h4-grid {
  display: grid;
  grid-template-columns: repeat(2, 17.617vw);
  justify-content: center;
  column-gap: 10.742vw;
  row-gap: 85px;
}
.h4-grid h4 { margin-bottom: 32px;
  text-align: center;
}
/* Phones: live stacks the four cells as separate blocks, so the gap between
   them is the 17px+17px block padding, not the desktop spacer. */
@media (max-width: 767px) { .h4-grid { grid-template-columns: 1fr; row-gap: 34px; } }

/* Palette strip (Brushstroke Pro) */
/* Palette strip — live is a full-bleed SquareSpace list carousel:
   at 1280px → 172.9px portrait (3:4) slides, 20.1px gaps, 51px left inset,
   7th slide cropped at the right viewport edge */
.palette-carousel {
  position: relative;
  width: 100vw;
  margin-left: calc(50% - 50vw);
}
.palette-row {
  display: flex;
  gap: 1.5703vw;
  padding-left: 3.984vw;
  padding-bottom: 10.3px;
  overflow-x: hidden;
}
/* live: 60px circular arrows 5vw from each edge, centered on the slides */
.palette-arrow {
  position: absolute;
  top: calc(50% - 5px);
  transform: translateY(-50%);
  width: 60px;
  height: 60px;
  border: 0;
  border-radius: 50%;
  background: #EAEAEE;
  color: #000;
  display: grid;
  place-items: center;
  cursor: pointer;
  padding: 0;
}
.palette-arrow.prev { left: 5vw; }
.palette-arrow.next { right: 5vw; }
.palette-arrow.next svg { transform: scaleX(-1); }
.palette-arrow:hover { opacity: 0.85; }
.palette-row img { width: 13.507vw; flex: none; aspect-ratio: 3 / 4; object-fit: cover; }
/* tablet: live carousel shows fewer, larger slides (278.8px wide at 996) */
@media (max-width: 1099px) and (min-width: 768px) {
  .palette-row { gap: 2.018vw; }
  .palette-row img { width: 27.992vw; }
}
@media (max-width: 767px) {
  .palette-carousel { width: 100%; margin-left: 0; }
  .palette-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.45rem; padding: 0; }
  .palette-row img { width: 100%; }
  .palette-row .clone, .palette-arrow { display: none; }
}

/* Vertical badge stack (Made for Mac / iPad sections) */
.badge-col { display: flex; flex-direction: column; align-items: center; gap: 34px; margin-top: 16.5px; }
/* A rating line in the column pairs with the badge above it: pull it up against
   the 34px column gap so the spacing matches the badge-row + store-rating pairs
   (~14px), while the next badge keeps the full gap below. */
.badge-col .store-rating { margin-top: -20px; }
.badge-col img { height: 56.6px; width: auto; }
.badge-col a:hover img { opacity: 0.85; }

/* Modal (adjustments list popup) */
.modal {
  position: fixed;
  inset: 0;
  z-index: 400;
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.7);
  padding: 1.5rem;
}
.modal.open { display: flex; }
.modal-panel {
  background: #fff;
  color: #000;
  border-radius: 8px;
  padding: 2rem 3rem;
  max-height: 85vh;
  overflow-y: auto;
  position: relative;
  text-align: center;
  min-width: 16rem;
}
.modal-close {
  position: absolute;
  top: 0.5rem; right: 0.9rem;
  background: none;
  border: 0;
  font-size: 1.8rem;
  line-height: 1;
  cursor: pointer;
  color: #000;
}

/* ---- Image blocks (image + caption card, SquareSpace "poster"/card) ----
   Original uses two equal columns with a wide (~9vw) gutter; the image
   fills its column, so it scales down with the viewport instead of
   overlapping the caption. */
.img-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(1.5rem, 9.2vw, 7.4rem);
  align-items: center;
  text-align: left;
}
.cw-medium .img-card { gap: clamp(1.2rem, 7vw, 5.6rem); }
.img-card.media-right .media { order: 2; }
.img-card .media img, .img-card .media video { border-radius: var(--radius-img); margin: 0 auto; width: 100%; max-width: 530px; }
.img-card .caption h2, .img-card .caption h3 { margin-bottom: 0.4em; }
.img-card .caption .btn { margin-top: 1.2rem; }
@media (max-width: 767px) {
  .img-card { grid-template-columns: 1fr; text-align: center; }
  .img-card.media-right .media { order: 0; }
}

/* Standalone centered image with caption below */
.img-stack { text-align: center; }
/* An image block flanked by SquareSpace spacer blocks (the About hero pencil).
   Live's gaps around it: 122px above / 82px below at 1280, but only 34/34 on a
   phone where the spacers collapse. The old inline `84.5px auto 102px` was a
   single compromise value that was wrong at both. */
.img-stack.spaced-lg { margin: 122px auto 82px; }
@media (max-width: 767px) { .img-stack.spaced-lg { margin: 34px auto; } }
.img-stack img { border-radius: var(--radius-img); margin: 0 auto; }
.img-stack .caption { margin-top: 1.6rem; }
.img-stack .caption { max-width: var(--cw-narrow); margin: 0 auto; }

/* ---- Galleries --------------------------------------------------------- */
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 1.25rem;
  width: 100%;
}
.gallery-grid figure { margin: 0; }
.gallery-grid img, .gallery-grid video {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius-img);
  cursor: zoom-in;
}
@media (max-width: 1000px) { .gallery-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 640px) { .gallery-grid { grid-template-columns: repeat(2, 1fr); } }

.logo-row {
  display: grid;
  grid-template-columns: repeat(var(--cols, 4), 1fr);
  gap: clamp(1rem, 3vw, 3rem);
  align-items: center;
  width: 100%;
}
.logo-row figure { margin: 0; }
.logo-row img { width: 100%; max-height: 150px; object-fit: contain; }
@media (max-width: 800px) {
  .logo-row { grid-template-columns: repeat(2, 1fr); }
  .logo-row.icons { grid-template-columns: repeat(3, 1fr); }
}

/* ---- Feature columns (e.g. Brushstroke "Beautiful Styles / Palette / Video") */
.feature-cols {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1.5rem, 4vw, 3.5rem);
  text-align: center;
}
@media (max-width: 800px) { .feature-cols { grid-template-columns: 1fr; } }

/* ---- "Which Brushstroke?" comparison (Brushstroke Pro page, SEO phase 2) --
   Three cards on the pale section ground: platform eyebrow, app name, what
   you get, one action. Cards stretch to equal height; the list is the
   flexible region so buttons line up across the row. */
.compare-intro { max-width: 46em; margin: 0 auto 0.5em; }
.compare {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1rem, 2.2vw, 2rem);
  text-align: left;
  margin-top: clamp(1.6rem, 3vw, 2.6rem);
}
.compare-card {
  display: flex;
  flex-direction: column;
  background: #fff;
  border-radius: var(--radius-img);
  padding: clamp(1.4rem, 2.4vw, 2.2rem);
}
.compare-eyebrow {
  margin: 0 0 0.35rem;
  font-family: var(--heading-font);
  font-weight: 600;
  font-size: var(--fs-small);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.6;
}
.compare-card h3 { margin-bottom: 0.25em; }
.compare-price { margin: 0 0 1.1rem; font-size: var(--fs-small); opacity: 0.75; }
.compare-card ul { list-style: none; padding: 0; margin: 0 0 1.5rem; flex: 1; }
.compare-card li { position: relative; padding-left: 1.45em; margin: 0 0 0.5em; }
.compare-card li::before {
  content: "";
  position: absolute; left: 0; top: 0.62em;
  width: 0.55em; height: 0.55em;
  border-radius: 50%;
  background: var(--accent);
}
.compare-card .btn { align-self: flex-start; }
.compare-alt { margin: 0.75rem 0 0; font-size: var(--fs-small); opacity: 0.8; }
@media (max-width: 900px) { .compare { grid-template-columns: 1fr; max-width: 36rem; margin-left: auto; margin-right: auto; } }

/* ---- "Find out more" rows (app pages) ----------------------------------
   Live layout: heading + store button in a left column (5/12), then
   Requirements and Support in two narrow columns to the right. */
.fom {
  /* live column widths @1280: 471 / 67(spacer) / 269 / 269 with 34px gutters */
  display: grid;
  grid-template-columns: 471fr 67fr 269fr 269fr;
  gap: 1rem 34px;
  text-align: left;
  align-items: start;
}
.fom .fom-req { grid-column: 3; }
.fom .fom-sup { grid-column: 4; }
.fom h2 { margin-bottom: 0.6em; }
.fom-head .btn { display: block; width: fit-content; margin-bottom: 1.9rem; }
.fom h4 { margin-bottom: 32px; }
.fom li + li { margin-top: 23.3px; }
.fom { padding-top: 17px; }
.fom ul { list-style: none; padding: 0; margin: 0; }
@media (max-width: 767px) {
  .fom { grid-template-columns: 1fr; }
  .fom .fom-req, .fom .fom-sup { grid-column: auto; }
}

/* ---- FAQ two-column layout (heading left, questions right) -------------- */
.faq-cols h4, .faq-cols .as-h4 { margin: 32px 0; }
.faq-cols h4:first-child, .faq-cols .as-h4:first-child { margin-top: 0; }
.faq-cols p { margin: 16px 0; }
/* live keeps an empty trailing paragraph after each answer (31.6px + margins) */
.faq-cols p + h4, .faq-cols p + .as-h4 { margin-top: 79.6px; }
.faq-cols {
  display: grid;
  grid-template-columns: 348fr 501fr;   /* live column widths @1280 */
  gap: 1rem 34px;
  text-align: left;
}
.faq-cols h4, .faq-cols .as-h4 { margin-top: 1.2em; }
.faq-cols h4:first-child, .faq-cols .as-h4:first-child { margin-top: 0; }
@media (max-width: 800px) { .faq-cols { grid-template-columns: 1fr; } }

/* ---- Instagram post grid (About page "Follow our work.") ---------------- */
/* Live Instagram block: 4 square 257px tiles, 50px gaps, ~84px meta strip */
.ig-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 3.906vw;
  width: 100%;
  margin-top: 0;
  padding-bottom: 84px;
}
.ig-grid a { display: block; }
.ig-grid img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--radius-img);
}
.ig-grid a:hover img { opacity: 0.85; }
@media (max-width: 640px) { .ig-grid { grid-template-columns: repeat(2, 1fr); } }

/* ---- Contact page columns (text left, emails right, like the original) -- */
.contact-cols {
  display: grid;
  grid-template-columns: 5fr 3fr 4fr;
  gap: 0 1.5rem;
  text-align: left;
}
.contact-cols > div:last-child { grid-column: 3; }
@media (max-width: 767px) {
  .contact-cols { grid-template-columns: 1fr; gap: 1.5rem; }
  .contact-cols > div:last-child { grid-column: auto; }
}

/* ---- Quote / testimonial ----------------------------------------------- */
.quote h3 { line-height: 1.33; }
.quote .attribution { margin-top: 1rem; }
/* Inset quote bands: narrower 63vw column with 10vw padding (measured) */
.section.bg-inset.quote .content.cw-medium { max-width: 63vw; }
.section.bg-inset.quote { --pv: clamp(4.5rem, 10vw, 8.5rem); }
@media (max-width: 767px) {
  .section.bg-inset.quote .content.cw-medium { max-width: 100%; }
}

/* ---- Newsletter -------------------------------------------------------- */
/* Newsletter — measured on live @1280: title 42.7/lh1.43 +16, desc +40,
   3 fields 280x66 + white 123x64 button, 13px gaps, footnote +40 */
.newsletter-form { max-width: none; margin: 34px auto 50px; }
.newsletter-form h2 { font-size: var(--fs-h3); line-height: 1.43; margin-bottom: 16px; }
.newsletter-form > p { margin: 0 0 40px; }
.newsletter-fields {
  display: flex;
  flex-wrap: wrap;   /* 641-810px viewports (iPad portrait) can't fit the row */
  gap: 13px;
  justify-content: center;
  align-items: center;
  margin: 0;
}
.newsletter-fields input {
  width: 280px;
  height: 66px;
  font: inherit;
  font-size: var(--fs-p);
  padding: 0 20px;
  border: 0;
  border-radius: 0;
  background: #fff;
  color: #000;
}
.newsletter-fields input:focus { outline: 2px solid rgba(0,0,0,0.35); }
.newsletter-fields .btn {
  background: #fff;
  color: var(--accent);
  height: 64px;
  padding: 0 32px;
  font-size: var(--fs-btn-sm);
  border-radius: var(--radius-btn);
}
.newsletter-form > p.newsletter-disclaimer { font-size: 1rem; margin: 40px 0 0; }
.newsletter-success,
.newsletter-error { display: none; font-size: var(--fs-lead); padding: 1rem 0; }
.newsletter-form.done .newsletter-fields,
.newsletter-form.done .newsletter-disclaimer { display: none; }
.newsletter-form.done .newsletter-success { display: block; }
/* Failure keeps the fields on screen — the whole point is that they can try
   again, unlike `.done`, which retires the form. */
.newsletter-form.error .newsletter-error { display: block; }
.newsletter-fields .btn[disabled] { opacity: 0.55; cursor: default; }
.hp-field { position: absolute; left: -5000px; opacity: 0; pointer-events: none; }
/* Turnstile container. The widget is created in Invisible mode, so it never
   draws anything and never asks for interaction — this only has to exist and
   stay out of the layout. Not `.hp-field`: pointer-events:none there would
   break a widget that did want a click. */
#cf-turnstile { position: absolute; left: -5000px; opacity: 0; }
/* Stacked on phones. Live does this with inline-block wrappers inside a
   text-align:center form, so the 280px fields stay 280px and CENTRE, and the
   button keeps its natural width — `align-items: stretch` left the fields
   flush left in the 354px column and blew the button out to full width.
   Live's wrappers carry `padding: .5rem .25rem` (a 16px gap between fields)
   and the button wrapper adds `margin-top: 1rem` between its own .5rem and
   the field above, i.e. 32px from the last input to the button. */
@media (max-width: 640px) {
  .newsletter-fields { flex-direction: column; align-items: center; gap: 16px; }
  .newsletter-fields input { max-width: 100%; }
  .newsletter-fields .btn { margin-top: 16px; }
}

/* ---- Footer ------------------------------------------------------------
   Mirrors the original layout: tagline left, links + social in a narrow
   right column, full-width copyright below. All left-aligned.             */
.site-footer {
  background: #fff;
  color: #000;
  text-align: left;
  padding: 1.6rem var(--pad-section-h) 42.6px;
}
.footer-inner { max-width: var(--cw-wide); margin: 0 auto; }
.footer-main {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 2rem;
}
.site-footer .footer-tagline {
  font-size: var(--fs-h3);
  font-family: var(--heading-font);
  font-weight: 700;
  line-height: 1.33;
  margin: 60.8px 0 0;              /* live tagline sits 60.8px below pad */
}
.footer-side { flex: 0 0 auto; min-width: 10rem; }
.footer-links { display: flex; flex-direction: column; gap: 16px; margin-bottom: 34px; }
.footer-links a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  font-size: 1rem;
  line-height: 1.8;
}
.footer-links a:hover { opacity: 0.75; }
.site-footer .social-links { margin: 0; color: #000; }
.site-footer .copyright {
  font-size: 0.822rem;
  color: #d3d3d3;
  line-height: 31.6px;
  margin: 36px auto 0;
  width: fit-content;
  text-align: center;
}
.site-footer .copyright a { color: #d3d3d3; text-decoration: none; }
.site-footer .copyright a:hover { text-decoration: underline; }
@media (max-width: 767px) {
  .footer-main { flex-direction: column; gap: 1.6rem; }
  .footer-side { min-width: 0; }
}

/* ---- Before/after comparison slider ------------------------------------ */
.ba-slider {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-img);
  max-width: 100%;
  margin: 0 auto;
  user-select: none;
}
.ba-slider img { width: 100%; display: block; pointer-events: none; }
/* Sliders whose live embed has a different crop: force live's aspect, carried
   as an inline `--ar` so the phone rules further down can drop it.
   (The "after" image is the slider's first child — bare <img> or a <picture>.) */
.ba-slider.ba-fixed { aspect-ratio: var(--ar); }
.ba-slider.ba-fixed > img:first-child,
.ba-slider.ba-fixed > picture:first-child > img { height: 100%; object-fit: cover; }
/* Caption between two stacked sliders (Brightly Pro's "Light years ahead").
   Each slider is a block of its own on live, so on phones the caption takes the
   full 34px block gap on either side. */
.section > .content > .ba-slider + p { margin-top: 17px; }
@media (max-width: 767px) {
  .section > .content > .ba-slider + p,
  .section > .content > p + .ba-slider { margin-top: 34px; }
}
.ba-slider .ba-before {
  position: absolute;
  inset: 0;
  clip-path: inset(0 calc(100% - var(--split, 50%)) 0 0);
}
.ba-slider .ba-before img { width: 100%; height: 100%; object-fit: cover; }
.ba-slider .ba-divider {
  position: absolute;
  top: 0; bottom: 0;
  left: var(--split, 50%);
  width: 3px;
  margin-left: -1.5px;
  background: #fff;
  box-shadow: 0 0 8px rgba(0,0,0,0.4);
  pointer-events: none;
}
.ba-slider .ba-divider::after {
  /* drawn double-arrow (a text glyph never centers optically) */
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 2.4rem; height: 2.4rem;
  border-radius: 50%;
  background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 14' fill='none' stroke='%231470AF' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.5 1.5 1 7l5.5 5.5M17.5 1.5 23 7l-5.5 5.5M1 7h22'/%3E%3C/svg%3E") center / 16px 10px no-repeat;
}
.ba-slider .ba-label {
  position: absolute;
  bottom: 0.8rem;
  padding: 0.25rem 0.8rem;
  background: rgba(0,0,0,0.55);
  color: #fff;
  font-size: 0.85rem;
  border-radius: 4px;
  pointer-events: none;
}
.ba-slider .ba-label.before { left: 0.8rem; }
.ba-slider .ba-label.after { right: 0.8rem; background: var(--accent); }
.ba-slider input[type="range"] {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  opacity: 0;
  cursor: ew-resize;
  margin: 0;
}

/* Below 900px the live plugin drops the per-slider desktop crop and pins every
   slider to a fixed height instead (its own ladder, copied verbatim), scaling
   the photo to the viewport width and cropping from the left. Scaling our
   desktop aspect ratio down instead left the sliders far too short: 141px
   against live's 250px on a 402px-wide phone. */
@media (max-width: 899px) { .ba-slider.ba-fixed { aspect-ratio: auto; height: 400px; } }
@media (max-width: 599px) { .ba-slider.ba-fixed { height: 300px; } }
@media (max-width: 499px) { .ba-slider.ba-fixed { height: 250px; } }
@media (max-width: 349px) { .ba-slider.ba-fixed { height: 200px; } }
/* Below 700px live also switches the photo from its natural size to
   `background-size: 100vw`, anchored left and centred vertically — a wider,
   flatter crop than object-fit:cover would give at these box sizes. Above 700
   the cover crop above stands in for live's natural-size background. */
@media (max-width: 700px) {
  .ba-slider.ba-fixed > img,
  .ba-slider.ba-fixed picture > img {
    position: absolute;
    top: 50%;
    left: 0;
    width: 100vw;
    max-width: none;
    height: auto;
    transform: translateY(-50%);
    object-fit: fill;
  }
}

/* ---- Lightbox ---------------------------------------------------------- */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.92);
  padding: 2rem;
  cursor: zoom-out;
}
.lightbox.open { display: flex; }
.lightbox img, .lightbox video { max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; }
.lightbox video { max-width: min(100%, 90vw); max-height: 90vh; }
.lightbox .close {
  position: absolute;
  top: 1rem; right: 1.2rem;
  background: none;
  border: 0;
  color: #fff;
  font-size: 2.2rem;
  line-height: 1;
  cursor: pointer;
}

/* ---- Scroll reveal ------------------------------------------------------ */
.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.8s cubic-bezier(0.22, 0.61, 0.36, 1),
              transform 0.8s cubic-bezier(0.22, 0.61, 0.36, 1);
  transition-delay: var(--reveal-delay, 0s);
}
.reveal.in-view { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  html { scroll-behavior: auto; }
}

/* ---- Long-form text pages (legal, FAQ, help guides) -------------------- */
.text-page h3, .text-page .as-h3 { margin-top: 1.6em; }
.text-page .content { text-align: left; }
/* The first block in the content never carries a top margin on live — the
   guard used to cover only h2, so the help guides' opening h3 picked up
   `.help-page h3 { margin: 32px 0 }` and sat 32px too low. */
.text-page .content > :first-child { margin-top: 0; }
/* Long-form help pages: live paragraph/heading rhythm */
.help-page p { margin: 16px 0; }
.help-page li { margin: 16px 0; }
/* live puts each h4 topic and figure in its own 17px-padded block */
.help-page p + h4, .help-page ul + h4, .help-page ol + h4, .help-page table + h4, .help-page .help-figure + h4,
.help-page p + .as-h4, .help-page ul + .as-h4, .help-page ol + .as-h4, .help-page table + .as-h4, .help-page .help-figure + .as-h4 { margin-top: 66px; }
.help-page .help-figure { margin: 49px 0; }
.help-page h4, .help-page .as-h4 { margin: 32px 0; }
.help-page h3, .help-page .as-h3 { margin: 32px 0; }
.help-figure { margin: 2rem 0; }
.help-figure img { border-radius: var(--radius-img); }
.text-page table {
  border-collapse: collapse;
  width: 100%;
  margin: 1.5rem 0;
  font-size: 1rem;
  display: block;
  overflow-x: auto;
}
.text-page caption { padding: 8px; text-align: left; font-weight: 600; }
.text-page td, .text-page th {
  border-bottom: 1px solid rgba(0, 0, 0, 0.35);
  text-align: left;
  padding: 8px;
}
.text-page th { border-bottom-width: 2px; }
