/*
 * Section Styles
 *
 * Page layout, section containers, and theme variants.
 * Sections are the main structural containers for page content.
 *
 * Section themes override button tokens so buttons automatically
 * adapt to their background context.
 */

/* ============================================
   BASE SECTION
   ============================================ */
main > .section {
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
  padding: var(--space-2xl) 0;
  overflow-x: clip; /* Prevent animation transforms from causing horizontal scroll */
}

main > .section > div {
  width: 100%;
  max-width: var(--container-max-width);
  margin-inline: auto;
  padding-inline: var(--container-padding);
  box-sizing: border-box;
}

main > .section:first-of-type {
  padding-block: 0;
}

main > .section:nth-of-type(2) {
  padding-top: 0;
}


/* ============================================
   ARTICLE PAGES (PROTO-749)

   Pages whose Template includes `article` (body.article), once utils/article.js has built the
   hero (main[data-article="hero"]). Every wrapper outside the hero, default content and blocks
   alike, takes the body width and is centered; the hero keeps the container width. A section or
   block that sets its own wrapper width keeps it (banner, full-width logos, sides, the hero
   blocks): the :where() holds this rule at 0,2,1, above the default `main > .section > div` and
   below those resets. The width leaves room for the share pane's gutter (PROTO-750), so the
   column is the same with or without it. Here and not in a stylesheet of its own, so first paint never waits for an extra request.
   ============================================ */
body.article {
  --article-gutter: 320px;
  --article-gutter-gap: var(--space-2xl);
  --article-body-width: calc(var(--container-max-width) - var(--article-gutter) - var(--article-gutter-gap));
}

:where(body.article main[data-article="hero"]) > .section > div:not(.article-hero-wrapper) {
  max-width: var(--article-body-width);
}


/* ============================================
   ALIGNMENT AXIS — three scopes, narrowest wins

     global   this block, on unclassed `body`
     page     `body.align-*`, styles/utilities.css, from page Metadata Style
     section  `main .section.align-*`, below, from Section Metadata Style

   Reaches section intro copy and nothing else — `main > .section > .default-content-wrapper`,
   below. Blocks set their own alignment. Fragment copy is reached too: the fragment block puts a
   fragment's sections directly under main. One deliberate opt-out: a form-tabbing panel hard-
   centers its copy to match the form beneath it (further down this file).

   THE DEFAULT MUST STAY ON `body`. It looks like it belongs on `main > .section` with every
   other section default — do not move it there. The page scope declares on `body`, so a default
   on the section would sit BELOW it in the tree, the page value would never inherit past it,
   and the page scope would die silently with no specificity change to notice in review. Moving
   it fails four browser checks.

   Values are logical (`start`, and `margin-inline` at the consumer) so text direction and box
   placement cannot disagree. Every locale this site serves is left-to-right.
   ============================================ */
body {
  --section-align: center;

  /* Where a narrow (75%) paragraph box sits in the column: `auto` centers it, `0 auto` pushes
     it to the start edge. Read by large-paragraph below. Always set alongside --section-align;
     setting one without the other leaves the text going one way and the box the other. */
  --section-measure-margin: auto;
}

main .section.align-left {
  --section-align: start;
  --section-measure-margin: 0 auto;
}

main .section.align-center {
  --section-align: center;
  --section-measure-margin: auto;
}

/* Section intro - centered by default per Figma, unless a scope above says otherwise */
main > .section > .default-content-wrapper,
main > .section.structured-headings > :is(.sides-top, .side) > .default-content-wrapper {
  text-align: var(--section-align);
}

/* Remove top margin from first element in intro */
main > .section > .default-content-wrapper > :first-child,
main > .section.structured-headings > :is(.sides-top, .side) > .default-content-wrapper > :first-child {
  margin-top: 0;
}

/* Remove bottom margin from last element - wrapper handles spacing */
main > .section > .default-content-wrapper > :last-child,
main > .section.structured-headings > :is(.sides-top, .side) > .default-content-wrapper > :last-child {
  margin-bottom: 0;
}

/* Compact variant - tighter gap between section children */
main > .section.compact {
  gap: var(--space-m);
}

/* Images in default wrapper should have vertical breathing room */
main > .section > .default-content-wrapper > p > picture > img,
main > .section.structured-headings > :is(.sides-top, .side) > .default-content-wrapper > p > picture > img {
  padding-block: var(--space-l);
}

/* Article pages (PROTO-749): a picture in the body is centered in the body column. After the
   rule above, so the specificity order stylelint checks holds; the rest of the article rules are
   under ARTICLE PAGES near the top of this file. */
body.article main[data-article="hero"] > .section > .default-content-wrapper > p > picture > img {
  display: block;
  margin-inline: auto;
}

@media (width >= 900px) {
  main > .section {
    gap: var(--space-2xl);
    padding: var(--space-4xl) 0;
  }

  main > .section > div {
    padding: 0 var(--container-padding);
  }

}

/* ============================================
   SECTION METADATA VARIANTS
   Applied via section-metadata block in AEM
   ============================================ */

/* Light/Highlight background */
main .section.light,
main .section.highlight,
main .section.theme-light {
  background-color: var(--light-color);
}

/* `centered` retired in favour of `align-center`, which sets the axis and nothing else. The old
   rule declared text-align on the SECTION, so it also inherited into blocks that set no alignment
   of their own. The standalone `align-left` rule went too — the axis covers it. */

main .section.full-width > .logos-wrapper {
  max-width: unset; 
  padding: unset;
}

/* The second selector is the heading row of a `sides, structured-headings` section, the same copy
   one level deeper. `:where()` keeps its specificity equal to the first selector's, so the two can
   share these rules without breaking stylelint no-descending-specificity. */
main > .section.large-paragraph > .default-content-wrapper:first-child > p,
main > .section.large-paragraph > :where(.sides-top:first-child) > .default-content-wrapper:first-child > p {
  font-size: 20px;
  line-height: normal;
  color: var(--digicert-neutral-700);
}

/* large-paragraph is typography and measure only. It used to force the text and the box back
   to centered here, declaring `text-align` directly ON the <p> — and an element's own
   declaration beats an inherited value regardless of specificity, so no alignment scope could
   reach it. That is why `Style: large-paragraph, align-left` read left below 900px and centered
   above it. The text now inherits like everything else, and the narrow box follows the axis.
   This is the first half of PROTO-582.

   The 24px here is the ONLY rule delivering it at desktop — an identical selector earlier in
   the file was dead, overridden by the 20px rule above on source order, and was removed. */
@media (width >= 900px) {
  main > .section.large-paragraph > .default-content-wrapper:first-child > p:not(.button-container),
  main > .section.large-paragraph > :where(.sides-top:first-child) > .default-content-wrapper:first-child > p:not(.button-container) {
    font-size: var(--body-font-size-l);
    width: 75%;
    margin-inline: var(--section-measure-margin);
  }
}


/* ============================================
   SECTION THEMES
   Synced with Figma backgrounds
   ============================================ */

/* Primary blue theme */
main .section.theme-primary {
  background-color: var(--digicert-blue);
  color: var(--digicert-white);

  /* Override button tokens for this theme */
  --btn-primary-bg: var(--btn-primary-bg-light);
  --btn-primary-fg: var(--btn-primary-fg-light);
  --btn-primary-bg-hover: var(--digicert-neutral-100);
  --btn-text-fg: var(--digicert-white);
  --link-color: var(--digicert-white);
}

/* Secondary dark blue theme */
main .section.theme-secondary {
  background-color: var(--digicert-dark-blue);
  color: var(--digicert-white);

  /* Override button tokens for this theme */
  --btn-primary-bg: var(--digicert-teal);
  --btn-primary-fg: var(--digicert-dark-blue);
  --btn-text-fg: var(--digicert-teal);
  --link-color: var(--digicert-teal);
}

/* Gradient theme (CTA banners) */
main .section.theme-gradient {
  background: var(--gradient-primary);
  color: var(--digicert-white);

  /* Override button tokens for this theme */
  --btn-primary-bg: var(--btn-primary-bg-light);
  --btn-primary-fg: var(--btn-primary-fg-light);
  --btn-primary-bg-hover: var(--digicert-neutral-100);
  --btn-text-fg: var(--digicert-white);
  --link-color: var(--digicert-white);
}

/* Dark theme */
main .section.theme-dark {
  background-color: var(--digicert-ink);
  color: var(--digicert-white);

  /* Override button tokens for this theme */
  --btn-primary-bg: var(--digicert-white);
  --btn-primary-fg: var(--digicert-ink);
  --btn-text-fg: var(--digicert-white);
  --link-color: var(--digicert-teal);
}

/* Headings on dark/gradient sections need to inherit, not use the default near-black */
main .section.theme-dark :is(h1, h2, h3, h4, h5, h6),
main .section.theme-gradient :is(h1, h2, h3, h4, h5, h6) {
  color: inherit;
}

/* ============================================
   SECTION BACKGROUND IMAGE
   Applied via section-metadata 'image' field
   ============================================ */
main .section.bg-image {
  position: relative;
  background-image: var(--background-image);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* ============================================
   TABBED SECTIONS
   Section-level tabs for grouping blocks
   Grid stacking prevents layout shift when switching tabs
   ============================================ */
main .section.tabs-container .tabs {
  display: grid;
  grid-template-rows: auto 1fr;

  .tabs-list {
    grid-row: 1;
    display: flex;
    justify-content: center;
    gap: var(--space-s);
    max-width: 100%;
    font-size: var(--body-font-size-s);
    overflow-x: auto;
    margin-bottom: var(--space-l);
    padding-bottom: 0;
  }

  @media (width >= 600px) {
    .tabs-list {
      gap: var(--space-4xl);
      font-size: var(--body-font-size-m);
    }
  }

  @media (width >= 900px) {
    .tabs-list {
      gap: var(--space-5xl);
      font-size: var(--body-font-size-l);
    }
  }

  .tabs-list button {
    flex: 0 0 max-content;
    margin: 0;
    border: none;
    border-radius: 0;
    padding: var(--space-s) var(--space-m) var(--space-xs) var(--space-m);
    background-color: transparent;
    color: var(--digicert-neutral-500);
    font-weight: var(--font-weight-medium);
    line-height: var(--line-height-normal);
    text-align: center;
    text-overflow: unset;
    overflow: unset;
    white-space: nowrap;
    transition: color var(--duration-fast) ease, border-color var(--duration-fast) ease;
    border-bottom: var(--btn-border-width) solid transparent;
    cursor: pointer;
  }

  .tabs-list button:hover {
    color: var(--digicert-neutral-700);
  }

  .tabs-list button p {
    margin: 0;
  }

  .tabs-list button[aria-selected='true'] {
    cursor: default;
    color: var(--digicert-blue);
    border-bottom: var(--btn-border-width) solid var(--digicert-blue);
    font-weight: var(--font-weight-semibold);
  }

  /* Stack all panels in same grid cell - tallest defines height */
  .tabs-panel {
    grid-row: 2;
    grid-column: 1;
    overflow: hidden;
    transition: opacity var(--duration-fast) ease;

    h2:first-of-type {
      margin-top: 0;
      color: var(--digicert-blue);
    }
  }

  /* Hidden panels stay in layout flow but invisible */
  .tabs-panel[aria-hidden='true'] {
    visibility: hidden;
    opacity: 0;
    pointer-events: none;
  }
}

/* --------------------------------------------------------------------------
   BETA: form tabbing (`Style: tabbed-blocks, form-tabbing-beta`)

   Each form is tabbed together with the heading and copy that introduce it, so a
   tab panel now contains default content — which a tab panel never did before.
   Two consequences to correct:

   1. `main > .section > .default-content-wrapper` centres section intro text.
      Inside a panel the wrapper is no longer a direct child of the section, so
      that rule stops applying and the content goes left-aligned. That is what we
      want above a form, so this is a note, not a fix.
   2. The wrapper's own bottom margin plus the panel's spacing double up between
      the copy and the form. Collapse it.
   -------------------------------------------------------------------------- */
main .section.tabs-container.form-tabbing-beta .tabs .tabs-panel {
  .default-content-wrapper {
    /* Centred to match the form beneath it. Section intro copy is centred by
       `main > .section > .default-content-wrapper`, but inside a panel the wrapper is no
       longer a direct child of the section, so that rule stops applying — this restores it
       for the tabbed case only. */
    text-align: center;

    /* The wrapper's own bottom margin plus the panel's spacing double up against the form;
       drop the margin and set the gap explicitly. --space-l is 24px. */
    margin-bottom: 0;
    padding-bottom: var(--space-l);
  }
}

/* --------------------------------------------------------------------------
   TAB SKIN: vertical (Section Metadata `Style: tabbed-blocks, tab-style-vertical`)

   Tab strip in a left column, active block on the right. Desktop only — below
   900px this whole block is inert and the mobile rendering is the horizontal
   strip defined above, which is the intended responsive behavior, not a gap.

   SPECIFICITY IS LOAD-BEARING. Every selector below carries the full
   `main .section.tabs-container.tab-style-vertical` prefix on purpose:

     base root            main .section.tabs-container .tabs        (0,3,1)
     base nested child    …&.tabs-list / .tabs-panel                (0,4,1)
     base selected tab    …&.tabs-list button[aria-selected]        (0,5,2)
     vertical root        + .tab-style-vertical                     (0,4,1) ✓ beats base root
     vertical child       nested                                    (0,5,1) ✓ beats base child

   Media queries do NOT raise priority, so a shorter selector like
   `.tabs-container.tab-style-vertical .tabs .tabs-panel` (0,4,0) would LOSE to
   the base rules and the panels would silently stay in row 2 / column 1,
   squashed underneath the strip. Do not shorten these.

   The tablist rules additionally qualify on [role='tablist'] to reach (0,6,1).
   That is not decoration: blocks/card-ecommerce/card-ecommerce.css scopes
   `main .section.tabs-container:has(.card-ecommerce) .tabs .tabs-list` — also
   (0,5,1) — and block CSS loads AFTER this file, so an equal-specificity rule
   there would win on source order and re-apply `gap: 0` to a vertical strip.
   -------------------------------------------------------------------------- */
@media (width >= 900px) {
  main .section.tabs-container.tab-style-vertical .tabs {
    grid-template-columns: minmax(12rem, 20%) 1fr;
    grid-template-rows: 1fr;
    gap: var(--space-2xl);

    .tabs-list[role='tablist'] {
      grid-row: 1;
      grid-column: 1;
      flex-direction: column;
      align-items: stretch;
      justify-content: flex-start;

      /* The horizontal strip scrolls sideways when it overflows; a column does not. */
      overflow-x: visible;

      /* Base sets --space-5xl (80px) at this breakpoint — right between horizontal
         tabs, absurd between stacked ones. */
      gap: var(--space-xs);

      /* Base separates the strip from the panel below it; here they sit side by side. */
      margin-bottom: 0;

      /* Font size is deliberately NOT overridden: the base >=900px rule already sets
         --body-font-size-l (24px), which is the intended desktop tab text size. Unlike the
         heading tokens, that one stays 24px at every breakpoint. */
    }

    .tabs-list[role='tablist'] button {
      /* Desktop tab text is 24px. It has to be set HERE, on the button: buttons.css gives
         every `button` an explicit `font-size: var(--btn-font-size)`, and a direct
         declaration always beats inheritance — so the base rule's font-size on `.tabs-list`
         never reaches the label. (That makes the base declaration a no-op for the
         horizontal skin too; left alone here rather than restyling shipped pages.) */
      font-size: var(--body-font-size-l);

      /* Long labels wrap in a fixed-width rail instead of overflowing it. */
      white-space: normal;
      text-align: left;
      padding: var(--space-s) var(--space-m);

      /* Active indicator moves from the bottom edge to the leading edge. */
      border-bottom: none;
      border-inline-start: var(--btn-border-width) solid var(--border-color);
    }

    .tabs-list[role='tablist'] button[aria-selected='true'] {
      border-bottom: none;
      border-inline-start: var(--btn-border-width) solid var(--digicert-blue);
    }

    /* Panels move to the right column. They still share ONE grid cell so the
       tallest defines the height and switching tabs causes no layout shift. */
    .tabs-panel {
      grid-row: 1;
      grid-column: 2;
    }
  }
}

/* ============================================
   SIDES (Section Metadata `Style: Sides`)
   Main column + aside at >=900px, 3:2. The FIRST wrapper is the main column
   and spans every row; every wrapper after it stacks in the aside (a form
   card, a list + a subscribe box, …). Below 900px nothing here applies: the
   wrappers stack in authored order.

   The grid targets the section's wrappers generically, so the main column
   can be a hero block, a card block, or plain default content (hero
   typography only comes with the hero block; default content keeps the
   centered section-intro rule unless `align-left` is added). Hero's own
   in-column posture (no band padding, no background, no self-centering)
   lives in blocks/hero/hero.css — this file is only the grid. A full-bleed
   / bg-image hero inside a column is not supported.

   Ratio, not a fixed aside: a fixed-width aside starves the main column at
   the low end of the breakpoint, and both comps built on this style (WQRD
   registration, Blogs V2 hero band) sit at 3:2 in the site container.

   Inset: the section itself carries the container inset so both columns
   share one container edge, and the wrappers drop theirs. Block CSS that
   styles its own wrapper at higher specificity (hero) repeats that drop.

   Band: the sides section is a page band in its own right (the card needs
   room above and below), so it keeps its padding even as `:first-of-type`,
   which otherwise starts flush under the header.
   ============================================ */
main > .section.sides {
  padding-block: var(--space-2xl);
}

/* `reverse` stacks the secondary column above the main wrapper. Visual order
   only — the DOM still leads with the main wrapper, so keyboard and reader
   order follow content priority, the same trade hero's align-right makes. */
main > .section.sides.reverse:not(.structured-headings) > div:first-child {
  order: 1;
}

/* ============================================
   STRUCTURED SIDES (`Style: sides, structured-headings`)
   utils/section-sides.js regroups the section into generated elements: an optional `.sides-top`
   (the heading row across both columns) and one `.side` per side, numbered by `data-side`. The
   wrapper-count rules in the plain sides block are keyed on wrapper position, so each of them is
   written `:not(.structured-headings)`; these rules place the generated elements instead.

   The wrappers inside a side are no longer section children, so the section's gap does not reach
   them; the side carries its own. `.side` is a flex column so its content can be centred in a row
   made taller by the other side, which is the default; `vertical-align-top` starts it at the top.
   ============================================ */
main > .section.sides.structured-headings > .sides-top,
main > .section.sides.structured-headings > .side {
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
}

main > .section.sides.structured-headings > .side {
  justify-content: center;
}

main > .section.sides.structured-headings.vertical-align-top > .side {
  justify-content: flex-start;
}

/* `reverse` below 900px: side 2 above side 1, as plain sides puts its second column on top. The
   top row stays first. Visual order only, the same trade the plain rule above makes. */
main > .section.sides.structured-headings.reverse > .side[data-side="1"] {
  order: 1;
}

/* Side backgrounds (the `sides-background` Section Metadata row; utils/section-sides.js puts
   `side-bg-<color>` on the side). The background covers the whole side, heading and caption
   included. Text and button color come from the color utility, which reads this background and
   classes the side and its buttons; what it cannot reach is set here: text links take
   `--link-color` (the utility's class on a link loses to `a:any-link`), and hover takes
   `--link-hover-color`, which otherwise turns a link darker blue on the blue side. Hover keeps
   the link color; on the two dark colors the cue is the underline going away (rule below). Link
   colors match the section themes: white on primary, teal on secondary. */
main > .section.sides.structured-headings > .side.side-bg-primary {
  --link-color: var(--digicert-white);
  --link-hover-color: var(--digicert-white);

  background-color: var(--digicert-blue);
}

main > .section.sides.structured-headings > .side.side-bg-secondary {
  --link-color: var(--digicert-teal);
  --link-hover-color: var(--digicert-teal);

  background-color: var(--digicert-dark-blue);
}

main > .section.sides.structured-headings > .side.side-bg-neutral {
  background-color: var(--light-color);
}

/* Custom properties inherit, so the side's link colors also reach a block inside it that paints
   its own light background — a white card's link would be white on white, or teal on white at
   2.1:1. The color utility marks such content `text-dark-on-light` (a card item, or the link
   itself), so there the site's default link colors come back, from the `-default` tokens that
   nothing overrides. */
main > .section.sides.structured-headings > .side:is(.side-bg-primary, .side-bg-secondary) .text-dark-on-light {
  --link-color: var(--link-color-default);
  --link-hover-color: var(--link-hover-color-default);
}

/* Text links on a dark side are underlined at rest. Without it they differ from the copy by color
   alone: white on white text (primary), teal on white text at about 2.1:1 (secondary), under the
   3:1 a color-only link needs (WCAG 1.4.1). This covers the side's own copy, and any link inside a
   block that the color utility classed light-on-dark (a block with no background of its own, such
   as columns, or a dynamic-cards byline). A link in a white card is classed dark-on-light and keeps
   the site default. Buttons are not text links. On hover the underline goes away, since the color
   stays the same. */
main > .section.sides.structured-headings > .side:is(.side-bg-primary, .side-bg-secondary) > .default-content-wrapper a:any-link:not(.button),
main > .section.sides.structured-headings > .side:is(.side-bg-primary, .side-bg-secondary) a:any-link.text-light-on-dark:not(.button) {
  text-decoration: underline;
}

main > .section.sides.structured-headings > .side:is(.side-bg-primary, .side-bg-secondary) > .default-content-wrapper a:any-link:not(.button):hover,
main > .section.sides.structured-headings > .side:is(.side-bg-primary, .side-bg-secondary) a:any-link.text-light-on-dark:not(.button):hover {
  text-decoration: none;
}

/* Inner padding so copy does not touch the colored edge. Below 900px the sides stack and a
   colored side runs edge to edge, so it keeps the container side margin that
   `main > .section > div` gives it, adds only top and bottom padding, and has square corners. From
   900px it is a panel in its column, with rounded corners.

   The transparent border is invisible in normal rendering. Forced colors replace the background
   with the system background and draw borders in the system text color, so the border keeps the
   panel's edge visible there, the same approach dynamic-cards takes for its hover outline. */
main > .section.sides.structured-headings > .side:is(.side-bg-primary, .side-bg-secondary, .side-bg-neutral) {
  padding-block: var(--space-l);
  border: 1px solid transparent;
}

@media (width >= 900px) {
  main > .section.sides.structured-headings > .side:is(.side-bg-primary, .side-bg-secondary, .side-bg-neutral) {
    padding: var(--space-xl);
    border-radius: var(--border-radius-xl);
  }
}

@media (width >= 900px) {
  main > .section.sides {
    padding-block: var(--space-4xl);
    display: grid;
    grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    gap: var(--space-l) var(--space-2xl);

    /* A lone aside wrapper centers against the main column (the WQRD comp:
       hero copy beside a taller form card). A stacked aside instead packs to
       the top — see the :has() override below — because centered items in
       per-wrapper grid rows drift apart when the main column is taller. */
    align-items: center;
    padding-inline: max(var(--container-padding), calc((100% - var(--container-max-width)) / 2 + var(--container-padding)));
  }

  main > .section.sides > div {
    max-width: none;
    padding-inline: 0;
  }

  /* First wrapper = main column. It must span one row per aside wrapper, and `1 / -1` cannot
     express that (with no explicit rows, -1 resolves to the end of a one-row explicit grid and the
     span collapses to a single row). Count the wrappers instead: one rule per supported aside
     depth, up to four stacked aside wrappers. A fifth lands in a row the main column does not
     reach, so it sits beside empty space rather than beside the main content. */
  main > .section.sides:not(.structured-headings) > div:first-child {
    grid-column: 1;
    grid-row: 1;
  }

  main > .section.sides:not(.structured-headings) > div:not(:first-child) {
    grid-column: 2;
  }

  main > .section.sides:not(.structured-headings):has(> div:nth-child(3)) {
    align-items: start;
  }

  /* `vertical-align-top` on a plain sides section: every column starts at the top. */
  main > .section.sides.vertical-align-top:not(.structured-headings) {
    align-items: start;
  }

  /* `reverse` (`Style: Sides, reverse`): the secondary column leads at every
     viewport — left column on desktop, on top of the stack below 900px (see
     the order rule outside this media query). Authored order is unchanged:
     the first wrapper is still the main column, so the DOM keeps leading
     with the main content. */
  main > .section.sides.reverse {
    grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  }

  main > .section.sides.reverse:not(.structured-headings) > div:first-child {
    /* The grid places both columns explicitly, so the stacking order the base
       rule sets has no job here. */
    order: 0;
    grid-column: 2;
  }

  main > .section.sides.reverse:not(.structured-headings) > div:not(:first-child) {
    grid-column: 1;
  }

  main > .section.sides:not(.structured-headings):has(> div:nth-child(3)) > div:first-child {
    grid-row: 1 / span 2;
  }

  main > .section.sides:not(.structured-headings):has(> div:nth-child(4)) > div:first-child {
    grid-row: 1 / span 3;
  }

  main > .section.sides:not(.structured-headings):has(> div:nth-child(5)) > div:first-child {
    grid-row: 1 / span 4;
  }

  /* Structured sides. Sides stretch to the row's height so their content can be centred (or
     started at the top) against the taller side.

     Rows: the top row and side 1 take explicit rows; later sides set only a column and take auto
     rows. Explicit rows on every side would put a third side on top of side 2. Auto rows on every
     side would, under `reverse`, put side 2 a row below side 1: side 1 moves the placement cursor
     to column 2, and an auto item for column 1 then has to advance a row. Side 1 being explicit
     means it never moves the cursor. utilities.css moves these rows down one when a preview badge
     takes row 1. */
  main > .section.sides.structured-headings {
    align-items: stretch;
  }

  main > .section.sides.structured-headings > .sides-top {
    grid-column: 1 / -1;
    grid-row: 1;
  }

  main > .section.sides.structured-headings > .side {
    grid-column: 2;
  }

  main > .section.sides.structured-headings > .side[data-side="1"] {
    grid-column: 1;
    grid-row: 1;
  }

  main > .section.sides.structured-headings > .sides-top ~ .side[data-side="1"] {
    grid-row: 2;
  }

  /* `reverse` swaps the side columns. The column widths come from the plain reverse rule above
     (2fr 3fr), so side 1 keeps the wide column, now on the right, as the main column does on a
     plain reverse section. */
  main > .section.sides.structured-headings.reverse > .side {
    grid-column: 1;
  }

  main > .section.sides.structured-headings.reverse > .side[data-side="1"] {
    grid-column: 2;
  }
}
