/* =========================================================================
   FJ T64 -- HOMEPAGE STYLESHEET (build sitting 1, 2026-08-24)
   FIX ROUND applied 2026-08-24 (post-QA) under Fred's rulings R1-R4
   ("#179 ruling" in the comments below).

   Companion to front-page-t64.php and assets/js/fj-t64-home.js.
   NEW FILE -- not yet enqueued anywhere. Renamed this session from
   fj-home.css after a filename collision: assets/css/fj-home.css now holds
   the RESTORED 13/08 stylesheet and is NOT this file.

   Governed by FJ_VISUAL_SYSTEM_MOTION_2026-08-17.md (SIGNED 24/08/2026,
   DECISION_LOG #177-D) and T54_TOKENS_AND_TYPOGRAPHY.md (24/08 amendments).

   #179 ruling R2 -- TOKEN PURITY. Every colour, font, size, duration,
   easing and radius below is a BARE var(--token) with NO literal fallback.
   The tokens are registered in style.css at integration (same package);
   the complete list this file consumes is in the build note's FIX ROUND
   section, and the integration lane registers exactly that list.
   FIX ROUND 2 applied 2026-08-24 after the re-gate returned NO-GO. The
   delta closed here is MAJ-1..MAJ-9 / MIN-1..MIN-8; every edit carries a
   "FIX ROUND 2" comment naming its re-gate ID. DECISION_LOG #179 now
   EXISTS on disk, so the #179 citations below are live.

   LITERALS IN THIS FILE, AND THEIR AUTHORITY (re-gate MAJ-8; rebuilt fix
   round 4 from a MECHANICAL comment-stripped declaration sweep -- 49
   distinct literal tokens, _litsweep.js, 24/08):
     (white)                 -- FIX ROUND 3 / MI-2: every white declaration
                                now reads var(--white). --white:#FFFFFF is
                                ADDED to the integration token list by
                                coordinator ruling (recorded in the build
                                note fix section) -- system sec2.2 names
                                white as the dark-band ink; T54 sec5 rule 1
                                forbids the raw hex in this file.
     44px (H1) / 30px (H2)   -- ratified sec1.2 ladder VALUES with no token
                                name anywhere on disk. Flagged, not invented.
     48px / 14px 24px        -- button min-height and padding, stated as
                                literals by system sec4.1.
     12px                    -- placecard inset hairline, system sec4.7.
     calc(var(--radius-3) - 6px) -- the inset hairline's radius. 6px is NOT
                                in any spec: it is the geometric consequence
                                of a 12px inset (a concentric inner radius
                                would be r-12; 6px is a HALF-inset visual
                                choice made in round 1). FLAGGED as an
                                un-sourced literal -- coordinator's call.
     1240px                  -- page max width, system sec2.1a / T54 sec3.
     220px (x3)              -- FIX ROUND 3 / MA-1+MI-3 recount: the
                                flex-basis on the mobile scroller, the
                                minmax() floor on the desktop grid, AND
                                .fj-placecard's min-height (which only
                                --hero resets). None is in any spec on
                                disk. FLAGGED as un-sourced round-1
                                literals; the first two are load-bearing
                                for MAJ-2.
     5fr / 7fr, 55fr / 45fr  -- hero and custom-band column splits. 55/45 is
                                sourced: PHOTO_SLOTS_T64.md sizes CUSTOM-01
                                at ">=55% optical weight". The hero's 5/7 is
                                NOT sourced -- FLAGGED, a round-1 choice.
     2px 6px                 -- owed-copy marker padding. Internal build-only
                                element, never customer-visible. Not in any
                                spec; FLAGGED as arbitrary but harmless.
     600px                   -- perspective on the M4 Fold parent. NOT in any
                                spec; rotateX is invisible without a
                                perspective, so some value was required.
                                FLAGGED as a round-1 choice.
     24ch/28ch/34ch/40ch/64ch -- measures. 24ch (H1), 28ch (H2), 34ch
                                (product name) and 64ch (lede/body) are all
                                system sec1.3's own figures. 40ch on
                                .fj-custom__step-body is NOT -- sec1.3 gives
                                body 60-75ch. FLAGGED as a round-1 tightening.
     1.10 / 1.14 / 1.35 / 1.4 / 1.3 / 1.5 / 1.6 -- line heights, all from
                                system sec1.3's own table (see section 2).
     rgba(0,0,0,.18) / .12    -- the two pressed-state inset shadows, quoted
                                from system sec4.1 / T54 sec5 item 5.
     .08em                   -- micro-label letter tracking, system sec4.7's
                                own placecard label spec (uppercase 600
                                .08em). Added to this audit fix round 3 --
                                MA-1 found it missing.
     motion transforms       -- translateY(12px) Rise / translateY(8px)
                                Settle / translateY(10px) scale(1.06) Nest /
                                rotateX(-8deg) Fold: ALL system sec3.3's own
                                motion table, byte-for-byte (verified re-gate
                                2). translateY(-2px) card hover = sec4.4
                                verbatim; translateY(-1px) button hover =
                                sec4.1/4.2.
     "opsz" 64 / 48          -- font-variation-settings, sec1.1a item 4
                                verbatim.
     1px                     -- underline thickness (sec4.3), hairlines
                                (sec4.7/sec5.4), card border (sec4.4).
     2px                     -- focus outline + offset (T54 sec3 24/08),
                                underline offset (sec4.3), pressed-shadow
                                geometry "inset 0 2px 4px" (sec4.1, colour
                                listed above).
     6%                      -- the color-mix() Navy hover wash, sec4.2.
     .01ms                   -- reduced-motion kill duration (sec3.7
                                backstop), x3.
     4/3 and 1/1             -- aspect-ratios: HERO-01 desktop crop and
                                CUSTOM-01 square, both PHOTO_SLOTS_T64.md.
     3 (bare)                -- arithmetic constant in the nest group-gap
                                calc (3 * --stagger-tight); derivation in
                                section 12's comment.
     400/600/700, 100%       -- font weights (sec1.1/1.3 rows) and
                                structural width/height percentages -- not
                                design tokens.
   AUDIT LAW: this list is maintained WITH the file -- any literal found in
   a declaration and not listed here is a defect in this header as well as
   in the declaration. No absolute completeness claim is made beyond the
   MECHANICAL sweep dated 24/08 fix round 4 (_litsweep.js, 49 tokens).

   ASCII only. Mobile-first, min-width breakpoints throughout.
   12-col / 1240px grid (system sec2.1a, ratified T54 sec3 24/08).
   Focus ring: 2px Royal everywhere, 2px var(--white) on dark bands (#179 R1).

   Space scale (T54): 4/8/12/16/20/24/32/40/48/64 = --space-1..10.
   ========================================================================= */

/* -------------------------------------------------------------------------
   0. RESET-LITE (scoped to this template's own elements only)
   ------------------------------------------------------------------------- */
.fj-main, .fj-main * { box-sizing: border-box; }
/* FIX ROUND 2 (re-gate MAJ-1): the page canvas is PAPER. system sec2.2 names
   Paper as the surface every light band sits on, and #177-D item 8 settled
   which Paper hex that is. Round 1 painted no canvas at all, so the light
   bands inherited whatever the parent theme's body colour happened to be and
   the dark bands were the only surfaces this file actually controlled. */
.fj-main { background: var(--paper); }
.fj-main ul, .fj-main ol { list-style: none; margin: 0; padding: 0; }
.fj-main img { max-width: 100%; height: auto; display: block; }
.fj-main a { color: inherit; text-decoration: none; }

/* Buttons/inputs must inherit font-family -- T54-D1 defect, do not regress. */
.fj-main button,
.fj-main input,
.fj-main select,
.fj-main textarea,
.fj-btn {
  font-family: inherit;
}

/* <b>/<strong> synthesised-weight fix -- T54-D3. */
.fj-main b,
.fj-main strong {
  font-weight: 700;
}

/* -------------------------------------------------------------------------
   1. LAYOUT -- 12-col / 1240px grid (ratified T54 sec3, 24/08; system F14)
   Mobile-first: the base rules ARE the <=767px values, and every override
   below is min-width (finding m2 -- one breakpoint direction, not two).
   ------------------------------------------------------------------------- */
.fj-container {
  max-width: 1240px;
  margin-inline: auto;
  padding-inline: var(--space-4);
}
@media (min-width: 768px) {
  .fj-container { padding-inline: var(--space-6); }
}

.fj-band {
  padding-block: var(--space-8);
}

.fj-band--dark {
  background: var(--navy);
  color: var(--white); /* system sec2.2 dark-band ink; --white registered at integration (MI-2) */
}

/* Rhythm variation (sec2.1) -- no two adjacent bands share a padding pair.
   Base = mobile.

   FIX ROUND 2 (re-gate MAJ-5): band 4 no longer shares band 2's pair.
   Band 3 only exists when real products come back (see the template's
   `if ( $fj_product_count > 0 )`), so there are TWO real band orders and the
   rule has to hold in both. Round 1 gave bands 2 and 4 the SAME pair, which
   passed only because band 3 sat between them -- in the empty state they
   became adjacent twins. Band 4 now takes its own pair from the same T54
   space scale: --space-8/--space-7 (40/32) on mobile and
   --space-10/--space-9 (64/48) from 768. Both registers verified below.

     WITH band 3, mobile:    48/40 . 32/32 . 40/40 . 40/32 . 24/40   all differ
     WITHOUT band 3, mobile: 48/40 . 32/32 . 40/32 . 24/40           all differ
     WITH band 3, >=768:     64/64 . 48/48 . 40/40 . 64/48 . 48/40   all differ
     WITHOUT band 3, >=768:  64/64 . 48/48 . 64/48 . 48/40           all differ

   Noted, not fixed (outside this delta): in the empty-band-3 state bands 2
   and 4 are both DARK and now sit directly against each other. The padding
   pairs differ, so sec2.1's rhythm rule holds, but two abutting navy bands
   is a composition question for the coordinator, not a spacing one. */
.fj-band--hero { padding-block: var(--space-9) var(--space-8); }
.fj-band--trust { padding-block: var(--space-7); }
.fj-band--custom { padding-block: var(--space-8) var(--space-7); }
.fj-band--products { padding-block: var(--space-8); }
.fj-band--faq { padding-block: var(--space-6) var(--space-8); }

@media (min-width: 768px) {
  .fj-band--hero { padding-block: var(--space-10); }
  .fj-band--trust { padding-block: var(--space-9); }
  .fj-band--custom { padding-block: var(--space-10) var(--space-9); }
  .fj-band--products { padding-block: var(--space-8); }
  .fj-band--faq { padding-block: var(--space-9) var(--space-8); }
}

/* -------------------------------------------------------------------------
   2. TYPE (T54 sec1 + system sec1.2/1.3; display steps ratified T54 sec3)
   Finding m10: the dead .fj-trust__h2 rules are gone -- band 2 has no H2.
   ------------------------------------------------------------------------- */
.fj-hero__h1,
.fj-section-h2,
.fj-custom__h2 {
  font-family: var(--font-display);
  font-weight: 700; /* T54 sec1: the display face loads at 700 and only 700 */
  color: var(--navy);
  margin: 0 0 var(--space-4);
}
.fj-band--dark .fj-custom__h2 {
  color: var(--white);
}

/* H1 ladder. FIX ROUND 2 (re-gate MIN-3): the top step starts at 769, NOT
   1024. sec1.2's own table has three columns -- "px desktop | px <=768 |
   px <=390" -- so 64 is the value for everything ABOVE 768, i.e. from 769.
   Round 1's 1024 was invented: it left 769-1023 rendering the 44px step,
   which sec1.2 assigns to <=768 only. The citation comment is corrected
   with it.
   36 is --3xl and 64 is --text-5xl; the 44 intermediate step is ratified as
   a VALUE in sec1.2 but has no token name anywhere on disk -- flagged in the
   build note rather than invented as a token here (finding m2). */
.fj-hero__h1 {
  font-size: var(--text-3xl);
  line-height: 1.10; /* sec1.3 Homepage H1 */
  max-width: 24ch;   /* sec1.3 Homepage H1 */
}
@media (min-width: 391px) {
  .fj-hero__h1 { font-size: 44px; }
}
@media (min-width: 769px) {
  .fj-hero__h1 {
    font-size: var(--text-5xl);
    /* Finding M8 / system sec1.1a item 4: name the optical-size position so
       the 64px H1 gets Fraunces' DISPLAY drawing, not a text drawing scaled
       up. Inert if the loaded file is a static instance -- that is an open
       verification item in the build note, not an assumption. */
    font-variation-settings: "opsz" 64;
  }
}

/* H2 ladder, ratified sec1.2: 30 at <=390, 36 from 391, 48 from 769.
   FIX ROUND 2 (re-gate MIN-3): 769, not 1024 -- same correction as the H1.
   36 is --3xl and 48 is --text-4xl; 30 has no token name (see H1 note). */
.fj-section-h2,
.fj-custom__h2 {
  font-size: 30px;
  line-height: 1.14; /* sec1.3 Section H2 */
  max-width: 28ch;   /* sec1.3 Section H2 */
}
@media (min-width: 391px) {
  .fj-section-h2,
  .fj-custom__h2 { font-size: var(--text-3xl); }
}
@media (min-width: 769px) {
  .fj-section-h2,
  .fj-custom__h2 {
    font-size: var(--text-4xl);
    font-variation-settings: "opsz" 48; /* finding M8 / sec1.1a item 4 */
  }
}

/* Body / lede. F10 is still open: no --ink token is registered anywhere on
   disk, so body ink resolves to the locked Navy token DIRECTLY rather than
   depending on an unregistered name (the old var(--ink, ...) chain would
   compute to nothing once its literal fallback was stripped under R2).
   When --ink is registered and measured on Paper, swap it in here. */
.fj-hero__delivery,
.fj-trust__body {
  font-family: var(--font-body);
  font-size: var(--text-lg);
  line-height: 1.6; /* sec1.3 Lede / intro */
  max-width: 64ch;  /* sec1.3 Lede / intro */
  color: var(--navy);
  margin: 0 0 var(--space-6);
}
.fj-band--dark .fj-trust__body { color: var(--white); }

.fj-product-row__name {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--text-base);
  line-height: 1.35; /* sec1.3 Product name in a list */
  max-width: 34ch;   /* sec1.3 Product name in a list */
  color: var(--navy);
}
/* Money -- inline / unit price: body 600 --sm, line-height 1.4 (sec1.3).
   FIX ROUND 2 (re-gate MIN-4): the 1.4 was missing. The BASE line now holds
   sec12's whole sentence -- "$X.XX ex GST ($Y.YY inc GST)" -- which wraps on
   a narrow card, so the leading is doing real work here, not decoration. */
.fj-product-row__price {
  display: block;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--text-sm);
  line-height: 1.4; /* sec1.3 Money -- inline / unit price */
  color: var(--navy);
}
/* FIX ROUND 2: .fj-product-row__basis is DELETED. It existed to name the tax
   basis when the store had no price-display suffix; the BASE string now names
   both bases itself in every branch, so the element no longer renders. */
.fj-product-row__unit {
  display: block;
  font-family: var(--font-body);
  font-weight: 600;      /* FIX ROUND 3 / MI-4: sec1.3 "Money -- inline / unit price" = --sm 600 */
  font-size: var(--text-sm);
  line-height: 1.4; /* sec1.3 Money -- inline / unit price */
  color: var(--muted);
}
/* FIX ROUND 2 (re-gate BLOCKER-2): the sec7 "Ctn Qty" note. Typed as sec1.3's
   "Legal / footnote" row -- body --xs (13) 400, line-height 1.5 -- because
   sec1.3 has no row for a secondary product note and this is the nearest
   registered one. Deliberately NOT typed as the micro-label row: that row
   carries uppercase + .08em tracking, which would transform real stored data
   ("Ctn Qty: 500" -> "CTN QTY: 500") rather than just present it. */
.fj-product-row__ctn {
  display: block;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--text-xs);
  line-height: 1.5; /* sec1.3 Legal / footnote */
  color: var(--muted);
}

/* Finding m3: the step numeral is BODY 700, not display. T54 sec1 restricts
   --font-display to h1-h3 and money display figures only. */
.fj-custom__step-num {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--text-xl);
  color: var(--gold);
}
/* Finding M11: step label line -- body 600 --lg (system sec5.4). */
.fj-custom__step-label {
  display: block;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--text-lg);
  line-height: 1.6; /* sec1.3 Lede / intro -- the nearest --lg body row */
  color: var(--white);
}
.fj-custom__step-body {
  display: block;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--text-base);
  line-height: 1.6; /* sec1.3 Body */
  max-width: 40ch;
  color: var(--white);
}

.fj-faq__q,
.fj-faq__a {
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.6; /* sec1.3 Body */
  color: var(--navy);
}
.fj-faq__q { font-weight: 600; }
.fj-faq__a { font-weight: 400; }

/* -------------------------------------------------------------------------
   2a. PROSE LINKS (system sec4.3) -- scoped to prose contexts only, so the
   product-row link (a whole clickable unit, spec sec4.4) is never caught.
   ON PAPER: Royal, no underline at rest inside a visually distinct prose
   block, underlined on hover AND focus, 1px, offset 2px.
   ON A DARK BAND (finding B2, #179 ruling R1 lane): the underline is
   PERSISTENT AT REST and the ink is white. Royal on Navy measures 1.99:1 --
   far under any floor -- so a dark-band prose link can be neither Royal nor
   colour-only; the underline is the resting signal, per sec2.2's
   "underline on hover, never colour-only state" read on a reversed surface.
   Band 2's own link is OWED COPY today (#179 ruling R4); this rule ships so
   the link is correct the moment TRUST-01's real copy lands.
   ------------------------------------------------------------------------- */
.fj-main p a,
.fj-main .fj-faq__q a,
.fj-main .fj-faq__a a,
.fj-main .fj-custom__step-label a,
.fj-main .fj-custom__step-body a {
  color: var(--royal);
  text-decoration: none;
}
.fj-main p a:hover,
.fj-main p a:focus-visible,
.fj-main .fj-faq__q a:hover,
.fj-main .fj-faq__q a:focus-visible,
.fj-main .fj-faq__a a:hover,
.fj-main .fj-faq__a a:focus-visible,
.fj-main .fj-custom__step-label a:hover,
.fj-main .fj-custom__step-label a:focus-visible,
.fj-main .fj-custom__step-body a:hover,
.fj-main .fj-custom__step-body a:focus-visible {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}
.fj-main .fj-band--dark p a,
.fj-main .fj-band--dark .fj-custom__step-label a,
.fj-main .fj-band--dark .fj-custom__step-body a {
  color: var(--white);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

/* -------------------------------------------------------------------------
   3. BAND 1 -- HERO -- Device D1 SPLIT (system sec2.1a / sec5.6)
   Nothing above the fold animates on first paint (binding, system sec5.2).
   ------------------------------------------------------------------------- */
.fj-band--hero {
  display: grid;
  gap: var(--space-6);
}
@media (min-width: 900px) {
  .fj-band--hero {
    grid-template-columns: 5fr 7fr; /* quiet copy half / busy media half */
    align-items: center;
  }
}
.fj-hero__ctas {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-top: var(--space-6);
}
/* HERO-01 when the real photo is set (finding M5) -- same box as the
   placecard it replaces, so nothing reflows on the swap.

   FIX ROUND 2 (re-gate MAJ-4): the photo branch now carries the SAME ratio
   register as the placecard branch. Round 1 put aspect-ratio on the
   placecard only, so the placecard-to-photo swap changed the box shape --
   exactly the reflow sec4.7 exists to prevent. Below 900 both branches are
   free-height; from 900 both are 4/3, and the photo is cover-cropped into
   it (PHOTO_SLOTS_T64.md: HERO-01 is "shot 3:2 with safe margin" precisely
   so a 4:3 crop is safe). */
.fj-hero__photo {
  width: 100%;
  border-radius: var(--radius-3);
}
@media (min-width: 900px) {
  .fj-hero__photo {
    aspect-ratio: 4 / 3;
    object-fit: cover;
  }
}

/* -------------------------------------------------------------------------
   4. BAND 2 -- TRUST / DELIVERY -- Device D2 TYPE STATEMENT
   ------------------------------------------------------------------------- */
.fj-trust__type { max-width: 64ch; }
.fj-trust__photo {
  margin-top: var(--space-6);
  border-radius: var(--radius-2);
}

/* -------------------------------------------------------------------------
   5. BAND 3 -- PRODUCT ROW (Option B, ruled #177-D item 7) -- Device D3
   Finding m9: the SCROLLER is the keyboard-reachable named region, so the
   <ul> keeps its list semantics (and now an explicit role="list", MAJ-9).
   ------------------------------------------------------------------------- */
.fj-product-row__scroller {
  overflow-x: auto;
  scroll-snap-type: x proximity;
  padding-bottom: var(--space-2);
}
.fj-product-row {
  display: flex;
  gap: var(--space-5);
}
.fj-product-row__item {
  flex: 0 0 220px;
  scroll-snap-align: start;
}
@media (min-width: 900px) {
  .fj-product-row__scroller {
    overflow: visible;
    padding-bottom: 0;
  }
  /* FIX ROUND 2 (re-gate MAJ-2): auto-fit, not the count-derived --fj-cols.
     220px is the product card's unit width (the same figure the mobile
     scroller uses as its flex-basis). repeat(var(--fj-cols), minmax(220px,1fr))
     would still SQUEEZE: six count-derived tracks at 220px minimum overflow a
     1240px container (6*220 + 5*20 gap = 1420px), and with minmax(0,1fr) they
     silently shrank below the unit instead. auto-fit derives the track count
     from the REAL available width, so cards wrap to a second row rather than
     compressing, and the 220px floor is never breached.
     The original M3 concern is unaffected: auto-fit COLLAPSES tracks that end
     up with no items in them, so a short row of 3 still stretches to fill the
     band with no dead columns -- exactly what --fj-cols was there to prevent.
     Consequence, stated: --fj-cols is no longer read by anything, and the
     template no longer emits it. */
  .fj-product-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  }
  .fj-product-row__item { flex: initial; min-width: 0; }
}
/* Finding M4 / FIX ROUND 2 (re-gate MAJ-3): sec4.4's resting card is
   "Paper surface . 1px --line . --radius-2 . --elev-1 at rest", and its hover
   is "--elev-2 CROSS-FADED over --dur-1, translateY(-2px), border -> Navy".
   Round 1 read "no box-shadow transition" (sec3.3's paint budget) as licence
   to drop the cross-fade entirely and snap the elevation. Both rules can be
   kept at once, and now are: a PSEUDO-ELEMENT carries the --elev-2 shadow and
   its OPACITY cross-fades 0 -> 1 over --dur-1. box-shadow itself is still on
   no transition list anywhere in this file; opacity is one of the two
   properties sec3.3 permits. The card keeps its own transform and
   border-color transitions. */
.fj-product-row__link {
  position: relative;
  display: block;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  box-shadow: var(--elev-1);
  padding: var(--space-4);
  transition: transform var(--dur-1) var(--ease-out),
              border-color var(--dur-1) var(--ease-out);
}
.fj-product-row__link::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: var(--elev-2);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-1) var(--ease-out);
}
.fj-product-row__link:hover::after,
.fj-product-row__link:focus-visible::after {
  opacity: 1;
}
.fj-product-row__link:hover {
  transform: translateY(-2px);
  border-color: var(--navy); /* sec4.4: gold hover border withdrawn, 2.89:1 */
}
.fj-product-row__image {
  display: block;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  margin-bottom: var(--space-3);
}
.fj-product-row__image img { width: 100%; height: 100%; object-fit: contain; }

/* -------------------------------------------------------------------------
   6. BAND 4 -- CUSTOM PACKAGING -- Device D6 DOMINANT PANEL + subordinate
   D5 ORDINAL LADDER. FIX ROUND 2 (re-gate BLOCKER-4): round 1's re-label to
   D1 SPLIT is REVERTED on the #179 coordinator ruling -- D6 is what sec5.4
   and PHOTO_SLOTS_T64.md's CUSTOM-01 entry both already say. The 55fr/45fr
   grid below is UNCHANGED by the revert; the 55% is PHOTO_SLOTS_T64.md's own
   ">=55% optical weight per sec5.4's D6 dominant-panel spec".
   M9 tap-to-turn cup NOT built this sitting -- sec7 item 5 unsigned.
   ------------------------------------------------------------------------- */
/* Finding M11: Gold 1px hairline ABOVE the band, and nowhere else in the
   section (system sec5.4, verbatim). Non-state decoration, so gold is
   correct here where it is not on a hover border. */
.fj-band--custom {
  border-top: 1px solid var(--gold);
}
.fj-custom {
  display: grid;
  gap: var(--space-6);
}
@media (min-width: 900px) {
  .fj-custom {
    grid-template-columns: 55fr 45fr; /* panel carries >=55% optical weight */
    align-items: center;
  }
}
.fj-custom__steps {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  margin: var(--space-5) 0 var(--space-6);
  /* Finding m4: M4 Fold rotates on X, which is invisible without a
     perspective on the parent. Transform + opacity only -- no new
     animatable property is introduced by this. */
  perspective: 600px;
}
.fj-custom__step {
  display: flex;
  gap: var(--space-4);
  align-items: flex-start;
  /* no bounding box, no card, no hairline -- subordinate ladder, sec5.4 */
}
.fj-custom__step-text {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

/* -------------------------------------------------------------------------
   7. BAND 5 -- "Things we sorted out so you don't have to" -- Device D4
   STACKED PAIRS. No separating hairline between pairs (system sec2.1a).
   ------------------------------------------------------------------------- */
.fj-faq {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  max-width: 64ch;
}
.fj-faq__pair {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* -------------------------------------------------------------------------
   8. BUTTONS (system sec4.1/4.2) -- min 48px, tap-target safe.
   Finding M4: box-shadow is off every transition list here too.
   ------------------------------------------------------------------------- */
.fj-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;      /* sec4.1 metric, stated as a literal in the spec */
  padding: 14px 24px;    /* sec4.1 metric, as above */
  border-radius: var(--radius-2);
  font-weight: 600;
  font-size: var(--text-base);
  border: none;
  cursor: pointer;
  transition: transform var(--dur-1) var(--ease-out),
              background-color var(--dur-1) var(--ease-out),
              border-color var(--dur-1) var(--ease-out);
}
.fj-btn--primary {
  background: var(--navy);
  color: var(--white);
}
.fj-btn--primary:hover {
  background: var(--royal);
  transform: translateY(-1px);
  box-shadow: var(--elev-2);
}
.fj-btn--primary:active {
  background: var(--navy);
  transform: translateY(0);
  box-shadow: inset 0 2px 4px rgba(0,0,0,.18); /* T54 sec5 item 5 */
}
.fj-btn--secondary {
  background: transparent;
  color: var(--navy);
  border: 1px solid var(--navy);
}
/* FIX ROUND 2 (re-gate MIN-7): sec4.2's "Navy fill at 6%" is expressed as a
   color-mix against the Navy TOKEN, not as a hand-copied rgba() of the Navy
   hex. The literal rgba(22,32,63,.06) silently forked the palette: if --navy
   is ever re-registered, the hover wash would keep the old colour. color-mix
   is a modern-browser-only feature (no IE, no pre-2023 Safari/Firefox); that
   is accepted on this project's stated baseline, and the failure mode is
   benign -- an unsupported browser drops the declaration and the secondary
   button simply keeps its transparent rest fill on hover, with the 1px Navy
   border and the lift still carrying the state. */
.fj-btn--secondary:hover {
  background: color-mix(in srgb, var(--navy) 6%, transparent); /* sec4.2 */
  transform: translateY(-1px);
}
.fj-btn--secondary:active {
  transform: translateY(0);
  box-shadow: inset 0 2px 4px rgba(0,0,0,.12);
}

/* Finding B4 / #179 ruling R1: the primary CTA on a Navy band is GOLD fill
   with a NAVY label -- computed 5.11:1 per DECISION_LOG #179 R1 (figure
   corrected fix round 3 / MI-1). Hover lightens to the ONE sanctioned lighter
   gold (--gold-l), which computes 7.79:1 against the Navy label, so the
   hover state gains contrast instead of spending it; active returns to
   --gold and marks state with an inset shadow, never a lighter wash
   (T54 sec5 item 5). A fill change is used rather than lift-only so the
   state survives reduced motion, where the translate is removed. */
.fj-band--dark .fj-btn--primary {
  background: var(--gold);
  color: var(--navy);
}
.fj-band--dark .fj-btn--primary:hover {
  background: var(--gold-l);
  transform: translateY(-1px);
  box-shadow: var(--elev-2);
}
.fj-band--dark .fj-btn--primary:active {
  background: var(--gold);
  transform: translateY(0);
  box-shadow: inset 0 2px 4px rgba(0,0,0,.18);
}

/* -------------------------------------------------------------------------
   9. FOCUS -- 2px solid Royal, instant, never animated (T54 sec3 24/08;
   system sec7 item 13, supersedes --ring #767E8C).
   Finding B3 / #179 ruling R1: on a dark band the ring is 2px #FFFFFF at
   the same 2px offset -- Royal on Navy measures 1.99:1 and would be an
   invisible focus indicator. Royal stays the ring everywhere else.
   ------------------------------------------------------------------------- */
.fj-main a:focus-visible,
.fj-main button:focus-visible,
.fj-btn:focus-visible,
.fj-product-row__link:focus-visible,
.fj-product-row__scroller:focus-visible {
  outline: 2px solid var(--royal);
  outline-offset: 2px;
  transition: none;
}
.fj-main .fj-band--dark a:focus-visible,
.fj-main .fj-band--dark button:focus-visible,
.fj-main .fj-band--dark .fj-btn:focus-visible {
  outline: 2px solid var(--white);
  outline-offset: 2px;
}

/* -------------------------------------------------------------------------
   10. PLACECARDS -- #151 pattern (system sec4.7). Zero image bytes.
   Navy panel, 1px Gold inset hairline at 12px, radius-3 standalone.
   Never animate (system sec5.5).
   ------------------------------------------------------------------------- */
.fj-placecard {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--navy);
  border-radius: var(--radius-3);
  min-height: 220px;
  padding: var(--space-6);
  text-align: center;
}
.fj-placecard::before {
  content: "";
  position: absolute;
  inset: 12px; /* sec4.7 metric, stated as a literal in the spec */
  border: 1px solid var(--gold);
  border-radius: calc(var(--radius-3) - 6px);
  pointer-events: none;
}
.fj-placecard__label {
  position: relative;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--text-xs); /* finding m1 -- the registered name is --text-xs */
  line-height: 1.3;          /* FIX ROUND 2 / MIN-4: sec1.3 Micro-label */
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--white);
}
/* HERO-01 ratio register. FIX ROUND 2 (re-gate MAJ-4) -- rebuilt against
   control/PHOTO_SLOTS_T64.md, which gives HERO-01 exactly TWO render states:
   "the slot crops to 4:3 (desktop) and free-height (mobile)". Desktop for
   this slot is the register the same file names for it -- "right panel of
   the split-screen (desktop 900px+)".

   So: below 900 it is genuinely FREE HEIGHT -- no aspect-ratio and no
   min-height floor, so the box is only as tall as its own label and padding.
   Round 1 re-imposed the 220px placecard floor from 391 up, which is not
   free height, and invented a 3:2 step at 768 by reading the SHOOT ratio
   ("shot 3:2 with safe margin") as a render step. Both are gone. */
.fj-placecard--hero { min-height: 0; }
@media (min-width: 900px) {
  .fj-placecard--hero { aspect-ratio: 4 / 3; }
}
.fj-placecard--custom { aspect-ratio: 1 / 1; } /* CUSTOM-01, square per PHOTO_SLOTS_T64 24/08 */

/* -------------------------------------------------------------------------
   11. OWED-COPY MARKER -- internal build-only label, NEVER shipped as real
   content. Extends the placecard honesty pattern (sec4.7/5.5) to text
   slots with no approved copy source. Uses the interface-state --err
   colour deliberately (it must read as "cannot ship"), never a brand
   surface colour, per system sec2.2's interface-state rule.
   ------------------------------------------------------------------------- */
.fj-owed-copy {
  display: inline-block;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 600;
  line-height: 1.3; /* FIX ROUND 2 / MIN-4: sec1.3 Micro-label */
  color: var(--err);
  border: 1px dashed var(--err);
  border-radius: var(--radius-1);
  padding: 2px 6px;
}
/* Finding M7: on a dark band the marker inverts -- white text on an --err
   FILL (7.40:1), never bare --err ink on Navy, which is unreadable and
   would quietly turn a "cannot ship" flag into an invisible one. The fill
   is an interface state on an interface element, not a brand surface. */
.fj-band--dark .fj-owed-copy {
  color: var(--white);
  background: var(--err);
  border-color: var(--white);
}

/* -------------------------------------------------------------------------
   12. MOTION VOCABULARY -- M1 Rise, M2 Settle, M3 Nest, M4 Fold
   (system sec3.3). transform + opacity only. Architectural rule: resting
   state (no html.fj-motion class) is ALWAYS the final composed state --
   the offset only exists once JS confirms motion is allowed (sec3.7).
   THE <=4-CONCURRENT CAP (sec3.2) -- FIX ROUND 2, re-gate MAJ-6.
   Round 1 held the cap by SILENCING units: band 3 items 5-6 and band 5 pairs
   4-5 carried no data-fj-anim at all. That contradicted sec4.4/sec5.6, which
   animate all six product cards and all five pairs. Both bands animate every
   unit again, and the cap is now held by DELAY GROUPING.

   Why grouping, and not simply a stagger: the ratified token values make a
   flat stagger impossible to cap. "Item i ends before item i+4 starts" needs
   --stagger-tight >= duration / 4. On disk (system sec3.2):
       --stagger-tight = 40ms
       --dur-3 = 240ms  ->  needs 60ms   (40 < 60,  fails)
       --dur-5 = 480ms  ->  needs 120ms  (40 < 120, fails badly)
   At 40ms per step a 480ms M3 Nest puts ALL SIX cards in flight at once
   (floor(480/40)+1 = 13 slots, far more than the six that exist). So the
   delay is composed of two parts instead: --i staggers WITHIN a group by
   --stagger-tight, and --g pushes each group past the end of the one before.

   M3 Nest, groups of 4 (template emits --i 0-3, --g 0-1):
     group gap = --dur-5 + 3 * --stagger-tight = 480 + 120 = 600ms
     delays  0 / 40 / 80 / 120 | 600 / 640
     spans   0-480, 40-520, 80-560, 120-600 | 600-1080, 640-1120
     peak concurrency 4, at t in [120,480). Item 3 ENDS at exactly t=600, the
     instant item 4 begins, so the two never overlap and 4 is never exceeded.

   M2 Settle, groups of 3 (template emits --i 0-2, --g 0-1) -- three, not
   four, because the band's own M1 Rise heading occupies one of the four slots:
     group gap = --dur-4 = 320ms  (which is also 2 * --stagger-tight + --dur-3
                 = 80 + 240 = 320, so both derivations agree on the value)
     heading 0-320 | pairs 0-240, 40-280, 80-320 | 320-560, 360-600
     peak concurrency 4, at t in [80,240). Heading and pair 3 both end at
     t=320, the instant pair 4 begins.

   M4 Fold is unchanged: 3 steps, --stagger 60ms, --dur-4 320ms, spans
   0-320 / 60-380 / 120-440, peak 3. It uses the generic delay rule below.

   Known limitation, unchanged from round 1 and outside this delta: the cap is
   per-band. On a tall desktop viewport two bands can enter view together, and
   nothing in CSS or JS serialises them.
   ------------------------------------------------------------------------- */
[data-fj-anim] {
  opacity: 1;
  transform: none;
}

/* FIX ROUND 2 (re-gate MIN-1): no var() fallbacks. Every consumer of --i and
   --g sets both inline on the element, so a fallback could only ever mask a
   template bug by silently animating everything on delay 0. */
html.fj-motion [data-fj-anim] {
  transition-delay: calc(var(--i) * var(--stagger));
}

/* M1 Rise -- section headers, copy blocks (--dur-4 / --ease-out).
   FIX ROUND 2 (re-gate MIN-2): written as LONGHANDS, matching M2/M3/M4. The
   `transition:` shorthand resets transition-delay to 0s, so it was wiping the
   generic delay rule above -- M1 could never stagger. Nothing else changed. */
html.fj-motion [data-fj-anim="rise"] {
  transition-property: transform, opacity;
  transition-duration: var(--dur-4);
  transition-timing-function: var(--ease-out);
}
html.fj-motion [data-fj-anim="rise"]:not(.fj-play) { opacity: 0; transform: translateY(12px); }
html.fj-motion [data-fj-anim="rise"].fj-play { opacity: 1; transform: none; }

/* M2 Settle -- stacked pairs, stagger-tight (--dur-3 / --ease-settle).
   Grouped delay, groups of 3 -- see the arithmetic in this section's header. */
html.fj-motion [data-fj-anim="settle"] {
  transition-delay: calc( (var(--i) * var(--stagger-tight)) + (var(--g) * var(--dur-4)) );
  transition-property: transform, opacity;
  transition-duration: var(--dur-3);
  transition-timing-function: var(--ease-settle);
}
html.fj-motion [data-fj-anim="settle"]:not(.fj-play) { opacity: 0; transform: translateY(8px); }
html.fj-motion [data-fj-anim="settle"].fj-play { opacity: 1; transform: none; }

/* M3 Nest -- the signature, once per page, cap 4 (--dur-5 / --ease-settle).
   Grouped delay, groups of 4 -- see the arithmetic in this section's header.
   Deviation recorded: sec3.3's M3 row specifies `--stagger` (60ms). The
   re-gate delta directs --stagger-tight for both bands 3 and 5, which is what
   ships; --stagger would need a 720ms group gap for the same cap. */
/* FIX ROUND 4 (re-gate 3 D-1) -- COORDINATOR RULING, recorded as deviation 8:
   M3 Nest applies at >=900px ONLY, where the grid enters as one unit and the
   grouped-delay arithmetic provably holds the sec3.2 cap at 4. Below 900px
   the row is a horizontal scroller whose entry timing is scroll-velocity-
   driven: round 2 held the cap but blanked cards for 600ms (MA-5); round 3
   fixed the blanking but let a fast fling put 5-6 in flight (D-1). No delay
   scheme can hold a hard cap against user-controlled entry timing, so below
   900px band 3 renders COMPOSED -- no hidden state, no transition, nothing
   ever blank, cap trivially satisfied. The signature still fires once per
   page on every viewport where the full row enters together. */
@media (min-width: 900px) {
  html.fj-motion [data-fj-anim="nest"] {
    transition-delay: calc( (var(--i) * var(--stagger-tight)) + (var(--g) * (var(--dur-5) + (3 * var(--stagger-tight)))) );
    transition-property: transform, opacity;
    transition-duration: var(--dur-5);
    transition-timing-function: var(--ease-settle);
  }
  html.fj-motion [data-fj-anim="nest"]:not(.fj-play) {
    opacity: 0;
    transform: translateY(10px) scale(1.06);
  }
  html.fj-motion [data-fj-anim="nest"].fj-play { opacity: 1; transform: none; }
}

/* M4 Fold -- custom-packaging steps, cap 3 (--dur-4 / --ease-seat) */
html.fj-motion [data-fj-anim="fold"] {
  transition-property: transform, opacity;
  transition-duration: var(--dur-4);
  transition-timing-function: var(--ease-seat);
  transform-origin: top;
}
html.fj-motion [data-fj-anim="fold"]:not(.fj-play) {
  opacity: 0;
  transform: rotateX(-8deg);
}
html.fj-motion [data-fj-anim="fold"].fj-play { opacity: 1; transform: none; }

/* -------------------------------------------------------------------------
   13. PREFERS-REDUCED-MOTION -- mandatory, system sec3.7. Per-motion rules
   are the implementation; the blanket killer below is a BACKSTOP only.
   fj-t64-home.js never adds html.fj-motion when reduce is true, so in the
   normal case these selectors do not even match -- this block is defence
   in depth for any element the JS gate missed.
   ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html.fj-motion [data-fj-anim] {
    transition: none !important;
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
  .fj-btn,
  .fj-product-row__link,
  /* FIX ROUND 2 (MAJ-3): sec3.7's M6 row says "--elev-2 still applies on
     hover, applied INSTANTLY (no shadow cross-fade)". The elevation
     pseudo-element therefore still reaches opacity 1 under reduced motion,
     but with no fade time. */
  .fj-product-row__link::after {
    transition-duration: .01ms !important;
  }
  .fj-btn:hover,
  .fj-product-row__link:hover {
    transform: none !important; /* M6: hover lift removed under reduced motion */
  }
}

/* T54's blanket killer -- backstop only, scoped to this template's tree so
   it cannot regress anything outside it before the coordinator merges a
   site-wide equivalent into style.css. */
@media (prefers-reduced-motion: reduce) {
  .fj-main *, .fj-main *::before, .fj-main *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Placecards and owed-copy markers never animate, in either experience
   (system sec5.5). */
.fj-placecard,
.fj-placecard *,
.fj-owed-copy {
  animation: none !important;
  transition: none !important;
}
