/**
 * @file
 * Vertical rhythm between Layout Builder sections and the blocks inside them.
 *
 * Spacing lives here rather than on the components because it is a relationship
 * between two things, not a property of either. A block cannot know what sits
 * above it, what sits below it, or whether it is the last thing on the page, so
 * a margin declared inside a component is the component asserting something
 * about a context it cannot see. Layout Builder sections are the unit that
 * expresses "these are separate bands of the page", so the rhythm belongs to
 * them.
 *
 * Two gaps, not one: a full break between sections, a smaller step between the
 * blocks inside a section. That is what lets an editor group an intro with the
 * block it introduces — put them in the same section — without a spacing field
 * on every block type or a spacer block to place and later delete by accident.
 *
 * Both rules use the adjacent sibling selector deliberately. Space is only ever
 * added *between* siblings, never before the first or after the last, which:
 *
 * - keeps the hero flush under the site header with no reset needed;
 * - leaves no trailing margin to collapse against, or fail to collapse against,
 *   whatever follows the last section;
 * - behaves identically in flex and grid regions, where adjoining margins do not
 *   collapse at all. A top-and-bottom margin pair would silently double to 2x
 *   the gap in a flex region and read as 1x in a normal-flow one.
 *
 * Scoped to .layout and .layout__region, which are core Layout Builder's classes
 * from layout_discovery's templates. Site Studio pages do not use them, so this
 * cannot reach the legacy pages during the migration.
 *
 * Not written with :where(). Zero specificity sounded right — anything could
 * override it — but it also loses to an element-level reset such as
 * `div { margin: 0 }`, and Site Studio ships a reset. The plain class selectors
 * below sit at 0,1,0 to 0,2,0: still trivially overridable by a component or a
 * section modifier, but no longer beaten by the cascade's floor.
 *
 * Not covered here, deliberately: the gap between the final section and the site
 * footer. There is no trailing margin by design, so that space has to come from
 * whatever wraps the sections or from the footer itself, and it applies to Site
 * Studio pages too. Left alone rather than guessed at.
 *
 * @see layout_discovery/layouts/onecol/layout--onecol.html.twig
 */

/**
 * Breakpoints.
 *
 * One page breakpoint: **48rem / 768px**. Below it, the designer's 401px phone
 * comp; at and above it, the desktop design. Chosen rather than measured — there
 * is no tablet comp — so it is a decision to revisit rather than a fact.
 *
 * A media query cannot read a custom property, so the number is duplicated in
 * every consumer and there is no way around that. `grep -rn '47.99rem\|48rem'`
 * finds all of them. 47.99rem is used for max-width so it cannot overlap a
 * min-width: 48rem rule at exactly 768px.
 *
 * Two component-level breakpoints exist as well, and are deliberately not the
 * page one:
 *
 * - 64rem in carousel.css drops its two columns early, because 510px of copy
 *   beside a card track does not fit at 1024px. Between 48 and 64rem the
 *   carousel is one column without the phone treatment.
 * - 62rem in button.css applies --ln-cta-min-width. Below it the CTAs size to
 *   their labels, which is what the phone comp shows.
 *
 * The known weak spot is 700-767px: a large phone in landscape or a small tablet
 * gets the desktop layout in not much width. Accepted for now; a tablet comp
 * would settle it.
 */

:root {
  /**
   * Two values, because a section boundary means something.
   *
   * --ln-section-gap is the break between one band of the page and the next.
   * --ln-block-gap is the smaller step between blocks that belong together.
   *
   * Both scale with the viewport. The components' own internal padding is already
   * responsive, so a fixed gap looked proportionally huge on narrow screens next
   * to a section that had tightened up.
   */
  /**
   * Both measured from the full-page design (a 2x export of the 1920 frame).
   *
   * 96px between sections: the design shows 94.5, 94.5 and 95.5 at three
   * boundaries, which is as close to a system as it gets.
   *
   * 72px within a section: the gap between the pill closing the "Signature
   * Advertising Updates" text block and the tab strip below it — the exact case
   * this pair of tokens exists to serve.
   *
   * Three boundaries in the design do not fit either value: 63px below the hero,
   * 132px before the FAQ and 174px before the comparison chart. No two tokens
   * express that, which is the argument for a per-section spacing setting on a
   * custom layout plugin.
   */
  --ln-section-gap: clamp(48px, 8vw, 96px);
  --ln-block-gap: clamp(40px, 5vw, 72px);
}

/* Between sections: the full break. */
.layout + .layout {
  margin-block-start: var(--ln-section-gap);
}

/**
 * Between blocks inside one section: the smaller step.
 *
 * This started out as the same value as between sections, on the reasoning that a
 * section boundary is an authoring detail a visitor should not be able to see.
 * That was wrong, and it threw away the only grouping signal Layout Builder
 * offers.
 *
 * Designs regularly want a headline and a paragraph introducing the block below
 * them — a Text block above an accordion, say — and with one uniform gap those
 * two read as unrelated bands rather than as one section with an intro. Making
 * the within-section step smaller gives an editor a way to say "these belong
 * together" using structure that already exists, with no per-block spacing field
 * and no spacer to place.
 *
 * The convention this implies, which is worth stating in the authoring notes:
 * one section per visual band. Blocks that read as a unit go in the same section;
 * anything that should stand alone gets its own.
 */
.layout__region > * + * {
  margin-block-start: var(--ln-block-gap);
}

/**
 * The gap between the last section and the site footer.
 *
 * The sibling rules above leave no trailing margin, by design, so this is the
 * one place a bottom margin is correct. .layout is the outermost element Layout
 * Builder owns — everything above it (the unclassed wrapper, article, the
 * #block-mainpagecontent block, Site Studio's .coh-container) is shared with the
 * legacy pages, so putting the space there would move every page on the site.
 *
 * Keyed on .layout rather than a Site Studio class for the same reason: .layout
 * comes from layout_discovery's templates and appears on Layout Builder pages
 * only, so this cannot reach a Cohesion-built page.
 *
 * Padding, not margin, and this is the point of the rule. A bottom margin here
 * has nothing to its right or below to collapse against, so it collapses *out*
 * through every ancestor that has no padding, border or block formatting
 * context — the unclassed wrapper, <article>, #block-mainpagecontent — and
 * whether it survives that journey depends on markup this module does not own.
 * Padding cannot collapse and cannot escape, so the space is where it is put.
 *
 * Safe because .layout carries no background of its own. If a section variant
 * ever gains one, the padding will extend it and this wants revisiting.
 */
.layout:last-child {
  padding-block-end: var(--ln-section-gap);
}

/**
 * Keep anchor targets clear of the sticky site header.
 *
 * Without this a link to #comparison-table scrolls the section's top edge to the
 * top of the viewport, which is underneath the 60px header — so the heading is
 * hidden and the page looks like it jumped to the wrong place.
 *
 * Applied to anything with an id inside a Layout Builder region rather than to
 * the blocks that have an anchor field, so it also covers ids an editor writes
 * into a rich text field. It reaches form inputs too, which is a bonus rather
 * than a side effect: focusing a field scrolls it into view, and the margin keeps
 * it below the header instead of behind it.
 *
 * scroll-margin only participates when something is scrolled into view, so this
 * is inert the rest of the time.
 */
.layout__region [id] {
  scroll-margin-top: calc(var(--ln-site-header-height, 60px) + 24px);
}

/**
 * Smooth scrolling for the anchor links above.
 *
 * On html, and on a class, for two reasons that pull in the same direction.
 * scroll-behavior only affects a fragment jump when it is set on the scrolling
 * container, and for a fragment jump that is the root element — a value on body
 * is ignored for the viewport. So it cannot be scoped with a descendant
 * selector. And a bare html rule would change every Cohesion-built page on the
 * site, which is a lot of pages to alter as a side effect of adding two anchors.
 * loopnet_blocks_preprocess_html() adds .ln-lb-page only where Layout Builder is
 * in play.
 *
 * Behind prefers-reduced-motion: a long smooth scroll is one of the clearer
 * triggers for motion sensitivity, and unlike a decorative animation it moves
 * the entire viewport.
 *
 * This also applies to scrollIntoView() and scrollTo() without an explicit
 * behavior, which is why the carousel forces scroll-behavior: auto on its track
 * — see the note in carousel.css. Its arrow buttons pass behavior: 'smooth'
 * explicitly, so they are unaffected either way.
 */
@media (prefers-reduced-motion: no-preference) {
  html.ln-lb-page {
    scroll-behavior: smooth;
  }
}

/**
 * The Layout Builder editing UI keeps the rhythm — the preview is meant to read
 * as the page — but its own furniture is exempt.
 *
 * LayoutBuilder::buildAdministrativeSection() adds two containers as direct
 * children of each region, so both are siblings of the blocks and both are
 * caught by the rule above:
 *
 * - the region label, at min(weights) - 1, so it sorts first. It never picks up
 *   a gap itself, but the first real block then follows it and does — an
 *   indent at the top of every region that the rendered page does not have.
 * - the "Add block" link, at weight 1000, so it sorts last and gets a full gap
 *   pushing it away from the block above.
 *
 * Both are chrome rather than content, so they use the editing UI's own spacing.
 *
 * @see \Drupal\layout_builder\Element\LayoutBuilder::buildAdministrativeSection()
 */
.layout-builder__region > .layout-builder__add-block,
.layout__region-info + * {
  margin-block-start: 0;
}

/**
 * Blocks with nothing in the flow are exempt from the rhythm too.
 *
 * The sticky CTA's panel is position:fixed, so its block wrapper collapses to
 * zero height — but it is still a sibling in the region, so the rule above gives
 * it a gap. The result is an unexplained hole between the two blocks either side
 * of it, from an element the editor cannot see and would not think to blame.
 *
 * Same class of bug as the hidden marketing checkbox in the form block: an
 * element that occupies no space still takes part in the layout.
 *
 * Doubled class rather than !important. The rule above is .layout__region > * + *
 * at (0,2,0), and a single class here would tie it — leaving the outcome to the
 * order the browser happened to parse layout.css and the component's stylesheet
 * in. (0,3,0) wins regardless. Same convention as .ln-pill.ln-pill in
 * css/editor-styles.css.
 *
 * This lives here rather than in sticky-cta.css because this file owns the rule
 * being excepted, and one list of exceptions is easier to reason about than
 * several. If the sticky CTA component is ever removed, remove this too.
 */
.layout__region > .ln-block--sticky-cta.ln-block--sticky-cta {
  margin-block-start: 0;
}
