/* ==== fonts.css ==== */
/* Self-hosted so the faces are present at first paint.
   Loading these from Google Fonts async cost 0.35 CLS in one 105px
   reflow when the real metrics replaced the fallback. Generated by
   tools/fetch_fonts.py — regenerate rather than editing by hand. */

@font-face {
  font-family: 'Archivo';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/archivo-400-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Archivo';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/archivo-400-italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/archivo-400-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/archivo-400-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/archivo-500-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/archivo-500-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ==== base.css ==== */
/* ==========================================================================
   Axteria Group Berhad — foundation
   Palette sampled directly from AGB_logo-for-axteria-group.png:
     monogram gradient  #B06239 -> #CE7948 -> #F39458
     wordmark charcoal  #2A333F  (cool slate, not warm black)
   Every text pair below was measured against WCAG before being committed.
   Ratios are quoted against the #FFFFFF page; re-measure them all if the page
   surface ever changes again, because every one of them moves with it.
   ========================================================================== */

:root {
  /* --- surfaces --- */
  --bone:        #FFFFFF;   /* page base */
  --bone-warm:   #F4EEE5;   /* alternating band */
  --sand:        #EDE4D9;   /* tint fill */
  --rule:        #CFC2B2;   /* hairline, 1.75:1 on white — visible, not loud */
  --rule-soft:   #E0D6C9;

  /* --- ink (brand charcoal) --- */
  --ink:         #2A333F;   /* 12.78:1 on white — AAA */
  --ink-deep:    #151B22;   /* dark band base */
  --ink-muted:   #5C6472;   /* 5.96:1 on white, 5.17:1 on --bone-warm — AA */
  --ink-faint:   #8A919C;   /* decorative only, never body copy */
  --on-dark:     #FFFFFF;   /* 17.33:1 on ink-deep — AAA */
  --on-dark-mut: #C9CED6;   /* 10.96:1 on ink-deep — AAA */

  /* --- copper (use is contrast-gated, see comments) --- */
  --copper:      #CE7948;   /* 3.25:1 on white — DECORATIVE + display >=24px only */
  --copper-lite: #F39458;   /* 7.58:1 on ink-deep — AAA, accents on dark */
  --copper-deep: #B06239;   /* 4.51:1 on white — large text only */
  --copper-text: #9B5532;   /* 5.62:1 on white, 4.87:1 on --bone-warm — AA */
  --copper-btn:  #9F572F;   /* white on this = 5.41:1 — AA button fill */
  --copper-grad: linear-gradient(100deg, #B06239 0%, #CE7948 52%, #F39458 100%);

  /* --- unit availability states ---
     Ratios below are text-on-fill, and the line colours clear 3:1 against the
     white panel so each cell's edge is perceivable (WCAG 1.4.11). Green and
     red are the classic colour-blind collision, so the plan also prints an
     A / B / S letter in every cell and spells the state out in the
     accessible name — the colour is the fast path, never the only one. */
  --st-avail-bg:   #E6F2E8;
  --st-avail-line: #5D8F6A;   /* 3.75:1 on white */
  --st-avail-ink:  #215B30;   /* 7.00:1 on its fill */
  --st-book-bg:    #ECEEF0;
  --st-book-line:  #8A929C;   /* 3.15:1 on white */
  --st-book-ink:   #4E555F;   /* 6.47:1 on its fill */
  --st-sold-bg:    #F7E6E2;
  --st-sold-line:  #BB7461;   /* 3.63:1 on white */
  --st-sold-ink:   #9B2C15;   /* 6.28:1 on its fill */

  --wa-green:    #25D366;

  /* --- type ---
     One family for the whole page. Archivo is a neo-grotesque with a sturdy,
     even stroke: it reads as an established listed company rather than a
     fashion label, and it leaves the copper Didone logo as the only ornate
     thing on screen instead of competing with it. Hierarchy comes from size,
     weight and tracking — both tokens resolve to Archivo, and they stay
     separate so the display face can be swapped without touching body copy. */
  --display: "Archivo", system-ui, -apple-system, "Segoe UI", sans-serif;
  --sans:    "Archivo", system-ui, -apple-system, "Segoe UI", sans-serif;

  --fs-hero:   clamp(2.9rem, 7.4vw, 6.75rem);
  --fs-d1:     clamp(2.15rem, 4.6vw, 3.9rem);
  --fs-d2:     clamp(1.6rem, 2.8vw, 2.4rem);
  --fs-d3:     clamp(1.35rem, 1.9vw, 1.6rem);
  --fs-body:   1.0625rem;
  --fs-lead:   clamp(1.0625rem, 1.35vw, 1.25rem);
  --fs-meta:   0.78rem;
  --fs-micro:  0.7rem;

  --track-meta: 0.16em;
  --track-wide: 0.28em;

  /* --- space --- */
  --gutter: clamp(1.25rem, 5vw, 5.5rem);
  --shell:  1280px;
  --sec-y:  clamp(4.5rem, 9vw, 9rem);
  --header-h: 76px;

  --ease: cubic-bezier(.22, .61, .36, 1);
}

@media (max-width: 767px) { :root { --header-h: 62px; } }

/* ==========================================================================
   reset
   ========================================================================== */

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

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

/* No `overflow-x: hidden` here on purpose. It makes the body a scroll
   container on some engines, which breaks scroll anchoring and screenshot
   tooling — and it hides layout bugs rather than fixing them. Sections that
   bleed past the viewport clip themselves locally instead (.vision, .hero). */
body {
  margin: 0;
  background: var(--bone);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-body);
  line-height: 1.65;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, p, figure, blockquote, ul, ol, dl, dd { margin: 0; }
ul, ol { padding: 0; list-style: none; }

/* The UA stylesheet makes headings and <b>/<strong> bold (700). This design
   ships 400 and 500 only, so anything left at 700 is rendered as a synthesised
   fake bold — smeared outlines, wrong sidebearings. Everything opts into a
   weight we actually ship; nothing inherits 700.
   tools/audit-site.mjs fails the build if any element still wants a weight
   that is not in the loaded font set. */
h1, h2, h3, h4, h5, h6 { font-weight: 400; }
b, strong { font-weight: 500; }

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

/* Must come after the blanket display:block above, and must win: an author
   `display` declaration beats the UA stylesheet's [hidden]{display:none}
   whatever the specificity, so without this an svg[hidden] still renders. */
[hidden] { display: none !important; }

a { color: inherit; text-decoration: none; }

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

:focus-visible {
  outline: 2px solid var(--copper-text);
  outline-offset: 3px;
  border-radius: 2px;
}
:focus:not(:focus-visible) { outline: none; }

/* ==========================================================================
   type primitives
   ========================================================================== */

.display {
  font-family: var(--display);
  font-weight: 400;
  /* A grotesque set at 100px looks loose with default tracking — serifs carry
     their own rhythm, a sans does not. Negative tracking and tight leading are
     what give this the density the serif used to supply. */
  line-height: 1.04;
  letter-spacing: -0.028em;
}

/* small tracked caps — the wordmark's voice, reused for every label */
.eyebrow {
  font-family: var(--sans);
  font-size: var(--fs-meta);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--copper-text);
}
.eyebrow--dark { color: var(--copper-lite); }
.eyebrow--mute { color: var(--ink-muted); }

.lead {
  font-size: var(--fs-lead);
  line-height: 1.6;
  color: var(--ink-muted);
  max-width: 46ch;
}

.mute { color: var(--ink-muted); }

/* ==========================================================================
   layout
   ========================================================================== */

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  /* padding-inline set on its own axis — a `padding: x 0 y` shorthand here
     would silently zero the gutter and glue content to the viewport edge
     without ever tripping a horizontal-overflow check */
  padding-inline: var(--gutter);
}

.shell--wide { max-width: 1520px; }

.section { padding-block: var(--sec-y); }

.skip-link {
  position: absolute;
  left: 50%;
  top: 0;
  transform: translate(-50%, -120%);
  z-index: 200;
  background: var(--ink);
  color: var(--on-dark);
  padding: 0.7rem 1.4rem;
  font-size: var(--fs-meta);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  transition: transform 0.2s var(--ease);
}
.skip-link:focus { transform: translate(-50%, 0); }

/* hairline used as a structural device throughout */
.rule {
  height: 1px;
  background: var(--rule);
  border: 0;
}

/* ==========================================================================
   buttons
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.95rem 1.7rem;
  font-size: var(--fs-meta);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  border: 1px solid transparent;
  transition: background-color 0.3s var(--ease), color 0.3s var(--ease),
              border-color 0.3s var(--ease);
}

.btn--solid {
  background: var(--copper-btn);   /* white on this = 5.41:1 */
  color: var(--bone);
}
.btn--solid:hover { background: #874725; }

.btn--line {
  border-color: var(--ink);
  color: var(--ink);
}
.btn--line:hover { background: var(--ink); color: var(--bone); }

.btn--ghost {
  border-color: rgba(255, 255, 255, 0.45);
  color: var(--on-dark);
}
.btn--ghost:hover { background: var(--on-dark); color: var(--ink); }

.btn__arrow { width: 15px; height: 15px; flex: none; }

/* ==========================================================================
   motion — every animated rule is duplicated as a no-op in the
   prefers-reduced-motion block at the end of this file
   ========================================================================== */

.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.8s var(--ease), transform 0.8s var(--ease);
}
.reveal.is-in { opacity: 1; transform: none; }

/* no-JS fallback: if the observer never runs, content must still be visible */
.no-js .reveal { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .reveal { opacity: 1; transform: none; }
}

/* ==== sections.css ==== */
/* ==========================================================================
   Axteria Group Berhad — header + hero
   ========================================================================== */

/* --------------------------------------------------------------------------
   header — in flow, sticky, exactly --header-h tall.
   Kept in flow (rather than overlaid on the hero) so header + hero sum to
   precisely 100svh, and so nav sits at 11.96:1 instead of fighting the sky.
   -------------------------------------------------------------------------- */

.header {
  position: sticky;
  top: 0;
  z-index: 90;
  height: var(--header-h);
  background: var(--bone);
  border-bottom: 1px solid var(--rule-soft);
  transition: box-shadow 0.35s var(--ease);
}
.header.is-scrolled { box-shadow: 0 1px 24px rgba(42, 51, 63, 0.08); }

.header__inner {
  height: 100%;
  display: flex;
  align-items: center;
  gap: clamp(1rem, 3vw, 2.75rem);
}

.header__logo { flex: none; display: block; }
.header__logo img {
  height: clamp(34px, 4.4vw, 44px);
  width: auto;
}

.header__nav { margin-left: auto; }

.nav__list {
  display: flex;
  align-items: center;
  gap: clamp(1.1rem, 2.4vw, 2.4rem);
}

.nav__link {
  position: relative;
  display: block;
  padding-block: 0.4rem;
  font-size: var(--fs-meta);
  font-weight: 400;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink);
  transition: color 0.25s var(--ease);
}

/* scroll-spy indicator — the single-page equivalent of a current-page state */
.nav__link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: var(--copper);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.35s var(--ease);
}
.nav__link:hover { color: var(--copper-text); }
.nav__link:hover::after,
.nav__link.is-current::after { transform: scaleX(1); }
.nav__link.is-current { color: var(--copper-text); font-weight: 500; }

.header__aside {
  display: flex;
  align-items: center;
  gap: clamp(0.9rem, 1.8vw, 1.5rem);
  flex: none;
}

.header__cta { padding: 0.7rem 1.25rem; }

/* burger ------------------------------------------------------------------ */
.burger {
  display: none;
  width: 42px;
  height: 42px;
  align-items: center;
  justify-content: center;
  margin-right: -8px;
}
.burger__box { display: block; width: 22px; height: 12px; position: relative; }
.burger__box span {
  position: absolute;
  left: 0;
  width: 100%;
  height: 1.5px;
  background: var(--ink);
  transition: transform 0.3s var(--ease), opacity 0.2s var(--ease);
}
.burger__box span:nth-child(1) { top: 0; }
.burger__box span:nth-child(2) { bottom: 0; }
[aria-expanded="true"] .burger__box span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
[aria-expanded="true"] .burger__box span:nth-child(2) { transform: translateY(-5px) rotate(-45deg); }

/* mobile panel ------------------------------------------------------------ */
.navpanel {
  position: fixed;
  inset: var(--header-h) 0 0 0;
  z-index: 88;
  background: var(--bone);
  padding: clamp(1.75rem, 6vw, 2.5rem) var(--gutter);
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  overflow-y: auto;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease), visibility 0.3s;
}
.navpanel.is-open { opacity: 1; visibility: visible; transform: none; }

.navpanel__link {
  font-family: var(--display);
  font-size: clamp(1.75rem, 8vw, 2.5rem);
  line-height: 1.5;
  color: var(--ink);
  border-bottom: 1px solid var(--rule-soft);
  padding-block: 0.55rem;
}
.navpanel__foot {
  margin-top: auto;
  padding-top: 2rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  align-items: flex-start;
}

@media (max-width: 1023px) {
  .header__nav, .header__cta { display: none; }
  .burger { display: flex; }
}

/* --------------------------------------------------------------------------
   hero — full-bleed photograph, type anchored bottom-left,
   facts stacked against the right edge.  Section signature: bottom-anchored
   asymmetric type over a single bleeding image.
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  /* svh, not vh — vh jumps when mobile browser chrome collapses and would
     push the hero past the fold on first paint */
  min-height: calc(100svh - var(--header-h));
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: var(--ink-deep);
  isolation: isolate;
}

/* Layered with positive z-indexes: .hero is a stacking context (isolate) and
   carries an opaque fallback background, so a negative z-index here would
   paint the photograph behind that background and hide it entirely. */
.hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 62%;
}

/* Scrim carrying the headline to AA over a dusk sky.
   Stops are not eyeballed: tools/check_hero_contrast.py recomposites this exact
   crop and gradient pair and reports the worst ratio per text box. This set is
   the one that clears AA everywhere while staying nearly transparent by 44%
   width — the tower is the subject of the photograph and a gutter still dark at
   that point flattens it into silhouette. Re-run the checker if either the
   photograph or the type positions change. */
.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(to top,
      rgba(15, 20, 26, 0.93) 0%,
      rgba(15, 20, 26, 0.76) 28%,
      rgba(15, 20, 26, 0.46) 58%,
      rgba(15, 20, 26, 0.26) 100%),
    linear-gradient(to right,
      rgba(15, 20, 26, 0.86) 0%,
      rgba(15, 20, 26, 0.60) 22%,
      rgba(15, 20, 26, 0.14) 44%,
      rgba(15, 20, 26, 0.00) 100%);
}

.hero__inner {
  position: relative;
  z-index: 2;
  width: 100%;
  padding-block: clamp(2.5rem, 6vw, 4.5rem);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: clamp(1.5rem, 4vw, 3.5rem);
}

/* Bone, not copper: this label sits over the brightest cloud in the frame,
   where copper measures 2.20:1 against a 4.5:1 requirement. Bone reads 8.84:1
   there, and holding copper back to a single word makes that word land harder. */
.hero__eyebrow {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  color: var(--on-dark);
  margin-bottom: clamp(1rem, 2.2vw, 1.6rem);
}
.hero__eyebrow::after {
  content: "";
  height: 1px;
  width: clamp(38px, 7vw, 92px);
  background: currentColor;
  opacity: 0.55;
}

.hero__title {
  color: var(--on-dark);
  font-size: var(--fs-hero);
  max-width: 15ch;
  text-shadow: 0 2px 40px rgba(15, 20, 26, 0.35);
}
/* the one expressive type move on the page — Bodoni's italic, used once */
.hero__title em {
  font-style: italic;
  color: var(--copper-lite);
}

.hero__lead {
  margin-top: clamp(1.1rem, 2.4vw, 1.75rem);
  max-width: 38ch;
  color: var(--on-dark-mut);
  font-size: var(--fs-lead);
}

.hero__actions {
  margin-top: clamp(1.6rem, 3.2vw, 2.5rem);
  display: flex;
  flex-wrap: wrap;
  gap: 0.85rem;
}

/* right-edge fact stack — the asymmetry that keeps this off a centred grid */
.hero__facts {
  display: flex;
  flex-direction: column;
  gap: 1.15rem;
  padding-left: clamp(1.25rem, 2.5vw, 2rem);
  border-left: 1px solid rgba(255, 255, 255, 0.28);
  text-align: left;
}
.hero__fact dt {
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.62);
  margin-bottom: 0.15rem;
}
.hero__fact dd {
  font-family: var(--display);
  font-size: 1.2rem;
  line-height: 1.2;
  color: var(--on-dark);
}

.hero__caption {
  position: absolute;
  right: var(--gutter);
  bottom: clamp(0.85rem, 2vw, 1.25rem);
  font-size: var(--fs-micro);
  letter-spacing: 0.08em;
  color: rgba(255, 255, 255, 0.5);
}

@media (max-width: 900px) {
  .hero__inner { grid-template-columns: 1fr; }
  .hero__facts {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 0.9rem 2rem;
    padding-left: 0;
    padding-top: 1.35rem;
    border-left: 0;
    border-top: 1px solid rgba(255, 255, 255, 0.28);
  }
  .hero__caption { display: none; }
}

@media (max-width: 600px) {
  .hero__title { max-width: 100%; }
  .hero__actions .btn { flex: 1 1 100%; justify-content: center; }
}

/* ==========================================================================
   2 · VISION — oversized editorial statement, image bleeding off the right
   Section signature: single large pull-quote, no cards, asymmetric margin image
   ========================================================================== */

.vision {
  padding-block: var(--sec-y);
  overflow: hidden;              /* guards the bleed calc against rounding */
}

.vision__inner {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-left: var(--gutter);
  padding-right: var(--gutter);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.78fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: end;
}

/* Runs the figure out to the viewport edge. min(0px, …) keeps it a no-op once
   the viewport is narrower than the shell, where the value would flip positive
   and push the figure inward. */
.vision__figure {
  margin-right: min(0px, calc(-50vw + var(--shell) / 2 + var(--gutter)));
  position: relative;
}
.vision__figure img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }

.vision__caption {
  margin-top: 0.85rem;
  font-size: var(--fs-micro);
  letter-spacing: 0.06em;
  color: var(--ink-muted);
  text-transform: uppercase;
}

.vision__statement {
  font-size: var(--fs-d1);
  max-width: 13ch;
  margin-block: clamp(1.1rem, 2.5vw, 1.6rem) clamp(1.5rem, 3vw, 2.25rem);
}
.vision__statement em { font-style: italic; color: var(--copper-text); }

.vision__body { max-width: 44ch; color: var(--ink-muted); }

/* RISE — the mission acronym, set as a rule-separated rail */
.rise {
  display: flex;
  flex-wrap: wrap;
  gap: 0.55rem 1.4rem;
  margin-top: clamp(1.75rem, 3.5vw, 2.5rem);
  padding-top: 1.35rem;
  border-top: 1px solid var(--rule);
}
.rise li {
  font-size: var(--fs-meta);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink);
}
.rise b { color: var(--copper-text); font-weight: 500; }

@media (max-width: 860px) {
  .vision__inner { grid-template-columns: 1fr; }
  .vision__statement { max-width: 18ch; }
  .vision__figure { margin-right: 0; order: -1; margin-bottom: 1.5rem; }
}

/* ==========================================================================
   3 · PORTFOLIO — two tiers: a featured pair, then a quiet catalogue strip
   Section signature: the only section with an internal hierarchy break. Eight
   equally-weighted tiles fought each other and left a ragged offset grid; the
   two projects actually on sale now carry the weight, the rest read as an index.
   ========================================================================== */

.portfolio { background: var(--bone-warm); padding-block: var(--sec-y); }

.portfolio__head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: 1.25rem 2.5rem;
  padding-bottom: 1.4rem;
  margin-bottom: clamp(2rem, 4vw, 3.25rem);
  border-bottom: 1px solid var(--rule);
}
.portfolio__title {
  font-size: var(--fs-d2);
  max-width: 22ch;
  margin-top: 0.7rem;
}
.portfolio__count {
  font-size: var(--fs-meta);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink-muted);
  white-space: nowrap;
}

/* --- tier 1 : featured pair --------------------------------------------- */

.featured {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1.5rem, 3.5vw, 3rem);
}

.fproj__media {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--sand);
}
.fproj__media img { width: 100%; height: 100%; object-fit: cover; transition: transform 1s var(--ease); }
.fproj:hover .fproj__media img { transform: scale(1.04); }

/* Both source renders are landscape; a centred crop into a 4:5 card would fill
   the frame with sky. These hold the towers — the subject — in view. */
.fproj--asoho   .fproj__media img { object-position: 50% 38%; }
.fproj--asteria .fproj__media img { object-position: 50% 46%; }

.fproj__status {
  position: absolute;
  top: 1rem;
  left: 1rem;
  padding: 0.42rem 0.8rem;
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  background: var(--copper-btn);
  color: var(--bone);
}

/* the project's own tagline, in the display italic — the one emphasis move */
.fproj__tagline {
  font-family: var(--display);
  font-style: italic;
  font-size: clamp(1.05rem, 1.5vw, 1.3rem);
  line-height: 1.3;
  color: var(--copper-text);
  margin-top: 1.15rem;
}
.fproj__name {
  font-family: var(--display);
  font-size: clamp(1.75rem, 2.9vw, 2.6rem);
  line-height: 1.1;
  margin-top: 0.3rem;
}
.fproj__place {
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-top: 0.5rem;
}

/* fact sheet — dt left, dd right, hairline per row */
.spec { margin-top: 1.35rem; }
.spec > div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.25rem;
  padding-block: 0.6rem;
  border-top: 1px solid var(--rule);
}
.spec > div:last-child { border-bottom: 1px solid var(--rule); }
.spec dt {
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink-muted);
}
.spec dd { font-size: 0.95rem; text-align: right; }

.fproj__link {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  margin-top: 1.35rem;
  font-size: var(--fs-meta);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--copper-text);
  border-bottom: 1px solid currentColor;
  padding-bottom: 0.3rem;
  transition: gap 0.3s var(--ease);
}
.fproj__link:hover { gap: 0.95rem; }
.fproj__link svg { width: 14px; height: 14px; }

/* --- tier break ---------------------------------------------------------- */

.portfolio__break {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  margin-block: clamp(3rem, 6vw, 5rem) clamp(1.5rem, 3vw, 2.25rem);
}
.portfolio__break span {
  font-size: var(--fs-meta);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink-muted);
  white-space: nowrap;
}
.portfolio__break::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--rule);
}

/* --- tier 2 : catalogue strip -------------------------------------------- */

.catalogue {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: clamp(1rem, 2vw, 1.6rem);
}

.cproj__media {
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--sand);
  margin-bottom: 0.75rem;
}
.cproj__media img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.8s var(--ease); }
.cproj:hover .cproj__media img { transform: scale(1.06); }

.cproj__name {
  font-family: var(--display);
  font-size: 1.15rem;
  line-height: 1.2;
}
.cproj__place {
  font-size: var(--fs-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-top: 0.28rem;
}
.cproj__soon {
  display: inline-block;
  margin-top: 0.5rem;
  padding: 0.2rem 0.5rem;
  font-size: var(--fs-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink);
  border: 1px solid var(--rule);
}

@media (max-width: 1023px) {
  .catalogue { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
  .portfolio__head { grid-template-columns: 1fr; align-items: start; }
  .portfolio__count { white-space: normal; }
  .featured { grid-template-columns: 1fr; gap: clamp(2.5rem, 8vw, 3.5rem); }
  .fproj__media { aspect-ratio: 3 / 2; }
  .catalogue { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ==========================================================================
   4 · SUSTAINABILITY — 50/50 split, image bleeding to the left viewport edge
   Section signature: edge-to-edge two-panel split with a numbered rail
   ========================================================================== */

.sustain {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: stretch;
  background: var(--bone);
}

.sustain__media { position: relative; min-height: clamp(340px, 46vw, 620px); }
.sustain__media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

.sustain__panel {
  padding-block: var(--sec-y);
  padding-inline: clamp(1.25rem, 4vw, 4rem) var(--gutter);
  display: flex;
  flex-direction: column;
  justify-content: center;
  max-width: 620px;
}
.sustain__title { font-size: var(--fs-d2); margin-block: 0.9rem 1.1rem; max-width: 16ch; }
.sustain__body { color: var(--ink-muted); max-width: 42ch; }

.steps { margin-top: clamp(1.6rem, 3vw, 2.25rem); counter-reset: step; }
.steps li {
  counter-increment: step;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 1rem;
  padding-block: 0.95rem;
  border-top: 1px solid var(--rule);
  align-items: baseline;
}
.steps li:last-child { border-bottom: 1px solid var(--rule); }
.steps li::before {
  content: counter(step, decimal-leading-zero);
  font-family: var(--display);
  font-size: 0.95rem;
  color: var(--copper-text);
}
.steps b { font-weight: 500; }
.steps span { display: block; font-size: 0.9rem; color: var(--ink-muted); margin-top: 0.15rem; }

@media (max-width: 860px) {
  .sustain { grid-template-columns: 1fr; }
  .sustain__media { min-height: clamp(260px, 58vw, 420px); }
  .sustain__panel { max-width: none; padding-inline: var(--gutter); }
}

/* ==========================================================================
   5 · TRACK — dark full-bleed band, horizontal milestone rail + panorama strip
   Section signature: the only inverted band on the page; horizontal rail
   ========================================================================== */

.track { background: var(--ink-deep); color: var(--on-dark); padding-top: var(--sec-y); }

.track__head { max-width: 52ch; margin-bottom: clamp(2.25rem, 4.5vw, 3.5rem); }
.track__title { font-size: var(--fs-d2); color: var(--on-dark); margin-top: 0.9rem; }

.rail {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(1.25rem, 2.6vw, 2.25rem);
  padding-top: 1.6rem;
  border-top: 1px solid rgba(255, 255, 255, 0.2);
}
.rail__item { position: relative; padding-top: 1.35rem; }
/* node on the rail */
.rail__item::before {
  content: "";
  position: absolute;
  top: -1.6rem;
  left: 0;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--copper-lite);
  transform: translateY(-4px);
}
.rail__year {
  font-family: var(--display);
  font-size: clamp(1.9rem, 3.4vw, 2.9rem);
  line-height: 1;
  color: var(--copper-lite);
}
.rail__label {
  margin-top: 0.55rem;
  font-size: 0.9rem;
  color: var(--on-dark-mut);
  max-width: 24ch;
}

/* rotating banner ----------------------------------------------------------
   Auto-advancing content has to be stoppable (WCAG 2.2.2), so this ships a
   pause control and jump dots rather than an unstoppable timer. It also halts
   when scrolled out of view, when the tab is hidden, and on hover/focus — and
   it starts paused under prefers-reduced-motion so motion is opt-in. */
.track__strip { margin-top: clamp(2.75rem, 6vw, 4.5rem); }

.strip__frame {
  position: relative;
  aspect-ratio: 21 / 7;
  overflow: hidden;
  background: var(--ink-deep);
}
.strip__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 52%;
  opacity: 0;
  transition: opacity 0.9s var(--ease);
}
/* the first slide carries is-on in the markup, so with JS off the banner is
   simply a single static photograph rather than an empty black box */
.strip__img.is-on { opacity: 1; }

.strip__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem 1.5rem;
  padding-block: 0.85rem 1.5rem;
}
.strip__caption {
  font-size: var(--fs-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.62);   /* 6.87:1 on --ink-deep */
}

.strip__controls { display: flex; align-items: center; gap: 0.25rem; margin-left: auto; }

.strip__btn {
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: rgba(255, 255, 255, 0.72);
  transition: background-color 0.25s var(--ease), color 0.25s var(--ease);
}
.strip__btn:hover { background: rgba(255, 255, 255, 0.14); color: var(--on-dark); }
/* both icons share one grid cell, so the button keeps its size no matter
   which one is showing — grid would otherwise stack them in two rows */
.strip__btn svg { grid-area: 1 / 1; width: 12px; height: 12px; }

.strip__dots { display: flex; align-items: center; }
/* small mark, generous target — the dot is 7px but the button is 28x34 */
.strip__dot { width: 28px; height: 34px; display: grid; place-items: center; }
.strip__dot::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.45);   /* 4.25:1 — visible when inactive */
  transition: background-color 0.3s var(--ease), transform 0.3s var(--ease);
}
.strip__dot:hover::before { background: rgba(255, 255, 255, 0.8); }
.strip__dot[aria-current="true"]::before {
  background: var(--copper-lite);
  transform: scale(1.55);
}

@media (max-width: 760px) {
  .rail { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2rem 1.25rem; }
  .strip__frame { aspect-ratio: 16 / 9; }
}
@media (max-width: 420px) {
  .rail { grid-template-columns: 1fr; }
}

/* ==========================================================================
   6 · GALLERY — masonry, opens a lightbox
   Section signature: the only multi-column (not grid) block on the page
   ========================================================================== */

.gallery { padding-block: var(--sec-y); }

.gallery__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem 2rem;
  margin-bottom: clamp(1.75rem, 3.5vw, 2.75rem);
}
.gallery__title { font-size: var(--fs-d2); }
.gallery__hint {
  font-size: var(--fs-meta);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink-muted);
}

/* CSS multicol, not grid. It is real masonry with no JS and no re-layout on
   resize — and multicol fills column 1 top-to-bottom before starting column 2,
   so DOM order, visual order, tab order and lightbox order all agree. A JS
   masonry that positions absolutely would break that alignment. */
.gallery__grid {
  columns: 4;
  column-gap: clamp(0.5rem, 1.1vw, 0.85rem);
}

.shot {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  position: relative;
  overflow: hidden;
  background: var(--sand);
  cursor: pointer;
  margin-bottom: clamp(0.5rem, 1.1vw, 0.85rem);
  break-inside: avoid;
  -webkit-column-break-inside: avoid;   /* older WebKit spelling */
}
.shot img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.8s var(--ease); }
.shot:hover img { transform: scale(1.05); }

.shot::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(21, 27, 34, 0);
  transition: background-color 0.35s var(--ease);
}
.shot:hover::after { background: rgba(21, 27, 34, 0.14); }

/* Every source photograph in the client's library is landscape, between 1.30
   and 1.78 — there is not one portrait or square frame among the eighteen.
   Left at their natural ratios these would stack into near-identical rows and
   read as a ragged grid, not masonry, so the shapes are assigned here. The
   originals are 5477x3651 and larger, so cropping to portrait costs no
   resolution; object-position below keeps each subject in frame. */
.shot--tall { aspect-ratio: 3 / 4; }
.shot--sq   { aspect-ratio: 1 / 1; }
.shot--wide { aspect-ratio: 3 / 2; }
.shot--pano { aspect-ratio: 16 / 9; }

.shot--upview   img { object-position: 46% 58%; }
.shot--corridor img { object-position: 38% 50%; }
.shot--lobby    img { object-position: 52% 46%; }
.shot--recept   img { object-position: 44% 50%; }
.shot--dress    img { object-position: 50% 46%; }

@media (max-width: 1023px) { .gallery__grid { columns: 3; } }
@media (max-width: 720px)  { .gallery__grid { columns: 2; } }

/* ==========================================================================
   7 · INVESTORS — sticky heading beside an index of list rows
   Section signature: table-of-contents rows, the only list-driven block
   ========================================================================== */

.ir { background: var(--bone-warm); padding-block: var(--sec-y); }

.ir__inner {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}

.ir__side { position: sticky; top: calc(var(--header-h) + 2rem); }
.ir__title { font-size: var(--fs-d2); margin-block: 0.9rem 1.1rem; max-width: 12ch; }
.ir__body { color: var(--ink-muted); max-width: 34ch; font-size: 0.95rem; }

.ir__report {
  margin-top: clamp(1.75rem, 3vw, 2.5rem);
  display: flex;
  gap: 1.1rem;
  align-items: flex-start;
}
.ir__report img { width: 96px; height: auto; box-shadow: 0 6px 24px rgba(42, 51, 63, 0.18); }
.ir__reportmeta { padding-top: 0.35rem; }

.irlist li + li { border-top: 1px solid var(--rule); }
.irlist a {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 1.1rem;
  padding-block: 1.15rem;
  transition: color 0.25s var(--ease);
}
.irlist a:hover { color: var(--copper-text); }
/* --ink-faint (#8A919C) reads 2.75:1 on --bone-warm and fails AA. These
   ordinals are content, not decoration, so they take --ink-muted at 5.17:1. */
.irlist__idx {
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}
/* display:block is load-bearing — these are <span>s, and inline boxes ignore
   the margin-top below, which collapses the name and its meta onto one line */
.irlist__name { display: block; font-family: var(--display); font-size: 1.15rem; line-height: 1.25; }
.irlist__meta { display: block; font-size: 0.83rem; color: var(--ink-muted); margin-top: 0.15rem; }
.irlist svg { width: 16px; height: 16px; flex: none; color: var(--copper-text); }

.ticker {
  margin-top: clamp(1.75rem, 3vw, 2.5rem);
  padding: 1.25rem 1.4rem;
  background: var(--ink-deep);
  color: var(--on-dark);
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2rem;
  align-items: baseline;
}
/* Scoped to out-specify `.ticker dd` below (0,1,1) — as a bare class this rule
   loses and the stock code renders as ordinary body text. */
.ticker dd.ticker__code {
  font-family: var(--display);
  font-size: 1.6rem;
  line-height: 1.1;
  color: var(--copper-lite);
}
.ticker dt {
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
}
.ticker dd { font-size: 0.95rem; color: var(--on-dark); }

@media (max-width: 860px) {
  .ir__inner { grid-template-columns: 1fr; }
  .ir__side { position: static; }
}

/* ==========================================================================
   8 · CONTACT — bone panel offset over a full-bleed photograph
   Section signature: overlapping panel, the only card-over-image on the page
   ========================================================================== */

.contact { position: relative; isolation: isolate; }

.contact__media { position: relative; min-height: clamp(420px, 52vw, 640px); }
.contact__media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.contact__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to right, rgba(15, 20, 26, 0.55), rgba(15, 20, 26, 0.12));
}

.contact__panelwrap {
  position: relative;
  z-index: 2;
  margin-top: clamp(-9rem, -13vw, -5rem);
  padding-bottom: var(--sec-y);
}

.contact__panel {
  background: var(--bone);
  padding: clamp(1.75rem, 4vw, 3.25rem);
  max-width: 760px;
  box-shadow: 0 24px 70px rgba(42, 51, 63, 0.16);
}
.contact__title { font-size: var(--fs-d2); margin-block: 0.85rem 1.5rem; max-width: 14ch; }

.contact__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
  gap: 1.5rem 2rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule);
}
.contact__grid dt {
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--copper-text);
  margin-bottom: 0.45rem;
}
.contact__grid dd { font-size: 0.95rem; line-height: 1.6; color: var(--ink); }
.contact__grid a:hover { color: var(--copper-text); }

.contact__actions { margin-top: clamp(1.6rem, 3vw, 2.25rem); display: flex; flex-wrap: wrap; gap: 0.85rem; }

@media (max-width: 600px) {
  .contact__actions .btn { flex: 1 1 100%; justify-content: center; }
}

/* ==== pages.css ==== */
/* ==========================================================================
   Axteria Group Berhad — interior pages
   Navigation dropdowns, page banner, and the six content archetypes the
   generator emits: prose, project, docs, people, info, posts, grid.
   ========================================================================== */

/* --------------------------------------------------------------------------
   navigation dropdowns
   -------------------------------------------------------------------------- */

.nav__item { position: relative; }

.nav__trigger {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.4rem 0;
  font: inherit;
  font-size: var(--fs-meta);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
}
.nav__trigger svg {
  width: 12px;
  height: 12px;
  transition: transform 0.3s var(--ease);
}
.navdrop.is-open .nav__trigger svg { transform: rotate(180deg); }

.navdrop__panel {
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translate(-50%, 6px);
  min-width: 240px;
  padding: 0.9rem 0;
  background: var(--bone);
  border: 1px solid var(--rule-soft);
  box-shadow: 0 18px 44px rgba(42, 51, 63, 0.13);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.22s var(--ease), transform 0.22s var(--ease), visibility 0.22s;
  z-index: 5;
}
/* Investor Relations carries fifteen entries — one column would run off the
   bottom of most laptop screens, so it splits. */
.navdrop__panel--wide {
  min-width: 520px;
}
.navdrop__panel--wide ul {
  columns: 2;
  column-gap: 1.5rem;
}
.navdrop.is-open .navdrop__panel,
.navdrop:hover .navdrop__panel,
.navdrop:focus-within .navdrop__panel {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
}

.navdrop__panel a {
  display: block;
  padding: 0.5rem 1.4rem;
  font-size: 0.9rem;
  color: var(--ink);
  break-inside: avoid;
  transition: background-color 0.2s var(--ease), color 0.2s var(--ease);
}
.navdrop__panel a:hover { background: var(--bone-warm); color: var(--copper-text); }
.navdrop__panel a[aria-current] { color: var(--copper-text); font-weight: 500; }

/* mobile accordion --------------------------------------------------------- */
.mnav { display: flex; flex-direction: column; }
.mnav__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 0.85rem;
  font-family: var(--display);
  font-size: clamp(1.35rem, 6vw, 1.75rem);
  letter-spacing: -0.02em;
  color: var(--ink);
  border-bottom: 1px solid var(--rule-soft);
  cursor: pointer;
  list-style: none;
}
.mnav__top::-webkit-details-marker { display: none; }
.mnav__top svg { width: 18px; height: 18px; flex: none; transition: transform 0.3s var(--ease); }
.mnav__group[open] .mnav__top svg { transform: rotate(180deg); }
.mnav__top[aria-current] { color: var(--copper-text); }

.mnav__sub { display: flex; flex-direction: column; padding: 0.6rem 0 1rem 0.9rem; }
.mnav__sub a {
  padding-block: 0.5rem;
  font-size: 0.95rem;
  color: var(--ink-muted);
}
.mnav__sub a[aria-current] { color: var(--copper-text); font-weight: 500; }

@media (max-width: 1279px) {
  /* the full bar stops fitting well before the mobile breakpoint once the
     Investor Relations label is in it */
  .header__nav, .header__cta { display: none; }
  .burger { display: flex; }
}

/* --------------------------------------------------------------------------
   page banner
   Deliberately NOT the homepage's 100svh hero: a full-viewport banner on
   "Quarterly Reports" would push the page's actual content below the fold on
   every visit. This is fully visible at scroll 0, which is the point.
   -------------------------------------------------------------------------- */

.pagehead {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: clamp(340px, 48vh, 520px);
  overflow: hidden;
  background: var(--ink-deep);
  isolation: isolate;
}
.pagehead__media { position: absolute; inset: 0; z-index: 0; }
.pagehead__media img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 52%; }

/* Banner photographs vary from bright renders to dusk aerials, so the scrim is
   sized for the brightest of them rather than tuned per image. */
.pagehead__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(to top,
      rgba(15, 20, 26, 0.90) 0%,
      rgba(15, 20, 26, 0.72) 42%,
      rgba(15, 20, 26, 0.52) 100%),
    linear-gradient(to right,
      rgba(15, 20, 26, 0.55) 0%,
      rgba(15, 20, 26, 0.20) 60%,
      rgba(15, 20, 26, 0.10) 100%);
}
.pagehead__inner {
  position: relative;
  z-index: 2;
  width: 100%;
  padding-block: clamp(1.5rem, 4vw, 2.75rem);
}
.pagehead__title {
  color: var(--on-dark);
  font-size: var(--fs-d1);
  max-width: 18ch;
}
.pagehead__sub {
  margin-top: 0.85rem;
  max-width: 52ch;
  font-size: var(--fs-lead);
  color: var(--on-dark-mut);
}
.pagehead__copy .eyebrow { margin-bottom: 0.7rem; }

.crumbs { margin-bottom: clamp(1.5rem, 5vw, 3.5rem); }
.crumbs ol { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.crumbs li { display: flex; align-items: center; gap: 0.5rem; font-size: var(--fs-micro);
  letter-spacing: var(--track-meta); text-transform: uppercase; }
.crumbs li + li::before { content: "/"; color: rgba(255, 255, 255, 0.45); }
.crumbs a { color: rgba(255, 255, 255, 0.72); }
.crumbs a:hover { color: var(--on-dark); }
.crumbs [aria-current] { color: var(--copper-lite); }

.section__intro {
  max-width: 62ch;
  margin-bottom: clamp(2rem, 4vw, 3rem);
  font-size: var(--fs-lead);
  color: var(--ink-muted);
}

/* --------------------------------------------------------------------------
   prose
   -------------------------------------------------------------------------- */

.prose__body { max-width: 68ch; }
.prose__body > * + * { margin-top: 1.15rem; }
.prose__lead { font-size: var(--fs-lead); line-height: 1.6; color: var(--ink); }
.prose__h {
  font-size: var(--fs-d2);
  margin-top: clamp(2.25rem, 5vw, 3.25rem) !important;
}
.prose__h3 {
  font-size: 1.15rem;
  font-weight: 500;
  margin-top: 2rem !important;
}
.prose__body p { color: var(--ink-muted); }
.prose__body .prose__lead { color: var(--ink); }

.prose__list { display: flex; flex-direction: column; gap: 0.55rem; }
.prose__list li {
  position: relative;
  padding-left: 1.2rem;
  color: var(--ink-muted);
}
.prose__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.72em;
  width: 5px; height: 1px;
  background: var(--copper);
}
.prose__nums { counter-reset: n; display: flex; flex-direction: column; gap: 0.5rem; }
.prose__nums li {
  counter-increment: n;
  display: grid;
  grid-template-columns: 2.4rem minmax(0, 1fr);
  font-size: 0.95rem;
  color: var(--ink-muted);
}
.prose__nums li::before {
  content: counter(n, decimal-leading-zero);
  color: var(--copper-text);
  font-variant-numeric: tabular-nums;
}

.prose__note {
  padding: 1.1rem 1.35rem;
  background: var(--bone-warm);
  border-left: 2px solid var(--copper);
  font-size: 0.95rem;
  color: var(--ink) !important;
}
.prose__note a { color: var(--copper-text); border-bottom: 1px solid currentColor; }

.prose__rule { margin-block: clamp(2rem, 4vw, 3rem) !important; }

.prose__fig { margin-block: clamp(1.75rem, 4vw, 2.5rem) !important; }
.prose__fig img { width: 100%; }
.prose__fig figcaption {
  margin-top: 0.7rem;
  font-size: var(--fs-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

/* definition rail, used for milestones / core values / responsibilities */
.valuelist > div {
  display: grid;
  grid-template-columns: minmax(0, 0.42fr) minmax(0, 1fr);
  gap: 0.4rem 1.5rem;
  padding-block: 1rem;
  border-top: 1px solid var(--rule);
}
.valuelist > div:last-child { border-bottom: 1px solid var(--rule); }
.valuelist dt { font-weight: 500; color: var(--ink); }
.valuelist dd { color: var(--ink-muted); font-size: 0.95rem; }

@media (max-width: 640px) {
  .valuelist > div { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   document lists
   -------------------------------------------------------------------------- */

.docgroup + .docgroup { margin-top: clamp(2rem, 4vw, 3rem); }
.docgroup__year {
  font-family: var(--display);
  font-size: var(--fs-d3);
  color: var(--copper-text);
  padding-bottom: 0.6rem;
  border-bottom: 1px solid var(--rule);
}
.doclist li + li { border-top: 1px solid var(--rule-soft); }
.doclist a {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 1rem;
  padding-block: 1rem;
  transition: color 0.25s var(--ease);
}
.doclist a:hover { color: var(--copper-text); }
.doc__name { font-size: 0.98rem; }
.doc__meta {
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink-muted);
}
.doclist svg { width: 16px; height: 16px; color: var(--copper-text); flex: none; }

/* --------------------------------------------------------------------------
   people
   -------------------------------------------------------------------------- */

.bio { display: grid; grid-template-columns: minmax(0, 0.4fr) minmax(0, 1fr);
  gap: clamp(1rem, 3vw, 2.5rem); padding-block: clamp(1.75rem, 3.5vw, 2.5rem);
  border-top: 1px solid var(--rule); }
.bio:last-child { border-bottom: 1px solid var(--rule); }
.bio__name { font-family: var(--display); font-size: var(--fs-d3); line-height: 1.2; }
.bio__role {
  margin-top: 0.4rem;
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--copper-text);
}
.bio__body > * + * { margin-top: 0.9rem; }
.bio__body p { color: var(--ink-muted); font-size: 0.97rem; }
.bio__career { counter-reset: c; display: flex; flex-direction: column; gap: 0.4rem;
  padding-top: 0.4rem; }
.bio__career li {
  counter-increment: c;
  display: grid;
  grid-template-columns: 2.2rem minmax(0, 1fr);
  font-size: 0.9rem;
  color: var(--ink-muted);
}
.bio__career li::before {
  content: counter(c, decimal-leading-zero);
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 760px) { .bio { grid-template-columns: 1fr; } }

/* --------------------------------------------------------------------------
   info blocks
   -------------------------------------------------------------------------- */

.info__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: clamp(1.5rem, 3vw, 2.5rem);
  align-items: start;
}
.infoblock { padding-top: 1.1rem; border-top: 1px solid var(--rule); }
.infoblock__h {
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--copper-text);
  margin-bottom: 0.9rem;
}
.infoblock p { color: var(--ink-muted); font-size: 0.95rem; }
.info__address { line-height: 1.7; color: var(--ink) !important; }
.info__meta { margin-top: 0.6rem; font-size: 0.9rem; }
.info__list { display: flex; flex-direction: column; gap: 0.5rem; font-size: 0.95rem;
  color: var(--ink-muted); }
.info__list li { padding-left: 1.1rem; position: relative; }
.info__list li::before {
  content: "";
  position: absolute; left: 0; top: 0.72em;
  width: 5px; height: 1px; background: var(--copper);
}
.infoblock a { color: var(--copper-text); border-bottom: 1px solid rgba(155, 85, 50, 0.35); }
.infoblock a:hover { border-bottom-color: currentColor; }

/* the board table needs the full row, not a column of the auto-fit grid */
.infoblock:has(.infotable) { grid-column: 1 / -1; }
.infotable { width: 100%; border-collapse: collapse; font-size: 0.95rem; }
.infotable th {
  text-align: left;
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink-muted);
  padding-bottom: 0.6rem;
  border-bottom: 1px solid var(--rule);
}
.infotable td { padding-block: 0.8rem; border-bottom: 1px solid var(--rule-soft);
  color: var(--ink-muted); }
.infotable td:first-child { color: var(--ink); }

/* --------------------------------------------------------------------------
   posts
   -------------------------------------------------------------------------- */

.post {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1fr);
  gap: clamp(1.25rem, 3.5vw, 3rem);
  padding-block: clamp(2rem, 4vw, 3.25rem);
  border-top: 1px solid var(--rule);
  align-items: stretch;
}
.post:last-child { border-bottom: 1px solid var(--rule); }
.post__media { overflow: hidden; background: var(--sand); }
/* height:100% as well as the ratio — the row is as tall as the clamped text,
   and without it the image keeps its 4:3 box and leaves a strip of container
   background showing underneath. */
.post__media img { width: 100%; height: 100%; aspect-ratio: 4 / 3; object-fit: cover; }

/* The photograph sets the row height and the article is clamped to match.
   Truncating on a listing that has no per-article page would bury the rest of
   the copy for good, so the clamp comes with a toggle — and with scripting off
   the clamp is lifted instead, because a "Read more" that cannot fire is worse
   than an untidy column. */
.post__body { display: flex; flex-direction: column; min-height: 0; }
.post__text {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--post-lines, 8);
  overflow: hidden;
  min-height: 0;
}
.post__text.is-open { display: block; -webkit-line-clamp: unset; }
.post__more {
  align-self: flex-start;
  margin-top: 0.85rem;
  padding-block: 0.25rem;
  font-size: var(--fs-meta);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--copper-text);
  border-bottom: 1px solid currentColor;
}
.post__more[hidden] { display: none; }
.no-js .post__text { display: block; -webkit-line-clamp: unset; }
.no-js .post__more { display: none; }
.post__date {
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--copper-text);
}
.post__title { font-size: var(--fs-d3); margin-top: 0.5rem; }
.post__sub { font-size: 1rem; font-weight: 500; margin-top: 0.7rem; color: var(--ink); }
.post__text > p { color: var(--ink-muted); font-size: 0.97rem; }
.post__text > p + p { margin-top: 0.9rem; }

@media (max-width: 1023px) { .posts { --post-lines: 7; } }
@media (max-width: 760px) {
  .post { grid-template-columns: 1fr; }
  /* stacked: the photo no longer constrains the column, so show more */
  .posts { --post-lines: 10; }
}

/* --------------------------------------------------------------------------
   card grid (properties index)
   -------------------------------------------------------------------------- */

.gridsec__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 290px), 1fr));
  gap: clamp(1.25rem, 2.6vw, 2rem);
}
.gcard { display: flex; flex-direction: column; }
.gcard__media { position: relative; aspect-ratio: 4 / 3; overflow: hidden;
  background: var(--sand); }
.gcard__media img { width: 100%; height: 100%; object-fit: cover;
  transition: transform 0.85s var(--ease); }
.gcard:hover .gcard__media img { transform: scale(1.05); }
.gcard__status {
  position: absolute; top: 0.85rem; left: 0.85rem; z-index: 2;
  padding: 0.35rem 0.7rem;
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  background: var(--copper-btn);
  color: var(--bone);
}
.gcard__status--soon { background: rgba(21, 27, 34, 0.85); }
.gcard__body { padding-top: 0.9rem; }
.gcard__name { font-family: var(--display); font-size: 1.2rem; line-height: 1.2; }
.gcard__place {
  margin-top: 0.3rem;
  font-size: var(--fs-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.gcard__specs {
  margin-top: 0.7rem; padding-top: 0.7rem;
  border-top: 1px solid var(--rule);
  display: flex; flex-wrap: wrap; gap: 0.2rem 0.85rem;
  font-size: 0.83rem; color: var(--ink-muted);
}

/* --------------------------------------------------------------------------
   project page
   -------------------------------------------------------------------------- */

.povr__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.72fr);
  gap: clamp(1.75rem, 4vw, 3.5rem);
  align-items: start;
}
.povr__h { font-size: var(--fs-d2); margin-block: 0.8rem 1.2rem; max-width: 20ch; }
.povr__copy p { color: var(--ink-muted); }
.povr__copy p + p { margin-top: 1rem; }

.pspec > div {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1.25rem;
  padding-block: 0.7rem;
  border-top: 1px solid var(--rule);
}
.pspec > div:last-child { border-bottom: 1px solid var(--rule); }
.pspec dt {
  font-size: var(--fs-micro); letter-spacing: var(--track-meta);
  text-transform: uppercase; color: var(--ink-muted);
}
.pspec dd { font-size: 0.95rem; text-align: right; }

.ppoints { background: var(--bone-warm); padding-block: clamp(2.5rem, 5vw, 4rem); }
.ppoints__list { counter-reset: pp; display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: clamp(1.25rem, 3vw, 2.25rem); }
.ppoints__list li { counter-increment: pp; padding-top: 1rem;
  border-top: 1px solid var(--rule); }
.ppoints__list li::before {
  content: counter(pp, decimal-leading-zero);
  display: block; margin-bottom: 0.5rem;
  font-family: var(--display); font-size: 0.95rem; color: var(--copper-text);
}
.ppoints__list b { display: block; font-weight: 500; }
.ppoints__list span { display: block; margin-top: 0.35rem; font-size: 0.92rem;
  color: var(--ink-muted); }

.ploc { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: stretch; }
.ploc__media { position: relative; min-height: clamp(280px, 40vw, 480px); }
.ploc__media img { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; }
.ploc__panel {
  padding-block: var(--sec-y);
  padding-inline: clamp(1.25rem, 4vw, 4rem) var(--gutter);
  display: flex; flex-direction: column; justify-content: center;
  max-width: 620px;
}
.ploc__h { font-size: var(--fs-d2); margin-block: 0.8rem 1.4rem; }
.ploc__facts > div { padding-block: 0.85rem; border-top: 1px solid var(--rule); }
.ploc__facts > div:last-child { border-bottom: 1px solid var(--rule); }
.ploc__facts dt {
  font-size: var(--fs-micro); letter-spacing: var(--track-meta);
  text-transform: uppercase; color: var(--ink-muted); margin-bottom: 0.3rem;
}
.ploc__facts dd { line-height: 1.6; }
.ploc__note { margin-top: 1.1rem; font-size: 0.92rem; color: var(--ink-muted); }
.ploc__note a { color: var(--copper-text); border-bottom: 1px solid currentColor; }

@media (max-width: 860px) {
  .povr__grid { grid-template-columns: 1fr; }
  .ploc { grid-template-columns: 1fr; }
  .ploc__panel { max-width: none; padding-inline: var(--gutter); }
}

.pcta { background: var(--ink-deep); color: var(--on-dark);
  padding-block: clamp(2.5rem, 5vw, 4rem); }
.pcta__inner { display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: 1.5rem 2.5rem; }
.pcta__h { font-size: var(--fs-d2); color: var(--on-dark); max-width: 18ch; }
.pcta__p { margin-top: 0.6rem; color: var(--on-dark-mut); }
.pcta__actions { display: flex; flex-wrap: wrap; gap: 0.85rem; }
.pcta .btn--line { border-color: rgba(255, 255, 255, 0.5); color: var(--on-dark); }
.pcta .btn--line:hover { background: var(--on-dark); color: var(--ink); }

@media (max-width: 600px) { .pcta__actions .btn { flex: 1 1 100%; justify-content: center; } }

/* ==========================================================================
   unit availability + booking
   ========================================================================== */

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

.units { background: var(--bone-warm); }
.units__head { max-width: 62ch; margin-bottom: clamp(2rem, 4vw, 3rem); }
.units__h { font-size: var(--fs-d2); margin-block: 0.8rem 0.9rem; }
.units__note {
  font-size: 0.9rem;
  color: var(--ink-muted);
  padding-left: 0.9rem;
  border-left: 2px solid var(--copper);
}

.units__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 290px), 1fr));
  gap: clamp(1.25rem, 2.6vw, 2rem);
}
.utype { display: flex; flex-direction: column; background: var(--bone);
  border: 1px solid var(--rule-soft); }
.utype__media { aspect-ratio: 4 / 3; overflow: hidden; background: var(--sand); }
.utype__media img { width: 100%; height: 100%; object-fit: cover;
  transition: transform 0.8s var(--ease); }
.utype:hover .utype__media img { transform: scale(1.04); }
.utype__body { padding: 1.25rem 1.35rem 1.4rem; display: flex; flex-direction: column;
  flex: 1; }
.utype__name { font-family: var(--display); font-size: 1.3rem; line-height: 1.2; }
.utype__meta {
  margin-top: 0.3rem;
  font-size: var(--fs-micro);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--copper-text);
}
.utype__blurb { margin-top: 0.8rem; font-size: 0.92rem; color: var(--ink-muted); }
.utype__price { margin-top: 1.1rem; }
.utype__price > div {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding-block: 0.55rem; border-top: 1px solid var(--rule);
}
.utype__price > div:last-child { border-bottom: 1px solid var(--rule); }
.utype__price dt {
  font-size: var(--fs-micro); letter-spacing: var(--track-meta);
  text-transform: uppercase; color: var(--ink-muted);
}
.utype__price dd { font-size: 1.05rem; }
.utype__cta { margin-top: 1.25rem; align-self: flex-start; }
.utype__soldout {
  margin-top: 1.25rem;
  font-size: var(--fs-meta);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink-muted);
}

/* --- dialog --------------------------------------------------------------- */

.bk, .modal {
  position: fixed;
  inset: 0;
  z-index: 190;
  display: grid;
  place-items: center;
  padding: clamp(0.5rem, 3vw, 2rem);
  background: rgba(11, 15, 20, 0.72);
  opacity: 0;
  transition: opacity 0.22s var(--ease);
}
.bk.is-open, .modal.is-open { opacity: 1; }
.bk[hidden], .modal[hidden] { display: none; }

.bk__panel, .modal__panel {
  width: min(100%, 900px);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--bone);
  box-shadow: 0 30px 80px rgba(11, 15, 20, 0.4);
  overflow: hidden;
}
.bk__head, .modal__head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem;
  padding: clamp(1.1rem, 3vw, 1.6rem) clamp(1.1rem, 3vw, 1.9rem);
  border-bottom: 1px solid var(--rule);
}
.bk__title { font-size: var(--fs-d3); margin-top: 0.35rem; }
/* These sit on a light panel but borrow .lb-btn, which is styled for the
   lightbox's dark backdrop and is loaded later in the bundle. The extra
   qualifier is what stops a white glyph being painted onto a white surface —
   which is exactly what happened, invisibly, until it was measured. */
.bk .bk__close, .modal .modal__close {
  border-color: var(--rule);
  color: var(--ink);
  width: 40px; height: 40px; flex: none;
}
.bk .bk__close:hover, .modal .modal__close:hover { background: var(--bone-warm); }
.bk__close:hover, .modal__close:hover { background: var(--bone-warm); }

.bk__live {
  padding-inline: clamp(1.1rem, 3vw, 1.9rem);
  font-size: var(--fs-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--copper-text);
  min-height: 1.4rem;
  padding-top: 0.7rem;
}

.bk__step, .modal__body { padding: 0.4rem clamp(1.1rem, 3vw, 1.9rem) clamp(1.25rem, 3vw, 1.9rem);
  overflow-y: auto; }

.bk__toolbar {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 0.75rem 1.5rem; padding-block: 0.6rem 1rem;
}
.bk__blocks { display: flex; gap: 0.4rem; }
.bk__block {
  padding: 0.45rem 0.9rem;
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  border: 1px solid var(--rule);
  color: var(--ink-muted);
}
.bk__block.is-on { background: var(--ink); border-color: var(--ink); color: var(--bone); }

.bk__legend { display: flex; flex-wrap: wrap; gap: 0.4rem 1rem; }
.bk__key {
  display: flex; align-items: center; gap: 0.4rem;
  font-size: var(--fs-micro); letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--ink-muted);
}
.bk__key span { width: 12px; height: 12px; border: 1px solid; }
.bk__key--available span { background: var(--st-avail-bg); border-color: var(--st-avail-line); }
.bk__key--booked span { background: var(--st-book-bg); border-color: var(--st-book-line); }
.bk__key--sold span { background: var(--st-sold-bg); border-color: var(--st-sold-line); }

.bk__planwrap { overflow-x: auto; display: flex; justify-content: center; }
.bk__plan { border-collapse: separate; border-spacing: 4px; }
.bk__floor {
  font-size: var(--fs-micro);
  letter-spacing: 0.06em;
  color: var(--ink-muted);
  text-align: right;
  padding-right: 0.5rem;
  font-weight: 400;
  white-space: nowrap;
}
.bk__cell { padding: 0; }
.bk__unit {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 0.3rem;
  width: 100%;
  min-width: 62px;
  padding: 0.42rem 0.5rem;
  border: 1px solid var(--rule);
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
  transition: background-color 0.2s var(--ease), border-color 0.2s var(--ease);
}
/* The A / B / S letter is load-bearing, not decoration. Green-for-available
   against red-for-sold is exactly the pair deuteranopia and protanopia
   collapse, so the state has to survive with the colour removed — the letter
   and the accessible name both carry it. */
.bk__ustate { font-size: 0.62rem; letter-spacing: 0.05em; opacity: 0.85; }

.bk__unit.is-available {
  background: var(--st-avail-bg);
  border-color: var(--st-avail-line);
  color: var(--st-avail-ink);
  cursor: pointer;
}
.bk__unit.is-available:hover {
  background: var(--st-avail-ink);
  border-color: var(--st-avail-ink);
  color: #FFFFFF;
}
.bk__unit.is-booked {
  background: var(--st-book-bg);
  border-color: var(--st-book-line);
  color: var(--st-book-ink);
  cursor: not-allowed;
}
.bk__unit.is-sold {
  background: var(--st-sold-bg);
  border-color: var(--st-sold-line);
  color: var(--st-sold-ink);
  cursor: not-allowed;
}

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

.bk__back {
  display: inline-flex; align-items: center; gap: 0.45rem;
  padding-block: 0.6rem;
  font-size: var(--fs-meta);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--copper-text);
}
.bk__back svg { width: 14px; height: 14px; }

.bk__summary { margin-block: 0.8rem 1.4rem; padding: 1.1rem 1.25rem;
  background: var(--bone-warm); }
.bk__sumlabel {
  font-size: var(--fs-micro); letter-spacing: var(--track-meta);
  text-transform: uppercase; color: var(--ink-muted);
}
.bk__sumunit { font-family: var(--display); font-size: 1.5rem; margin-top: 0.2rem; }
.bk__sumfacts { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 0.6rem 1.25rem; margin-top: 0.9rem; padding-top: 0.9rem;
  border-top: 1px solid var(--rule); }
.bk__sumfacts dt {
  font-size: var(--fs-micro); letter-spacing: var(--track-meta);
  text-transform: uppercase; color: var(--ink-muted);
}
.bk__sumfacts dd { font-size: 0.95rem; margin-top: 0.15rem; }

.bk__form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.9rem 1.1rem; }
.fld--wide { grid-column: 1 / -1; }
.fld label {
  display: block;
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-bottom: 0.35rem;
}
.req { color: var(--copper-text); }
.fld input, .fld textarea {
  width: 100%;
  padding: 0.7rem 0.8rem;
  background: var(--bone);
  border: 1px solid var(--rule);
  font-size: 0.95rem;
  transition: border-color 0.2s var(--ease);
}
.fld input:focus, .fld textarea:focus { border-color: var(--copper-text); }
.fld input[aria-invalid="true"], .fld textarea[aria-invalid="true"] {
  border-color: #A3341F;
}
.fld__err { margin-top: 0.3rem; font-size: 0.82rem; color: #A3341F; }
.fld__err:empty { display: none; }

.bk__submit { display: flex; flex-wrap: wrap; align-items: center; gap: 0.85rem 1.25rem;
  margin-top: 0.4rem; }
.bk__smallprint { font-size: 0.82rem; color: var(--ink-muted); max-width: 44ch; }

.bk__done { display: grid; place-items: center; text-align: center;
  padding-block: clamp(1.5rem, 5vw, 3rem); }
.bk__doneinner { max-width: 46ch; }
.bk__doneh { font-size: var(--fs-d3); margin-block: 0.6rem 0.8rem; }
.bk__donep { color: var(--ink-muted); font-size: 0.95rem; }
.bk__doneactions { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.75rem;
  margin-top: 1.5rem; }
.bk__restart { margin-top: 1.1rem; }

@media (max-width: 620px) {
  .bk__form { grid-template-columns: 1fr; }
  .bk__panel { max-height: 100%; }
  .bk__doneactions .btn { flex: 1 1 100%; justify-content: center; }
}

/* card badges — derived from stock levels in build/inventory.py, so the label
   moves with the data instead of being a fixed marketing claim */
.utype__media { position: relative; }
.utag {
  position: absolute;
  top: 0.85rem;
  left: 0.85rem;
  z-index: 2;
  padding: 0.35rem 0.7rem;
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: #FFFFFF;
}
.utag--urgent { background: #9B2C15; }   /* white on this = 6.28:1 */
.utag--value  { background: #215B30; }   /* white on this = 8.03:1 */
.utag--promo  { background: var(--copper-btn); }

/* --------------------------------------------------------------------------
   project resources — brochure + 360 tour
   -------------------------------------------------------------------------- */

.resources { padding-block: clamp(1.5rem, 3vw, 2.5rem); border-block: 1px solid var(--rule); }
.resources__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: clamp(0.75rem, 2vw, 1.5rem);
}
.res {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 1rem;
  padding: 1rem 1.2rem;
  border: 1px solid var(--rule);
  transition: border-color 0.25s var(--ease), background-color 0.25s var(--ease);
}
.res:hover { border-color: var(--copper-btn); background: var(--bone-warm); }
.res__icon {
  display: grid; place-items: center;
  width: 42px; height: 42px;
  border-radius: 50%;
  background: var(--bone-warm);
  color: var(--copper-text);
  flex: none;
}
.res:hover .res__icon { background: var(--copper-btn); color: #FFFFFF; }
.res__icon svg { width: 19px; height: 19px; }
.res__body b { display: block; font-weight: 500; font-size: 0.98rem; }
.res__body span { display: block; margin-top: 0.15rem; font-size: 0.85rem; color: var(--ink-muted); }

/* awaiting a URL: still legible at AA, but clearly not a live control */
.res--pending { cursor: not-allowed; border-style: dashed; }
.res--pending .res__icon { background: var(--sand); color: var(--ink-muted); }
.res--pending:hover { border-color: var(--rule); background: transparent; }
.res--pending:hover .res__icon { background: var(--sand); color: var(--ink-muted); }

/* --------------------------------------------------------------------------
   banner slider
   Shared with the homepage hero; the engine is makeSlider() in main.js.
   -------------------------------------------------------------------------- */

.hs, .hs__frame { position: absolute; inset: 0; }
.hs__slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1s var(--ease);
}
/* the first slide carries is-on in the markup, so with JS off the banner is
   a single static photograph rather than an empty box */
.hs__slide.is-on { opacity: 1; }
.hs__slide img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 52%; }

.hs__controls {
  position: absolute;
  z-index: 3;
  right: var(--gutter);
  bottom: clamp(1rem, 2.5vw, 1.75rem);
  display: flex;
  align-items: center;
  gap: 0.35rem;
}
.hs__btn {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  grid-template-areas: "i";
  border-radius: 50%;
  color: rgba(255, 255, 255, 0.85);
  transition: background-color 0.25s var(--ease);
}
.hs__btn svg { grid-area: i; width: 11px; height: 11px; }
.hs__btn:hover { background: rgba(255, 255, 255, 0.18); color: #FFFFFF; }

.hs__dots { display: flex; align-items: center; }
.hs__dot { width: 26px; height: 34px; display: grid; place-items: center; }
.hs__dot::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.5);
  transition: background-color 0.3s var(--ease), transform 0.3s var(--ease);
}
.hs__dot:hover::before { background: rgba(255, 255, 255, 0.85); }
.hs__dot[aria-current="true"]::before { background: var(--copper-lite); transform: scale(1.5); }

/* Taller than the plain banner — a project page is a sales page and the
   photography is the argument. Interior text pages keep the shorter one so
   their content is not pushed off the fold. */
.pagehead--tall { min-height: clamp(460px, 72vh, 760px); }
.pagehead--tall .pagehead__inner { padding-bottom: clamp(3.25rem, 6vw, 4.5rem); }

@media (max-width: 600px) {
  .hs__controls { right: auto; left: var(--gutter); }
}

/* appointment confirmation */
.bk__tick {
  display: grid;
  place-items: center;
  width: 54px; height: 54px;
  margin: 0 auto 1.1rem;
  border-radius: 50%;
  background: var(--st-avail-bg);
  color: var(--st-avail-ink);          /* 7.00:1 on that fill */
  border: 1px solid var(--st-avail-line);
}
.bk__tick svg { width: 24px; height: 24px; }
.bk__ref {
  margin-top: 0.5rem;
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink-muted);
}
.bk__ref b { color: var(--ink); font-variant-numeric: tabular-nums; }
.bk__donep b { font-weight: 500; color: var(--ink); }

/* ==========================================================================
   owner portal
   ========================================================================== */

.auth { padding-block: clamp(2.5rem, 6vw, 5rem); }
.auth__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}
.auth__card { max-width: 460px; }
.auth__h { font-size: var(--fs-d2); margin-block: 0.7rem 0.8rem; }
.auth__intro { color: var(--ink-muted); }

/* Stated on the page, not only in a code comment: a sign-in form that verifies
   nothing must say so where the person typing can see it. */
.auth__warn {
  margin-top: 1.4rem;
  padding: 0.9rem 1.1rem;
  background: var(--st-sold-bg);
  border-left: 2px solid var(--st-sold-line);
  color: var(--st-sold-ink);          /* 6.28:1 on that fill */
  font-size: 0.88rem;
}

.auth__form {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.9rem;
  margin-top: 1.6rem;
}
.auth__submit { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.5rem; }
.auth__link { font-size: 0.9rem; color: var(--copper-text); border-bottom: 1px solid currentColor; }
.auth__foot { margin-top: 1.6rem; font-size: 0.88rem; color: var(--ink-muted); }
.auth__foot a { color: var(--copper-text); border-bottom: 1px solid currentColor; }
.auth__aside img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }

@media (max-width: 860px) {
  .auth__inner { grid-template-columns: 1fr; }
  .auth__aside { display: none; }
}

/* --- portal --------------------------------------------------------------- */

.pv__notice {
  padding: 0.9rem 1.1rem;
  background: var(--bone-warm);
  border-left: 2px solid var(--copper);
  font-size: 0.88rem;
  color: var(--ink);
  margin-bottom: clamp(1.75rem, 4vw, 2.75rem);
}

.pv__account {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  gap: clamp(1.5rem, 4vw, 3rem);
  padding-bottom: clamp(1.75rem, 4vw, 2.5rem);
  border-bottom: 1px solid var(--rule);
  align-items: start;
}
.pv__name { font-size: var(--fs-d3); margin-block: 0.5rem 0.5rem; }
.pv__unit { color: var(--ink-muted); font-size: 0.95rem; line-height: 1.6; }
.pv__facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr));
  gap: 1rem 1.5rem;
}
.pv__facts dt {
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink-muted);
}
.pv__facts dd { font-size: 1.05rem; margin-top: 0.2rem; }

.pv__grid {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(2rem, 5vw, 4rem);
  margin-top: clamp(2rem, 4vw, 3rem);
  align-items: start;
}
.pv__h { font-size: var(--fs-d3); margin-bottom: 1.2rem; }
.pv__form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.9rem 1rem; }
.pv__form select,
.pv__form input[type="file"] {
  width: 100%;
  padding: 0.7rem 0.8rem;
  background: var(--bone);
  border: 1px solid var(--rule);
  font-size: 0.95rem;
}
.pv__form input[type="file"] { padding: 0.55rem 0.6rem; font-size: 0.88rem; }
.fld__hint { margin-top: 0.35rem; font-size: 0.82rem; color: var(--ink-muted); }
.pv__submit { margin-top: 0.3rem; }
.pv__live {
  margin-top: 1rem;
  min-height: 1.4rem;
  font-size: 0.9rem;
  color: var(--copper-text);
}

.pv__listhead {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: 0.5rem 1.5rem; margin-bottom: 1.2rem;
}
.pv__count { font-size: var(--fs-micro); letter-spacing: var(--track-meta);
  text-transform: uppercase; color: var(--ink-muted); }
.pv__count b { color: var(--ink); }

.tk { padding-block: 1.25rem; border-top: 1px solid var(--rule); }
.tk:first-child { border-top: 0; padding-top: 0; }
.tk__head { display: flex; align-items: flex-start; justify-content: space-between;
  gap: 1rem; }
.tk__ref {
  font-size: var(--fs-micro); letter-spacing: var(--track-meta);
  text-transform: uppercase; color: var(--ink-muted);
}
.tk__title { font-family: var(--display); font-size: 1.1rem; line-height: 1.25;
  margin-top: 0.3rem; }
.tk__meta { margin-top: 0.25rem; font-size: 0.85rem; color: var(--ink-muted); }
.tk__detail { margin-top: 0.7rem; font-size: 0.92rem; color: var(--ink-muted); }

/* Status colour is backed by the word itself, never carried alone. */
.tk__status {
  flex: none;
  padding: 0.3rem 0.65rem;
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  border: 1px solid;
  white-space: nowrap;
}
.tk__status--wait   { background: var(--st-book-bg);  border-color: var(--st-book-line);
                      color: var(--st-book-ink); }
.tk__status--active { background: #FDF0E4; border-color: #C98A55; color: #7C4223; }
.tk__status--done   { background: var(--st-avail-bg); border-color: var(--st-avail-line);
                      color: var(--st-avail-ink); }

.tk__more { margin-top: 0.8rem; }
.tk__more summary {
  cursor: pointer;
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--copper-text);
  list-style: none;
}
.tk__more summary::-webkit-details-marker { display: none; }
.tk__more summary::before { content: "+ "; }
.tk__more[open] summary::before { content: "– "; }
.tk__timeline { margin-top: 0.8rem; display: flex; flex-direction: column; gap: 0.6rem;
  padding-left: 0.9rem; border-left: 1px solid var(--rule); }
.tk__timeline li { display: grid; grid-template-columns: 8.5rem minmax(0, 1fr); gap: 0.75rem;
  font-size: 0.88rem; }
.tk__when { color: var(--copper-text); font-variant-numeric: tabular-nums; }
.tk__what { color: var(--ink-muted); }

@media (max-width: 900px) {
  .pv__account, .pv__grid { grid-template-columns: 1fr; }
}
@media (max-width: 620px) {
  .pv__form { grid-template-columns: 1fr; }
  .tk__timeline li { grid-template-columns: 1fr; gap: 0.15rem; }
}

/* the header button doubles as the nav entry for the portal */
.header__cta[aria-current] { background: var(--ink); border-color: var(--ink); color: #FFFFFF; }

/* --- ticket list + detail -------------------------------------------------
   Rows carry only reference, title, date and status. A list that has to hold
   fifty-plus tickets cannot repeat the description and a progress accordion on
   every row — the detail moves into a dialog opened from the row.
   -------------------------------------------------------------------------- */

.tklist li + li { border-top: 1px solid var(--rule-soft); }
.tkrow {
  display: grid;
  grid-template-columns: 8.5rem minmax(0, 1fr) auto auto auto;
  align-items: center;
  gap: 0.6rem 1.1rem;
  width: 100%;
  padding-block: 0.85rem;
  text-align: left;
  transition: background-color 0.2s var(--ease);
}
.tkrow:hover { background: var(--bone-warm); }
.tkrow__ref {
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}
.tkrow__title { font-size: 0.98rem; color: var(--ink); }
.tkrow__date {
  font-size: var(--fs-micro);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-muted);
  white-space: nowrap;
}
.tkrow svg { width: 15px; height: 15px; color: var(--copper-text); flex: none; }

@media (max-width: 760px) {
  .tkrow {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "ref status" "title title" "date arrow";
  }
  .tkrow__ref { grid-area: ref; }
  .tkrow__title { grid-area: title; }
  .tkrow__date { grid-area: date; }
  .tkrow .tk__status { grid-area: status; }
  .tkrow svg { grid-area: arrow; justify-self: end; }
}

/* detail dialog */
.modal__panel { width: min(100%, 680px); }
.tkd__ref {
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink-muted);
}
.tkd__title { font-size: var(--fs-d3); margin-top: 0.35rem; }
.tkd__facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr));
  gap: 1rem 1.5rem;
  padding-block: 1.1rem;
  border-block: 1px solid var(--rule);
  margin-block: 1.2rem;
}
.tkd__facts dt {
  font-size: var(--fs-micro);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink-muted);
}
.tkd__facts dd { font-size: 0.95rem; margin-top: 0.2rem; }
.tkd__detail { color: var(--ink-muted); font-size: 0.95rem; }
.tkd__h {
  margin-top: 1.6rem;
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--copper-text);
}

/* ticket pagination */
.pv__showing {
  margin-bottom: 0.6rem;
  font-size: var(--fs-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.pv__showing:empty { display: none; }

.pg { display: flex; flex-wrap: wrap; align-items: center; gap: 0.3rem;
  margin-top: 1.4rem; padding-top: 1.1rem; border-top: 1px solid var(--rule); }
.pg:empty { display: none; }
.pg__btn {
  min-width: 36px;
  height: 36px;
  padding-inline: 0.5rem;
  display: grid;
  place-items: center;
  border: 1px solid var(--rule);
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  transition: background-color 0.2s var(--ease), border-color 0.2s var(--ease);
}
.pg__btn:hover:not(:disabled) { background: var(--bone-warm); border-color: var(--copper); }
.pg__btn[aria-current] {
  background: var(--ink);
  border-color: var(--ink);
  color: #FFFFFF;              /* 12.78:1 */
  font-weight: 500;
}
/* disabled still has to be legible, just plainly unavailable */
.pg__btn:disabled { color: var(--ink-muted); border-color: var(--rule-soft); cursor: not-allowed; }
.pg__btn--step { font-size: 1.1rem; line-height: 1; }
.pg__gap { padding-inline: 0.2rem; color: var(--ink-muted); }

/* ==== components.css ==== */
/* ==========================================================================
   Axteria Group Berhad — footer, floating contact, lightbox
   ========================================================================== */

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

.footer {
  background: var(--ink-deep);
  color: var(--on-dark-mut);
  padding-block: clamp(3.5rem, 7vw, 5.5rem) 0;
}

.footer__top {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) repeat(3, minmax(0, 1fr));
  gap: clamp(2rem, 4vw, 3.5rem);
  padding-bottom: clamp(2.5rem, 5vw, 4rem);
}

.footer__brand img {
  height: 62px;
  width: auto;
  /* Flatten the charcoal-and-copper mark to a single white silhouette for the
     dark footer. brightness(0) crushes it to black, invert(1) lifts it to pure
     white — the old multi-stop chain was tuned to land on the off-white the
     page no longer uses. */
  filter: brightness(0) invert(1);
  opacity: 0.92;
  margin-bottom: 1.5rem;
}
.footer__tagline {
  font-family: var(--display);
  font-size: 1.35rem;
  line-height: 1.35;
  color: var(--on-dark);
  max-width: 22ch;
}

.footer__colhead {
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--copper-lite);
  margin-bottom: 1.15rem;
}

.footer__list { display: flex; flex-direction: column; gap: 0.7rem; }
.footer__list a,
.footer__list span { font-size: 0.9rem; color: var(--on-dark-mut); }
.footer__list a { transition: color 0.25s var(--ease); }
.footer__list a:hover { color: var(--copper-lite); }

.footer__social { display: flex; gap: 0.75rem; margin-top: 1.35rem; }
.footer__social a {
  width: 38px; height: 38px;
  display: grid; place-items: center;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 50%;
  transition: background-color 0.25s var(--ease), border-color 0.25s var(--ease);
}
.footer__social a:hover { background: var(--copper-btn); border-color: var(--copper-btn); }
.footer__social svg { width: 17px; height: 17px; }

.footer__legal {
  border-top: 1px solid rgba(255, 255, 255, 0.14);
  padding-block: 1.6rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem clamp(1rem, 2.5vw, 2rem);
  font-size: 0.8rem;
  color: rgba(255, 255, 255, 0.6);
}
.footer__legal a { transition: color 0.25s var(--ease); }
.footer__legal a:hover { color: var(--copper-lite); }
.footer__legal-links { display: flex; flex-wrap: wrap; gap: 0.6rem 1.4rem; }
.footer__copy { margin-right: auto; }

/* delivery signature — required on every deliverable */
.footer__sig {
  border-top: 1px solid rgba(255, 255, 255, 0.14);
  padding-block: 1.1rem;
  text-align: center;
  font-size: var(--fs-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.48);
}
.footer__sig a {
  color: rgba(255, 255, 255, 0.78);
  border-bottom: 1px solid rgba(255, 255, 255, 0.28);
  padding-bottom: 1px;
  transition: color 0.25s var(--ease), border-color 0.25s var(--ease);
}
.footer__sig a:hover { color: var(--copper-lite); border-color: var(--copper-lite); }

@media (max-width: 900px) {
  .footer__top { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer__brand { grid-column: 1 / -1; }
}
@media (max-width: 520px) {
  .footer__top { grid-template-columns: 1fr; }
  .footer__copy { margin-right: 0; }
}

/* --------------------------------------------------------------------------
   floating WhatsApp
   The brand green is fixed at #25D366, and against a white page that is only
   1.98:1 — well under the 3:1 WCAG 1.4.11 wants for a control's boundary. The
   ring, not the green, is what makes the button perceivable: at 0.55 alpha it
   composites to #7E8285 over white, 3.88:1. (At the 0.28 it carried on the
   old off-white background this measured 1.84:1 and did not qualify.)
   -------------------------------------------------------------------------- */

.wa-float {
  position: fixed;
  right: clamp(1rem, 2.5vw, 1.85rem);
  bottom: clamp(1rem, 2.5vw, 1.85rem);
  z-index: 120;
  width: 56px;
  height: 56px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--wa-green);
  box-shadow: 0 0 0 1px rgba(21, 27, 34, 0.55),
              0 10px 30px rgba(21, 27, 34, 0.26);
  transition: transform 0.28s var(--ease), box-shadow 0.28s var(--ease);
}
.wa-float:hover {
  transform: translateY(-3px) scale(1.04);
  box-shadow: 0 0 0 1px rgba(21, 27, 34, 0.62),
              0 16px 38px rgba(21, 27, 34, 0.32);
}
.wa-float svg { width: 30px; height: 30px; fill: #fff; }

/* pulse ring */
.wa-float::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--wa-green);
  opacity: 0.55;
  z-index: -1;
  animation: wa-pulse 2.6s var(--ease) infinite;
}
@keyframes wa-pulse {
  0%   { transform: scale(1);    opacity: 0.55; }
  70%  { transform: scale(1.75); opacity: 0; }
  100% { transform: scale(1.75); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .wa-float::before { animation: none; opacity: 0; }
}
@media (max-width: 600px) {
  .wa-float { width: 50px; height: 50px; }
  .wa-float svg { width: 26px; height: 26px; }
}

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

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  grid-template-rows: auto 1fr auto;
  background: rgba(11, 15, 20, 0.96);
  opacity: 0;
  transition: opacity 0.24s var(--ease);
}
.lightbox.is-open { opacity: 1; }
.lightbox[hidden] { display: none; }

.lightbox__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.1rem clamp(1rem, 3vw, 2rem);
  color: rgba(255, 255, 255, 0.8);
  font-size: var(--fs-meta);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
}

.lightbox__stage {
  position: relative;
  display: grid;
  place-items: center;
  padding-inline: clamp(0.75rem, 3vw, 2rem);
  min-height: 0;
}
.lightbox__stage img {
  max-width: min(100%, 1400px);
  max-height: 100%;
  width: auto;
  object-fit: contain;
}

.lightbox__foot {
  padding: 1.1rem clamp(1rem, 3vw, 2rem) 1.6rem;
  text-align: center;
  color: rgba(255, 255, 255, 0.72);
  font-size: 0.9rem;
  min-height: 3.25rem;
}

.lb-btn {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 50%;
  color: var(--on-dark);
  flex: none;
  transition: background-color 0.25s var(--ease), border-color 0.25s var(--ease);
}
.lb-btn:hover { background: rgba(255, 255, 255, 0.14); border-color: rgba(255, 255, 255, 0.5); }
.lb-btn svg { width: 19px; height: 19px; }

.lightbox__nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
}
.lightbox__nav--prev { left: clamp(0.4rem, 2vw, 1.5rem); }
.lightbox__nav--next { right: clamp(0.4rem, 2vw, 1.5rem); }

@media (max-width: 600px) {
  .lightbox__nav { top: auto; bottom: -0.25rem; transform: none; }
  .lightbox__nav--prev { left: 25%; }
  .lightbox__nav--next { right: 25%; }
  .lightbox__foot { padding-bottom: 4.5rem; }
}
