/* ============================================================
   ConstructCert Australia — the home page's own sections
   THE PROTOTYPED SECTIONS. NOTHING IN HERE STILL SWITCHES.

   Every section this file holds has now been decided:

     service streams   12 Aug 2026   "Stacked notice"
     Where we work     13 Aug 2026   all three dropped for MyReno's
                                     service-area band, reskinned
     hero              25 Aug 2026   "Archive — split hero"
     Our Commitment    25 Aug 2026   "Split"
     Our Expertise     25 Aug 2026   "Index"
     Testimonials      25 Aug 2026   "Sequence"

   Each carries one plain set of rules under its own class prefix
   (cc-streams-*, cc-coverage-*, cc-hero-*, cc-commitment-*,
   cc-expertise-*, cc-t-*), so they cannot reach each other. There is
   no data-variant selector left anywhere in this file. Every option
   that lost is in archive/2026-08-*-options/, one folder per section,
   each with the prototype it was compared in and a README.

   THE CONDITION AT THE TOP OF THIS FILE HAS BEEN MET. It used to read
   "the whole file moves to page.css when the last of them locks", and
   Testimonials was the last. That move has NOT been made: it is a
   two-thousand-line refactor of a file three separate sessions edited
   on 25 Aug 2026, and it is nobody's side effect. Doing it is a
   decision for whoever is holding the whole site. Until then
   this file is a stylesheet like any other and only its name still
   says "variants".

   Lifted from the section prototypes, all six of which
   have moved to archive/2026-08-*-options/ as their sections locked.
   Those files put data-variant on <html> and each section here was
   scoped to a wrapper carrying the same attribute, so a rule could
   cross over unchanged. Every one of those prefixes has now been
   stripped, but NOT all the same way, and the difference matters to
   anyone adding a rule near one of these sections:

     hero, Our Expertise    re-scoped to a parent class, .cc-hero
                            .cc-hero-X and .cc-expertise
                            .cc-expertise-X, holding 0,2,0 so their
                            rules keep beating their own narrow-
                            viewport overrides on weight. 12 rules
                            and 2.
     Testimonials           stripped to plain .cc-t-X, 0,2,0 down to
                            0,1,0. The only section in this file that
                            moved down a level. Reasoned through in
                            the 7B header.
     Our Commitment,        nothing to lose — all three were already
     streams, Where we work plain before their locks.

   STRIPPED on the way across, because a prototype is a standalone
   page and this is not:
     - bare element selectors (body { padding-bottom } clearing the
       prototype switcher, body { background })
     - :root token overrides. Commitment's --cc-step-N and --cc-rule
       ramp now sits on .cc-commitment — which is the section itself
       since the lock, not a wrapper, so the scope is unchanged.
       Coverage had its own --cc-mono / --cc-rule / --cc-ink-N ramp
       and shipped a --cc-rule meaning something else again (a colour,
       not a border shorthand); the reskin uses no section-local
       properties at all, so only commitment's survives and nothing
       collides.
     - the :root prefix on commitment's pane-visibility selectors,
       which would otherwise never match a wrapper-scoped variant.
       Those selectors are gone entirely as of the 25 Aug lock
     - prototype chrome: the black instruction strip, the floating
       variant bar, and the prototypes' own reduced-motion blocks
       (page.css already carries one)
     - expertise's .cc-expertise-datum rule; the signed-off section
       header on the base page does not carry that element
     - and, not deliberately, expertise variant B's sticky rule. See
       section 7: it was found missing at that section's lock and was
       not restored, because restoring it would have changed a design
       the client had already chosen from

   Nothing else is changed. In particular the hero's container
   model is intact: .cc-hero-stage is a real centred container on
   --cc-hero-edge.
   ============================================================ */


/* ============================================================
   2 - HERO   LOCKED - "Archive — split hero"

   Locked to A on 25 Aug 2026. B ("The intake") had already been withdrawn;
   C ("The drawing sheet") went with the lock. Both prototypes are in
   archive/2026-08-hero-options/.

   THE SELECTORS. Every rule that read [data-variant="a"] .cc-hero-X now
   reads .cc-hero .cc-hero-X, and that redundant-looking scope is load
   bearing. .cc-hero-intake{display:none} sits further down this file than
   the rule that turns the intake on; only specificity was deciding between
   them. Dropping the wrapper selector outright would have made the two equal
   and let source order win, which would have switched the intake off. The
   swap keeps every selector at the weight it already had, so the cascade is
   the one that was signed off.

   NO VBA PLACEHOLDER, and that is a decision rather than an oversight.
   The client had already asked for it out of the intake's assurance list,
   which is what [data-variant="a"] .cc-hero-vba was for. The lock read that
   display:none as a bug left over from B being withdrawn and dropped it,
   which put the placeholder back on the page; it was removed again the same
   day, this time from the markup, since B and C are both gone and there is
   no longer another variant sharing the string.

   So the VBA registration number is stated nowhere on this site and nothing
   marks its absence. That is the client's call and it is recorded here
   because nothing on the page records it any more.
   ============================================================ */

.cc-hero{
  /* local type scale — _tokens.css ships no --step-* ramp */
  --cc-hero-xs:      0.72rem;
  --cc-hero-lede:    clamp(1.0625rem, 1rem + 0.3vw, 1.25rem);
  /* A's headline size, carried over from the archived build unchanged */
  --cc-hero-arc:     clamp(2.4rem, 4.2vw, 3.7rem);

  /* THE HEIGHT CONTRACT.
     Every variant is built around a 1fr track absorbing slack, but the section
     had no height of its own, so 1fr resolved to content height: the figure
     never filled, the columns never reached a common bottom, and each variant
     read as a fragment floating in white.
     Deliberately NOT svh/vh — a viewport-height hero balloons full-page
     headless captures to the window height and pushes content out of frame.
     rem + vw is deterministic: one width always yields one height.
     Sized to sit just above what the tallest variant needs at each width: high
     enough that every 1fr track has slack to spend, low enough that no variant
     is forced to invent 200px of air it has nothing to put in. */
  --cc-hero-h: clamp(40rem, 28.75rem + 34vw, 68rem);

  /* THE CONTAINER MODEL — read this before touching any padding below.
     --cc-hero-edge is the minimum white margin at the viewport edge, and
     .cc-hero-stage is a REAL centred container (same idiom as base.css
     .container): width: min(--content-max, 100% - 2*edge); margin-inline: auto.
     Every grid item therefore sits inside the container by simply existing —
     no item carries a viewport-derived padding of its own.

     NOTHING HERE MAY SPEND A VIEWPORT-DERIVED PADDING. box-sizing is border-box
     globally, so a padding computed from 100vw can exceed the element's own
     width and collapse its content box to zero: a deleted --cc-hero-bleed did
     exactly that to the lede at 2560px, wrapping every word onto its own line.
     If you ever need to escape the container, pair a negative margin with an
     equal positive padding so the two always cancel. */
  --cc-hero-edge:  var(--space-5);

  /* "technical record" voice, built from Inter — no third typeface */
  --cc-hero-rec-size: 0.7rem;

  position: relative;
  isolation: isolate;
  background: var(--bg);
  /* clip, not hidden: it still contains the rotated stamp, but it also absorbs
     the one place a bleed can overshoot. 100vw includes the classic scrollbar
     while the visible width does not, so a full-bleed element can run half a
     scrollbar past each edge; clip eats that WITHOUT making the section a
     scroll container, so it never reaches the document's scrollWidth. */
  overflow: clip;
}

/* --- the one grid every variant re-plates ------------------- */
.cc-hero-stage{
  display: grid;
  align-content: start;
  /* THE CONTAINER. Not a full-width grid with per-item insets pretending to be
     one — an actual centred box. The composition therefore centres at every
     width instead of being shoved rightwards by a padding that grows with the
     viewport. Matches base.css .container exactly, so the hero and the rest of
     the sheet share one measure. */
  /* --cc-hero-max defaults to the sheet's measure so the hero lines up with
     every other section. A variant may widen itself by overriding it — see A,
     which the client asked to run wider than the rest of the page. */
  width: min(var(--cc-hero-max, var(--content-max)), 100% - 2 * var(--cc-hero-edge));
  margin-inline: auto;
  /* the contract. Each variant below names exactly one 1fr row, so the slack
     has a declared home instead of leaking out as a ragged bottom edge. */
  min-height: var(--cc-hero-h);
}

/* shared voice for anything that should read as a record entry */
.cc-hero-rec{
  /* fallback: the custom property is declared on .cc-hero, and this class is
     also used by the commitment section's margin labels, outside that scope */
  font-size: var(--cc-hero-rec-size, 0.7rem);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  line-height: 1.5;
  color: var(--muted);
}

/* base.css sets .eyebrow to weight 700 and centre-aligns its rule; only 400/600
   of Inter are loaded, and a centred rule floats mid-block once the label wraps
   onto two or three lines at 360px. Pin the rule to the first line instead. */
.cc-hero .eyebrow{ font-weight: 600; align-items: flex-start; }
.cc-hero .eyebrow::before{ margin-top: 0.62em; }

.cc-hero-title{
  font-weight: 400;
  letter-spacing: -0.035em;
  text-wrap: balance;
}
/* A's headline, ported from the archive: 600 weight, an 11ch measure, and its
   own tracking. text-wrap is reset because the archived heading was set to wrap
   on its measure, and balancing a four-line title of unequal words re-breaks it
   somewhere the previous build never did. */
.cc-hero-title-arc{
  display: none;
  max-width: 15ch; /* the wider column earns a shorter stack of lines */
  font-size: var(--cc-hero-arc);
  font-weight: 600;
  letter-spacing: -0.01em;
  text-wrap: wrap;
}

.cc-hero-lede{
  font-size: var(--cc-hero-lede);
  color: var(--muted);
  max-width: 48ch;
  line-height: 1.55;
}

/* --- actions ------------------------------------------------ */
.cc-hero-actions{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
}
.cc-hero-actions .button,
.cc-hero-actions .button-outline{ padding-inline: 1.5rem; }

.cc-hero-call{
  display: inline-flex;
  flex-direction: column;
  gap: 0.1rem;
  background-image: none;
  padding-bottom: 0;
  color: var(--text);
}
.cc-hero-call span{
  font-size: var(--cc-hero-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}
.cc-hero-call b{
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.375rem;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
}
.cc-hero-call:hover b{ color: var(--link-hover); }

/* --- the figure (ONE img, re-plated per variant) ------------ */
.cc-hero-figure{
  position: relative;
  margin: 0;
  overflow: hidden;
  background: var(--surface);
}
/* NO CAPTION ON EITHER IMAGE. The hero figure carried .cc-hero-cap and the
   commitment figure a figcaption plate, both holding a [PLACEHOLDER: …], and
   both were removed on request on 26 Aug 2026 along with every rule that
   styled them: the chip, its z-index above the scrim, its narrow-width
   caption-bar override, .cc-commitment-todo and the commitment plate.

   The scrim on .cc-hero-figure::after stays. It was never there for the
   caption — its job is keeping the photograph's bottom edge from fighting the
   page ground, and it still does that with nothing sitting on it. */
.cc-hero-figure img{
  /* absolutely positioned so the image contributes NO intrinsic height to its
     figure. With height:100% in flow, an indefinite parent height makes the img
     fall back to its 3:2 ratio, which balloons whichever grid row it lands in
     (in C that was a 950px plate and a horizontal scrollbar). Out of flow, the
     figure takes its height from the grid row and the image covers it. */
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* A and C crop the 3:2 frame to a wide band. Dead-centre cropping opened the
     plate exactly on the top edge of the rendered upper level — a pale band
     bounded by the frame above and windows below, which read as a seam across
     the photo rather than as part of the house. 26% opens on sky and takes in
     the whole roofline, so the band is legibly a photograph of a building.
     B crops horizontally only (tall column), so this is a no-op there. */
  object-position: 50% 26%;
  display: block;
}

/* ============================================================
   VARIANT A — ARCHIVE, SPLIT HERO
   The previous build's hero, ported here class-for-class under the
   cc-hero-arc-* prefix. Two things had to change for it to live in this file:

   1. The container. The archived rule ran the copy panel off the LEFT viewport
      edge and the photo plate to within 1.75rem of the RIGHT one, so at 2560
      the composition had a 112px margin on one side and 28px on the other.
      Here both columns are simply items of .cc-hero-stage, which is the real
      centred container, so the left and right page margins are the same number
      at every width.
   2. The panel's padding. The archive set it in viewport units
      (clamp(4rem, 8vw, 8rem) clamp(2rem, 6vw, 7rem)). Inside a max-width
      container that is the exact bug this file's container model exists to
      prevent: 6vw of inline padding at 2560 eats a fifth of a 1200px measure
      for no reason. The block padding is a fixed stage inset and the inline
      inset is the container's, i.e. none of its own.
   Everything else — the 0.88/1.12 split, the centred copy, the 11ch headline, the
   rounded plate, its raise shadow and its bottom scrim — is the archive's.
   ============================================================ */
.cc-hero .cc-hero-stage{
  /* MyReno's hero runs the full width of the page: the copy panel takes the left
     column behind a generous inline pad, the plate takes the right and is inset
     from the viewport edge by its own margin. A opts out of the sheet's centred
     measure entirely to match it.
     The pad sits on the GRID CONTAINER, never on a child carrying a max-width —
     that distinction is the whole reason the 2560 collapse cannot come back. */
  width: 100%;
  max-width: none;
  padding-inline: clamp(2rem, 8vw, 10rem) 0;
  /* MyReno's own hero proportions: minmax(25rem, 0.88fr) / minmax(32rem, 1.12fr).
     The track minimums are eased to 20rem/28rem — MyReno's add up to 57rem, which
     is wider than the 900px where both designs drop to one column, so between
     901 and 912px they would be clipped by the section's own overflow. Above
     that width the minimums never bind and the 0.88/1.12 ratio governs, so the
     photograph gets exactly MyReno's share. */
  grid-template-columns: minmax(18rem, 0.75fr) minmax(28rem, 1.25fr);
  /* the two 1fr rows ARE the archived panel's align-items: center — the copy
     block sits in the middle of the plate's height, not at its top */
  grid-template-areas:
    ".      media"
    "head   media"
    "lede   media"
    "intake media"
    "acts   media"
    ".      media";
  grid-template-rows: 1fr auto auto auto auto 1fr;
  /* more air than the shared inset: this variant is the widest on the page, and
     at 1440+ the copy, the intake and the plate were all sitting tight against
     each other and against the nav above. */
  column-gap: clamp(var(--space-6), 4.4vw, var(--space-9));
  row-gap: clamp(1.25rem, 1.5vw, 1.9rem);
  padding-block: clamp(var(--space-7), 4.6vw, var(--space-9));
  /* the archived hero's own height contract was min(58rem, viewport). The
     shared one reaches 68rem at 2560, which stretches a 3:2 photograph into a
     portrait crop that loses the roofline the plate is there to show. */
  min-height: min(var(--cc-hero-h), 62rem);
}
/* A keeps the archived HEADLINE but takes B's content: the shared lede, the
   two-field permit intake, and the secondary CTA. Its own lede and buttons
   are off. .cc-hero-reg is gone with C, and nothing replaced it: the
   registration line was the last place a VBA placeholder appeared. */
.cc-hero .cc-hero-title-arc{ display: block; }

.cc-hero .cc-hero-head{ grid-area: head; padding-top: 0; }
/* Both of the strings this rule used to switch off — the eyebrow's locality
   suffix and the assurance list's VBA placeholder — were dropped at the
   client's request and kept in the markup only because variant B still
   needed them. B and C are both gone, so they are gone from the markup too
   and this rule went with them. Kept as a note because "the client asked for
   these out" is the kind of fact that gets re-added by someone tidying. */

/* B and C set their own; A had none, so the label sat hard against the h1. */
.cc-hero .cc-hero-head .eyebrow{ margin-bottom: var(--space-5); }

.cc-hero .cc-hero-lede{ grid-area: lede; display: block; }
.cc-hero .cc-hero-intake{ grid-area: intake; display: block; }
.cc-hero .cc-hero-actions{ grid-area: acts; display: flex; }

/* the plate: spans every row, so it takes the whole column height and the copy
   floats in the middle of it. No bleed — its right edge is the container's. */
.cc-hero .cc-hero-figure{
  grid-area: media;
  min-height: 42rem; /* MyReno's .hero--split .hero__media, exactly */
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-raise);
  /* MyReno insets the plate from the top, right and bottom edges and leaves the
     left to the column gap, so the photograph reads as a card laid on the page
     rather than a panel welded to it. */
  margin: clamp(1rem, 2vw, 1.75rem) clamp(1rem, 2vw, 1.75rem) clamp(1rem, 2vw, 1.75rem) 0;
}
/* archived: a bottom scrim so the image edge doesn't fight the page background.
   The hardcoded rgb(7 8 8 / .38) becomes the palette's own ink at the same
   strength, so the plate follows the tokens like everything else. */
.cc-hero .cc-hero-figure::after{
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(0deg, color-mix(in srgb, var(--text) 38%, transparent), transparent 38%);
  pointer-events: none;
}

/* --- A's own copy elements ----------------------------------
   Emptied 25 Aug 2026. This held one rule, for .cc-hero-reg, described as
   "A's one addition to the archived copy: the archive had nowhere for the
   registration placeholder, and this file's rule is that the VBA number is
   a visible gap in every variant." That rule is no longer this file's: the
   element went with C and the placeholder came out at the client's request.
   ------------------------------------------------------------ */

/* ============================================================
   VARIANT B — THE INTAKE
   ============================================================ */
/* the form's submit IS the primary, so the standalone Request Permit button is
   off in both variants that carry the intake — otherwise it appears twice. */
/* min-height only — the figure spans all four rows and stretches to whatever
   the stage's height contract gives it, filling the column top to bottom. */

.cc-hero-intake{ display: none; max-width: 34rem; margin-bottom: var(--space-5); }
.cc-hero-intake-legend{
  display: block;
  padding: 0 0 var(--space-3);
  margin-bottom: var(--space-4);
  border-bottom: 1px solid var(--border);
  color: var(--text);
}
.cc-hero-fields{ display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }
.cc-hero-field{ display: grid; gap: 0.35rem; min-width: 0; }
.cc-hero-field--wide{ grid-column: 1 / -1; }
.cc-hero-label{ font-size: 0.85rem; font-weight: 600; }
.cc-hero-input,
.cc-hero-select{
  width: 100%;
  font: inherit;
  font-size: 0.95rem;
  color: var(--text);
  background: var(--bg);
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--outline-border);
  border-radius: var(--radius-xs);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.cc-hero-input::placeholder{ color: color-mix(in srgb, var(--muted) 82%, var(--bg)); }
.cc-hero-input:hover,
.cc-hero-select:hover{ border-color: var(--outline-border-hover); }
.cc-hero-input:focus,
.cc-hero-select:focus{ border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent); }
.cc-hero-selectwrap{ position: relative; display: block; }
.cc-hero-select{ appearance: none; padding-right: 2.4rem; }
/* The select opens on an empty option, so while it is unanswered it should read
   like the placeholder next to it rather than like a choice already made. It is
   deliberately not `required` — a suburb on its own is a perfectly good enquiry
   — so :invalid can't do this and :has has to. Browsers without :has simply
   leave it in --text, which is the old behaviour, not a broken one. */
.cc-hero-select:has(option[value=""]:checked){
  color: color-mix(in srgb, var(--muted) 82%, var(--bg));
}
.cc-hero-selectwrap::after{
  content: "";
  position: absolute;
  right: 1rem;
  top: 50%;
  width: 0.5rem;
  height: 0.5rem;
  border-right: 1.5px solid var(--muted);
  border-bottom: 1.5px solid var(--muted);
  transform: translateY(-70%) rotate(45deg);
  pointer-events: none;
}
/* the intake's submit is the hero's primary action, so it gets a taller target
   than base.css's 3rem default and real separation from the field above it —
   0.5rem read as if the button belonged to the select. */
.cc-hero-intake .button{
  width: 100%;
  margin-top: var(--space-4);
  min-height: 3.4rem;
  padding-block: 1rem;
}
.cc-hero-assurance{
  margin: var(--space-5) 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.cc-hero-assurance li{ display: flex; align-items: flex-start; gap: 0.5rem; }
.cc-hero-assurance li::before{
  content: "";
  flex: none;
  width: 0.5rem;
  height: 0.5rem;
  margin-top: 0.32rem;
  border-radius: 50%;
  border: 1.5px solid var(--brand);
}

/* ============================================================
   VARIANT C — THE DRAWING SHEET
   ============================================================ */

/* no height of its own: it fills the flexible plate row top to bottom */
/* nothing straddles the plate any more, so the caption sits at its foot like
   everywhere else. The plate bleeds, so the chip is offset back to the
   container's right edge by exactly the bleed distance — an absolute offset
   inside a bled box, not a padding on a sized one. */

/* the three statutory gates: the right-hand column of the title block, where
   the record rail was. It keeps the rail's rules exactly — a strong rule across
   the top on the same line as the headline's, a hairline down the left as the
   column separator, and the same 2rem inset off it — so the cards land in the
   cell the rail vacated rather than floating in it. space-6 is a fixed 2rem
   column separator, never a viewport inset. */
/* A card in a 20rem rail, not a tab across a 75rem plate: the number sits on
   the baseline of the name rather than in a band above it. Stacked the other
   way the three cards ran ~200px taller than the headline and lede beside them, and
   grid shared that excess out across the copy rows — which opened a hole
   between the h1 and the lede that read as a mistake. */
/* the CTA band is full-bleed: its rules and its surface run to both viewport
   edges while its content stays on the container. Inline padding comes from the
   bleed escape below. */

/* the registration placeholder and the ABN ride in C's CTA band, which is where
   the record rail's two irreducible entries went when the cards took its cell */

/* ============================================================
   RESPONSIVE — single column below 900px, per variant
   ============================================================ */
@media (max-width: 900px){
  /* no gutter override needed any more: below 1248px the bleed distance is
     already exactly --cc-hero-edge, because the container is 100% - 2*edge. */
  /* one column: every row is content-sized and the section is as tall as what
     is in it. A height contract here would only open white at the foot. */
  .cc-hero-stage{ min-height: 0; }

  /* stacked, on MyReno's pattern: one column, the copy panel padded 4rem/3rem,
     then the photograph as an inset rounded plate beneath it.
     "intake" MUST be named here. It was missing, and a missing area does not get
     ignored — grid plants the item in an implicit column, which collapsed the
     explicit 1fr and squeezed the lede to one word per line at 360. */
  .cc-hero .cc-hero-stage{
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "head" "lede" "intake" "acts" "media";
    grid-template-rows: auto; /* reset the desktop centring rows */
    row-gap: 1.55rem;         /* MyReno's .hero__content gap */
    padding-block: var(--space-8) var(--space-7);
    /* stacked, the panel's pad comes back to both sides — MyReno's
       padding: 5rem max(1.25rem, 6vw) 3rem. */
    padding-inline: max(1.25rem, 6vw);
  }
  /* one column: the plate becomes a band at the foot, edge to edge — a full
     bleed to BOTH edges, never a plate inset on one side only, so the rounded
     corners and the raise shadow come off with the inset. The escape itself is
     at the foot of this media query with B's. */
  /* MyReno keeps the plate a rounded, inset card when stacked (min-height 42vh,
     margin 0 1rem 1rem) rather than bleeding it edge to edge, so the hero ends
     on a card and not on a band. Same here. */
  .cc-hero .cc-hero-figure{
    height: clamp(240px, 42vh, 380px);
    min-height: 0;
    margin: var(--space-5) 0 0;
    border-top: 0;
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-raise);
  }
  /* one column: the rail's rules and its inset come off */

  /* stacked, the photo is a band at the foot (A) or the head (B) of the column,
     and a band runs edge to edge. Same escape as the desktop bleeds, both sides,
     and last in the media query so it wins over the margin longhands above. */
  /* B's plate is a band at the head of the column and still bleeds. A's is an
     inset card (see above), so it is deliberately NOT in this rule any more. */
}

@media (max-width: 560px) {
  .cc-hero-fields{ grid-template-columns: 1fr; }
  .cc-hero-actions{ gap: var(--space-4); }
  .cc-hero-actions .button,
.cc-hero-actions .button-outline{ flex: 1 1 100%; }
}

/* A status line stood under the intake's submit button, for the hand-off to
   report into. The intake leaves the page now — the report is the contact form
   arriving already filled in — so there is nothing left to say here, and the
   element and this rule went together on 20 August 2026. */

/* ============================================================
   3 - SERVICE STREAMS   LOCKED — "Stacked notice"

   Chosen from five prototyped treatments on 12 Aug 2026. The other four —
   Band, Docket, Notice and Stack — are gone from this file, and the prototype
   that carried all five is in archive/2026-08-streams-options/.

   What it is: the two streams as one section of two tiles on a tinted band.
   Each tile is a photograph with a hard-ruled white card laid over its lower
   edge and centred on it, labelled above with the page's own eyebrow and
   footed with the three stages. This section is the one --surface step in the
   run; the hero above it and Our Commitment below it are both on --bg.

   This is no longer variant CSS and only lives in variants.css because the
   four sections around it still are. It moves to page.css when they lock.

   THE INSET RULE — read before touching any padding below. box-sizing is
   border-box globally. A viewport-derived padding on an element that ALSO
   carries a max-width leaves a content box of zero at 2560 and wraps every
   word onto its own line; that bug has been fixed twice on this codebase. So
   the band inset is only ever applied to .cc-streams-grid, which carries no
   max-width. The only max-widths here are on .cc-streams-h and
   .cc-streams-text, and neither of those carries any padding at all.
   ============================================================ */

.cc-streams{
  /* --- local type scale — _tokens.css ships no --step-* ramp --- */
  --ccs-mono:  ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --ccs-micro: 0.68rem;
  --ccs-h:     clamp(1.5rem, 1.2rem + 1.35vw, 2.375rem);
  --ccs-body:  clamp(0.9375rem, 0.9rem + 0.15vw, 1.0625rem);

  /* --- two rule weights, and only two ---------------------------
     --ccs-edge is the card's own edge; --ccs-rule is the hairline inside it,
     above the stages. Both are palette border tokens; this section introduces
     no colour of its own. */
  --ccs-edge: var(--border-strong);
  --ccs-rule: var(--border);

  /* the band inset. Character-for-character the hero copy panel's own padding,
     so each plate's left edge sits on the hero <h1>'s vertical line. */
  --ccs-bandpad: clamp(2rem, 8vw, 10rem);
  --ccs-gap:     clamp(2rem, 4vw, 4.5rem);

  padding-block: clamp(var(--space-7), 5.5vw, var(--space-9));
  /* the alternation. No hairline: the tone change is the edge, and an edge
     stated twice is an edge stated once too often. */
  background: var(--surface);
}

.cc-streams-grid{
  display: grid;
  gap: var(--ccs-gap);
  align-items: stretch;
  /* THE INSET SITS HERE, on the grid container, which has no max-width.
     Never on a tile, never on the paragraph. */
  width: 100%;
  padding-inline: var(--ccs-bandpad);
}

/* --- a tile ---------------------------------------------------
   Every leaf is a direct child so the layout can re-seat it by grid-area
   without a second DOM. */
.cc-streams-tile{
  position: relative;
  display: grid;
  grid-template-areas: "applies" "plate" "body";
  grid-template-rows: auto auto 1fr;
  gap: 0;
  margin: 0;
  min-width: 0;
}

/* THE EYEBROW. base.css .eyebrow written out, because that class is not on
   this element. Weight 600, not base.css's 700: only 400 and 600 of Inter are
   loaded here and 700 would be synthesised, which is the same correction
   .cc-hero makes. flex-start with the rule pushed down 0.62em is also the
   hero's, and it is what keeps the rule on the first line when the strip wraps
   to two — which the commercial one does below about 1060 and on every phone. */
.cc-streams-applies{
  grid-area: applies;
  display: inline-flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin: 0 0 var(--space-4);
  font-family: var(--font-body);
  font-size: 0.76rem;
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}
.cc-streams-applies::before{
  content: "";
  flex: none;
  width: 2.5rem;
  height: 1px;
  margin-top: 0.62em;
  background: var(--brand);
}

.cc-streams-plate{
  grid-area: plate;
  position: relative;
  overflow: hidden;
  margin: 0;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-lg);
  /* reads as a frame before the photograph decodes — on a tinted section a
     --surface placeholder would show as nothing at all */
  background: color-mix(in srgb, var(--text) 8%, var(--surface));
}
.cc-streams-img{
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* THE CARD. --ccs-edge, not --ccs-rule: this is the instrument's own edge, and
   white on --surface is a 2% step that nothing else would carry. Square and
   unraised — a shadow under a square edge reads as a rounded card that forgot
   its radius.

   THE STEP is a block-axis negative margin and nothing is absolutely
   positioned, so the tile's height stays the sum of what is in it, less
   exactly this overlap, and nothing can be clipped. It measures 38px where the
   two tiles first sit side by side and 56px from 1440 up; stacked it is the
   24px below, which is exactly the card's radius in the version that had one.

   The card is CENTRED on its plate, so the photograph shows down both sides.
   The inline inset is 2.5vw, not the 4vw of the step — MEASURED, because
   centring pays it twice. At 960 the tile is 384px: at 4vw a side the copy
   would get a 248px box, under the 260px floor this section holds. At 2.5vw it
   gets 276px, and the reveal still opens to the same 56px cap by 1600. */
.cc-streams-body{
  grid-area: body;
  display: grid;
  grid-template-areas: "head" "text" "act" "stages";
  /* The prose row takes the slack, so the action and the stages sit on the
     card's foot. The two cards are stretched to a common height by the grid,
     so the two CTAs land on one line whatever the paragraphs do — which is
     what "equal in weight, neither stream secondary" has to look like when one
     paragraph runs a line longer than the other. */
  grid-template-rows: auto 1fr auto auto;
  min-width: 0;
  position: relative;
  z-index: 1;
  background: var(--bg);
  border: 1px solid var(--ccs-edge);
  padding: clamp(var(--space-5), 3vw, var(--space-7));
  margin: calc(-1 * clamp(2rem, 4vw, 3.5rem)) clamp(1.25rem, 2.5vw, 3.5rem) 0;
}

.cc-streams-h{
  grid-area: head;
  align-self: start;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--ccs-h);
  max-width: 20ch;
  margin: 0;
}
.cc-streams-text{
  grid-area: text;
  margin: var(--space-4) 0 0;
  color: var(--muted);
  font-size: var(--ccs-body);
  line-height: 1.7;
  max-width: 54ch;
}
.cc-streams-act{
  grid-area: act;
  align-self: start;
  margin: var(--space-6) 0 0;
}

/* the stage rail, footing the card. A wrapping flex row, not a three-column
   grid: at any width the cells are as wide as their label needs and no wider,
   so no width can squeeze a cell into a mid-word break. */
.cc-streams-stages{
  grid-area: stages;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 var(--space-4);
  list-style: none;
  margin: var(--space-6) 0 0;
  padding: var(--space-3) 0 0;
  border-top: 1px solid var(--ccs-rule);
  font-family: var(--ccs-mono);
  font-size: var(--ccs-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}
.cc-streams-stages li{ display: flex; align-items: baseline; gap: var(--space-4); }
.cc-streams-stages li + li::before{
  content: "";
  align-self: stretch;
  width: 1px;
  background: var(--ccs-rule);
}


/* --- two tiles, side by side, equal by construction -------------
   ROW SYNC. The eyebrow sits above the plate, and the commercial one is longer
   than the residential one. MEASURED with the subgrid overridden away: from
   960 — where the two tiles first sit side by side — to about 1055, the
   commercial eyebrow wraps to two lines while the residential one does not,
   which starts one plate, and therefore one card, 17.4px below the other
   across that whole band. That is not an edge case; it covers a 1024 laptop.
   Two cards whose top edges disagree is the one thing this composition cannot
   survive.

   Subgrid puts both tiles on the SECTION's three rows, so the eyebrow row is
   as tall as the taller eyebrow in both tiles and the plates always begin on
   the same line: measured 0.00px apart at every width from 360 to 2560, and it
   holds for whatever the client puts in these strips. Where subgrid is
   unsupported each tile keeps its own rows and the two cards can differ by one
   line — degraded, not broken. Stacked, there is nothing to sync. */
@media (min-width: 60rem){
  .cc-streams-grid{
    grid-template-columns: 1fr 1fr;
    grid-template-rows: auto auto 1fr;
  }
  .cc-streams-tile{
    grid-row: span 3;
    grid-template-rows: subgrid;
    /* a subgrid inherits its parent's gutters, and --ccs-gap is up to 4.5rem —
       which would open between the eyebrow, the plate and the card. */
    row-gap: 0;
  }
}

/* Above 135rem the card is wide enough that one copy column leaves a third of
   it empty: the prose caps at 54ch, which measures 579px, while the card's
   content box reaches 874px at 2560. The copy splits, heading and action
   together in the left column.

   THE THRESHOLD IS MEASURED, NOT PICKED: at 130rem the two columns come to
   290px, under the 300px floor this section holds; at 135rem, 303px. */
@media (min-width: 135rem){
  .cc-streams-body{
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    /* every item must have a named area — .cc-streams-stages is a grid item
       here, and an item left out of grid-template-areas is planted in an
       implicit track and takes its own column with it. That exact omission has
       cost this build a broken hero once already. */
    grid-template-areas:
      "head   text"
      "act    text"
      "stages stages";
    grid-template-rows: auto 1fr auto;
    column-gap: clamp(var(--space-6), 3vw, var(--space-8));
  }
  .cc-streams-text{ margin-top: 0; }
  /* The action hangs from the foot of its column, not from the heading. The
     two headings do not always wrap to the same number of lines — scanned in
     20px steps, "Residential compliance & permitting" takes two lines from
     2520 to 2580 while the commercial one still takes three — and an action
     sitting under the heading inherits that 40px difference, which is two CTAs
     off one line. Anchored to the bottom of the slack row instead, they are
     level at every width, which is what the single-column layout already does
     by putting the slack in the prose row. */
  .cc-streams-act{ align-self: end; }
}

/* --- the two tiles stack ---------------------------------------- */
@media (max-width: 59.9375rem){
  /* the band inset is a page margin at this width, not a composition */
  .cc-streams-grid{ padding-inline: var(--space-5); }
  /* 16:9 is a letterbox on a phone; the plate goes back to the photo's ratio */
  .cc-streams-plate{ aspect-ratio: 3 / 2; }
  /* the step shortens — a 3.5rem overlap on a phone eats a third of the
     photograph — and the card stays centred */
  .cc-streams-body{ margin: calc(-1 * var(--space-5)) var(--space-4) 0; }
}

/* MEASURED. At 360 the layout is 345 and the grid's inset takes 48 of it; a
   16px side margin on the card plus a 24px padding would leave a 231px content
   box, under the 260px floor. Flush to the tile's edge at a 16px padding puts
   it at 263. */
@media (max-width: 30rem){
  .cc-streams-body{
    margin-inline: 0;
    padding: var(--space-4);
  }
}


/* ============================================================
   5 - OUR COMMITMENT   LOCKED - "Split"

   Locked to C on 25 Aug 2026. A ("Sheet") and B ("Datum") went with the
   lock; all three are in archive/2026-08-commitment-options/.

   THE SELECTORS. Nothing needed the hero's careful rewrite here. C's rules
   were already plain .cc-commitment-split* / .cc-commitment-note*, with no
   [data-variant] scope on any of them: the only variant selectors in this
   section were the three pane-visibility rules at the top, and those are
   simply gone along with .cc-commitment-v. So every surviving rule keeps
   the exact weight it was signed off at.

   .cc-commitment IS NOW THE SECTION, not a wrapper around three of them.
   It still has to exist, because it is what scopes the ramp below — in
   particular --cc-rule, which is a border shorthand here and a colour in
   "Where we work". Two sections, one property name, kept apart by scope.

   THE RAMP HAS GAPS, and they are deliberate. --cc-step-0, -2 and -4 were
   the claim/support/masthead sizes A and B set; --cc-label dressed their
   margin tags; --cc-tick was the set-out mark hanging off their rules. C
   used none of the five, so all five went. The remaining steps keep their
   original names rather than being renumbered, so a rule that reads
   --cc-step-3 is still the size it was on 12 Aug.

   BORROWED, NOT COPIED: C's margin labels are .cc-hero-assurance and
   .cc-hero-rec from section 2. Both are still used by the hero's own
   intake, so this section is not the last caller and neither is at risk
   of being deleted as hero leftovers. .cc-hero-rec carries a fallback on
   --cc-hero-rec-size for exactly this out-of-scope use; see section 2.
   ============================================================ */

.cc-commitment{
  /* Local type ramp. tokens.css ships space/radius/colour but no
     size scale, so the section carries its own, prefixed. The gaps
     in the numbering are A's and B's steps, deleted at the lock;
     --cc-step--1 went the same way on 31 Aug 2026, unspent since. */
  --cc-step-1:  1.0625rem;
  --cc-step-3:  clamp(1.75rem, 1.25rem + 2.1vw, 3rem);

  --cc-rule: 1px solid var(--border);
  --cc-rule-datum: 1px solid var(--accent);
}

.cc-commitment-title{
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: -0.025em;
  text-wrap: balance;
}


/* ============================================================
   SPLIT
   The current site's shape, shaped. Photo bleeds to the left
   viewport edge and runs the full height of the prose; each
   paragraph is annotated in the outer margin.
   ============================================================ */
.cc-commitment-split{
  display: grid;
  grid-template-columns: minmax(0, 41fr) minmax(0, 59fr);
  background: var(--surface);
}
.cc-commitment-split__media{
  position: relative;
  margin: 0;                      /* UA gives <figure> 1em/40px — kills the bleed */
  min-height: 26rem;
  background: color-mix(in srgb, var(--text) 8%, var(--surface));
}
.cc-commitment-split__media img{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 46% 30%;
}
.cc-commitment-split__body{
  background: var(--bg);
  padding: clamp(var(--space-7), 6vw, var(--space-9)) clamp(var(--space-5), 5vw, var(--space-8));
}
.cc-commitment-split__inner{
  max-width: 48rem;
  /* Centred in its half of the split, not flush against the photo. Past
     ~1600 the body column outgrows the text block by 300px and more, and a
     left-aligned block spends the whole surplus as a void on the right —
     which reads as the section being shoved off-centre. */
  margin-inline: auto;
}
.cc-commitment-split__body .cc-commitment-title{
  margin-top: var(--space-5);
  margin-bottom: clamp(var(--space-6), 4vw, var(--space-7));
  font-size: var(--cc-step-3);
  max-width: 20ch;
}

.cc-commitment-note{
  display: grid;
  grid-template-columns: minmax(0, 1fr) 8.5rem;
  column-gap: var(--space-6);
  padding: var(--space-6) 0;
  border-top: var(--cc-rule);
}
/* The first rule is the datum; the two below it are hairlines. Three
   peers, one line they are all measured from. */
.cc-commitment-note:first-of-type{ border-top: var(--cc-rule-datum); }
/* The margin label is the hero's assurance entry, borrowed by class:
   same ring marker, same record voice (.cc-hero-assurance / .cc-hero-rec,
   defined in the hero block above). The leader hairline the prototype
   drew alongside it went with the borrow — a ring and a leader are two
   markers doing one job. Only the placement is set here. */
.cc-commitment-note .cc-hero-assurance{
  grid-column: 2;
  grid-row: 1;
  margin: 0;
  padding-top: 0.3rem;   /* first label line on the paragraph's first line */
}
.cc-commitment-note__text{
  grid-column: 1;
  grid-row: 1;
  font-size: var(--cc-step-1);
  line-height: 1.65;
  color: var(--text);
  text-wrap: pretty;
}

/* ============================================================
   RESPONSIVE
   ============================================================ */
/* The margin label stops being a margin: it goes above the paragraph it
   names rather than beside it, because 8.5rem of outer column is no
   longer worth the measure it costs the prose. */
@media (max-width: 1080px) {
  .cc-commitment-note{ grid-template-columns: minmax(0, 1fr); row-gap: var(--space-4); }
  .cc-commitment-note .cc-hero-assurance{ grid-column: 1; grid-row: 1; padding-top: 0; }
  .cc-commitment-note__text{ grid-column: 1; grid-row: 2; }
}
/* the split stops splitting: photo over prose, and it takes a stated
   ratio because it no longer has a prose column to match in height */
@media (max-width: 900px) {
  .cc-commitment-split{ grid-template-columns: minmax(0, 1fr); }
  .cc-commitment-split__media{ min-height: 0; aspect-ratio: 16 / 10; }
}
@media (max-width: 420px) {
  .cc-commitment-split__media{ aspect-ratio: 4 / 3; }
}

/* ============================================================
   7 - OUR EXPERTISE   LOCKED - "Index"

   Locked to B on 25 Aug 2026. A ("Schedule") and C ("Plates") went with
   the lock; all three are in archive/2026-08-expertise-options/.

   THE SELECTORS. Every rule that read [data-variant="b"] .cc-expertise-X
   now reads .cc-expertise .cc-expertise-X. Same treatment the hero got and
   for the same reason: the wrapper selector was carrying weight, and
   dropping it outright would have dropped a whole attribute-selector's
   worth of specificity out of rules that then have to beat their own
   ≤1000px overrides. Rewritten this way every selector keeps the weight it
   was signed off at and the cascade is unchanged.

   THE RAIL IS NOT STICKY, AND WAS MEANT TO BE. The prototype set

       [data-variant="b"] .cc-expertise-head{ position: sticky; top: var(--space-6); }

   and that rule never made it into this file. Its own counterpart in the
   ≤1000px block did — `position: static`, overriding a sticky that was not
   there — which is how the loss was found at the lock. Every description of
   B in this build calls it a sticky editorial rail; the assembled page has
   never had one.

   IT WAS NOT RESTORED AT THE LOCK, deliberately. B was chosen from what was
   on screen, and a lock is meant to delete code, not change the design. The
   fix is one rule — add `position: sticky; top: var(--space-6);` to
   .cc-expertise .cc-expertise-head below and put the `position: static`
   line back in the ≤1000px block — and it is the client's call, not the
   lock's. See archive/2026-08-expertise-options/README.md.

   THE RAMP LOST FOUR ENTRIES. --cce-cols was A's register rhythm and went
   with the register. --cce-0 and --cce-1 were already dead before the lock:
   nothing in this file had referenced either since the lift. --cce-2 stays,
   because B's trigger name is set on it. The survivors keep their names
   rather than being renumbered.

   ALSO DELETED, and not A's or C's: .cc-expertise-seg and its buttons, the
   segmented Order control (Sequence / A-Z). It belonged to A, it was real in
   the prototype, and the assembled page never carried markup for it — so
   these rules had matched nothing here since the day they were lifted.

   THE DISCLOSURE BEHAVIOUR IS NO LONGER IN panel.js. initExpertiseIndex()
   lived there because it belonged to a variant that might not survive. It
   survived, so the function is in ../scripts/main.js now.
   ============================================================ */

.cc-expertise{
  /* type scale, local to this section */
  --cce-micro: 0.7rem;
  --cce--1:    0.8125rem;
  --cce-2:     clamp(1.25rem, 1.05rem + 0.55vw, 1.5rem);
  --cce-3:     clamp(1.875rem, 1.4rem + 1.9vw, 2.75rem);
  --cce-mono:  ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  /* how far each row breaks out of the body column, so the hover fill and
     the rules run wider than the text they belong to */
  --cce-bleed: var(--space-4);

  padding: var(--space-9) 0;
  /* The wash, not white: Our Commitment above ends on white — its prose
     half is --bg, full width from 900 down — and a white section under a
     white section has no edge; the heading simply appears in the same
     field. */
  background: var(--surface);
}

/* ---------- the two-column shell ----------------------------
   The header is a rail in its own column beside the list, not a banner
   above it. A and C ran it as a measure-width column above a full-width
   body so their datum line read as a dimension string rather than a
   page-wide border; with both gone, the rail is the only shape left.
   ------------------------------------------------------------ */
.cc-expertise .cc-expertise-shell{
  display: grid;
  grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
  gap: var(--space-8);
  align-items: start;
}
.cc-expertise-head h2{
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--cce-3);
  margin: var(--space-4) 0 var(--space-4);
}
.cc-expertise-intro{
  color: var(--muted);
  max-width: 54ch;
}

/* ---------- shared atoms ------------------------------------ */
.cc-expertise-ord{
  font-family: var(--cce-mono);
  font-size: var(--cce--1);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  color: var(--accent);
  line-height: 1.5;
}
.cc-expertise-ord::before{ content: counter(cce-item, decimal-leading-zero); }

.cc-expertise-scope{
  color: var(--muted);
  font-size: 0.95rem;
  line-height: 1.55;
}


/* ---------- tools row (Open all) ----------------------------- */
.cc-expertise-tools{
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  font-size: var(--cce-micro);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.cc-expertise-allbtn{
  font-family: var(--font-body);
  font-size: var(--cce-micro);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--muted);
  background: transparent;
  padding: 0.5rem 0.9rem;
  min-height: 2.25rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
  transition: background var(--transition-fast), color var(--transition-fast);
}
/* hovers fill white, not the wash — the wash is the section's own ground,
   so a wash-filled hover would be no change at all */
.cc-expertise-allbtn:hover{ background: var(--bg); color: var(--text); }

/* ============================================================
   INDEX — the disclosure list
   Names only. Six of them fit one screen with room to spare, and
   twelve still do on /services, which is what this shape was
   chosen to survive. Each scope note is one disclosure away.
   ============================================================ */
.cc-expertise-index{
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: cce-item;
  border-top: 1px solid var(--border-strong);
}
.cc-expertise-item{
  counter-increment: cce-item;
  border-bottom: 1px solid var(--border);
  padding-inline: var(--cce-bleed);
  margin-inline: calc(var(--cce-bleed) * -1);
  transition: background var(--transition-fast);
}
.cc-expertise-item:hover,
.cc-expertise-item:focus-within{ background: var(--bg); }
.cc-expertise-itemh{ margin: 0; }
.cc-expertise-trigger{
  display: grid;
  grid-template-columns: 2.75rem minmax(0, 1fr) 1.25rem;
  gap: var(--space-4);
  align-items: baseline;
  width: 100%;
  padding: var(--space-5) 0;
  background: none;
  border: 0;
  text-align: left;
  color: var(--text);
  transition: color var(--transition-fast);
}
.cc-expertise-trigger:hover{ color: var(--accent); }
.cc-expertise-triggername{
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--cce-2);
  letter-spacing: -0.02em;
  line-height: 1.15;
}
/* the sign is a plus that loses its vertical stroke when the panel opens —
   no rotation, so nothing to reverse under reduced motion */
.cc-expertise-sign{
  width: 1.25rem; height: 1.25rem;
  align-self: center;
  stroke: var(--accent);
  stroke-width: 1.25;
  overflow: visible;
}
.cc-expertise-sign .cc-expertise-signv{
  transform-origin: 8px 8px;
  transition: transform var(--transition);
}
.cc-expertise-item[data-open="true"] .cc-expertise-signv{ transform: scaleY(0); }

/* Height animated as a grid track, 0fr to 1fr, so the panel opens to its
   own content height without that height being measured in JS. */
.cc-expertise-panel{
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--transition);
}
.cc-expertise-item[data-open="true"] .cc-expertise-panel{ grid-template-rows: 1fr; }
/* visibility, not display: a 0fr track still leaves its content focusable,
   so the delay hides it for tabbing without cancelling the transition */
.cc-expertise-panelinner{
  overflow: hidden;
  visibility: hidden;
  transition: visibility 0s linear 240ms;
}
.cc-expertise-item[data-open="true"] .cc-expertise-panelinner{
  visibility: visible;
  transition: visibility 0s linear 0s;
}
/* the scope note lines up under the name, not under the ordinal */
.cc-expertise-panelbody{
  padding: 0 0 var(--space-5) calc(2.75rem + var(--space-4));
  display: grid;
  gap: var(--space-3);
  max-width: 62ch;
}

/* ---------- the way out ------------------------------------- */
/* Added 26 Aug 2026. Locking this section to the disclosure list turned all
   six service names into buttons, which left the section with no link in it
   at all and /services reachable only from the header nav.

   Sits under the list on the list's own measure, not the rail's, and is set
   at body size rather than the micro/uppercase register the tools row uses.
   That row is a control; this is a sentence, and the two should not be
   mistaken for each other.

   NO RULE ABOVE IT. This first shipped with a border-top and a padding-top to
   clear it, which put a second hairline three and a half rem below the one
   .cc-expertise-item already draws under the last row — the same colour, the
   same weight, reading as a mistake because it was one. The list's own last
   border closes the list; space alone is what separates the sentence from it.

   The link carries the arrow, the sentence does not: only the half that
   navigates should look like it navigates. */
.cc-expertise-more{
  margin: var(--space-6) 0 0;
  color: var(--muted);
  line-height: 1.7;
}
.cc-expertise-morelink{
  color: var(--link-color);
  font-weight: 600;
  text-decoration: none;
  background-image: none;
  white-space: nowrap;
}
.cc-expertise-morelink:hover{ color: var(--link-hover); text-decoration: underline; }
.cc-expertise-morelink:focus-visible{ outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; }
/* The arrow nudges, the words do not move — a hover cue that does not reflow
   the sentence it sits in. Zeroed under reduced motion by page.css's global
   block, which is why there is no second query for it here. */
.cc-expertise-morelink span{
  display: inline-block;
  margin-left: 0.15rem;
  transition: transform var(--transition-fast);
}
.cc-expertise-morelink:hover span{ transform: translateX(3px); }

/* ---------- responsive -------------------------------------- */
/* The rail stops being a rail: the header goes back above the list, because
   20rem of column is no longer worth what it costs the names beside it. */
@media (max-width: 1000px){
  .cc-expertise .cc-expertise-shell{ grid-template-columns: 1fr; gap: var(--space-6); }
}
@media (max-width: 720px) {
  .cc-expertise{ --cce-bleed: var(--space-3); }
  .cc-expertise-trigger{ grid-template-columns: 2.25rem minmax(0, 1fr) 1.25rem; gap: var(--space-3); }
  .cc-expertise-panelbody{ padding-left: calc(2.25rem + var(--space-3)); }
}

/* ============================================================
   7B - TESTIMONIALS   LOCKED - "Sequence"

   Locked to C on 25 Aug 2026. A ("Register") and B ("Streams")
   went with the lock; all three are in
   archive/2026-08-testimonials-options/.

   7B, not 8. The numbers here are the original build's section
   slots and the gaps record what was dropped (6 was the marquee).
   This section has no slot of its own: it was deferred before the
   numbering was written, and it lands between 7 and 8. Renumbering
   Where we work onwards would break every comment that refers to a
   section by number for the sake of one integer.

   THIS SECTION LOST A LEVEL, AND IT IS THE ONLY ONE THAT DID. Every
   rule of C was scoped `[data-variant="c"] .cc-t...` (0,2,0), and
   stripping the prefix takes them to 0,1,0.

   The other locks in this file did not go that way, so do not read
   this paragraph as a statement about the file. The hero and Our
   Expertise re-scoped to a parent class instead — `.cc-hero
   .cc-hero-X`, `.cc-expertise .cc-expertise-X` — holding 0,2,0 so
   their rules keep beating their own narrow-viewport overrides on
   weight rather than on source order. Twelve rules and two,
   respectively. Our Commitment, service streams and Where we work
   had nothing to lose: all three were already plain.

   Plain is right here for two reasons. Nothing competes at either
   weight — .cc-t is this section's alone, and base.css reaches these
   elements only by tag at 0,0,1. And the 900px block below overrides
   .cc-t-stop at exactly the weight of the rule it overrides, which
   is what it did at 0,2,0 as well: that pair has always been settled
   by source order and the relationship is unchanged. The rules above
   0,1,0 further down are sibling combinators and pseudo-elements,
   not variant leftovers.

   THE THREE GROUNDS ARE NOW ONE. a took the footer's own dark
   palette, b took the wash and drew a top rule against Our
   Expertise above it, and c takes a brand tint - the one ground on
   this page that is neither white nor the wash, and the only one of
   the three that added to the site's palette. C's ground has been
   folded into the base .cc-t rule rather than left as a second rule
   on the same selector.

   THE RAMP HAS GAPS, and they are deliberate. --cct-0, --cct-2 and
   --cct-quote were sizes only a and b set: --cct-quote dressed the
   big pulled quote both of them ran, --cct-2 the classification.
   C sets its quote from its own clamp, one step below --cct-2,
   because three columns at 1440 leave about 350px each. The
   surviving steps keep their original names rather than being
   renumbered, so a rule reading --cct--1 is the size it was signed
   off at.

   DELETED WITH A AND B: .cc-t-list (c hangs its stops off
   .cc-t-seq), .cc-t-row, .cc-t-class, .cc-t-rule, the curly-quote
   ::before/::after pair that was a's alone, the whole 720px
   breakpoint that stacked a's rows, and the .cc-t-panelfor
   visibility rules that kept all three bodies in the DOM at once.

   NO REDUCED-MOTION GUARD, and none is needed: nothing in this
   section moves. There is no transition, animation or transform in
   any surviving rule - the two `transform` matches are
   text-transform on the stage label and nothing else. page.css
   still carries the page-wide block, which is where a rule that
   broad belongs.
   ============================================================ */

/* ============================================================
   TESTIMONIALS — all section CSS lives here, prefixed cc-t-*.
   Local custom properties use --cct- so they cannot collide
   with the token file.

   Ink is read from --cct-ink / --cct-dim / --cct-key / --cct-rule,
   set once alongside the ground. That indirection is what let the
   three variants swap palettes without a second set of colour
   rules; it survives the lock because the section's own type still
   reads through it and flattening it now would touch every rule
   below to save four declarations.
   ============================================================ */

.cc-t {
  --cct-micro: 0.7rem;
  --cct--1:    0.8125rem;
  --cct-1:     1.0625rem;
  --cct-3:     clamp(1.875rem, 1.4rem + 1.9vw, 2.75rem);

  --cct-ink:  var(--text);
  --cct-dim:  var(--muted);
  /* --brand measures 4.13:1 on this tint, and the stage labels are
     0.7rem uppercase — small text, so 4.5:1 is the floor and 4.13 is
     under it. --link-hover is the token's own darker step and clears
     it at 6.10:1. The ring and the spine keep --brand: neither is text. */
  --cct-key:  var(--link-hover);
  --cct-rule: color-mix(in srgb, var(--brand) 25%, transparent);
  /* Was 6%, which computed to #F4F8F9 against the wash's #F5F8F9 —
     a fourth ground that was the third ground with extra steps.
     12% is unmistakably a tint and still nowhere near a colour field. */
  background: color-mix(in srgb, var(--brand) 12%, #FFFFFF);

  padding: var(--space-9) 0;
  color: var(--cct-ink);
}

/* ---------- section header ----------------------------------- */
.cc-t-head {
  max-width: 44rem;
  margin-bottom: var(--space-8);
}
.cc-t-head h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--cct-3);
  line-height: 1.12;
  letter-spacing: -0.02em;
  margin: var(--space-4) 0 var(--space-4);
  text-wrap: balance;
}
.cc-t-lede {
  max-width: 40rem;
  color: var(--cct-dim);
  font-size: var(--cct-1);
  line-height: 1.75;
}
/* .eyebrow is a base.css rule and reads --muted / --brand off the
   root. --brand is the wrong key on this tint — see --cct-key
   above, where it fails contrast at 0.7rem. Restated. */
.cc-t .eyebrow { color: var(--cct-dim); }
.cc-t .eyebrow::before { background: var(--cct-key); }

.cc-t-quote { margin: 0; }
.cc-t-quote p { margin: 0; text-wrap: pretty; }

/* <cite> is the right element for the attribution and every browser
   italicises it by default. Undone: these are people, not titles of
   works, and the slant reads as emphasis nobody asked for. */
.cc-t cite { font-style: normal; }

/* base.css resets ul, not ol, and this ordered list arrived painting
   1. 2. 3. beside its own spine. The order is real and stays in the
   markup; the markers are what the spine already draws, so only they
   go. */
.cc-t-seq { list-style: none; margin: 0; padding: 0; }


/* ============================================================
   the spine
   Permit, inspections, occupancy: the statutory order a certifier
   actually works in. Continuous because the list has no gap — each
   stop carries its own inside padding instead, so the three
   border-tops meet.
   ============================================================ */
.cc-t-seq {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  counter-reset: none;
}
.cc-t-stop {
  position: relative;
  /* Rows, so the three attributions sit on one baseline however
     unevenly the quotes above them wrap. */
  display: grid;
  grid-template-rows: auto 1fr auto;
  border-top: 2px solid var(--cct-rule);
  padding: var(--space-6) var(--space-6) 0 0;
}
.cc-t-stop + .cc-t-stop { padding-left: var(--space-6); }
/* A ring rather than a filled dot: it reads as a survey point, and
   it stays legible against the spine it sits on. */
.cc-t-stop::before {
  content: "";
  position: absolute;
  top: -0.5rem;
  left: 0;
  box-sizing: border-box;
  width: 0.9rem;
  height: 0.9rem;
  border: 2px solid var(--brand);
  border-radius: 50%;
  background: color-mix(in srgb, var(--brand) 12%, #FFFFFF);
}
.cc-t-stop + .cc-t-stop::before { left: var(--space-6); }
.cc-t-stage {
  margin: 0 0 var(--space-4);
  color: var(--cct-key);
  font-size: var(--cct-micro);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.cc-t-quote p {
  font-family: var(--font-display);
  font-weight: 400;
  /* Its own step, below the retired --cct-2: three columns at 1440
     leave about 350px each, and --cct-2 ran the shortest quote to
     six lines. */
  font-size: clamp(1.05rem, 0.95rem + 0.42vw, 1.24rem);
  line-height: 1.6;
  letter-spacing: -0.01em;
}
.cc-t-name {
  margin: var(--space-5) 0 0;
  color: var(--cct-dim);
  font-size: var(--cct--1);
}
.cc-t-name b { color: var(--cct-ink); font-weight: 600; }


/* ============================================================
   responsive
   ============================================================ */
@media (max-width: 900px) {
  .cc-t-seq { grid-template-columns: 1fr; }
  /* The spine turns 90 degrees and runs down the left. Same device,
     same node, no second design to keep true. */
  .cc-t-stop,
  .cc-t-stop + .cc-t-stop {
    border-top: 0;
    border-left: 2px solid var(--cct-rule);
    padding: 0 0 var(--space-8) var(--space-6);
  }
  .cc-t-stop::before,
  .cc-t-stop + .cc-t-stop::before { top: 0; left: -0.5rem; }
  .cc-t-stop:last-child { padding-bottom: 0; }
}


/* ============================================================
   8 - WHERE WE WORK   LOCKED - no variants

   The three prototyped options (Schedule / Plan / Record) were
   dropped on 13 Aug 2026 for the MyReno service-area band. It
   stays in this file rather than moving to page.css only because
   the sections around it are still switching.

   A reskin, not a redesign: the grid, the type scale, the map
   treatment and the responsive break are ../../myreno's .areas
   rules ported across. Only the tokens changed, and two of them
   change the result:
     --gold           -> --accent, for the hairlines and the one
                         focused suburb name
     --surface-strong == --bg here, where MyReno's is a warm tint
   So the band's polarity inverts. MyReno lays a tinted strip
   between white sections; this lays a white strip under the
   washed Our Expertise above it. Same device, same 6.7% step,
   opposite direction.

   It was a strip between two washes until the enquiry form was
   removed from this page on 20 August 2026. It is now the last
   section, and the run still alternates into the dark footer:
   wash, white, dark.
   ============================================================ */

/* Deliberately a slim band, not a full-height section like Our Expertise - it
   is the short answer to "do you cover my suburb?", and giving it the weight of
   the service schedule would overstate it.

   Suburb names take --text against the muted body so someone scanning for their
   own suburb finds it without the prose turning into a list. */
.cc-coverage{
  padding: clamp(4.5rem, 8vw, 8rem) 0;
  border-top: 1px solid color-mix(in srgb, var(--accent) 24%, var(--border));
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 24%, var(--border));
  background: var(--surface-strong);
}

/* Two columns for the whole section: heading and prose stack on the left, the
   map is a full-height column on the right. align-items defaults to stretch, so
   the map's row is sized by the left column and the map fills it top to bottom. */
.cc-coverage__layout{
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(18rem, 30rem);
  gap: clamp(2rem, 5vw, 5rem);
}

.cc-coverage__body{
  display: grid;
  align-content: start;
  gap: clamp(2rem, 4vw, 3rem);
}

.cc-coverage__title-group{
  display: grid;
  gap: var(--space-4);
}

/* MyReno carries two .areas h2 rules - a leftover prototype scale of 4.5rem
   further up its file, and the real one that overrides it. Only the winner
   is ported. */
.cc-coverage h2{
  max-width: 19ch;
  font-size: clamp(2rem, 3.4vw, 3rem);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.cc-coverage__prose{
  display: grid;
  gap: 1.5rem;
  max-width: 46rem;
}

.cc-coverage__prose p{
  color: var(--muted);
  font-size: 1.05rem;
  line-height: 1.8;
}

.cc-coverage__prose b{
  color: var(--text);
  font-weight: 500;
}

/* Fraser Rise is the one name here that is not coverage - it is where they
   actually are. --accent computes 4.83:1 on --bg, so it clears AA at body size
   even though it is only carrying a proper noun. */
.cc-coverage__focus{
  color: var(--accent);
  font-weight: 700;
}

/* Coverage map - the right-hand column, running the full height of the section.
   No aspect-ratio here: the grid row is sized by the text column beside it, so
   the height is already deterministic and reserved before the iframe loads.
   min-height guards the case where the prose is unusually short.

   This is the page's only third-party iframe, and its src is withheld until
   scroll - see initCoverageMap() in scripts/main.js. */
.cc-coverage__map{
  position: relative;
  min-height: 24rem;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-soft);
}

.cc-coverage__map iframe{
  width: 100%;
  height: 100%;
  display: block;
  border: 0;
  /* Google's tiles are saturated next to the page's near-neutral palette;
     easing them back keeps the map from shouting over the type. */
  filter: saturate(0.82) contrast(0.96);
}

/* =============================================================
   RESPONSIVE
   ============================================================= */
/* MyReno stacks at 860. This stacks at 1000, the one number in the port that
   is not theirs. Between those two widths the map track is pinned at its 30rem
   maximum while the text track is minmax(0, 1fr) and takes what is left — at
   900px that is a 343px column of prose beside a 480px map, which puts the
   supporting element in charge of the section. Above 1000 the proportion is
   MyReno's again. */
@media (max-width: 1000px){
  .cc-coverage__layout{ grid-template-columns: 1fr; }

  /* Stacked, so there is no text column to inherit a height from - fall back to
     a fixed ratio, which also keeps the space reserved against layout shift. */
  .cc-coverage__map{
    aspect-ratio: 4 / 3;
    min-height: 0;
  }
}

/* REMOVED 25 Aug 2026 — the section-level reduced-motion block stood here,
   holding two rules and nothing else:

       .cc-hero-gate:hover { transform: none; }
       .cc-expertise-plate:hover, :focus-within { transform: none; }

   Both cancelled a translate on hover. The plates were Our Expertise's
   variant C and went with that section's lock; .cc-hero-gate was hero C's
   statutory gates and had already been deleted at the hero lock the day
   before, leaving that rule matching nothing. Removing the plates emptied
   the block in effect, so it went rather than being left as a
   reduced-motion guard over two selectors that no longer exist.

   Nothing on the page moves on hover any more that needs guarding here:
   B's disclosure sign scales a stroke rather than translating, and the
   panel animates a grid track. page.css still carries the global block,
   which is where a page-wide rule belongs. */


/* REMOVED 21 Aug 2026 — a block titled "RECOVERED: the B variants of
   Our Commitment, Our Expertise and Where we work" sat here holding
   nothing but three :root[data-variant] commitment rules. :root is
   <html>, which carries no data-variant in this build: the zone
   wrapper does. The rules never matched. The identical, correctly
   scoped pair is at the head of section 5. */
