/* ==========================================================================
   Huda Academy — Message from the Principal  (/about/principal/)

   Loaded ONLY by about/principal/index.html, after site.css and never instead
   of it.

   WHAT THIS IS. A port of the client's concept page,
   <https://huda-academy-about-concept.ahmed206429.chatgpt.site/about/principal/>,
   first captured 2026-09-18 and kept verbatim at lab/about-principal-ref.html.
   The client asked for it one-to-one, changing only what is clearly wrong.
   Deviations that still apply are marked with their reason; later client-led
   redesigns are dated at the sections they supersede.

   THE SPEC MOVED ON 2026-09-19. The client supplied a NEW export of the same
   concept, captured at lab/concept-2026-09-19/about-principal-ref.html, and
   that file is now the specification — tools/verify-principal.mjs reads it.
   Two sections were relaid out by it and are rebuilt here from the new export:

     .abp-priorities  was three equal cards, then a scattered deep-red flow;
                      direct client feedback now makes it a pinned photographic
                      chapter deck with compact burgundy copy panels.
     .abp-leadership  was a list of four full-width rows; it is now a tile grid
                      of four rust-filled panels, the first one spanning three
                      rows and carrying the principal's photograph.

   The letter now uses the supplied reference's centred editorial column and
   clean burgundy pull quote. The hero uses a full-bleed classroom photograph;
   the principal's portrait remains in the related leadership tile.

   THIS PAGE FOLLOWS /about/ AND /about/mission/, NOT site.css. Those two were
   built the same day from the same author's concept and settled the house rule
   for this family: keep the concept's palette and typefaces as authored, and
   change only what actively conflicts with the real site. This is the third
   page of that family and mirrors their tokens.

   EVERYTHING IS NAMESPACED `abp-`, AND THAT IS NOT TIDINESS.
   site.css already owns .hero (13 rules), .cta (5), .btn (9) and .nav for the
   home page, and the concept names four of its own sections exactly that. Two
   of the collisions are actively dangerous:

     - site.css .hero is built around the home page's video and 100svh sizing;
       a bare .hero here would inherit it and size this page's split hero to
       the viewport.
     - the concept's `.progress` is a fixed-position bar. site.css has no
       .progress, but .arrow, .dot, .rule and .signature are generic enough
       that an unprefixed version is a collision waiting for the next section
       to be designed.

   So the concept's class names all carry the prefix. Nothing on this page can
   be reached by a site.css selector written for the home page, and nothing
   here can reach the home page either.

   TOKENS are declared on .abp rather than :root, because :root belongs to
   site.css and this file is a guest on one page. They mirror about.css; the
   two must stay in step, and tools/verify-principal.mjs asserts it.
   ========================================================================== */

.abp {
  /* The concept's own values, read off its stylesheet.

     DEVIATION 1 — the two reds are the site's, not the concept's.
     Concept: --rust #9F231C, --deep #711E15.
     Site:    --terracotta #A83226, --terracotta-deep #86251B.
     Measured dE76 4.24 and 5.18 — small, and the page now sits under the real
     nav, which is painted --terracotta. Two reds that close together, adjacent
     on one screen, read as a mistake rather than a choice. One red on the page.
     This is the same call /about/ made for the same reason. */
  --abp-rust: var(--terracotta);
  --abp-deep: var(--terracotta-deep);

  /* Kept as the concept authored them, matching /about/. Each is far enough
     from its site.css neighbour to be a real choice rather than a rounding
     error — measured dE76 against the site token in brackets. */
  /* DEVIATION 13 — the cream is the family's, not this concept's.
     This concept authored #F3ECE1; /about/ and /about/mission/ both authored
     and kept #F4EEE4. The two are 1.9 dE76 apart, which is under the ~2.3
     threshold where a flat field reads as changed at all — but it is the
     ground of the hero, and a reader moving from /about/ to this page would
     cross it. One cream in the family. Mirrored from about.css and asserted by
     tools/verify-principal.mjs so it cannot drift back. */
  --abp-cream: #F4EEE4;   /* site --paper-2 #EEE7DC  [2.28 vs the site token] */
  --abp-paper: #F8F4EE;   /* site --paper   #F8F4EE  [3.24] */
  --abp-gold: #CFAF82;    /* site --gold    #F2A33A  [12.05 — plainly deeper] */
  --abp-ink: var(--ink);  /* #23160C vs #34231A [3.65]: same colour, use the token */
  --abp-line: rgba(35,22,12,.17);
  --abp-shadow: 0 28px 70px rgba(55,27,12,.15);

  background: var(--abp-paper);
  color: var(--abp-ink);
  font-family: "DM Sans", Inter, ui-sans-serif, system-ui, sans-serif;

  /* DEVIATION 14 — line-height is reset to `normal`, which is what the concept
     actually uses. Its <body> declares no line-height at all, so every element
     it does not set one on falls to `normal`. site.css sets `line-height:1.6`
     on <body>, and without this reset the whole page inherits 1.6 wherever the
     concept relied on the default: the crumbs, the eyebrows, the salutation,
     the portrait note, and both sets of headings.

     Measured rather than assumed. The leadership rows rendered 124px tall
     against the reference's 110px in the same browser at the same width,
     because .abp-link-row h3 at 38px was getting 1.6 (60.8px) instead of
     `normal` (~48px). Everything the concept sets explicitly — 1.75 on the
     letter body, 1.7 on the card copy, 1.3 on the pullquote — still wins over
     this, so only the unset cases move, which is exactly the set that was
     wrong. */
  line-height: normal;

  /* DEVIATION 3 — the concept's `body{overflow-x:hidden}` is NOT copied.
     site.css already sets `html,body{overflow-x:clip}`, and CLAUDE.md is
     explicit that `hidden` must never be used because it makes <body> a scroll
     container. */
}

/* DEVIATION 4 — the concept's global rules are scoped, not global.
   It ships `*{box-sizing:border-box}`, `a{color:inherit;text-decoration:none}`
   and `html{scroll-behavior:smooth}` unscoped. site.css already owns the first
   two for the whole site; `scroll-behavior` on <html> is a document-level
   property this page has no business setting for every other page that shares
   the stylesheet cache. Only the text-decoration reset is actually needed. */
.abp a { text-decoration: none; }

/* ---------- reveals ------------------------------------------------------
   DEVIATION 5 — the concept hides content with a bare `[data-reveal]{opacity:0}`
   and nothing else. If its script 404s or throws, the whole letter stays
   invisible forever. That is the exact failure CLAUDE.md's "content visibility
   must never depend on JS or an animation firing" rule was written against.

   Three guards, matching how about.css already does it:
     1. gated on `html.js`, which the inline <head> script sets — so with no
        JS at all, nothing is ever hidden in the first place;
     2. revealed per element by `.is-in`, which the page's own small script
        adds as each one scrolls in — this preserves the concept's staggered
        fade-up;
     3. revealed wholesale by `html.abp-revealed`, which a 6s timer in the
        page's inline <head> script sets if the page script never armed.

   Only content carries these — never a control, per CLAUDE.md. The concept
   puts [data-reveal] on the CTA's <a class="btn"> AND on each of the four
   <a class="feature-link"> tiles. Every one of those is an anchor, so none of
   them gets one here: an anchor that starts at opacity 0 and waits on a
   transition that may never finish is the burger bug of 2026-08-04 with a
   different class name. The tiles are the page's navigation and are simply
   always there. tools/verify-principal.mjs gate D5 asserts it directly. */
html.js .abp [data-rv] {
  opacity: 0;
  transform: translateY(30px);
  transition: opacity .8s ease, transform .8s cubic-bezier(.2, .7, .2, 1);
}
html.js .abp [data-rv].is-in { opacity: 1; transform: none; }
/* THE FAILSAFE PATH KILLS THE TRANSITION, and that is not belt-and-braces —
   without it the failsafe does nothing at all. Caught on this page: the 6s
   timer fired, `html.abp-revealed` was on the element, and all 19 [data-rv]
   elements were still computing opacity 0 twelve seconds in.

   CLAUDE.md states the reason: a running CSS transition is a higher cascade
   origin than author !important, so a transition that starts and never
   finishes pins its element at the START value and no author rule can beat
   it. In a backgrounded tab requestAnimationFrame is frozen, so the 0 -> 1
   opacity transition this rule would otherwise trigger never advances a
   frame. `transition:none` here means the reveal is a cascade change with no
   transition to start, so it applies instantly.

   This is a rescue, not an effect. The staggered fade lives on .is-in above
   and is untouched. /about/mission/ does the same; /about/ does NOT and is
   still exposed. */
html.abp-revealed .abp [data-rv] {
  opacity: 1;
  transform: none;
  transition: none;
}
.abp .abp-delay-1 { transition-delay: .1s; }
.abp .abp-delay-2 { transition-delay: .2s; }

/* ---------- scroll progress ----------------------------------------------
   DEVIATION 6 — the bar is anchored to the top of the viewport, not to 136px.
   The concept hard-codes `top:136px`, which is its own fixed shell: a 46px
   notice plus a 90px nav. Our shell is the real one from index.html, it is
   `position:relative`, and it scrolls away — so 136px would leave a gold line
   floating in the middle of the page as soon as the reader moved. Pinned to 0
   it reads as a progress bar at every scroll position, which is what it is. */
.abp-progress {
  position: fixed;
  z-index: 60;
  top: 0;
  left: 0;
  height: 3px;
  width: 0;
  background: var(--abp-gold);
  transform-origin: left center;
}

/* ---------- hero: MOVED TO THE MASTER, 2026-09-27 -------------------------
   This page's own hero - the split grid, the burgundy portrait side and its
   office photograph, the crumbs, the quoted lede and the letter meta line -
   is gone. The client decided that every interior page opens with the one
   master hero, this one included ("lose them"), and assets/css/page-hero.css
   owns it. Do not restyle the hero here: a rule in this file that reaches
   into .page-hero makes this page the odd one out, which is exactly what the
   decision was made to end. DEVIATION 7 (minmax(0) on the hero's grid) and
   DEVIATION 2a (the portrait side's dark ground) went with it. The
   principal's own portrait was never the hero's; it stays with the
   signature at the end of the letter. */
.abp-eyebrow {
  font-size: 12px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--abp-rust);
  font-weight: 700;
  margin-bottom: 20px;
}

/* ---------- the letter ---------------------------------------------------- */
.abp-letter {
  padding: clamp(92px, 10vw, 155px) clamp(24px, 6.6vw, 96px);
  position: relative;
}
/* One centred editorial column, matching the approved letter reference. */
.abp-letter-shell {
  max-width: 940px;
  margin: auto;
  position: relative;
}
.abp-letter-side {
  text-align: center;
  margin-bottom: 17px;
}
.abp-letter-side p {
  font-size: 10px;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--abp-rust);
  font-weight: 700;
  margin: 0;
}

.abp-letter-body { max-width: none; min-width: 0; }
/* The letter's own title and standfirst, new in the 2026-09-19 concept. They
   are inside a <header> rather than loose in the body so that
   `.abp-letter-body > p` - which sets the letter's serif body type and hangs
   the drop cap off the first of them - cannot reach the standfirst. */
.abp-letter-heading {
  margin-bottom: clamp(60px, 7vw, 88px);
  text-align: center;
}
.abp-letter-heading h2 {
  font-family: "Libre Caslon Display", serif;
  font-weight: 400;
  font-size: clamp(40px, 4.1vw, 60px);
  line-height: 1.06;
  letter-spacing: -.025em;
  margin: 0;
}
.abp-letter-intro {
  margin: 17px auto 0;
  font-size: 15px;
  line-height: 1.65;
  color: #6B584F;
  max-width: 600px;
}
.abp-salutation {
  font-family: "Libre Caslon Display", serif;
  font-size: clamp(28px, 2.6vw, 36px);
  margin-bottom: 30px;
}
/* DEVIATION 8 — scoped to the body, not written as a bare child selector on
   the section. The concept's `.letter-body>p` is fine in isolation; here the
   same rule has to not reach the aside's <p>, which is the uppercase kicker in
   the sticky rail and would otherwise be set at 25px serif. */
.abp-letter-body > p {
  font-family: "Libre Caslon Display", serif;
  font-size: clamp(17px, 1.35vw, 20px);
  line-height: 1.8;
  color: #503E36;
  margin: 0 0 28px;
}
/* DEVIATION 9 — `::first-letter`, not `:first-letter`. The concept uses the
   legacy single-colon form. Both work; the double-colon form is the one that
   is specified, and the two are not interchangeable in every engine for
   pseudo-elements added after CSS2. Same glyph, same size. */
.abp-letter-body > p:first-of-type::first-letter {
  font-size: 76px;
  float: left;
  line-height: .72;
  color: var(--abp-rust);
  margin: 13px 12px 0 0;
}

.abp-pullquote {
  margin: 48px 0;
  padding: clamp(34px, 4.3vw, 55px) clamp(38px, 5.5vw, 70px);
  /* Clean brand burgundy: no green and no grain/texture layer. */
  background: var(--abp-deep);
  color: #FCF7EE;
  position: relative;
  font-family: "Libre Caslon Display", serif;
  font-size: clamp(25px, 2.4vw, 34px);
  line-height: 1.3;
}
.abp-pullquote::before {
  content: "\201C";
  position: absolute;
  color: var(--abp-gold);
  font-size: 70px;
  left: 17px;
  top: 6px;
  opacity: .7;
}

.abp-signature {
  max-width: 590px;
  margin-top: 62px;
  padding-top: 34px;
  border-top: 1px solid var(--abp-line);
  display: grid;
  grid-template-columns: 132px minmax(0, 1fr);
  gap: 28px;
  align-items: center;
}
.abp-signature__portrait {
  position: relative;
  overflow: hidden;
  aspect-ratio: 5 / 6;
  margin: 0;
  border-radius: 70px 70px 4px 4px;
  background: var(--abp-deep);
  box-shadow: 0 16px 34px rgba(71,35,19,.16);
}
.abp-signature__portrait img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  object-position: 50% 30%;
  filter: saturate(.88) contrast(1.03);
}
.abp-signature__details { min-width: 0; }
.abp-signature__close {
  display: block;
  margin-bottom: 11px;
  color: #7D685D;
  font-family: "Libre Caslon Display", serif;
  font-size: 16px;
  font-style: italic;
}
.abp-signature .abp-script {
  font-family: "Mrs Saint Delafield", cursive;
  font-size: 59px;
  color: var(--abp-rust);
  line-height: 1;
}
.abp-signature b {
  display: block;
  font-size: 13px;
  letter-spacing: .13em;
  text-transform: uppercase;
  margin-top: 9px;
}
.abp-signature__details > span:not(.abp-signature__close) { font-size: 13px; color: #7D685D; }

/* ---------- the three promises --------------------------------------------
   CLIENT-DIRECTED REDESIGN 2026-09-19. The concept's scattered dark band is
   superseded by a pinned chapter deck. A later client pass replaced the solid
   cards with real photographs while retaining the same physical stack. The
   unenhanced state is deliberately a normal three-card flow; .is-stack-ready
   is added only after the page script has found every required element and
   installed the scroll driver. */
.abp-priorities {
  position: relative;
  background: var(--abp-cream);
  color: var(--abp-ink);
  overflow: clip;
}
.abp-values-sticky {
  min-height: 100svh;
  display: grid;
  grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr);
  align-items: center;
  gap: clamp(40px, 7vw, 110px);
  padding: clamp(70px, 8vw, 120px);
}
.abp-values-heading { position: relative; z-index: 10; }
.abp-values-label {
  display: block;
  margin-bottom: 20px;
  color: var(--abp-rust);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
}
.abp-priorities h2,
.abp-leadership h2 {
  font-family: "Libre Caslon Display", serif;
  font-size: clamp(44px, 5.4vw, 78px);
  line-height: 1.02;
  letter-spacing: -.035em;
  margin: 0;
}
.abp-values-heading h2 {
  max-width: 590px;
  font-size: clamp(45px, 6vw, 82px);
  line-height: .95;
  letter-spacing: -.045em;
}
.abp-values-heading > p {
  max-width: 420px;
  margin: 28px 0 0;
  color: #66544D;
  font-size: 16px;
  line-height: 1.7;
}
.abp-chapter-deck { display: grid; gap: 18px; }
.abp-value-chapter {
  position: relative;
  min-height: 420px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: clamp(22px, 2.6vw, 36px);
  overflow: hidden;
  isolation: isolate;
  border-radius: 28px;
  background: #5C1F15;
  color: #FEFAF3;
  transform-origin: center bottom;
  box-shadow: 0 30px 80px rgba(64,27,10,.20);
}
.abp-chapter-photo {
  position: absolute;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  pointer-events: none;
}
.abp-chapter-number {
  position: relative;
  z-index: 1;
  align-self: flex-start;
  padding: 8px 11px;
  border: 1px solid rgba(254,250,243,.18);
  border-radius: 999px;
  background: rgba(82,24,14,.90);
  box-shadow: 0 8px 24px rgba(37,16,8,.18);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: #FCCA72;
}
.abp-chapter-content {
  position: relative;
  z-index: 1;
  align-self: flex-start;
  width: min(100%, 460px);
  padding: clamp(22px, 2.6vw, 32px);
  border: 1px solid rgba(254,250,243,.14);
  border-radius: 20px;
  background: rgba(82,24,14,.94);
  box-shadow: 0 18px 48px rgba(33,15,7,.26);
}
.abp-chapter-content h3 {
  margin: 0;
  font-family: "Libre Caslon Display", serif;
  font-size: clamp(31px, 3.4vw, 46px);
  font-weight: 400;
  line-height: 1;
  letter-spacing: -.035em;
}
.abp-chapter-content p {
  margin: 14px 0 0;
  color: rgba(254,250,243,.88);
  font-size: 14px;
  line-height: 1.6;
}
.abp-values-progress { display: none; }

/* Enhanced state. Only transform changes while the page scrolls; the section
   height supplies the runway and sticky does the pinning without JS layout
   writes. The page script writes each card's transform and the fill's scale. */
.abp-priorities.is-stack-ready { min-height: calc(100svh + 2400px); }
.abp-priorities.is-stack-ready .abp-values-sticky {
  position: sticky;
  top: 0;
  height: 100svh;
  min-height: 620px;
  overflow: hidden;
}
.abp-priorities.is-stack-ready .abp-chapter-deck {
  position: relative;
  height: min(570px, 68svh);
  min-height: 480px;
  perspective: 1200px;
}
.abp-priorities.is-stack-ready .abp-value-chapter {
  position: absolute;
  inset: 0;
  min-height: 0;
  will-change: transform;
}
.abp-priorities.is-stack-ready .abp-value-chapter-1 { z-index: 1; }
.abp-priorities.is-stack-ready .abp-value-chapter-2 { z-index: 2; }
.abp-priorities.is-stack-ready .abp-value-chapter-3 { z-index: 3; }
.abp-priorities.is-stack-ready .abp-values-progress {
  position: absolute;
  right: clamp(24px, 3vw, 50px);
  bottom: 32px;
  left: clamp(24px, 3vw, 50px);
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 14px;
  color: #7D685D;
  font-size: 11px;
  letter-spacing: .12em;
}
.abp-progress-line {
  position: relative;
  flex: 1;
  height: 2px;
  overflow: hidden;
  background: rgba(35,22,12,.15);
}
.abp-progress-fill {
  position: absolute;
  inset: 0;
  background: var(--abp-rust);
  transform: scaleX(0);
  transform-origin: left;
}

/* ---------- leadership links ----------------------------------------------
   REBUILT 2026-09-19 from lab/concept-2026-09-19/. The 2026-09-18 concept made
   these four related pages a hairline-ruled list of full-width rows; the new
   export makes them a tile grid - one tall tile carrying the principal's
   photograph down the left, three short ones stacked beside it. The row rules
   (.abp-link-list / .abp-link-row) are deleted rather than kept, for the same
   reason the priority cards are. */
.abp-leadership {
  padding: clamp(100px, 11vw, 170px) clamp(25px, 8vw, 145px);
  background: #EEE7DC;
}
.abp-leadership-head {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: 35px;
  margin-bottom: 55px;
  /* NOT the concept's, and kept from the 2026-09-18 port. The concept lets this
     row stay a two-up flex all the way down to its own 760px breakpoint, where
     it becomes a block. Between ~760 and ~1000 the heading and the 470px
     paragraph together are wider than the padded content box, and without a
     wrap the paragraph is squeezed to a column of two-word lines. Wrapping is
     the same information in the same order. */
  flex-wrap: wrap;
}
.abp-leadership-head > div { max-width: 690px; }
.abp-leadership-head p { max-width: 470px; color: #66544D; line-height: 1.7; margin: 0; }

.abp-link-grid {
  display: grid;
  /* `minmax(0, ...)` rather than the concept's bare `1.2fr .8fr`: the first
     tile holds a 640px-wide <img>, and a bare fr track is min-width:auto, so
     the image's intrinsic width can refuse to shrink and push the grid past
     the viewport. Same call as DEVIATION 7. */
  grid-template-columns: minmax(0, 1.2fr) minmax(0, .8fr);
  grid-template-rows: repeat(3, 205px);
  gap: 18px;
}
.abp-feature-link {
  position: relative;
  overflow: hidden;
  padding: 32px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  background: var(--abp-rust);
  color: #FFFFFF;
  min-height: 0;
}
/* The photograph tile spans all three rows of the left column. Auto-placement
   then fills the right column top to bottom with the other three. */
.abp-feature-link:first-child { grid-row: 1 / 4; }
.abp-feature-link img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .8s cubic-bezier(.2, .7, .2, 1);
}
/* THE TILE GROUND IS A PHOTOGRAPH ON ALL FOUR OF THEM, AND THIS RULE IS WHERE
   THAT IS SAID ONCE.

   DEVIATION 20 - the concept's second scrim is dropped, because the thing it
   was for is gone. Until 2026-09-19 only the first tile carried a picture, so
   the concept scrims tile 1 with a bottom-up ramp and the other three with a
   115deg ramp over the bare rust: a fill treatment, not a photo treatment. All
   four tiles now carry their destination's photograph, and that diagonal ramp
   puts its darkest end at the RIGHT of the tile while the label and the title
   sit bottom-LEFT, so over a picture it thins out exactly where the text has
   to stay legible. One vertical ramp on all four is the concept's own
   treatment of its one photographic tile, applied to four photographic tiles.
   A block of four links scrimmed two different ways does not read as one
   component, which is the whole reason the tiles are a component.

   DROPPED WITH IT: `.abp-feature-link--photo::after`, the port's own third
   scrim, and the modifier class in the markup that selected it. The rule was
   0-1-1 and sat after `:not(:first-child)::after` at 0-2-1, so it never once
   won a cascade it was in - the tile it was written for has been wearing the
   diagonal ramp all along. "The tile with the photograph" no longer picks
   anything out in any case.

   THE RUST STAYS ON `.abp-feature-link`, AS THE DECODE FALLBACK AND NOTHING
   ELSE: the colour visible for the few hundred ms before the picture arrives.
   That is the same reading tools/check-page-rules.mjs gives /about/board/'s
   `.brd-resource{background:#7A1E14}` - it counts the elements carrying the
   class and exempts the fill only when every one of them holds a full-bleed
   img, which all four here do. The no-flat-dark rule is about a sustained flat
   field a dither can organise itself across; a fallback underneath a picture
   is not one, and a 205px tile is not a large section either. That is also why
   these tiles need no noise film of their own. */
.abp-feature-link::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(0deg, rgba(29,14,5,.9), rgba(29,14,5,.06) 72%);
}
.abp-feature-link:hover img { transform: scale(1.05); }
.abp-label {
  position: relative;
  z-index: 2;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .18em;
  margin-bottom: 9px;
  color: #FFD27A;
}
.abp-feature-link h3 {
  position: relative;
  z-index: 2;
  font-family: "Libre Caslon Display", serif;
  font-size: clamp(24px, 2.6vw, 40px);
  font-weight: 400;
  line-height: 1.08;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
}
.abp-arrow {
  width: 46px;
  height: 46px;
  border: 1px solid rgba(255,255,255,.56);
  border-radius: 50%;
  display: grid;
  place-items: center;
  flex: none;
  /* The concept writes the shorthand `transition:.3s`, which is
     `transition:all .3s` and animates every property the hover happens to
     change, layout ones included. Named properties only, all three of them
     compositor or paint - CLAUDE.md's rule for the radar sweep applied to a
     hover. */
  transition: background .3s, color .3s, transform .3s;
}
.abp-feature-link:hover .abp-arrow {
  background: #FFFFFF;
  color: var(--abp-rust);
  transform: rotate(-35deg);
}
/* DEVIATION 10 - the tiles answer to the keyboard as well as the mouse.
   The concept styles :hover only. These are <a> elements and a keyboard reader
   gets no equivalent of the state at all, which is a WCAG 2.4.7 problem on the
   page's only navigation block. The focus treatment is the hover treatment
   plus a visible ring. The ring is inset, because the tile clips its own
   overflow and an outside ring would be half-cut by the neighbouring tile. */
.abp-feature-link:focus-visible {
  outline: 3px solid var(--abp-gold);
  outline-offset: -3px;
}
.abp-feature-link:focus-visible .abp-arrow {
  background: #FFFFFF;
  color: var(--abp-rust);
  transform: rotate(-35deg);
}

/* ---------- responsive ---------------------------------------------------- */
@media (max-width: 800px) {
  .abp-values-sticky {
    grid-template-columns: minmax(0, 1fr);
    align-content: center;
    gap: 24px;
    padding: 54px 22px 64px;
  }
  .abp-values-heading h2 { font-size: clamp(40px, 12vw, 58px); }
  .abp-values-heading > p { margin-top: 16px; }
  .abp-value-chapter { min-height: 350px; padding: 20px; border-radius: 22px; }
  .abp-chapter-content { padding: 20px; border-radius: 16px; }
  .abp-chapter-content h3 { font-size: clamp(31px, 8vw, 38px); }
  .abp-priorities.is-stack-ready { min-height: calc(100svh + 1900px); }
  .abp-priorities.is-stack-ready .abp-values-sticky { min-height: 560px; }
  .abp-priorities.is-stack-ready .abp-chapter-deck {
    height: clamp(340px, 46svh, 410px);
    min-height: 340px;
  }
  .abp-priorities.is-stack-ready .abp-values-progress { bottom: 18px; }
}

@media (max-width: 760px) {
  .abp-letter { padding: 78px clamp(24px, 6.6vw, 35px); }
  .abp-letter-side { margin-bottom: 17px; }
  .abp-letter-body > p { font-size: 17px; }
  .abp-pullquote { margin: 42px 0; padding: 34px 38px; }
  .abp-leadership { padding: 95px 18px; }
  .abp-leadership-head { display: block; }
  .abp-leadership-head p { margin-top: 22px; }
  /* The tile grid becomes four stacked panels. `display:block` also retires
     `grid-row`, so the photograph tile is simply the first and tallest of
     them. */
  .abp-link-grid { display: block; }
  .abp-feature-link,
  .abp-feature-link:first-child { height: 280px; margin-top: 14px; }
  .abp-feature-link:first-child { height: 460px; }
}

@media (max-width: 420px) {
  .abp-signature { grid-template-columns: 98px minmax(0, 1fr); gap: 20px; }
  .abp-signature .abp-script { font-size: 46px; }
}

/* A pinned two-row composition cannot fit short phones or landscape screens.
   Keep the same content and cards, but return them to normal flow rather than
   clipping either the heading or the deck. */
@media (max-height: 619px), (max-width: 800px) and (max-height: 719px) {
  .abp-priorities.is-stack-ready { min-height: auto; }
  .abp-priorities.is-stack-ready .abp-values-sticky {
    position: relative;
    height: auto;
    min-height: 0;
    overflow: visible;
  }
  .abp-priorities.is-stack-ready .abp-chapter-deck {
    display: grid;
    height: auto;
    min-height: 0;
    gap: 18px;
  }
  .abp-priorities.is-stack-ready .abp-value-chapter {
    position: relative;
    inset: auto;
    min-height: 350px;
    transform: none !important;
    will-change: auto;
  }
  .abp-priorities.is-stack-ready .abp-values-progress { display: none; }
}

/* DEVIATION 12 - reduced motion.
   The concept ships its own `prefers-reduced-motion` block, and it is kept.
   It is extended to every hover transform the concept leaves running, because
   a lift or a scale under the pointer is the same class of motion as the
   fade-up it already turns off. The transition shorthand above already stops
   them animating; these stop them happening at all. */
@media (prefers-reduced-motion: reduce) {
  .abp *,
  .abp *::before,
  .abp *::after { transition: none !important; }
  html.js .abp [data-rv] { opacity: 1; transform: none; }
  .abp-feature-link:hover img,
  .abp-feature-link:hover .abp-arrow,
  .abp-feature-link:focus-visible .abp-arrow { transform: none; }
  .abp-priorities.is-stack-ready { min-height: auto; }
  .abp-priorities.is-stack-ready .abp-values-sticky {
    position: relative;
    height: auto;
    min-height: 0;
    overflow: visible;
  }
  .abp-priorities.is-stack-ready .abp-chapter-deck {
    display: grid;
    height: auto;
    min-height: 0;
    gap: 18px;
  }
  .abp-priorities.is-stack-ready .abp-value-chapter {
    position: relative;
    inset: auto;
    min-height: 350px;
    transform: none !important;
    will-change: auto;
  }
  .abp-priorities.is-stack-ready .abp-values-progress { display: none; }
}

/* ---------- about the principal (live 2026-09-30; the bio itself is still being gathered) ---------------------
   The plan's missing section (docs/OTHER-PAGES-PLAN.md, page 4, row 3): who the
   principal is, after his letter and the three promises. The page's own family:
   Libre Caslon Display at 400 for the name, DM Sans for the rest, the rust
   eyebrow, the cream ground (so the edge reads without a rule line), the
   portrait at 14px radius with the family's shadow. */
.abp-bio {
  background: var(--abp-cream);
  padding: clamp(64px, 7vw, 112px) clamp(24px, 6.6vw, 96px);
}
.abp-bio__shell {
  max-width: 1080px; margin: 0 auto;
  display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: clamp(40px, 6vw, 96px); align-items: center;
}
.abp-bio__portrait { margin: 0; }
.abp-bio__portrait img {
  display: block; width: 100%; height: auto; aspect-ratio: 640 / 768; object-fit: cover;
  border-radius: 14px; box-shadow: var(--abp-shadow);
}
.abp-bio h2 {
  font-family: "Libre Caslon Display", serif; font-weight: 400;   /* the face ships 400 only */
  font-size: clamp(40px, 4.1vw, 60px); line-height: 1.06; letter-spacing: -.025em;
  margin: 0 0 8px;
}
.abp-bio__role { margin: 0 0 30px; font-size: 13px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: #6B584F; }
.abp-bio__text p { margin: 0 0 18px; font-size: clamp(16px, 1.25vw, 18px); line-height: 1.75; color: #503E36; max-width: 560px; }
.abp-bio__contact { margin-top: 28px; display: flex; flex-wrap: wrap; gap: 12px 26px; align-items: center; }
.abp-bio__contact a { font-weight: 700; color: var(--abp-deep); text-decoration: underline; text-underline-offset: 4px; }
.abp-bio__contact a:hover { color: var(--abp-rust); }
/* The bio is not written yet, and the page says so on its face, as the site's
   skeleton pages do (client, 2026-09-30): a red banner where the bio will go.
   Crest red with the family's cream text (6.25:1, measured). Delete it when the bio lands. */
.abp-bio__text .abp-bio__pending {
  margin: 0 0 24px; padding: 14px 18px; border-radius: 8px;
  background: var(--abp-rust); color: #FCF7EE;
  font-size: 15px; line-height: 1.6; max-width: 560px;
}
.abp-bio__text .abp-bio__pending strong { font-weight: 700; }
@media (max-width: 860px) {
  .abp-bio__shell { grid-template-columns: minmax(0, 1fr); }
  .abp-bio__portrait { max-width: 360px; }
}
