/* ============================================================
   B3X GRAPHICS — b3x-core styles.css (plugin assets/styles.css)
   Built 5 Oct 2026 (stream B) from the signed-off staging CSS, in the
   order staging loads it:
     1. /assets/refresh/blueprint-bg.css   (verbatim)
     2. /site/site.css?v=40                 (verbatim, @font-face moved to fonts.css)
     3. b3x-core additions                  (end of file: editable-field
        wrappers, engine lead form, html.static editor freeze, AW credit)
   ============================================================ */

/* ===================== 1. blueprint-bg.css ===================== */
/* ============================================================
   B3X BLUEPRINT BACKGROUND (prototype, TOGGLEABLE) — Paul, 17 Sep.
   Concept: drop the baked-in blueprint PNG for a plain (living/breathing)
   gradient, then DRAW the blueprint lines in on load like they're etched
   into ice/glass, then run sparks across ALL the lines at random.

   Toggle: this whole layer only activates when blueprint-bg.js runs (its
   two tags in index.html). Remove those tags to fall back to the current
   Hero-background.png + electric-bg spark version. Scoped under .b3xbp-* /
   html.b3x-blueprint so it never collides with the .b3xr-* refresh layer.

   Assets (generated from Hero-background.png, offline, pngjs):
   - hero-gradient.png : the de-lined gradient (64x56, upscaled smoothly here)
   - hero-lines.json   : every blueprint line traced to strokable SVG paths
   ============================================================ */

/* hide the baked-line hero PNG so only the clean gradient (breathing layer) shows */
html.b3x-blueprint body{background-color:#02132c !important;background-image:none !important;}

/* ---- breathing gradient layer (fixed, behind everything) ---- */
.b3xbp-grad{
  position:fixed;top:0;left:0;width:100%;z-index:-3;pointer-events:none;
  /* size to the LARGE viewport height as a constant (not 100% / dvh) so the mobile URL
     bar hiding/showing never resizes the background — it stays one size + position through
     the whole scroll. EXTENDED well past the bottom (+200px) so it always covers the iOS
     home-indicator / bottom-safe-area gap where the body's flat navy was showing through as
     a seam. The gradient is smooth so the extra zoom is invisible; the lines are a separate
     layer so they're unaffected. (Paul, iOS test) */
  height:calc(100vh + 200px); height:calc(100lvh + 200px);
  /* cover + pinned TOP + RIGHT so it matches the right-aligned line overlay (the art hugs
     the right edge). Landscape/desktop has no horizontal crop so this looks the same as
     centred; only portrait/mobile pins to the right. */
  background-size:cover;background-position:right top;background-repeat:no-repeat;
  /* image-rendering smooth so the tiny 64x56 gradient upscales cleanly */
  image-rendering:auto;
  will-change:transform,filter;
  transform:scale(1.06);
  animation:b3xbp-breathe 14s ease-in-out infinite alternate;
}
/* constant life — a slow drift + brightness/saturation swell, now MORE noticeable
   (Paul, 17 Sep). Scale stays well >1 so the bigger drift never exposes an edge. */
@keyframes b3xbp-breathe{
  0%  {transform:scale(1.06) translate3d(0,0,0);          filter:saturate(1) brightness(0.98);}
  50% {transform:scale(1.13) translate3d(-1.5%,-1.1%,0);  filter:saturate(1.13) brightness(1.09);}
  100%{transform:scale(1.08) translate3d(1.3%,0.9%,0);    filter:saturate(1.03) brightness(0.96);}
}

/* ---- line overlay (fixed, cover-mapped to match the gradient) ---- */
.b3xbp-lines{
  position:fixed;top:0;left:0;width:100%;z-index:-2;pointer-events:none;overflow:visible;
  height:100vh; height:100lvh; /* constant large-viewport height (see .b3xbp-grad) — no resize/seam on mobile */
  transform:translateZ(0);     /* own compositing layer = steadier fixed painting on iOS */
}
/* drawn/resting line: thin, soft sky, 1px at any scale. A faint dark halo (drop-shadow
   on the whole overlay) gives the lines contrast on the BRIGHT right side of the gradient
   as well as the dark left, so they read everywhere without being heavy. */
.b3xbp-lines{filter:drop-shadow(0 0 0.6px rgba(2,14,38,0.55));}
.b3xbp-line{
  /* SOLID colour at full opacity (Paul): semi-transparent lines summed brighter where they
     crossed; this is the blended shade the 0.55 gave, so crossings no longer stack. */
  fill:none;stroke:#88b0dd;stroke-width:1.1;
  vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round;
}
/* a travelling spark = a short bright segment sweeping a line */
.b3xbp-spark{
  fill:none;stroke:#e6f6ff;stroke-width:1.5;
  vector-effect:non-scaling-stroke;stroke-linecap:round;
  filter:drop-shadow(0 0 3px rgba(120,220,255,0.95)) drop-shadow(0 0 7px rgba(60,170,255,0.5));
}

/* (mobile framing is handled by right-aligning the cover — xMaxYMin on the SVG +
   background-position:right on the gradient — so the art always hugs the right edge and
   the lines never trail off into empty gradient. No fixed per-width shift needed.) */

@media (prefers-reduced-motion:reduce){
  .b3xbp-grad{animation:none;}
  .b3xbp-line{stroke-dashoffset:0 !important;transition:none !important;}
}


/* ===================== 2. site.css ===================== */
/* ============================================================
   B3X GRAPHICS — shared site shell (clean new-brand build)
   Powers the outer Projects listing, the individual project
   TEMPLATE, Contact and About. Same brand system as the approved
   homepage (fonts / navy+sky palette / glass / floating bar), but
   built as clean standalone HTML so it doubles as the aw-wp-build
   source. Header + footer + policy modals are server-rendered by
   assets/inc/chrome.php; behaviour is in assets/app.js.
   ============================================================ */

/* ---- fonts: see assets/fonts.css (loaded first by the engine frame) ---- */

/* ---- tokens (match the homepage refresh layer exactly) ---- */
:root{
  --navy:#031b3d;          /* brand ink */
  --sky:#04b5ff;           /* brand accent */
  --sky-2:#0474ff;
  --deep:#02132c;          /* deep page bg */
  --ink:#eaf2ff;           /* light text on dark */
  --muted:rgba(255,255,255,.72);
  --line:rgba(255,255,255,.14);
  --glass:linear-gradient(155deg,rgba(9,26,54,.52) 0%,rgba(3,13,30,.68) 100%);
  --glass-solid:linear-gradient(155deg,rgba(9,26,54,.92) 0%,rgba(3,13,30,.95) 100%);
  --shadow:0 18px 48px rgba(0,6,20,.26),inset 0 1px 0 rgba(255,255,255,.10);
  --side:clamp(20px,2.2vw,50px);   /* 20px gutter on tablet/mobile (Paul), growing to 50 on desktop */
  --max:1780px;
  --bar-max:1820px;
  --cap:max(var(--side),calc((100% - var(--max)) / 2));
  /* per-project theming — a page can override these on <body data-...> or inline.
     Default = the site's deep navy + sky accent. */
  --proj-bg:var(--deep);
  --proj-bg-2:#061a3a;
  --proj-accent:var(--sky);
  --proj-on:#ffffff;       /* text colour on the project bg */
  --proj-muted:rgba(255,255,255,.72);
  --proj-line:rgba(255,255,255,.14);
  /* subtle edge drawn round every project graphic so rounded corners read against the bg */
  --img-edge:rgba(255,255,255,.16);
  /* generous project-page gutter (Bex: bigger padding either side so full
     graphics fit on screen). Wider than the standard content cap. */
  --proj-gut:clamp(20px,7vw,120px);
}

*{box-sizing:border-box;}
html,body{margin:0;overflow-x:clip;overscroll-behavior-x:none;}
html{scroll-behavior:smooth;}
body{
  font-family:'Aileron',sans-serif;font-weight:400;color:var(--ink);
  background:var(--proj-bg);
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  min-height:100vh;
}
img{max-width:100%;display:block;}
a{color:inherit;}
h1,h2,h3,h4{font-family:'Palma Heavy',sans-serif;font-weight:400;margin:0;}
.wrap{max-width:var(--max);margin-inline:auto;padding-inline:var(--side);}

/* light-background project mode (e.g. Spurs 1901 needs solid white) */
body.proj-light{
  --proj-on:#0b1220; --proj-muted:rgba(11,18,32,.66); --proj-line:rgba(11,18,32,.12);
  /* darker edge on the white page so white-bordered graphics don't vanish into the bg */
  --img-edge:rgba(10,20,40,.22);
}
body.proj-light .b3xr-kick{color:var(--proj-accent);}

/* =========================================================
   BUTTONS — navy pill, white text at every state, 1px sky
   edge + glow + draw-around line + trailing arrow (matches home)
   ========================================================= */
.b3xr-gbtn{
  position:relative;isolation:isolate;display:inline-flex;align-items:center;gap:9px;
  font-family:'Safiro',sans-serif;font-weight:700;font-size:16px;color:#fff;
  text-transform:capitalize;letter-spacing:.02em;text-decoration:none;
  padding:14px 30px;border-radius:100px;background:var(--navy);
  border:1px solid rgba(4,181,255,.5);box-shadow:0 6px 22px rgba(0,10,30,.42);
  transition:box-shadow .45s ease;overflow:visible;cursor:pointer;line-height:1;
}
.b3xr-gbtn:hover{color:#fff;box-shadow:0 6px 22px rgba(0,10,30,.42),0 0 24px rgba(4,181,255,.4);}
.b3xr-btnline{position:absolute;inset:-1px;width:calc(100% + 2px);height:calc(100% + 2px);overflow:visible;pointer-events:none;z-index:2;filter:drop-shadow(0 0 1.4px rgba(4,181,255,.55));}
.b3xr-btnline rect{fill:none;stroke:url(#b3xr-btnstroke);stroke-width:1;vector-effect:non-scaling-stroke;stroke-linecap:butt;stroke-dasharray:0 200;stroke-dashoffset:-50;transition:stroke-dasharray .72s cubic-bezier(.45,0,.25,1),stroke-dashoffset .72s cubic-bezier(.45,0,.25,1);}
.b3xr-gbtn:hover .b3xr-btnline rect{stroke-dasharray:106 200;stroke-dashoffset:3;}
.b3xr-btnarrow{display:inline-flex;transition:transform .35s cubic-bezier(.16,1,.3,1);}
.b3xr-gbtn:hover .b3xr-btnarrow{transform:translateX(4px);}
.b3xr-gbtn.ghost{background:transparent;border-color:rgba(255,255,255,.4);}
body.proj-light .b3xr-gbtn.ghost{border-color:rgba(11,18,32,.28);color:var(--navy);}
@media(prefers-reduced-motion:reduce){.b3xr-btnline rect{transition:none;}}

/* shared eyebrow / kicker */
.b3xr-kick{font-family:'Aileron',sans-serif;text-transform:uppercase;letter-spacing:.18em;font-size:14px;font-weight:700;color:var(--sky);margin:0 0 14px;}

/* =========================================================
   HEADER: the global header (bar, nav panel, page transition) lives in its own standalone
   assets/chrome.css + chrome.js (5 Oct), so the Woo shop can load it too. Nothing here.
   ========================================================= */

/* =========================================================
   FOOTER — floating frosted-glass panel + AI-policy modal
   ========================================================= */
/* The footer + policy modals are the ONE global footer (5 Oct, Paul: the inner pages' footer, homepage
   included). They use their own font family names: the homepage redeclares 'Aileron' / 'Palma Heavy'
   with size-adjust and forces body/p/li to Aileron 400 !important, the inner pages do not. These
   aliases (no size-adjust = the inner pages' signed-off look) and the explicit inherited values below
   keep the footer and modals identical on every page, whatever page CSS sits around them. */
@font-face{font-family:'B3XF Palma';src:url('fonts/PPPalma-Heavy.woff2') format('woff2'),url('fonts/PPPalma-Heavy.woff') format('woff');font-weight:100 900;font-style:normal;font-display:swap;}
@font-face{font-family:'B3XF Aileron';src:url('fonts/aileron-700.woff2') format('woff2');font-weight:600 900;font-style:normal;font-display:swap;}
@font-face{font-family:'B3XF Aileron';src:url('fonts/aileron-400.woff2') format('woff2');font-weight:100 599;font-style:normal;font-display:swap;}
.site-footer,.b3xr-modal-overlay{font-family:'B3XF Aileron',sans-serif;font-size:16px;font-weight:400;font-style:normal;line-height:normal;
  letter-spacing:normal;text-transform:none;text-align:start;color:var(--ink);text-rendering:optimizeLegibility;}
.site-footer p,.site-footer li,.b3xr-modal-overlay p,.b3xr-modal-overlay li{font-family:'B3XF Aileron',sans-serif!important;font-weight:400!important;}
.site-footer{padding:60px var(--side);}
.footer-glass{max-width:var(--bar-max);margin-inline:auto;
  display:flex;align-items:center;justify-content:space-between;gap:40px;flex-wrap:wrap;
  padding:clamp(30px,3vw,52px) clamp(32px,3.4vw,60px);border-radius:26px;border:1px solid var(--line);
  background:var(--glass);box-shadow:var(--shadow);
  -webkit-backdrop-filter:blur(8px) saturate(1.3);backdrop-filter:blur(8px) saturate(1.3);}
/* left column capped ~810px like the homepage (this is what wraps the CTA to 2 lines) */
.foot-left{flex:1 1 320px;min-width:0;max-width:810px;}
.foot-cta{font-family:'B3XF Palma',sans-serif;font-weight:400;color:#fff;font-size:clamp(38px,7.5vw,78px);line-height:1.06;margin:0 0 18px;}
.foot-get{font-size:23px;color:var(--muted);margin:0 0 18px;}
.foot-get a{color:var(--sky);text-decoration:none;}
/* order (matches homepage): CTA, Get in touch, SOCIAL, then POLICIES pinned at the bottom */
.foot-policies{list-style:none;display:flex;flex-wrap:wrap;gap:8px 26px;padding:0;margin:0;}
.foot-policies a{font-family:'B3XF Aileron',sans-serif;font-weight:400;font-size:13px;letter-spacing:normal;text-transform:none;color:#fff;text-decoration:none;white-space:nowrap;transition:color .25s ease;}
.foot-policies a:hover{color:var(--sky);}
/* social = white circle, navy glyph, 44px — identical to the homepage footer */
.foot-social{display:flex;gap:14px;margin:0 0 30px;}
.foot-social a{width:44px;height:44px;border-radius:50%;border:0;background:#fff;display:grid;place-content:center;color:#022656;transition:transform .25s ease,background-color .25s ease;}
/* hover (Paul, 6 Oct): sky background, the navy icon stays */
.foot-social a:hover{transform:translateY(-2px);background:var(--sky);}
.site-footer .foot-social a:hover,.site-footer .foot-social a:focus{color:#022656;}
.site-footer .foot-social a:hover,.site-footer .foot-social a:focus-visible{background:var(--sky);}
.site-footer .foot-social a:focus-visible{outline:2px solid #fff;outline-offset:3px;}
.foot-social svg{width:22px;height:22px;fill:currentColor;}
.foot-right{flex:0 0 auto;}
.foot-b{height:160px;width:auto;opacity:.96;}
@media(max-width:768px){
  .footer-glass{justify-content:flex-start;gap:24px;padding:30px 26px;}
  .foot-right{order:-1;width:100%;text-align:center;}
  .foot-b{height:84px;margin-inline:auto;}
  .foot-cta{font-size:clamp(34px,10vw,54px);}
  .foot-get{font-size:19px;}
  /* 7 Oct, Paul: everything centred on phones, like the logo (and the old site) */
  .foot-left{width:100%;text-align:center;}
  .foot-social,.foot-policies{justify-content:center;}
}

/* AI-policy modal (verbatim, same glass language as the home modal) */
.b3xr-modal-overlay{position:fixed;inset:0;z-index:100000;display:flex;align-items:center;justify-content:center;padding:24px;background:rgba(2,8,22,.62);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);opacity:0;pointer-events:none;transition:opacity .3s ease;}
.b3xr-modal-overlay.b3xr-open{opacity:1;pointer-events:auto;}
html.b3xr-modal-lock{overflow:hidden;}
.b3xr-modal{position:relative;width:100%;max-width:720px;max-height:86vh;overflow:hidden;border-radius:24px;border:1px solid var(--line);background:var(--glass-solid);-webkit-backdrop-filter:blur(18px) saturate(1.3);backdrop-filter:blur(18px) saturate(1.3);box-shadow:0 30px 80px rgba(0,6,20,.6);color:#eaf2ff;transform:translateY(12px) scale(.98);transition:transform .32s cubic-bezier(.16,1,.3,1);}
.b3xr-modal-overlay.b3xr-open .b3xr-modal{transform:none;}
/* the BODY scrolls (not the whole modal), so the close button stays fixed in place while you read
   and the scrollbar is clipped inside the modal's rounded corners (track margin keeps it off the radius) */
.b3xr-modal-body{max-height:86vh;overflow-y:auto;overscroll-behavior:contain;padding:clamp(28px,4vw,48px);}
.b3xr-modal-body::-webkit-scrollbar{width:8px;}
.b3xr-modal-body::-webkit-scrollbar-track{margin:18px 0;background:transparent;}
.b3xr-modal-body::-webkit-scrollbar-thumb{background:rgba(255,255,255,.18);border-radius:8px;}
/* close button: ~half size, fixed top-right (absolute on the non-scrolling modal), sits above the
   scrolling content with a subtle backdrop so it stays legible */
.b3xr-modal-close{position:absolute;top:12px;right:12px;z-index:3;width:26px;height:26px;border-radius:50%;border:1px solid rgba(255,255,255,.28);background:rgba(20,30,54,.6);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .2s ease,border-color .2s ease;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);}
/* the browser button defaults the signed-off inner pages rendered with (the icon sits squeezed to 12px
   inside 1px 6px padding), written out so a theme button reset (the homepage Hello theme) cannot change it */
.b3xr-modal-overlay .b3xr-modal-close{padding:1px 6px;margin:0;font-family:Arial;font-size:13.3333px;font-weight:400;line-height:normal;white-space:normal;}
.b3xr-modal-overlay .b3xr-modal-close:focus{background:rgba(20,30,54,.6);border-color:rgba(255,255,255,.28);color:#fff;}
.b3xr-modal-close:hover,.b3xr-modal-overlay .b3xr-modal-close:hover{background:var(--sky);border-color:var(--sky);}
.b3xr-modal-close svg{width:15px;height:15px;}
.b3xr-modal-title{font-family:'B3XF Palma',sans-serif;font-weight:400;line-height:normal;font-size:clamp(26px,3.4vw,36px);margin:0 0 18px;color:#fff;}
.b3xr-modal-body p{font-size:15.5px;line-height:1.62;margin:0 0 14px;color:#d6e2f5;}
.b3xr-modal-subhead{font-weight:700;color:#fff;margin-top:20px;}
.b3xr-modal-overlay .b3xr-modal-subhead{font-weight:700!important;}
.b3xr-modal-list{margin:0 0 16px;padding:0;list-style:none;}
.b3xr-modal-list li{position:relative;padding-left:22px;margin:0 0 9px;font-size:15.5px;line-height:1.55;color:#d6e2f5;}
.b3xr-modal-list li::before{content:"";position:absolute;left:2px;top:9px;width:7px;height:7px;border-radius:50%;background:var(--sky);}
/* section heading inside a policy modal (privacy / licence) */
.b3xr-modal-h{font-family:'B3XF Palma',sans-serif;font-weight:400;color:#fff;font-size:clamp(18px,2vw,22px);line-height:1.18;margin:24px 0 10px;}
.b3xr-modal-body>.b3xr-modal-h:first-of-type{margin-top:6px;}

/* =========================================================
   REVEAL ON SCROLL (fade + rise) — fail-safe: only hides once JS marks html.reveal-on
   ========================================================= */
html.reveal-on .reveal{opacity:0;transform:translateY(26px);}
html.reveal-on .reveal.in{opacity:1;transform:none;transition:opacity .8s cubic-bezier(.16,1,.3,1),transform .8s cubic-bezier(.16,1,.3,1);}
@media(prefers-reduced-motion:reduce){html.reveal-on .reveal{opacity:1;transform:none;}}

/* =========================================================
   PAGE HEAD (shared top spacing under the fixed bar)
   ========================================================= */
.page-top{padding-top:150px;}
@media(max-width:600px){.page-top{padding-top:110px;}}

/* generic section heading */
.sec-title{font-family:'Palma Heavy',sans-serif;color:var(--proj-on);font-size:clamp(36px,5.4vw,78px);line-height:.95;margin:0;}
.lede{font-size:clamp(18px,1.5vw,22px);line-height:1.6;color:var(--proj-muted);max-width:64ch;}

/* =========================================================
   PROJECTS LISTING (outer page) — card grid, keeps the home look
   ========================================================= */
.pl-head{margin-bottom:clamp(30px,4vw,56px);}
.pl-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(16px,1.6vw,26px);}
@media(max-width:1080px){.pl-grid{grid-template-columns:repeat(2,1fr);}}
@media(max-width:640px){.pl-grid{grid-template-columns:1fr;}}
.pl-card{position:relative;display:block;border-radius:22px;overflow:hidden;background:#0a1c3d;
  aspect-ratio:4/3;text-decoration:none;transition:transform .5s cubic-bezier(.16,1,.3,1);}
.pl-card:hover{transform:translateY(-6px);}
.pl-card img{width:100%;height:100%;object-fit:cover;transition:transform .8s cubic-bezier(.16,1,.3,1);}
.pl-card:hover img{transform:scale(1.04);}
.pl-card .ov{position:absolute;inset:0;padding:28px;display:flex;flex-direction:column;justify-content:flex-end;
  background:linear-gradient(to top,rgba(2,10,26,.92) 0%,rgba(2,10,26,.15) 48%,rgba(2,10,26,0) 72%);}
.pl-card .tag{align-self:flex-start;margin-bottom:auto;font-family:'Aileron',sans-serif;font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:#fff;background:rgba(4,181,255,.92);padding:5px 12px;border-radius:100px;}
.pl-card h3{font-family:'Palma Heavy',sans-serif;color:#fff;font-size:clamp(20px,1.8vw,28px);line-height:1.02;margin:0 0 6px;}
.pl-card p{font-family:'Aileron',sans-serif;font-weight:700;font-size:14px;color:rgba(255,255,255,.82);margin:0;}
.pl-card.soon{pointer-events:none;}
.pl-card .soonbadge{position:absolute;top:20px;right:20px;font-family:'Aileron',sans-serif;font-weight:700;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:#fff;background:rgba(3,13,30,.72);border:1px solid var(--line);padding:6px 12px;border-radius:100px;z-index:2;}

/* =========================================================
   INDIVIDUAL PROJECT TEMPLATE
   ========================================================= */
.proj{background:transparent;min-height:100vh;
  /* Bex: pull the project content into a tighter column (Roussel/Dom); graphics sit fully on screen.
     R1 (Bex, 29 Sep — CORRECTED): she wants LESS side padding so images fill more of the screen on
     smaller devices (iPad/MacBook), not more. So: narrower gutter than the original (vw 5->3.2,
     cap 72->88 only bites on very wide screens) + a wider content cap 1200->1280 = bigger images at
     tablet/laptop widths, moderate on big desktops. Images still height-capped to the fold below. */
  --proj-max:1280px;--proj-gut:clamp(12px,2.6vw,88px);}
/* continuous page background — no footer seam. The project colour lives on <body>, fixed, so the
   content AND the floating footer sit on ONE unbroken gradient (Paul, 18 Sep). */
body[data-page="work"]{background:linear-gradient(180deg,var(--proj-bg) 0%,var(--proj-bg-2) 100%) fixed;background-repeat:no-repeat;}
body.proj-light[data-page="work"]{background:#ffffff;}

/* banner across the top */
.proj-banner{position:relative;width:100%;height:clamp(360px,72vh,760px);overflow:hidden;}
.proj-banner img{width:100%;height:100%;object-fit:cover;}
.proj-banner::after{content:"";position:absolute;inset:0;background:linear-gradient(to top,var(--proj-bg) 2%,rgba(0,0,0,0) 42%);}
body.proj-light .proj-banner::after{background:linear-gradient(to top,#ffffff 2%,rgba(0,0,0,0) 46%);}
/* top scrim so the header chrome stays legible on dark cover art from load (light pages get the frosted bar instead) */
.proj-banner::before{content:"";position:absolute;top:0;right:0;left:0;z-index:1;height:clamp(140px,22vh,240px);background:linear-gradient(to bottom,rgba(2,8,20,0.62) 0%,rgba(2,8,20,0.30) 48%,rgba(2,8,20,0) 100%);pointer-events:none;}
body.proj-light .proj-banner::before{display:none;}

/* contained header block: title + meta row + Brief + intro */
.proj-head{max-width:var(--proj-max,var(--max));margin-inline:auto;padding:clamp(28px,4vw,60px) var(--proj-gut) 0;position:relative;z-index:2;margin-top:clamp(-90px,-8vw,-40px);}
/* sized so the LONGEST project title ("Bristol City Women 2026/27 Kit Launch") fits on ONE line
   within the 1200 column (measured ~52px max at 1056px available); 50px = a touch of safety margin.
   Scales down on smaller screens; may wrap on mobile, which is fine. (Paul, 18 Sep) */
.proj-title{font-family:'Palma Heavy',sans-serif;color:var(--proj-on);font-size:clamp(30px,4.2vw,50px);line-height:1.06;margin:0 0 clamp(22px,2.6vw,36px);letter-spacing:-.01em;}
/* equal columns across the FULL width for ANY number of fields (3 or 4) */
.proj-meta{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:24px;padding:clamp(22px,2.4vw,30px) 0;border-top:1px solid var(--proj-line);border-bottom:1px solid var(--proj-line);}
.proj-meta .m{display:flex;flex-direction:column;gap:7px;}
@media(max-width:640px){.proj-meta{grid-auto-flow:row;grid-template-columns:repeat(2,1fr);gap:22px;}}
.proj-meta .m .k{font-family:'Aileron',sans-serif;font-weight:700;text-transform:uppercase;letter-spacing:.16em;font-size:12px;color:var(--proj-accent);}
.proj-meta .m .v{font-family:'Aileron',sans-serif;font-weight:400;font-size:16px;color:var(--proj-on);}

/* Brief block — contained, tidy width (no long full-bleed text lines) */
.proj-brief{max-width:var(--proj-max,var(--max));margin-inline:auto;padding:clamp(40px,5vw,80px) var(--proj-gut);
  display:grid;grid-template-columns:1fr 1fr;gap:clamp(30px,6vw,110px);align-items:start;}
.proj-brief .lbl{font-family:'Palma Heavy',sans-serif;color:var(--proj-on);font-size:clamp(26px,2.4vw,34px);line-height:1;}
.proj-brief .body{justify-self:end;max-width:54ch;}
.proj-brief .body p{font-size:16px;line-height:1.65;color:var(--proj-muted);margin:0 0 16px;}
.proj-brief .body p:last-child{margin-bottom:0;}
@media(max-width:760px){.proj-brief{grid-template-columns:1fr;gap:14px;}
  .proj-brief .lbl{padding-left:0;}
  .proj-brief .body{justify-self:start;max-width:none;}}

/* image presentation area (Dom / Roussel feel: big gutters, full graphics fit) */
.proj-media{max-width:var(--proj-max,var(--max));margin-inline:auto;padding:0 var(--proj-gut) clamp(40px,6vw,90px);
  display:flex;flex-direction:column;gap:clamp(18px,2.4vw,40px);
  /* fold budget = viewport minus the floating bar + a little breathing room. Any single image is
     capped to this height so it always sits fully on screen (Bex: see any image completely in the fold). */
  --fold:calc(100svh - 120px);}
/* single image: hug the image (rounded corners tight), centred, never taller than the fold */
/* single images CENTRE in the column (Paul: re-stacked / single images default to centre, not left) */
.proj-media .full{width:-moz-fit-content;width:fit-content;max-width:100%;margin-inline:auto;border-radius:14px;overflow:hidden;background:rgba(255,255,255,.03);}
.proj-media .full img{display:block;width:auto;height:auto;max-width:100%;max-height:var(--fold);}
/* strip graphics (her "THE DETAILS..." bands) run the full column width, not height-capped */
.proj-media .full.bleed{width:100%;border-radius:0;}
.proj-media .full.bleed img{width:100%;max-height:none;}
/* two-up grid: centre each image in its cell, each capped so the pair fits the fold together */
/* every 2-up pair is flush by default: equal height, fills the pair, columns auto-sized to the
   images' aspect ratios by flushGrids() in site.js (no crop, not fixed 50/50). */
.proj-grid2{display:grid;grid-template-columns:1fr 1fr;gap:clamp(14px,1.6vw,26px);align-items:stretch;}
.proj-grid2 .full{margin:0;width:100%;height:100%;}
.proj-grid2 .full img{width:100%;height:100%;object-fit:cover;max-height:none;}
@media(max-width:700px){.proj-grid2{grid-template-columns:1fr;}
  .proj-grid2 .full,.proj-grid2 .full img{height:auto;object-fit:contain;}}
/* flush pair: a 4:5 + a 1:1 sit the SAME height, flush top and bottom, no crop —
   the square grows into a wider column so its height matches the 4:5 (4fr / 5fr) */
.proj-grid2.flush{grid-template-columns:4fr 5fr;align-items:stretch;}
.proj-grid2.flush .full{width:100%;height:100%;margin:0;}
.proj-grid2.flush .full img{width:100%;height:100%;object-fit:cover;max-height:none;}
@media(max-width:700px){.proj-grid2.flush{grid-template-columns:1fr;}
  .proj-grid2.flush .full,.proj-grid2.flush .full img{height:auto;object-fit:contain;}}
.proj-caption{font-family:'Aileron',sans-serif;font-size:14px;color:var(--proj-muted);margin:2px 0 0;letter-spacing:.01em;}
/* subtle 1px edge on every project graphic (not the full-bleed hero banner) so rounded corners
   and graphic edges always read against the bg — especially white-bordered graphics on the light
   Spurs 1901 page. A box-shadow ring follows the radius and adds no layout shift. */
.proj-media .full,.proj-video,.ba,.lab-four>.lab-four-cell>img,.pl-card{box-shadow:0 0 0 1px var(--img-edge);}
/* cards inside a horizontal scroller draw the ring on an overlay ABOVE the image (the image
   is opaque, so an inset shadow behind it only shows at the clipped corners). ::after fills the
   card, sits on top, and its inset ring shows all four edges — and it can't be clipped by the scroller. */
.lab-card{position:relative;}
.ts-card::after,.lab-card::after{content:"";position:absolute;inset:0;border-radius:inherit;box-shadow:inset 0 0 0 1px var(--img-edge);pointer-events:none;z-index:3;}

/* label strip / section marker inside a project */
.proj-marker{font-family:'Palma Heavy',sans-serif;color:var(--proj-on);font-size:clamp(24px,2.6vw,40px);line-height:1;margin:clamp(20px,3vw,40px) 0 4px;}
/* text "details" section (real on-page text, not an image) */
.proj-details{margin:clamp(6px,1.5vw,20px) 0;}
.proj-points{list-style:none;margin:clamp(18px,2vw,30px) 0 0;padding:0;display:grid;grid-template-columns:1fr 1fr;gap:14px clamp(30px,4vw,70px);}
.proj-points li{position:relative;padding-left:24px;font-family:'Aileron',sans-serif;font-size:16px;line-height:1.5;color:var(--proj-muted);}
.proj-points li::before{content:"";position:absolute;left:2px;top:9px;width:7px;height:7px;border-radius:50%;background:var(--proj-accent);}
@media(max-width:640px){.proj-points{grid-template-columns:1fr;gap:12px;}}
/* centred statement / caption line between media blocks */
.proj-say{max-width:760px;margin:clamp(18px,3vw,44px) auto;text-align:center;font-family:'Aileron',sans-serif;font-size:clamp(18px,1.5vw,21px);line-height:1.55;color:var(--proj-muted);}
/* contained body-copy block (multi-paragraph) set as real on-page text */
.proj-copy{max-width:720px;margin:clamp(20px,3.5vw,52px) 0;}
.proj-copy p{font-family:'Aileron',sans-serif;font-size:clamp(16px,1.25vw,18px);line-height:1.72;color:var(--proj-muted);margin:0 0 16px;}
.proj-copy p:last-child{margin-bottom:0;}
/* credits block (role / name) */
.proj-credits{display:grid;grid-template-columns:repeat(3,1fr);gap:20px clamp(24px,3vw,50px);margin:clamp(4px,1.4vw,16px) 0 clamp(8px,1.6vw,20px);}
.proj-credits .c .k{display:block;font-family:'Aileron',sans-serif;font-weight:700;text-transform:uppercase;letter-spacing:.14em;font-size:11px;color:var(--proj-accent);margin-bottom:6px;}
.proj-credits .c .v{font-family:'Aileron',sans-serif;font-size:15px;color:var(--proj-on);line-height:1.45;}
@media(max-width:640px){.proj-credits{grid-template-columns:1fr;gap:14px;}}
/* 3-up waterfall grid (solos) */
.proj-grid3{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(12px,1.4vw,22px);justify-items:start;align-items:start;}
.proj-grid3 .full{margin:0;}
.proj-grid3 .full img{max-height:calc(100svh - 150px);}
@media(max-width:820px){.proj-grid3{grid-template-columns:repeat(2,1fr);}}
@media(max-width:520px){.proj-grid3{grid-template-columns:1fr;}}
/* video module (lightweight replacement for a heavy GIF) */
.proj-video{width:-moz-fit-content;width:fit-content;max-width:100%;margin-inline:auto;border-radius:14px;overflow:hidden;background:var(--proj-bg);}
.proj-video video{display:block;width:auto;height:auto;max-width:100%;max-height:var(--fold,calc(100svh - 120px));}

/* =========================================================
   BEFORE / AFTER SLIDER (vanilla, no jQuery)
   ========================================================= */
.ba{position:relative;width:100%;border-radius:14px;overflow:hidden;user-select:none;touch-action:pan-y;background:var(--proj-bg);cursor:ew-resize;}
.ba img{width:100%;height:100%;object-fit:cover;display:block;pointer-events:none;}
.ba .ba-after{position:relative;z-index:1;}
/* reveal via clip-path on a FULL-SIZE before layer (not a width-changing clip): the before image
   always fills the slider identically to the after image and stays perfectly static — the handle
   just clips how much of it shows. True split-screen, no JS width-pinning to go wrong. */
.ba .ba-before{position:absolute;inset:0;z-index:2;overflow:hidden;will-change:clip-path;}
.ba .ba-before img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;}
.ba .ba-tag{position:absolute;top:16px;z-index:3;font-family:'Aileron',sans-serif;font-weight:700;font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:#fff;background:rgba(3,13,30,.66);border:1px solid var(--line);padding:6px 12px;border-radius:100px;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);}
.ba .ba-tag.before{left:16px;} .ba .ba-tag.after{right:16px;}
.ba .ba-handle{position:absolute;top:0;bottom:0;z-index:4;width:2px;background:rgba(255,255,255,.9);transform:translateX(-1px);pointer-events:none;}
.ba .ba-knob{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:52px;height:52px;border-radius:50%;background:var(--sky);border:3px solid #fff;box-shadow:0 6px 20px rgba(0,6,20,.5);display:grid;place-content:center;}
.ba .ba-knob svg{width:26px;height:26px;color:var(--navy);}

/* =========================================================
   TREATMENT-STUDIES SCROLLER (Dan Parker style) — library module,
   reused via wireCarouselNav in site.js (not used on the mural, but
   available for Spurs 1901 etc.)
   ========================================================= */
.ts-wrap{margin-top:clamp(24px,3vw,48px);}
/* in-section carousel (not an off-page bleed like the homepage ones): exactly 3 cards fit the
   section width with no cut-offs, and it steps one clean card at a time. Because the cards fit
   exactly, every snap point is reachable, so mandatory snap pages cleanly without trapping. */
.ts-scroller{display:flex;gap:20px;overflow-x:auto;padding:6px 0 18px;scrollbar-width:none;scroll-snap-type:x mandatory;}
.ts-scroller::-webkit-scrollbar{display:none;}
.ts-card{flex:0 0 calc((100% - 40px)/3);scroll-snap-align:start;border-radius:16px;overflow:hidden;background:var(--proj-bg);aspect-ratio:4/5;position:relative;}
/* Below the 3-up breakpoint the scroller BLEEDS off the page like every other carousel on
   the site (Paul, 30 Sep): it escapes the section gutter with a negative margin and puts that
   gutter back as its own padding, so card 1 still lines up with the copy while the rest run
   off the screen edge. scroll-padding-left keeps wireCarouselNav landing on the right card.
   The desktop 3-up composition (exactly three, no cut-offs) is deliberately left alone. */
@media(max-width:900px){
  .ts-scroller{margin-inline:calc(var(--proj-gut) * -1);padding:6px var(--proj-gut) 18px;scroll-padding-left:var(--proj-gut);}
  .ts-card{flex-basis:calc((100% - 20px)/2);}
}
/* one card plus a peek of the next, so the bleed reads as "swipe for more" */
@media(max-width:560px){.ts-card{flex-basis:calc(100% - 34px);}}
.ts-card img{width:100%;height:100%;object-fit:cover;}
.ts-card .cap{position:absolute;left:16px;bottom:14px;font-family:'Palma Heavy',sans-serif;color:#fff;font-size:20px;text-shadow:0 2px 12px rgba(0,0,0,.5);}
.ts-controls{display:flex;gap:14px;margin-top:14px;}

/* =========================================================
   PROJECT SECTION LAYOUTS (6 Oct, Paul): "how many per row" for every image and
   media section, chosen per section in Edit Site > Projects. Driven ONLY by the
   data-cols / data-per attributes render.php prints (no inline layout, no JS).
   A section left on its default prints no attribute and no wrapper, so the
   signed-off pages are untouched. Rules: tablets (900px and under) at most 2 per
   row, phones (600px and under) 1 per row. The waterfall grid and the studies
   scroller keep their own existing breakpoints (820/520 and 900/560).
   ========================================================= */
/* image runs, side-by-side images (3+), before and after sliders, videos */
.proj-cols{--cols:2;display:grid;grid-template-columns:repeat(var(--cols),minmax(0,1fr));gap:clamp(14px,1.6vw,26px);align-items:start;}
.proj-cols[data-cols="3"]{--cols:3;}
.proj-cols[data-cols="4"]{--cols:4;}
/* each image whole (never cropped, never enlarged past its own size), centred in its column */
.proj-cols>.full{margin:0 auto;}
@media(max-width:900px){.proj-cols[data-cols="3"],.proj-cols[data-cols="4"]{--cols:2;}}
@media(max-width:600px){.proj-cols[data-cols]{--cols:1;}}
/* waterfall grid: 2 or 4 across on a desktop (3, the default, is the rule above) */
.proj-grid3[data-cols="2"]{grid-template-columns:repeat(2,1fr);}
.proj-grid3[data-cols="4"]{grid-template-columns:repeat(4,1fr);}
@media(max-width:820px){.proj-grid3[data-cols]{grid-template-columns:repeat(2,1fr);}}
@media(max-width:520px){.proj-grid3[data-cols]{grid-template-columns:1fr;}}
/* studies scroller: cards in view on a desktop (3, the default, is the rule above) */
@media(min-width:901px){
  .ts-wrap[data-per="2"] .ts-card{flex-basis:calc((100% - 20px)/2);}
  .ts-wrap[data-per="4"] .ts-card{flex-basis:calc((100% - 60px)/4);}
  .ts-wrap[data-per="5"] .ts-card{flex-basis:calc((100% - 80px)/5);}
}
/* before and after: the knob is the keyboard handle (app.js), so it shows where focus is */
.ba .ba-knob:focus{outline:none;}
.ba .ba-knob:focus-visible{outline:3px solid #fff;outline-offset:3px;}

/* =========================================================
   MIXED SHAPES IN A ROW (6 Oct, Paul): side-by-side images (other than the flush pair of
   two) and image runs with 2+ per row. Images in a row share ONE height and each takes
   width in proportion to its shape: never cropped, never drawn larger than its file
   (render.php b3x_proj_fit_rows() prints the sizes as --ar/--sd/--hd/--st/--ht/--hp and
   ends each row with .proj-br). Same row counts as before: tablets at most 2, phones 1.
   Each row is also kept within the fold, the same height cap as a single image.
   7 Oct (Paul): before and after sliders and videos set 2+ per row follow the same rule. A
   slider takes its after picture's shape (as a single slider always has), a video its still
   image's; the box gets that shape (aspect-ratio) and the pictures sit inside it whole.
   ========================================================= */
.proj-fit{display:flex;flex-wrap:wrap;justify-content:center;align-items:flex-start;--g:clamp(14px,1.6vw,26px);column-gap:var(--g);row-gap:0;margin-bottom:calc(var(--g) * -1);}
.proj-media .proj-fit>:is(.full,.ba,.proj-video){flex:0 0 auto;margin:0 0 var(--g);
  width:min(calc((100% - (var(--cols) - 1) * var(--g)) * var(--ar) / var(--sd) * .9999),calc(var(--fold) * var(--ar)),calc(var(--hd) * var(--ar) * 1px));}
.proj-media .proj-fit>.full.bleed{width:min(calc((100% - (var(--cols) - 1) * var(--g)) * var(--ar) / var(--sd) * .9999),calc(var(--hd) * var(--ar) * 1px));}
.proj-media .proj-fit>.full img{width:100%;height:auto;max-width:none;max-height:none;}
.proj-br{display:none;flex:0 0 100%;height:0;margin:0;padding:0;}
@media(min-width:901px){.proj-br--d{display:block;}}
@media(max-width:900px){
  .proj-media .proj-fit>:is(.full,.ba,.proj-video){width:min(calc((100% - (var(--cols) - 1) * var(--g)) * var(--ar) / var(--st) * .9999),calc(var(--fold) * var(--ar)),calc(var(--ht) * var(--ar) * 1px));}
  .proj-media .proj-fit>.full.bleed{width:min(calc((100% - (var(--cols) - 1) * var(--g)) * var(--ar) / var(--st) * .9999),calc(var(--ht) * var(--ar) * 1px));}
  .proj-br--t{display:block;}
}
@media(max-width:600px){
  .proj-fit{flex-direction:column;align-items:center;}
  .proj-media .proj-fit>:is(.full,.ba,.proj-video){width:min(100%,calc(var(--fold) * var(--ar)),calc(var(--hp) * var(--ar) * 1px));}
  .proj-media .proj-fit>.full.bleed{width:min(100%,calc(var(--hp) * var(--ar) * 1px));}
  .proj-br,.proj-br--t{display:none;}
}
.proj-media .proj-fit>.ba{aspect-ratio:var(--ar);}
.proj-media .proj-fit>.ba .ba-after{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;}
.proj-media .proj-fit>.proj-video video{width:100%;height:auto;aspect-ratio:var(--ar);max-width:none;max-height:none;object-fit:contain;}
/* a project slider whose before and after differ in shape (render.php prints .ba--fit): the before
   picture is fitted inside the slider whole (never cropped), centred on the page colour. Same-shape
   pairs (all the signed-off ones) get no class and look exactly as before. The Lab page is not touched. */
.proj-media .ba.ba--fit .ba-before{background:var(--proj-bg);}
body.proj-light .proj-media .ba.ba--fit .ba-before{background:#ffffff;}
.proj-media .ba.ba--fit .ba-before img{object-fit:contain;}

/* chevron nav buttons (shared) */
.b3xr-navbtn{width:54px;height:54px;border-radius:50%;border:1.6px solid rgba(255,255,255,.45);background:transparent;color:#fff;display:grid;place-content:center;cursor:pointer;transition:background .3s ease,border-color .3s ease,opacity .3s ease,transform .3s ease;padding:0;-webkit-tap-highlight-color:transparent;touch-action:manipulation;}
.b3xr-navbtn:hover{background:var(--sky);border-color:var(--sky);transform:translateY(-2px);}
.b3xr-navbtn svg{width:20px;height:20px;}
.b3xr-navbtn.off{opacity:.28;pointer-events:none;}
body.proj-light .b3xr-navbtn{border-color:rgba(11,18,32,.4);color:var(--navy);}
body.proj-light .b3xr-navbtn:hover{background:var(--sky);border-color:var(--sky);color:#fff;}

/* back-to-projects button within a project (Bex R1: make it a clear rounded button with an arrow
   back to the projects page — the old "More work / All projects" split read as two things) */
.proj-next{max-width:var(--proj-max,var(--max));margin-inline:auto;padding:clamp(30px,4vw,60px) var(--proj-gut) clamp(20px,4vw,60px);border-top:1px solid var(--proj-line);}
.proj-back{position:relative;isolation:isolate;display:inline-flex;align-items:center;gap:11px;text-decoration:none;
  font-family:'Safiro',sans-serif;font-weight:700;font-size:16px;letter-spacing:.01em;color:var(--proj-on);
  padding:14px 28px;border-radius:100px;border:1px solid var(--proj-line);background:rgba(255,255,255,.05);
  box-shadow:0 6px 22px rgba(0,10,30,.28);overflow:visible;
  transition:box-shadow .45s ease,transform .3s ease,border-color .3s ease;}
body.proj-light .proj-back{background:rgba(11,18,32,.04);}
/* hover = same as the other site buttons: keep the fill, draw the gradient line all the way round,
   soft glow, arrow nudges (here the arrow points back, so it nudges left) */
.proj-back:hover{transform:translateY(-2px);box-shadow:0 6px 22px rgba(0,10,30,.28),0 0 24px rgba(4,181,255,.4);}
.proj-back:hover .b3xr-btnline rect{stroke-dasharray:106 200;stroke-dashoffset:3;}
.proj-back .arw{display:inline-flex;transition:transform .3s ease;}
.proj-back:hover .arw{transform:translateX(-4px);}
.proj-back .arw svg{width:18px;height:18px;display:block;}

/* =========================================================
   CONTACT PAGE
   ========================================================= */
.contact{max-width:1200px;margin-inline:auto;padding:clamp(110px,15vw,150px) var(--side) clamp(60px,8vw,120px);}
/* form column wider than the text, with more space between them (Paul); still shrinks with the window */
.contact-grid{display:grid;grid-template-columns:0.85fr 1.15fr;gap:clamp(40px,6vw,100px);align-items:start;}
@media(max-width:820px){.contact-grid{grid-template-columns:1fr;gap:36px;}}
/* line-height .94 was too tight for Palma Heavy over two lines — descenders (the j/p in "project")
   touched the "i" dot on the line below and the j tail clipped; 1.08 gives the descenders room */
.contact h1{font-family:'Palma Heavy',sans-serif;color:#fff;font-size:clamp(44px,7vw,96px);line-height:1.08;margin:0 0 22px;}
.contact .sub{font-size:clamp(18px,1.6vw,22px);line-height:1.6;color:var(--muted);margin:0 0 28px;max-width:46ch;}
.contact .direct{font-family:'Aileron',sans-serif;font-weight:700;font-size:18px;}
.contact .direct a{color:var(--sky);text-decoration:none;}
.form-card{background:var(--glass);border:1px solid var(--line);border-radius:24px;padding:clamp(26px,3vw,44px);box-shadow:var(--shadow);-webkit-backdrop-filter:blur(8px) saturate(1.3);backdrop-filter:blur(8px) saturate(1.3);}
.field{margin-bottom:20px;}
.field label{display:block;font-family:'Aileron',sans-serif;font-weight:700;font-size:13px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);margin-bottom:8px;}
.field input,.field textarea{width:100%;font-family:'Aileron',sans-serif;font-size:16px;color:#fff;background:rgba(255,255,255,.04);border:1px solid var(--line);border-radius:12px;padding:14px 16px;transition:border-color .25s ease,background .25s ease;}
.field input:focus,.field textarea:focus{outline:none;border-color:var(--sky);background:rgba(4,181,255,.06);}
.field textarea{min-height:150px;resize:vertical;}
.form-note{font-size:13px;color:var(--muted);margin-top:10px;}
.form-ok{display:none;font-family:'Aileron',sans-serif;font-weight:700;color:var(--sky);margin-top:14px;}

/* =========================================================
   ABOUT PAGE
   ========================================================= */
/* top padding clears the fixed bar (page-top's top padding was being reset by this rule's
   shorthand, which dropped the hero under the bar) */
.about{max-width:var(--max);margin-inline:auto;padding:clamp(110px,15vw,150px) var(--side) clamp(50px,7vw,110px);}
.about-hero{display:grid;grid-template-columns:1.15fr .85fr;gap:clamp(30px,5vw,80px);align-items:center;}
@media(max-width:860px){.about-hero{grid-template-columns:1fr;gap:34px;}}
.about-hero h1{font-family:'Palma Heavy',sans-serif;color:#fff;font-size:clamp(44px,7vw,104px);line-height:.92;margin:0 0 24px;}
.about-hero p{font-size:clamp(18px,1.5vw,22px);line-height:1.62;color:var(--muted);margin:0 0 18px;max-width:56ch;}
.about-portrait{position:relative;border-radius:20px;overflow:hidden;aspect-ratio:3/4;background:var(--glass);border:1px solid var(--line);box-shadow:var(--shadow);}
.about-portrait img{width:100%;height:100%;object-fit:cover;}
.ph{display:grid;place-content:center;height:100%;text-align:center;padding:24px;color:var(--muted);gap:12px;}
.ph .ph-ic{width:64px;height:64px;border-radius:16px;border:1px solid rgba(4,181,255,.3);background:linear-gradient(155deg,rgba(4,181,255,.16),rgba(4,181,255,.05));display:grid;place-content:center;margin-inline:auto;color:var(--sky);}
.ph .ph-ic svg{width:34px;height:34px;}
.ph strong{color:#fff;font-family:'Aileron',sans-serif;font-weight:700;font-size:15px;letter-spacing:.02em;}
.ph span{font-size:13px;line-height:1.5;max-width:26ch;}
.about-graphic{margin-top:clamp(40px,6vw,90px);border-radius:20px;overflow:hidden;aspect-ratio:16/7;background:var(--glass);border:1px solid var(--line);box-shadow:var(--shadow);}
.about-graphic img{width:100%;height:100%;object-fit:cover;}

/* About — Why work with me + EAFA blocks (Bex R1: this content was missing) */
/* "Why should you work with me?" sits in a CENTRED frosted-glass panel, like the homepage FAQ box,
   with the heading + copy centre-aligned (Paul R1) */
.about-why{margin:clamp(50px,7vw,110px) auto 0;max-width:1180px;text-align:center;
  border-radius:28px;border:1px solid var(--line);background:var(--glass);
  box-shadow:var(--shadow);
  -webkit-backdrop-filter:blur(8px) saturate(1.3);backdrop-filter:blur(8px) saturate(1.3);
  padding:clamp(32px,4vw,60px);}
.about-why .sec-title{font-size:clamp(32px,4.4vw,56px);margin-bottom:clamp(20px,3vw,32px);}
.about-why-body p{font-size:clamp(17px,1.4vw,20px);line-height:1.7;color:var(--muted);margin:0 auto 18px;max-width:72ch;}
.about-why-body p:last-child{margin-bottom:0;}
.about-eafa{margin-top:clamp(50px,7vw,110px);}
.about-eafa-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(32px,5vw,72px);align-items:center;}
@media(max-width:860px){.about-eafa-grid{grid-template-columns:1fr;gap:30px;}}
.about-eafa-body .sec-title{font-size:clamp(30px,3.8vw,52px);line-height:1.04;margin:6px 0 22px;}
.about-eafa-body p{font-size:clamp(16px,1.3vw,19px);line-height:1.68;color:var(--muted);margin:0 0 16px;}
/* the Find Out More button was touching the last responsibility (the section's `p{margin-top:0}`
   was overriding .mt-cta) — give it proper breathing room below the list */
.about-eafa-body .mt-cta{margin-top:clamp(32px,4vw,54px) !important;margin-bottom:0;}
.about-points-lead{font-weight:700;color:var(--ink) !important;margin-top:22px !important;}
.about-points{list-style:none;margin:6px 0 0;padding:0;display:grid;gap:11px;}
.about-points li{position:relative;padding-left:24px;font-family:'Aileron',sans-serif;font-size:16px;line-height:1.5;color:var(--muted);}
.about-points li::before{content:"";position:absolute;left:2px;top:9px;width:7px;height:7px;border-radius:50%;background:var(--sky);}
/* aspect = Bex's EAFA Brand Cover (1920x1243) so nothing is cropped: it is a brand grid with
   artwork and photos running right to the edges (was a 4:3 placeholder box, 2 Oct) */
.about-eafa-graphic{border-radius:20px;overflow:hidden;aspect-ratio:1920/1243;background:var(--glass);border:1px solid var(--line);box-shadow:var(--shadow);}
.about-eafa-graphic img{width:100%;height:100%;object-fit:cover;}

/* =========================================================
   THE LAB — personal work: hero + static gallery + auto-scroll 4:5 rows
   (Bex's brief: remove the old top scrolling-graphics banner; add 1-2
   auto-advance draggable 4:5 rows to break up the statics; keep adding
   work in sections. Reference: dbanart.com/thelab)
   ========================================================= */
.lab-hero{max-width:var(--max);margin-inline:auto;padding-left:var(--side);padding-right:var(--side);padding-bottom:clamp(30px,4vw,56px);}
.lab-hero .b3xr-kick{margin-bottom:10px;}
.lab-hero h1{font-family:'Palma Heavy',sans-serif;color:#fff;font-size:clamp(56px,12vw,150px);line-height:.9;margin:0 0 22px;letter-spacing:-.01em;}
.lab-hero .lede{max-width:60ch;}
.lab-hero .lede+.lede{margin-top:14px;font-family:'Palma Heavy',sans-serif;color:var(--sky);font-size:clamp(19px,1.7vw,26px);}

.lab-section{max-width:var(--max);margin-inline:auto;padding:clamp(16px,2vw,30px) var(--side);}
.lab-lbl{font-family:'Aileron',sans-serif;font-weight:700;text-transform:uppercase;letter-spacing:.16em;font-size:12px;color:var(--sky);margin:0 0 clamp(14px,1.6vw,22px);}

/* top gallery = the four pieces in one row across the full CONTENT width, fading in one
   after another on load. Unlike the carousels below, this row keeps the site gutter and
   stops at it — it does not bleed off the page. The SECTION keeps .reveal so site.js
   still flips .in on it, but its own fade is cancelled here: the stagger belongs to the
   images, not the block. */
.lab-four-sec{max-width:var(--max);margin-inline:auto;padding:clamp(16px,2vw,30px) var(--side);}
.lab-four{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:clamp(12px,1.3vw,22px);}
.lab-four>.lab-four-cell>img{width:100%;aspect-ratio:4/5;object-fit:cover;display:block;border-radius:14px;background:#0a1c3d;}
@media(max-width:900px){.lab-four{grid-template-columns:repeat(2,minmax(0,1fr));}}
/* b3x-core: each image sits in a .lab-four-cell (the editable gallery row) */
.lab-four>.lab-four-cell{min-width:0;}
html.reveal-on .lab-four-sec.reveal{opacity:1;transform:none;}
html.reveal-on .lab-four>.lab-four-cell>img{opacity:0;transform:translateY(22px);}
html.reveal-on .lab-four-sec.in .lab-four>.lab-four-cell>img{opacity:1;transform:none;
  transition:opacity .85s cubic-bezier(.16,1,.3,1),transform .85s cubic-bezier(.16,1,.3,1);}
html.reveal-on .lab-four-sec.in .lab-four>.lab-four-cell:nth-child(2)>img{transition-delay:.14s;}
html.reveal-on .lab-four-sec.in .lab-four>.lab-four-cell:nth-child(3)>img{transition-delay:.28s;}
html.reveal-on .lab-four-sec.in .lab-four>.lab-four-cell:nth-child(4)>img{transition-delay:.42s;}
@media(prefers-reduced-motion:reduce){html.reveal-on .lab-four>.lab-four-cell>img{opacity:1;transform:none;}}

/* Lab carousel — full-bleed like the homepage Featured scroller: card 1 aligns to the content
   column, cards run off the RIGHT at rest and off the LEFT as you scroll; chevrons bottom-left;
   drag with the custom B-lettermark cursor (see below). */
.lab-carousel{width:100%;padding:clamp(18px,2.4vw,34px) 0;}
.lab-carousel>.lab-lbl{padding-left:var(--cap);padding-right:var(--side);margin:0 0 clamp(14px,1.6vw,22px);}
.lab-row{box-sizing:border-box;display:flex;gap:22px;overflow-x:auto;scroll-snap-type:x mandatory;
  scroll-padding-left:var(--cap);cursor:grab;width:100%;
  padding:8px var(--side) 20px var(--cap);scrollbar-width:none;-ms-overflow-style:none;overscroll-behavior-x:contain;}
.lab-row::-webkit-scrollbar{display:none;}
.lab-row.drag{cursor:grabbing;scroll-snap-type:none;}
.lab-row.drag *{pointer-events:none;}
/* cards are generously wide (like the homepage Featured cards) so the strip always overflows the
   viewport and bleeds off-page — a few big cards in view, the rest running off the right/left. */
.lab-card{scroll-snap-align:start;flex:0 0 clamp(300px,34vw,460px);aspect-ratio:4/5;
  border-radius:16px;overflow:hidden;position:relative;background:#0a1c3d;}
.lab-card img{width:100%;height:100%;object-fit:cover;transition:transform .8s cubic-bezier(.16,1,.3,1);}
@media(hover:hover){.lab-card:hover img{transform:scale(1.04);}}
.lab-controls{display:flex;gap:14px;margin-top:clamp(16px,2vw,26px);padding-left:var(--cap);}

/* carousel rows fade in the first time they reach the viewport: label first, then the cards
   one after another, then the arrows. The card delays are written by lab.js in VISUAL
   left-to-right order, never DOM order — a drifting row is often showing clones rather than
   the originals, so nth-child would stagger cards nobody can see. The hide rule is gated on
   .lab-stagger, which lab.js itself adds, so if lab.js ever fails the cards stay visible. */
html.reveal-on .lab-carousel.reveal{opacity:1;transform:none;}
html.reveal-on .lab-carousel>.lab-lbl,
html.reveal-on .lab-carousel>.lab-controls{opacity:0;transform:translateY(18px);}
html.reveal-on .lab-carousel.in>.lab-lbl,
html.reveal-on .lab-carousel.in>.lab-controls{opacity:1;transform:none;
  transition:opacity .8s cubic-bezier(.16,1,.3,1),transform .8s cubic-bezier(.16,1,.3,1);}
html.reveal-on .lab-carousel.in>.lab-controls{transition-delay:.3s;}
html.reveal-on .lab-carousel.lab-stagger .lab-card{opacity:0;transform:translateY(18px);}
html.reveal-on .lab-carousel.lab-stagger.cards-in .lab-card{opacity:1;transform:none;
  transition:opacity .8s cubic-bezier(.16,1,.3,1),transform .8s cubic-bezier(.16,1,.3,1);}
@media(prefers-reduced-motion:reduce){
  html.reveal-on .lab-carousel.lab-stagger .lab-card,
  html.reveal-on .lab-carousel>.lab-lbl,
  html.reveal-on .lab-carousel>.lab-controls{opacity:1;transform:none;}}

/* custom draggable cursor over the Lab carousels (ported from the homepage): a ring that shows
   two chevrons + a "Drag" label on hover, and fills sky with the B lettermark when you grab. */
.b3xr-nocur,.b3xr-nocur *{cursor:none !important;}
.b3xr-cursor{position:fixed;left:0;top:0;width:84px;height:84px;border-radius:50%;pointer-events:none;z-index:99999;
  display:grid;place-items:center;opacity:0;border:1.5px solid rgba(255,255,255,.9);color:#fff;background:rgba(4,181,255,0);
  transition:opacity .28s ease,background .28s ease,border-color .28s ease,color .28s ease;
  font-family:'Aileron',sans-serif;font-size:11px;font-weight:700;letter-spacing:.18em;text-transform:uppercase;will-change:transform;}
.b3xr-cursor.show{opacity:1;}
.b3xr-cursor.grab{background:#04b5ff;border-color:#04b5ff;color:#031b3d;}
.b3xr-cursor .chev{position:absolute;left:50%;top:50%;width:13px;height:13px;color:#fff;transform:translate(calc(-50% + var(--cx)),-50%);transition:transform .32s cubic-bezier(.16,1,.3,1),color .28s ease;}
.b3xr-cursor .chev svg{width:100%;height:100%;display:block;}
.b3xr-cursor .chev.l{--cx:-15px;} .b3xr-cursor .chev.r{--cx:15px;}
.b3xr-cursor .bmark{position:absolute;left:50%;top:50%;width:52px;height:auto;opacity:0;transform:translate(-50%,-50%) scale(.4);transition:transform .32s cubic-bezier(.16,1,.3,1),opacity .25s ease;}
.b3xr-cursor .lab{position:absolute;bottom:-22px;left:50%;transform:translateX(-50%);font-size:9px;letter-spacing:.22em;opacity:.85;white-space:nowrap;transition:opacity .2s ease;}
.b3xr-cursor.grab .bmark{opacity:1;transform:translate(-50%,-50%) scale(1);}
.b3xr-cursor.grab .chev.l{--cx:-52px;} .b3xr-cursor.grab .chev.r{--cx:52px;} .b3xr-cursor.grab .lab{opacity:0;}

/* the Lab before/afters reuse the shared .ba slider, sat side by side and centred
   directly under the NBA row. They stack below 760px, where two would be too small to drag. */
.lab-ba-pair{max-width:var(--max);margin-inline:auto;padding:clamp(16px,2vw,30px) var(--side);}
.lab-ba-pair>.lab-lbl{text-align:center;}
.ba-duo{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:clamp(16px,2vw,32px);max-width:1180px;margin-inline:auto;align-items:start;}
.ba-duo .ba{width:100%;aspect-ratio:4/5;}
.ba-duo .ba .ba-after{position:absolute;inset:0;z-index:1;}
@media(max-width:760px){.ba-duo{grid-template-columns:1fr;max-width:560px;}}

/* A forced line break is a DESKTOP composition choice only. Below 1025px the heading
   wraps wherever it naturally falls, so a phone never gets an orphaned word on its own
   line. Mark EVERY deliberate <br> with this class (Paul, 30 Sep). */
@media(max-width:1024px){.br-desk{display:none;}}

/* small utility */
.center{text-align:center;}
.nowrap{white-space:nowrap;}
.mt-cta{margin-top:clamp(28px,4vw,50px);}


/* =====================================================================
   3. b3x-core ADDITIONS (stream B, 5 Oct 2026). Everything below exists only
   because the pages are now engine partials with editable fields; none of it
   changes how the approved design looks.
   ===================================================================== */

/* ---- one editable text column holding several paragraphs ----
   A rich field is ONE element, and kses only keeps inline tags, so a run of
   <p>s becomes one <div> rich field whose paragraphs are <span class="b3x-p">
   blocks. Each span carries the exact typography + spacing the original <p>
   had, so the default renders identically (margins still collapse into the
   next element). A client's Enter inserts a <br> as on every AW build. */
.b3x-p{display:block;}
/* About hero intro (was .about-hero p) */
.about-hero .about-hero-copy,
.about-hero .about-hero-copy .b3x-p{font-size:clamp(18px,1.5vw,22px);line-height:1.62;color:var(--muted);max-width:56ch;}
.about-hero .about-hero-copy .b3x-p{margin:0 0 18px;}
/* Why work with me (was .about-why-body p) */
.about-why-body{font-size:clamp(17px,1.4vw,20px);line-height:1.7;color:var(--muted);}
.about-why-body .b3x-p{font-size:clamp(17px,1.4vw,20px);line-height:1.7;color:var(--muted);margin:0 auto 18px;max-width:72ch;}
.about-why-body .b3x-p:last-child{margin-bottom:0;}
/* EAFA body (was .about-eafa-body p) */
.about-eafa-copy,
.about-eafa-copy .b3x-p{font-size:clamp(16px,1.3vw,19px);line-height:1.68;color:var(--muted);}
.about-eafa-copy .b3x-p{margin:0 0 16px;}

/* ---- hidden per-row alt text (data-alt-sub) ----
   Gallery rows carry their alt as a hidden text sub so each image keeps its own
   alt (a list template would otherwise freeze row 1's alt onto every row).
   [hidden] keeps it off the public page; in the editor the engine swaps it for an
   input, lifted here above the image layers so it can be reached. */
html.static .lab-card .cc-hidden-edit,
html.static .lab-four-cell .cc-hidden-edit,
html.static .ba .cc-hidden-edit{position:relative;z-index:6;display:block;margin:6px;}

/* ---- Contact: the engine lead form, dressed as the approved form ----
   forms.php prints its own <style> AFTER this file (.ccform input.inp etc, some
   at 0,3,1), so every override here is scoped .form-card .ccform … to win. */
.form-card .ccform .field input.inp,
.form-card .ccform .field textarea.inp{width:100%;height:auto;font-family:'Aileron',sans-serif;font-size:16px;line-height:normal;color:#fff;
  background:rgba(255,255,255,.04);border:1px solid var(--line);border-radius:12px;padding:14px 16px;outline:none;
  -webkit-appearance:auto;appearance:auto;transition:border-color .25s ease,background .25s ease;}
.form-card .ccform .field textarea.inp{min-height:150px;resize:vertical;}
.form-card .ccform .field input.inp:focus,
.form-card .ccform .field textarea.inp:focus{outline:none;border-color:var(--sky);background:rgba(4,181,255,.06);}
/* the submit row: the approved button sat straight under the last field, not
   full width, not in a .field of its own */
.form-card .ccform>.field:last-child{margin-bottom:0;}
.form-card .ccform button.btn{position:relative;isolation:isolate;display:inline-flex;align-items:center;gap:9px;
  width:auto!important;justify-content:flex-start!important;
  font-family:'Safiro',sans-serif;font-weight:700;font-size:16px;color:#fff;text-transform:capitalize;letter-spacing:.02em;
  text-decoration:none;padding:14px 30px;border-radius:100px;background:var(--navy);border:1px solid rgba(4,181,255,.5);
  box-shadow:0 6px 22px rgba(0,10,30,.42);transition:box-shadow .45s ease;overflow:visible;cursor:pointer;line-height:1;}
.form-card .ccform button.btn:hover{color:#fff;box-shadow:0 6px 22px rgba(0,10,30,.42),0 0 24px rgba(4,181,255,.4);}
.form-card .ccform button.btn:disabled{cursor:default;}
/* success / error line = the approved .form-ok */
.form-card .ccform-msg{margin:14px 0 16px;padding:0;border:0;background:none;font-family:'Aileron',sans-serif;font-weight:700;font-size:16px;line-height:normal;color:var(--sky);}
.form-card .ccform-msg.ok{border:0;background:none;}
.form-card .ccform-msg.err{border:0;background:none;color:#fff;}
.form-card .ccform-msg.ok.show~.form-note{display:none;}

/* ---- editor format bar (brief: highlights / text_colours / font_choices) ----
   Spans the client applies from the toolbar. Scoped with the engine's base
   markers (hl / tc / ff) so nothing else on the site picks them up. */
.hl.b3x-hl{color:var(--sky);}
.tc.tc-sky{color:#04b5ff;}
.tc.tc-white{color:#ffffff;}
.tc.tc-muted{color:rgba(255,255,255,.72);}
.tc.tc-navy{color:#031b3d;}
.ff.ff-palma{font-family:'Palma Heavy',sans-serif;font-weight:400;}
.ff.ff-safiro{font-family:'Safiro',sans-serif;font-weight:700;}
.ff.ff-aileron{font-family:'Aileron',sans-serif;}

/* ---- AW credit ----
   The footer carries the credit inline (CC_AW_CREDIT_INLINE in inc/chrome.php),
   so the engine strip is not printed. If it ever is, it blends into the page
   under the floating footer instead of reading as a separate band. */
.cc-aw-credit{background:transparent;color:var(--muted);}

/* =====================================================================
   EDITOR (html.static, added by the engine in edit mode): freeze every motion,
   force every reveal, and keep the chrome out of the editor toolbar's way.
   app.js also skips the reveal observer, the floating bar, the Lab marquee
   (its clones would be saved as extra rows), the blueprint etch + sparks, the
   before/after drag and project video autoplay when html.static is set.
   ===================================================================== */
html.static{scroll-behavior:auto;}
html.static .reveal,
html.static .reveal.in,
html.static .lab-four>.lab-four-cell>img,
html.static .lab-carousel>.lab-lbl,
html.static .lab-carousel>.lab-controls,
html.static .lab-card{opacity:1!important;transform:none!important;transition:none!important;}
html.static .b3xbp-grad{animation:none!important;}
html.static .b3xbp-line{stroke-dasharray:none!important;stroke-dashoffset:0!important;}
html.static .b3xbp-spark{display:none!important;}
html.static .b3xr-btnline rect,
html.static .b3xr-btnarrow,
html.static .lab-card img{transition:none!important;}
/* (the header's editor rules are in chrome.css) */
/* Lab rows: no drift in the editor, so wrap them and every card is on screen to click */
html.static .lab-row{flex-wrap:wrap;overflow:visible;scroll-snap-type:none;cursor:auto;padding-right:var(--side);}
html.static .lab-card{flex:0 0 clamp(160px,16vw,240px);}

/* =========================================================
   EDITOR CHIPS (Edit Site only; Paul 6 Oct): "Replace photo of Bex", "Replace logo", the URL chip,
   list add / row buttons. The engine draws them as dark chips, but the page's own button reset
   (Hello's `button{color:#c36;border:1px solid #c36}`, pink fill on hover) out-ranked them, so
   they showed pink outline + pink text, then a pink block on hover. Branded narrow pills instead:
   navy glass, white text, sky edge; sky fill + navy text on hover / keyboard focus.
   ========================================================= */
body.cc-editing :is(.cc-img-fab,.cc-link-chip,.cc-list-add,.cc-row-btn,.cc-hidden-edit,.cc-marquee-edit){
  background:rgba(2,19,44,.88);color:#fff;border:1px solid rgba(4,181,255,.6);border-radius:100px;
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);box-shadow:0 6px 18px rgba(0,6,20,.45);
  font:600 12px/1 'Aileron',-apple-system,'Segoe UI',sans-serif;letter-spacing:.01em;text-transform:none;text-decoration:none;}
body.cc-editing .cc-img-fab{padding:7px 12px 7px 10px;}
body.cc-editing .cc-img-fab b{color:#04b5ff;font-style:normal;margin-right:2px;}
body.cc-editing .cc-link-chip{padding:5px 9px;font-size:10px;letter-spacing:.08em;}
body.cc-editing :is(.cc-img-fab,.cc-link-chip,.cc-list-add,.cc-row-btn,.cc-hidden-edit,.cc-marquee-edit):is(:hover,:focus-visible){
  background:#04b5ff;color:#02132c;border-color:#04b5ff;}
body.cc-editing .cc-img-fab:is(:hover,:focus-visible) b{color:#02132c;}
body.cc-editing :is(.cc-img-fab,.cc-link-chip,.cc-list-add,.cc-row-btn,.cc-hidden-edit,.cc-marquee-edit):focus-visible{outline:2px solid #fff;outline-offset:2px;}

/* Edit Site toolbar Update button (6 Oct): the engine paints it var(--cc-red) = brand blue #0474FF, white text 4.2:1
   (fails AA). Same deeper blue as the project builder: 5.3:1 at rest, darker on hover/press. Edit mode only. */
body.cc-editing .cc-btn.primary{background:#0066e0;border-color:#0066e0;color:#fff;}
body.cc-editing .cc-btn.primary:not([disabled]):hover{background:#0057bf;border-color:#0057bf;color:#fff;}
body.cc-editing .cc-btn.primary:not([disabled]):active{background:#004aa3;border-color:#004aa3;color:#fff;}

/* QA 13-10-26: footer policy links were a 15px tap target. Grown to 44px on
   touch only, so the desktop footer height is unchanged. */
@media (pointer:coarse){
  .foot-policies{gap:0 26px;}
  .foot-policies a{display:inline-flex;align-items:center;min-height:44px;}
}
