/* ==========================================================================
   PAconnect — Why PAconnect
   Page-specific styles. Tokens and shared components come from styles.css;
   nothing here invents a colour, a font or a spacing scale.

   WHY THIS PAGE LOOKS DIFFERENT ON PURPOSE
   index.html and ai-services-2.html run the same section spine — hero, stats,
   friction, services, difference, testimonials, consultation — with the AI page
   inserting three blocks and never dropping or reordering one. A third page on
   that skeleton would make the repetition the site's signature.

   So the consistency here lives in the visual system (tokens, the gold eyebrow
   and rule, the dark/light banding, the type scale, the button treatment) and
   NOT in the section list.

   THE WIDTH LESSON, learned the hard way on 2026-09-09.
   The first build expressed "this page is an essay" by centring a 544px prose
   column on its own. Every section ended up a different width — 544, 480, 992,
   736, 704, 1200 — against a site where every other page holds a single 1200px
   shell. It read as broken, and PK said so immediately.

   Sections now sit on the same 1200px shell as the rest of the site. The prose
   keeps a 660px measure, but the heading sits in a rail beside it so the
   SECTION fills the shell even though the LINE does not. Differentiation comes
   from the devices — the pull quote, the callout, the flow, the definition list
   — never from starving the content width. Only the two centred display blocks
   (pull quote, close) are narrower, and that is a deliberate contrast.

   Deliberately absent, and please keep them absent: a stats band, the friction
   picker, a services card grid, a three-card testimonial row.
   ========================================================================== */

/* ------------------------------------------------------------- hero ----- */
/* Inherits .hero wholesale. The homepage hero makes a statement and offers two
   buttons; this one makes a recognition and offers one, so it wants less
   vertical drama and a longer measure for a two-line headline. */

.hero--essay { --hero-size: 58px; --hero-measure: 72%; }
.hero--essay .hero__lead { max-width: 54ch; }

/* Lighter than the shared hero treatment, at PK's request (2026-09-09).
   Deliberately scoped to .hero--essay: both `.hero__scrim` (styles.css) and
   `.hero.has-video .hero__video` (video-layer.css) are global, and the homepage
   hero is a different piece of artwork that was tuned on its own terms. Editing
   the shared rules would have silently relit the homepage too.

   Two levers, used unevenly on purpose. Raising the video's own opacity
   brightens the artwork without thinning the protection over the copy; the
   scrim is then thinned mostly at its RIGHT end, which is pure artwork — no
   text lives past about 60% of the width. The left stop is left at .95 because
   that is what sits behind the h1. */
.hero--essay.has-video .hero__video { opacity: .72; }

.hero--essay .hero__scrim {
  background: linear-gradient(90deg,
    rgba(7, 27, 11, .95) 0%,     /* unchanged — this is behind the headline */
    rgba(7, 27, 11, .79) 46%,    /* was .82 */
    rgba(7, 27, 11, .16) 100%);  /* was .28 — artwork only, no text here */
}

/* The still, for the visitors who never get the video (narrow, reduced-motion,
   data-saver). Kept in step with the video above so they see the same picture,
   not a darker one. */
@media (max-width: 720px) {
  .hero--essay.has-video .hero__art,
  .hero--essay .hero__art { opacity: .72; }
}

/* --------------------------------------------------------- the essay ---- */

.essay { background: var(--ink-50); padding: var(--section-pad); }
.essay--white { background: var(--white); }

/* The first build centred a 34rem prose column on its own. The measure was
   right and the result was wrong: 544px stranded in a 1440px viewport with
   440px of dead space either side, on a site where every other section fills
   the 1200px shell. It read as unfinished rather than editorial.

   The fix keeps the line length and fills the shell — the heading moves into a
   left rail beside the prose, so the SECTION spans the shell even though the
   LINE does not. Editorial differentiation should come from the devices (the
   pull quote, the callout, the flow, the definition list), never from starving
   the content width. */
.essay__inner {
  max-width: var(--shell);
  margin: 0 auto;
  display: grid;
  grid-template-columns: 300px minmax(0, 660px);
  gap: 0 76px;
  justify-content: center;
}

/* Sticks alongside the prose on tall sections so the reader keeps the heading
   in view through a long passage — the rail earns its width that way rather
   than just holding a label. */
.essay__head {
  position: sticky;
  top: 108px;
  align-self: start;
}
.essay__head h2 { margin: 12px 0 0; font-size: 34px; }

.essay__body > :first-child { margin-top: 0; }

.essay__body p {
  margin: 22px 0 0;
  font-size: 18px;
  line-height: 1.78;
  color: var(--ink-700);
}

/* The turn in the argument. Sized between body and h2 so it reads as emphasis
   inside the prose rather than as a new section heading. */
.essay__body p.essay__callout {
  margin: 34px 0 30px;
  font-family: 'Oswald', sans-serif;
  font-size: 27px;
  font-weight: 500;
  line-height: 1.28;
  letter-spacing: .01em;
  color: var(--green-700);
  border-left: 3px solid var(--gold-500);
  padding-left: 22px;
}

.essay__body p.essay__coda {
  margin-top: 30px;
  font-weight: 700;
  color: var(--ink-900);
}

/* --------------------------------------------------------- pull quote --- */
/* A full-bleed band, not a card. Breaking the column entirely is what stops
   1,400 words reading as one slab. */

.pullquote {
  background: var(--ink-950);
  padding: 26px 24px;   /* was 74px; PK, 22 Oct: tightened three times */
}
.pullquote__inner {
  max-width: 52rem;
  margin: 0 auto;
  text-align: center;
}
.pullquote__inner p {
  margin: 0;
  font-family: 'Oswald', sans-serif;
  font-size: 36px;      /* PK, 22 Oct: just under the 42px H2 below */
  font-weight: 500;
  line-height: 1.18;
  color: var(--white);
}

/* ------------------------------------------------------- vendor tangle -- */

.tangle {
  position: relative;
  overflow: hidden;               /* clips the pinned layer to the section */
  background: var(--ink-950);     /* the image's own ground, so the seam is invisible while it loads */
  padding: var(--section-pad);
  /* Both bands are ink, so the quote's bottom padding and this top padding
     read as one gap. Trimmed (PK, 22 Oct) so the quote sits closer. */
  padding-top: 40px;
}

/* Resting state doubles as the no-JS and reduced-motion state: a plain section
   background, correct on its own.

   The scrim is stacked into this layer rather than being a sibling, and that is
   a correctness requirement, not tidiness. Once the image is pinned to the
   viewport and the scrim is not, the two slide against each other — the
   gradient's lightest stop drifts over the image's brightest pixels and the
   contrast you tuned stops being the contrast you get. Same layer, same
   transform, alignment guaranteed. */
.tangle__bg {
  position: absolute;
  inset: 0;
  background: url("/images/bg-hex-horizon.jpg") center center / cover no-repeat;
}

/* The animated version of the same artwork, exported from Claude Design. It
   crossfades over the still rather than replacing it, so the still is painted
   from the first frame and every failure path just leaves it there. */
.tangle__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  pointer-events: none;
  transition: opacity 900ms var(--ease);
}
.tangle__bg.has-video .tangle__video { opacity: 1; }

/* The animation is BRIGHTER than the still it replaces — it carries a flare
   peaking at rgb(183,214,185) around 70% height, where the still's own peak is
   only rgb(131,146,81). Tuning the scrim against the still alone left the
   vendor pills at 4.22:1 over that flare, under the 4.5 minimum.

   Rather than darken the artwork for everyone, the scrim tightens only while
   the video is actually showing — `has-video` is exactly that signal. At a 0.74
   mid stop the pills measure 5.58:1 over the flare, the same margin the still
   gets at 0.60. Whoever swaps the video must re-measure this: the still and the
   animation have independent peaks, and the still tells you nothing about the
   video's. */
/* Lightened 2026-09-09, but only at the ends. The 42% stop is untouched: it is
   the one holding the vendor pills above 4.5:1 over the flare, and the note
   above records that they measured 4.22:1 before it was tuned. Thinning it to
   match the ends would put them back under, knowingly this time. */
.tangle__bg.has-video .tangle__scrim {
  background:
    linear-gradient(180deg,
      rgba(10, 12, 10, .82) 0%,     /* was .88 — above the heading */
      rgba(10, 12, 10, .74) 42%,    /* UNCHANGED — protects the pills */
      rgba(10, 12, 10, .78) 100%);  /* was .80 */
}

/* Now a real element and the LAST child of the pinned layer, so it covers the
   still and the video both. It has to live inside that layer: pinned image
   plus unpinned scrim means the gradient's lightest stop slides over the
   image's brightest pixels, and the contrast you measured stops being the
   contrast you get. Measured that way it cost the vendor pills 5.09:1 → 4.89:1.
   Inside the layer it holds at 5.58:1.

   0.50 is the floor for the mid stop: 0.55 gives 5.09:1, 0.50 gives 4.61:1,
   0.45 fails at 4.17:1. The worst point is 44% down — the horizon line, the
   brightest thing in the frame. Do not lighten past 0.50, and re-measure from
   scratch if the artwork is replaced; these numbers describe this image only. */
.tangle__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg,
      rgba(10, 12, 10, .84) 0%,
      rgba(10, 12, 10, .60) 42%,
      rgba(10, 12, 10, .70) 100%);
}

/* Pinned mode, added by reveal.js. The layer becomes exactly viewport-tall and
   is translated against the scroll, so it holds still on screen while the
   section's content rides up over it — the effect people mean by "parallax".
   `bottom: auto` is required: the resting rule sets both edges, and the height
   cannot take effect until the bottom edge is released. */
.tangle__bg.is-pinned {
  bottom: auto;
  height: 100vh;
}


.tangle__inner { position: relative; z-index: 1; max-width: var(--shell); margin: 0 auto; }
.tangle .section-head { margin: 0 auto 52px; max-width: 62ch; }

.flow {
  display: flex; flex-direction: column; align-items: center;
  gap: 18px;
}

/* The six vendors, deliberately uneven — a tidy row of six pills would read as
   an orderly system, which is the opposite of the argument being made. */
.flow__scatter {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 12px;
  max-width: 56rem;   /* was 44rem; wider so the bigger pills stay on one row */
}
/* Reversed out to an opaque chip (PK, 2026-09-09). The pills were getting lost
   once the background video was lightened — and the cause was never contrast
   (they measured 7.8:1 at the animation's brightest frame, well clear of 4.5).
   It was figure/ground: 14px/400 text sitting directly on a MOVING texture has
   no stable ground to hold onto, and a static contrast reading cannot see that.
   An opaque fill fixes it at the source, which a colour tweak could not.

   Grey rather than any brand colour is doing real work here: these six are the
   interchangeable commodity vendors, and the gold .flow__end below is the one
   that isn't. Grey-to-gold is the argument the section is making.

   The dashed border is gone with the transparency — dashes on a solid fill read
   as a coupon, not as "provisional". Some of that "not yet resolved" signal is
   lost; the flow's arrows and the grey/gold split now carry it instead. */
.flow__scatter li {
  border-radius: 999px;
  padding: 12px 24px;     /* PK, 22 Oct: bigger and bolder, they got lost */
  font-size: 16px; font-weight: 400;   /* PK, 22 Oct: not bold */
  box-shadow: 0 6px 16px rgba(0, 0, 0, .35);
  /* --ink-200 (#d7dcd8) at 80%, so a little of the animation reads through the
     chip instead of it sitting on the section like a sticker. Literal rgba
     rather than color-mix() on the token: no build step here, and Pinegrow
     opens these files directly.

     80% is close to the floor of what still works. The chip's job is to give
     14px text a ground that does not move; below roughly 70% the animation
     starts telegraphing through again and the figure/ground problem this was
     built to fix comes back. Measured 8.2:1 over the brightest frame.

     It also settles the weight problem in the note above: the chip lands at
     luminance .470 against the gold end's .467 — the six commodity vendors now
     read at parity with the one partner rather than outshining it. */
  /* PALE GOLD with dark text (PK, 22 Oct; his idea, after an
     off-white try). Safe now that PAconnect's end box is dark with a gold
     border and glow, so the pills no longer compete with a gold fill. */
  background: rgba(248, 226, 176, .97);
  color: var(--ink-950);
}
/* THE DEVICE (PK, 22 Oct; prototype prototypes/why-tangle/, version B).
   The static tilt was meant as "scattered vendors" but readers asked whether
   it was a mistake. Now the mess is unmistakably deliberate and then fixed:
   the pills start scattered wide and tilted, snap into a straight row, a
   gold pulse runs down the arrows, the green middle lights, PAconnect lands.
   RESTING STATE = FINISHED PICTURE (straight pills, everything showing).
   js/why-flow.js adds .armed then .s1-.s4; gated on .js-reveal. Each pill
   carries its own --sx/--sy/--sr scatter in the markup. The animated
   background stays (PK's pick over the still). */
.flow__scatter li { transition: transform .65s cubic-bezier(.2, 1.25, .35, 1); }
.flow__arrow { transform-origin: top; transition: transform .3s ease; }
.flow__mid, .flow__end { transition: opacity .3s ease, transform .4s cubic-bezier(.2, 1.5, .4, 1); }
.flow.armed .flow__scatter li { transform: translate(calc(var(--sx) * var(--k, 1)), var(--sy)) rotate(var(--sr)); }
.flow.armed .flow__arrow { transform: scaleY(0); }
.flow.armed .flow__mid, .flow.armed .flow__end { opacity: 0; transform: scale(.92); }
.flow.s1 .flow__scatter li { transform: none; }
.flow.s2 .flow__arrow:nth-of-type(1) { transform: none; }
.flow.s3 .flow__mid { opacity: 1; transform: none; }
.flow.s3 .flow__arrow:nth-of-type(2) { transform: none; transition-delay: .2s; }
.flow.s4 .flow__end { opacity: 1; transform: none; }
@media (max-width: 720px) { .flow { --k: .35; } }

.flow__arrow {
  width: 2px; height: 34px;
  background: linear-gradient(var(--gold-500), rgba(240, 168, 48, .18));
}

.flow__mid {
  margin: 0;
  border: 1px solid var(--green-600);
  border-radius: 8px;
  padding: 14px 30px;
  font-size: 16px; font-weight: 700;
  color: var(--green-300);
  background: rgba(30, 122, 43, .12);
}

/* THE REAL MARK, NOT TYPED TEXT (PK, 22 Oct). The logo is built for a dark
   ground, so the box went dark with a gold border and glow instead of solid
   gold; "One partner" stays above it as a small gold label. */
.flow__end {
  margin: 0;
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  background: var(--ink-950);
  border: 2px solid var(--gold-500);
  box-shadow: 0 0 0 6px rgba(240, 168, 48, .12), 0 0 34px rgba(240, 168, 48, .28);
  color: var(--gold-400);
  border-radius: 12px;
  padding: 16px 40px 18px;
  font-size: 13px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .14em;
}
.flow__end img { display: block; width: 190px; height: auto; }

/* ----------------------------------------------------------- outcomes --- */
/* A definition list, not cards. The outcome is the heading and the service
   name is the supporting detail — the inverse of the homepage services grid,
   which leads with the product name. */

.outcomes { background: var(--white); padding: var(--section-pad); }
/* ═══ TWO FIXES IN ONE DAY, AND THE SECOND UNDID THE FIRST'S SIDE EFFECT ═══
   2026-10-06. Cutting the descriptions this morning left the rules running
   1017px under 468px of text — more than twice the width, crossing about 550px
   of nothing. The first fix was to borrow the essay sections' 300px rail grid,
   which brought the rules in. It also quietly removed the page's own variation:
   the section order runs Authority (rail) → this → How we start (rail), and
   before the change THIS was the section breaking that run. Three consecutive
   rail layouts, spotted by PK within minutes.

   So: heading above the list, as it was, AND NO RULES. The rules were inherited
   from the two-column version where they separated a promise from its
   explanation across a row. With one column of seven short declarative lines,
   space does that job — and with no rule there is no width to be wrong.

   DO NOT reintroduce either the rail grid or the rules here. One fixes the
   proportion by breaking the page's rhythm; the other recreates the proportion
   problem. The list measure is capped so the lines keep a readable length. */
.outcomes__inner { max-width: var(--shell); margin: 0 auto; }
.outcomes .section-head { margin-bottom: 40px; }

.outcomes__list { margin: 0; padding: 0; }

/* Seven promises, 2026-10-06. This was a two-column dl — a promise on the left
   and a 20-25 word explanation on the right — and the explanations came out.
   See the comment on the section in why-paconnect.html for why. What is left is
   one ruled column of seven lines, which scans in about five seconds, and the
   type goes UP because each line is now the only thing in its row rather than a
   label for something else. DO NOT reintroduce a second column. */
.outcomes__list { list-style: none; max-width: 660px; }
.outcome {
  padding: 0 0 22px;
  font-family: 'Oswald', sans-serif;
  font-size: 24px; font-weight: 500;
  line-height: 1.3;
  color: var(--green-700);
}
.outcome:last-child { padding-bottom: 0; }

/* ── NUMBERED 01–07, added 2026-10-19 ────────────────────────────────────
   PK's complaint was that the block "looks like something we started and
   didn't finish", and it did: seven identical lines with no internal
   structure read as seven headings whose bodies are missing — which is
   literally what happened when the descriptions were cut on 6 Oct.

   A set that runs 01 to 07 reads as COMPLETE. Nothing can look missing from
   it, so this answers the complaint at its root instead of filling space.

   ⚠ IT BREAKS NONE OF THE THREE PROHIBITIONS ABOVE. The number is a grid
   column INSIDE the row, not a second column of content; there is no rule and
   no rail, and the 660px list measure is unchanged. Those three bans all
   concern the section's outer proportion. This does not touch it.

   The number is gold against the promise's forest green: the same
   eyebrow/rule family used across the site, and small enough that the promise
   is still the only thing with weight in the row. */
.outcome { display: grid; grid-template-columns: 46px 1fr; align-items: baseline; }
.outcome::before {
  content: attr(data-n);
  font-family: 'Open Sans', sans-serif;
  font-size: 12px; font-weight: 800;
  letter-spacing: .1em;
  color: var(--gold-700);
  transform: translateY(-3px);
}

/* ---------------------------------------------------------- questions --- */

.questions {
  background: var(--ink-950);
  padding: var(--section-pad);
}
.questions__inner {
  max-width: var(--shell); margin: 0 auto;
  display: grid;
  grid-template-columns: 300px minmax(0, 660px);
  gap: 0 76px;
  justify-content: center;
}
.questions__inner .section-head { align-self: start; }
.questions__list { margin-top: 0 !important; }

.questions__list {
  list-style: none;
  margin: 36px 0 0; padding: 0;
}
.questions__list li {
  border-top: 1px solid rgba(255, 255, 255, .14);
  padding: 18px 0 18px 34px;
  position: relative;
  font-family: 'Oswald', sans-serif;
  font-size: 22px; font-weight: 400;
  color: var(--white);
}
.questions__list li:last-child { border-bottom: 1px solid rgba(255, 255, 255, .14); }
/* Gold marker rather than a bullet — the eyebrow/rule family, not a list glyph. */
.questions__list li::before {
  content: ""; position: absolute;
  left: 0; top: 28px;
  width: 18px; height: 2px;
  background: var(--gold-500);
}

.questions__coda {
  margin: 28px 0 0;
  font-size: 17px; line-height: 1.7;
  color: rgba(255, 255, 255, .78);
}

/* -------------------------------------------------------------- close --- */
/* Not the consultation form the other two pages end with — see the markup
   comment for why. Text-led, one button. */

.close {
  background: var(--ink-900);
  padding: var(--section-pad);
  border-top: 3px solid var(--gold-500);
}
.close__inner { max-width: 48rem; margin: 0 auto; text-align: center; }

.close__detail {
  margin: 26px auto 0;
  max-width: 46ch;
  font-size: 17px; line-height: 1.75;
  color: rgba(255, 255, 255, .78);
}

.close__actions { margin-top: 34px; }
.close__phone {
  margin: 18px 0 0;
  font-size: 15px;
  color: var(--ink-400);
}
.close__phone a { color: var(--gold-400); text-decoration: none; font-weight: 700; }
.close__phone a:hover { text-decoration: underline; }

/* ----------------------------------------------------------- responsive - */

/* The rail sits beside the prose only while both fit. Below this it stacks
   back above it — a 300px rail next to a squeezed body is worse than no rail. */
@media (max-width: 1040px) {
  .essay__inner,
  .questions__inner {
    grid-template-columns: minmax(0, 660px);
    justify-content: start;
  }
  .essay__head { position: static; margin-bottom: 6px; }
  .questions__inner .section-head { margin-bottom: 8px; }
}

@media (max-width: 900px) {
  .hero--essay { --hero-size: 44px; --hero-measure: 100%; }
  .pullquote__inner p { font-size: 29px; }
  .outcome { font-size: 21px; padding-bottom: 18px; }
  .essay__body p.essay__callout { font-size: 23px; padding-left: 18px; }
}

/* The section is ~950px tall and ~360px wide on a phone — 0.38:1 against a
   16:9 image. `cover` there throws away 79% of the width, and a perspective
   grid does not survive that: the vanishing point and the horizon both go, and
   what is left reads as a green smear rather than a receding floor.

   So on narrow screens the image stops covering and becomes a horizon band
   anchored to the bottom of the section, which is where a floor belongs
   anyway. The flat ink above it carries the copy more legibly than a stretched
   crop would. */
@media (max-width: 720px) {
  /* Two background layers now, so both need a size: `auto` for the gradient so
     it still fills the box, then the band size for the image. Pinned, the band
     anchors to the bottom of the viewport rather than the section — a floor you
     scroll over, which suits the artwork.
     The gradient is flipped here: on a phone the copy sits high in the section
     over flat ink, and the image is only near the base, so the heavy end of the
     scrim belongs at the top. */
  /* A purpose-made 1600×382 crop rather than the 16:9 original stretched to
     150% and anchored bottom. Same band, natively composed, sharper, and 60 KB
     against 97 KB. The video never loads at this width (video-layer.js gates
     it out below 720px), so this is the whole treatment on a phone. */
  /* `auto` height, never `cover`. Cover would scale a 4.19:1 band to fill a
     0.38:1 section and crop 91% of the width — the exact failure the band
     exists to avoid. At 140% it lands about 120px tall across the base. */
  .tangle__bg {
    background-image: url("/images/bg-hex-horizon-band.jpg");
    background-size: 140% auto;
    background-position: center bottom;
  }
  /* Flipped: on a phone the copy sits high over flat ink and the artwork is
     only near the base, so the heavy end of the scrim belongs at the top. */
  .tangle__scrim {
    background:
      linear-gradient(180deg,
        rgba(10, 12, 10, .92) 0%,
        rgba(10, 12, 10, .74) 55%,
        rgba(10, 12, 10, .60) 100%);
  }

  .essay { padding: var(--section-pad-tight); }
  .essay__body p { font-size: 17px; }
  .pullquote { padding: 40px 24px; }
  .pullquote__inner p { font-size: 25px; }
  .questions__list li { font-size: 19px; }
  .flow__scatter li { font-size: 14px; padding: 10px 18px; }
}
