@charset "UTF-8";
/* ==========================================================================
   AJNA Asset Management Services — design system
   --------------------------------------------------------------------------
   One stylesheet for the whole site. No framework, no icon font: layout is
   CSS grid, icons are an inline SVG sprite, motion is CSS transforms and
   opacity only so it stays on the compositor.

   Contents
     01  Tokens
     02  Reset & base
     03  Typography & primitives
     04  Buttons
     05  Reveal on scroll
     06  Header & navigation
     07  Hero
     08  About
     09  Services
     10  Service & hero graphics
     11  Gallery & lightbox
     12  Contact
     13  Footer
     14  Legal pages
     15  Reduced motion & print
   ========================================================================== */

/* 01  Tokens ============================================================== */

:root {
  /* brand — taken from the AJNA mark: the blue and green of the third eye */
  --brand: #2f80ed;
  --brand-2: #14dd73;
  --brand-deep: #1b62c4;
  --grad: linear-gradient(135deg, #2f80ed 0%, #14dd73 100%);
  --grad-soft: linear-gradient(135deg, rgba(47, 128, 237, .12), rgba(20, 221, 115, .12));

  /* ink */
  --ink: #0a1120;
  --ink-2: #101a2c;
  --ink-3: #17233a;

  /* surfaces */
  --paper: #ffffff;
  --paper-2: #f4f7fb;
  --paper-3: #e9eff7;

  /* text on light */
  --text: #101828;
  --text-2: #475467;
  --text-3: #6b7789;
  --line: #e4eaf2;
  --card: #ffffff;
  --card-line: #e8edf5;

  /* metrics */
  --wrap: 1240px;
  --gutter: clamp(20px, 5vw, 56px);
  --head-h: 78px;
  --r-sm: 12px;
  --r: 18px;
  --r-lg: 26px;
  /* Structural ink inside the scene drawings, as channels so each use
     keeps its own alpha. .tone-dark flips it to white, which is what
     lets one set of scenes read on paper and on ink. */
  --sc-ink: 16, 33, 60;

  --shadow-sm: 0 2px 10px rgba(16, 33, 60, .05);
  --shadow: 0 18px 44px -22px rgba(16, 33, 60, .28);
  --shadow-lg: 0 40px 90px -40px rgba(16, 33, 60, .42);

  --ease: cubic-bezier(.22, .68, .32, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);

  --font-display: "Sora", "Josefin Sans", system-ui, sans-serif;
  --font-body: "Inter", "Commissioner", system-ui, -apple-system, "Segoe UI", sans-serif;
}

/* Dark surfaces re-point the same tokens, so every component below works on
   light and dark without a second set of rules. */
.tone-dark {
  --sc-ink: 255, 255, 255;
  --text: #ffffff;
  --text-2: rgba(255, 255, 255, .72);
  --text-3: rgba(255, 255, 255, .55);
  --line: rgba(255, 255, 255, .12);
  --card: rgba(255, 255, 255, .045);
  --card-line: rgba(255, 255, 255, .1);
  --paper-2: rgba(255, 255, 255, .045);
  color: var(--text-2);
}

/* 02  Reset & base ======================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--head-h) + 16px);
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--text-2);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.7;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

body.is-locked { overflow: hidden; }

img, svg, video { display: block; max-width: 100%; }
img { height: auto; }

a { color: var(--brand); text-decoration: none; transition: color .25s var(--ease); }
a:hover { color: var(--brand-deep); }

button { font: inherit; color: inherit; border: 0; background: none; cursor: pointer; }
input, textarea, select { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 3px;
  border-radius: 4px;
}

::selection { background: rgba(47, 128, 237, .18); }

.aj-skip {
  position: absolute;
  left: 16px;
  top: -60px;
  z-index: 200;
  padding: 12px 20px;
  border-radius: 0 0 10px 10px;
  background: var(--ink);
  color: #fff;
  transition: top .2s var(--ease);
}
.aj-skip:focus { top: 0; color: #fff; }

.aj-sr {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

.aj-icon {
  width: 1.15em;
  height: 1.15em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex: none;
}

/* 03  Typography & primitives ============================================ */

h1, h2, h3, h4 {
  margin: 0;
  font-family: var(--font-display);
  color: var(--text);
  font-weight: 600;
  line-height: 1.14;
  letter-spacing: -.02em;
}

h1 { font-size: clamp(2.05rem, 1.3rem + 2vw, 2.85rem); line-height: 1.08; letter-spacing: -.03em; }
h2 { font-size: clamp(1.95rem, 1.3rem + 2.4vw, 2.6rem); letter-spacing: -.03em; }
h3 { font-size: clamp(1.3rem, 1.1rem + .7vw, 1.7rem); }
h4 { font-size: 1.06rem; letter-spacing: -.01em; }

p { margin: 0 0 1.15em; }
p:last-child { margin-bottom: 0; }

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.wrap-wide { max-width: 1420px; }

.sec { position: relative; padding-block: clamp(76px, 8.5vw, 138px); }
.sec--tint { background: var(--paper-2); }
.sec--dark { background: var(--ink); }
.sec--flush-t { padding-top: clamp(48px, 5vw, 82px); }

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 18px;
  font-family: var(--font-body);
  font-size: .74rem;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--brand);
}
.eyebrow::before {
  content: "";
  width: 26px;
  height: 2px;
  border-radius: 2px;
  background: var(--grad);
}
.tone-dark .eyebrow { color: var(--brand-2); }

.lead { font-size: clamp(1.02rem, .98rem + .3vw, 1.16rem); color: var(--text-2); }

.sec-head { max-width: 720px; margin-bottom: clamp(40px, 4.5vw, 68px); }
.sec-head--center { margin-inline: auto; text-align: center; }
.sec-head--center .eyebrow::before { display: none; }
.sec-head h2 + p { margin-top: 18px; }

.rule {
  height: 1px;
  border: 0;
  margin: 0;
  background: var(--line);
}

/* 04  Buttons ============================================================= */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 15px 27px;
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: .93rem;
  font-weight: 600;
  letter-spacing: .01em;
  line-height: 1;
  white-space: nowrap;
  position: relative;
  isolation: isolate;
  transition: transform .3s var(--ease), box-shadow .3s var(--ease), background-color .3s var(--ease), color .3s var(--ease), border-color .3s var(--ease);
}
.btn .aj-icon { width: 1.05em; height: 1.05em; transition: transform .35s var(--ease); }
.btn:hover .aj-icon { transform: translateX(4px); }
.btn:active { transform: translateY(1px); }

.btn--primary {
  background: var(--grad);
  background-size: 160% 160%;
  color: #fff;
  box-shadow: 0 14px 30px -14px rgba(47, 128, 237, .75);
}
.btn--primary:hover {
  color: #fff;
  background-position: 100% 0;
  transform: translateY(-2px);
  box-shadow: 0 20px 38px -14px rgba(20, 221, 115, .6);
}

.btn--ghost {
  border: 1px solid var(--line);
  color: var(--text);
  background: var(--card);
}
.btn--ghost:hover {
  color: var(--text);
  border-color: transparent;
  transform: translateY(-2px);
  box-shadow: var(--shadow);
}

.btn--onDark {
  border: 1px solid rgba(255, 255, 255, .28);
  color: #fff;
  background: var(--grad);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.btn--onDark:hover {
  color: #fff;
  background: rgba(255, 255, 255, .14);
  border-color: rgba(255, 255, 255, .5);
  transform: translateY(-2px);
}

.btn--sm { padding: 11px 20px; font-size: .86rem; }

.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  font-size: .93rem;
  color: var(--brand);
}
.link-arrow .aj-icon { transition: transform .35s var(--ease); }
.link-arrow:hover .aj-icon { transform: translateX(5px); }

/* 05  Reveal on scroll ==================================================== */

/* Applied only when JS is running, so the page is complete without it. */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity .85s var(--ease-out), transform .85s var(--ease-out);
  transition-delay: var(--d, 0s);
  will-change: opacity, transform;
}
.js [data-reveal="left"]  { transform: translateX(-34px); }
.js [data-reveal="right"] { transform: translateX(34px); }
.js [data-reveal="scale"] { transform: scale(.955); }
.js [data-reveal].is-in {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* 06  Header & navigation ================================================ */

.aj-header {
  position: fixed;
  inset: 0 0 auto;
  z-index: 100;
  height: var(--head-h);
  display: flex;
  align-items: center;
  transition: background-color .35s var(--ease), box-shadow .35s var(--ease), height .35s var(--ease);
}
/* The solid bar is the default. Sitting transparent over a dark hero is the
   exception, and it is only safe where JavaScript can bring the solid bar
   back on scroll — hence the .js gate on every knock-out rule below. */
.aj-header::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgba(255, 255, 255, .86);
  backdrop-filter: saturate(160%) blur(14px);
  -webkit-backdrop-filter: saturate(160%) blur(14px);
  border-bottom: 1px solid var(--line);
  opacity: 1;
  transition: opacity .35s var(--ease);
}
.js .has-hero .aj-header:not(.is-solid)::after { opacity: 0; }
.aj-header.is-solid { height: 68px; }

.aj-header .wrap {
  display: flex;
  align-items: center;
  gap: clamp(14px, 2vw, 30px);
  max-width: 1420px;
}

.aj-brand { display: flex; align-items: center; gap: 12px; margin-right: auto; }
.aj-brand img { height: 46px; width: auto; transition: height .35s var(--ease); }
.aj-header.is-solid .aj-brand img { height: 30px; }
.aj-brand-mark { height: 34px; width: auto; }

.aj-brand-word { transition: filter .35s var(--ease); }
.js .has-hero .aj-header:not(.is-solid) .aj-brand-word { filter: brightness(0) invert(1); }

.aj-nav { display: flex; align-items: center; }
.aj-nav ul {
  display: flex;
  align-items: center;
  gap: clamp(4px, 1.4vw, 22px);
  margin: 0;
  padding: 0;
  list-style: none;
}
.aj-nav a {
  position: relative;
  display: block;
  padding: 9px 4px;
  font-size: .93rem;
  font-weight: 500;
  color: var(--text-2);
  transition: color .25s var(--ease);
}
.aj-nav a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 2px;
  width: 100%;
  height: 2px;
  border-radius: 2px;
  background: var(--grad);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .4s var(--ease);
}
.aj-nav a:hover::after, .aj-nav li.is-active a::after { transform: scaleX(1); }
.aj-nav a:hover, .aj-nav a:focus-visible, .aj-nav li.is-active a { color: var(--text); }

.js .has-hero .aj-header:not(.is-solid) .aj-nav a { color: rgba(255, 255, 255, .82); }
.js .has-hero .aj-header:not(.is-solid) .aj-nav a:hover,
.js .has-hero .aj-header:not(.is-solid) .aj-nav a:focus-visible,
.js .has-hero .aj-header:not(.is-solid) .aj-nav li.is-active a { color: #fff; }

.aj-header-cta { display: flex; align-items: center; gap: 10px; }

.aj-burger {
  display: none;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line);
  color: var(--text);
}
.js .has-hero .aj-header:not(.is-solid) .aj-burger { border-color: rgba(255, 255, 255, .28); color: #fff; }
.aj-burger i {
  position: relative;
  width: 18px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transition: background-color .2s var(--ease);
}
.aj-burger i::before, .aj-burger i::after {
  content: "";
  position: absolute;
  left: 0;
  width: 18px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transition: transform .35s var(--ease);
}
.aj-burger i::before { top: -6px; }
.aj-burger i::after { top: 6px; }
.aj-burger[aria-expanded="true"] i { background: transparent; }
.aj-burger[aria-expanded="true"] i::before { transform: translateY(6px) rotate(45deg); }
.aj-burger[aria-expanded="true"] i::after { transform: translateY(-6px) rotate(-45deg); }

/* mobile panel */
.aj-mobile {
  position: fixed;
  inset: 0;
  z-index: 99;
  display: grid;
  align-content: center;
  padding: calc(var(--head-h) + 24px) var(--gutter) 40px;
  background: var(--ink);
  visibility: hidden;
  opacity: 0;
  transition: opacity .4s var(--ease), visibility .4s;
}
.aj-mobile.is-open { visibility: visible; opacity: 1; }
.aj-mobile-bg {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(60% 50% at 80% 12%, rgba(47, 128, 237, .3), transparent 70%),
    radial-gradient(50% 44% at 12% 88%, rgba(20, 221, 115, .22), transparent 70%);
  pointer-events: none;
}
.aj-mobile ul { position: relative; margin: 0; padding: 0; list-style: none; }
.aj-mobile li { border-bottom: 1px solid rgba(255, 255, 255, .1); }
.aj-mobile a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 2px;
  font-family: var(--font-display);
  font-size: 1.6rem;
  font-weight: 500;
  letter-spacing: -.02em;
  color: #fff;
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .5s var(--ease-out), transform .5s var(--ease-out), color .25s;
}
.aj-mobile a .aj-icon { color: var(--brand-2); opacity: .55; }
.aj-mobile a:hover { color: var(--brand-2); }
.aj-mobile.is-open a { opacity: 1; transform: none; transition-delay: calc(.08s + var(--i, 0) * .06s); }
.aj-mobile-foot {
  position: relative;
  margin-top: 30px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

@media (max-width: 979px) {
  .aj-nav, .aj-header-cta .btn { display: none; }
  .aj-burger { display: inline-flex; }
}

/* 07  Hero =============================================================== */

.aj-hero {
  position: relative;
  isolation: isolate;
  min-height: 100svh;
  display: grid;
  align-items: center;
  padding-top: calc(var(--head-h) + clamp(22px, 3.4vw, 44px));
  padding-bottom: clamp(22px, 3.4vw, 44px);
  background: var(--ink);
  overflow: hidden;
}

.aj-hero-bg { position: absolute; inset: 0; z-index: -3; }
.aj-hero-bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: .42;
  transform: scale(1.06);
  animation: heroDrift 26s var(--ease) infinite alternate;
}
@keyframes heroDrift {
  from { transform: scale(1.06) translate3d(0, 0, 0); }
  to   { transform: scale(1.14) translate3d(-1.6%, -1.4%, 0); }
}
.aj-hero-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(10, 17, 32, .88) 0%, rgba(10, 17, 32, .6) 45%, rgba(10, 17, 32, .97) 100%),
    linear-gradient(100deg, rgba(10, 17, 32, .94) 8%, rgba(10, 17, 32, .22) 58%);
}

.aj-hero-glow {
  position: absolute;
  z-index: -2;
  border-radius: 50%;
  filter: blur(70px);
  pointer-events: none;
  opacity: .5;
}
.aj-hero-glow--a { width: 46vw; height: 46vw; top: -12vw; right: -8vw; background: rgba(47, 128, 237, .5); animation: glowA 16s var(--ease) infinite alternate; }
.aj-hero-glow--b { width: 34vw; height: 34vw; bottom: -10vw; left: -6vw; background: rgba(20, 221, 115, .34); animation: glowB 19s var(--ease) infinite alternate; }
@keyframes glowA { to { transform: translate3d(-4%, 6%, 0) scale(1.12); } }
@keyframes glowB { to { transform: translate3d(6%, -5%, 0) scale(1.1); } }

.aj-hero .wrap {
  position: relative;
  display: grid;
  gap: clamp(46px, 6vw, 80px);
  align-items: center;
  max-width: 1420px;
}
@media (min-width: 1080px) {
  .aj-hero .wrap { grid-template-columns: minmax(0, 1.18fr) minmax(0, .82fr); }
}

.aj-hero-copy { position: relative; z-index: 2; max-width: 70ch; }
.aj-hero .eyebrow { color: rgba(255, 255, 255, .72); }
.aj-hero .eyebrow::before { background: var(--grad); }

.aj-hero h1 { color: #fff; }
.aj-hero h1 .hl {
  white-space: nowrap;
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.aj-hero-sub {
  margin-top: 20px;
  font-size: clamp(1rem, .96rem + .3vw, 1.12rem);
  color: rgba(255, 255, 255, .76);
  max-width: 46ch;
}
.aj-hero-actions {
  margin-top: 30px;
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
}

.aj-hero-trust {
  margin: 34px 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 26px;
}
.aj-hero-trust li {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: .85rem;
  letter-spacing: .02em;
  color: rgba(255, 255, 255, .66);
}
.aj-hero-trust .aj-icon { width: 17px; height: 17px; color: var(--brand-2); }

/* entrance — staggered, and only on the first paint */
.js .aj-hero-anim > * {
  opacity: 0;
  transform: translateY(24px);
  animation: heroIn .95s var(--ease-out) forwards;
  animation-delay: calc(.15s + var(--i, 0) * .11s);
}
@keyframes heroIn { to { opacity: 1; transform: none; } }

.aj-hero-visual { position: relative; z-index: 1; display: grid; place-items: center; }

@media (max-width: 1079px) {
  .aj-hero { min-height: auto; padding-bottom: clamp(30px, 5vw, 52px); }
  .aj-hero-copy { max-width: none; }
}

/* 08  About =============================================================== *
   Built as four blocks on a twelve-column field rather than a picture beside
   a column of text:

     row 1   the introduction (7 cols)      the numbers over a photo (5 cols)
     row 2   the exploded building (5)      the rest of the story (7)

   The columns swap width between the rows, which is what keeps it from
   reading as a plain two-column layout. Everything collapses to one column
   below 1000px in the order it is written, which is the order it reads in.  */

.aj-about-sec { position: relative; overflow: hidden; }
/* one soft wash behind the composition, nothing more decorative than that */
.aj-about-sec::before {
  content: "";
  position: absolute;
  inset: -20% -10% auto auto;
  width: 52vw;
  height: 52vw;
  max-width: 720px;
  max-height: 720px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(47, 128, 237, .07), transparent 62%);
  pointer-events: none;
}
.aj-about-sec .wrap { position: relative; }

.aj-about { display: grid; gap: clamp(30px, 3.6vw, 58px); }
@media (min-width: 1000px) {
  .aj-about {
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: clamp(28px, 3vw, 52px);
    /* stretch, not start: each block fills its row so the two columns end
       flush with one another instead of running ragged */
    align-items: stretch;
  }
  .aj-about-lead  { grid-column: 1 / span 7; }
  .aj-vitals      { grid-column: 8 / span 5; }
  .aj-stack       { grid-column: 1 / span 5; }
  .aj-about-story { grid-column: 6 / span 7; }
  .aj-pillars     { grid-column: 1 / -1; grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* --- the introduction: the largest type in the section ------------------ */

.aj-about-lead h2 {
  font-size: clamp(2rem, 1.1rem + 2.9vw, 3.1rem);
  letter-spacing: -.034em;
  line-height: 1.08;
}
.aj-about-lead .lead {
  margin-top: 22px;
  max-width: 54ch;
  font-size: clamp(1.04rem, 1rem + .34vw, 1.2rem);
}

/* --- the numbers, over a photograph of the people behind them ----------- */

.aj-vitals {
  position: relative;
  isolation: isolate;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--ink);
  box-shadow: var(--shadow-lg);
  display: flex;
  align-self: stretch;
  min-height: 300px;
  /* the panel inside sets colours only where it departs from white, which
     is what the hero shell it came from used to establish */
  color: #fff;
}
.aj-vitals-art {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  opacity: .9;
}
.va-ring { fill: none; stroke: rgba(255, 255, 255, .09); stroke-width: 1; }
.va-arc {
  fill: none;
  stroke: url(#ajVitArc);
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-dasharray: var(--dash) var(--c);
  opacity: .8;
  transform-box: view-box;
  transform-origin: 340px 64px;
}
.is-in .va-arc--1 { animation: ajVitTurn 26s linear infinite; }
.is-in .va-arc--2 { animation: ajVitTurn 38s linear infinite reverse; }
.is-in .va-arc--3 { animation: ajVitTurn 54s linear infinite; }
@keyframes ajVitTurn { to { transform: rotate(360deg); } }
.va-dot { fill: #6fb4ff; opacity: .22; }
.is-in .va-dot { animation: ajVitDot 7s var(--ease) infinite; animation-delay: var(--d, 0s); }
@keyframes ajVitDot { 0%, 100% { opacity: .12; } 50% { opacity: .42; } }
.aj-vitals::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(165deg, rgba(10, 17, 32, .1) 0%, rgba(10, 17, 32, .82) 62%, rgba(10, 17, 32, .95) 100%),
    radial-gradient(66% 56% at 88% 2%, rgba(47, 128, 237, .34), transparent 72%);
}
.aj-vitals-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: clamp(24px, 2.6vw, 34px);
}

/* The operations readout, moved here from the hero. The card above
   already provides the dark surface it used to carry itself, so only
   the inner rules travelled with it. */
.aj-panel-head { display: flex; align-items: center; gap: 14px; }
.aj-panel-eye { width: 46px; height: 46px; flex: none; }
.aj-panel-eye svg { width: 100%; height: 100%; }
.aj-panel-eye .eye-rings { fill: none; stroke: var(--brand-2); stroke-width: 1; opacity: .3; }
.aj-panel-eye .eye-lid { fill: none; stroke: var(--brand); stroke-width: 2; }
.aj-panel-eye .eye-iris { fill: var(--brand); opacity: .55; }
.aj-panel-eye .eye-pupil { fill: #fff; }
.js .aj-panel-eye .eye-rings { animation: vSpin 24s linear infinite; transform-box: fill-box; transform-origin: 50% 50%; }
.js .aj-panel-eye .eye-pupil,
.js .aj-panel-eye .eye-iris { animation: eyeLook 7s var(--ease) infinite; transform-box: fill-box; transform-origin: 50% 50%; }
@keyframes eyeLook {
  0%, 100% { transform: translateX(0); }
  22% { transform: translateX(3.5px); }
  55% { transform: translateX(-3.5px); }
}
.aj-panel-title { display: block; font-family: var(--font-display); font-weight: 600; font-size: 1.02rem; letter-spacing: -.01em; }
.aj-panel-sub { display: flex; align-items: center; gap: 7px; font-size: .78rem; color: rgba(255, 255, 255, .6); }
.aj-live {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--brand-2);
  box-shadow: 0 0 0 0 rgba(20, 221, 115, .6);
}
.js .aj-live { animation: livePulse 2.2s var(--ease) infinite; }
@keyframes livePulse {
  0% { box-shadow: 0 0 0 0 rgba(20, 221, 115, .55); }
  70% { box-shadow: 0 0 0 9px rgba(20, 221, 115, 0); }
  100% { box-shadow: 0 0 0 0 rgba(20, 221, 115, 0); }
}

.aj-panel-rows { margin: 22px 0 0; padding: 0; list-style: none; }
.aj-panel-rows li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 13px 0;
  border-top: 1px solid rgba(255, 255, 255, .1);
}
.aj-panel-k { font-size: .86rem; color: rgba(255, 255, 255, .66); }
.aj-panel-v {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -.03em;
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-variant-numeric: tabular-nums;
}
.aj-panel-foot {
  margin-top: 20px;
  padding-top: 18px;
  border-top: 1px solid rgba(255, 255, 255, .1);
  font-size: .76rem;
  letter-spacing: .04em;
  color: rgba(255, 255, 255, .55);
}
.aj-panel-scan {
  height: 4px;
  margin-bottom: 12px;
  border-radius: 4px;
  background: rgba(255, 255, 255, .1);
  overflow: hidden;
}
.aj-panel-scan i {
  display: block;
  width: 38%;
  height: 100%;
  border-radius: 4px;
  background: var(--grad);
}
.js .aj-panel-scan i { animation: panelScan 3.6s var(--ease) infinite; }
@keyframes panelScan {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(266%); }
}


/* --- the property, taken apart --------------------------------------- *
   Each level is its own block with its label beside it, and the blocks sit
   with air between them so the four read as one building pulled apart. The
   label is real text rather than SVG so it stays legible and selectable. */

.aj-stack { display: flex; flex-direction: column; }
.aj-stack-k {
  display: block;
  margin-bottom: 18px;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--text-3);
}

.aj-stack-row {
  display: grid;
  grid-template-columns: clamp(116px, 13vw, 172px) minmax(0, 1fr);
  align-items: center;
  gap: clamp(12px, 1.6vw, 20px);
  padding: 12px 14px 12px 0;
  border-radius: var(--r);
  transition: transform .45s var(--ease), background-color .45s var(--ease);
}
.aj-stack-rows {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 6px;
}
.aj-stack-row:hover {
  transform: translateX(6px);
  background: linear-gradient(90deg, rgba(47, 128, 237, .07), transparent 70%);
}
.aj-stack-txt b {
  display: block;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -.012em;
  color: var(--text);
}
.aj-stack-txt span {
  display: block;
  margin-top: 4px;
  font-size: .86rem;
  line-height: 1.55;
  color: var(--text-3);
}

.aj-lv { width: 100%; height: auto; overflow: visible; }
.lv-face { fill: rgba(47, 128, 237, .1); stroke: rgba(47, 128, 237, .46); stroke-width: 1.3; }
.lv-top { fill: rgba(47, 128, 237, .22); stroke: rgba(47, 128, 237, .46); stroke-width: 1.3; }
.lv-side { fill: rgba(47, 128, 237, .34); stroke: rgba(47, 128, 237, .46); stroke-width: 1.3; }
.aj-stack-row:hover .lv-top { fill: rgba(20, 221, 115, .24); }
.lv-face, .lv-top, .lv-side { transition: fill .45s var(--ease); }

.lv-floor, .lv-louvre, .lv-mullion, .lv-duct {
  fill: none;
  stroke: rgba(47, 128, 237, .34);
  stroke-width: 1;
}
.lv-ground { fill: none; stroke: rgba(47, 128, 237, .3); stroke-width: 1.4; stroke-linecap: round; }
.lv-win { fill: var(--brand); opacity: .22; }
.lv-glass { fill: rgba(47, 128, 237, .16); stroke: rgba(47, 128, 237, .3); stroke-width: 1; }
.lv-tank, .lv-unit { fill: rgba(47, 128, 237, .34); stroke: rgba(47, 128, 237, .5); stroke-width: 1; }
.lv-shaft { fill: rgba(47, 128, 237, .1); stroke: rgba(47, 128, 237, .3); stroke-width: 1; }
.lv-lift rect { fill: url(#ajGrad); opacity: .8; }
.lv-trolley { fill: var(--brand-2); opacity: .5; }
.lv-door { fill: rgba(47, 128, 237, .2); stroke: rgba(47, 128, 237, .4); stroke-width: 1; }
.lv-canopy, .lv-post { fill: rgba(47, 128, 237, .42); }
.lv-boom rect { fill: url(#ajGrad); }
.lv-scan-plate { fill: rgba(20, 221, 115, .16); stroke: var(--brand-2); stroke-width: 1.2; }
.lv-scan-dot { fill: var(--brand-2); }

/* Three quiet loops only. This section sits near the top of the page, so it
   has to stay calmer than the service scenes further down. */
.is-in .lv-unit--on { animation: ajLvRun 3.4s var(--ease) infinite; }
@keyframes ajLvRun { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }

.lv-lift { transform-box: view-box; }
.is-in .lv-lift { animation: ajLvLift 7s var(--ease) infinite; }
@keyframes ajLvLift {
  0%, 8% { transform: translateY(0); }
  42%, 58% { transform: translateY(-30px); }
  92%, 100% { transform: translateY(0); }
}

.is-in .lv-scan-dot { animation: ajLvScan 2.6s var(--ease) infinite; }
@keyframes ajLvScan { 0%, 100% { opacity: 1; } 55% { opacity: .2; } }

.is-in .lv-win { animation: ajLvWin 6.5s var(--ease) infinite; animation-delay: var(--d, 0s); }
@keyframes ajLvWin {
  0%, 20% { opacity: .18; }
  32%, 62% { opacity: .72; }
  76%, 100% { opacity: .18; }
}

/* --- the rest of the story ---------------------------------------------- */

.aj-about-story { display: flex; flex-direction: column; }
.aj-about-story > div > p:last-child { margin-bottom: 0; }

.aj-about-quote {
  position: relative;
  margin: 30px 0 0;
  /* pushed down so it lands level with the foot of the stack beside it */
  margin-top: auto;
  padding: 28px 30px;
  border-radius: var(--r);
  background: var(--grad-soft);
  border: 1px solid var(--card-line);
  font-family: var(--font-display);
  font-size: clamp(1.06rem, 1rem + .5vw, 1.3rem);
  line-height: 1.5;
  letter-spacing: -.015em;
  color: var(--text);
}
.aj-about-quote::before {
  content: "";
  position: absolute;
  left: 0;
  top: 20px;
  bottom: 20px;
  width: 3px;
  border-radius: 3px;
  background: var(--grad);
}
.aj-about-quote cite {
  display: block;
  margin-top: 12px;
  font-family: var(--font-body);
  font-size: .76rem;
  font-style: normal;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--brand);
}

/* --- how we work: four cards ------------------------------------------- */

.aj-pillars {
  margin: clamp(10px, 1.4vw, 22px) 0 0;
  padding-top: clamp(26px, 3vw, 42px);
  border-top: 1px solid var(--line);
  padding: 0;
  list-style: none;
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(215px, 1fr));
}
.aj-pillar {
  padding: 20px;
  border-radius: var(--r-sm);
  border: 1px solid var(--card-line);
  background: var(--card);
  transition: transform .4s var(--ease), box-shadow .4s var(--ease), border-color .4s var(--ease);
}
.aj-pillar:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow);
  border-color: transparent;
}
.aj-pillar-ic {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  margin-bottom: 14px;
  border-radius: 11px;
  background: var(--grad-soft);
  color: var(--brand);
  transition: background .4s var(--ease), color .4s var(--ease);
}
.aj-pillar:hover .aj-pillar-ic { background: var(--grad); color: #fff; }
.aj-pillar-ic .aj-icon { width: 19px; height: 19px; }
.aj-pillar b {
  display: block;
  font-family: var(--font-display);
  font-size: .99rem;
  font-weight: 600;
  letter-spacing: -.012em;
  color: var(--text);
}
.aj-pillar > span {
  display: block;
  margin-top: 5px;
  font-size: .86rem;
  line-height: 1.55;
  color: var(--text-3);
}

/* 09  Services =========================================================== */

.aj-svc {
  position: relative;
  padding-block: clamp(58px, 5.6vw, 98px);
  overflow: hidden;
}
.aj-svc--tint { background: var(--paper-2); }
.aj-svc--dark { background: var(--ink); }
.aj-svc--dark::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(48% 70% at 78% 24%, rgba(47, 128, 237, .3), transparent 70%),
    radial-gradient(44% 64% at 14% 88%, rgba(20, 221, 115, .2), transparent 70%);
  pointer-events: none;
}

.aj-svc-grid {
  position: relative;
  display: grid;
  gap: clamp(36px, 5vw, 74px);
  align-items: center;
}
@media (min-width: 900px) {
  .aj-svc-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.04fr); }
  /* alternate: even-numbered services put the graphic on the left */
  .aj-svc--flip .aj-svc-copy { order: 2; }
}

.aj-svc-copy { max-width: 54ch; }

.aj-svc-index {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  font-family: var(--font-display);
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: .16em;
  color: var(--text-3);
}
.aj-svc-index b {
  font-size: 1.5rem;
  letter-spacing: -.02em;
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.aj-svc-copy h2 { margin: 14px 0 0; }
.aj-svc-copy .eyebrow { margin: 16px 0 0; }
.aj-svc-copy > p { margin-top: 20px; }

.aj-svc-points {
  margin: 26px 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.aj-svc-points li {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 15px;
  border-radius: 999px;
  border: 1px solid var(--card-line);
  background: var(--card);
  font-size: .84rem;
  font-weight: 500;
  color: var(--text);
  transition: transform .35s var(--ease), border-color .35s var(--ease);
}
.aj-svc-points li:hover { transform: translateY(-2px); border-color: var(--brand); }
.aj-svc-points .aj-icon { width: 15px; height: 15px; color: var(--brand-2); }
.aj-svc-copy .btn { margin-top: 30px; }

/* Each service frames its graphic differently — a night panel, plain paper,
   no frame at all, a drawing sheet, a board, dark glass — so the six do not
   read as six of the same card. */
.aj-svc-visual {
  position: relative;
  border-radius: var(--r-lg);
  padding: clamp(14px, 2vw, 26px);
}

.aj-svc-visual--night {
  background: linear-gradient(158deg, #0d1729 0%, #0a1120 62%, #0c1a2c 100%);
  --sc-ink: 255, 255, 255;
  box-shadow: 0 34px 70px -34px rgba(8, 16, 32, .8);
  --text-3: rgba(255, 255, 255, .48);
  --card: rgba(255, 255, 255, .07);
  --card-line: rgba(255, 255, 255, .14);
}
.aj-svc-visual--night::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(60% 50% at 74% 14%, rgba(47, 128, 237, .3), transparent 70%);
  pointer-events: none;
}

.aj-svc-visual--paper {
  background: var(--card);
  border: 1px solid var(--card-line);
  box-shadow: var(--shadow);
}

/* No frame at all: the crowd runs wider than the column and clips on the
   section edge, which is what makes it read as a street rather than a card. */
.aj-svc-visual--bleed { padding: 0; background: none; }
@media (min-width: 900px) {
  .aj-svc-visual--bleed { width: 116%; }
  .aj-svc--flip .aj-svc-visual--bleed { margin-left: -16%; }
}

.aj-svc-visual--sheet {
  background:
    repeating-linear-gradient(0deg, rgba(47, 128, 237, .07) 0 1px, transparent 1px 26px),
    repeating-linear-gradient(90deg, rgba(47, 128, 237, .07) 0 1px, transparent 1px 26px),
    var(--card);
  border: 1px solid var(--card-line);
  box-shadow: var(--shadow);
}

.aj-svc-visual--board {
  background: radial-gradient(rgba(47, 128, 237, .13) 1px, transparent 1px) 0 0 / 18px 18px, var(--card);
  border: 1px solid var(--card-line);
  box-shadow: var(--shadow);
}

.aj-svc-visual--glass {
  background: rgba(255, 255, 255, .04);
  --sc-ink: 255, 255, 255;
  border: 1px solid rgba(255, 255, 255, .1);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

/* 10  Service scenes ===================================================== */

/* Six scenes, six visual languages. What they share is the cast (one figure
   pictogram) and the brand palette; nothing else is reused between them —
   not the projection, not the framing, not the kind of motion.

   Two motion sources:
     .is-live   added by js/ajna.js when the scene enters the viewport, and
                gates every autoplay loop so off-screen scenes do no work
     --p        0 to 1 as the section crosses the viewport, also set by
                js/ajna.js. Scenes 01, 02, 04 and 05 are driven by it, so the
                story advances and rewinds with the reader.
   With scripting off, --p falls back to .5 and the loops never start, which
   leaves every scene legible as a still. */

.aj-visual-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
.aj-visual { width: 100%; height: auto; overflow: visible; }
.aj-visual text { font-family: var(--font-body); }

@keyframes ajSpin { to { transform: rotate(360deg); } }
@keyframes ajBlink { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
@keyframes ajDash { to { stroke-dashoffset: 0; } }

/* --- the cast ---------------------------------------------------------- */

.p { --fig: #2f80ed; --hat: #14dd73; }
.p--public { --fig: rgba(16, 24, 40, .24); --hat: rgba(16, 24, 40, .24); }
.tone-dark .p--public { --fig: rgba(255, 255, 255, .3); --hat: rgba(255, 255, 255, .3); }
.p-head, .p-torso, .p-leg-s, .p-leg rect, .p-arm rect { fill: var(--fig); }
.p-hat { fill: var(--hat); }
.p-leg { transform-box: fill-box; transform-origin: 50% 6%; }
.p-arm { transform-box: fill-box; transform-origin: 50% 7%; }

/* ========================= 01  IT parks ================================= *
   Isometric campus after dark, and the one scene that runs entirely on its
   own clock. The round has to look like it never stops, so nothing here is
   tied to scroll position — it plays whenever the section is on screen.

   Everything shares one 26s timeline (--round), which is what keeps the
   officer, the trail behind him, the checkpoint lights and the round meter in
   step. The patrol path is a closed square whose four sides come out exactly
   equal in this projection, so the checkpoints sit at exactly 12.5%, 37.5%,
   62.5% and 87.5% — the numbers the keyframes below are written against. If
   the route in includes/service-visuals.php ever changes shape, these
   percentages have to move with it.

   Because the path closes, every loop here is seamless: no fade at the seam,
   no reset flash, nothing that gives away where the cycle restarts.          */

.sc1 { --round: 26s; }

.sc1-plate { fill: rgba(47, 128, 237, .06); stroke: rgba(47, 128, 237, .2); stroke-width: 1; }
.sc1-grid line { stroke: rgba(47, 128, 237, .12); stroke-width: 1; }
.iso-top { fill: rgba(47, 128, 237, .22); }
.iso-right { fill: rgba(47, 128, 237, .4); }
.iso-left { fill: rgba(47, 128, 237, .28); }
.iso-win { fill: #79bcff; opacity: .16; }
.is-live .iso-win { animation: ajWin 6.4s var(--ease) infinite; animation-delay: var(--d, 0s); }
@keyframes ajWin {
  0%, 14% { opacity: .14; }
  24%, 58% { opacity: .95; }
  70%, 100% { opacity: .14; }
}

/* The route, and the short lit trail that follows him round it. The trail is
   one dash chased along a closed path by its offset, which is why it can loop
   forever without ever resetting. */
.sc1-route { fill: none; stroke: rgba(47, 128, 237, .32); stroke-width: 2; stroke-dasharray: 4 7; stroke-linecap: round; }
.sc1-route-trail {
  fill: none;
  stroke: url(#ajGrad);
  stroke-width: 3.4;
  stroke-linecap: round;
  stroke-dasharray: 88px calc(var(--len) * 1px);
  stroke-dashoffset: calc(88px - var(--len) * .42px);
}
.is-live .sc1-route-trail { animation: ajTrail var(--round) linear infinite; }
@keyframes ajTrail {
  from { stroke-dashoffset: 88px; }
  to { stroke-dashoffset: calc(88px - var(--len) * 1px); }
}

/* Checkpoints: dashed until he reaches one, lit while he is near it, out
   again once he has moved on. */
.sc1-cp-pad { fill: none; stroke: rgba(47, 128, 237, .34); stroke-width: 1.4; stroke-dasharray: 3 4; }
.sc1-cp-lit { fill: rgba(20, 221, 115, .16); stroke: var(--brand-2); stroke-width: 1.6; }
.sc1-cp-beam { fill: url(#ajGlow); }
.sc1-cp-dot { fill: var(--brand-2); }
.sc1-cp-k { font-size: 9px; font-weight: 600; letter-spacing: .1em; fill: var(--brand-2); text-anchor: middle; }

.sc1-cp-on { opacity: 0; }
.sc1-cp--1 .sc1-cp-on, .sc1-cp--2 .sc1-cp-on { opacity: 1; }
.is-live .sc1-cp--1 .sc1-cp-on { animation: ajCp1 var(--round) linear infinite; }
.is-live .sc1-cp--2 .sc1-cp-on { animation: ajCp2 var(--round) linear infinite; }
.is-live .sc1-cp--3 .sc1-cp-on { animation: ajCp3 var(--round) linear infinite; }
.is-live .sc1-cp--4 .sc1-cp-on { animation: ajCp4 var(--round) linear infinite; }
@keyframes ajCp1 { 0%, 12.5% { opacity: 0; } 15%, 34% { opacity: 1; } 40%, 100% { opacity: 0; } }
@keyframes ajCp2 { 0%, 37.5% { opacity: 0; } 40%, 59% { opacity: 1; } 65%, 100% { opacity: 0; } }
@keyframes ajCp3 { 0%, 62.5% { opacity: 0; } 65%, 84% { opacity: 1; } 90%, 100% { opacity: 0; } }
/* the fourth wraps across the seam, which is why both ends are lit */
@keyframes ajCp4 { 0%, 9% { opacity: 1; } 15%, 87.5% { opacity: 0; } 90%, 100% { opacity: 1; } }

/* The officer. offset-path carries him; the flip at the far corner turns him
   round so he never walks backwards down the two returning sides. */
.sc1-walker { offset-distance: 42%; offset-rotate: 0deg; }
.is-live .sc1-walker { animation: ajPatrol var(--round) linear infinite; }
@keyframes ajPatrol { from { offset-distance: 0%; } to { offset-distance: 100%; } }

/* He mirrors about his own centre line, which is the origin of this
   group's local coordinate system — the point the motion path is
   carrying. fill-box would pivot on the bounding box instead, and the
   torch beam stretches that box far to his right, which threw him about
   43 units clear of the route for the whole mirrored half of the lap. */
.sc1-face { transform-box: view-box; transform-origin: 0 0; }
.is-live .sc1-face { animation: ajTurn var(--round) linear infinite; }
@keyframes ajTurn {
  0%, 48.5% { transform: scaleX(1); }
  51.5%, 98.5% { transform: scaleX(-1); }
  100% { transform: scaleX(1); }
}

.sc1-shadow { fill: rgba(4, 9, 18, .42); }
.sc1-torch-beam { fill: url(#ajGlow); opacity: .26; }
.is-live .sc1-torch-beam { animation: ajTorch 5.5s var(--ease) infinite; }
@keyframes ajTorch { 0%, 100% { opacity: .2; } 50% { opacity: .4; } }

/* the uniform */
.gd-trouser { fill: #16304f; }
.gd-boot { fill: #0b1c31; }
.gd-belt { fill: #0b1c31; }
.gd-buckle { fill: var(--brand-2); }
.gd-shirt { fill: #2f80ed; }
.gd-sleeve { fill: #3d8bef; }
.gd-collar { fill: none; stroke: rgba(9, 24, 46, .5); stroke-width: 1.1; stroke-linejoin: round; }
/* the far side of him sits in his own shadow, which is what gives the
   figure depth at a size too small for any real shading */
.gd-sleeve--far { fill: #1d5cb4; }
.gd-trouser--far { fill: #10233c; }
.gd-boot--far { fill: #071324; }
.gd-skin--far { fill: #c99b78; }
.gd-epaulette { fill: var(--brand-2); }
.gd-radio { fill: #0b1c31; }
.gd-skin { fill: #e7bd97; }
.gd-cap { fill: #0b1c31; }
.gd-badge { fill: var(--brand-2); }
.gd-torch-body { fill: #dbe6f5; }

/* The walk.
   --------------------------------------------------------------------------
   Phasing is the whole thing here. `animation-direction: reverse` cannot be
   used to oppose two limbs when the keyframes are symmetric (0% and 100% hold
   the same value), because reversing such a run reproduces it exactly — which
   is how all four limbs ended up swinging together. Opposition comes from a
   negative delay of half the cycle instead.

   Human gait is contralateral: the arm and the leg on the *same* side move in
   opposite phase. The near arm and near leg therefore run half a cycle apart,
   and the far pair likewise:

     near leg   phase 0        near arm   phase 0.5
     far  leg   phase 0.5      far  arm   phase 0

   Cadence is matched to how fast he actually crosses the ground — 25.2 user
   units a second — so at 1.28s a stride covers about 32 units against a
   natural stride of roughly 35 for his leg length. Slightly under, which
   reads as an unhurried patrol; over would look like skating. */

.sc1 { --gait: 1.28s; }

.gd { transform-box: fill-box; transform-origin: 50% 100%; }
.gd-hips { transform-box: fill-box; transform-origin: 50% 0%; }
.gd-upper { transform-box: fill-box; transform-origin: 50% 100%; }
/* Each limb pivots at its joint, which with transform-box: fill-box means
   the joint expressed as a percentage of that group's own bounding box.
   Three of the four sit near the middle; the near arm does not, because
   the torch in its hand stretches the box to the right and drags the
   centre off the shoulder with it. */
.gd-leg, .gd-arm { transform-box: fill-box; transform-origin: 50% 0; }
.gd-leg-a { transform-origin: 52% 0; }
.gd-leg-b { transform-origin: 48% 0; }
.gd-arm-a { transform-origin: 24% 0; }

.is-live .gd-leg-a { animation: ajStride var(--gait) linear infinite; }
.is-live .gd-leg-b { animation: ajStride var(--gait) linear infinite; animation-delay: calc(var(--gait) * -.5); }
.is-live .gd-arm-a { animation: ajArmSwing var(--gait) linear infinite; }
.is-live .gd-arm-b { animation: ajArmSwing var(--gait) linear infinite; animation-delay: calc(var(--gait) * -.5); }
.is-live .gd-hips { animation: ajHips var(--gait) linear infinite; }
.is-live .gd-upper { animation: ajShoulders var(--gait) linear infinite; }
.is-live .gd { animation: ajBob var(--gait) linear infinite; }

/* Hip angle across one stride, negative in front of him. Long slow extension
   through the stance phase, then a quick flexion as the leg swings through —
   the asymmetry is what stops it reading as a metronome. Amplitudes are about
   two thirds of life so the walk stays calm at this size. */
@keyframes ajStride {
  0%    { transform: rotate(-14deg); }
  12.5% { transform: rotate(-10deg); }
  25%   { transform: rotate(-5.5deg); }
  37.5% { transform: rotate(-1deg); }
  50%   { transform: rotate(3.5deg); }
  62.5% { transform: rotate(8deg); }
  75%   { transform: rotate(2deg); }
  87.5% { transform: rotate(-9deg); }
  100%  { transform: rotate(-14deg); }
}

/* Arms are close enough to a free pendulum, and shallower than the legs. */
@keyframes ajArmSwing {
  0%    { transform: rotate(11deg); }
  12.5% { transform: rotate(7.8deg); }
  25%   { transform: rotate(0deg); }
  37.5% { transform: rotate(-7.8deg); }
  50%   { transform: rotate(-11deg); }
  62.5% { transform: rotate(-7.8deg); }
  75%   { transform: rotate(0deg); }
  87.5% { transform: rotate(7.8deg); }
  100%  { transform: rotate(11deg); }
}

/* Pelvis turns with the leading leg; shoulders turn against it. Barely a
   degree either way, but it is what keeps the torso from looking like a plank
   carried between two swinging legs. */
@keyframes ajHips {
  0%    { transform: rotate(1.5deg); }
  12.5% { transform: rotate(1.1deg); }
  25%   { transform: rotate(0deg); }
  37.5% { transform: rotate(-1.1deg); }
  50%   { transform: rotate(-1.5deg); }
  62.5% { transform: rotate(-1.1deg); }
  75%   { transform: rotate(0deg); }
  87.5% { transform: rotate(1.1deg); }
  100%  { transform: rotate(1.5deg); }
}
@keyframes ajShoulders {
  0%    { transform: rotate(-1.2deg); }
  12.5% { transform: rotate(-.9deg); }
  25%   { transform: rotate(0deg); }
  37.5% { transform: rotate(.9deg); }
  50%   { transform: rotate(1.2deg); }
  62.5% { transform: rotate(.9deg); }
  75%   { transform: rotate(0deg); }
  87.5% { transform: rotate(-.9deg); }
  100%  { transform: rotate(-1.2deg); }
}

/* The body rises over each mid-stance and drops at each foot fall, so this
   runs at twice the stride frequency — two rises per cycle, not one. */
@keyframes ajBob {
  0%    { transform: translateY(.5px); }
  12.5% { transform: translateY(0); }
  25%   { transform: translateY(-.5px); }
  37.5% { transform: translateY(0); }
  50%   { transform: translateY(.5px); }
  62.5% { transform: translateY(0); }
  75%   { transform: translateY(-.5px); }
  87.5% { transform: translateY(0); }
  100%  { transform: translateY(.5px); }
}

/* the meter: one segment per checkpoint, lit by the same four keyframes */
.sc1-hud-k { font-size: 9px; font-weight: 600; letter-spacing: .16em; fill: var(--text-3); }
.sc1-hud-track { fill: rgba(47, 128, 237, .18); }
.sc1-hud-lit { fill: url(#ajGrad); opacity: 0; }
.sc1-hud-seg--1 .sc1-hud-lit, .sc1-hud-seg--2 .sc1-hud-lit { opacity: 1; }
.is-live .sc1-hud-seg--1 .sc1-hud-lit { animation: ajCp1 var(--round) linear infinite; }
.is-live .sc1-hud-seg--2 .sc1-hud-lit { animation: ajCp2 var(--round) linear infinite; }
.is-live .sc1-hud-seg--3 .sc1-hud-lit { animation: ajCp3 var(--round) linear infinite; }
.is-live .sc1-hud-seg--4 .sc1-hud-lit { animation: ajCp4 var(--round) linear infinite; }

/* ========================= 02  Landscape ================================ *
   The grounds, and the schedule that keeps them.

   --season is the clock. Turf, shrubs and hedge share one growth keyframe
   that creeps up and drops back at 90%; what differs is the delay, which is
   computed in the markup from each planting's own x so that it is cut at
   the instant the trim pass arrives over it. Pass and cut are therefore one
   event, not two set to the same time by hand. The pass crosses between 70%
   and 90%, which is why the delays span a fifth of the cycle -- the visible
   side effect is that plantings sit at slightly different heights, which is
   what a real bed does anyway.

   The tree is deliberately outside all of that. Nobody cuts a tree back
   every month, so it only sways. */

.sc2 {
  --season: 10s;
  --year: 30s;
  --ls-green: rgba(20, 221, 115, .5);
  --ls-deep: rgba(11, 150, 79, .46);
}

/* the schedule strip */
.ls-cell { fill: var(--card); stroke: var(--card-line); stroke-width: 1.6; }
.ls-cell-k { font-size: 9px; font-weight: 700; fill: var(--text-3); text-anchor: middle; }
.ls-cell-t { fill: none; stroke: var(--brand-2); stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.ls-cursor-r { fill: rgba(20, 221, 115, .16); stroke: var(--brand-2); stroke-width: 2; }
.ls-cursor { transform-box: view-box; }
/* twelve discrete months, not a slide across them */
.is-live .ls-cursor { animation: ajLsCursor var(--year) steps(12, end) infinite; }
@keyframes ajLsCursor { to { transform: translateX(576px); } }

/* the property behind the grounds */
.ls-fac { fill: rgba(var(--sc-ink), .05); stroke: var(--card-line); stroke-width: 1.6; }
.ls-win { fill: rgba(47, 128, 237, .12); }
.ls-door { fill: rgba(var(--sc-ink), .14); }
.ls-ground { stroke: rgba(var(--sc-ink), .22); stroke-width: 2.4; stroke-linecap: round; }

/* one growth for everything that gets cut */
.ls-grow { transform-box: view-box; transform-origin: 0 0; }
.is-live .ls-grow { animation: ajLsGrow var(--season) linear infinite; animation-delay: var(--d, 0s); }
@keyframes ajLsGrow {
  0% { transform: scaleY(1); }
  90% { transform: scaleY(1.24); }
  90.6% { transform: scaleY(1); }
  100% { transform: scaleY(1); }
}

/* turf */
.ls-turf { fill: var(--ls-green); }
.ls-stripe { fill: rgba(255, 255, 255, .34); }
.ls-tuft { fill: var(--ls-deep); }

/* beds */
.ls-mulch { fill: rgba(var(--sc-ink), .13); }
.ls-kerb { stroke: rgba(var(--sc-ink), .2); stroke-width: 2.4; stroke-linecap: round; }
.ls-shrub { fill: var(--ls-green); }

/* hedge */
.ls-hedge { fill: var(--ls-deep); }
.ls-hedge-t { fill: rgba(20, 221, 115, .5); }

/* the tree, which only sways */
.ls-trunk { fill: rgba(var(--sc-ink), .3); }
.ls-canopy { fill: var(--ls-green); }
.ls-sway { transform-box: view-box; transform-origin: 0 0; }
.is-live .ls-sway { animation: ajLsSway 7.5s ease-in-out infinite; }
@keyframes ajLsSway {
  0%, 100% { transform: rotate(-1.3deg); }
  50% { transform: rotate(1.3deg); }
}

/* the trim pass */
.ls-pass-glow { fill: rgba(20, 221, 115, .16); }
.ls-pass-l { fill: var(--brand-2); }
.ls-pass { transform-box: view-box; opacity: 0; }
.is-live .ls-pass { animation: ajLsPass var(--season) linear infinite; }
@keyframes ajLsPass {
  0%, 70% { transform: translateX(0); opacity: 0; }
  72% { opacity: .9; }
  88% { opacity: .9; }
  90% { transform: translateX(598px); opacity: 0; }
  100% { transform: translateX(598px); opacity: 0; }
}

/* the quantities the work is priced against */
.ls-ext { stroke: rgba(var(--sc-ink), .18); stroke-width: 1.4; }
.ls-dim { stroke: rgba(var(--sc-ink), .3); stroke-width: 1.4; }
.ls-arrow { fill: none; stroke: rgba(var(--sc-ink), .3); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.ls-dim-k { font-size: 9.4px; font-weight: 700; letter-spacing: .1em; fill: var(--text-3); text-anchor: middle; }

.ls-k { font-size: 8.8px; font-weight: 700; letter-spacing: .18em; fill: var(--text-3); }
.ls-foot { font-size: 8.4px; font-weight: 700; letter-spacing: .16em; fill: var(--text-3); text-anchor: middle; opacity: .72; }

/* ========================= 03  Housekeeping ============================= *
   A flat interior elevation — the only one on the page — and a housekeeper
   who does not travel. Where the officer in scene 01 covers ground with a
   walk cycle, everything here happens from the waist: she braces, leans into
   the forward push and rocks back on the pull while the machine runs out and
   back in front of her. Legs stay planted.

   The floor is the other half of it. A shine passes over the boards and
   glints pop where it has been, so the work has a visible result rather than
   only a worker. Nothing reads scroll position.                             */

.sc3 { --stroke: 3.6s; }

/* the room */
.hk-wall { fill: rgba(47, 128, 237, .05); }
.hk-glass rect { fill: url(#ajGlass); stroke: rgba(47, 128, 237, .3); stroke-width: 1.2; }
.hk-mullion { fill: none; stroke: rgba(47, 128, 237, .3); stroke-width: 1.2; }
.hk-panel { fill: rgba(47, 128, 237, .07); stroke: rgba(47, 128, 237, .24); stroke-width: 1.2; }
.hk-panel-line { fill: none; stroke: rgba(47, 128, 237, .24); stroke-width: 1.4; stroke-linecap: round; }
.hk-skirt { fill: rgba(47, 128, 237, .26); }

/* --- the few values a single number cannot serve on both surfaces ------ *
   Most of the scene follows --sc-ink and needs nothing here. These do not:
   a sheen has to be brighter than the floor it crosses, so on paper it is
   near-white and on ink that same near-white is a slab; and a wash this
   faint needs more of itself on ink than it does on paper to register at
   all. Kept as overrides rather than folded into the base rules so the
   scenes still read if a section is ever set light again. */

.tone-dark .hk-shine { opacity: .12; }
.tone-dark .hk-wall { fill: rgba(47, 128, 237, .1); }
.tone-dark .hk-floor { fill: rgba(47, 128, 237, .17); }
.tone-dark .ls-stripe { fill: rgba(255, 255, 255, .15); }
.tone-dark .ut-lot { fill: rgba(var(--sc-ink), .035); }

.hk-floor { fill: rgba(47, 128, 237, .11); }
.hk-board { fill: none; stroke: rgba(47, 128, 237, .18); stroke-width: 1.2; }
.hk-light { fill: url(#ajGlow); opacity: .22; }
.is-live .hk-light { animation: ajHkLight 9s var(--ease) infinite; }
@keyframes ajHkLight { 0%, 100% { opacity: .16; } 50% { opacity: .3; } }

/* the floor coming up, and the glints left behind */
.hk-shine-wrap { transform-box: view-box; }
.hk-shine { fill: #ffffff; opacity: .5; }
.is-live .hk-shine-wrap { animation: ajHkShine 7s var(--ease) infinite; }
@keyframes ajHkShine {
  0% { transform: translateX(0); }
  100% { transform: translateX(830px); }
}
.hk-glint { fill: var(--brand-2); opacity: 0; transform-box: fill-box; transform-origin: 50% 50%; }
.is-live .hk-glint { animation: ajHkGlint 7s var(--ease) infinite; animation-delay: var(--d, 0s); }
@keyframes ajHkGlint {
  0%, 4% { opacity: 0; transform: scale(.3) rotate(-25deg); }
  10% { opacity: 1; transform: scale(1) rotate(0deg); }
  24% { opacity: 0; transform: scale(.5) rotate(20deg); }
  100% { opacity: 0; transform: scale(.3) rotate(-25deg); }
}

/* her trolley and the caution sign */
.hk-trolley-body { fill: rgba(47, 128, 237, .2); stroke: rgba(47, 128, 237, .4); stroke-width: 1.3; }
.hk-trolley-bag { fill: rgba(47, 128, 237, .34); }
.hk-trolley-bottle { fill: var(--brand-2); opacity: .55; }
.hk-trolley-bar { fill: none; stroke: rgba(47, 128, 237, .45); stroke-width: 3.4; stroke-linecap: round; stroke-linejoin: round; }
.hk-wheel { fill: rgba(var(--sc-ink), .4); }
.hk-sign-face { fill: rgba(232, 163, 61, .3); stroke: rgba(232, 163, 61, .75); stroke-width: 1.6; stroke-linejoin: round; }
.hk-sign-fold { fill: none; stroke: rgba(232, 163, 61, .5); stroke-width: 1.2; }
.hk-sign-dot { fill: rgba(232, 163, 61, .95); }

/* the machine, and the stroke it is pushed through */
.hk-nozzle { fill: rgba(var(--sc-ink), .55); }
.hk-wand { fill: rgba(47, 128, 237, .5); }
.hk-vac-body { fill: var(--brand); }
.hk-grip { fill: rgba(var(--sc-ink), .6); }
.hk-vac-led { fill: var(--brand-2); }
.is-live .hk-vac-led { animation: ajBlink 1.8s var(--ease) infinite; }

/* dust drawn into the nozzle each time it goes forward */
.hk-mote { fill: rgba(var(--sc-ink), .3); opacity: 0; transform-box: fill-box; transform-origin: 50% 50%; }
.is-live .hk-mote { animation: ajHkMote var(--stroke) ease-in infinite; animation-delay: var(--d, 0s); }
@keyframes ajHkMote {
  0% { opacity: 0; transform: translate(0, 0) scale(1); }
  18% { opacity: .9; }
  60% { opacity: 0; transform: translate(-58px, 14px) scale(.2); }
  100% { opacity: 0; transform: translate(-58px, 14px) scale(.2); }
}

/* the housekeeper: uniform in AJNA blue under a green apron, so she reads as
   the same company as the officer without being the same figure */
.hk-shadow { fill: rgba(var(--sc-ink), .13); }
.hk-trouser { fill: #16304f; }
.hk-trouser--far { fill: #10233c; }
.hk-shoe { fill: #0b1c31; }
.hk-shoe--far { fill: #07152a; }
.hk-shirt { fill: #5aa3f2; }
.hk-sleeve { fill: none; stroke: #4b97ec; stroke-width: 15; stroke-linecap: round; }
.hk-sleeve--far { stroke: #3f88dd; stroke-width: 14; }
.hk-apron { fill: var(--brand-2); opacity: .9; }
.hk-apron-tie { fill: none; stroke: rgba(9, 24, 46, .3); stroke-width: 1.6; }
.hk-collar { fill: none; stroke: rgba(9, 24, 46, .35); stroke-width: 1.4; stroke-linejoin: round; }
.hk-hand { fill: #e7bd97; }
.hk-hand--far { fill: #d3a983; }
.hk-head { fill: #e7bd97; }
.hk-hair, .hk-bun { fill: #24344f; }

/* --- one stroke, five parts, one timeline ------------------------------ *
   Every set below is nine samples of the same sinusoidal stroke, so the
   machine, her shoulders, her lean and both arms are solved at exactly the
   same instants and interpolate together. The arm values are not eyeballed:
   for each sample the angle and scale are the ones that put that hand on the
   grip, worked out from the geometry in scratch (see the comment on the
   figure in includes/service-visuals.php).

   Because they share a timeline and a linear timing function, nothing can
   drift out of step with anything else.                                     */

/* --- one stroke, one body ---------------------------------------------- *
   Every set below is nine samples of the same sinusoid, so the machine and
   each joint are solved at the same instants and interpolate together. Only
   the machine translates; the body is all rotation about the joint beneath,
   which is why the waist stays on the hips and nothing slides.

   The arm values are not eyeballed. For each sample the grip is pulled back
   through the stance and torso rotations into the shoulder's own frame, and
   the angle and scale that land that hand on the handle fall out of the
   geometry.                                                                */

.hk-stroke { transform-box: view-box; }
.is-live .hk-stroke { animation: ajHkStroke var(--stroke) linear infinite; }
@keyframes ajHkStroke {
  0% { transform: translateX(-16.0px); }
  12.5% { transform: translateX(-11.3px); }
  25% { transform: translateX(-0.0px); }
  37.5% { transform: translateX(11.3px); }
  50% { transform: translateX(16.0px); }
  62.5% { transform: translateX(11.3px); }
  75% { transform: translateX(0.0px); }
  87.5% { transform: translateX(-11.3px); }
  100% { transform: translateX(-16.0px); }
}


/* the legs lean about the ankles, carrying the hips with them */
.hk-body { transform-box: view-box; transform-origin: 5px -6px; }
.is-live .hk-body { animation: ajHkStance var(--stroke) linear infinite; }
@keyframes ajHkStance {
  0% { transform: rotate(-4.00deg); }
  12.5% { transform: rotate(-2.83deg); }
  25% { transform: rotate(-0.00deg); }
  37.5% { transform: rotate(2.83deg); }
  50% { transform: rotate(4.00deg); }
  62.5% { transform: rotate(2.83deg); }
  75% { transform: rotate(0.00deg); }
  87.5% { transform: rotate(-2.83deg); }
  100% { transform: rotate(-4.00deg); }
}

/* the torso leans about the hips, carrying the shoulders with it */
.hk-upper { transform-box: view-box; transform-origin: 0 -55px; }
.is-live .hk-upper { animation: ajHkLean var(--stroke) linear infinite; }
@keyframes ajHkLean {
  0% { transform: rotate(-8.00deg); }
  12.5% { transform: rotate(-5.66deg); }
  25% { transform: rotate(-0.00deg); }
  37.5% { transform: rotate(5.66deg); }
  50% { transform: rotate(8.00deg); }
  62.5% { transform: rotate(5.66deg); }
  75% { transform: rotate(0.00deg); }
  87.5% { transform: rotate(-5.66deg); }
  100% { transform: rotate(-8.00deg); }
}

/* each arm pivots at its own shoulder and stretches onto the grip */
.hk-arm { transform-box: view-box; }
.hk-arm--near { transform-origin: 10px -79px; }
.hk-arm--far { transform-origin: -4px -81px; }
.is-live .hk-arm--near { animation: ajHkArmNear var(--stroke) linear infinite; }
.is-live .hk-arm--far { animation: ajHkArmFar var(--stroke) linear infinite; }
@keyframes ajHkArmNear {
  0% { transform: rotate(17.94deg) scaleX(0.8615); }
  12.5% { transform: rotate(13.95deg) scaleX(0.9007); }
  25% { transform: rotate(3.96deg) scaleX(0.9968); }
  37.5% { transform: rotate(-6.39deg) scaleX(1.0968); }
  50% { transform: rotate(-10.76deg) scaleX(1.1399); }
  62.5% { transform: rotate(-6.39deg) scaleX(1.0968); }
  75% { transform: rotate(3.96deg) scaleX(0.9968); }
  87.5% { transform: rotate(13.95deg) scaleX(0.9007); }
  100% { transform: rotate(17.94deg) scaleX(0.8615); }
}
@keyframes ajHkArmFar {
  0% { transform: rotate(34.86deg) scaleX(0.8597); }
  12.5% { transform: rotate(31.08deg) scaleX(0.9046); }
  25% { transform: rotate(21.61deg) scaleX(1.0073); }
  37.5% { transform: rotate(11.70deg) scaleX(1.1037); }
  50% { transform: rotate(7.47deg) scaleX(1.1423); }
  62.5% { transform: rotate(11.70deg) scaleX(1.1037); }
  75% { transform: rotate(21.61deg) scaleX(1.0073); }
  87.5% { transform: rotate(31.08deg) scaleX(0.9046); }
  100% { transform: rotate(34.86deg) scaleX(0.8597); }
}

/* ========================= 04  Utilities ================================ *
   The property's back of house, in plan -- the drawing facility management
   works from, and the one projection nothing else here uses.

   Everything is a solid architectural form. The previous pass drew open
   vessels under a chart recorder, and glassware plus a graph reads as a
   laboratory bench rather than a building being run; there is deliberately
   no transparent vessel and no instrument in this one.

   --plant is the clock for the treatment compound. The charge crossing the
   main and the four chamber flashes run off it together, each chamber
   delayed by the time the charge actually takes to reach it, so a chamber
   lights because the flow arrived rather than on a rhythm of its own. Those
   delays are computed in the markup from the chamber's own position. */

.sc4 { --plant: 6s; --round: 9s; }

/* the lot, and one line around all of it */
.ut-lot { fill: rgba(var(--sc-ink), .02); stroke: rgba(47, 128, 237, .34); stroke-width: 1.8; stroke-dasharray: 9 7; }
.ut-zone { fill: rgba(var(--sc-ink), .05); stroke: var(--card-line); stroke-width: 1.6; }

/* the building */
.ut-built { fill: rgba(var(--sc-ink), .11); stroke: var(--card-line); stroke-width: 1.8; }
.ut-core { stroke: rgba(var(--sc-ink), .2); stroke-width: 1.6; stroke-linejoin: round; }
.ut-plant { fill: rgba(var(--sc-ink), .2); }
.ut-tankwell { fill: var(--card); }
.ut-tankline { fill: none; stroke: var(--card-line); stroke-width: 1.8; }
.ut-tankfill { fill: rgba(47, 128, 237, .34); }
.ut-tanklvl { transform-box: view-box; }
.is-live .ut-tanklvl { animation: ajUtTank 8.5s ease-in-out infinite; }
@keyframes ajUtTank { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-11px); } }

/* the pool */
.ut-deck { fill: rgba(var(--sc-ink), .07); stroke: var(--card-line); stroke-width: 1.6; }
.ut-pool { fill: rgba(47, 128, 237, .36); }
.ut-lane { stroke: rgba(255, 255, 255, .5); stroke-width: 1.6; stroke-dasharray: 16 12; }
.ut-ladder { stroke: rgba(var(--sc-ink), .28); stroke-width: 2; stroke-linecap: round; }
.ut-skim { fill: var(--card); stroke: var(--card-line); stroke-width: 1.6; }
.ut-flowdot { fill: rgba(255, 255, 255, .8); transform-box: view-box; }
.is-live .ut-flowdot { animation: ajUtDrift var(--t, 5.4s) linear infinite; animation-delay: var(--d, 0s); }
@keyframes ajUtDrift {
  0% { transform: translateX(0); opacity: 0; }
  15% { opacity: .9; }
  85% { opacity: .9; }
  100% { transform: translateX(var(--run)); opacity: 0; }
}

/* the treatment compound */
.ut-main { stroke: rgba(47, 128, 237, .22); stroke-width: 7; stroke-linecap: round; }
.ut-cell { fill: var(--card); stroke: var(--card-line); stroke-width: 1.6; }
.ut-cell-on { fill: rgba(20, 221, 115, .3); stroke: var(--brand-2); stroke-width: 1.8; opacity: 0; }
.is-live .ut-cell-on { animation: ajUtCell var(--plant) linear infinite; animation-delay: var(--d, 0s); }
@keyframes ajUtCell {
  0% { opacity: 0; }
  7% { opacity: 1; }
  22% { opacity: 0; }
  100% { opacity: 0; }
}
.ut-manhole { fill: rgba(var(--sc-ink), .14); stroke: rgba(var(--sc-ink), .26); stroke-width: 1.6; }
.ut-manhole-l { stroke: rgba(var(--sc-ink), .26); stroke-width: 1.4; }
.ut-charge { fill: var(--brand); transform-box: view-box; }
.is-live .ut-charge { animation: ajUtCharge var(--plant) linear infinite; }
@keyframes ajUtCharge {
  0% { transform: translateX(0); opacity: 0; }
  6% { opacity: 1; }
  94% { opacity: 1; }
  100% { transform: translateX(244px); opacity: 0; }
}

/* the bin bay. Bins fill through the round, then the collection empties them. */
.ut-bin { fill: var(--card); }
.ut-binline { fill: none; stroke: var(--card-line); stroke-width: 1.6; }
.ut-binlid { stroke: rgba(var(--sc-ink), .22); stroke-width: 1.8; stroke-linecap: round; }
.ut-binlvl { transform-box: view-box; }
.ut-binfill--0 { fill: rgba(20, 221, 115, .42); }
.ut-binfill--1 { fill: rgba(47, 128, 237, .36); }
.ut-binfill--2 { fill: rgba(232, 163, 61, .42); }
.ut-binfill--3 { fill: rgba(116, 128, 148, .36); }
.is-live .ut-binlvl { animation: ajUtBin var(--round) ease-in-out infinite; animation-delay: var(--d, 0s); }
@keyframes ajUtBin {
  0% { transform: translateY(38px); }
  64% { transform: translateY(8px); }
  76% { transform: translateY(38px); }
  100% { transform: translateY(38px); }
}
.ut-bay { stroke: rgba(var(--sc-ink), .14); stroke-width: 5; stroke-linecap: round; stroke-dasharray: 8 8; }

/* the record */
.ut-sheet { stroke: rgba(var(--sc-ink), .16); stroke-width: 3; stroke-linecap: round; }
.ut-stamp-r { fill: none; stroke: var(--brand-2); stroke-width: 2.6; }
.ut-stamp-t { fill: none; stroke: var(--brand-2); stroke-width: 3.4; stroke-linecap: round; stroke-linejoin: round; }
.ut-stamp { transform-box: view-box; transform-origin: 0 0; opacity: 1; }
.is-live .ut-stamp { animation: ajUtStamp var(--round) ease-out infinite; }
@keyframes ajUtStamp {
  0% { transform: scale(1.9) rotate(-9deg); opacity: 0; }
  9% { transform: scale(1) rotate(-9deg); opacity: 1; }
  80% { transform: scale(1) rotate(-9deg); opacity: 1; }
  94%, 100% { transform: scale(1) rotate(-9deg); opacity: 0; }
}

/* pest control, held around the perimeter */
.ut-bait { fill: var(--card); stroke: var(--card-line); stroke-width: 1.6; }
.ut-cover { fill: none; stroke: var(--brand-2); stroke-width: 2; opacity: 0; transform-box: fill-box; transform-origin: 50% 50%; }
.is-live .ut-cover { animation: ajUtCover 4.4s ease-out infinite; animation-delay: var(--d, 0s); }
@keyframes ajUtCover {
  0% { transform: scale(.5); opacity: .6; }
  78%, 100% { transform: scale(2.4); opacity: 0; }
}

/* captions */
.ut-k { font-size: 8.8px; font-weight: 700; letter-spacing: .18em; fill: var(--text-3); }
.ut-tag { font-size: 9.4px; font-weight: 700; letter-spacing: .12em; fill: var(--text-3); }
.ut-tag--mid { text-anchor: middle; }

/* ========================= 05  Technical ================================ *
   The board and what it feeds. Everything here runs on its own clock: the
   fast loops are the current in the conductors and the air off the fan, and
   the slow one — --sys — is the fault.

   That slow loop is the whole point of the section. At 41% the pump's
   breaker snaps off, its conductor turns amber and goes dead, and the
   impeller coasts down rather than stopping dead. It sits still while a
   service pulse travels out along the conductor, and at 71% the breaker is
   reset and the impeller spins back up. Preventive work is the flow that
   never stops; the breakdown is the one that does.

   The impeller's totals are chosen so the loop closes seamlessly: it ends
   on 1728deg, a whole multiple of the 72deg vane spacing, and the two
   running stretches turn at the same 24deg per unit of the timeline, so
   only the coast and the pick-up read as a change of speed. */

.sc5 { --sys: 13s; --flow: 1.5s; }

/* the enclosure */
.tm-case { fill: var(--card); stroke: var(--card-line); stroke-width: 1.8; }
.tm-case-top { fill: rgba(47, 128, 237, .07); stroke: var(--card-line); stroke-width: 1.4; }
.tm-case-side { fill: rgba(47, 128, 237, .13); stroke: var(--card-line); stroke-width: 1.4; }
.tm-panel { fill: rgba(var(--sc-ink), .03); stroke: var(--card-line); stroke-width: 1.2; }
.tm-note { font-size: 8.6px; font-weight: 700; letter-spacing: .16em; fill: var(--text-3); }

/* incoming supply, and the busbar it lands on */
.tm-incomer { stroke: rgba(47, 128, 237, .16); stroke-width: 9; stroke-linecap: round; }
.tm-incomer-live { stroke: var(--brand); stroke-width: 3; stroke-linecap: round; stroke-dasharray: 9 24; }
.is-live .tm-incomer-live { animation: ajTmRun var(--flow) linear infinite; }

.tm-bus { fill: rgba(47, 128, 237, .15); }
.tm-bus-live { fill: url(#ajGrad); transform-box: view-box; opacity: 0; }
.is-live .tm-bus-live { animation: ajTmBus 3.4s linear infinite; }
@keyframes ajTmBus {
  0%   { transform: translateX(0); opacity: 0; }
  20%  { opacity: .85; }
  80%  { opacity: .85; }
  100% { transform: translateX(134px); opacity: 0; }
}

/* the breakers */
.tm-rail { fill: rgba(var(--sc-ink), .1); }
.tm-mcb-body { fill: var(--card); stroke: var(--card-line); stroke-width: 1.6; }
.tm-mcb-slot { fill: rgba(var(--sc-ink), .09); }
.tm-lever-bar { fill: rgba(var(--sc-ink), .32); }
.tm-led { fill: var(--brand-2); }
.is-live .tm-led { animation: ajTmBreathe 2.8s ease-in-out infinite; }
@keyframes ajTmBreathe { 0%, 100% { opacity: .5; } 50% { opacity: 1; } }

/* the lever pivots at its own foot, which sits at 18,24 inside the
   breaker's translate — hence view-box with explicit local values. */
.tm-lever { transform-box: view-box; transform-origin: 18px 24px; }
.is-live .tm-mcb--trip .tm-lever { animation: ajTmTrip var(--sys) linear infinite; }
@keyframes ajTmTrip {
  0%, 40%   { transform: rotate(0deg); }
  42%, 71%  { transform: rotate(-34deg); }
  73%, 100% { transform: rotate(0deg); }
}
.is-live .tm-mcb--trip .tm-led {
  animation: ajTmBreathe 2.8s ease-in-out infinite, ajTmFault var(--sys) linear infinite;
}
@keyframes ajTmFault {
  0%, 40%   { fill: var(--brand-2); }
  43%, 70%  { fill: #e8a33d; }
  73%, 100% { fill: var(--brand-2); }
}

/* the load reading */
.tm-meter-bar { fill: url(#ajGrad); transform-box: fill-box; transform-origin: 50% 100%; opacity: .75; }
.is-live .tm-meter-bar { animation: ajTmMeter 2.4s ease-in-out infinite; animation-delay: var(--d, 0s); }
@keyframes ajTmMeter { 0%, 100% { transform: scaleY(.38); } 50% { transform: scaleY(1); } }

/* the four circuits */
.tm-run, .tm-lead { stroke: rgba(47, 128, 237, .16); stroke-width: 4.5; stroke-linecap: round; stroke-linejoin: round; }
.tm-flow { stroke: var(--brand); stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 9 26; }
.is-live .tm-flow { animation: ajTmRun var(--flow) linear infinite; animation-delay: var(--d, 0s); }
@keyframes ajTmRun { to { stroke-dashoffset: -35px; } }

/* circuit 2 is the one that drops out */
.is-live .tm-run--drop { animation: ajTmDim var(--sys) linear infinite; }
@keyframes ajTmDim {
  0%, 40%   { stroke: rgba(47, 128, 237, .16); }
  43%, 70%  { stroke: rgba(232, 163, 61, .38); }
  73%, 100% { stroke: rgba(47, 128, 237, .16); }
}
.is-live .tm-flow--drop, .is-live .tm-pipe-flow {
  animation: ajTmRun var(--flow) linear infinite, ajTmDead var(--sys) linear infinite;
  animation-delay: var(--d, 0s), 0s;
}
@keyframes ajTmDead {
  0%, 40%   { opacity: 1; }
  44%, 70%  { opacity: 0; }
  73%, 100% { opacity: 1; }
}

/* the service pulse. Its circles are centred on the group's own origin, so
   the default offset-anchor lands the dot exactly on the conductor. */
.tm-service { transform-box: fill-box; transform-origin: 50% 50%; offset-rotate: 0deg; opacity: 0; }
.tm-service-halo { fill: rgba(20, 221, 115, .22); }
.tm-service-dot { fill: var(--brand-2); }
.is-live .tm-service { animation: ajTmService var(--sys) linear infinite; }
@keyframes ajTmService {
  0%, 49%   { offset-distance: 0%; opacity: 0; }
  52%       { offset-distance: 4%; opacity: 1; }
  66%       { offset-distance: 96%; opacity: 1; }
  69%, 100% { offset-distance: 100%; opacity: 0; }
}

/* lighting */
.tm-load-k { font-size: 9px; font-weight: 700; letter-spacing: .14em; fill: var(--text-3); }
.tm-fitting { fill: var(--card); stroke: var(--card-line); stroke-width: 1.8; }
.tm-lamp { fill: rgba(247, 201, 108, .5); }
.is-live .tm-lamp { animation: ajTmLamp 4.6s ease-in-out infinite; }
@keyframes ajTmLamp { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }

/* air handling unit */
.tm-ahu { fill: var(--card); stroke: var(--card-line); stroke-width: 1.8; }
.tm-fan-ring { stroke: rgba(47, 128, 237, .2); stroke-width: 2; }
.tm-blade { fill: rgba(47, 128, 237, .3); }
.tm-vane { fill: rgba(47, 128, 237, .32); }
.tm-hub { fill: var(--brand); }
.tm-fan { transform-box: view-box; transform-origin: 0 0; }
.is-live .tm-fan { animation: ajTmSpin 2.4s linear infinite; }
@keyframes ajTmSpin { to { transform: rotate(360deg); } }
.tm-air { stroke: var(--brand); stroke-width: 2.4; stroke-linecap: round; stroke-dasharray: 11 15; opacity: .45; }
.is-live .tm-air { animation: ajTmAir 1.1s linear infinite; }
@keyframes ajTmAir { to { stroke-dashoffset: -26px; } }

/* pump set */
.tm-pump { fill: var(--card); stroke: var(--card-line); stroke-width: 2; }
.tm-flange { fill: rgba(var(--sc-ink), .16); }
.tm-plinth { fill: rgba(var(--sc-ink), .1); }
.tm-pipe { stroke: rgba(47, 128, 237, .13); stroke-width: 11; stroke-linecap: round; stroke-linejoin: round; }
.tm-pipe-flow { stroke: rgba(47, 128, 237, .5); stroke-width: 5; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 10 22; }

.tm-impeller { transform-box: view-box; transform-origin: 0 0; }
.is-live .tm-impeller { animation: ajTmPump var(--sys) linear infinite; }
@keyframes ajTmPump {
  0%   { transform: rotate(0deg); }
  40%  { transform: rotate(960deg); animation-timing-function: ease-out; }
  50%  { transform: rotate(1068deg); }
  71%  { transform: rotate(1068deg); animation-timing-function: ease-in; }
  76%  { transform: rotate(1128deg); }
  100% { transform: rotate(1728deg); }
}

.tm-alarm { transform-box: view-box; transform-origin: 500px 275px; }
.tm-alarm-ring { stroke: #e8a33d; stroke-width: 2.6; stroke-dasharray: 7 10; stroke-linecap: round; opacity: 0; }
.is-live .tm-alarm { animation: ajTmSpin 7s linear infinite; }
.is-live .tm-alarm-ring { animation: ajTmAlarm var(--sys) linear infinite; }
@keyframes ajTmAlarm {
  0%, 41%   { opacity: 0; }
  44%, 69%  { opacity: .95; }
  72%, 100% { opacity: 0; }
}

/* the isolating valve on the discharge: wound shut while the pump is down */
.tm-valve-body { fill: rgba(47, 128, 237, .26); }
.tm-valve-stem { stroke: rgba(var(--sc-ink), .3); stroke-width: 3; stroke-linecap: round; }
.tm-wheel-rim { fill: none; stroke: rgba(var(--sc-ink), .34); stroke-width: 3; }
.tm-wheel-spoke { stroke: rgba(var(--sc-ink), .34); stroke-width: 2.4; stroke-linecap: round; }
.tm-wheel { transform-box: view-box; transform-origin: 0 0; }
.is-live .tm-wheel { animation: ajTmWheel var(--sys) linear infinite; }
@keyframes ajTmWheel {
  0%, 43%   { transform: rotate(0deg); }
  55%, 62%  { transform: rotate(-166deg); }
  72%, 100% { transform: rotate(0deg); }
}

/* the lamp itself, and the duct the fan discharges into */
.tm-tube { fill: rgba(247, 201, 108, .85); }
.tm-duct { fill: rgba(47, 128, 237, .07); stroke: var(--card-line); stroke-width: 1.6; }

/* sub-board */
.tm-sub { fill: var(--card); stroke: var(--card-line); stroke-width: 1.8; }
.tm-sub-row { stroke: rgba(47, 128, 237, .2); stroke-width: 4; stroke-linecap: round; }
.tm-sub-led { fill: var(--brand-2); }
.is-live .tm-sub-led { animation: ajTmBreathe 3.4s ease-in-out infinite; }

/* ========================= 06  Technology =============================== *
   Device scale, on the angle. The beam and the plate answer each other on
   one loop; the log arrives from the right rather than fading up. */

.sc6-wall { fill: rgba(255, 255, 255, .028); stroke: rgba(255, 255, 255, .1); stroke-width: 1.4; }
.sc6-plate { fill: rgba(20, 221, 115, .05); stroke: rgba(20, 221, 115, .34); stroke-width: 1.6; }
.sc6-mod { fill: var(--brand-2); opacity: .8; }
.sc6-fp { fill: none; stroke: var(--brand-2); stroke-width: 4; }
.sc6-fpc { fill: var(--brand-2); }
.sc6-plate-k { font-size: 9px; font-weight: 600; letter-spacing: .16em; fill: rgba(255, 255, 255, .45); }
.sc6-hit { fill: rgba(20, 221, 115, .26); opacity: 0; }
.is-live .sc6-hit { animation: ajHit 4.4s var(--ease) infinite; }
@keyframes ajHit { 0%, 50% { opacity: 0; } 57% { opacity: 1; } 74%, 100% { opacity: 0; } }

.sc6-beam path { fill: url(#ajGlow); }
.sc6-beam { opacity: 0; }
.is-live .sc6-beam { animation: ajBeamOn 4.4s var(--ease) infinite; }
@keyframes ajBeamOn { 0%, 32% { opacity: 0; } 44%, 66% { opacity: .9; } 80%, 100% { opacity: 0; } }

.sc6-arm { fill: none; stroke: #2f80ed; stroke-width: 56; stroke-linecap: round; opacity: .5; }
.sc6-palm { fill: #2f80ed; opacity: .82; }
.sc6-grip rect { fill: #3f8cef; }
.sc6-hold { transform-box: fill-box; transform-origin: 50% 100%; }
.is-live .sc6-hold { animation: ajHold 6s var(--ease) infinite; }
.sc6-phone { fill: #0d1727; stroke: rgba(255, 255, 255, .24); stroke-width: 1.6; }
.sc6-screen { fill: #060c17; }
.sc6-vf { fill: none; stroke: var(--brand-2); stroke-width: 2.6; stroke-linecap: round; }
.sc6-vf-fill { fill: rgba(20, 221, 115, .12); }
.sc6-vf-scan { fill: url(#ajGrad); }
.is-live .sc6-vf-scan { animation: ajVf 2.2s var(--ease) infinite; }
@keyframes ajVf { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(56px); } }
.sc6-phone-k { font-size: 8px; font-weight: 600; letter-spacing: .22em; fill: rgba(255, 255, 255, .45); text-anchor: middle; }
@keyframes ajHold { 0%, 100% { transform: rotate(0); } 50% { transform: rotate(-1.4deg); } }

.sc6-log-k { font-size: 9px; font-weight: 600; letter-spacing: .16em; fill: rgba(255, 255, 255, .45); }
.sc6-row-bg { fill: rgba(255, 255, 255, .05); stroke: rgba(255, 255, 255, .12); stroke-width: 1.2; }
.sc6-row-dot { fill: rgba(20, 221, 115, .14); stroke: var(--brand-2); stroke-width: 1.6; }
.sc6-row-tick { fill: none; stroke: var(--brand-2); stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.sc6-row-t { font-size: 10.5px; font-weight: 600; fill: #fff; }
.sc6-row-k { font-size: 8.6px; letter-spacing: .04em; fill: rgba(255, 255, 255, .55); }
.sc6-row { transform-box: view-box; }
.is-live .sc6-row { animation: ajRowIn .75s var(--ease-out) both; animation-delay: var(--d, 0s); }
@keyframes ajRowIn { from { opacity: 0; transform: translateX(40px); } to { opacity: 1; transform: none; } }

.sc6-route-line { stroke: rgba(255, 255, 255, .13); stroke-width: 3; stroke-linecap: round; }
.sc6-route-done { stroke: url(#ajGrad); stroke-width: 3; stroke-linecap: round; stroke-dasharray: 250px; stroke-dashoffset: 250px; }
.is-live .sc6-route-done { animation: ajRoute 6.6s var(--ease) infinite; }
@keyframes ajRoute { 0% { stroke-dashoffset: 250px; } 72%, 100% { stroke-dashoffset: 0; } }
.sc6-stop { fill: rgba(255, 255, 255, .16); }
.is-live .sc6-stop { animation: ajStopOn 6.6s var(--ease) infinite; animation-delay: var(--d, 0s); }
@keyframes ajStopOn { 0%, 5% { fill: rgba(255, 255, 255, .16); } 12%, 100% { fill: #14dd73; } }
.sc6-route-k { font-size: 9.5px; letter-spacing: .04em; fill: rgba(255, 255, 255, .45); }

/* --- keyframes the hero graphics below still rely on -------------------- */

@keyframes vLight {
  0%, 12% { opacity: .1; }
  22%, 62% { opacity: .78; }
  76%, 100% { opacity: .1; }
}
@keyframes vNodePulse {
  0%, 100% { opacity: .35; transform: scale(1); }
  40% { opacity: 1; transform: scale(1.12); }
}
@keyframes vPatrol { from { stroke-dashoffset: 1460; } to { stroke-dashoffset: 0; } }
@keyframes vSpin { to { transform: rotate(360deg); } }

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

.aj-skyline-band {
  position: relative;
  height: clamp(165px, 19vw, 262px);
  background: var(--ink);
  overflow: hidden;
}
.aj-skyline-band .aj-skyline { z-index: 0; }

.aj-skyline {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: -1;
  width: 100%;
  height: clamp(165px, 19vw, 262px);
  pointer-events: none;
}
.sk-body { fill: rgba(47, 128, 237, .12); stroke: rgba(47, 128, 237, .42); stroke-width: 1; }
.sk-win { fill: #6fb4ff; opacity: .14; }
.js .sk-win { animation: vLight 7s var(--ease) infinite; animation-delay: var(--d, 0s); }
.sk-link { fill: none; stroke: rgba(47, 128, 237, .38); stroke-width: 1.2; stroke-dasharray: 3 6; }
.sk-link-run { fill: none; stroke: var(--brand-2); stroke-width: 2; stroke-linecap: round; stroke-dasharray: 60 1200; }
.js .sk-link-run { animation: vPatrol 6.5s linear infinite; }
.sk-node-ring { fill: none; stroke: var(--brand-2); stroke-width: 1.2; opacity: .55; }
.sk-node-dot { fill: var(--brand-2); }
.sk-node { transform-box: fill-box; transform-origin: 50% 50%; }
.js .sk-node { animation: vNodePulse 3.2s var(--ease) infinite; animation-delay: var(--d, 0s); }

/* the live operations readout */

/* --- the hero graphic: a property as a digital twin --------------------- *
   Everything here runs on its own clock. Nothing reads scroll position, so
   the graphic is already moving when the page opens and never stops.        */

.aj-twin {
  width: 100%;
  max-width: 470px;
  height: auto;
  overflow: visible;
}

.tw-glow { opacity: .5; }
.js .tw-glow { animation: twGlow 7s var(--ease) infinite; }
@keyframes twGlow { 0%, 100% { opacity: .38; } 50% { opacity: .62; } }
.tw-shadow { fill: rgba(4, 9, 18, .55); }

/* the stack: three faces a slab, lit from the front-left */
.tw-face { fill: rgba(47, 128, 237, .17); stroke: rgba(120, 185, 255, .5); stroke-width: 1.3; }
.tw-top { fill: rgba(120, 185, 255, .3); stroke: rgba(120, 185, 255, .5); stroke-width: 1.3; }
.tw-side { fill: rgba(20, 40, 78, .72); stroke: rgba(120, 185, 255, .38); stroke-width: 1.3; }

/* the tower breathes very slightly, each slab a beat behind the one below */
.tw-slab { transform-box: view-box; }
.js .tw-slab { animation: twLift 9s var(--ease) infinite; animation-delay: calc(var(--i) * .28s); }
@keyframes twLift { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } }

.tw-win { fill: #8fc8ff; opacity: .2; }
.js .tw-win { animation: twWin 6s var(--ease) infinite; animation-delay: var(--d, 0s); }
@keyframes twWin {
  0%, 16% { opacity: .16; }
  28%, 60% { opacity: .92; }
  74%, 100% { opacity: .16; }
}

/* the survey plane running the height of the building */
.tw-scan { transform-box: view-box; }
.js .tw-scan { animation: twScan 6.5s var(--ease) infinite; }
@keyframes twScan {
  0% { transform: translateY(492px); opacity: 0; }
  12%, 76% { opacity: 1; }
  100% { transform: translateY(136px); opacity: 0; }
}
.tw-scan-disc { fill: rgba(20, 221, 115, .12); }
.tw-scan-ring { fill: none; stroke: var(--brand-2); stroke-width: 2; opacity: .85; }

/* the orbits, and the node each one carries */
.tw-orbit-path { fill: none; stroke: rgba(140, 195, 255, .45); stroke-width: 1.8; stroke-dasharray: 6 10; }
.tw-orbit--b .tw-orbit-path { stroke: rgba(20, 221, 115, .48); }
.tw-orbit-node { offset-rotate: 0deg; offset-distance: 0%; }
.js .tw-orbit-node { animation: twOrbit var(--dur, 20s) linear infinite; }
@keyframes twOrbit { to { offset-distance: 100%; } }
.tw-node-dot { fill: var(--brand-2); }
.tw-orbit--a .tw-node-dot { fill: #6fb4ff; }
.tw-node-halo { fill: rgba(20, 221, 115, .22); }
.tw-orbit--a .tw-node-halo { fill: rgba(111, 180, 255, .22); }
.js .tw-node-halo { animation: twHalo 2.4s var(--ease) infinite; transform-box: fill-box; transform-origin: 50% 50%; }
@keyframes twHalo { 0%, 100% { transform: scale(.7); opacity: .8; } 50% { transform: scale(1.25); opacity: .25; } }

/* abstract readout chips, each on its own timing */
.tw-chip-bg { fill: rgba(255, 255, 255, .07); stroke: rgba(255, 255, 255, .14); stroke-width: 1; }
.tw-chip-dot { fill: var(--brand-2); }
.tw-chip-bar { fill: rgba(255, 255, 255, .34); }
.tw-chip-bar--short { fill: rgba(255, 255, 255, .18); }
.tw-chip { transform-box: view-box; }
.js .tw-chip { animation: twChip 8s var(--ease) infinite; animation-delay: var(--d, 0s); }
@keyframes twChip { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-9px); } }
.js .tw-chip-dot { animation: ajBlink 2.6s var(--ease) infinite; animation-delay: var(--d, 0s); }

@media (max-width: 1079px) {
  .aj-twin { max-width: 380px; }
}
@media (max-width: 479px) {
  .aj-twin { max-width: 290px; }
}

/* 11  Gallery & lightbox ================================================= *
   Twenty-two photographs is a lot of wall, so the job here is rhythm and a
   place for the eye to land. The grid is an explicit twelve columns rather
   than auto-fill, which is what lets the opening frame take a lead slot and
   the portraits take tall ones -- the tile shapes are chosen in PHP from each
   file's own dimensions, so nothing is measured at runtime and nothing shifts
   while the images load.

   The spotlight is the part that does the work: hovering one photograph steps
   every other one back, so a dense wall resolves to a single subject instead
   of competing for attention. It is behind a hover query, because on a touch
   screen there is no hover to end and the wall would simply sit dimmed. */

.aj-gal-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px 20px;
  margin-bottom: 26px;
}
.aj-gal-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.aj-gal-filter {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 9px 17px;
  border: 1px solid var(--card-line);
  border-radius: 999px;
  background: var(--card);
  color: var(--text-2);
  font: inherit;
  font-size: .84rem;
  font-weight: 600;
  cursor: pointer;
  transition: transform .35s var(--ease), color .3s var(--ease),
              border-color .3s var(--ease), background .3s var(--ease);
}
.aj-gal-n {
  font-size: .68rem;
  font-weight: 700;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  transition: color .3s var(--ease);
}
.aj-gal-filter:hover { transform: translateY(-2px); color: var(--text); border-color: var(--brand); }
.aj-gal-filter[aria-pressed="true"] {
  background: linear-gradient(120deg, var(--brand), var(--brand-2));
  border-color: transparent;
  color: #fff;
}
.aj-gal-filter[aria-pressed="true"] .aj-gal-n { color: rgba(255, 255, 255, .8); }
.aj-gal-meta {
  margin: 0;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .08em;
  color: var(--text-3);
}

.aj-gal {
  display: grid;
  /* two even columns until there is room for the twelve-column bands */
  grid-template-columns: repeat(2, 1fr);
  grid-auto-rows: 132px;
  gap: 14px;
}
.aj-gal-item {
  position: relative;
  margin: 0;
  grid-column: span 1;
  grid-row: span 2;
  border-radius: var(--r);
  overflow: hidden;
  background: var(--paper-3);
  transition: opacity .45s var(--ease), transform .45s var(--ease-out),
              box-shadow .45s var(--ease);
}
.aj-gal-item.is-out,
.aj-gal-item.is-hidden { display: none; }

/* the spotlight */
@media (hover: hover) {
  .aj-gal:hover .aj-gal-item { opacity: .42; }
  .aj-gal .aj-gal-item:hover,
  .aj-gal .aj-gal-item:focus-within {
    opacity: 1;
    transform: translateY(-4px);
    box-shadow: var(--shadow-lg);
  }
}

.aj-gal-btn {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  text-align: left;
  cursor: zoom-in;
}
.aj-gal-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .8s var(--ease-out);
}
.aj-gal-item::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(10, 17, 32, 0) 34%, rgba(10, 17, 32, .84) 100%);
  opacity: .58;
  transition: opacity .45s var(--ease);
  pointer-events: none;
}
.aj-gal-item:hover img, .aj-gal-btn:focus-visible img { transform: scale(1.06); }
.aj-gal-item:hover::after { opacity: .95; }

/* the frame number, which is what makes it read as a record rather than a
   pile of pictures */
.aj-gal-no {
  position: absolute;
  top: 13px;
  left: 16px;
  z-index: 2;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .14em;
  color: rgba(255, 255, 255, .92);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 8px rgba(10, 17, 32, .6);
  pointer-events: none;
}
.aj-gal-tag {
  position: absolute;
  top: 11px;
  right: 13px;
  z-index: 2;
  padding: 5px 11px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .17);
  backdrop-filter: blur(7px);
  -webkit-backdrop-filter: blur(7px);
  color: #fff;
  font-size: .63rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(-7px);
  transition: opacity .4s var(--ease), transform .45s var(--ease-out);
  pointer-events: none;
}
.aj-gal-item:hover .aj-gal-tag,
.aj-gal-btn:focus-visible .aj-gal-tag { opacity: 1; transform: none; }

.aj-gal-cap {
  position: absolute;
  inset: auto 0 0;
  z-index: 2;
  padding: 18px;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  color: #fff;
  pointer-events: none;
}
.aj-gal-cap-txt { display: block; min-width: 0; }
.aj-gal-t {
  display: block;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -.01em;
  transform: translateY(10px);
  transition: transform .45s var(--ease-out);
}
.aj-gal-d {
  display: block;
  margin-top: 4px;
  font-size: .78rem;
  line-height: 1.45;
  color: rgba(255, 255, 255, .78);
  opacity: 0;
  max-height: 0;
  overflow: hidden;
  transform: translateY(10px);
  transition: opacity .4s var(--ease), transform .45s var(--ease-out), max-height .45s var(--ease);
}
.aj-gal-item:hover .aj-gal-t,
.aj-gal-btn:focus-visible .aj-gal-t { transform: none; }
.aj-gal-item:hover .aj-gal-d,
.aj-gal-btn:focus-visible .aj-gal-d { opacity: 1; max-height: 4em; transform: none; }
.aj-gal-zoom {
  flex: none;
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(255, 255, 255, .16);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transform: scale(.6);
  opacity: 0;
  transition: transform .45s var(--ease-out), opacity .35s var(--ease);
}
.aj-gal-item:hover .aj-gal-zoom,
.aj-gal-btn:focus-visible .aj-gal-zoom { transform: none; opacity: 1; }

.aj-gal-more {
  display: flex;
  justify-content: center;
  margin-top: 30px;
}

/* the bands only exist where there is width for twelve columns; below that
   every frame is one of two even tiles, which packs without holes too */
@media (min-width: 1024px) {
  .aj-gal { grid-template-columns: repeat(12, 1fr); grid-auto-rows: 96px; gap: 16px; }
  .aj-gal-item { grid-column: span var(--c, 4); grid-row: span var(--r, 2); }
}
@media (max-width: 639px) {
  .aj-gal { grid-auto-rows: 104px; gap: 10px; }
  .aj-gal-cap { padding: 12px; }
  .aj-gal-t { font-size: .84rem; transform: none; }
  .aj-gal-d, .aj-gal-zoom { display: none; }
  .aj-gal-no { top: 9px; left: 11px; font-size: .64rem; }
  .aj-gal-tag { display: none; }
  .aj-gal-tools { justify-content: flex-start; }
}

/* lightbox */
.aj-lb {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  padding: 16px clamp(12px, 3vw, 28px) 18px;
  background: rgba(6, 11, 21, .94);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  opacity: 0;
  visibility: hidden;
  transition: opacity .35s var(--ease), visibility .35s;
}
.aj-lb.is-open { opacity: 1; visibility: visible; }
.aj-lb-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  color: rgba(255, 255, 255, .7);
}
.aj-lb-count { font-size: .82rem; letter-spacing: .12em; font-variant-numeric: tabular-nums; }

/* The stage is the 1fr row, so it has a definite height and the picture
   below can be capped against it. minmax(0, 1fr) rather than 1fr: a bare
   1fr floors at min-content, which is the intrinsic height of the image and
   exactly the overflow this replaced. */
.aj-lb-stage {
  position: relative;
  min-height: 0;
}
.aj-lb-stage img {
  position: absolute;
  inset: 0;
  margin: auto;
  /* the cap keeps a wide picture from running under the arrows */
  max-width: calc(100% - 116px);
  max-height: 100%;
  width: auto;
  height: auto;
  border-radius: var(--r);
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, .9);
  opacity: 0;
  transform: scale(.97);
  transition: opacity .4s var(--ease-out), transform .5s var(--ease-out);
}
.aj-lb-stage img.is-ready { opacity: 1; transform: none; }
.aj-lb-cap {
  width: min(100%, max(340px, var(--lb-w, 720px)));
  margin-inline: auto;
  text-align: center;
  color: #fff;
  padding: 18px 0 2px;
  transition: width .35s var(--ease);
}
.aj-lb-cap b { display: block; font-family: var(--font-display); font-size: 1.06rem; }
.aj-lb-cap span { font-size: .85rem; color: rgba(255, 255, 255, .62); }
.aj-lb-btn {
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: #fff;
  background: rgba(255, 255, 255, .1);
  border: 1px solid rgba(255, 255, 255, .16);
  transition: background-color .3s var(--ease), transform .3s var(--ease);
}
.aj-lb-btn:hover { background: rgba(255, 255, 255, .22); transform: scale(1.06); }
.aj-lb-btn .aj-icon { width: 20px; height: 20px; }
.aj-lb-prev, .aj-lb-next {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
}
.aj-lb-prev { left: 0; }
.aj-lb-next { right: 0; }
.aj-lb-prev:hover, .aj-lb-next:hover { transform: translateY(-50%) scale(1.06); }

@media (max-width: 639px) {
  .aj-lb-stage img { max-width: 100%; max-height: calc(100% - 62px); margin: auto auto 62px; }
  .aj-lb-prev, .aj-lb-next { top: auto; bottom: -4px; transform: none; }
  .aj-lb-prev:hover, .aj-lb-next:hover { transform: none; }
  .aj-lb-prev { left: 24%; }
  .aj-lb-next { right: 24%; }
}

/* 12  Contact ============================================================ */

.aj-contact { position: relative; overflow: hidden; }
.aj-contact::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(46% 60% at 84% 8%, rgba(47, 128, 237, .32), transparent 68%),
    radial-gradient(42% 58% at 6% 92%, rgba(20, 221, 115, .2), transparent 68%);
  pointer-events: none;
}
.aj-contact .wrap { position: relative; }

.aj-contact-grid {
  display: grid;
  gap: clamp(28px, 3.4vw, 46px);
  align-items: start;
}
@media (min-width: 940px) {
  .aj-contact-grid { grid-template-columns: minmax(0, .86fr) minmax(0, 1.14fr); }
}

.aj-channels { display: grid; gap: 12px; margin: 0; padding: 0; list-style: none; }
.aj-channel {
  display: flex;
  gap: 15px;
  padding: 18px 20px;
  border-radius: var(--r);
  background: rgba(255, 255, 255, .045);
  border: 1px solid rgba(255, 255, 255, .1);
  transition: transform .4s var(--ease), background-color .4s var(--ease), border-color .4s var(--ease);
}
.aj-channel:hover {
  transform: translateY(-3px);
  background: rgba(255, 255, 255, .08);
  border-color: rgba(255, 255, 255, .22);
}
.aj-channel-ic {
  flex: none;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 13px;
  background: var(--grad);
  color: #fff;
}
.aj-channel-ic .aj-icon { width: 20px; height: 20px; }
.aj-channel-k {
  display: block;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .5);
  margin-bottom: 5px;
}
.aj-channel a { display: block; color: #fff; font-size: .98rem; }
.aj-channel a:hover { color: var(--brand-2); }
.aj-channel p { margin: 0; color: rgba(255, 255, 255, .78); font-size: .95rem; line-height: 1.6; }

.aj-map {
  margin-top: 12px;
  position: relative;
  border-radius: var(--r);
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, .12);
  aspect-ratio: 16 / 10;
  background: rgba(255, 255, 255, .04);
}
.aj-map iframe { width: 100%; height: 100%; border: 0; filter: grayscale(.35) contrast(1.05); }
.aj-map-tag {
  position: absolute;
  left: 14px;
  bottom: 14px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 15px;
  border-radius: 999px;
  font-size: .8rem;
  font-weight: 600;
  color: #fff;
  background: rgba(10, 17, 32, .82);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, .16);
}
.aj-map-tag:hover { color: #fff; background: rgba(10, 17, 32, .95); }
.aj-map-tag .aj-icon { width: 16px; height: 16px; color: var(--brand-2); }

/* enquiry card */
.aj-form-card {
  padding: clamp(26px, 3vw, 36px);
  border-radius: var(--r-lg);
  background: rgba(255, 255, 255, .055);
  border: 1px solid rgba(255, 255, 255, .12);
  backdrop-filter: blur(16px) saturate(140%);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  box-shadow: 0 50px 90px -50px rgba(0, 0, 0, .95);
}
.aj-form-card h3 { color: #fff; }
.aj-form-card > p { margin-top: 10px; color: rgba(255, 255, 255, .66); font-size: .95rem; }

.aj-form { margin-top: 26px; display: grid; gap: 16px; }
.aj-form-row { display: grid; gap: 16px; }
@media (min-width: 620px) { .aj-form-row { grid-template-columns: 1fr 1fr; } }

.aj-field { position: relative; }
.aj-field input,
.aj-field textarea {
  width: 100%;
  padding: 22px 16px 11px;
  border-radius: 14px;
  background: rgba(255, 255, 255, .05);
  border: 1px solid rgba(255, 255, 255, .14);
  color: #fff;
  font-size: .96rem;
  line-height: 1.5;
  transition: border-color .3s var(--ease), background-color .3s var(--ease), box-shadow .3s var(--ease);
  appearance: none;
  -webkit-appearance: none;
}
.aj-field textarea { min-height: 120px; resize: vertical; }

.aj-field label {
  position: absolute;
  left: 17px;
  top: 18px;
  font-size: .95rem;
  color: rgba(255, 255, 255, .5);
  pointer-events: none;
  transform-origin: left top;
  transition: transform .28s var(--ease), color .28s var(--ease);
}
.aj-field input:focus, .aj-field textarea:focus {
  outline: none;
  border-color: rgba(47, 128, 237, .85);
  background: rgba(255, 255, 255, .09);
  box-shadow: 0 0 0 4px rgba(47, 128, 237, .16);
}
.aj-field input:focus + label,
.aj-field input:not(:placeholder-shown) + label,
.aj-field textarea:focus + label,
.aj-field textarea:not(:placeholder-shown) + label {
  transform: translateY(-11px) scale(.76);
  color: var(--brand-2);
}
.aj-field textarea + label { top: 16px; }

/* the gradient underline that sweeps in on focus */
.aj-field::after {
  content: "";
  position: absolute;
  left: 16px;
  right: 16px;
  bottom: 0;
  height: 2px;
  border-radius: 2px;
  background: var(--grad);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .45s var(--ease);
}
.aj-field:focus-within::after { transform: scaleX(1); }
.aj-field--area::after { bottom: 6px; }


.aj-field.has-error input,
.aj-field.has-error textarea { border-color: #ff6b6b; box-shadow: 0 0 0 4px rgba(255, 107, 107, .14); }

.aj-form-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
  justify-content: space-between;
  margin-top: 6px;
}
.aj-form-note { font-size: .8rem; color: rgba(255, 255, 255, .5); max-width: 30ch; }

.aj-submit { min-width: 190px; }
.aj-submit .aj-spin {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .4);
  border-top-color: #fff;
  display: none;
  animation: vSpin .7s linear infinite;
}
.aj-submit.is-busy { pointer-events: none; opacity: .82; }
.aj-submit.is-busy .aj-spin { display: block; }
.aj-submit.is-busy .aj-icon { display: none; }

.aj-form-msg {
  margin-top: 4px;
  display: none;
  align-items: flex-start;
  gap: 10px;
  padding: 13px 16px;
  border-radius: 13px;
  font-size: .89rem;
  line-height: 1.55;
}
.aj-form-msg.is-shown { display: flex; }
.aj-form-msg.is-ok { background: rgba(20, 221, 115, .14); border: 1px solid rgba(20, 221, 115, .34); color: #b6ffd8; }
.aj-form-msg.is-bad { background: rgba(255, 107, 107, .13); border: 1px solid rgba(255, 107, 107, .32); color: #ffc9c9; }
.aj-form-msg .aj-icon { margin-top: 2px; }

/* 13  Footer ============================================================= */

.aj-cta {
  position: relative;
  padding-block: clamp(46px, 5vw, 70px);
  background: var(--ink);
  overflow: hidden;
}
.aj-cta::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(60% 140% at 80% 0%, rgba(255, 255, 255, .22), transparent 60%);
  pointer-events: none;
}
.aj-cta .wrap {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}
.aj-cta h2 { color: #fff; font-size: clamp(1.5rem, 1.2rem + 1.4vw, 2.15rem); }
.aj-cta p { margin: 8px 0 0; color: rgba(255, 255, 255, .84); }
.aj-cta-actions { display: flex; flex-wrap: wrap; gap: 12px; }
.aj-cta .btn--light {
  background: var(--grad);
  color: #fff;
  box-shadow: 0 16px 32px -18px rgba(0, 0, 0, .6);
}
.aj-cta .btn--light:hover { color: var(--brand-deep); transform: translateY(-2px); }

.aj-footer {
  position: relative;
  background: var(--ink);
  color: rgba(255, 255, 255, .68);
  /* padding-top: clamp(34px, 3.6vw, 52px); */
  overflow: hidden;
}
.aj-footer::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(46% 60% at 88% 0%, rgba(47, 128, 237, .22), transparent 66%);
  pointer-events: none;
}
.aj-footer .wrap { position: relative; }

.aj-footer-top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 22px;
}
.aj-footer-top img { height: 34px; width: auto; filter: brightness(0) invert(1); }

.aj-social { display: flex; gap: 10px; }
.aj-social a {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: 12px;
  color: rgba(255, 255, 255, .8);
  background: rgba(255, 255, 255, .06);
  border: 1px solid rgba(255, 255, 255, .1);
  transition: transform .35s var(--ease), background-color .35s var(--ease), color .35s var(--ease), border-color .35s var(--ease);
}
.aj-social a:hover {
  color: #fff;
  transform: translateY(-3px);
  background: var(--grad);
  border-color: transparent;
}
.aj-social .aj-icon { width: 18px; height: 18px; }



.aj-footer-bar {
  /* margin-top: clamp(26px, 2.8vw, 38px); */
  padding: 12px 0px;
  border-top: 1px solid rgba(255, 255, 255, .1);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  font-size: .85rem;
  color: rgba(255, 255, 255, .5);
}
.aj-footer-bar nav { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 18px; }
.aj-footer-bar a { color: rgba(255, 255, 255, .62); }
.aj-footer-bar a:hover { color: #fff; }

.aj-top {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 16px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, .16);
  color: rgba(255, 255, 255, .72);
  font-size: .82rem;
  transition: transform .35s var(--ease), border-color .35s var(--ease), color .35s var(--ease);
}
.aj-top:hover { color: #fff; border-color: var(--brand-2); transform: translateY(-3px); }
.aj-top .aj-icon { width: 15px; height: 15px; transition: transform .35s var(--ease); }
.aj-top:hover .aj-icon { transform: translateY(-2px); }

/* 14  Legal pages ======================================================== */

.aj-page-head {
  position: relative;
  padding-top: calc(var(--head-h) + clamp(48px, 6vw, 92px));
  padding-bottom: clamp(44px, 5vw, 76px);
  background: var(--ink);
  overflow: hidden;
}
.aj-page-head::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(52% 80% at 84% 10%, rgba(47, 128, 237, .34), transparent 68%),
    radial-gradient(44% 70% at 8% 96%, rgba(20, 221, 115, .2), transparent 68%);
}
.aj-page-head .wrap { position: relative; }
.aj-page-head h1 { color: #fff; font-size: clamp(2.1rem, 1.5rem + 2.6vw, 3.4rem); }
.aj-page-head p { margin-top: 16px; color: rgba(255, 255, 255, .7); max-width: 62ch; }

.aj-crumbs { display: flex; gap: 9px; align-items: center; margin-bottom: 20px; font-size: .82rem; color: rgba(255, 255, 255, .5); }
.aj-crumbs a { color: rgba(255, 255, 255, .72); }
.aj-crumbs a:hover { color: #fff; }

.aj-legal-grid { display: grid; gap: clamp(30px, 4vw, 56px); align-items: start; }
@media (min-width: 980px) {
  .aj-legal-grid { grid-template-columns: 276px minmax(0, 1fr); }
  .aj-legal-toc { position: sticky; top: calc(var(--head-h) + 30px); }
}

.aj-legal-toc {
  padding: 24px;
  border-radius: var(--r);
  border: 1px solid var(--card-line);
  background: var(--paper-2);
}
.aj-legal-toc h2 {
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 14px;
}
.aj-legal-toc ol { margin: 0; padding: 0 0 0 4px; list-style: none; counter-reset: toc; display: grid; gap: 8px; }
.aj-legal-toc li { counter-increment: toc; }
.aj-legal-toc a {
  display: flex;
  gap: 10px;
  font-size: .88rem;
  color: var(--text-2);
  line-height: 1.45;
}
.aj-legal-toc a::before {
  content: counter(toc, decimal-leading-zero);
  color: var(--brand);
  font-weight: 600;
  font-size: .78rem;
  flex: none;
}
.aj-legal-toc a:hover { color: var(--brand); }

.aj-legal { max-width: 74ch; }
.aj-legal-meta {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 34px;
  padding: 8px 16px;
  border-radius: 999px;
  background: var(--paper-2);
  border: 1px solid var(--card-line);
  font-size: .8rem;
  letter-spacing: .04em;
  color: var(--text-3);
}
.aj-legal h2 { margin: 54px 0 16px; scroll-margin-top: calc(var(--head-h) + 24px); font-size: clamp(1.3rem, 1.1rem + .8vw, 1.68rem); }
.aj-legal h3 { margin: 32px 0 12px; font-size: 1.08rem; }
.aj-legal p, .aj-legal li { color: var(--text-2); }
.aj-legal ul, .aj-legal ol { margin: 0 0 1.2em; padding-left: 22px; }
.aj-legal li { margin-bottom: 9px; }
.aj-legal a { text-decoration: underline; text-underline-offset: 3px; }
.aj-legal-card {
  margin: 26px 0;
  padding: 24px 26px;
  border-radius: var(--r);
  border: 1px solid var(--card-line);
  background: var(--paper-2);
}
.aj-legal-card h3 { margin-top: 0; }
.aj-legal-card p { margin-bottom: 6px; }

/* 15  Reduced motion & print ============================================= */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .js [data-reveal] { opacity: 1 !important; transform: none !important; }
  .js .aj-hero-anim > * { opacity: 1 !important; transform: none !important; }
  /* --p is pinned mid-story by js/ajna.js and .is-live is not added, so the
     scenes hold a readable still. These three carry their meaning in the
     animation itself, so they are shown resolved instead of blank. */
  /* the housekeeping floor carries its meaning in the shine and the
     glints, so those are shown resolved rather than blank */
  .hk-shine-wrap { transform: translateX(430px); }
  .hk-glint { opacity: .85; }
  .sc6-beam { opacity: .8; }
  .aj-hero-bg img { animation: none; }
}

@media print {
  .aj-header, .aj-mobile, .aj-hero-visual, .aj-skyline, .aj-cta,
  .aj-footer::before, .aj-gal-bar, .aj-lb { display: none !important; }
  body { color: #000; background: #fff; }
  .sec, .aj-svc { padding-block: 18px; }
  a { color: #000; }
}
