@layer layout {
  /* ---- Container ---- */
  .fh-shell {
    width: 100%;
    max-width: var(--l-container);
    margin-inline: auto;
    padding-inline: var(--l-gutter);
  }

  .fh-shell--narrow {
    max-width: var(--l-container-narrow);
  }

  /* ---- Plate: a chart sheet. Every major section is one plate, separated by
          a neatline rather than a colour change, because a chart is one
          continuous surface. ---- */
  .fh-plate {
    position: relative;
    padding-block: var(--l-plate-y);
    border-top: var(--l-hairline) solid var(--l-neatline);
  }

  .fh-plate--first {
    border-top: 0;
    padding-block-start: clamp(2rem, 5vw, 3.5rem);
  }

  .fh-plate--flush {
    padding-block-end: 0;
  }

  /* Graduation ticks along a plate's neatline: the chart's latitude marks.
     Decorative but structural — it is the border, not an added ornament. */
  .fh-plate--graduated::before {
    content: "";
    position: absolute;
    inset-block-start: 0;
    inset-inline: 0;
    height: 6px;
    background-image: repeating-linear-gradient(
      to right,
      var(--l-neatline) 0 var(--l-hairline),
      transparent var(--l-hairline) 32px
    );
    pointer-events: none;
  }

  /* ---- Grids. CSS Grid, because these are content relationships, not a
          12-column contract. The Bootstrap grid is not reimplemented here;
          this layout owns its own structure. ---- */
  .fh-cols {
    display: grid;
    gap: var(--l-space-12) var(--l-space-14);
  }

  .fh-cols--split {
    grid-template-columns: minmax(0, 1fr);
  }

  .fh-cols--halves {
    grid-template-columns: minmax(0, 1fr);
  }

  .fh-cols--2 {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  }

  .fh-cols--3 {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  }

  /* ---- THE LOGO WALL: 1 / 2 / 4, EXPLICIT, NEVER `auto-fit`. ----

     Restores the incumbent's 4-up integration wall (`col-md-6 col-lg-3`), which
     the migration had collapsed into `.fh-cols--2`. At the 1220px shell that
     resolved to THREE columns, so eight logos ran 3 + 3 + 2 and the wall ended
     on a ragged row.

     Explicit counts, because The Empty Cell Rule is avoided by construction here
     rather than mitigated. `auto-fit` with a 13rem minimum would resolve to FIVE
     columns at 1220px (5x208 + 4x12 = 1088 <= 1220), and eight items over five
     is 5 + 3 -- a partial row at exactly the width the page is designed for.
     Eight over 1, 2 or 4 is always a whole number of full rows.

     Breakpoints match the incumbent's: full width, 2-up at md, 4-up at lg. 64rem
     rather than 62rem for the 4-up, measured: at 62rem the card's content box is
     ~179px and the Sumo Logic lockup row (55px icon + 0.75rem gap + "Sumo Logic"
     at --l-fs-d3) needs ~177px, which is inside the box but with 2px to spare.
     64rem gives it ~188px and real slack. */
  .fh-cols--wall,
  .fh-cols--quad {
    grid-template-columns: minmax(0, 1fr);
    /* The base `.fh-cols` rhythm is 3rem/3.5rem, which is a SECTION gap, not a
       gap between cards in a wall. The incumbent's partner grid ran ~1rem. */
    gap: 1rem;
  }

  /* ---- A PAIR OF MACHINE-OUTPUT BLOCKS THAT MUST NOT BE SQUEEZED. ----

     For two terminal/code blocks side by side. `.fh-code` is `overflow-x: auto`
     by the data block's contract -- machine output scrolls rather than soft-wraps,
     because a wrapped command line lies about where the line ends. That contract
     is right, and it makes COLUMN WIDTH the thing that decides whether a reader
     has to scroll to finish reading a command.

     Measured on /integrations/ with the real webfonts: the longest line is
     `  "https://fullhunt.io/api/v1/domain/example.com/subdomains" \` at 562px.
     Two-up needs ~1204px of shell to clear that, so it is gated at 82rem, where
     the shell has reached its 1220px cap:
       >=82rem  2-up, column 604px -> 572px of code box, 10px clear
       < 82rem  1-up, full shell   -> clears down to a ~700px viewport
     `.fh-cols--halves` was the obvious reuse and is WRONG here: it goes two-up at
     62rem, where the column is ~428px and the command clips by 134px.

     Below ~700px the block scrolls internally, which is the documented behaviour
     and the right answer on a phone. Do not lower the breakpoint without
     re-measuring the longest line. */
  .fh-cols--pair {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.75rem;
  }

  @media (min-width: 82rem) {
    .fh-cols--pair {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
  }

  /* The logo wall is tighter still: the incumbent put `p-1` on every column, so
     8px of gutter. Only the gap differs, so the structure is shared above rather
     than declared twice -- two near-identical grid classes is exactly the drift
     TASK-484 exists to collect. */
  .fh-cols--wall {
    gap: 0.625rem;
  }

  @media (min-width: 40rem) {
    .fh-cols--wall,
    .fh-cols--quad {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
  }

  @media (min-width: 64rem) {
    .fh-cols--wall,
    .fh-cols--quad {
      grid-template-columns: repeat(4, minmax(0, 1fr));
    }
  }

  .fh-cols--tight {
    gap: 1px;
  }

  .fh-stack {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 1.25rem;
    min-width: 0;
  }

  .fh-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
  }

  .fh-head {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1rem;
    margin-block-end: var(--l-space-12);
    max-width: 46rem;
  }

  @media (min-width: 62rem) {
    .fh-cols--split {
      grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
      align-items: center;
    }

    /* ---- The zig-zag. Six pages (products/{asm,enterprise_asm},
       solutions/{enterprises,mssps,national_cert,security_vendors}) alternate
       image-left / image-right down the page with Bootstrap's
       `.order-lg-1` / `.order-lg-2`, and `.fh-cols--split` had no reverse
       modifier -- so three page tasks across CP3 and CP4 would each have
       invented one. Authored once here.

       Placement is by `grid-column`, not `order` and not `direction: rtl`:
         - `order` on a grid item works, but `direction: rtl` would also flip
           punctuation and any inline progression inside the cells, which is a
           text bug dressed up as a layout trick;
         - explicit columns keep the DOM in READING order. Write the text cell
           first in the markup on every one of the six sections, reversed or
           not, and the tab order, the screen-reader order and the narrow
           single-column stack all stay consistent down the page while only
           the wide-viewport painting alternates. Never reverse in the markup
           to get the visual you want.
       The ratio mirrors too, so the text column keeps the wider 1.05fr track
       whichever side it is painted on.

       It is a MODIFIER, not a replacement -- it only exists inside this media
       query, so the narrow single-column stack still comes from --split:
         class="fh-cols fh-cols--split fh-cols--split-reverse"
       Both are needed. --split-reverse alone has no rules under 62rem. ---- */
    .fh-cols--split-reverse {
      grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
    }

    /* `grid-row: 1` IS LOAD-BEARING, on both. Without it this modifier put
       every one of its twelve call sites into TWO rows instead of one.

       Auto-placement is sparse by default and never moves the cursor
       backwards. The text cell is first in source and takes column 2, which
       leaves the cursor past column 1; the figure then asks for column 1,
       cannot be placed behind the cursor, and starts a new row. The result
       is a full-width text block with the figure stranded underneath it --
       on all 12 grids across 7 pages, measured.

       No gate caught it and none could have: two rows overflow nothing,
       violate no axe rule, lose no copy and change no motion count, so the
       page reports clean while the layout it was written for never
       rendered. Pinning the row is the fix rather than `grid-auto-flow:
       dense`, which would also license re-ordering any later item into a
       hole and makes placement depend on child count. */
    .fh-cols--split-reverse > :first-child {
      grid-column: 2;
      grid-row: 1;
    }

    .fh-cols--split-reverse > :nth-child(2) {
      grid-column: 1;
      grid-row: 1;
    }

    .fh-cols--halves {
      grid-template-columns: repeat(2, minmax(0, 1fr));
      align-items: stretch;
    }
  }
}
