/* ============================================================
   ABOUT   (loads AFTER style.css, so it only adds)
   One fixed full-viewport stage: wheel / touch / keys turn the
   three.js signal pole; the page itself never moves. Namespaced
   under .ab2 so nothing here reaches the other pages.
   ============================================================ */

/* the page never scrolls: wheel / touch / keys turn the pole instead, so
   there is no track, no scrollbar and no end to reach */
body.ab2-page { overflow: hidden; overscroll-behavior: none; height: 100svh; }
body.ab2-page::-webkit-scrollbar { display: none; }
body.ab2-page { scrollbar-width: none; }

.ab2 {
  position: relative;
  height: 100svh;
  /* no ground of its own: `body.ab2-page` carries the blue PAPER (style.css),
     so this page is the same material as every other page instead of a flat
     field of colour. */
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  align-items: center;
  gap: clamp(20px, 4vw, 72px);
  padding: clamp(84px, 12vh, 130px) clamp(24px, 6vw, 110px) clamp(32px, 5vh, 64px);
  overflow: hidden;
}
.ab2-card { grid-column: 2; }

/* ---- the 3D stage: full-bleed behind everything, so the heads can
   swing past the card's column without being cut by a canvas edge ---- */
.ab2-stage {
  position: absolute; inset: 0;
  z-index: 1;                  /* the pole sits BEHIND the word */
}
.ab2-card { position: relative; z-index: 4; }

/* ---- the blur plate ----
   The word stands in FRONT of the pole now, so something has to separate the
   two. This is a band of backdrop blur across the foot of the stage, masked
   with a linear gradient so it is strongest at the bottom and gone by the top
   — the pole softens as it passes under the type instead of cutting through
   it. `--blur-top` is set from the word's own measured box (about.js), so the
   band always starts just above the letters whatever size they solve to. */
.ab2-blur {
  position: absolute;
  left: 0; right: 0;
  top: var(--blur-top, 58%);
  bottom: 0;
  z-index: 2;
  pointer-events: none;
  backdrop-filter: blur(14px) saturate(1.05);
  -webkit-backdrop-filter: blur(14px) saturate(1.05);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, rgba(0, 0, 0, .55) 34%, #000 72%);
  mask-image: linear-gradient(to bottom, transparent 0%, rgba(0, 0, 0, .55) 34%, #000 72%);
}
/* without backdrop-filter a plate here would be a flat block of nothing, which
   is worse than no plate at all — so it simply does not appear */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .ab2-blur { display: none; }
}

/* ---- the word --------------------------------------------------
   From the reference: a huge white word lying along the foot of the
   page, with the pole standing in front of it. It is the page's h1;
   the title used to be a small label inside the card's grey plate,
   which made it a caption rather than the page's voice.
   Sized off BOTH axes — a short, wide window would otherwise drive
   it into the card, which is the same trap the Contact page's
   "slide in." hit. */
.ab2-big {
  position: absolute;
  z-index: 3;                  /* in FRONT of the pole */
  /* the reference starts the word at ~3% of the frame, not at the page's own
     6% gutter — which is also what keeps it from running under the card */
  left: clamp(14px, 3vw, 60px);
  bottom: clamp(4px, 1vh, 18px);
  margin: 0;
  font-family: var(--roc); font-weight: 700;
  /* about.js › fitBig() overrides both of these. It sizes the word to exactly
     the size the Contact page's "slide in." would be at this width, and sets
     the floor from the font's own metrics. These hold before the first resize,
     and if the module never runs. */
  font-size: min(30vw, calc(var(--vhu) * 44));
  line-height: 1;
  /* -.05em, not the -.055em the rest of the page's headings use: this word is
     the Contact page's display type and `.ct2-big` is tracked at -.05em. The
     probe that sizes it measures "slide in." in THIS element's font, so if the
     tracking differed the two pages' words would differ in size by about 1.5%. */
  letter-spacing: -.05em;
  color: #fff;
  white-space: nowrap;
  pointer-events: none;
  user-select: none;
}
.ab2-stage canvas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block;
  touch-action: none;
}
/* handle chip that follows the pointer over a head */
.ab2-chip {
  position: absolute;
  translate: 14px 14px;
  font-family: var(--helv); font-weight: 700; letter-spacing: -.04em;
  font-size: clamp(11px, 1.05vw, 14px);
  white-space: nowrap;
  background: #fff; color: var(--ink);
  padding: .38em .85em; border-radius: 999px;
  pointer-events: none;
  z-index: 2;
}
/* (the "scroll to turn the pole" hint was removed on request — the page
   carries no instruction now. about.js still sets `.scrolled` on the stage
   when the pole first turns; nothing styles it any more.) */
/* if WebGL never came up, the card still carries the links */
.ab2-stage.no-gl canvas { display: none; }

/* ============ THE CARD ============ */
/* The Contact page's panel, verbatim: solid white, the same soft drop shadow
   and inset hairline, the same radius and padding. It was glass for one
   version; it is not any more. A flex column so the picture plate takes
   whatever height the copy leaves, which is what gives it the tall image. */
.ab2-card {
  display: flex; flex-direction: column;
  /* full height of the row — the grid centres its items, so the card has to
     opt out of that to stand up. It can never overflow: the row IS the content
     box, which is the viewport less `.ab2`'s padding. */
  align-self: stretch;
  max-height: calc(var(--vhu) * 86);
  background: #fff;
  border-radius: clamp(18px, 2vw, 30px);
  box-shadow: 0 18px 50px rgba(20, 20, 80, .16), inset 0 0 0 1px #eceaf6;
  padding: clamp(18px, 2.2vw, 34px);
  max-width: 560px;
  width: 100%;
  justify-self: end;
}
/* The picture plate. In the reference it is the tallest thing in the card and
   carries no type — the title moved out to the word along the foot of the
   page. `flex: 1` lets it take whatever height the copy leaves, which is what
   gives the reference its tall image. */
.ab2-plateimg {
  position: relative;
  flex: 1 1 auto;
  min-height: clamp(120px, 20vh, 220px);
  border-radius: clamp(20px, 2.2vw, 32px);
  background: #8d8a9a center / cover no-repeat;
  margin-bottom: clamp(14px, 1.6vw, 24px);
}
/* the plate is for a photo. Without one it read as a broken grey box, so it
   only shows once there is a picture in it (the theme: the About page's
   Featured Image) */
.ab2-plateimg:not(.has-img) { display: none; }
.ab2-plateimg.has-img { overflow: hidden; background-color: #3d5cf5; }
.ab2-plateimg picture,
.ab2-plateimg img {
  position: absolute; inset: 0;
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: 52% 38%;
}
.ab2-btns { display: flex; flex-wrap: wrap; gap: clamp(10px, 1.1vw, 16px); margin: 0 0 clamp(12px, 1.3vw, 18px); }
.ab2-btn {
  font-family: var(--helv); font-weight: 700; letter-spacing: -.06em;
  font-size: clamp(15px, 1.35vw, 20px);
  text-decoration: none;
  padding: .68em 2.3em;
  border-radius: 999px;
  transition: transform .18s var(--ease);
}
.ab2-btn:hover { transform: translateY(-3px); }
.ab2-btn-1 { background: var(--blue); color: #fff; }
.ab2-btn-2 { background: var(--lav); color: var(--ink); }
.ab2-body {
  font-family: var(--roc); font-weight: 500;
  font-size: clamp(14px, 1.2vw, 18px);
  line-height: 1.5;
  color: #3a3550;
  margin: 0 0 clamp(12px, 1.4vw, 20px);
  padding: 0 clamp(4px, .4vw, 8px);
}
/* (the Instagram / LinkedIn links were removed from the card on request — the
   two LED heads on the pole still open both) */

/* ---- one column: word on top, pole behind, card below ----
   There is no room to lay the word along the foot AND stand the card on it, so
   here it returns to the flow as an ordinary heading at the top, and the pole
   is framed into the gap between the two (see about.js › resize).

   The test is ORIENTATION, not width alone. It used to be `max-width: 900px`,
   which also caught a short LANDSCAPE window: 883x590 stacked a word, a pole
   and a full card down 590px and left the pole about 60px to live in. A wide
   window has room for two columns whatever its width; a portrait one does not.
   **about.js reads this exact query through matchMedia** — if the two ever
   disagree, the script clears the size of a word the CSS is still laying along
   the floor. */
@media (max-width: 900px) and (orientation: portrait), (max-width: 620px) {
  .ab2 {
    grid-template-columns: 1fr;
    align-items: end;
    gap: 0;
    padding: clamp(76px, 11vh, 100px) 16px 16px;
  }
  /* There is no room to lay the word along the foot AND stand the card on it,
     so on one column it returns to the flow as an ordinary heading at the top
     and the pole is framed into the gap between the two (about.js › resize). */
  .ab2-big {
    position: static;
    /* sized off BOTH axes: on a short screen the word has to give the pole and
       the card their room back */
    font-size: clamp(34px, min(13vw, calc(var(--vhu) * 10)), 86px);
    line-height: .9;
    margin-bottom: auto;
  }
  .ab2-card { grid-column: 1; }
  .ab2-card {
    justify-self: stretch; max-width: none; padding: 14px; border-radius: 24px;
    align-self: end;
    max-height: calc(var(--vhu) * 58);
  }
  .ab2-plateimg { min-height: clamp(96px, 15svh, 180px); margin-bottom: 12px; }
  .ab2-btns { margin: 0 0 10px; }
  .ab2-body { font-size: 13px; line-height: 1.45; margin-bottom: 10px; }
}
