/* ---------------------------------------------------------------------------
   Applied Plastics — site theme

   Layered ON TOP of the shared page-builder stylesheet (`shared.css`, loaded
   first by `_layout.twig`). shared.css styles the blocks generically; this file
   turns them into the Applied Plastics look, a port of
   https://appliedplasticsinc.com/ (WordPress theme
   `/wp-content/themes/appliedplasticsinc-default/style.css`).

   Every colour / size below is taken from that stylesheet unless a comment says
   otherwise. Deliberate departures are all accessibility fixes and are marked
   "AA:".

   Hooks come from each block's `customCssClasses` (see
   modules/console/controllers/ApController.php):

     .ap-hero  .ap-hero__text
     .ap-features  .ap-features__video  .ap-features__list
     .ap-markets  .ap-markets__grid  .ap-markets__intro  .ap-markets__list
     .ap-cta  .ap-cta__text  .ap-cta__buttons (.ap-btn)  .ap-cta__image
     .ap-products
     .ap-accent  (blue word inside the hero / CTA headings)

   Body classes are `landing-page home`; the builder wrapper is
   `.page-builder.home-page`.

   Chrome hooks (components/_navbar.twig, components/_footer.twig):

     .ap-header  .ap-header__bars  (+ .is-scrolled)   shrinking sticky header
     .menu__link  .menu__caret  .submenu  (+ .is-open, .is-current, .is-ancestor)
     .footer-col  .footer-address  .footer-contact
     .footer-bottom__inner  .footer-legal__list

   Accessibility (ACCESSIBILITY.md / WCAG 2.2 AA):
   - every interactive element keeps a visible :focus-visible indicator
   - submenus are hidden with visibility:hidden (not opacity alone) so they
     stay out of the tab order while closed
   - text over the Markets photo sits on an opaque-enough scrim (see "AA:")
   - the product strip's autoplay stops under prefers-reduced-motion
     (handled in templates/page-builder/blocks/blockSlider.twig), and its
     prev/next arrows stay visible at every width rather than appearing on
     hover as they do on the source
   - every transition/animation added here has a prefers-reduced-motion rule:
     the header compaction, the CTA button's hover chevron, the CTA photo's
     slide-in and the strip's smooth scrolling
   --------------------------------------------------------------------------- */

:root {
    --ap-blue: #00529c;          /* theme primary */
    --ap-ink: #494949;           /* headings */
    --ap-body: #666;             /* body copy (5.7:1 on white) */
    --ap-ink-dark: #2b2c2a;      /* CTA button / small footer */
    --ap-yellow: #fcbf00;        /* CTA button label (8.6:1 on --ap-ink-dark) */
    --ap-grey-band: #f4f4f4;     /* CTA band */
    --ap-rule: rgba(0, 0, 0, 0.1);
    --ap-rule-soft: #aeafaf;     /* the rule beside each capability label */
    --ap-footer-bg: #222;
    --ap-maroon: #86003b;        /* theme accent — current nav item (10.1:1 on #fff, 9.4:1 on --ap-sub-bg) */
    --ap-nav-ink: rgba(0, 0, 0, 0.7);   /* nav links (8.5:1 on #fff) */
    /* AA: the source hovers nav links to rgba(0,0,0,.5) = 3.98:1 on #fff and 3.92:1
       on the dropdown's #f7f7f7 — below 4.5:1 for 14px text. .55 is the nearest step
       of the same neutral that passes on both: 4.76:1 / 4.68:1. */
    --ap-nav-hover: rgba(0, 0, 0, 0.55);
    --ap-sub-bg: #f7f7f7;        /* dropdown panel */
    --ap-focus: rgba(0, 82, 156, 0.75);
    --ap-font-body: "Open Sans", system-ui, sans-serif;
    --ap-font-head: "Oswald", "Open Sans", system-ui, sans-serif; /* buttons only */
    --ap-max: 70.5rem;           /* .inner-wrap max-width, 1128px */
    --ap-gutter: 1rem;
}

/* --- Base typography ------------------------------------------------------ */

body {
    font-family: var(--ap-font-body);
    font-size: 1rem;
    line-height: 1.5;
    color: var(--ap-body);
    background: #fff;
    -webkit-font-smoothing: antialiased;
}

/* The source theme sets headings in Open Sans 800 uppercase and reserves
   Oswald for buttons — not the other way round. */
h1, h2, h3, h4, h5, h6 {
    font-family: var(--ap-font-body);
    color: var(--ap-ink);
    line-height: 1.25;
    margin: 0;
}

.ap-accent {
    color: var(--ap-blue);
}

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* Shared focus indicator — rounded elements use box-shadow, not outline. */
.brand:focus-visible,
.nav-toggle:focus-visible,
.menu__link:focus-visible,
.menu__caret:focus-visible,
.submenu a:focus-visible,
.footer-contact a:focus-visible,
.footer-trg:focus-visible,
.ap-btn:focus-visible,
.video-embed__play:focus-visible {
    outline: none;
    /* box-shadow, not outline, so the ring follows each element's own radius
       (the shared play button is a circle) — hence no border-radius here. */
    box-shadow: 0 0 0 3px var(--ap-focus);
    z-index: 1;
}

/* The CTA button is dark-on-grey, where a translucent ring reads faintly —
   give it a white gap plus a solid blue ring (7.4:1 against the #f4f4f4 band). */
.ap-btn:focus-visible {
    box-shadow: 0 0 0 2px #fff, 0 0 0 5px var(--ap-blue);
}

/* Desktop nav links and carets fill the whole nav row (like the source's `li`
   hover column), so an OUTER ring would spill over the contact strip and the
   header's bottom rule — draw it inset instead. Same colour and width as the
   shared ring (4.35:1 on #fff, 4.17:1 on the dropdown's #f7f7f7), and far
   more visible than the hover state, which is a colour shift only. */
@media (min-width: 921px) {
    .menu__link:focus-visible,
    .menu__caret:focus-visible,
    .submenu a:focus-visible {
        box-shadow: inset 0 0 0 3px var(--ap-focus);
    }

    .submenu a.is-current:focus-visible {
        box-shadow: inset 3px 0 0 var(--ap-maroon), inset 0 0 0 3px var(--ap-focus);
    }
}

/* Interactive elements sitting on the blue strip get a white ring instead. */
.topbar__link:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
}

/* --- Shared brand bar ----------------------------------------------------- */

/* The shared component pins itself with `position: fixed` when the site's
   brandBar global has `sticky` on. Fixed takes it out of flow, so it covered
   the blue contact strip (the first in-flow child of <header>). `sticky` keeps
   the same pinned behaviour AND keeps it in flow above the header — the bar
   itself is otherwise untouched. Specificity beats the component's own rule, so
   no !important is needed. */
body > header .brand-bar.sticky {
    position: sticky;
}

/* --- Sticky / shrinking header -------------------------------------------
   Port of the source theme's `.sh-sticky-wrap.stuck` (style.css): once the
   header has scrolled out of view the contact strip + logo/nav row detach to
   the top of the viewport and compact — logo 16.0625em → 11.25em, nav row
   ~6.5em → 5em, `transition: all 0.4s ease-in-out`, plus a soft shadow.

   `.ap-header` is the in-flow SHELL. JS (components/_navbar.twig) pins its
   height to the EXPANDED bars, so when `.ap-header__bars` goes `position:
   fixed` the shell still reserves the same space and nothing below it moves.
   The whole thing only engages when `siteSettings.stickyHeader` is on, which
   is what puts `.ap-header--sticky` on the shell.
   -------------------------------------------------------------------------- */

.ap-header {
    position: relative;
    z-index: 60;
}

.ap-header__bars {
    background: #fff;
}

.ap-header--sticky.is-scrolled .ap-header__bars {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 90;
    box-shadow: 0 0 7px rgba(0, 0, 0, 0.1);
}

/* The source swaps the nav bar's bottom rule for that shadow once stuck. */
.ap-header--sticky.is-scrolled .site-header {
    border-bottom-color: transparent;
}

/* Height of the desktop nav row (the menu items fill it, so it is also the
   hover/click column and where the dropdown hangs from). Source: `.sn-li-l1`
   7.125em, 5em once stuck. Only read at >=921px, where the inline menu shows. */
.ap-header {
    --ap-nav-row: 5.5rem;
}

.ap-header--sticky.is-scrolled {
    --ap-nav-row: 3.75rem;
}

@media (min-width: 64em) {
    .ap-header {
        --ap-nav-row: 7.125rem;
    }

    .ap-header--sticky.is-scrolled {
        --ap-nav-row: 5rem;
    }
}

/* The source animates `all`; an explicit property list is used instead so a
   :focus-visible ring inside the header can never animate (ACCESSIBILITY.md). */
.ap-header__bars,
.ap-header .header-inner,
.ap-header .brand__text,
.ap-header .brand__img,
.ap-header .menu__item {
    transition-duration: 0.4s;
    transition-timing-function: ease-in-out;
}

.ap-header__bars { transition-property: box-shadow; }
.ap-header .header-inner { transition-property: min-height, padding; }
.ap-header .brand__text { transition-property: font-size; }
.ap-header .brand__img { transition-property: max-width; }
.ap-header .menu__item { transition-property: height; }

/* Phone-width compaction (the source doesn't pin below 64em at all; here the
   bar pins at every width, so it gets smaller on a phone too). The desktop row
   is sized by --ap-nav-row instead. */
@media (max-width: 920px) {
    .ap-header--sticky.is-scrolled .header-inner {
        min-height: 3rem;
        padding-top: 0.375rem;
        padding-bottom: 0.375rem;
    }
}

/* `.brand__text` is only rendered as a fallback while `siteSettings.companyLogo`
   is empty; with the logo set (the normal case) it is `.brand__img` that shrinks. */
.ap-header--sticky.is-scrolled .brand__text {
    font-size: 1.25rem;
}

.ap-header--sticky.is-scrolled .brand__img {
    max-width: 7.6875rem;
}

/* A pinned header must not swallow the viewport when the mobile menu is open. */
.ap-header--sticky.is-scrolled .nav.is-open {
    max-height: calc(100vh - 7rem);
    overflow-y: auto;
}

@media (min-width: 64em) {
    /* 70% of the expanded sizes — the source's stuck logo, 16.0625em → 11.25em. */
    .ap-header--sticky.is-scrolled .brand__text {
        font-size: 1.3125rem;
    }

    .ap-header--sticky.is-scrolled .brand__img {
        max-width: 11.25rem;
    }
}

/* The header still pins and compacts under reduced motion — that is a state
   change the user asked for by scrolling — it just does so instantly. */
@media (prefers-reduced-motion: reduce) {
    .ap-header__bars,
    .ap-header .header-inner,
    .ap-header .brand__text,
    .ap-header .brand__img,
    .ap-header .menu__item {
        transition: none;
    }
}

/* Set by the script only while it measures the expanded height, so the
   momentary un-stick is never animated. Matches the weight of the rules above
   (0,2,0) and wins on source order. */
.ap-header.is-measuring .ap-header__bars,
.ap-header.is-measuring .header-inner,
.ap-header.is-measuring .brand__text,
.ap-header.is-measuring .brand__img,
.ap-header.is-measuring .menu__item {
    transition: none;
}

/* --- Top contact strip ---------------------------------------------------- */

.topbar {
    background: var(--ap-blue);
    color: #fff;
    font-size: 0.75rem;
}

/* Source `.sh-utility-nav .inner-wrap`: a border-box 70.5em wrap with 1em side
   padding (1.5em from 40em — the same wrap the page content uses, so the strip,
   the logo and the page all share one left edge) and 0.125em / 0.3125em top /
   bottom around a 24px line: 31px tall. */
.topbar__inner {
    box-sizing: border-box;
    max-width: var(--ap-max);
    margin-inline: auto;
    padding: 0.125rem var(--ap-gutter) 0.3125rem;
}

.topbar__list {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    min-height: 1.5rem;
    gap: 0 1rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* Icon → text: 14px on the phone link, 16px on the email link (the source's
   padding-left of 1.1667em / 1.3333em around a 1em glyph). */
.topbar__link {
    display: inline-flex;
    align-items: center;
    gap: 0.1667em;
    color: #fff;
    font-weight: 600;
    text-decoration: none;
}

.topbar__list li + li .topbar__link {
    gap: 0.3333em;
}

/* Source hover: rgba(255,255,255,.7) = #b2cbe1 on the #00529c strip, 4.67:1 —
   passes AA for this 12px/600 text, so it is kept as-is. */
.topbar__link:hover {
    color: rgba(255, 255, 255, 0.7);
}

/* Decorative phone / envelope marks, matching the source's icon-font glyphs.
   Pure CSS so nothing extra is announced; the link text carries the meaning. */
.topbar__link::before {
    content: "";
    width: 1em;
    height: 1em;
    flex: 0 0 auto;
    background: no-repeat center / contain;
}

.topbar__list li:first-child .topbar__link::before {
    background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23ffffff'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M6.6%203.5h3.1l1.6%203.9-2%201.3a11%2011%200%200%200%205%205l1.3-2%203.9%201.6v3.1a2%202%200%200%201-2.2%202A17.6%2017.6%200%200%201%204.6%205.7a2%202%200%200%201%202-2.2Z'/%3E%3C/svg%3E");
}

.topbar__list li + li .topbar__link::before {
    background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23ffffff'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Crect%20x='2.8'%20y='5'%20width='18.4'%20height='14'%20rx='2'/%3E%3Cpath%20d='m3.4%206.6%208.6%206%208.6-6'/%3E%3C/svg%3E");
}

@media (min-width: 40em) {
    .topbar__inner {
        padding-left: 1.5rem;
        padding-right: 1.5rem;
    }
}

@media (min-width: 60em) {
    .topbar__list {
        justify-content: flex-start;
    }
}

/* --- Header / brand ------------------------------------------------------- */

.site-header {
    background: #fff;
    border-bottom: 1px solid var(--ap-rule);
    transition: border-color 0.4s ease-in-out;
}

/* Source `.sh-nav-bar .inner-wrap`: same border-box wrap as the strip above;
   1.1875em / 1.25em top / bottom on a phone, none from 921px (the row is sized
   by the menu items, see --ap-nav-row). */
.header-inner {
    box-sizing: border-box;
    max-width: var(--ap-max);
    margin-inline: auto;
    padding: 1.1875rem var(--ap-gutter) 1.25rem;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 1rem;
    min-height: 3.5rem;
}

@media (min-width: 40em) {
    .header-inner {
        padding-left: 1.5rem;
        padding-right: 1.5rem;
    }
}

.brand {
    display: inline-flex;
    align-items: center;
    margin-right: auto;
    text-decoration: none;
}

/* The source nudges the logo 0.25em right of the wrap edge from 80em. */
@media (min-width: 80em) {
    .brand {
        position: relative;
        left: 0.25rem;
    }
}

/* The <img> carries width/height attributes so the header reserves the right box
   before the logo decodes; `auto`/`auto` hands sizing back to max-width (the
   source sizes `.sh-logo` by max-width too), which is what the shrink-on-scroll
   animates. 9.1875em = 147px wide on a phone, 16.0625em = 257px from 64em. */
.brand__img {
    display: block;
    max-width: 9.1875rem;
    width: auto;
    height: auto;
}

/* Fallback until a logo asset is set on the siteSettings global. */
.brand__text {
    font-family: var(--ap-font-head);
    font-size: 1.5rem;
    font-weight: 500;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--ap-blue);
}

@media (min-width: 921px) {
    .header-inner {
        padding-top: 0;
        padding-bottom: 0;
    }
}

@media (min-width: 64em) {
    .header-inner {
        gap: 2rem;
    }

    .brand__img {
        max-width: 16.0625rem;
    }

    .brand__text {
        font-size: 1.875rem;
    }
}

/* --- Nav toggle (mobile) -------------------------------------------------- */

.nav-toggle {
    border: 0;
    background: none;
    padding: 0.25rem;
    appearance: none;
    cursor: pointer;
    font: inherit;
    color: var(--ap-blue);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* The source's menu icon is a 32×48 target. */
    min-width: 2rem;
    min-height: 3rem;
}

/* --- Primary nav ---------------------------------------------------------- */

.menu,
.submenu {
    margin: 0;
    padding: 0;
    list-style: none;
}

.menu {
    display: flex;
    flex-wrap: wrap;
    gap: 0;
}

/* The parent link and its caret button are siblings (the button is the dropdown's
   real control — see the note in components/_navbar.twig), so the item lays them
   out in a row. `flex-wrap` is what lets the submenu drop onto its own line in the
   mobile accordion, where it is in flow rather than absolutely positioned. */
.menu__item {
    position: relative;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
}

/* Source `.sn-li-l1 > a`: Open Sans 14px / 600, rgba(0,0,0,.7), 0.6875em each
   side (22px between labels), no underline. */
.menu__link {
    position: relative;
    display: inline-flex;
    align-items: center;
    padding: 0 0.6875rem;
    color: var(--ap-nav-ink);
    font-size: 0.875rem;
    font-weight: 600;
    line-height: 1.5;
    text-decoration: none;
    white-space: nowrap;
}

/* The caret button takes the parent link's right-hand padding. */
.menu__item.has-children > .menu__link {
    padding-right: 0;
}

/* Source hover: the whole item is the hover target (`.sn-li-l1:hover > a`), so
   the parent label stays in its hover colour while the pointer is down in its
   dropdown. It also wins over the current-page colour, as on the source — the
   current-page bar stays, so the item is still marked. Colour only, no underline,
   as on the source. AA: see --ap-nav-hover. */
.menu__link:hover,
.menu__item:hover > .menu__link,
.menu__item:hover > .menu__caret {
    color: var(--ap-nav-hover);
}

/* --- Dropdown toggle ------------------------------------------------------ */

/* Standard button reset (ACCESSIBILITY.md → Interactive Elements).
   The source has no desktop caret at all (hover-only dropdowns); this one stays
   because it is the keyboard/touch control for the submenu. 24px wide so it
   meets WCAG 2.5.8 (Target Size (Minimum)) right next to the parent link. */
.menu__caret {
    border: 0;
    background: none;
    padding: 0 0.375rem;
    margin: 0;
    min-width: 1.5rem;
    appearance: none;
    cursor: pointer;
    font: inherit;
    line-height: 0;
    color: var(--ap-nav-ink);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.menu__caret .caret {
    transition: transform 0.15s ease;
}

.menu__item.is-open > .menu__caret .caret {
    transform: rotate(180deg);
}

@media (prefers-reduced-motion: reduce) {
    .menu__caret .caret {
        transition: none;
    }
}

/* With JS off the button can't do anything, so don't offer it — and let focus
   alone reveal the submenu instead, which is the CSS-only fallback. (`.ap-js` is
   set on <html> before first paint by the site layout.) */
html:not(.ap-js) .menu__caret {
    display: none;
}

html:not(.ap-js) .menu__item.has-children > .menu__link {
    padding-right: 0.6875rem;
}

/* --- Current page --------------------------------------------------------- */

/* `is-current` = this exact page, `is-ancestor` = a parent of it (the source
   colours only the exact page; the ancestor state is kept here as a location
   cue). Source colour: the theme maroon #86003b, 10.1:1 on white.

   AA (1.4.1 Use of Color): the source marks the current page by colour ALONE,
   and maroon vs the rgba(0,0,0,.7) of the other links is only 1.2:1 — so the
   item also gets a 3px maroon bar (10.1:1 against white, over the 3:1 needed
   for a non-text indicator). It is a drawn bar the width of the label, sitting
   clear of the descenders — not a text-decoration underline — and the link
   also carries aria-current="page" for assistive tech. */
.menu__link.is-current,
.menu__link.is-ancestor {
    color: var(--ap-maroon);
}

.menu__link.is-current::after,
.menu__link.is-ancestor::after {
    content: "";
    position: absolute;
    left: 0.6875rem;
    right: 0.6875rem;
    top: calc(50% + 0.75rem);
    height: 3px;
    background: var(--ap-maroon);
    pointer-events: none;
}

.menu__item.has-children > .menu__link::after {
    right: 0;
}

/* A nav item whose target entry was deleted renders as plain text, never a dead
   link — see the note in components/_nav-link.twig. */
.menu__link.is-broken,
.footer-legal__list .is-broken {
    opacity: 0.6;
    cursor: default;
}

/* --- Dropdown panel -------------------------------------------------------- */

/* Source `.sn-level-2`: hangs from the bottom of the nav row, min-width 9.375em,
   no border or shadow; each item is a #f7f7f7 row, 50px line, 0.6875em side
   padding (so the labels line up with the parent's), 14px / 400, with a faint
   rgba(0,0,0,.03) rule between rows. */
.submenu {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 20;
    min-width: 9.375rem;
    background: var(--ap-sub-bg);
    opacity: 0;
    visibility: hidden; /* keeps closed items out of the tab order */
}

.submenu a {
    display: block;
    padding: 0 0.6875rem;
    color: var(--ap-nav-ink);
    font-size: 0.875rem;
    font-weight: 400;
    line-height: 3.125rem;
    text-decoration: none;
    white-space: nowrap;
}

.submenu li:not(:last-child) > a {
    border-bottom: 1px solid rgba(0, 0, 0, 0.03);
}

/* AA: see --ap-nav-hover (4.68:1 on the #f7f7f7 row). The row stays #f7f7f7, as on the source. */
.submenu a:hover {
    color: var(--ap-nav-hover);
}

/* The source leaves the current child unmarked. Here it gets the same maroon
   (9.4:1 on #f7f7f7) plus a non-colour cue — 600 weight and a 3px maroon edge
   bar — so it isn't indicated by colour alone (1.4.1). */
.submenu a.is-current {
    color: var(--ap-maroon);
    font-weight: 600;
    box-shadow: inset 3px 0 0 var(--ap-maroon);
}

/* Hover is the source's mouse behaviour; `.is-open` is what the caret button and
   the keyboard set. With JS off, :focus-within stands in for the button. */
.menu__item.has-children:hover > .submenu,
.menu__item.has-children.is-open > .submenu,
html:not(.ap-js) .menu__item.has-children:focus-within > .submenu {
    opacity: 1;
    visibility: visible;
}

/* Escape wins over :hover. Without this, dismissing a dropdown while the pointer
   is still resting on it does nothing visible (the hover rule re-opens it) — the
   class is dropped again on mouseleave, so the next hover behaves normally.
   Must stay AFTER the rules above: same specificity, later wins. */
.menu__item.has-children.is-dismissed > .submenu {
    opacity: 0;
    visibility: hidden;
}

@media (max-width: 920px) {
    .nav {
        display: none;
        flex-basis: 100%;
    }

    .nav.is-open,
    /* No JS → no hamburger, so the menu has to be there already. */
    html:not(.ap-js) .nav {
        display: block;
        border-top: 1px solid var(--ap-rule);
        padding-top: 0.5rem;
    }

    html:not(.ap-js) .nav-toggle {
        display: none;
    }

    .menu {
        flex-direction: column;
    }

    .menu__item {
        border-bottom: 1px solid rgba(0, 0, 0, 0.06);
        justify-content: space-between;
    }

    /* The link fills the row, so a tap anywhere on the label side follows it —
       not just a tap on the words. A parent item is a split row: link on the
       left, its submenu toggle as a separate full-height button on the right
       behind a hairline, so the two targets are never confused. */
    .menu__link,
    .menu__item.has-children > .menu__link,
    html:not(.ap-js) .menu__item.has-children > .menu__link {
        flex: 1 1 auto;
        padding: 0.75rem 0;
    }

    /* The link is now the full row, so a drawn bar would span it; under the
       label it becomes a 3px underline instead (same maroon, same cue — 1.4.1),
       offset clear of the descenders. */
    .menu__link.is-current::after,
    .menu__link.is-ancestor::after {
        content: none;
    }

    .menu__link.is-current,
    .menu__link.is-ancestor {
        text-decoration: underline 3px var(--ap-maroon);
        text-underline-offset: 0.45em;
    }

    /* 48px wide and the full row tall (WCAG 2.5.8 asks for 24×24). */
    .menu__caret {
        align-self: stretch;
        min-width: 3rem;
        padding: 0 0.75rem;
        margin-right: -0.75rem;
        border-left: 1px solid rgba(0, 0, 0, 0.08);
    }

    .submenu {
        position: static;
        flex-basis: 100%;
        background: none;
        padding: 0 0 0.5rem 1rem;
        display: none;
    }

    .submenu a {
        padding: 0.5rem 1rem;
        line-height: 1.5;
    }

    .submenu li:not(:last-child) > a {
        border-bottom: 0;
    }

    .menu__item.has-children.is-open > .submenu,
    html:not(.ap-js) .menu__item.has-children:focus-within > .submenu {
        display: block;
    }
}

@media (min-width: 921px) {
    .nav-toggle {
        display: none;
    }

    /* Items fill the nav row, so the dropdown hangs from the row's bottom edge
       and the whole column is the hover target — both as on the source. */
    .menu__item {
        height: var(--ap-nav-row);
        align-items: stretch;
    }

    .menu__caret .caret {
        width: 0.75rem;
        height: 0.75rem;
    }
}

/* ===========================================================================
   Home page — page-builder blocks
   =========================================================================== */

/* --- 1. Hero (section.site-intro headings on the source) ------------------ */

/* Content widths on the homepage, the Contact band and the footer all use the
   theme's `.inner-wrap`, like the inner pages and the header: a BORDER-BOX
   70.5em (1128px) wrap with 1em gutters, 1.5em from 40em — 1080px of content
   starting at x=93 in a 1280px window, as on the source. (Content-box plus
   1rem gave 1128px of content at x=69.) Top padding is the source's
   `.site-intro .inner-wrap`: 1.5em, 1.8125em from 64em. */
.ap-hero .block--section__inner {
    box-sizing: border-box;
    max-width: var(--ap-max);
    margin-inline: auto;
    padding: 1.5rem var(--ap-gutter) 0.25rem;
    text-align: center;
}

.ap-hero__text h1 {
    font-size: 1.875rem;
    line-height: 1.5;
    font-weight: 800;
    text-transform: uppercase;
    margin: 0 0 10px;
}

.ap-hero__text h2 {
    font-size: 1.375rem;
    line-height: 1.5;
    font-weight: 500;
    text-transform: none;
    color: var(--ap-ink);
    margin: 0;
}

@media (min-width: 60em) {
    .ap-hero__text h1 {
        font-size: 2.5rem;
    }
}

@media (min-width: 64em) {
    .ap-hero .block--section__inner {
        padding-top: 1.8125rem;
    }

    .ap-hero__text h1 {
        font-size: 2.875rem;
    }
}

/* --- 2. Intro video + the 8 capability items ------------------------------ */

.ap-features {
    /* border-box, or the 1rem gutters are ADDED to the block's full width and
       the page picks up 32px of horizontal scroll below 1160px. This is the one
       .ap-* wrapper that is a top-level page-builder child with no width
       constraint above it, so it is the only one that overflowed. */
    box-sizing: border-box;
    max-width: var(--ap-max);
    margin-inline: auto;
    padding: 1.875rem var(--ap-gutter) 4.25rem;
}

.ap-features > .block--column-multi {
    gap: 2rem;
    align-items: center;
}

/* Single column until there is room for the video beside the list. */
@media (max-width: 63.99em) {
    .ap-features > .block--column-multi.block--layout-1fr-1fr {
        grid-template-columns: 1fr;
    }
}

/* The source's `.si-video-wrap`: 47.25% wide with a 5.5% gutter, so 510px of
   video in the 1080px wrap; its two `.si-list-wrap`s split the other half
   with the same 5.5%-of-the-wrap gutter (11.64% of that half). */
@media (min-width: 64em) {
    .ap-features > .block--column-multi {
        gap: 3rem 5.5%;
    }
}

/* Video — square corners like the source poster, not shared.css's 8px radius. */
.ap-features__video .video-embed__ratio {
    border-radius: 0;
}

.ap-features__video .video-embed__play {
    background: rgba(0, 0, 0, 0.55);
}

.ap-features__video .video-embed__play:hover {
    background: var(--ap-blue);
}

/* Capability list. shared.css renders card-grid items as padded white cards in
   a 4-up flex row; the source is a flat 2-column list of icon + ruled label.
   The shared rules are `.block--card-grid:not(...):not(...) .block--card-grid__*`
   (specificity 0,4,0), so these selectors match that weight and win on order. */
.page-builder .ap-features__list.block--card-grid .block--card-grid__wrapper {
    display: grid;
    grid-template-columns: 1fr;
    justify-content: start;
    column-gap: 2rem;
    row-gap: 1.3125rem;
}

.page-builder .ap-features__list.block--card-grid .block--card-grid__item {
    display: grid;
    grid-template-columns: 2.9375em 1fr;
    align-items: center;
    flex: none;
    background: none;
    border-radius: 0;
    box-shadow: none;
    padding: 0;
}

/* Decorative capability marks. The source uses Private Use Area glyphs from the
   theme's own icon font, which cannot be migrated — these are stand-in line
   icons drawn in the theme blue, added via ::before so they are not announced.
   Order matches ApController::FEATURES. */
.ap-features__list .block--card-grid__item::before {
    content: "";
    width: 1.75rem;
    height: 1.75rem;
    background: no-repeat center / contain;
}

/* 1. Engineering and Design — drafting compass */
.ap-features__list .block--card-grid__item:nth-child(1)::before {
    background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%2300529c'%20stroke-width='1.7'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Ccircle%20cx='12'%20cy='4.2'%20r='1.7'/%3E%3Cpath%20d='M10.7%205.7%206%2020.5'/%3E%3Cpath%20d='m13.3%205.7%204.7%2014.8'/%3E%3Cpath%20d='M8.6%2014h6.8'/%3E%3C/svg%3E");
}

/* 2. In House Tooling — wrench */
.ap-features__list .block--card-grid__item:nth-child(2)::before {
    background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%2300529c'%20stroke-width='1.7'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M15.6%204.2a4.4%204.4%200%200%200-5.9%205.6L3.6%2015.9a1.8%201.8%200%200%200%200%202.5l2%202a1.8%201.8%200%200%200%202.5%200l6.1-6.1a4.4%204.4%200%200%200%205.6-5.9l-2.8%202.8-2.6-.7-.7-2.6z'/%3E%3C/svg%3E");
}

/* 3. Solid Rod Capabilities — solid rod */
.ap-features__list .block--card-grid__item:nth-child(3)::before {
    background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%2300529c'%20stroke-width='1.7'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Crect%20x='2.6'%20y='8.6'%20width='18.8'%20height='6.8'%20rx='3.4'/%3E%3Cpath%20d='M9%208.6v6.8'/%3E%3C/svg%3E");
}

/* 4. Profile Capabilities — extruded profile shapes */
.ap-features__list .block--card-grid__item:nth-child(4)::before {
    background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%2300529c'%20stroke-width='1.7'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Crect%20x='3.2'%20y='3.6'%20width='7'%20height='7'%20rx='1'/%3E%3Ccircle%20cx='17.2'%20cy='7.1'%20r='3.5'/%3E%3Cpath%20d='M6.7%2013.4%203.2%2020.4h7z'/%3E%3Crect%20x='13.7'%20y='13.6'%20width='7'%20height='6.8'%20rx='1'/%3E%3C/svg%3E");
}

/* 5. Custom Tubing Capabilities — tube section */
.ap-features__list .block--card-grid__item:nth-child(5)::before {
    background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%2300529c'%20stroke-width='1.7'%3E%3Ccircle%20cx='12'%20cy='12'%20r='8.2'/%3E%3Ccircle%20cx='12'%20cy='12'%20r='3.6'/%3E%3C/svg%3E");
}

/* 6. Value Added Operations — gear */
.ap-features__list .block--card-grid__item:nth-child(6)::before {
    background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%2300529c'%20stroke-width='1.7'%20stroke-linecap='round'%3E%3Ccircle%20cx='12'%20cy='12'%20r='3.1'/%3E%3Cpath%20d='M12%202.6v2.3M12%2019.1v2.3M4.4%204.4l1.7%201.7M17.9%2017.9l1.7%201.7M2.6%2012h2.3M19.1%2012h2.3M4.4%2019.6l1.7-1.7M17.9%206.1l1.7-1.7'/%3E%3C/svg%3E");
}

/* 7. Quality Assurance — checked shield */
.ap-features__list .block--card-grid__item:nth-child(7)::before {
    background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%2300529c'%20stroke-width='1.7'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M12%202.8%204.6%206v5.6c0%204.4%203.1%208.1%207.4%209.6%204.3-1.5%207.4-5.2%207.4-9.6V6z'/%3E%3Cpath%20d='m8.8%2012.2%202.3%202.3%204.1-4.7'/%3E%3C/svg%3E");
}

/* 8. Just In Time Delivery — delivery truck */
.ap-features__list .block--card-grid__item:nth-child(8)::before {
    background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%2300529c'%20stroke-width='1.7'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Crect%20x='2.4'%20y='6.2'%20width='10.6'%20height='9.4'%20rx='1'/%3E%3Cpath%20d='M13%209.5h3.7l3.9%203.4v2.7H13z'/%3E%3Ccircle%20cx='6.7'%20cy='18'%20r='1.9'/%3E%3Ccircle%20cx='16.8'%20cy='18'%20r='1.9'/%3E%3C/svg%3E");
}

.ap-features__list .block--card-grid__text {
    min-width: 0;
}

.ap-features__list .block--card-grid__title {
    font-size: 1.125rem;
    line-height: 1.5;
    font-weight: 800;
    text-transform: uppercase;
    text-align: left;
    color: var(--ap-ink);
    border-left: 1px solid var(--ap-rule-soft);
    padding-left: 0.8333em;
    margin: 0;
}

/* Two columns, filled COLUMN-FIRST (1-4 left, 5-8 right) — the source renders
   them as two separate `si-list-wrap` divs. The eight capabilities are an
   unordered set, so the visual order carrying no sequence is not a 1.3.2
   concern; the DOM order is still the authored one. */
@media (min-width: 40em) {
    .page-builder .ap-features__list.block--card-grid .block--card-grid__wrapper {
        grid-template-columns: 1fr 1fr;
        grid-template-rows: repeat(4, auto);
        grid-auto-flow: column;
    }
}

/* See the `.si-video-wrap` note above: the source's 5.5%-of-the-wrap gutter. */
@media (min-width: 64em) {
    .page-builder .ap-features__list.block--card-grid .block--card-grid__wrapper {
        column-gap: 11.64%;
    }
}

/* --- 3. Markets Served ---------------------------------------------------- */

.ap-markets {
    position: relative;
    background-size: cover;
    background-position: center;
}

/* AA: the source scrims the left half at only 28% black, which leaves the white
   headline around 2.5:1 over the bright sky in the photo. The contrast is put
   where the text is rather than over the whole photo — exactly the treatment
   (and the values) of the inner pages' photo bands; see the AA note on
   `.ap-band::before`: a 15% veil, 54% in total behind the intro text, 45%
   under the list. */
.ap-markets::before {
    content: "";
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.15);
    pointer-events: none;
}

.ap-markets__grid > .block--column-multi > .column:first-child {
    background: rgba(0, 0, 0, 0.46);
}

@media (min-width: 64em) {
    .ap-markets__grid > .block--column-multi > .column:first-child {
        background: linear-gradient(to right,
            rgba(0, 0, 0, 0) 0,
            rgba(0, 0, 0, 0.46) calc(20% - 2rem),
            rgba(0, 0, 0, 0.46) calc(100% - 7.8125rem),
            rgba(0, 0, 0, 0) 100%);
    }
}

.ap-markets .block--section__inner {
    position: relative;
}

.ap-markets__grid .block--column-multi {
    gap: 0;
}

.ap-markets__intro,
.ap-markets__list {
    height: 100%;
}

.ap-markets__intro .block--column-single__inner {
    padding: 3.5rem 1.5rem;
}

.ap-markets__intro h2 {
    font-size: 1.875rem;
    line-height: 1.5;
    font-weight: 800;
    text-transform: uppercase;
    color: #fff;
    margin: 0 0 10px;
}

.ap-markets__intro p {
    font-size: 1.5rem;
    line-height: 1.5;
    font-weight: 700;
    text-transform: uppercase;
    color: #fff;
    margin: 0;
}

/* Right-hand panel — the source paints it at 74% black; 35% on the 15% veil
   (45%) keeps it a distinct, darker panel with the photo showing through. */
.ap-markets__list {
    background: rgba(0, 0, 0, 0.35);
}

.ap-markets__list .block--column-single__inner {
    padding: 3.125rem 1.5rem;
}

/* ONE 16-item <ul>, split into two columns by CSS so the reading order stays
   correct for screen readers and editors can add a market without rebalancing. */
.ap-markets__list ul {
    columns: 2;
    column-gap: 2rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.ap-markets__list li {
    break-inside: avoid;
    font-size: 1.1875rem;   /* 19px/800 = WCAG large text (the source: 18px) — see the AA note on .ap-band::before */
    line-height: 1.4;
    font-weight: 800;
    text-transform: uppercase;
    color: #fff;
    margin: 0 0 1.75rem;
}

.ap-markets__list li:last-child {
    margin-bottom: 0;
}

/* One column on a phone — the source stacks its two 8-item lists at this width,
   and two columns inside 375px force "Lawn & Garden" / "Water Treatment" to wrap. */
@media (max-width: 39.99em) {
    .ap-markets__list ul {
        columns: 1;
    }

    .ap-markets__list li {
        margin-bottom: 1.25rem;
    }
}

/* The source's `.msm-left` widths — see the note on `.ap-band__intro`. */
@media (min-width: 60em) {
    .ap-markets__intro .block--column-single__inner {
        padding-right: 19.375rem;
    }
}

@media (min-width: 64em) {
    .ap-markets {
        /* Parallax, as on the source — but only where a pointer-driven layout
           can take it, and never when reduced motion is requested. */
        background-attachment: scroll;
    }

    .ap-markets__intro .block--column-single__inner {
        padding: 4.5rem 9.8125rem 4.5rem 20%;
    }

    .ap-markets__list .block--column-single__inner {
        padding: 5rem 2.8125rem;
    }

    .ap-markets__intro h2 {
        font-size: 2.875rem;
    }

    .ap-markets__list li {
        font-size: 1.25rem;
        margin-bottom: 2.5rem;
    }
}

@media (min-width: 64em) and (prefers-reduced-motion: no-preference) {
    .ap-markets {
        background-attachment: fixed;
    }
}

@media (max-width: 63.99em) {
    .ap-markets__grid .block--column-multi.block--layout-1fr-1fr {
        grid-template-columns: 1fr;
    }
}

/* --- 4. Contact CTA ------------------------------------------------------- */

.ap-cta {
    background: var(--ap-grey-band);
    /* The photo slides in from off to the right (see `.ap-cta__image` below).
       `clip` contains it without turning the section into a scroll container. */
    overflow-x: clip;
}

.ap-cta .block--section__inner {
    box-sizing: border-box;
    max-width: var(--ap-max);
    margin-inline: auto;
    padding: 3rem var(--ap-gutter);
    display: grid;
    gap: 1.5rem;
}

/* Selectors are `.ap-cta .block--rich-text .ap-cta__text …` (0,3,1) so they
   also win on the inner pages, where `.ap-page h2` and `.ap-page .block--rich-text p`
   (0,2,1, later in this file) would otherwise shrink the strapline to 16px grey. */
.ap-cta .block--rich-text .ap-cta__text h2 {
    font-size: 1.875rem;
    line-height: 1.1;
    font-weight: 800;
    text-transform: uppercase;
    margin: 0 0 17px;
}

/* shared.css sets `.block--rich-text p { margin-bottom: 0 !important }`, so the
   space under the CTA strapline can only be restored with !important. */
.ap-cta .block--rich-text .ap-cta__text p {
    font-size: 1.5rem;
    line-height: 1.5;
    font-weight: 700;
    text-transform: uppercase;
    color: var(--ap-ink);
    max-width: 13em;
    margin: 0 !important;
}

.ap-cta__image .standalone-image {
    display: block;
    width: 100%;
    height: auto;
}

/* Slide-in of the CTA photo — the source puts `wow slideInRight` (WOW.js +
   animate.css) on `.cum-right`, i.e. translate3d(100%,0,0) → 0 as it scrolls
   into view. Reproduced with an IntersectionObserver that adds `is-visible`
   (see templates/page-builder/_entry.twig).

   The hidden state is scoped to `.ap-js`, a class the layout's head script adds
   — so with JavaScript off the photo is simply there, never an invisible image
   waiting for an observer that will never run. Under reduced motion it also
   renders in its final state immediately.

   Two-column layout (≥60em) only. Once the CTA stacks, the photo is full width,
   so translateX(100%) parks it entirely off-screen inside the clipped band and the
   observer (threshold 0.15) never sees it — the photo stayed invisible on tablets
   and phones. Below 60em it simply renders in place. */
@media (min-width: 60em) {
    .ap-js .ap-cta__image {
        opacity: 0;
        transform: translateX(100%);
        transition: opacity 0.7s ease-out, transform 0.7s ease-out;
        will-change: opacity, transform;
    }

    .ap-js .ap-cta__image.is-visible {
        opacity: 1;
        transform: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .ap-js .ap-cta__image,
    .ap-js .ap-cta__image.is-visible {
        opacity: 1;
        transform: none;
        transition: none;
    }
}

/* Button — Oswald, uppercase, tracked, dark with the theme's yellow label
   (#fcbf00 on #2b2c2a = 8.2:1). */
.ap-btn {
    display: inline-block;
    font-family: var(--ap-font-head);
    font-size: 1.0625rem;
    font-weight: 500;
    line-height: normal;
    letter-spacing: 2px;
    text-transform: uppercase;
    text-decoration: none;
    padding: 0.4118em 1em;
    border: 2px solid var(--ap-ink-dark);
    border-radius: 0;
    background: var(--ap-ink-dark);
    color: var(--ap-yellow);
    /* Source: `.btn { transition: background 0.1s linear }`. */
    transition: background-color 0.1s linear, color 0.1s linear, border-color 0.1s linear;
}

/* Hover animation, ported from `.cum-btn` in the source theme: the fill drops
   out to the page colour, the label flips to the dark ink, and a glyph that is
   collapsed to zero width grows in beside it (`opacity 0 → 1`,
   `width 0 → auto`, `margin-left 0 → 0.2941em`, `transition: all 0.2s`).

   THE GLYPH. The source marks it up as `<span class="module-icon">9</span>`:
   the character `9` (U+0039) rendered in the theme's own private icon font
   `Conv_modules` (wp-content/themes/appliedplasticsinc-default/fonts/modules.*),
   where that slot holds a DOUBLE chevron — two right-pointing angle brackets,
   nested, with squared-off arm ends and a slightly rounded outer apex, no
   crossbars. The `d` below is that glyph's outline lifted verbatim from
   modules.svg (FontForge SVG font, 1024 upem; `translate(0 960)scale(1 -1)`
   flips the font's y-up coordinates into SVG's y-down, and the viewBox is the
   glyph's own ink bbox 285,266 483x494). So the shape is the source's, not an
   approximation of it — earlier this was a single Lucide-style chevron, which
   is what the owner flagged.

   It is a decorative ::after with an empty `content`, so nothing extra is
   announced. It is only ever visible over the light (hover/focus) state, so it
   is filled in the ink colour — same 12.4:1 as the label, contrast unchanged.
   Box is 0.5em tall to match the glyph's own 494/1024 em at the button's
   1.0625rem, and `vertical-align` reproduces its natural baseline position
   (ink sits 200..694 font units above the baseline). */
.ap-btn::after {
    content: "";
    display: inline-block;
    vertical-align: 0.19em;
    height: 0.4824em;
    width: 0;
    margin-left: 0;
    opacity: 0;
    background: no-repeat center / contain url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='285%20266%20483%20494'%3E%3Cpath%20transform='translate(0%20960)scale(1%20-1)'%20fill='%232b2c2a'%20d='M759,470l-190,214c-6,6.67-13.5,10-22.5,10s-16.5-3.33-22.5-10c-6.67-6-10-13.5-10-22.5s3.33-16.5,10-22.5l169-192l-169-192c-6.67-6-10-13.5-10-22.5s3.33-16.5,10-22.5c6-6.67,13.5-10,22.5-10s16.5,3.33,22.5,10l190,214c2.67,2.67,4.83,6.17,6.5,10.5s2.5,8.5,2.5,12.5s-0.83,8-2.5,12s-3.83,7.67-6.5,11v0zM294,210c6.67-6.67,14.33-10,23-10s16.33,3.33,23,10l189,214c3.33,2.67,5.67,6,7,10s2,8.33,2,13c0,4-0.67,8-2,12s-3.67,7.67-7,11l-189,214c-6.67,6.67-14.33,10-23,10s-16.33-3.33-23-10c-6-6-9-13.5-9-22.5s3-16.5,9-22.5l170-192l-170-192c-6-6-9-13.5-9-22.5s3-16.5,9-22.5v0z'/%3E%3C/svg%3E");
    transition: width 0.2s, margin-left 0.2s, opacity 0.2s;
}

/* Keyboard focus gets the SAME state as hover (plus the ring below), never a
   weaker one. The source did the opposite — `.cum-btn:focus` reverted to the
   default fill — which hides the affordance from keyboard users. */
.ap-btn:hover,
.ap-btn:focus-visible {
    background: transparent;
    color: var(--ap-ink-dark); /* 12.4:1 on the #f4f4f4 band */
}

.ap-btn:hover::after,
.ap-btn:focus-visible::after {
    width: 0.4717em; /* the glyph's own 483/1024 em — keeps its aspect exactly */
    margin-left: 0.2941em;
    opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
    .ap-btn,
    .ap-btn::after {
        transition: none;
    }
}

@media (min-width: 60em) {
    .ap-cta .block--section__inner {
        grid-template-columns: 48.5% 48.5%;
        justify-content: space-between;
        align-items: start;
        row-gap: 3rem;
        padding-top: 5.4375rem;
        padding-bottom: 4.6875rem;
    }

    .ap-cta .block--rich-text {
        grid-column: 1;
        grid-row: 1;
    }

    .ap-cta .block--button {
        grid-column: 1;
        grid-row: 2;
        align-self: start;
    }

    .ap-cta__image {
        grid-column: 2;
        grid-row: 1 / span 2;
        align-self: center;
    }

    .ap-cta .block--rich-text .ap-cta__text h2 {
        font-size: 2.375rem;
    }
}

/* --- 5. Product photo strip ----------------------------------------------- */

/* A carousel, like the source's Slick instance: a row of N photos that steps
   one slide at a time and loops endlessly in both directions. N and the row
   height are the source's own settings —
     slidesToShow  5 (>1410px) / 4 (≤1410) / 3 (≤961) / 2 (≤641) / 1 (≤600)
     row height    17.5em (<40em) / 15em (≥40em) / 12em (≥64em) / 16.375em (≥80em)
   — and the clones/arrows/autoplay/drag live in
   templates/page-builder/blocks/blockSlider.twig.

   TWO STATES. Without JS the track is exactly what the markup says it is, a
   horizontal scroll container. Once the script has cloned the ends it adds
   `.is-carousel` and the track becomes a transform-translated strip; that is
   the state the loop and the 500ms Slick-speed transition belong to. */

.ap-products {
    background: var(--ap-ink-dark);
}

.ap-products .pb-slider {
    --tile-w: auto;
    --gap: 0px;
    --center-padding: 0px;
    position: relative;
    /* The viewport. Also in shared.css, but the carousel depends on it, so it
       is not left to a cross-domain stylesheet. */
    overflow: hidden;
}

.ap-products .pb-slider__track {
    display: flex;
    flex-wrap: nowrap;
    align-items: stretch;
    gap: 0;
    /* No-JS fallback only — replaced below once .is-carousel lands. */
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -ms-overflow-style: none;
    scrollbar-width: none;
}

.ap-products .pb-slider__track::-webkit-scrollbar {
    display: none;
}

/* JS carousel. The strip overflows the viewport to the right and is moved by
   `translate3d`; 0.5s ease is Slick's default `speed`/`cssEase`. */
.ap-products .pb-slider.is-carousel .pb-slider__track {
    overflow: visible;
    scroll-snap-type: none;
    transition: transform 0.5s ease;
    will-change: transform;
}

/* Reduced motion: the script also forces a 0ms duration and never autoplays,
   so every move is an instant jump. This is belt and braces. */
@media (prefers-reduced-motion: reduce) {
    .ap-products .pb-slider.is-carousel .pb-slider__track {
        transition: none;
    }
}

/* Fewer slides than fit on screen → no carousel at all, and the decorative
   duplicates come out of the layout entirely. */
.ap-products .pb-slider.is-static .pb-slider__slide--clone {
    display: none;
}

/* Grab affordance, and let a vertical swipe still scroll the page while a
   horizontal one drags the strip (same contract as the LLC marquees). */
.ap-products .pb-slider.is-carousel:not(.is-static) {
    cursor: grab;
    touch-action: pan-y;
}

.ap-products .pb-slider.is-dragging {
    cursor: grabbing;
    user-select: none;
}

.ap-products .pb-slider__slide img {
    -webkit-user-drag: none;
    user-select: none;
}

/* The slides are sized as a PERCENTAGE of the track, which is what keeps the
   slide width and the breakpoint's slidesToShow in lockstep — the script reads
   the rendered width back out of the DOM rather than duplicating the table. */
.ap-products .pb-slider__slide {
    flex: 0 0 100%;
    max-width: 100%;
    width: auto;
    height: 17.5rem;
    scroll-snap-align: start;
}

.ap-products .pb-slider__img,
.ap-products picture.pb-slider__img {
    height: 100%;
    width: 100%;
}

.ap-products img.pb-slider__img {
    height: 100%;
    width: 100%;
    object-fit: cover;
    display: block;
}

/* The carousel region takes keyboard focus (Left/Right/Home/End), so it needs a
   ring; white over the photographs, inset so the viewport's own overflow
   clipping can't eat it. */
.ap-products .pb-slider:focus-visible {
    outline: 3px solid #fff;
    outline-offset: -3px;
}

@media (min-width: 37.5625em) { /* >600px — slick's 2-up */
    .ap-products .pb-slider__slide {
        flex-basis: 50%;
        height: 15rem;
    }
}

@media (min-width: 40.0625em) { /* >641px — 3-up */
    .ap-products .pb-slider__slide {
        flex-basis: 33.3333%;
    }
}

@media (min-width: 60.0625em) { /* >961px — 4-up */
    .ap-products .pb-slider__slide {
        flex-basis: 25%;
        height: 12rem;
    }
}

@media (min-width: 80em) { /* ≥1280px — the source's taller band */
    .ap-products .pb-slider__slide {
        height: 16.375rem;
    }
}

@media (min-width: 88.1875em) { /* >1410px — 5-up */
    .ap-products .pb-slider__slide {
        flex-basis: 20%;
    }
}

/* Arrows — the source's 48x48 `slick-prev` / `slick-next` at 22px from each
   edge. AA: the source fades them out entirely above 1280px until the strip is
   hovered, which hides the control from keyboard and touch users; here they are
   always visible, on a dark disc that carries the white chevron at ~13:1 over
   any of the photographs. */
.ap-products .pb-slider__arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    width: 48px;
    height: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 0;
    padding: 0;
    appearance: none;
    cursor: pointer;
    font: inherit;
    color: inherit;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.55);
    transition: background-color 0.2s ease-in-out;
}

.ap-products .pb-slider__arrow:hover {
    background: rgba(0, 0, 0, 0.8);
}

.ap-products .pb-slider__arrow[hidden] {
    display: none;
}

.ap-products .pb-slider__arrow--prev {
    left: 22px;
}

.ap-products .pb-slider__arrow--next {
    right: 22px;
}

.ap-products .pb-slider__arrow-icon {
    width: 30px;
    height: 30px;
    background: no-repeat center / contain
        url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23ffffff'%20stroke-width='2.2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='m9%205%207%207-7%207'/%3E%3C/svg%3E");
}

.ap-products .pb-slider__arrow--prev .pb-slider__arrow-icon {
    transform: scaleX(-1);
}

/* Over photographs, per ACCESSIBILITY.md. */
.ap-products .pb-slider__arrow:focus-visible {
    outline: 3px solid #fff;
    outline-offset: 2px;
    background: rgba(0, 0, 0, 0.8);
}

@media (prefers-reduced-motion: reduce) {
    .ap-products .pb-slider__arrow {
        transition: none;
    }
}

/* Phones: keep the arrows clear of the photo edges but still tappable. */
@media (max-width: 37.5em) {
    .ap-products .pb-slider__arrow--prev {
        left: 10px;
    }

    .ap-products .pb-slider__arrow--next {
        right: 10px;
    }
}

/* --- Footer --------------------------------------------------------------- */

.site-footer {
    background: var(--ap-footer-bg);
    color: #e6e6e6;
}

/* The source's `.sf-footer .inner-wrap`: address, then contact details, then the
   logo slot pushed to the right edge. Flex rather than an equal-column grid, so
   the two text blocks keep their natural width instead of each claiming half the
   footer when there is no logo — and so they simply stack on a phone. */
.footer-inner {
    box-sizing: border-box;
    max-width: var(--ap-max);
    margin-inline: auto;
    padding: 3rem var(--ap-gutter) 2rem;
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 1.5rem 4rem;
}

.footer-col {
    min-width: 0;
}

/* TRG logo, first column — 100px wide like FinishTek / Rowlam / Rowmark. The
   white SVG on --ap-footer-bg is far past the 3:1 non-text minimum. */
.footer-trg {
    display: inline-block;
    border-radius: 2px;
}

.footer-trg__logo {
    display: block;
    width: 100px;
    height: auto;
}

/* Only rendered when an editor has set `footerLogo`; pushed to the right edge
   the way the source's (empty) logo slot is. */
.footer-col--logo {
    margin-left: auto;
}

.footer-logo {
    display: block;
    max-width: 14rem;
    height: auto;
}

.footer-address {
    font-style: normal;
    font-size: 0.875rem;
    line-height: 1.7;
    color: #e6e6e6;
    margin: 0;
}


.footer-contact {
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 0.875rem;
    line-height: 1.7;
    color: #e6e6e6;
}

.footer-contact li {
    margin-bottom: 0.375rem;
}

/* AA: the source sets footer links to #666 on #222 (2.2:1). White clears 15:1
   and keeps the link visually distinct from the surrounding copy. */
.footer-contact a {
    display: inline-block;
    color: #fff;
    font-weight: 700;
    text-decoration: none;
}

.footer-contact a:hover {
    text-decoration: underline;
}

/* Bottom bar — the source's `.sf-small-footer`: rgba(0,0,0,.32) over the footer
   colour, 0.9375em of padding, and the links row centred at every width (its
   `.sf-copyright` span is `text-align: center` even where the bar goes left). */
.footer-bottom {
    background: rgba(0, 0, 0, 0.32);
    font-size: 0.875rem;
}

.footer-bottom__inner {
    box-sizing: border-box;
    max-width: var(--ap-max);
    margin-inline: auto;
    padding: 0.9375rem var(--ap-gutter);
}

/* The theme's `.inner-wrap` gutter steps up to 1.5em from 40em (see the note
   on `.ap-hero` above). After every rule it adjusts, so the shorthands above
   cannot undo it. */
@media (min-width: 40em) {
    .ap-hero .block--section__inner,
    .ap-features,
    .ap-cta .block--section__inner,
    .footer-inner,
    .footer-bottom__inner {
        padding-left: 1.5rem;
        padding-right: 1.5rem;
    }
}

/* Legal links row ("Sitemap | Privacy Policy | Terms of Service"). The "|"
   separators are CSS borders, never text — a pipe inside the link label would
   be read out by screen readers and would end up in the CMS content. */
.footer-legal__list {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    margin: 0;
    padding: 0;
    list-style: none;
    line-height: 1.7;
}

.footer-legal__list li + li {
    margin-left: 0.75rem;
    padding-left: 0.75rem;
    border-left: 1px solid rgba(255, 255, 255, 0.45);
}

/* AA: the source sets these to #666 on the dark bar (≈2.4:1). White is ≈17:1. */
.footer-legal__list a {
    display: inline-block;
    color: #fff;
    font-weight: 700;
    text-decoration: none;
}

.footer-legal__list a:hover {
    text-decoration: underline;
}

.footer-legal__list a:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
}

/* --- Guard shown until a `home-page` entry exists -------------------------- */

.no-home-guard {
    max-width: 45rem;
    margin-inline: auto;
    padding: 4rem 1.5rem;
    text-align: center;
}

/* ===========================================================================
   Inner pages — page-builder blocks
   ===========================================================================

   Body class `landing-page page`, builder wrapper `.page-builder.ap-page
   .ap-page--{slug}`. Hooks come from each block's `customCssClasses` (see
   ApController::PAGES and its blocks*() methods):

     .ap-hero-band  .ap-hero-band__text            every page's photo banner
     .ap-article (.--legal .--bare)  .ap-article__text  .ap-lead
     .ap-intro  .ap-intro__text
     .ap-buckets  .ap-bucket  .ap-bucket__head  .ap-bucket__img  .ap-bucket__body
     .ap-band  .ap-band__grid  .ap-band__intro-stack  .ap-band__intro
       .ap-band__cta  .ap-band__list
     .ap-srow (.--flip)  .ap-srow__text  .ap-srow__cta  .ap-srow__img(--1|--2)
     .ap-qa  .ap-qa__heading  .ap-qa__video  .ap-qa__split  .ap-qa__img
       .ap-qa__text  .ap-qa__desc
     .ap-figure (.--flip)  .ap-figure__img  .ap-figure__text
     .ap-accordion
     .ap-table-section  .ap-table
     .ap-inline-video

   Values are the source theme's own (style.css: .page-intro, .mcm-*, .cbm-*,
   .sbm-*, .msm-*, .qam-*, .tabular-data, .accordion-tabs). Departures are all
   accessibility fixes and are marked "AA:".
   --------------------------------------------------------------------------- */

/* --- Shared container ----------------------------------------------------- */

/* The theme's `.inner-wrap`: 70.5em wide, 1em gutters (1.5em from 40em). */
.ap-page .ap-article > .block--section__inner,
.ap-page .ap-intro > .block--section__inner,
.ap-page .ap-qa > .block--section__inner,
.ap-page .ap-table-section > .block--section__inner,
.ap-page > .ap-buckets,
.ap-page .ap-srow > .block--section__inner {
    box-sizing: border-box;
    max-width: var(--ap-max);
    margin-inline: auto;
    padding: 1.5rem var(--ap-gutter);
}

@media (min-width: 40em) {
    .ap-page .ap-article > .block--section__inner,
    .ap-page .ap-intro > .block--section__inner,
    .ap-page .ap-qa > .block--section__inner,
    .ap-page .ap-table-section > .block--section__inner,
    .ap-page > .ap-buckets,
    .ap-page .ap-srow > .block--section__inner {
        padding: 2.5rem 1.5rem;
    }
}

/* --- Prose ---------------------------------------------------------------- */

/* shared.css sets `.block--rich-text p { margin-bottom: 0 !important }`, so the
   paragraph rhythm these pages need can only be restored with !important. */
.ap-page .block--rich-text p,
.ap-page .block--column-single p {
    font-size: 1rem;
    line-height: 1.5;
    color: var(--ap-body);
    margin: 1rem 0 !important;
}

.ap-page .block--rich-text > div > *:first-child,
.ap-page .block--column-single__inner > *:first-child {
    margin-top: 0 !important;
}

.ap-page .block--rich-text > div > *:last-child,
.ap-page .block--column-single__inner > *:last-child {
    margin-bottom: 0 !important;
}

/* In-article <h1> — About Us and Privacy Policy have no photo banner, so their
   page title sits in the prose column. The theme's own h1 scale. */
.ap-page .ap-article__text h1 {
    font-size: 1.875rem;
    line-height: 1.25;
    font-weight: 800;
    text-transform: uppercase;
    color: var(--ap-ink);
    margin: 0 0 24px;
}

.ap-page h2 {
    font-size: 1.875rem;
    line-height: 1.1;
    font-weight: 800;
    text-transform: uppercase;
    color: var(--ap-ink);
    margin: 2rem 0 0.625rem;
}

/* AA: the source sets h3 to 0.984em — SMALLER than its own body copy, so a
   subheading reads as less important than the text beneath it. Floored at
   1.125rem so the hierarchy is visible as well as programmatic. */
.ap-page h3 {
    font-size: 1.125rem;
    line-height: 1.3;
    font-weight: 700;
    text-transform: none;
    color: var(--ap-ink);
    margin: 1.75rem 0 0.625rem;
}

.ap-page ul,
.ap-page ol {
    margin: 1rem 0;
    padding-left: 1.25rem;
    color: var(--ap-body);
}

.ap-page li {
    line-height: 1.5;
    margin-bottom: 0.375rem;
}

/* Body links — the theme's own #86003b (8.6:1 on white), underlined so colour
   is never the only cue (WCAG 1.4.1). */
.ap-page .block--rich-text a,
.ap-page .block--column-single a {
    color: #86003b;
    text-decoration: underline;
}

.ap-page .block--rich-text a:hover,
.ap-page .block--column-single a:hover {
    color: #3a0019;
}

.ap-page .block--rich-text a:focus-visible,
.ap-page .block--column-single a:focus-visible {
    outline: 2px solid var(--ap-blue);
    outline-offset: 2px;
}

@media (min-width: 40em) {
    .ap-page .ap-article__text h1 { font-size: 2.25rem; }
}

@media (min-width: 60em) {
    .ap-page .ap-article__text h1 { font-size: 2.5rem; }
    .ap-page h2 { font-size: 2.25rem; }
    /* The source's desktop h3 is 1.6875em (27px). */
    .ap-page h3 { font-size: 1.6875rem; }
}

@media (min-width: 64em) {
    .ap-page h2 { font-size: 2.375rem; }
}

/* --- Photo banner (the theme's `.page-intro`) ------------------------------ */

.ap-hero-band {
    position: relative;
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    text-align: center;
}

/* AA, without darkening the whole photograph. The source lays white text
   straight onto the photo (no scrim); a 50% scrim over the whole banner fixed
   that but made every photo dull. Instead the contrast is put WHERE THE TEXT
   IS (2026-09-23):

     · a 15% veil over the whole banner (the photo reads almost as on the source);
     · a feathered 38% panel behind the text block only — the text wrapper is
       shrink-wrapped to its widest line and its ::before paints a soft-edged
       box 1rem/2rem beyond it (plus a 1.5rem solid box-shadow spread and a
       2.5rem blur), so every glyph sits on the solid part: 15% + 38% = 47%.

   Measured against the photos themselves (4x4px-averaged pixels, and with the
   fixed / parallax attachment every row of the photo the text can scroll
   over), 47% keeps white text at ≥3.6:1 over the BRIGHTEST pixel of every
   current banner — pure white in several of them — which is the 3:1 that the
   large text here needs: the 50px/800 heading, and the subheading at
   1.1875rem/700 (19px bold is WCAG large text; the source's 18px is not, and
   would need 4.5:1, i.e. 54% over pure white). A banner photo swapped in the CP
   gets the same guarantee, since 47% is what pure white needs. */
.ap-hero-band {
    overflow: hidden;       /* the text panel's feather must not widen the page */
    overflow: clip;
}

.ap-hero-band::before {
    content: "";
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.15);
    pointer-events: none;
}

.ap-hero-band__text {
    position: relative;
    z-index: 0;             /* own stacking context: the panel sits behind the text */
    width: fit-content;
    max-width: 100%;
    margin-inline: auto;
}

.ap-hero-band__text::before {
    content: "";
    position: absolute;
    z-index: -1;
    inset: -1rem -2rem;
    border-radius: 3rem;
    background: rgba(0, 0, 0, 0.38);
    box-shadow: 0 0 2.5rem 1.5rem rgba(0, 0, 0, 0.38);
    pointer-events: none;
}

.ap-hero-band > .block--section__inner {
    position: relative;
    box-sizing: border-box;
    max-width: var(--ap-max);
    margin-inline: auto;
    padding: 4.125rem var(--ap-gutter) 5.3125rem;
}

.ap-hero-band__text h1 {
    font-size: 1.875rem;
    line-height: 1.4;
    font-weight: 800;
    text-transform: uppercase;
    color: #fff;
    margin: 0 0 10px;
}

/* 1.1875rem, not the source's 1.125rem: see the AA note above — 19px bold is
   large text, so the banner panel can stay at 47% instead of 54%. */
.ap-hero-band__text p {
    font-size: 1.1875rem !important;
    line-height: 1.5;
    font-weight: 700;
    text-transform: uppercase;
    color: #fff !important;
    margin: 0 !important;
}

@media (min-width: 40em) {
    .ap-hero-band > .block--section__inner {
        padding: 5.25rem 1.5rem 6rem;
    }
}

@media (min-width: 60em) {
    .ap-hero-band > .block--section__inner {
        padding: 6.6875rem 1.5rem 6.8125rem;
    }

    .ap-hero-band__text h1 { font-size: 2.5rem; }
}

@media (min-width: 64em) {
    .ap-hero-band > .block--section__inner {
        padding: 9.3125rem 1.5rem 8.125rem;
    }

    .ap-hero-band__text h1 { font-size: 3.125rem; }
}

/* Banner → first line of content, matched to the source page by page (1280px,
   measured 2026-09-23). The theme-module pages (Capabilities, Quality,
   Careers, Sitemap) sit at the container's own 2.5rem = 40px, as here. The
   pages whose body is WordPress editor content start 16px under the banner
   (Custom Plastic Extrusions, Tooling Design, Terms of Service); Materials'
   intro sits at 56px; the Services rows at 82px. Keyed on the builder
   wrapper's `ap-page--{slug}` class. */
@media (min-width: 40em) {
    .ap-page--custom-plastic-extrusions .ap-hero-band + .block--section > .block--section__inner,
    .ap-page--tooling-design-custom-plastic-extrusions .ap-hero-band + .block--section > .block--section__inner,
    .ap-page--terms-of-service .ap-hero-band + .block--section > .block--section__inner {
        padding-top: 1rem;
    }

    .ap-page--materials .ap-hero-band + .block--section > .block--section__inner {
        padding-top: 3.5rem;
    }
}

@media (min-width: 64em) {
    .ap-page--services .ap-hero-band + .ap-srow > .block--section__inner {
        padding-top: 5.125rem;
    }
    /* live: rows sit 100px apart after the first (dev was 80) */
    .ap-page--services .ap-srow + .ap-srow > .block--section__inner {
        padding-top: 3.75rem;
    }
}

/* Parallax, as on the source — wide pointer layouts only, and never under
   reduced motion (the same contract as the homepage's Markets band). */
@media (min-width: 80em) and (prefers-reduced-motion: no-preference) {
    .ap-hero-band { background-attachment: fixed; }
}

/* --- Article / intro prose column ----------------------------------------- */

/* No measure of its own: prose runs the full `--ap-max` container (1080px of
   text), as on the source and as the other Craft sites' text pages do (rowlam
   1160px, finishtek 1140px, accent 1200px). A 50rem cap here made every inner
   page 30-40% longer than the source. */

/* The first heading in a section should not push away from the band above it —
   the section padding already provides that space. */
.ap-page .ap-article > .block--section__inner > .block:first-child h2,
.ap-page .ap-intro__text h2 {
    margin-top: 0;
}

.ap-page .ap-lead p {
    font-size: 1.125rem !important;
}

/* About Us carries nothing but its heading and the Materials Consult form, and
   (like the source) no Contact band after it, so the form's own bottom margin
   and the section padding are what separate it from the footer. */
.ap-page .ap-article--bare .ap-hubspot-form {
    margin-bottom: 0;
}

/* --- Capability buckets (the theme's `.capabilities-bucket-module`) -------- */

.ap-page > .ap-buckets {
    padding-top: 0;
}

.ap-buckets > .block--column-multi {
    gap: 3.125rem;
}

@media (max-width: 59.99em) {
    .ap-buckets > .block--column-multi.block--layout-1fr-1fr-1fr {
        grid-template-columns: 1fr;
    }
}

.ap-bucket > .block--column-multi {
    gap: 0;
}

.ap-bucket__head h2 {
    margin: 0 0 27px;
}

/* The source frames each photo in a 4px outset white border. */
.ap-bucket__img.block--image {
    margin: 0 0 1.875rem;
}

.ap-bucket__img .block--image__wrapper {
    border: 4px outset #fff;
    overflow: hidden;
}

.ap-bucket__img .standalone-image,
.ap-bucket__img picture.standalone-image {
    display: block;
    width: 100%;
    height: auto;
    border-radius: 0;
}

.ap-bucket__body ul {
    margin: 0;
}

/* --- Photo band (the theme's `.market-served-module`) ---------------------
   The same module as the homepage's Markets Served band, so the values match
   `.ap-markets` exactly — including the AA scrim that replaces the source's
   28% one. The only addition is the band's optional button (Quality's "View
   Material Comparison Chart"), which the homepage band does not have.
   -------------------------------------------------------------------------- */

.ap-band {
    position: relative;
    background-size: cover;
    background-position: center;
}

/* AA, without darkening the whole photograph (2026-09-23). The source scrims
   the left half at 28% and paints the list panel at 74%; a 55% scrim over the
   whole band (≈80% under the list) passed AA but made the photo dull. Now the
   contrast sits where the text is:

     · a 15% veil over the whole band;
     · + 46% in a vertical stripe behind the intro column's text (from 64em a
       gradient that is solid from 2rem before the text column to 2rem after it
       and fades to nothing at the column edges; below 64em, where the intro
       spans the band, flat) → 54% under the heading, copy and button;
     · + 35% on the list panel → 45% under the list.

   Those totals are what PURE WHITE behind the text needs — 54% keeps 18px
   regular copy at ≥4.6:1, 45% keeps the list labels at ≥3.3:1 (they are
   large text: 19px/800 below 64em — the source's 18px is not — and 20px/800
   above) — so they hold for any photo an editor swaps in, whichever row the
   fixed (parallax) background puts under the text. The rest of the photo
   shows at 15%. Same values on the homepage's `.ap-markets`. */
.ap-band::before {
    content: "";
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.15);
    pointer-events: none;
}

.ap-band__grid > .block--column-multi > .column:first-child {
    background: rgba(0, 0, 0, 0.46);
}

@media (min-width: 64em) {
    /* Text column = 20% in from the left, 9.8125rem in from the right (the
       intro padding below); solid 2rem either side of it. */
    .ap-band__grid > .block--column-multi > .column:first-child {
        background: linear-gradient(to right,
            rgba(0, 0, 0, 0) 0,
            rgba(0, 0, 0, 0.46) calc(20% - 2rem),
            rgba(0, 0, 0, 0.46) calc(100% - 7.8125rem),
            rgba(0, 0, 0, 0) 100%);
    }
}

.ap-band > .block--section__inner {
    position: relative;
}

.ap-band__grid .block--column-multi {
    gap: 0;
}

.ap-band__intro-stack,
.ap-band__intro,
.ap-band__list {
    height: 100%;
}

.ap-band__intro-stack > .block--column-multi {
    gap: 0;
    align-content: start;
}

.ap-band__intro .block--column-single__inner {
    padding: 3.5rem 1.5rem;
}

.ap-band__intro h2 {
    font-size: 1.875rem;
    line-height: 1.5;
    font-weight: 800;
    text-transform: uppercase;
    color: #fff;
    margin: 0 0 10px;
}

.ap-band__intro p,
.ap-band__intro li {
    color: #fff !important;
    font-size: 1.125rem !important;
    line-height: 1.5;
}

.ap-band__intro em,
.ap-band__intro strong {
    color: #fff;
}

/* The band's button is the source's `.msm-btn`: a white outline over the photo
   rather than the CTA band's dark fill. AA: focus gets the hover state plus a
   ring, where the source's `:focus` reverted to the resting state. */
.ap-band .ap-band__cta {
    padding: 0 1.5rem 3.5rem;
}

.ap-band .ap-band__cta .ap-btn {
    background: transparent;
    border-color: rgba(255, 255, 255, 0.6);
    color: #fff;
}

.ap-band .ap-band__cta .ap-btn::after {
    background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='285%20266%20483%20494'%3E%3Cpath%20transform='translate(0%20960)scale(1%20-1)'%20fill='%23ffffff'%20d='M759,470l-190,214c-6,6.67-13.5,10-22.5,10s-16.5-3.33-22.5-10c-6.67-6-10-13.5-10-22.5s3.33-16.5,10-22.5l169-192l-169-192c-6.67-6-10-13.5-10-22.5s3.33-16.5,10-22.5c6-6.67,13.5-10,22.5-10s16.5,3.33,22.5,10l190,214c2.67,2.67,4.83,6.17,6.5,10.5s2.5,8.5,2.5,12.5s-0.83,8-2.5,12s-3.83,7.67-6.5,11v0zM294,210c6.67-6.67,14.33-10,23-10s16.33,3.33,23,10l189,214c3.33,2.67,5.67,6,7,10s2,8.33,2,13c0,4-0.67,8-2,12s-3.67,7.67-7,11l-189,214c-6.67,6.67-14.33,10-23,10s-16.33-3.33-23-10c-6-6-9-13.5-9-22.5s3-16.5,9-22.5l170-192l-170-192c-6-6-9-13.5-9-22.5s3-16.5,9-22.5v0z'/%3E%3C/svg%3E");
}

.ap-band .ap-band__cta .ap-btn:hover,
.ap-band .ap-band__cta .ap-btn:focus-visible {
    background: rgba(255, 255, 255, 0.2);
    border-color: rgba(255, 255, 255, 0.6);
    color: #fff;
}

.ap-band .ap-band__cta .ap-btn:focus-visible {
    box-shadow: 0 0 0 3px #fff;
}

/* Right-hand panel — 74% black on the source. 35% on top of the 15% band veil
   = 45%: still a visibly darker panel, but the photo shows through it (see the
   AA note on `.ap-band::before`). */
.ap-band__list {
    background: rgba(0, 0, 0, 0.35);
}

.ap-band__list .block--column-single__inner {
    padding: 3.125rem 1.5rem;
}

/* ONE list, split into two columns by CSS — reading order stays correct for
   screen readers and an editor can add an item without rebalancing two lists. */
.ap-band__list ul {
    columns: 2;
    column-gap: 2rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.ap-band__list li {
    break-inside: avoid;
    font-size: 1.1875rem;   /* 19px/800 = WCAG large text (the source: 18px) — see the AA note on .ap-band::before */
    line-height: 1.4;
    font-weight: 800;
    text-transform: uppercase;
    color: #fff;
    margin: 0 0 1.75rem;
}

.ap-band__list li:last-child {
    margin-bottom: 0;
}

@media (max-width: 47.99em) {
    .ap-band__list ul { columns: 1; }
    .ap-band__list li { margin-bottom: 1.25rem; }
}

@media (max-width: 63.99em) {
    .ap-band__grid .block--column-multi.block--layout-1fr-1fr {
        grid-template-columns: 1fr;
    }
}

/* Intro column = the source's `.msm-left`: from 60em a 19.375em right pad on the
   full-width stack; from 64em half the band with 10%-of-the-BAND left padding
   and 9.8125em right, which leaves a 349px text column at 1280px, so the 46px
   heading wraps onto two lines as it does there. Here the padding sits inside
   the half-width column, so 20% of the column is the source's 10% of the band.
   Same values on the homepage's `.ap-markets__intro`. */
@media (min-width: 60em) {
    .ap-band__intro .block--column-single__inner,
    .ap-band .ap-band__cta {
        padding-right: 19.375rem;
    }
}

@media (min-width: 64em) {
    .ap-band__intro .block--column-single__inner {
        padding: 3.5rem 9.8125rem 1rem 20%;
    }

    .ap-band .ap-band__cta {
        padding: 0 9.8125rem 3.5rem 20%;
    }

    .ap-band__list .block--column-single__inner {
        padding: 5rem 2.8125rem;
    }

    .ap-band__intro h2 { font-size: 2.875rem; }
    .ap-band__list li { font-size: 1.25rem; margin-bottom: 2.5rem; }
}

@media (min-width: 64em) and (prefers-reduced-motion: no-preference) {
    .ap-band { background-attachment: fixed; }
}

/* --- Services rows (the theme's `.services-buckets-module`) ---------------
   The source floats a copy column beside two photos, the second of them
   absolutely positioned and overlapping. Reproduced as a grid: copy and button
   in one column, the two photos stacked and offset in the other, alternating
   sides row by row (`.ap-srow--flip`). The same technique as the homepage CTA
   band — every child stays a plain shared block and the layout lives here.
   -------------------------------------------------------------------------- */

.ap-srow > .block--section__inner {
    display: grid;
    gap: 1.25rem;
}

.ap-srow__text h2 {
    margin-top: 0;
}

.ap-srow .block--button {
    margin-top: 0.5rem;
}

.ap-srow .ap-srow__img.block--image {
    margin: 0;
}

.ap-srow .ap-srow__img .standalone-image,
.ap-srow .ap-srow__img picture.standalone-image {
    display: block;
    width: 100%;
    height: auto;
    border-radius: 0;
}

/* Phones and tablets: the two photos sit side by side under the copy, as they
   do on the source below 64em. */
@media (max-width: 63.99em) {
    .ap-srow > .block--section__inner {
        grid-template-columns: 1fr 1fr;
        column-gap: 1.5rem;
    }

    .ap-srow .block--rich-text,
    .ap-srow .block--button {
        grid-column: 1 / -1;
    }
}

/* Row heading: the source's `.sbm-title`, 1.875em / 2.5em (60em) / 2.875em
   (64em) on a 1.4 line. `.ap-page .ap-srow__text h2` (0,2,1) outranks the
   generic `.ap-page h2`. */
.ap-page .ap-srow__text h2 {
    line-height: 1.4;
    margin-bottom: 27px;
}

@media (min-width: 60em) {
    .ap-page .ap-srow__text h2 { font-size: 2.5rem; }
}

@media (min-width: 64em) {
    .ap-page .ap-srow__text h2 { font-size: 2.875rem; }

    /* Copy column 48.5% + 3% gap, as on the source; the photo pair shares the
       remaining 48.5%. Each photo is the source's fixed 16.25em (19.0625em from
       80em — 305px wide, 381px tall at 4:5), one at each edge of that area, so
       they OVERLAP in the middle exactly as the source's absolutely positioned
       second photo does. Both sit in the same grid cell; the later one paints
       on top, as there. */
    /* `auto 1fr`: the photo pair spans both rows and is usually taller than the
       copy. With two auto rows that surplus was shared out between them, opening
       a gap between the copy and its button; the 1fr row takes all of it, below
       the button, as on the source. */
    .ap-srow > .block--section__inner {
        grid-template-columns: 48.5% 48.5%;
        grid-template-rows: auto 1fr;
        column-gap: 3%;
        align-items: start;
        padding-top: 4rem;
        padding-bottom: 4rem;
    }

    .ap-srow .block--rich-text { grid-column: 1; grid-row: 1; }
    .ap-srow .block--button    { grid-column: 1; grid-row: 2; }

    .ap-srow .ap-srow__img.block--image {
        grid-column: 2;
        grid-row: 1 / span 2;
        width: 100%;
        max-width: 16.25rem;
    }

    /* The source drops the first photo well down the row and hangs the second
       from the top edge; the 6.25em offset is its own. */
    .ap-srow .ap-srow__img--1.block--image {
        justify-self: start;
        margin-top: 6.25rem;
    }

    .ap-srow .ap-srow__img--2.block--image {
        justify-self: end;
    }

    /* Alternate rows put the copy on the right and mirror the photo offsets. */
    .ap-srow--flip .block--rich-text { grid-column: 2; }
    .ap-srow--flip .block--button    { grid-column: 2; }
    .ap-srow--flip .ap-srow__img.block--image { grid-column: 1; }

    .ap-srow--flip .ap-srow__img--1.block--image {
        margin-top: 0;
    }

    .ap-srow--flip .ap-srow__img--2.block--image {
        margin-top: 6.25rem;
    }
}

@media (min-width: 80em) {
    .ap-srow .ap-srow__img.block--image {
        max-width: 19.0625rem;
    }
}

/* --- Quality assurance module (the theme's `.quality-assurance-module`) ---- */

/* Heading beside the video — the source's `.qam-title-video`: the heading
   (`.qam-heading`, 1.875em / 2.5em / 2.875em on a 1.4 line) in a 31.33% column,
   3% gap, the video in 65.667%; stacked below 64em. A 1fr-2fr blockColumnMulti
   whose tracks are set to the source's percentages here. */
.ap-qa__title-video {
    margin-bottom: 3.125rem;
}

.ap-qa__title-video > .block--column-multi {
    gap: 0;
    align-items: start;
}

.ap-page .ap-qa__heading h2 {
    line-height: 1.4;
    margin: 0 0 30px;
}

@media (max-width: 63.99em) {
    .ap-qa__title-video > .block--column-multi.block--layout-1fr-2fr {
        grid-template-columns: 1fr;
    }
}

@media (min-width: 60em) {
    .ap-page .ap-qa__heading h2 { font-size: 2.5rem; }
}

@media (min-width: 64em) {
    .ap-qa__title-video > .block--column-multi.block--layout-1fr-2fr {
        grid-template-columns: 31.33% 65.667%;
        column-gap: 3%;
    }

    .ap-page .ap-qa__heading h2 { font-size: 2.875rem; }
}

.ap-qa__video .video-embed__ratio {
    border-radius: 0;
}

.ap-qa__video .video-embed__play {
    background: rgba(0, 0, 0, 0.55);
}

.ap-qa__video .video-embed__play:hover {
    background: var(--ap-blue);
}

.ap-qa__split {
    margin-bottom: 3.125rem;
}

.ap-qa__split > .block--column-multi {
    gap: 1.875rem;
    align-items: start;
}

.ap-qa__img.block--image {
    margin: 0;
}

.ap-qa__img .standalone-image,
.ap-qa__img picture.standalone-image {
    display: block;
    width: 100%;
    height: auto;
    border-radius: 0;
}

@media (max-width: 63.99em) {
    .ap-qa__split > .block--column-multi.block--layout-1fr-1fr {
        grid-template-columns: 1fr;
    }

    .ap-qa__img {
        max-width: 40rem;
        margin-inline: auto;
    }
}

@media (min-width: 64em) {
    .ap-page .ap-qa__heading h2 { margin-bottom: 27px; }
    .ap-qa__split > .block--column-multi { gap: 3rem; }
}

/* --- Figure (photo beside copy) ------------------------------------------- */

.ap-figure > .block--column-multi {
    gap: 1.875rem;
    align-items: start;
}

.ap-figure__img.block--image {
    margin: 0;
}

.ap-figure__img .standalone-image,
.ap-figure__img picture.standalone-image {
    display: block;
    width: 100%;
    height: auto;
    border-radius: 0;
}

@media (max-width: 47.99em) {
    .ap-figure > .block--column-multi.block--layout-2fr-3fr,
    .ap-figure > .block--column-multi.block--layout-3fr-2fr {
        grid-template-columns: 1fr;
    }

    /* Keep the picture above the copy on a phone, flipped variant included. */
    .ap-figure--flip > .block--column-multi .column:last-child { order: -1; }
}

/* --- Inline video --------------------------------------------------------- */

.ap-inline-video.block--video-embed {
    max-width: 40rem;
    margin: 2rem auto;
}

.ap-inline-video .video-embed__ratio {
    border-radius: 0;
}

/* --- Materials accordion (the theme's `.accordion-tabs`) ------------------ */

/* Full prose width, like the text around it (see "Article / intro prose column"). */
.ap-accordion {
    margin-top: 1.5rem;
}

.ap-accordion .block--accordion__item {
    border-bottom: 1px solid var(--ap-rule);
}

.ap-accordion .block--accordion__question {
    padding: 0.875rem 0;
    font-weight: 700;
    color: var(--ap-ink);
}

.ap-accordion .block--accordion__question:hover {
    color: var(--ap-blue);
}

/* The <summary> is the control, so it carries its own visible focus ring. */
.ap-accordion .block--accordion__question:focus-visible {
    outline: 2px solid var(--ap-blue);
    outline-offset: 2px;
}

.ap-accordion .block--accordion__answer-inner p {
    margin: 0 0 1rem !important;
}

/* --- Materials comparison table ------------------------------------------- */

.ap-table-section {
    background: var(--ap-grey-band);
}

/* From 48em up the table fits its column: fixed layout with the proportions
   below, so Features (the longest lists) gets the most room and nothing is cut
   off at tablet width.

   Below 48em each row becomes a card of label/value lines, like the source's
   mobile chart. Changing `display` on table elements strips their implicit table
   roles from the accessibility tree, so the stacked view only switches on once
   the script in _layout.twig has put explicit ARIA roles back and given every
   cell its column name (`data-label`); it marks the box `.ap-table--cards`.
   Without that script the table keeps its full width and scrolls sideways, and
   the same script makes the box a focusable, labelled region so it can be
   scrolled from the keyboard (WCAG 2.1.1). */
.ap-table {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.ap-table:focus-visible {
    outline: 2px solid var(--ap-blue);
    outline-offset: 2px;
}

.ap-table table {
    width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
    background: #fff;
    font-size: 1rem;           /* the source's td size; never below body copy */
}

.ap-table thead th:nth-child(1) { width: 26%; }
.ap-table thead th:nth-child(2) { width: 22%; }
.ap-table thead th:nth-child(3) { width: 30%; }
.ap-table thead th:nth-child(4) { width: 22%; }

.ap-table caption {
    caption-side: top;
    text-align: left;
    font-size: 1rem;
    font-weight: 700;
    color: var(--ap-ink);
    padding: 0 0 0.75rem;
}

.ap-table th,
.ap-table td {
    border: 1px solid #d7d7d7;
    padding: 0.625rem 0.75rem;
    text-align: left;
    vertical-align: top;
    line-height: 1.45;
}

.ap-table thead th {
    background: var(--ap-blue);
    color: #fff;
    font-weight: 700;
    text-transform: uppercase;
}

.ap-table tbody th[scope="row"] {
    background: #f4f4f4;
    color: var(--ap-ink);
    font-weight: 700;
}

.ap-table tbody tr:nth-child(even) td {
    background: #fafafa;
}

/* Cells carry their bullet lines as bare <p>s (that is how the source stores
   them); tightened so one cell does not read as four paragraphs. */
.ap-table p {
    margin: 0 !important;
    font-size: inherit !important;
    line-height: 1.45;
}

@media (max-width: 47.99em) {
    .ap-table:not(.ap-table--cards) table {
        min-width: 46rem;
    }

    .ap-table--cards table,
    .ap-table--cards tbody,
    .ap-table--cards tr,
    .ap-table--cards th,
    .ap-table--cards td {
        display: block;
        width: auto;
    }

    .ap-table--cards caption {
        display: block;
    }

    /* Column headings move into each cell's label; keep them for screen readers. */
    .ap-table--cards thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .ap-table--cards tbody tr {
        border: 1px solid #d7d7d7;
        margin-bottom: 1rem;
    }

    .ap-table--cards tbody th,
    .ap-table--cards tbody td {
        position: relative;
        border: 0;
        border-top: 1px solid #e6e6e6;
        padding: 0.625rem 0.75rem 0.625rem 9.25rem;
    }

    .ap-table--cards tbody tr > :first-child {
        border-top: 0;
    }

    .ap-table--cards tbody th::before,
    .ap-table--cards tbody td::before {
        content: attr(data-label);
        position: absolute;
        top: 0.625rem;
        left: 0.75rem;
        width: 7.75rem;
        font-weight: 700;
        color: var(--ap-ink);
    }

    /* Zebra striping means nothing once rows are cards. */
    .ap-table--cards tbody tr:nth-child(even) td {
        background: #fff;
    }
}


/* ===========================================================================
   Inner pages, Batch B — Careers, Contact, Sitemap (+ the form placeholder)
   ===========================================================================

     .ap-form-placeholder                     stand-in for a HubSpot form
     .ap-hubspot-form  .ap-contact__form      a live HubSpot form (blockHubSpotForm)
     .ap-careers  .ap-careers__intro  .ap-careers__apply
     .ap-careers-list  .ap-job (__heading __toggle __title __icon __panel
       __meta __overview __description __actions __apply)
       .ap-careers-list__empty               the live `careers` listing
                                              (page-builder/blocks/blockEntryList.twig)
     .ap-contact-row  .ap-contact-row__grid  .ap-contact-row__item
     .ap-contact  .ap-contact__heading  .ap-contact__details
     .ap-map  .ap-map__frame                  Google Maps band (blockHtml)
     .ap-sitemap  .ap-sitemap__list
   --------------------------------------------------------------------------- */

.ap-page .ap-careers > .block--section__inner,
.ap-page .ap-contact-row > .block--section__inner,
.ap-page .ap-contact > .block--section__inner {
    box-sizing: border-box;
    max-width: var(--ap-max);
    margin-inline: auto;
    padding: 1.5rem var(--ap-gutter);
}

@media (min-width: 40em) {
    .ap-page .ap-careers > .block--section__inner,
    .ap-page .ap-contact-row > .block--section__inner,
    .ap-page .ap-contact > .block--section__inner {
        padding: 2.5rem 1.5rem;
    }
}

/* --- Form placeholder ------------------------------------------------------

   Deliberately LOOKS unfinished: it marks where marketing's HubSpot form goes
   and must never read as page content. #494949 on #fffbea is 9.2:1. */
.ap-page .ap-form-placeholder,
.ap-form-placeholder {
    box-sizing: border-box;
    max-width: 50rem;
    margin: 1.5rem 0;
    padding: 1.25rem 1.5rem;
    border: 3px dashed var(--ap-blue);
    background: #fffbea;
    color: var(--ap-ink);
}

.ap-form-placeholder p {
    margin: 0 !important;
}

.ap-form-placeholder strong {
    display: block;
    margin-bottom: 0.25rem;
    color: var(--ap-blue);
}

/* --- HubSpot forms (About Us "Materials Consult", Contact Us) --------------

   The shared blockHubSpotForm, class `.ap-hubspot-form` on its outer div. The
   form itself is HubSpot's self-styled iframe (fields, focus rings, button);
   this only sets the box it sits in: the same 50rem measure as the
   placeholder it replaced, so a two-column field row never stretches across
   a 1128px article, and room below the heading above it. */
.ap-page .ap-hubspot-form {
    box-sizing: border-box;
    width: 100%;
    max-width: 50rem;
    margin: 1.25rem 0 1.5rem;
}

.ap-hubspot-form .hubspot-form__container,
.ap-hubspot-form iframe {
    max-width: 100%;
}

/* --- Careers: openings ----------------------------------------------------

   The source's `.click-expand-module`: a white band, a centred heading over a
   centred italic intro, then one accordion bar per posting. */

.ap-careers {
    background: #fff;
}

.ap-careers__intro {
    max-width: 50rem;
    margin-inline: auto;
    text-align: center;
}

.ap-page .ap-careers__intro h2 {
    margin-top: 0;
}

.ap-page .ap-careers__intro p {
    font-style: italic;
    font-weight: 700;
}

.ap-careers-list {
    margin: 1.5rem 0;
}

.ap-careers-list__items {
    list-style: none;
    margin: 0 !important;
    padding: 0 !important;
    display: grid;
    gap: 1rem;
}

.ap-page .ap-careers-list__items > li {
    margin: 0;
}

/* One posting = the source's `.click-expand`: a #f4f4f4 bar with a #d9d9d9
   rule, 18px/700 title, and a 24px maroon circle holding a white +/-. */
.ap-job {
    background: #fff;
    border: 1px solid #d9d9d9;
}

.ap-page .ap-job__heading {
    margin: 0;
    font-size: 1.125rem;
    line-height: 1.3;
}

/* The whole bar is the button (a big target, WCAG 2.5.8). */
.ap-job__toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    width: 100%;
    margin: 0;
    padding: 1.25rem;
    border: 0;
    background: var(--ap-grey-band);
    font: inherit;
    font-weight: 700;
    color: var(--ap-ink);
    text-align: left;
    cursor: pointer;
}

.ap-job__toggle:hover {
    color: var(--ap-blue);
}

/* Inset: the bar runs edge to edge of its bordered box. */
.ap-job__toggle:focus-visible {
    outline: 2px solid var(--ap-blue);
    outline-offset: -4px;
}

.ap-job__icon {
    position: relative;
    flex-shrink: 0;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--ap-maroon);
}

.ap-job__icon::before,
.ap-job__icon::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 10px;
    height: 2px;
    background: #fff;
    transform: translate(-50%, -50%);
}

.ap-job__icon::after {
    transform: translate(-50%, -50%) rotate(90deg);
}

.ap-job__toggle[aria-expanded="true"] .ap-job__icon::after {
    display: none;
}

/* Without JS nothing can open a panel, so the icon would be a false promise. */
html:not(.ap-js) .ap-job__icon {
    display: none;
}

.ap-job__panel {
    padding: 1.25rem 1.25rem 1.5rem;
}

/* Collapsed only when the toggle script can run; display:none also takes the
   closed panel out of the accessibility tree. */
.ap-js .ap-job__panel:not(.is-open) {
    display: none;
}

.ap-job__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1.5rem;
    margin: 0 0 0.75rem;
}

.ap-job__meta dt {
    display: inline;
    font-weight: 700;
    color: var(--ap-ink);
}

.ap-job__meta dt::after {
    content: ":";
}

.ap-job__meta dd {
    display: inline;
    margin: 0 0 0 0.25rem;
}

.ap-job__overview {
    margin: 0 0 1rem !important;
}

.ap-job__description {
    margin: 0 0 1rem;
}

.ap-page .ap-job__description > :last-child {
    margin-bottom: 0 !important;
}

.ap-page .ap-job__actions {
    margin: 1.5rem 0 0 !important;
    text-align: center;
}

.ap-careers-list__empty {
    margin: 0 !important;
    padding: 1.25rem;
    border: 1px solid #d9d9d9;
    background: var(--ap-grey-band);
    font-weight: 700;
    color: var(--ap-ink);
    text-align: center;
}

/* .block--button__content is a flex row. */
.ap-careers__apply {
    margin-top: 0.5rem;
    justify-content: center;
}

/* --- Careers: location / resumes row (the theme's `.career-contact-us-module`) */

/* One column on a phone (shared.css makes 1fr-1fr two columns at every width). */
.ap-contact-row__grid > .block--column-multi.block--layout-1fr-1fr {
    grid-template-columns: 1fr;
    gap: 1.5rem;
}

@media (min-width: 48em) {
    .ap-contact-row__grid > .block--column-multi.block--layout-1fr-1fr {
        grid-template-columns: 1fr 1fr;
        gap: 2.5rem;
    }
}

.ap-page .ap-contact-row__item h2 {
    margin-top: 0;
    font-size: 1.375rem;
}

/* The source's `.ccum-ico-text-wrap`: a 20px maroon outline icon, a 12px gap,
   then a 1px #aeafaf rule and 8px before the heading text; the copy below
   lines up with the heading text (so the rule and icon hang to its left).
   The icons were glyphs of the theme's icon font (Conv_modules); these are
   SVG redraws. Decorative (CSS backgrounds), so assistive tech reads only the
   heading, as on the source. */
.ap-contact-row__item--location .block--column-single__inner,
.ap-contact-row__item--resumes .block--column-single__inner {
    padding-left: calc(2.5rem + 1px);
}

.ap-page .ap-contact-row__item--location h2,
.ap-page .ap-contact-row__item--resumes h2 {
    position: relative;
    margin-left: calc(-0.5rem - 1px);
    padding-left: 0.5rem;
    border-left: 1px solid var(--ap-rule-soft);
}

.ap-contact-row__item--location h2::before,
.ap-contact-row__item--resumes h2::before {
    content: "";
    position: absolute;
    top: 50%;
    left: calc(-2rem - 1px);
    width: 20px;
    height: 20px;
    transform: translateY(-50%);
    background: no-repeat center / contain;
}

.ap-contact-row__item--location h2::before {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2386003b' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 11.5 12 3l9.5 8.5'/%3E%3Cpath d='M5 9.5V21h5v-6.5h4V21h5V9.5'/%3E%3C/svg%3E");
}

.ap-contact-row__item--resumes h2::before {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2386003b' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.5' y='5' width='19' height='14' rx='1'/%3E%3Cpath d='m3 6 9 7.5L21 6'/%3E%3Cpath d='m3 18.5 7-6.5m11 6.5-7-6.5'/%3E%3C/svg%3E");
}

/* --- Contact: heading, form placeholder, details (`.contact-us-page-module`) */

.ap-contact > .block--section__inner {
    display: grid;
    gap: 0 2.5rem;
    grid-template-areas:
        "heading"
        "form"
        "details";
}

/* The hook classes sit on each rich-text block's INNER text wrapper, so the
   grid items (the `.block--rich-text` blocks themselves) are placed via :has(). */
.ap-contact > .block--section__inner > .block--rich-text:has(> .ap-contact__heading) { grid-area: heading; }
.ap-contact > .block--section__inner > .block--rich-text:has(> .ap-form-placeholder) { grid-area: form; }
.ap-contact > .block--section__inner > .ap-contact__form { grid-area: form; }
.ap-contact > .block--section__inner > .block--rich-text:has(> .ap-contact__details) { grid-area: details; }

.ap-contact .ap-form-placeholder,
.ap-page .ap-contact .ap-contact__form { margin-top: 0; }

@media (min-width: 64em) {
    .ap-contact > .block--section__inner {
        grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
        grid-template-areas:
            "heading heading"
            "form    details";
    }
}

.ap-page .ap-contact__heading h1 {
    margin: 0 0 1.5rem;
    font-size: 1.875rem;
    line-height: 1.1;
    font-weight: 800;
    text-transform: uppercase;
    color: var(--ap-ink);
}

@media (min-width: 40em) {
    .ap-page .ap-contact__heading h1 { font-size: 2.375rem; }
}

.ap-page .ap-contact__details h2 {
    margin-top: 0;
    font-size: 1.375rem;
}

/* Long e-mail addresses must wrap rather than push the page sideways at 375px. */
.ap-contact__details a {
    overflow-wrap: anywhere;
}

/* --- Map band (the theme's `.full-width-map-module`) ----------------------- */

.ap-map {
    width: 100%;
    height: 20rem;
    background: var(--ap-grey-band);
}

@media (min-width: 48em) {
    .ap-map { height: 28rem; }
}

.ap-map__frame {
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
}

.ap-map__frame:focus-visible {
    outline: 3px solid var(--ap-blue);
    outline-offset: -3px;
}

/* --- Sitemap --------------------------------------------------------------- */

.ap-page .ap-sitemap__list ul {
    margin: 0 0 0 1.25rem;
    padding-left: 1rem;
}

.ap-page .ap-sitemap__list > ul {
    margin-left: 0;
}

.ap-page .ap-sitemap__list li {
    margin: 0.375rem 0;
}

/* ===========================================================================
   Blog — the /blog listing and the post pages
   ===========================================================================

   Listing: a Landing Pages entry (`.page-builder.ap-page.ap-page--blog.ap-blog`)
   with a plain heading band (`.ap-hero-band--plain`) and one shared Blog
   Preview block (`.ap-blog__list`). The site's override of that block
   (page-builder/blocks/blockBlogPreview.twig) makes card titles <h2> and hides
   the duplicate thumbnail link from AT.

   Posts: appliedplastics/templates/blog/_entry.twig, `.ap-blog-post*`.

   Values are the source theme's (style.css: .page-intro, .site-content,
   .col-3/.col-9, h1/h2/h3). Departures are accessibility fixes, marked "AA:".
   --------------------------------------------------------------------------- */

/* --- Heading band without a photo (the source's blog `.page-intro`) ------- */

.ap-hero-band--plain::before,
.ap-hero-band--plain .ap-hero-band__text::before {
    content: none;
}

.ap-hero-band--plain .ap-hero-band__text h1 {
    color: var(--ap-ink);
    margin: 0;
}

/* --- Listing: one row per post, thumbnail left (col-3) + text (col-9) ----- */

.ap-blog .ap-blog__list {
    box-sizing: border-box;
    max-width: var(--ap-max);
    margin-inline: auto;
    padding: 0 var(--ap-gutter) 2.5rem;
}

@media (min-width: 40em) {
    .ap-blog .ap-blog__list {
        padding: 0 1.5rem 3.5rem;
    }
}

.ap-blog .blog-grid {
    display: block;
    margin: 0;
}

/* The shared card chrome (white tile, radius, shadow) becomes a plain row with
   a hairline between posts, like the source list. */
.ap-blog .blog-card {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem;
    padding: 1.5rem 0;
    border-top: 1px solid var(--ap-rule);
    border-radius: 0;
    background: none;
    box-shadow: none;
    overflow: visible;
}

.ap-blog .blog-card:first-child {
    border-top: 0;
    padding-top: 0;
}

/* Posts without a feature image still get an (empty) thumbnail link from the
   shared template. It is aria-hidden and untabbable (see the override); here
   it also takes no space. */
.ap-blog .blog-card__image:not(:has(img)) {
    display: none;
}

.ap-blog .blog-card__image img {
    display: block;
    width: 100%;
    height: auto;
}

.ap-blog .blog-card__body {
    padding: 0;
}

@media (min-width: 40em) {
    .ap-blog .blog-card {
        grid-template-columns: minmax(0, 1fr) minmax(0, 3.2fr);
        gap: 0 2.3576515979%;
    }

    /* Beside the thumbnail when there is one; a post without an image runs its
       text the full width of the row, as the source list does. */
    .ap-blog .blog-card__body {
        grid-column: 2;
    }

    .ap-blog .blog-card:not(:has(.blog-card__image img)) .blog-card__body {
        grid-column: 1 / -1;
    }
}

.ap-blog .blog-card__meta {
    margin: 0 0 0.375rem;
    font-size: 0.875rem;
    color: var(--ap-body);
}

/* The shared chip is #666 on #e9f7ff (5.3:1) and is kept; only the size is ours. */
.ap-blog .chip--category {
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}

/* The source's listing <h3>: sentence case, regular weight, a maroon underlined
   link — overriding `.ap-page h2`, which the card title now is. AA: the source's
   phone size (0.98em) is floored at 1.125rem. */
.ap-blog .blog-card__title {
    margin: 0 0 0.5rem;
    font-size: 1.125rem;
    line-height: 1.25;
    font-weight: 600;
    text-transform: none;
    color: var(--ap-ink);
}

@media (min-width: 40em) {
    .ap-blog .blog-card__title { font-size: 1.1875rem; }
}

@media (min-width: 60em) {
    .ap-blog .blog-card__title { font-size: 1.6875rem; }
}

.ap-blog .blog-card__title a {
    color: var(--ap-maroon);      /* 10.1:1 on #fff */
    text-decoration: underline;
}

.ap-blog .blog-card__title a:hover {
    color: #3a0019;
}

.ap-blog .blog-card__title a:focus-visible {
    outline: 2px solid var(--ap-blue);
    outline-offset: 2px;
}

.ap-blog .blog-card__excerpt {
    margin: 0;
    font-size: 1rem;
    line-height: 1.5;
    color: var(--ap-body);
}

/* AA: the shared current-page pill is white on #3b82f6 (3.7:1). Only shown once
   there are more than 10 posts. */
.ap-blog .pagination__item--current,
.ap-blog .pagination__item--current:hover {
    background: var(--ap-blue);
    border-color: var(--ap-blue);
}

.ap-blog .pagination__item:focus-visible {
    outline: 2px solid var(--ap-blue);
    outline-offset: 2px;
    z-index: 1;
    position: relative;
}

/* --- Post page ------------------------------------------------------------- */

.ap-blog-post {
    box-sizing: border-box;
    max-width: var(--ap-max);
    margin-inline: auto;
    padding: 1.5rem var(--ap-gutter) 2.5rem;
}

@media (min-width: 40em) {
    .ap-blog-post {
        padding: 2.5rem 1.5rem 3.5rem;
    }
}

/* One readable column, the width of the source's primary column. */
.ap-blog-post > * {
    max-width: 52.5rem;
}

.ap-blog-post__title {
    margin: 0 0 0.75rem;
    font-size: 1.875rem;
    line-height: 1.25;
    font-weight: 800;
    text-transform: uppercase;
    color: var(--ap-ink);
    overflow-wrap: break-word;
}

@media (min-width: 40em) {
    .ap-blog-post__title { font-size: 2.25rem; }
}

.ap-blog-post__meta {
    margin: 0 0 1.5rem;
    font-size: 0.9375rem;
    color: var(--ap-body);
}

.ap-blog-post__image {
    margin: 0 0 1.5rem;
}

.ap-blog-post__image img,
.ap-blog-post__body img {
    display: block;
    max-width: 100%;
    height: auto;
}

.ap-blog-post__body img {
    margin-inline: auto;
}

.ap-blog-post__body p,
.ap-blog-post__tags {
    margin: 1rem 0;
    font-size: 1rem;
    line-height: 1.5;
    color: var(--ap-body);
}

.ap-blog-post__body > :first-child {
    margin-top: 0;
}

.ap-blog-post__body h2 {
    margin: 2rem 0 0.625rem;
    font-size: 1.5rem;
    line-height: 1.2;
    font-weight: 800;
    text-transform: uppercase;
    color: var(--ap-ink);
}

/* AA: floored above body size, the same reasoning as `.ap-page h3`. */
.ap-blog-post__body h3,
.ap-blog-post__body h4 {
    margin: 1.75rem 0 0.625rem;
    font-size: 1.125rem;
    line-height: 1.3;
    font-weight: 700;
    color: var(--ap-ink);
}

@media (min-width: 60em) {
    /* The source's desktop scale: h1 40px, h2 38px, h3 27px. */
    .ap-blog-post__title { font-size: 2.5rem; }
    .ap-blog-post__body h2 { font-size: 2.375rem; }
    .ap-blog-post__body h3 { font-size: 1.6875rem; }
}

.ap-blog-post__body ul,
.ap-blog-post__body ol {
    margin: 1rem 0;
    padding-left: 1.25rem;
    color: var(--ap-body);
}

.ap-blog-post__body li {
    line-height: 1.5;
    margin-bottom: 0.375rem;
}

/* Links in the prose, the meta line and the tags: the theme's maroon
   (10.1:1 on #fff), underlined so colour is never the only cue (WCAG 1.4.1). */
.ap-blog-post__meta a,
.ap-blog-post__body a,
.ap-blog-post__tags a,
.ap-blog-post__back a {
    color: var(--ap-maroon);
    text-decoration: underline;
}

.ap-blog-post__meta a:hover,
.ap-blog-post__body a:hover,
.ap-blog-post__tags a:hover,
.ap-blog-post__back a:hover {
    color: #3a0019;
}

.ap-blog-post a:focus-visible {
    outline: 2px solid var(--ap-blue);
    outline-offset: 2px;
}

/* An image that is a link (the thermoplastics video card) draws its focus
   outline round the image, not round a zero-height inline run. */
.ap-blog-post__body a:has(> img) {
    display: inline-block;
}

.ap-blog-post__footer {
    margin-top: 2.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--ap-rule);
}

.ap-blog-post__pager {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 1rem 2rem;
}

.ap-blog-post__pager-link {
    display: block;
    flex: 1 1 16rem;
    color: var(--ap-blue);
    font-weight: 700;
    line-height: 1.35;
    text-decoration: none;
}

.ap-blog-post__pager-link--older {
    text-align: right;
}

.ap-blog-post__pager-link:hover {
    text-decoration: underline;
}

.ap-blog-post__pager-label {
    display: block;
    margin-bottom: 0.25rem;
    font-size: 0.8125rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--ap-body);
}

.ap-blog-post__back {
    margin: 1.5rem 0 0;
    font-weight: 700;
}

@media (max-width: 39.99em) {
    .ap-blog-post__pager-link--older {
        text-align: left;
    }
}
