/* Shared SolasEye site components. Exposed on window for the per-page babel scripts. */
const DS = window.SolasEyeDesignSystem_10f8ce;
const { Button, Eyebrow, Card, Divider, Input, Textarea, Select, Checkbox, FieldGroup, Icon, IconButton, Wordmark, FieldBackdrop } = DS;
const D = window.SE_DATA;
const money = window.SE_MONEY;
const AB = 'assets';

/* ---------- Iris sacred geometry overlay ----------
   One reusable SVG laid over every iris image. The iris occupies the central 100/EXTENT
   of the overlay; everything else is boundary and light around it. Hairline strokes
   (non-scaling, so they stay crisp at any size) at low opacity:
   - a barely visible gold/white circular field (two fine rings + a faint inner wash)
   - four tiny points at north, east, south and west
   - a second, soft diffuse halo beyond the field */
const IRIS_GEOMETRY_EXTENT = 1.5;
/* 'seven' = seven-ring protective field with encoded wording; 'classic' = the previous
   two-ring field with four cardinal points. Change this one word to revert. */
const IRIS_TREATMENT = 'seven';
/* Event-horizon treatment on the iris edge (seven-ring version only). Set to false to revert. */
const IRIS_HORIZON = true;
/* Equal-armed cross with a star point at each end, and a single clean outer seal.
   Set to false to revert to the previous cardinal ticks and doubled outer ring. */
const IRIS_CROSS = true;
let irisGeometryCount = 0;

/* Four identical arms on the cardinal axes, starting just outside the iris edge so the
   eye itself stays clear, each ending in a four-pointed star beyond the outer seal. */
const CROSS_INNER = 71.5;
const CROSS_OUTER = 95.4;
const STAR_R = 3.1;
const STAR_WAIST = 0.62;
const starPath = (R, w) =>
  `M0,${-R} Q${w * 0.35},${-w * 0.35} ${R},0 Q${w * 0.35},${w * 0.35} 0,${R} Q${-w * 0.35},${w * 0.35} ${-R},0 Q${-w * 0.35},${-w * 0.35} 0,${-R} Z`;

function IrisCross() {
  const gold = '#E2B87C';
  const white = '#F7F3EC';
  return (
    <g>
      {[0, 90, 180, 270].map((deg) => {
        const [x1, y1] = polar(CROSS_INNER, deg);
        const [x2, y2] = polar(CROSS_OUTER - STAR_R * 0.55, deg);
        const [sx, sy] = polar(CROSS_OUTER, deg);
        return (
          <g key={deg}>
            <line x1={x1} y1={y1} x2={x2} y2={y2} stroke={white} strokeOpacity="0.38" strokeWidth="0.5" vectorEffect="non-scaling-stroke" />
            <g transform={`translate(${sx} ${sy})`}>
              <circle r={STAR_R * 1.15} fill={gold} fillOpacity="0.08" />
              <path d={starPath(STAR_R, STAR_WAIST)} fill={gold} fillOpacity="0.85" />
              <circle r="0.45" fill={white} fillOpacity="0.9" />
            </g>
          </g>
        );
      })}
    </g>
  );
}

/* The iris edge rendered like a black hole's event horizon: the rim of the iris falls
   away into shadow, a dark gap separates it from a bright photon ring, and that ring is
   brighter on one side (as light from the near side of a spinning disc is), which is what
   gives the edge its 3D, lensed depth. All sizes are in viewBox units so it scales. */
function IrisEventHorizon({ k }) {
  const edge = 100 / IRIS_GEOMETRY_EXTENT;
  const lit = { x1: -edge, y1: edge, x2: edge, y2: -edge, gradientUnits: 'userSpaceOnUse' };
  return (
    <g>
      <defs>
        <radialGradient id={`${k}-well`} cx="0" cy="0" r={edge} gradientUnits="userSpaceOnUse">
          <stop offset="0.8" stopColor="#05060C" stopOpacity="0" />
          <stop offset="0.93" stopColor="#05060C" stopOpacity="0.32" />
          <stop offset="1" stopColor="#05060C" stopOpacity="0.72" />
        </radialGradient>
        <linearGradient id={`${k}-photon`} {...lit}>
          <stop offset="0" stopColor="#FFF6E6" stopOpacity="0.95" />
          <stop offset="0.38" stopColor="#E2B87C" stopOpacity="0.62" />
          <stop offset="0.72" stopColor="#E2B87C" stopOpacity="0.26" />
          <stop offset="1" stopColor="#ECE6F2" stopOpacity="0.16" />
        </linearGradient>
        <linearGradient id={`${k}-disc`} {...lit}>
          <stop offset="0" stopColor="#E2B87C" stopOpacity="0.4" />
          <stop offset="0.55" stopColor="#E2B87C" stopOpacity="0.12" />
          <stop offset="1" stopColor="#E2B87C" stopOpacity="0.04" />
        </linearGradient>
        <filter id={`${k}-glow`} x="-25%" y="-25%" width="150%" height="150%">
          <feGaussianBlur stdDeviation="2.2" />
        </filter>
        <filter id={`${k}-bloom`} x="-25%" y="-25%" width="150%" height="150%">
          <feGaussianBlur stdDeviation="0.7" />
        </filter>
      </defs>

      {/* the iris rim falling away into the well */}
      <circle r={edge} fill={`url(#${k}-well)`} />
      {/* shadow gap between the rim and the light */}
      <circle r={edge + 0.9} fill="none" stroke="#05060C" strokeOpacity="0.6" strokeWidth="1.6" />
      {/* wide, soft lensed glow, brightest on the near side */}
      <circle r={edge + 2.6} fill="none" stroke={`url(#${k}-disc)`} strokeWidth="5" filter={`url(#${k}-glow)`} />
      {/* photon ring: bloom, then the crisp ring */}
      <circle r={edge + 1.9} fill="none" stroke={`url(#${k}-photon)`} strokeWidth="1.6" filter={`url(#${k}-bloom)`} />
      <circle r={edge + 1.9} fill="none" stroke={`url(#${k}-photon)`} strokeWidth="0.55" />
      {/* faint secondary lensed image just inside the horizon */}
      <circle r={edge - 0.4} fill="none" stroke="#FFF6E6" strokeOpacity="0.16" strokeWidth="0.3" />
    </g>
  );
}
function IrisGeometry(props) {
  return IRIS_TREATMENT === 'classic' ? <IrisGeometryClassic {...props} /> : <IrisSevenRings {...props} />;
}

/* ---------- Seven-ring protective field ----------
   The iris edge sits at r = 100 / EXTENT (~66.7) in the -100..100 viewBox. Each ring's
   statement is micro-lettering set on the ring's own curve, repeated to close the circle,
   so at normal distance it reads as a fine filament and only resolves into words up close. */
const SEVEN_RINGS = [
  { r: 69.6, text: 'I am anchored in divine light', tone: 'white', op: 0.2 },
  { r: 73.2, text: 'Only what serves my highest good may enter', tone: 'pearl', op: 0.22 },
  { r: 76.8, text: 'My energy is sovereign, sealed and whole', tone: 'gold', op: 0.26 },
  { r: 80.4, text: 'All that is not mine is nullified and released', tone: 'champagne', op: 0.2 },
  { r: 84.0, text: 'No force may take, bind, drain or distort what is mine', tone: 'gold', op: 0.27 },
  { r: 87.6, text: 'I am guarded in all directions, across all realms and timelines', tone: 'pearl', op: 0.23 },
  { r: 91.2, text: 'By light, will and truth, I am sealed, protected and free', tone: 'gold', op: 0.3 },
];
const RING_TONES = { white: '#F7F3EC', pearl: '#ECE6F2', gold: '#E2B87C', champagne: '#EED9B4' };
const RING_FONT = 1.32;
const ringPath = (r) => `M 0,${-r} A ${r},${r} 0 1,1 0,${r} A ${r},${r} 0 1,1 0,${-r}`;
const polar = (r, deg) => { const a = (deg - 90) * Math.PI / 180; return [r * Math.cos(a), r * Math.sin(a)]; };

function RingText({ id, r, text, color, op }) {
  const circ = 2 * Math.PI * r;
  const phrase = `${text} \u00B7 `;
  const perRepeat = phrase.length * RING_FONT * 0.56;
  const repeats = Math.max(1, Math.floor(circ / perRepeat));
  return (
    <>
      <path id={id} d={ringPath(r)} fill="none" />
      <text fill={color} fillOpacity={op} fontSize={RING_FONT}
        style={{ fontFamily: 'var(--font-display, Georgia, serif)', letterSpacing: '0.02em', textTransform: 'uppercase', userSelect: 'none' }}>
        <textPath href={`#${id}`} textLength={circ * 0.996} lengthAdjust="spacing" dominantBaseline="central">
          {phrase.repeat(repeats)}
        </textPath>
      </text>
    </>
  );
}

function IrisSevenRings({ style }) {
  const id = React.useRef(null);
  if (id.current === null) id.current = `sr${++irisGeometryCount}`;
  const k = id.current;
  const gold = RING_TONES.gold;
  const white = RING_TONES.white;
  const hair = { fill: 'none', vectorEffect: 'non-scaling-stroke' };
  const fibres = Array.from({ length: 144 }, (_, i) => i * 2.5);
  return (
    <svg aria-hidden="true" focusable="false" viewBox="-100 -100 200 200"
      style={{ position: 'absolute', left: '50%', top: '50%', width: `${IRIS_GEOMETRY_EXTENT * 100}%`, height: `${IRIS_GEOMETRY_EXTENT * 100}%`, maxWidth: 'none', maxHeight: 'none', transform: 'translate(-50%,-50%)', pointerEvents: 'none', overflow: 'visible', ...style }}>
      <defs>
        <radialGradient id={`${k}-field`} cx="0" cy="0" r="100" gradientUnits="userSpaceOnUse">
          <stop offset="0.66" stopColor={gold} stopOpacity="0.05" />
          <stop offset="0.8" stopColor={white} stopOpacity="0.025" />
          <stop offset="0.9" stopColor={gold} stopOpacity="0.045" />
          <stop offset="1" stopColor={gold} stopOpacity="0" />
        </radialGradient>
        <filter id={`${k}-soft`} x="-20%" y="-20%" width="140%" height="140%">
          <feGaussianBlur stdDeviation="1.4" />
        </filter>
      </defs>

      {/* luminous field the rings sit in, plus the final seal's faint outer halo */}
      <circle r="100" fill={`url(#${k}-field)`} />
      {!IRIS_CROSS && <circle r="93.2" {...hair} stroke={gold} strokeOpacity="0.14" strokeWidth="2.6" filter={`url(#${k}-soft)`} vectorEffect={undefined} />}

      {/* Ring 1, Inner Light: iris fibres continue outward and fade into the first ring */}
      {fibres.map((deg) => {
        const [x1, y1] = polar(66.2, deg);
        const [x2, y2] = polar(deg % 10 === 0 ? 69 : 68, deg);
        return <line key={deg} x1={x1} y1={y1} x2={x2} y2={y2} stroke={white} strokeOpacity="0.1" strokeWidth="0.4" vectorEffect="non-scaling-stroke" />;
      })}
      <circle r="70.9" {...hair} stroke={white} strokeOpacity="0.1" strokeWidth="0.4" />
      {IRIS_HORIZON && <IrisEventHorizon k={k} />}

      {/* Ring 2, Threshold: a boundary with fine gates, permission rather than wall */}
      <circle r="74.5" {...hair} stroke={RING_TONES.pearl} strokeOpacity="0.2" strokeWidth="0.45" strokeDasharray="28 0.8" />

      {/* Ring 3, Sovereignty: complete and uninterrupted */}
      <circle r="78.1" {...hair} stroke={gold} strokeOpacity="0.34" strokeWidth="0.55" />

      {/* Ring 4, Neutralisation: interrupted arcs with small refractions where influence dissolves */}
      <circle r="81.7" {...hair} stroke={RING_TONES.champagne} strokeOpacity="0.2" strokeWidth="0.45" strokeDasharray="9 1.6 3 1.6" />
      {Array.from({ length: 12 }, (_, i) => i * 30 + 15).map((deg) => {
        const [x, y] = polar(81.7, deg);
        return <path key={deg} d="M0,-0.9 L0.45,0 L0,0.9 L-0.45,0 Z" fill={white} fillOpacity="0.32" transform={`translate(${x} ${y}) rotate(${deg})`} />;
      })}

      {/* Ring 5, Preservation: a doubled, slightly stronger hairline that holds what is within */}
      <circle r="85" {...hair} stroke={gold} strokeOpacity="0.3" strokeWidth="0.5" />
      <circle r="85.7" {...hair} stroke={gold} strokeOpacity="0.16" strokeWidth="0.4" />

      {/* Ring 6, Guardianship: directional geometry on every side */}
      <circle r="88.9" {...hair} stroke={RING_TONES.pearl} strokeOpacity="0.18" strokeWidth="0.4" />
      {IRIS_CROSS && <IrisCross />}
      {!IRIS_CROSS && [0, 90, 180, 270].map((deg) => {
        const [x1, y1] = polar(86.9, deg);
        const [x2, y2] = polar(90.9, deg);
        const [cx, cy] = polar(88.9, deg);
        return (
          <g key={deg}>
            <line x1={x1} y1={y1} x2={x2} y2={y2} stroke={white} strokeOpacity="0.42" strokeWidth="0.55" vectorEffect="non-scaling-stroke" />
            <circle cx={cx} cy={cy} r="0.85" fill={gold} fillOpacity="0.75" />
            <circle cx={cx} cy={cy} r="2" {...hair} stroke={gold} strokeOpacity="0.3" strokeWidth="0.4" />
          </g>
        );
      })}
      {!IRIS_CROSS && [45, 135, 225, 315].map((deg) => {
        const [cx, cy] = polar(88.9, deg);
        return <circle key={deg} cx={cx} cy={cy} r="0.5" fill={white} fillOpacity="0.4" />;
      })}

      {/* Ring 7, Final Seal: closed and absolute, containing all six */}
      {IRIS_CROSS ? (
        <circle r="92.6" {...hair} stroke={gold} strokeOpacity="0.55" strokeWidth="0.7" />
      ) : (
        <>
          <circle r="92.6" {...hair} stroke={gold} strokeOpacity="0.42" strokeWidth="0.6" />
          <circle r="93.4" {...hair} stroke={white} strokeOpacity="0.12" strokeWidth="0.4" />
        </>
      )}

      {/* the seven statements, innermost outward, encoded on their rings */}
      {SEVEN_RINGS.map((ring, i) => (
        <RingText key={i} id={`${k}-t${i}`} r={ring.r} text={ring.text} color={RING_TONES[ring.tone]} op={ring.op} />
      ))}
    </svg>
  );
}

function IrisGeometryClassic({ style }) {
  const id = React.useRef(null);
  if (id.current === null) id.current = `ig${++irisGeometryCount}`;
  const k = id.current;
  const gold = '#E2B87C';
  const white = '#F4EFE6';
  /* cardinal points sit on the field ring, with a short hairline tick pointing outward */
  const pts = [[0, -1], [1, 0], [0, 1], [-1, 0]];
  return (
    <svg aria-hidden="true" focusable="false" viewBox="-100 -100 200 200"
      style={{ position: 'absolute', left: '50%', top: '50%', width: `${IRIS_GEOMETRY_EXTENT * 100}%`, height: `${IRIS_GEOMETRY_EXTENT * 100}%`, maxWidth: 'none', maxHeight: 'none', transform: 'translate(-50%,-50%)', pointerEvents: 'none', overflow: 'visible', ...style }}>
      <defs>
        <radialGradient id={`${k}-halo`} cx="0" cy="0" r="100" gradientUnits="userSpaceOnUse">
          <stop offset="0.62" stopColor={gold} stopOpacity="0" />
          <stop offset="0.76" stopColor={gold} stopOpacity="0.07" />
          <stop offset="0.88" stopColor={white} stopOpacity="0.035" />
          <stop offset="1" stopColor={white} stopOpacity="0" />
        </radialGradient>
        <radialGradient id={`${k}-wash`} cx="0" cy="0" r="80" gradientUnits="userSpaceOnUse">
          <stop offset="0.84" stopColor={gold} stopOpacity="0" />
          <stop offset="1" stopColor={gold} stopOpacity="0.07" />
        </radialGradient>
        <filter id={`${k}-soft`} x="-20%" y="-20%" width="140%" height="140%">
          <feGaussianBlur stdDeviation="1.6" />
        </filter>
      </defs>
      {/* second, soft diffuse halo */}
      <circle r="100" fill={`url(#${k}-halo)`} />
      <circle r="90" fill="none" stroke={gold} strokeOpacity="0.16" strokeWidth="3" filter={`url(#${k}-soft)`} />
      {/* circular field */}
      <circle r="80" fill={`url(#${k}-wash)`} />
      <circle r="80" fill="none" stroke={gold} strokeOpacity="0.4" strokeWidth="0.6" vectorEffect="non-scaling-stroke" />
      <circle r="73" fill="none" stroke={white} strokeOpacity="0.2" strokeWidth="0.5" vectorEffect="non-scaling-stroke" />
      {/* four cardinal points */}
      {pts.map(([x, y]) => (
        <g key={`${x}${y}`}>
          <line x1={x * 76.5} y1={y * 76.5} x2={x * 84.5} y2={y * 84.5} stroke={white} strokeOpacity="0.45" strokeWidth="0.6" vectorEffect="non-scaling-stroke" />
          <circle cx={x * 80} cy={y * 80} r="1.5" fill={gold} fillOpacity="0.8" />
          <circle cx={x * 80} cy={y * 80} r="3.4" fill="none" stroke={gold} strokeOpacity="0.35" strokeWidth="0.5" vectorEffect="non-scaling-stroke" />
        </g>
      ))}
    </svg>
  );
}

/* ---------- Iris portal: CLEARLY REPLACEABLE PLACEHOLDER ----------
   Swap `src` for Sinéad's high-resolution iris at the same square crop.
   Nothing else needs to change. */
function IrisPortal({ size = 260, breathe = true, decorative = true, style }) {
  const [reduced] = React.useState(() => window.matchMedia('(prefers-reduced-motion: reduce)').matches);
  return (
    <div data-iris-placeholder="true" style={{ position: 'relative', width: size, height: size, display: 'grid', placeItems: 'center', flex: '0 0 auto', ...style }}>
      <div aria-hidden="true" style={{ position: 'absolute', inset: `-${Math.round(size * 0.7)}px`, background: 'var(--gradient-portal)', pointerEvents: 'none', animation: breathe && !reduced ? 'se-breathe var(--duration-breathe) var(--ease-in-out-deep) infinite' : undefined }} />
      <img src={`${AB}/marks/photographic-portal.png`} loading="lazy" decoding="async"
        alt={decorative ? '' : 'The SolasEye iris portal: silver-blue fibres around a warm amber centre and dark pupil.'}
        aria-hidden={decorative ? 'true' : undefined}
        style={{ width: '100%', height: '100%', objectFit: 'contain', position: 'relative' }} />
      <IrisGeometry />
    </div>
  );
}

/* ---------- Portrait of Sinéad ---------- */
/* Circular, echoing the portal: photography is circular-cropped where it stands in for
   the iris. Graded lighter than the old rectangle so the face actually reads, and lifted
   off the field by an amber ring, an offset outer ring and the amber glow. */
function Portrait({ width = 300, style }) {
  return (
    <figure style={{ margin: 0, position: 'relative', width: '100%', maxWidth: width, aspectRatio: '1', ...style }}>
      <div aria-hidden="true" style={{ position: 'absolute', inset: '-14px', borderRadius: '50%', border: '1px solid var(--amber-16)', pointerEvents: 'none' }} />
      <div aria-hidden="true" style={{ position: 'absolute', inset: '-46px', borderRadius: '50%', background: 'radial-gradient(circle, rgba(201,149,85,.16) 40%, rgba(201,149,85,0) 72%)', pointerEvents: 'none' }} />
      <div style={{ position: 'relative', width: '100%', aspectRatio: '1', overflow: 'hidden', borderRadius: '50%', border: '1px solid var(--line-accent)', boxShadow: 'var(--shadow-glow-amber)', background: 'var(--surface-depth-deep)' }}>
        <img src={`${AB}/imagery/sinead-portrait.jpeg`} loading="lazy" decoding="async"
          alt="Sinéad O’Sullivan, founder of SolasEye."
          style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: '50% 26%', filter: 'saturate(.74) contrast(1.05) brightness(.94) sepia(.05)', display: 'block' }} />
        {/* edge-only vignette so the circle settles into the field without dimming the face */}
        <div aria-hidden="true" style={{ position: 'absolute', inset: 0, background: 'radial-gradient(circle at 50% 44%, rgba(8,9,16,0) 54%, rgba(8,9,16,.26) 84%, rgba(8,9,16,.58) 100%)' }} />
      </div>
    </figure>
  );
}

/* The supplied sos-cycle.svg has an empty centre (its <image> shipped with no href),
   so the iris is composited behind it. Circle in the artwork: cx 600 cy 600 r 190
   within viewBox "-300 0 1800 1200" -> centred, diameter 21.11% of the width. */
function SosDiagram({ width = 440, style }) {
  return (
    <div style={{ position: 'relative', width: '100%', maxWidth: width, ...style }}>
      <img src={`${AB}/marks/photographic-portal.png`} alt="" aria-hidden="true" loading="lazy"
        style={{ position: 'absolute', left: '50%', top: '50%', transform: 'translate(-50%,-50%)', width: '21.11%', aspectRatio: '1', borderRadius: '50%', objectFit: 'cover' }} />
      <div aria-hidden="true" style={{ position: 'absolute', left: '50%', top: '50%', transform: 'translate(-50%,-50%)', width: '21.11%', aspectRatio: '1', pointerEvents: 'none' }}>
        <IrisGeometry />
      </div>
      <img src={`${AB}/diagrams/sos-cycle.svg`} loading="lazy"
        alt="The S.O.S. cycle shown as one-directional clockwise arrows around the iris: see, then surrender, then open, then shift, returning to see."
        style={{ width: '100%', display: 'block', position: 'relative' }} />
    </div>
  );
}

function Placeholder({ children }) {
  return <span style={{ fontFamily: 'var(--font-mono)', fontSize: '.85em', letterSpacing: '.04em', color: 'var(--text-accent)', background: 'var(--amber-08)', border: '1px dashed var(--line-accent)', borderRadius: 2, padding: '1px 6px' }}>{children}</span>;
}

/* ---------- Header ---------- */
function Header({ current }) {
  const [open, setOpen] = React.useState(false);
  return (
    <header style={{ position: 'sticky', top: 0, zIndex: 40, background: 'var(--surface-veil)', backdropFilter: 'blur(var(--blur-glass))', WebkitBackdropFilter: 'blur(var(--blur-glass))', borderBottom: '1px solid var(--line-hairline)' }}>
      <div style={{ maxWidth: 'var(--container-full)', margin: '0 auto', padding: 'var(--space-4) var(--gutter-page)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 'var(--space-6)' }}>
        <a href="index.html" aria-label="SolasEye - home" style={{ display: 'block', borderBottom: 0, flex: '0 0 auto' }}>
          <img src={`${AB}/logos/wordmark-on-dark.svg`} alt="SOLASEYE" style={{ width: 'clamp(120px,20vw,168px)', display: 'block' }} />
        </a>
        <nav aria-label="Primary" className="se-desktop-nav" style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-6)' }}>
          {D.nav.map(n => {
            const active = n.label === current;
            return <a key={n.label} href={n.href} aria-current={active ? 'page' : undefined}
              style={{ fontFamily: 'var(--font-body)', fontSize: 'var(--type-nav-size)', letterSpacing: 'var(--type-nav-tracking)', textTransform: 'uppercase', fontWeight: 'var(--weight-ui)', color: active ? 'var(--text-accent)' : 'var(--bone-64)', textDecoration: 'none', borderBottom: '1px solid ' + (active ? 'var(--line-accent-strong)' : 'transparent'), paddingBottom: 5 }}>{n.label}</a>;
          })}
          <Button size="sm" variant="primary" href="about.html#book">Book or enquire</Button>
        </nav>
        <button className="se-nav-toggle" aria-expanded={open} aria-controls="se-mobile-nav" aria-label={open ? 'Close menu' : 'Open menu'}
          onClick={() => setOpen(o => !o)}
          style={{ display: 'none', width: 44, height: 44, placeItems: 'center', background: 'transparent', border: '1px solid var(--line-hairline)', borderRadius: 'var(--radius-sm)', color: 'var(--text-secondary)', cursor: 'pointer' }}>
          <Icon name={open ? 'x' : 'menu'} size={20} />
        </button>
      </div>
      {open && <nav id="se-mobile-nav" aria-label="Primary - mobile" className="se-mobile-nav"
        style={{ borderTop: '1px solid var(--line-hairline)', padding: 'var(--space-5) var(--gutter-page) var(--space-6)', display: 'grid', gap: 'var(--space-5)', background: 'var(--obsidian-92)' }}>
        {D.nav.map(n => <a key={n.label} href={n.href} aria-current={n.label === current ? 'page' : undefined}
          style={{ fontFamily: 'var(--font-body)', fontSize: 14, letterSpacing: 'var(--type-nav-tracking)', textTransform: 'uppercase', color: n.label === current ? 'var(--text-accent)' : 'var(--bone-64)', textDecoration: 'none', borderBottom: 0 }}>{n.label}</a>)}
        <Button size="sm" variant="primary" href="about.html#book" fullWidth>Book or enquire</Button>
      </nav>}
    </header>
  );
}

/* ---------- Footer ---------- */
function Footer() {
  const P = D.placeholders;
  return (
    <footer style={{ position: 'relative', background: 'transparent', overflow: 'hidden' }}>
      {/* Settling layer: lets the page gradient's warm end show through the top of the
          footer, then deepens back to obsidian so muted type keeps its contrast. */}
      <div aria-hidden="true" style={{ position: 'absolute', inset: 0, pointerEvents: 'none', background: 'linear-gradient(180deg, rgba(8,9,16,0) 0%, rgba(8,9,16,.28) 18%, rgba(8,9,16,.66) 44%, rgba(8,9,16,.88) 68%, rgba(8,9,16,.97) 88%, var(--solaseye-obsidian) 100%)' }} />
      <div aria-hidden="true" style={{ position: 'absolute', top: 0, left: 0, right: 0, height: 1, background: 'var(--gradient-hairline)', pointerEvents: 'none' }} />
      <div style={{ position: 'relative', maxWidth: 'var(--container-full)', margin: '0 auto', padding: 'var(--space-10) var(--gutter-page) var(--space-7)' }}>
        <div style={{ display: 'grid', placeItems: 'center', textAlign: 'center' }}>
          <img src={`${AB}/marks/line-submark.svg`} alt="" aria-hidden="true" width="52" height="52" />
          <div style={{ marginTop: 'var(--space-5)', fontFamily: 'var(--font-display)', fontWeight: 300, fontSize: '1.4rem', letterSpacing: 'var(--type-wordmark-tracking)', color: 'var(--text-display)' }}>SOLASEYE</div>
          <p style={{ margin: 'var(--space-5) 0 0', maxWidth: '60ch', fontFamily: 'var(--font-display)', fontSize: '1.15rem', lineHeight: 1.5, color: 'var(--text-accent)' }}>
            <strong style={{ fontWeight: 500 }}>{D.footer.founderStatement}</strong>
          </p>
        </div>
        <Divider variant="glow" spacing="var(--space-7)" />
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit,minmax(240px,1fr))', gap: 'var(--space-7)' }}>
          <div>
            <Eyebrow>Navigate</Eyebrow>
            <ul style={{ listStyle: 'none', margin: 'var(--space-4) 0 0', padding: 0, display: 'grid', gap: 'var(--space-3)' }}>
              {D.nav.map(n => <li key={n.label}><a href={n.href} style={{ fontSize: 'var(--type-small-size)', color: 'var(--text-body)', borderBottom: 0 }}>{n.label}</a></li>)}
            </ul>
          </div>
          <div>
            <Eyebrow>Contact</Eyebrow>
            <ul style={{ listStyle: 'none', margin: 'var(--space-4) 0 0', padding: 0, display: 'grid', gap: 'var(--space-3)', fontSize: 'var(--type-small-size)', color: 'var(--text-body)' }}>
              <li><a href={`mailto:${P.contactEmail}`} style={{ color: 'var(--text-body)', borderBottom: 0 }}>{P.contactEmail}</a></li>
              <li><a href="https://wa.me/353877734444" rel="noopener noreferrer" target="_blank" style={{ color: 'var(--text-body)', borderBottom: 0 }}>{P.phone}</a></li>
              <li>{P.location}</li>
            </ul>
          </div>
          <div>
            <Eyebrow>Policies</Eyebrow>
            <ul style={{ listStyle: 'none', margin: 'var(--space-4) 0 0', padding: 0, display: 'grid', gap: 'var(--space-3)', fontSize: 'var(--type-small-size)' }}>
              <li><a href={P.privacyPolicyUrl} style={{ color: 'var(--text-body)', borderBottom: 0 }}>Privacy policy</a></li>
              <li><button type="button" onClick={() => window.seConsent && window.seConsent.open()} style={{ background: 'none', border: 0, padding: 0, cursor: 'pointer', font: 'inherit', fontSize: 'var(--type-small-size)', color: 'var(--text-body)', textAlign: 'left' }}>Cookie settings</button></li>
              <li><a href="workshops.html#policies" style={{ color: 'var(--text-body)', borderBottom: 0 }}>Cancellation &amp; deposit policy</a></li>
              <li><a href="about.html#book" style={{ color: 'var(--text-body)', borderBottom: 0 }}>Contact &amp; enquiries</a></li>
            </ul>
          </div>
          <div>
            <Eyebrow>Lineage</Eyebrow>
            <p style={{ margin: 'var(--space-4) 0 0', fontSize: 'var(--type-small-size)', color: 'var(--text-body)' }}>
              <a href={D.footer.officialSourceUrl} rel="noopener noreferrer" target="_blank">{D.footer.officialSourceLabel}</a>
            </p>
          </div>
        </div>
        <div style={{ marginTop: 'var(--space-7)', paddingTop: 'var(--space-5)', borderTop: '1px solid var(--line-hairline)', display: 'grid', gap: 'var(--space-4)' }}>
          <p style={{ margin: 0, fontSize: 'var(--type-caption-size)', lineHeight: 1.8, color: 'var(--text-muted)', maxWidth: '90ch' }}>{D.footer.independence}</p>
          <p style={{ margin: 0, fontSize: 'var(--type-caption-size)', lineHeight: 1.8, color: 'var(--text-muted)', maxWidth: '90ch' }}>{D.footer.disclaimer}</p>
          <p style={{ margin: 0, fontSize: 'var(--type-caption-size)', letterSpacing: 'var(--tracking-wide)', color: 'var(--text-muted)' }}>© {new Date().getFullYear()} SolasEye · Sinéad O’Sullivan · solaseye.com</p>
        </div>
      </div>
    </footer>
  );
}

/* ---------- PayPal checkout ---------- */
let paypalSdkPromise = null;
function loadPayPal() {
  if (window.paypal && window.paypal.Buttons) return Promise.resolve(window.paypal);
  if (paypalSdkPromise) return paypalSdkPromise;
  paypalSdkPromise = fetch('/api/paypal/config', { headers: { Accept: 'application/json' } })
    .then(r => { if (!r.ok) throw new Error('config'); return r.json(); })
    .then(cfg => new Promise((resolve, reject) => {
      if (!cfg || !cfg.clientId) return reject(new Error('config'));
      const params = new URLSearchParams({ 'client-id': cfg.clientId, currency: cfg.currency || 'EUR', intent: 'capture', components: 'buttons' });
      const s = document.createElement('script');
      s.src = `https://www.paypal.com/sdk/js?${params}`;
      s.async = true;
      s.onload = () => (window.paypal ? resolve(window.paypal) : reject(new Error('sdk')));
      s.onerror = () => reject(new Error('sdk'));
      document.head.appendChild(s);
    }))
    .catch(err => { paypalSdkPromise = null; throw err; });
  return paypalSdkPromise;
}

async function postJSON(url, body) {
  const r = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) });
  const data = await r.json().catch(() => ({}));
  if (!r.ok) { const e = new Error(data.error || 'The payment could not be completed.'); e.data = data; throw e; }
  return data;
}

function newRequestId() {
  return (window.crypto && crypto.randomUUID) ? crypto.randomUUID() : `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;
}

let hostedSdkPromise = null;
function loadHostedPayPal() {
  if (window.paypalHosted && window.paypalHosted.HostedButtons) return Promise.resolve(window.paypalHosted);
  if (hostedSdkPromise) return hostedSdkPromise;
  hostedSdkPromise = new Promise((resolve, reject) => {
    const clientId = D.payment.paypalClientId;
    if (!clientId) return reject(new Error('config'));
    const params = new URLSearchParams({ 'client-id': clientId, components: 'hosted-buttons', 'disable-funding': 'venmo', currency: 'EUR' });
    const s = document.createElement('script');
    s.src = `https://www.paypal.com/sdk/js?${params}`;
    s.async = true;
    // Separate namespace so it never collides with the server-checkout SDK.
    s.setAttribute('data-namespace', 'paypalHosted');
    s.onload = () => (window.paypalHosted ? resolve(window.paypalHosted) : reject(new Error('sdk')));
    s.onerror = () => reject(new Error('sdk'));
    document.head.appendChild(s);
  }).catch(err => { hostedSdkPromise = null; throw err; });
  return hostedSdkPromise;
}

function hostedButtonId(offering, kind) {
  const entry = (D.payment.hostedButtons || {})[offering.id];
  return (entry && entry[kind]) || '';
}

function HostedPayPalButton({ buttonId }) {
  const containerId = `paypal-container-${buttonId}`;
  const [state, setState] = React.useState('loading');
  React.useEffect(() => {
    let cancelled = false;
    loadHostedPayPal()
      .then(pp => { if (cancelled) return; return pp.HostedButtons({ hostedButtonId: buttonId }).render(`#${containerId}`); })
      .then(() => { if (!cancelled) setState('ready'); })
      .catch(() => { if (!cancelled) setState('unavailable'); });
    return () => { cancelled = true; };
  }, [buttonId, containerId]);
  return (
    <div style={{ display: 'grid', gap: 'var(--space-3)' }}>
      {state === 'loading' && <p role="status" style={{ margin: 0, fontSize: 'var(--type-small-size)', color: 'var(--text-muted)', textAlign: 'center', padding: 'var(--space-4) 0' }}>Preparing secure checkout…</p>}
      {state === 'unavailable' && <p style={{ margin: 0, fontSize: 'var(--type-small-size)', lineHeight: 1.7, color: 'var(--text-body)' }}>Secure online payment is unavailable just now. Please email <a href={`mailto:${D.placeholders.contactEmail}`}>{D.placeholders.contactEmail}</a>.</p>}
      <style>{'.pp-hosted-card h1,.pp-hosted-card h2,.pp-hosted-card h3,.pp-hosted-card .item-title{color:#1c1f26}'}</style>
      <div id={containerId} className="pp-hosted-card" style={{ colorScheme: 'light', background: '#fff', color: '#1c1f26', padding: state === 'ready' ? 'var(--space-4)' : 0, borderRadius: 'var(--radius-sm)' }} />
    </div>
  );
}

function PayPalCheckout(props) {
  const [mode, setMode] = React.useState('checking');
  React.useEffect(() => {
    let cancelled = false;
    loadPayPal().then(() => { if (!cancelled) setMode('server'); }).catch(() => { if (!cancelled) setMode('fallback'); });
    return () => { cancelled = true; };
  }, []);
  const buttonId = hostedButtonId(props.offering, props.kind);
  if (mode === 'checking') return <p role="status" style={{ margin: 0, fontSize: 'var(--type-small-size)', color: 'var(--text-muted)', textAlign: 'center', padding: 'var(--space-4) 0' }}>Preparing secure checkout…</p>;
  if (mode === 'fallback' && buttonId) return <HostedPayPalButton buttonId={buttonId} />;
  return <ServerPayPalCheckout {...props} />;
}

function ServerPayPalCheckout({ offering, kind, onPaid, onError, onBusy }) {
  const ref = React.useRef(null);
  const [state, setState] = React.useState('loading');
  const requestId = React.useMemo(newRequestId, [offering.id, kind]);
  const cb = React.useRef({});
  cb.current = { onPaid, onError, onBusy };
  React.useEffect(() => {
    let buttons = null;
    let cancelled = false;
    loadPayPal().then(paypal => {
      if (cancelled || !ref.current) return;
      buttons = paypal.Buttons({
        style: { layout: 'vertical', color: 'white', shape: 'rect', label: 'pay', height: 48, tagline: false },
        onClick: () => cb.current.onError(''),
        createOrder: () => postJSON('/api/paypal/create-order', { offeringId: offering.id, kind, requestId }).then(d => d.id),
        onApprove: (data, actions) => {
          cb.current.onBusy(true);
          return postJSON('/api/paypal/capture-order', { orderID: data.orderID })
            .then(res => cb.current.onPaid(res))
            .catch(err => {
              cb.current.onBusy(false);
              if (err.data && err.data.restart) { cb.current.onError(err.message); return actions.restart(); }
              cb.current.onError(err.message);
            });
        },
        onError: () => { cb.current.onBusy(false); cb.current.onError('Secure payment could not be completed and no money has been taken. Please try again, or email sos@solaseye.com.'); },
      });
      return buttons.render(ref.current).then(() => { if (!cancelled) setState('ready'); });
    }).catch(() => { if (!cancelled) setState('unavailable'); });
    return () => { cancelled = true; if (buttons && buttons.close) buttons.close().catch(() => {}); };
  }, [offering.id, kind, requestId]);

  if (state === 'unavailable') {
    return (
      <div style={{ border: '1px solid var(--line-hairline)', padding: 'var(--space-5)', display: 'grid', gap: 'var(--space-3)' }}>
        <p style={{ margin: 0, fontSize: 'var(--type-small-size)', lineHeight: 1.7, color: 'var(--text-body)' }}>Secure online payment is unavailable just now.</p>
        <p style={{ margin: 0, fontSize: 'var(--type-small-size)', lineHeight: 1.7, color: 'var(--text-secondary)' }}>
          Please email <a href={`mailto:${D.placeholders.contactEmail}?subject=${encodeURIComponent('Booking - ' + offering.name)}`}>{D.placeholders.contactEmail}</a> and Sinéad will send you a payment link personally.
        </p>
      </div>
    );
  }
  return (
    <div style={{ display: 'grid', gap: 'var(--space-3)' }}>
      {state === 'loading' && <p role="status" style={{ margin: 0, fontSize: 'var(--type-small-size)', color: 'var(--text-muted)', textAlign: 'center', padding: 'var(--space-4) 0' }}>Preparing secure checkout…</p>}
      <div ref={ref} style={{ colorScheme: 'light' }} />
    </div>
  );
}

const PAY_COPY = {
  healing: {
    eyebrow: 'Payment in full',
    terms: () => [D.terms.cancellationHealing],
    ack: 'I have read and accept the booking and cancellation terms.',
  },
  'workshop-full': {
    eyebrow: 'Payment in full',
    terms: () => [D.terms.cancellationTraining],
    ack: 'I have read and accept the cancellation terms, and understand that postage and handling is additional.',
  },
  'workshop-deposit': {
    eyebrow: 'Non-refundable deposit',
    terms: () => [D.depositPolicy, `${D.terms.balanceDue} ${D.terms.cancellationTraining}`],
    ack: 'I have read and accept the deposit and cancellation terms, and understand that postage and handling is additional.',
  },
};

/* ---------- Payment modal ---------- */
function PaymentModal({ offering, kind, onClose }) {
  const [accepted, setAccepted] = React.useState(false);
  const [error, setError] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [receipt, setReceipt] = React.useState(null);
  const ref = React.useRef(null);
  const isWorkshop = D.workshops.some(w => w.id === offering.id);
  const isDeposit = isWorkshop && kind === 'deposit';
  const copy = PAY_COPY[isWorkshop ? (isDeposit ? 'workshop-deposit' : 'workshop-full') : 'healing'];
  const value = isDeposit ? offering.deposit : offering.price;
  const currency = isDeposit ? offering.depositCurrency : offering.currency;
  const closeSafely = React.useCallback(() => { if (!busy) onClose(); }, [busy, onClose]);

  React.useEffect(() => { loadPayPal().catch(() => {}); }, []);
  React.useEffect(() => {
    const onKey = e => { if (e.key === 'Escape') closeSafely(); };
    document.addEventListener('keydown', onKey);
    document.body.style.overflow = 'hidden';
    return () => { document.removeEventListener('keydown', onKey); document.body.style.overflow = ''; };
  }, [closeSafely]);
  React.useEffect(() => {
    const node = ref.current;
    if (node) { const first = node.querySelector('button,a,input'); first && first.focus(); }
  }, [receipt]);

  const small = { margin: 0, fontSize: 'var(--type-small-size)', lineHeight: 1.75 };
  const firstName = receipt && receipt.payerName ? receipt.payerName.split(' ')[0] : '';
  const nextStep = !isWorkshop
    ? 'Sinéad will be in touch personally to arrange the date and time of your session.'
    : isDeposit
      ? 'Sinéad will be in touch personally to confirm your place. Postage and handling is additional and will be confirmed separately.'
      : 'Sinéad will be in touch personally to confirm your place.';

  return (
    <div role="presentation" onClick={e => { if (e.target === e.currentTarget) closeSafely(); }}
      style={{ position: 'fixed', inset: 0, zIndex: 100, background: 'var(--overlay-scrim)', display: 'grid', placeItems: 'center', padding: 'var(--space-4)', overflowY: 'auto' }}>
      <div ref={ref} role="dialog" aria-modal="true" aria-labelledby="se-pay-title" aria-busy={busy}
        style={{ background: 'var(--surface-card)', border: '1px solid var(--line-hairline)', boxShadow: 'var(--shadow-modal)', borderRadius: 'var(--radius-sm)', maxWidth: 560, width: '100%', padding: 'var(--space-7)', display: 'grid', gap: 'var(--space-5)', margin: 'auto' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 'var(--space-4)' }}>
          <div>
            <Eyebrow>{receipt ? (receipt.status === 'COMPLETED' ? 'Payment received' : 'Payment processing') : copy.eyebrow}</Eyebrow>
            <h2 id="se-pay-title" style={{ fontSize: 'var(--type-h3-size)', margin: 'var(--space-3) 0 0' }}>
              {receipt ? (firstName ? `Thank you, ${firstName}` : 'Thank you') : offering.name}
            </h2>
          </div>
          <IconButton name="x" label="Close payment panel" onClick={closeSafely} />
        </div>

        {receipt ? (
          <div style={{ display: 'grid', gap: 'var(--space-5)' }} role="status">
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 'var(--space-3)', paddingBottom: 'var(--space-4)', borderBottom: '1px solid var(--line-hairline)' }}>
              <span style={{ fontFamily: 'var(--font-display)', fontSize: '2rem', color: 'var(--text-display)', letterSpacing: '.03em' }}>{money(value, currency)}</span>
              <span style={{ fontFamily: 'var(--font-body)', fontSize: 'var(--type-caption-size)', letterSpacing: 'var(--tracking-wider)', textTransform: 'uppercase', color: 'var(--text-muted)' }}>{isDeposit ? 'Deposit paid' : 'Paid in full'}</span>
            </div>
            <p style={{ ...small, color: 'var(--text-body)' }}>
              {receipt.status === 'COMPLETED'
                ? <React.Fragment>Your payment for <strong style={{ fontWeight: 600, color: 'var(--text-display)' }}>{offering.name}</strong> has been received. A confirmation is on its way to your email, and PayPal will send a receipt.</React.Fragment>
                : 'PayPal is still processing this payment. You will receive an email from PayPal once it clears.'}
            </p>
            <p style={{ ...small, color: 'var(--text-accent)' }}>{nextStep}</p>
            <p style={{ margin: 0, fontFamily: 'var(--font-mono)', fontSize: 'var(--type-caption-size)', color: 'var(--text-muted)' }}>Reference {receipt.reference}</p>
            <Button variant="outline" fullWidth onClick={onClose}>Close</Button>
          </div>
        ) : (
          <React.Fragment>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 'var(--space-3)', paddingBottom: 'var(--space-4)', borderBottom: '1px solid var(--line-hairline)' }}>
              <span style={{ fontFamily: 'var(--font-display)', fontSize: '2rem', color: 'var(--text-display)', letterSpacing: '.03em' }}>{money(value, currency)}</span>
              <span style={{ fontFamily: 'var(--font-body)', fontSize: 'var(--type-caption-size)', letterSpacing: 'var(--tracking-wider)', textTransform: 'uppercase', color: 'var(--text-muted)' }}>{currency} · {isDeposit ? 'deposit' : 'full amount'}</span>
            </div>
            {isWorkshop && <p style={{ ...small, color: 'var(--text-body)' }}>Plus postage &amp; handling, confirmed separately.</p>}
            <p style={{ ...small, color: 'var(--text-accent)' }}>{D.payment.availabilityNote}</p>
            <div style={{ border: '1px solid var(--line-accent)', background: 'var(--amber-04)', padding: 'var(--space-5)', display: 'grid', gap: 'var(--space-4)' }}>
              <Eyebrow>{isDeposit ? 'Deposit policy' : 'Booking & cancellation'}</Eyebrow>
              <div style={{ display: 'grid', gap: 'var(--space-4)' }}>
                {copy.terms().map((t, i) => <p key={i} style={{ ...small, color: i === 0 ? 'var(--text-body)' : 'var(--text-secondary)' }}>{t}</p>)}
              </div>
              <Checkbox checked={accepted} onChange={setAccepted} label={copy.ack} />
            </div>
            {error && <p role="alert" style={{ ...small, color: 'var(--text-display)', borderLeft: '2px solid var(--line-accent)', paddingLeft: 'var(--space-4)' }}>{error}</p>}
            {busy && <p role="status" style={{ ...small, color: 'var(--text-muted)', textAlign: 'center' }}>Confirming your payment…</p>}
            {accepted
              ? <div style={{ display: busy ? 'none' : 'block' }}>
                  <PayPalCheckout offering={offering} kind={isDeposit ? 'deposit' : 'full'} onPaid={setReceipt} onError={setError} onBusy={setBusy} />
                </div>
              : <p style={{ margin: 0, padding: 'var(--space-4)', border: '1px dashed var(--line-hairline)', textAlign: 'center', fontSize: 'var(--type-small-size)', color: 'var(--text-muted)' }}>Accept the terms above to continue to secure payment.</p>}
            <p style={{ margin: 0, fontSize: 'var(--type-caption-size)', lineHeight: 1.8, color: 'var(--text-muted)' }}>{D.payment.confirmationNote}</p>
          </React.Fragment>
        )}
      </div>
    </div>
  );
}

/* ---------- Accordion ---------- */
function Accordion({ items }) {
  const [open, setOpen] = React.useState(null);
  return (
    <div style={{ borderTop: '1px solid var(--line-hairline)' }}>
      {items.map((it, i) => {
        const isOpen = open === i;
        return (
          <div key={it.q} style={{ borderBottom: '1px solid var(--line-hairline)' }}>
            <h3 style={{ margin: 0 }}>
              <button aria-expanded={isOpen} onClick={() => setOpen(isOpen ? null : i)}
                style={{ width: '100%', display: 'flex', gap: 'var(--space-4)', alignItems: 'center', justifyContent: 'space-between', background: 'transparent', border: 0, padding: 'var(--space-5) 0', cursor: 'pointer', textAlign: 'left', fontFamily: 'var(--font-display)', fontWeight: 300, fontSize: '1.3rem', letterSpacing: '.03em', color: isOpen ? 'var(--text-accent)' : 'var(--text-display)' }}>
                {it.q}<span style={{ color: 'var(--text-accent)', display: 'inline-flex', flex: '0 0 auto' }}><Icon name={isOpen ? 'minus' : 'plus'} size={18} /></span>
              </button>
            </h3>
            {isOpen && <p style={{ margin: '0 0 var(--space-6)', maxWidth: '68ch', fontSize: 'var(--type-body-size)', lineHeight: 1.8, color: 'var(--text-body)' }}>{it.a}</p>}
          </div>
        );
      })}
    </div>
  );
}

/* ---------- Section helper ----------
   Grounds are rendered here rather than through <FieldBackdrop> so the page owns its own
   atmosphere; the same variant names exist on the design-system component. */
const PATTERN_STRENGTH = { subtle: .08, soft: .13, medium: .19, strong: .27 };
const GROUND = {
  glow: 'radial-gradient(circle at 50% 42%, rgba(18,56,66,.52) 0%, rgba(18,56,66,.18) 40%, rgba(8,9,16,0) 66%)',
  atlantic: 'radial-gradient(124% 104% at 50% -4%, rgba(26,76,89,.56) 0%, rgba(18,56,66,.24) 44%, rgba(8,9,16,0) 78%)',
  dawn: 'radial-gradient(126% 102% at 50% 106%, rgba(201,149,85,.32) 0%, rgba(163,118,63,.17) 32%, rgba(18,56,66,.12) 58%, rgba(8,9,16,0) 82%)',
  tide: 'radial-gradient(104% 122% at 14% 16%, rgba(26,76,89,.44) 0%, rgba(8,9,16,0) 68%), radial-gradient(96% 114% at 88% 92%, rgba(18,56,66,.36) 0%, rgba(8,9,16,0) 70%)',
  depth: 'radial-gradient(140% 104% at 50% 104%, rgba(18,56,66,.44) 0%, rgba(18,56,66,.16) 46%, rgba(8,9,16,0) 80%)',
  bone: 'linear-gradient(176deg, rgba(238,226,202,.94) 0%, rgba(232,218,192,.95) 100%)'
};
/* Every ground dissolves at its own top and bottom edge. A bloom only falls to zero
   radially — at the edge its own center sits on it is still at full strength — so the
   mask is what actually removes the seam. */
/* The peak's bronze comes from the page field below the bone, not a wash over the type. */

function Section({ id, eyebrow, heading, lead, level = 2, children, width = 'var(--container-wide)', align = 'left', pad = 'var(--space-10)', backdrop, pattern, patternScale, tone, style }) {
  const H = 'h' + level;
  React.useEffect(() => { syncPeak(); }, [tone, children]);
  const lightPad = tone === 'light' ? `calc(${pad} + ${(window.SE_TWEAKS || {}).blend ?? 220}px * 0.5)` : pad;
  const inner = (
    <div style={{ maxWidth: width, margin: '0 auto', padding: `${lightPad} var(--gutter-page)`, ...style }}>
      {(eyebrow || heading || lead) && <div style={{ textAlign: align, maxWidth: align === 'center' ? 'var(--container-text)' : undefined, marginLeft: align === 'center' ? 'auto' : undefined, marginRight: align === 'center' ? 'auto' : undefined }}>
        {eyebrow && <Eyebrow align={align}>{eyebrow}</Eyebrow>}
        {heading && <H style={{ fontFamily: 'var(--font-display)', fontWeight: 'var(--weight-display)', color: 'var(--text-display)', letterSpacing: 'var(--type-display-tracking)', lineHeight: 'var(--type-display-leading)', fontSize: 'var(--type-display-size)', margin: eyebrow ? 'var(--space-4) 0 0' : 0 }}>{heading}</H>}
        {lead && <p style={{ fontSize: 'var(--type-lead-size)', lineHeight: 1.7, color: 'var(--text-secondary)', margin: 'var(--space-5) 0 0', maxWidth: '62ch', marginLeft: align === 'center' ? 'auto' : undefined, marginRight: align === 'center' ? 'auto' : undefined }}>{lead}</p>}
      </div>}
      {children}
    </div>
  );
  const tw = window.SE_TWEAKS || {};
  const blend = tw.blend ?? 220;
  const patternMul = tw.patternIntensity ?? 1;
  const groundMul = tw.groundIntensity ?? 1;
  let ground = backdrop;
  let light = tone === 'light';
  if (tw.boneMode === 'Stay dark' && ground === 'bone') { ground = 'depth'; light = false; }
  const edgeMask = blend > 0
    ? `linear-gradient(to bottom, transparent 0, #000 ${blend}px, #000 calc(100% - ${blend}px), transparent 100%)`
    : undefined;
  const layers = [];
  if (GROUND[ground]) layers.push({ background: GROUND[ground], opacity: ground === 'bone' ? 1 : groundMul, maskImage: edgeMask, WebkitMaskImage: edgeMask });
  if (pattern) layers.push({ background: `url(${AB}/patterns/field-pattern.png) center / ${patternScale || 480}px repeat`, opacity: (typeof pattern === 'number' ? pattern : (PATTERN_STRENGTH[pattern] ?? .13)) * patternMul, filter: light ? 'invert(1)' : undefined, maskImage: edgeMask, WebkitMaskImage: edgeMask });
  if (!layers.length && !light) return <section id={id}>{inner}</section>;
  return (
    <section id={id} className={light ? 'se-light' : undefined} style={{ position: 'relative', background: 'transparent', overflow: 'hidden' }}>
      {layers.map((l, i) => <div key={i} aria-hidden="true" style={{ position: 'absolute', inset: 0, pointerEvents: 'none', ...l }} />)}
      <div style={{ position: 'relative' }}>{inner}</div>
    </section>
  );
}

/* The warm peak follows the page's own light section rather than a fixed percentage,
   so every page reads dark → light → dark regardless of where that section falls. */
function syncPeak() {
  const light = document.querySelector('.se-light');
  const docH = document.documentElement.scrollHeight;
  /* Bail rather than write a fallback: this runs before React has rendered, and a
     premature default would stick. */
  if (!light || !docH) return false;
  const r = light.getBoundingClientRect();
  const pct = ((r.top + window.scrollY + r.height / 2) / docH) * 100;
  document.documentElement.style.setProperty('--se-peak', pct.toFixed(2) + '%');
  return true;
}
if (typeof window !== 'undefined') {
  window.addEventListener('resize', syncPeak);
  if (window.ResizeObserver) new ResizeObserver(syncPeak).observe(document.body);
}

Object.assign(window, { syncPeak, IrisPortal, Portrait, SosDiagram, Placeholder, Header, Footer, PaymentModal, loadPayPal, Accordion, Section, DS, D, money, AB });
