.elementor-kit-19{--e-global-color-primary:#183F5E;--e-global-color-secondary:#0071B7;--e-global-color-text:#183F5E;--e-global-color-accent:#F1AE45;--e-global-color-63af1b4:#009DB0;--e-global-color-0c26593:#FFFFFF;--e-global-color-893ac00:#F3E7CE;--e-global-color-ffff00a:#EAE8E4;--e-global-typography-primary-font-family:"Special Gothic Expanded One";--e-global-typography-primary-font-weight:400;--e-global-typography-secondary-font-family:"Special Gothic Expanded One";--e-global-typography-secondary-font-weight:400;--e-global-typography-text-font-family:"Lato 500";--e-global-typography-text-font-weight:500;--e-global-typography-accent-font-family:"Lato 800";--e-global-typography-accent-font-weight:800;color:var( --e-global-color-primary );font-family:"Lato 500", Sans-serif;font-size:16px;font-weight:500;line-height:1.75em;}.elementor-kit-19 button,.elementor-kit-19 input[type="button"],.elementor-kit-19 input[type="submit"],.elementor-kit-19 .elementor-button{background-color:var( --e-global-color-accent );font-family:"Lato 800", Sans-serif;font-size:16px;font-weight:800;text-transform:uppercase;color:var( --e-global-color-primary );border-radius:70px 70px 70px 70px;padding:14px 28px 14px 28px;}.elementor-kit-19 button:hover,.elementor-kit-19 button:focus,.elementor-kit-19 input[type="button"]:hover,.elementor-kit-19 input[type="button"]:focus,.elementor-kit-19 input[type="submit"]:hover,.elementor-kit-19 input[type="submit"]:focus,.elementor-kit-19 .elementor-button:hover,.elementor-kit-19 .elementor-button:focus{background-color:var( --e-global-color-primary );color:var( --e-global-color-accent );}.elementor-kit-19 e-page-transition{background-color:#FFBC7D;}.elementor-kit-19 a{color:var( --e-global-color-secondary );text-decoration:none;}.elementor-kit-19 a:hover{color:var( --e-global-color-primary );}.elementor-kit-19 h1{color:var( --e-global-color-primary );font-family:"Special Gothic Expanded One", Sans-serif;font-size:100px;font-weight:400;text-transform:uppercase;line-height:0.92em;}.elementor-kit-19 h2{color:var( --e-global-color-primary );font-family:"Special Gothic Expanded One", Sans-serif;font-size:60px;font-weight:400;text-transform:uppercase;}.elementor-kit-19 h3{color:var( --e-global-color-primary );font-family:"Special Gothic Expanded One", Sans-serif;font-size:40px;font-weight:400;text-transform:uppercase;line-height:1.05em;}.elementor-kit-19 h4{color:var( --e-global-color-primary );font-family:"Special Gothic Expanded One", Sans-serif;font-size:30px;font-weight:400;text-transform:uppercase;}.elementor-kit-19 h5{color:var( --e-global-color-primary );font-family:"Special Gothic Expanded One", Sans-serif;font-size:24px;font-weight:400;text-transform:uppercase;}.elementor-kit-19 h6{color:var( --e-global-color-primary );font-family:"Special Gothic Expanded One", Sans-serif;font-size:20px;font-weight:400;text-transform:uppercase;}.elementor-section.elementor-section-boxed > .elementor-container{max-width:1140px;}.e-con{--container-max-width:1140px;}.elementor-widget:not(:last-child){--kit-widget-spacing:20px;}.elementor-element{--widgets-spacing:20px 20px;--widgets-spacing-row:20px;--widgets-spacing-column:20px;}{}h1.entry-title{display:var(--page-title-display);}@media(max-width:1024px){.elementor-kit-19 h1{font-size:64px;line-height:0.92em;}.elementor-kit-19 h2{font-size:48px;line-height:0.97em;}.elementor-kit-19 h3{font-size:34px;line-height:1.05em;}.elementor-kit-19 h4{font-size:27px;line-height:1.1em;}.elementor-kit-19 h5{font-size:22px;line-height:1.15em;}.elementor-kit-19 h6{font-size:18px;line-height:1.2em;}.elementor-section.elementor-section-boxed > .elementor-container{max-width:1024px;}.e-con{--container-max-width:1024px;}}@media(max-width:767px){.elementor-kit-19 h1{font-size:40px;line-height:0.92em;}.elementor-kit-19 h2{font-size:38px;line-height:0.97em;}.elementor-kit-19 h3{font-size:30px;line-height:1.05em;}.elementor-kit-19 h4{font-size:24px;line-height:1.1em;}.elementor-kit-19 h5{font-size:20px;line-height:1.15em;}.elementor-kit-19 h6{font-size:17px;line-height:1.2em;}.elementor-section.elementor-section-boxed > .elementor-container{max-width:767px;}.e-con{--container-max-width:767px;}}/* Start custom CSS *//* ============================================================================
   ALL POWER MARINE — Site Custom CSS
   Elementor → Site Settings → Custom CSS. Paste this whole file.
   ----------------------------------------------------------------------------
   SWATCHES (Global Colors → CSS variables)
     --e-global-color-primary    #183F5E  Navy Blue
     --e-global-color-secondary  #0071B7  Mid Ship Blue
     --e-global-color-text       #183F5E  Body Text
     --e-global-color-accent     #F1AE45  Florida Sunshine
     --e-global-color-63af1b4    #009DB0  Sandy Lagoon
     --e-global-color-0c26593    #FFFFFF  Pure White
     --e-global-color-893ac00    #F3E7CE  Creamy Foam
   FONTS (Custom Fonts): "Special Gothic Expanded One", "Lato 800", "Lato 500",
   "Lato 300".
   ----------------------------------------------------------------------------
   CONTENTS
     @font-face  Custom font force-load (all four families)
      0  H2 line-height safety net · tt-none
      1  Buttons — variants
      2  Eyebrow · txt-link
      3  Two-tone headline word · nl · nb
      4  Product stat rows
      5  4Ocean impact stat
      6  Installed-for-Life promise bar
      7  Section padding helpers
      8  Header — desktop dropdown
      9  Header — logo
     10  Off-canvas mobile menu
     11  Trust bar (+ dock label pair)
     12  Footer
     13  Third-party widgets (note only — no rules)
     14  Sticky stack
     15  Inline rows safety net
     16  Motion — reveals + reduced motion
     17  Co-stats bar
     18  Display heading
     19  Fleet media tiles
     20  White-Glove step title + icon
     21  White-Glove layout
     22  Fleet tiles grid
     23  Lambo Lift
     24  Product spec sections
     25  Gallery — KISS CoverFlow
     26  "Not Sure?" CTA band
     27  Boat Lifts — stack off
     28  "60 Seconds" step sequence — pinned desktop / SWIPE CAROUSEL mobile
     29  3D viewer section
     30  Technical specs table
     31  Features — pinned background
     32  Anchor landing offset
     33  Docks — hero + pinned-photo sections
     34  Docks — icon feature grid
     35  Docks — testimonial cards
     36  Inline links on dark / on light
   ============================================================================ */


/* ----------------------------------------------------------------------------
   FONT FORCE-LOAD — all four custom families
   Elementor only auto-enqueues a Custom Font on the FRONT END when a widget
   uses it via typography controls. All three Lato weights are referenced
   from Custom CSS (.eyebrow, .stat-num, .sixty-dot, .footer-*), so Elementor
   never printed their @font-face and they fell back to system sans on the live
   page (the editor loads every custom font, which is why preview looked fine).
   Declaring them here forces it. Special Gothic is declared too — the kit
   should enqueue it as the Theme Style heading font, but a declaration costs
   nothing and removes the dependency. Client has committed to never renaming
   or removing these files.
   URLs are ROOT-RELATIVE so they survive the dev→live domain move. .eot is
   omitted deliberately — IE only, and no browser in service reads it.
---------------------------------------------------------------------------- */
@font-face{
  font-family:"Lato 300";
  font-style:normal;
  font-weight:300;
  font-display:swap;
  src:url("/wp-content/uploads/2026/07/Lato-Light.woff2") format("woff2"),
      url("/wp-content/uploads/2026/07/Lato-Light.woff")  format("woff"),
      url("/wp-content/uploads/2026/07/Lato-Light.ttf")   format("truetype");
}
@font-face{
  font-family:"Lato 500";
  font-style:normal;
  font-weight:500;
  font-display:swap;
  src:url("/wp-content/uploads/2026/07/Lato-Medium.woff2") format("woff2"),
      url("/wp-content/uploads/2026/07/Lato-Medium.woff")  format("woff"),
      url("/wp-content/uploads/2026/07/Lato-Medium.ttf")   format("truetype");
}
@font-face{
  font-family:"Lato 800";
  font-style:normal;
  font-weight:800;
  font-display:swap;
  src:url("/wp-content/uploads/2026/07/Lato-Heavy.woff2") format("woff2"),
      url("/wp-content/uploads/2026/07/Lato-Heavy.woff")  format("woff"),
      url("/wp-content/uploads/2026/07/Lato-Heavy.ttf")   format("truetype");
}
/* NOTE the filenames differ by format for this one — woff2/woff are
   special-gothic-expanded-one-400, the ttf is SpecialGothicExpandedOne-Regular.
   Do not "tidy" them to match. */
@font-face{
  font-family:"Special Gothic Expanded One";
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url("/wp-content/uploads/2026/07/special-gothic-expanded-one-400.woff2") format("woff2"),
      url("/wp-content/uploads/2026/07/special-gothic-expanded-one-400.woff")  format("woff"),
      url("/wp-content/uploads/2026/07/SpecialGothicExpandedOne-Regular.ttf")  format("truetype");
}


/* ----------------------------------------------------------------------------
   0.  H2 LINE-HEIGHT SAFETY NET  ⚠ READ ME
   Theme Style has the H2 *desktop* line-height stored in PX (0.97px ≈ 0),
   which is what collapsed every multi-line H2. Tablet/mobile are correct (EM).
   PROPER FIX: Site Settings → Theme Style → Typography → H2 → Line-Height →
   switch the desktop unit from PX to EM (value 0.97). This rule guarantees
   correct rendering until you do, and is harmless after.
---------------------------------------------------------------------------- */
.elementor-widget-heading h2.elementor-heading-title{ line-height:.97em; }

/* Sentence-case override for mixed-case headlines (Theme Style forces uppercase).
   Class on the heading widget: tt-none */
.tt-none .elementor-heading-title{ text-transform:none; }


/* ----------------------------------------------------------------------------
   1.  BUTTONS
   Base button (solid Sunshine + Navy text, radius, padding, Lato 800) comes
   from Theme Style → Buttons. These are only the variants + the wrap guard.
---------------------------------------------------------------------------- */
/* Keep all CTA labels on one line */
.elementor-button{ white-space:nowrap; }

/* CTA chevron/icon inherits the button's text color (was rendering white) */
.elementor-button .elementor-button-icon svg{ fill:currentColor; }

/* Full-width buttons on mobile — add class "btn-block-mobile" to the button */
@media (max-width:767px){
  .btn-block-mobile{ width:100%; }
  .btn-block-mobile .elementor-button{ display:flex; width:100%; justify-content:center; }
}

/* Ghost / outline — Sunshine (use on dark or blue sections). Class: btn-ghost */
.btn-ghost .elementor-button{
  background:transparent;
  border:2px solid var(--e-global-color-accent);
  color:var(--e-global-color-accent);
}
.btn-ghost .elementor-button:hover{
  background:var(--e-global-color-accent);
  color:var(--e-global-color-primary);
}

/* Ghost / outline — Mid Ship Blue (use on light sections). Class: btn-ghost-blue */
.btn-ghost-blue .elementor-button{
  background:transparent;
  border:2px solid var(--e-global-color-secondary);
  color:var(--e-global-color-secondary);
}
.btn-ghost-blue .elementor-button:hover{
  background:var(--e-global-color-secondary);
  color:var(--e-global-color-0c26593);
}

/* Solid Mid Ship Blue (e.g. Learn About 4ocean). Class: btn-blue */
.btn-blue .elementor-button{
  background:var(--e-global-color-secondary);
  color:var(--e-global-color-0c26593);
}
.btn-blue .elementor-button:hover{
  background:var(--e-global-color-primary);
  color:var(--e-global-color-0c26593);
}


/* ----------------------------------------------------------------------------
   2.  EYEBROW (kicker label above headings). Class: eyebrow  [+ is-navy]
---------------------------------------------------------------------------- */
.eyebrow{
  font-family:"Lato 800",sans-serif;
  font-weight:800;
  font-size:16px;
  text-transform:uppercase;
  letter-spacing:.02em;
  color:var(--e-global-color-accent);        /* Sunshine — dark/blue sections */
}
/* The comp draws every eyebrow in a 31px line box (31/16 = 1.9375). Declared on
   the title element, not the widget: Elementor's widget CSS loads after ours and
   sets .elementor-heading-title{line-height:1} directly on the <p>, which beats
   anything inherited from .eyebrow — that was crushing every eyebrow site-wide
   to a 16px box and pulling each section head 15px tight. */
.eyebrow .elementor-heading-title{ line-height:1.9375; }

.eyebrow.is-navy{ color:var(--e-global-color-primary); }   /* light sections   */
.eyebrow.is-blue{ color:var(--e-global-color-secondary); } /* Mid Ship Blue    */
.eyebrow.is-teal{ color:var(--e-global-color-63af1b4); }   /* Sandy Lagoon     */

/* Inline text link styled like an eyebrow (e.g. "View Our Brand Video") */
.txt-link{ text-decoration:underline; text-underline-offset:3px; }


/* ----------------------------------------------------------------------------
   3.  TWO-TONE HEADLINE WORD.  <span class="hl"> inside a heading
---------------------------------------------------------------------------- */
.hl{ color:var(--e-global-color-accent); }

/* Line break inside a heading without <br>. Put nl on the span that starts
   the new line:  THE WORK SPEAKS FOR <span class="hl nl">ITSELF.</span>       */
.nl{ display:block; }

/* Keep a phrase on one line (stops WHITE-GLOVE splitting at the hyphen).
   <span class="nb">THE WHITE-GLOVE</span>   Released on phones.               */
.nb{ white-space:nowrap; }
@media (max-width:767px){ .nb{ white-space:normal; } }


/* ----------------------------------------------------------------------------
   4.  PRODUCT STAT ROWS (Elevator / Post / Jetski)
   Figure: Class stat-num  [+ is-blue].   Label: Class stat-label  [+ is-navy].
---------------------------------------------------------------------------- */
.stat-num{
  font-family:"Special Gothic Expanded One",sans-serif;
  font-weight:400;
  font-size:22px;
  line-height:1;
  color:var(--e-global-color-0c26593);       /* Pure White — dark sections */
}
.stat-num.is-blue{ color:var(--e-global-color-secondary); }    /* light sections */

.stat-label{
  font-family:"Lato 500",sans-serif;
  font-weight:500;
  font-size:11px;
  text-transform:uppercase;
  letter-spacing:.045em;
  color:var(--e-global-color-accent);         /* Sunshine — dark sections */
}
.stat-label.is-navy{ color:var(--e-global-color-primary); }    /* light sections */


/* ----------------------------------------------------------------------------
   5.  4OCEAN IMPACT STAT.  Figure: stat-impact.  Label: stat-impact-label.
---------------------------------------------------------------------------- */
.stat-impact{
  font-family:"Special Gothic Expanded One",sans-serif;
  font-weight:400;
  font-size:40px;
  line-height:1;
  color:var(--e-global-color-secondary);
}
.stat-impact-label{
  font-family:"Lato 800",sans-serif;
  font-weight:800;
  font-size:13px;
  line-height:1.3;
  text-transform:uppercase;
  color:var(--e-global-color-63af1b4);        /* Sandy Lagoon */
}


/* ----------------------------------------------------------------------------
   6.  INSTALLED-FOR-LIFE PROMISE BAR
   Lead line: promise-lead.   Sub line: promise-sub.
   Re-measured off the comp 2026-09-05 (Figma 42:270 / 42:272). These were 18/1.2
   and 12px/.04em — both undersized, and the .82 opacity cost contrast on blue.
   Comp: lead Lato Heavy 24/28, sub Lato Medium 16/28, both solid white, no
   tracking. Card sizing is in section 51.
---------------------------------------------------------------------------- */
.promise-lead{
  font-family:"Lato 800",sans-serif;
  font-weight:800;
  font-size:24px;
  line-height:28px;
  text-transform:uppercase;
  color:var(--e-global-color-0c26593);
}
.promise-sub{
  font-family:"Lato 500",sans-serif;
  font-weight:500;
  font-size:16px;
  line-height:28px;
  letter-spacing:0;
  text-transform:uppercase;
  color:var(--e-global-color-0c26593);
}
/* BOTH LINES ARE HEADING WIDGETS. Elementor's widget CSS loads after ours and
   sets .elementor-heading-title{line-height:1} directly on the element, which
   beats anything inherited — the same trap section 2 hit with .eyebrow. Declare
   the line box on the title itself or the sub crushes to a 16px box. */
.promise-lead .elementor-heading-title{ line-height:28px; }
.promise-sub  .elementor-heading-title{ line-height:28px; }

@media (max-width:767px){
  .promise-lead{ font-size:19px; line-height:24px; }
  .promise-sub { font-size:14px; line-height:22px; }
  .promise-lead .elementor-heading-title{ line-height:24px; }
  .promise-sub  .elementor-heading-title{ line-height:22px; }
}


/* ----------------------------------------------------------------------------
   7.  SECTION PADDING HELPERS
---------------------------------------------------------------------------- */
/* Horizontal-only fluid padding (hero / full-viewport sections). Class: section-pad */
.section-pad{ padding-inline:clamp(24px,8vw,148px); }

/* Horizontal + vertical fluid padding (normal stacked sections). Class: apm-section */
.apm-section{ padding-block:clamp(40px,7vw,100px); padding-inline:clamp(24px,8vw,148px); }


/* ----------------------------------------------------------------------------
   8.  HEADER — desktop dropdown (submenu)
---------------------------------------------------------------------------- */
.elementor-nav-menu .sub-menu{
  background-color:var(--e-global-color-primary);
  border-radius:4px;
  box-shadow:0 10px 30px rgba(0,0,0,.15);
  padding:6px 0;
}
.elementor-nav-menu .sub-menu a.elementor-sub-item{
  color:var(--e-global-color-0c26593); font-family:"Lato 500",sans-serif; font-weight:500; font-size:15px;
  text-transform:none; padding:12px 20px;
}
.elementor-nav-menu .sub-menu a.elementor-sub-item:hover,
.elementor-nav-menu .sub-menu a.elementor-sub-item.elementor-item-active{
  background-color:var(--e-global-color-accent);
  color:var(--e-global-color-primary);
}


/* ----------------------------------------------------------------------------
   9.  HEADER — logo (render SVG as centered block, kill inline baseline gap)
   Class on the logo Icon widget: apm-logo
---------------------------------------------------------------------------- */
.apm-logo .elementor-icon{ display:flex; align-items:center; line-height:0; }
.apm-logo .elementor-icon svg{ display:block; width:auto; height:44px !important; }   /* desktop */
@media (max-width:1024px){ .apm-logo .elementor-icon svg{ height:40px !important; } } /* tablet  */
@media (max-width:767px){  .apm-logo .elementor-icon svg{ height:36px !important; } } /* mobile  */


/* ----------------------------------------------------------------------------
   10.  OFF-CANVAS MOBILE MENU (scoped: apm-offcanvas-menu)
---------------------------------------------------------------------------- */
.apm-offcanvas-menu .elementor-nav-menu a.elementor-item{
  color:var(--e-global-color-0c26593) !important; background:transparent !important;
  font-family:"Lato 800",sans-serif; font-weight:800; text-transform:uppercase;
  font-size:18px; padding:16px 0;
  border-bottom:1px solid rgba(255,255,255,.08);
}
.apm-offcanvas-menu .elementor-nav-menu a.elementor-item:hover,
.apm-offcanvas-menu .elementor-nav-menu a.elementor-item.elementor-item-active{
  color:var(--e-global-color-accent) !important; background:transparent !important;
}
.apm-offcanvas-menu .sub-menu{
  position:static !important; width:100% !important;
  inset:auto !important; transform:none !important; box-shadow:none !important;
  background:transparent !important; padding:0 0 0 14px !important;
}
.apm-offcanvas-menu .sub-menu a.elementor-sub-item{
  display:block !important; width:100% !important;
  color:rgba(255,255,255,.85) !important; background:transparent !important;
  font-family:"Lato 500",sans-serif; font-weight:500; text-transform:none;
  font-size:16px; padding:12px 0 !important; white-space:normal;
  border-bottom:1px solid rgba(255,255,255,.06);
}
.apm-offcanvas-menu .sub-menu a.elementor-sub-item:hover,
.apm-offcanvas-menu .sub-menu a.elementor-sub-item.elementor-item-active{
  color:var(--e-global-color-accent) !important; background:transparent !important;
}
.e-off-canvas__body,
.e-off-canvas__main{
  max-height:100vh;
  max-height:100dvh;              /* URL-bar-safe, or the last item hides */
  overflow-y:auto; -webkit-overflow-scrolling:touch;
}
.apm-offcanvas-menu .sub-arrow,
.apm-offcanvas-menu .sub-arrow i,
.apm-offcanvas-menu .sub-arrow svg,
.apm-offcanvas-menu .elementor-item-icon{
  color:var(--e-global-color-0c26593) !important;
  fill:var(--e-global-color-0c26593) !important; font-size:18px !important;
}
.apm-offcanvas-menu .menu-item-has-children>.sub-menu{ display:none !important; }
.apm-offcanvas-menu .menu-item-has-children.apm-open>.sub-menu{ display:block !important; }


/* ----------------------------------------------------------------------------
   11.  TRUST BAR  (the gold band — home, interiors, and Docks)
   ONE responsive model for BOTH bars. The original bar and the Docks bar were
   built two years apart and behaved differently; this makes them agree.

   MEASURED behaviour of the ORIGINAL bar before this block existed
   (simulated from its own export):
     tablet 1024 / 820 / 768  ->  ONE per row, four rows
     phone  480 / 412 / 390   ->  two per row, icon ABOVE the text
   The tablet failure is a missing width: the item containers set no tablet
   width, so they inherit Elementor's 100% nested-container default (gotcha #3)
   and each one claims a whole line the moment flex-wrap turns on. Mobile only
   worked because those items DO carry width_mobile:45%.

   MARKUP: put `apm-trust-row` on the flex row that holds the items, and
   `apm-trust-item` on each item container. `dock-trust-item` is kept as an
   alias so the Docks bar keeps working without a re-import.
   !important throughout, because every one of these fights a per-element value
   the templates already emit (width_mobile:45%, flex_direction_mobile:column,
   align_mobile:center, justify-content:center) at ID specificity.
---------------------------------------------------------------------------- */
.apm-trust-divider{
  flex:0 0 1px !important; width:1px !important; min-width:1px !important;
  padding:0 !important; align-self:center;
  background:rgba(24,63,94,.4) !important;   /* = primary @ 40% */
}
@media (max-width:1024px){ .apm-trust-divider{ display:none !important; } }
/* display/margin forced: Elementor's image-widget CSS loads after ours and its
   img{display:inline-block} + widget{text-align:center} otherwise win. */
.apm-trust-icon{ text-align:left !important; }
.apm-trust-icon img{ height:26px; width:auto; display:block !important; margin-inline:0 !important; }

/* Dock-page label pair. The Docks bar carries two lines per item where the
   original carries one, so it needs the two type styles. Navy on the gold
   band, both caps. Classes: trust-lead / trust-sub */
.trust-lead{
  font-family:"Lato 800",sans-serif; font-weight:800;
  font-size:16px; line-height:1.3; text-transform:uppercase;
  color:var(--e-global-color-primary);
}
.trust-sub{
  font-family:"Lato 500",sans-serif; font-weight:500;
  font-size:16px; line-height:1.3; text-transform:uppercase;
  color:var(--e-global-color-primary);
}
.dock-trust-copy{ width:auto !important; }

/* DESKTOP PADDING FOR BOTH BARS lives here; both templates set only tablet and
   mobile, so this applies unopposed (no !important needed). Held at a fixed
   value it leaves the row no room to shrink before it wraps, which was half of
   why the Docks row broke at 1280. */
.apm-trust-bar { padding:34px clamp(24px, 4.6vw, 80px); }
.dock-trust-bar{ padding:20px clamp(24px, 7.2vw, 125px); }

/* BAND HEIGHT IS 97 IN ALL THREE COMPS — Home 4:64, Boat Lifts 441:365,
   Docks 740:336, every one of them 1728 x 97.

   Held with min-height rather than by adding up padding, because the two bars
   carry different content — one 16/20 line beside a 28px icon on Home and Boat
   Lifts, two lines on Docks — and deriving the padding from that made the two
   bands land 8px apart. A floor plus vertical centring hits 97 on both, at
   every width, whatever the content does.

   NOTHING IN THE EDITOR IS INVOLVED. Checked both templates 2026-09-04: the
   section carries padding_tablet and padding_mobile only, and every nested
   container — row, item, copy, divider — is 0 on all four sides at every
   breakpoint. Desktop padding came entirely from this stylesheet, and Home read
   taller than Docks purely because these two lines disagreed:
       .apm-trust-bar   34px      .dock-trust-bar   25px
   The !important is fighting our own later `padding` shorthands in section 39,
   which would otherwise win on source order — not anything a client set.
   Scoped to >=1025 so the templates' own tablet and phone padding still applies
   below it. */
@media (min-width:1025px){
  .apm-trust-bar, .dock-trust-bar{
    min-height:97px !important;
    justify-content:center !important;
    padding-block:16px !important;
  }
}

/* DOUBLE-WRAPPED BARS. On /boat-lifts/ the class sits on a page container that
   only holds the Elementor template widget; the template's own root carries it
   too. Both boxes then take the band treatment and the paddings stack:
     97 (inner) + 16 + 16 = 129   — measured in the client's DevTools 2026-09-04,
   against 97 on /home/ and /docks/ where the class is on one box only.
   A container whose direct child is a template widget is a wrapper, not the
   band, so it collapses onto the real one. Its background stays, which keeps
   the gold continuous whichever of the two is painting it. Removing the class
   from that wrapper in the editor fixes it just as well; this makes the page
   right either way. */
.apm-trust-bar:has(> .elementor-widget-template),
.dock-trust-bar:has(> .elementor-widget-template){
  min-height:0 !important;
  padding:0 !important;
}

/* ---- THE THREE STATES ----------------------------------------------------
   Client call 2026-09-04: ONE ROW on laptops, two rows on tablets, stacked on
   phones. Both bars now switch at the same widths.

   Breakpoints are measured, not assumed. Label widths taken in the LIVE Lato
   on staging (not a fallback face), longest of lead/sub per item:

     bar          text @16   + icon+gap   + 3 dividers   + 6 gaps@20   = row
     boat lifts      812        144             3            120        1079
     docks          1019        152             3            120        1294

   The docks row is the constraint. Against the comp's 10.94vw side margin a
   1294px row needs a 1656px window — which is exactly why it broke on a 1512
   MacBook and looked fine on the 4K. Capping the margin between 1200 and 1727
   and letting the type ride from 16 down to 13 is what buys the row: at 1512
   the content measures 1277 against a 1379px track, 102px of slack; at 1200 it
   is 1045 against 1094.
   ------------------------------------------------------------------------- */

/* ---- ONE ROW, 1200 AND UP ---- */
@media (min-width:1200px){
  .apm-trust-row, .dock-trust-row{
    flex-wrap:nowrap !important;
    justify-content:space-between !important;
    column-gap:clamp(14px, 1.2vw, 20px) !important;
  }
  .apm-trust-row .apm-trust-divider,
  .dock-trust-row .apm-trust-divider{ display:block !important; }
  /* min-width:0 lets a flex item shrink below its content width instead of
     forcing the row to wrap — without it nowrap would overflow the page. */
  .apm-trust-item, .dock-trust-item{
    width:auto !important; max-width:none !important;
    flex:0 1 auto !important; min-width:0 !important;
  }
}
/* Below the design width the comp's proportional margin is too generous for
   four items, so it is capped and the type scales with the window. From 1728
   up the AD's own numbers take back over — see section 39. */
@media (min-width:1200px) and (max-width:1727px){
  .apm-trust-bar { padding:16px clamp(32px, 4.0vw, 80px) !important; }
  .dock-trust-bar{ padding:16px clamp(32px, 4.4vw, 96px) !important; }
  .trust-lead, .trust-sub{
    font-size:clamp(13px, 1.06vw, 16px) !important; line-height:1.25 !important;
  }
  .apm-trust-icon img{ height:clamp(22px, 1.75vw, 28px) !important; max-width:34px; }
}

/* ---- TWO ROWS, TABLET (768-1199) ----------------------------------------- */
/* calc() widths that subtract the gap — % plus a fixed px gap rounds past 100%
   and drops to one column (gotcha #3). The 2px of slack is deliberate: at
   exactly (100% - gap)/2 the pair totals precisely 100% and sub-pixel rounding
   tipped one item onto its own row.
   THE GAP HAS TO BE PINNED, not just assumed. The calc below subtracts 24px;
   the original bar's template sets 32px at tablet, emitted per-element above
   any class rule. At 1024 that made two 459px items plus a 32px gap total 950
   against 944 of room, so the row broke to one per line while REPORTING the
   right widths — which looks like a width bug and is not one. */
@media (min-width:768px) and (max-width:1199px){
  .trust-lead, .trust-sub{ font-size:14px !important; }
  .apm-trust-row, .dock-trust-row{
    flex-wrap:wrap !important; justify-content:flex-start !important;
    column-gap:24px !important; row-gap:28px !important;
  }
  .apm-trust-row .apm-trust-divider,
  .dock-trust-row .apm-trust-divider{ display:none !important; }
  .apm-trust-item, .dock-trust-item{
    flex:0 0 calc((100% - 26px) / 2) !important;
    width:calc((100% - 26px) / 2) !important;
    max-width:calc((100% - 26px) / 2) !important;
    /* the original bar stacked icon ABOVE text and centred it; the Docks bar
       reads better with the icon beside left-aligned text, and the client
       picked that one. These two lines are what make them agree. */
    flex-direction:row !important;
    text-align:left !important;
  }
  .apm-trust-item .elementor-heading-title{ text-align:left !important; }
}

/* ---- STACKED, PHONE (<=767) ---------------------------------------------- */
/* Two columns squeeze the longer labels to three lines on any phone, so the
   whole band goes one-up. Section 39 steps the type to 13 here. */
@media (max-width:767px){
  .apm-trust-row, .dock-trust-row{
    flex-wrap:wrap !important; justify-content:flex-start !important;
    column-gap:0 !important; row-gap:24px !important;
  }
  .apm-trust-row .apm-trust-divider,
  .dock-trust-row .apm-trust-divider{ display:none !important; }
  .apm-trust-item, .dock-trust-item{
    flex:0 0 100% !important; width:100% !important; max-width:100% !important;
    flex-direction:row !important; text-align:left !important;
  }
  .apm-trust-item .elementor-heading-title{ text-align:left !important; }
}


/* ----------------------------------------------------------------------------
   12.  FOOTER  (on Mid Ship Blue background)
---------------------------------------------------------------------------- */
/* Column heading — Special Gothic 14, white. Class: footer-col-title */
.footer-col-title{
  font-family:"Special Gothic Expanded One",sans-serif; font-weight:400;
  font-size:14px; text-transform:uppercase;
  color:var(--e-global-color-0c26593);
}

/* Link list — Lato 300 16/32, white (one <a> per line). Class: footer-links */
.footer-links a{
  display:block; font-family:"Lato 300",sans-serif; font-weight:300;
  font-size:16px; line-height:32px;
  text-decoration:none; color:var(--e-global-color-0c26593);
}
.footer-links a:hover{ color:var(--e-global-color-accent); }
.footer-links a.sub{ padding-left:16px; font-size:13px; line-height:22px; }  /* Our Story / Why Us */

/* Description + copyright — Lato 300 16, white. Class: footer-muted.
   The copyright matches the description in the comp, so it needs no class. */
.footer-muted{
  font-family:"Lato 300",sans-serif; font-weight:300;
  font-size:16px; line-height:24px; color:var(--e-global-color-0c26593);
}


/* ----------------------------------------------------------------------------
   13.  THIRD-PARTY WIDGETS (Elfsight IG feed + Google reviews) — NOTE ONLY
   Styled INSIDE Elfsight, not here. Elfsight injects ID-scoped !important styles
   that out-rank global class rules, so overriding from this sheet is a losing
   specificity war. Load More button = transparent fill, 2px #F1AE45 border,
   #F1AE45 text, radius 70, hover fill #F1AE45 / text #183F5E.
---------------------------------------------------------------------------- */


/* ----------------------------------------------------------------------------
   14.  SCROLL-OVER STICKY STACK  (full-screen panels)
   Each full-height panel pins to the top and the NEXT panel scrolls up over it.
   Pure CSS — no JS, no scroll library.
     Container .apm-stack-wrap     plain wrapper: full width, no bg/padding/gap
       Container .apm-stack        one panel
       Container .apm-stack        …
   The WRAPPER is the sticky containing block, so the pile releases the moment
   you scroll past it. Without it the panels glue to the top for the rest of the
   page.
   REQUIREMENTS
   - Every panel needs a solid edge-to-edge background, or lower panels show
     through.
   - Every panel must FIT the viewport. A pinned panel does not move relative to
     the viewport, so anything below the fold inside it is unreachable — that is
     what killed the Boat Lifts product panels (see 27).
   - No ancestor may clip overflow. Not hidden, not clip, not on any breakpoint.
---------------------------------------------------------------------------- */
/* NEVER CLIP AN ANCESTOR OF A STICKY ELEMENT.
   overflow-x:clip does not create a scroll container, so sticky still PINS —
   but in WebKit a clipped ancestor drops the sticky layer off the async
   scrolling path, so it repaints on the main thread every frame and the whole
   panel visibly vibrates. Chrome and Firefox absorb it; Safari does not. This
   cost a full day on section 28. `html, body, .elementor{overflow-x:clip}` used
   to live here — that was the bug. Hello Elementor's .page-content ships its own
   clip, so it is undone too. If a page scrolls sideways, fix the element that
   overflows; never clamp an ancestor. */
html, body, .elementor, .page-content{ overflow-x: visible !important; }

.apm-stack-wrap{ position: relative; overflow: visible; }

/* A reveal's transform on an ancestor re-parents the sticky containing block
   AND promotes a layer — same failure class as the clip above. Belt and braces
   in case `reveal` is ever dropped on one of these wrappers in the editor. */
.sixty-wrap.reveal, .apm-stack-wrap.reveal, .apm-stack.reveal{
  opacity:1 !important; transform:none !important; transition:none !important;
}

/* Must beat Elementor's base .e-con{position:relative} — equal specificity, so
   load order could otherwise let 'relative' win and kill the stick. */
.apm-stack{
  position: -webkit-sticky !important;
  position: sticky !important;
  top: 0;                 /* pin flush to the top; header floats above */
  min-height: 100vh;
  min-height: 100dvh;     /* true viewport on phones (URL-bar-safe) */
  overflow: visible;
  align-self: start;      /* don't let flex align-items:stretch defeat the stick */
}

/* NO PIN BELOW 1025 — every stack, every page.
   A pinned panel does not move relative to the viewport, so anything past its
   own fold can never be scrolled to. Measured on Docks at 390x844: composite is
   1213px, which buries 369px of copy; wood buries 63px. No panel on this site
   fits a phone, so there is no width below 1025 where the effect can work.
   Placed here, after the sticky rule, so equal specificity resolves in favour
   of static. Panels keep their 100vh floor; only the pin goes. */
@media (max-width:1024px){
  .apm-stack{ position: static !important; }
}

/* THE 100vh FLOOR GOES WITH THE PIN. Un-pinned it buys nothing and manufactures
   empty screens — the blank band a visitor reads as a dead end before a short
   panel's content. 60vh is the figure sections 31/33/47 already use when they
   un-pin, so a photographic band still reads as a band. Sections 27 and 49 load
   later and keep their own min-height:0. Delete this block to restore 100vh. */
@media (max-width:1024px){
  .apm-stack{ min-height:60vh; min-height:60dvh; }
}

/* The home page's Post Lifts panel holds two products side by side (~1 screen on
   desktop) but they stack below 1025px, making it ~2 screens = dead scroll.
   Class apm-stack-duo on that panel, keeping apm-stack. */
@media (max-width:1024px){
  /* Two classes, so it beats .apm-stack on specificity, not on source order. */
  .apm-stack.apm-stack-duo{ position: static !important; }
}


/* ----------------------------------------------------------------------------
   15.  INLINE ROWS SAFETY NET  (product spec stats + CTA button pairs)
   Elementor's flex-direction control can silently drop to column at depth, and
   nesting inside .apm-stack-wrap pushes these rows a level deeper. These win at
   any depth.
---------------------------------------------------------------------------- */
.spec-row{ display:flex !important; flex-direction:row !important; flex-wrap:nowrap !important; align-items:flex-start; }
.cta-row { display:flex !important; flex-direction:row !important; flex-wrap:nowrap !important; align-items:center; }

/* Phones: CTAs stack full-width; let the 3-up stats wrap only if genuinely needed. */
@media (max-width:767px){
  .cta-row { flex-direction:column !important; align-items:flex-start; }
  .spec-row{ flex-wrap:wrap !important; }
}


/* ----------------------------------------------------------------------------
   16.  MOTION — reduced-motion fallback + scroll-in reveals
   Pairs with the head snippet (Elementor → Custom Code) that adds .apm-anim to
   <html> and toggles .is-in via IntersectionObserver.
   Usage: class "reveal" on any section/column/widget; add d1..d4 to sequential
   children to stagger. ONE level per group — container or children, never both.
---------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce){
  .apm-stack{ position: static !important; }
  .apm-anim .reveal{ opacity:1 !important; transform:none !important; transition:none !important; }
}

/* Hidden pre-state is gated on .apm-anim. If the script fails, nothing hides —
   no blank sections, no SEO/LCP risk.

   TIMING — measured 2026-09-05, not eyeballed. Two numbers govern it: ENTRY
   OPACITY (what the element reads as the moment its top crosses the viewport
   bottom) and t50 (how far the section has travelled on screen before 50%).

   Originally .7s/24px/.08s with the snippet firing at 15% visibility, 10% up
   from the fold: a phone at 1600px/s reached 50% on the last staggered item
   only after 1336px of travel — 1.58 screens, top edge already off the top of
   the window. The dead end.

   Then .42s/14px/.05s with an 18% early trigger, which overcorrected: entry
   opacity 0.68 at a 800px/s reading scroll. Two-thirds of the animation had
   already run before the element appeared, so nothing was visible.

   Now .55s/22px/.07s with the trigger back on the fold. Entry opacity 0.00 at
   every speed — the whole move plays on screen — and t50 is 259px (800px/s) /
   418px (1600px/s) against the original 402 / 607. Sweep with sweep.js before
   changing any of them; a negative bottom margin buys no extra visibility once
   entry opacity is already 0, it only adds lateness. */
.apm-anim .reveal{
  opacity:0;
  transform:translateY(22px);
  transition:opacity .55s ease, transform .55s cubic-bezier(.2,.7,.2,1);
}
.reveal.is-in{ opacity:1; transform:none; }

/* Already in the first viewport at boot: paint final, never animate. A fade on
   the LCP element defers LCP by the whole duration. Set by the head snippet. */
.reveal.reveal-now{ opacity:1 !important; transform:none !important; transition:none !important; }

/* EDITOR SAFETY: the observer doesn't run in the editor iframe, so .reveal would
   sit at opacity:0 and be uneditable. Elementor only sets this body class in the
   editor, so the live page still animates. */
body.elementor-editor-active .reveal{ opacity:1 !important; transform:none !important; transition:none !important; }

.reveal.d1{ transition-delay:.07s; }
.reveal.d2{ transition-delay:.14s; }
.reveal.d3{ transition-delay:.21s; }
.reveal.d4{ transition-delay:.28s; }


/* ----------------------------------------------------------------------------
   17.  CO-STATS BAR  (interior hero stat strip, on navy)
   Figure: co-stat-num (trailing char uses .hl). Label: co-stat-label.
   Divider: co-stat-rule. Bar container: co-stats.
---------------------------------------------------------------------------- */
.co-stat-num{
  font-family:"Special Gothic Expanded One",sans-serif;
  font-weight:400; font-size:28px; line-height:1;
  color:var(--e-global-color-0c26593);
}
.co-stat-label{
  font-family:"Lato 500",sans-serif;
  font-weight:500; font-size:16px; line-height:1.25;
  letter-spacing:.02em; text-transform:uppercase;
  color:var(--e-global-color-0c26593);
}
.co-stat-rule{
  width:1px !important;
  height:47px;
  min-height:0;
  align-self:center;
  padding:0 !important;            /* kill Elementor's default 10px container padding */
  border-radius:0;
  background:rgba(255,255,255,.22);
}

/* Elementor makes nested containers width:100%, which forces each stat onto its
   own row — pin the cells to content width so the four sit inline. */
.co-stats{ display:flex; flex-direction:row; flex-wrap:wrap; align-items:center; }
.co-stats > *{ width:auto !important; }
.co-stats > .co-stat-rule{ width:1px !important; }
@media (max-width:767px){
  .co-stat-rule{ display:none; }
  .co-stats > *:not(.co-stat-rule){ width:44% !important; }  /* 2×2 on phones */
}


/* ----------------------------------------------------------------------------
   18.  DISPLAY HEADING — interior section titles run 100px, not the 60px home
   H2. Theme Style stays untouched; the tag stays H2. Class: h2-display
---------------------------------------------------------------------------- */
.h2-display .elementor-heading-title{ font-size:100px !important; line-height:.92em !important; }
@media (max-width:1024px){ .h2-display .elementor-heading-title{ font-size:64px !important; } }
@media (max-width:767px){  .h2-display .elementor-heading-title{ font-size:44px !important; } }
/* Line breaks come from <span class="nl"> in the title — see section 3. */


/* ----------------------------------------------------------------------------
   19.  FLEET SECTION media tiles
   Class on the Image widget: fleet-img.  On the Video widget: fleet-video.
---------------------------------------------------------------------------- */
/* The 16:9 box goes on the <img> ITSELF, with height:auto — a % height has no
   definite parent height to resolve against, so pinning the ratio on the widget
   container instead makes the img fall back to its natural height (this is why
   the barge tile grew and the truck tile looked fine). Do NOT add overflow or
   position:absolute here either — both break widget selection on the editor
   canvas. object-fit:cover also crops any alpha strip a Figma export carried. */
.fleet-img{ width:100% !important; align-self:stretch !important; }
.fleet-img img{
  display:block;
  width:100% !important;
  height:auto !important;
  aspect-ratio:16 / 9 !important;
  object-fit:cover; object-position:center;
  border-radius:0;
}

/* Brand-reel video tile — navy scrim + gold play disc, opens the Elementor
   lightbox. */
.fleet-video .elementor-wrapper,
.fleet-video .elementor-custom-embed-image-overlay{ border-radius:0; overflow:hidden; }
.fleet-video .elementor-custom-embed-image-overlay{ position:relative; }
.fleet-video .elementor-custom-embed-image-overlay::before{
  content:""; position:absolute; inset:0;
  background:rgba(24,63,94,.5); transition:opacity .3s ease; pointer-events:none;
}
.fleet-video .elementor-custom-embed-image-overlay:hover::before{ opacity:.72; }

/* Play button drawn entirely in CSS — Elementor's cut-SVG import is flaky and
   gives no size control. Hide whatever glyph the widget renders, then draw a
   52px gold disc masked by an inline SVG whose triangle is a true hole
   (fill-rule:evenodd), so the video shows through it.
   REQUIRED: Video widget → Image Overlay = Show, with a poster assigned —
   that is what makes Elementor render this overlay at all. The widget's Icon
   choice no longer matters. */
.fleet-video .elementor-custom-embed-play i,
.fleet-video .elementor-custom-embed-play svg{ opacity:0 !important; }
.fleet-video .elementor-custom-embed-play::before{
  content:""; position:absolute; top:50%; left:50%;
  transform:translate(-50%,-50%);
  width:52px; height:52px;
  background:var(--e-global-color-accent);
  filter:drop-shadow(0 4px 14px rgba(0,0,0,.22));
  transition:transform .25s ease;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 52 52'%3E%3Cpath fill='%23fff' fill-rule='evenodd' d='M26 0A26 26 0 1 0 26 52 26 26 0 0 0 26 0Z M21 17 L37 26 L21 35 Z'/%3E%3C/svg%3E") center/contain no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 52 52'%3E%3Cpath fill='%23fff' fill-rule='evenodd' d='M26 0A26 26 0 1 0 26 52 26 26 0 0 0 26 0Z M21 17 L37 26 L21 35 Z'/%3E%3C/svg%3E") center/contain no-repeat;
}
.fleet-video .elementor-custom-embed-play:hover::before{
  transform:translate(-50%,-50%) scale(1.08);
}


/* ----------------------------------------------------------------------------
   20.  WHITE-GLOVE step title + icon
   H3 shrunk to the comp's 20px, Title Case. Tag stays H3. Class: step-title
   Also used by the Docks icon grid (section 34).
---------------------------------------------------------------------------- */
.step-title .elementor-heading-title{
  font-size:20px !important;
  line-height:1.15 !important;
  text-transform:none !important;
}

/* Step icons as SVG-in-Image — Elementor's Icon-widget SVG mode crashes the
   editor with cut SVGs. Assign each via the Media Library. Class: wg-icon */
.wg-icon{ text-align:left !important; }
.wg-icon img{ width:28px; height:auto; display:block !important; margin-inline:0 !important; }


/* ----------------------------------------------------------------------------
   21.  WHITE-GLOVE layout
   % widths + a fixed px gap round past 100% and wrap (this is what made tablet
   render 3 rows of 2). calc() widths that SUBTRACT the gaps are exact at every
   width, and the columns then need no width settings of their own.
   Class on the steps row: wg-steps.  On the section: wg-section.
---------------------------------------------------------------------------- */
.wg-steps{ column-gap:48px !important; row-gap:52px !important; }
.wg-steps > *{                                   /* desktop: 3-across (2 gaps) */
  flex:0 0 calc((100% - 96px) / 3) !important;
  width:calc((100% - 96px) / 3) !important;
  max-width:calc((100% - 96px) / 3) !important;
}
@media (max-width:1024px){                        /* tablet: 2-across, roomy copy */
  .wg-steps{ column-gap:40px !important; row-gap:44px !important; }
  .wg-steps > *{
    flex:0 0 calc((100% - 40px) / 2) !important;
    width:calc((100% - 40px) / 2) !important;
    max-width:calc((100% - 40px) / 2) !important;
  }
}
@media (max-width:767px){                         /* mobile: single column */
  .wg-steps{ row-gap:24px !important; }
  .wg-steps > *{
    flex:0 0 100% !important; width:100% !important; max-width:100% !important;
    row-gap:8px !important;                       /* icon → title → copy */
  }
  .wg-steps .elementor-widget-text-editor p{ margin:0 !important; }
  /* The bleed photo is dropped below 768px, so the reserved space goes too. */
  .wg-section{ padding-bottom:56px !important; }
}

/* The bottom bleed photo crops to a pixelated vertical slice at phone width and
   destroys contrast under the copy. Drop it and force a solid white overlay;
   desktop and tablet keep the designed bleed. */
@media (max-width:767px){
  .wg-section{ background-image:none !important; }
  .wg-section > .elementor-background-overlay{
    opacity:1 !important; background:var(--e-global-color-0c26593) !important;
  }
}


/* ----------------------------------------------------------------------------
   22.  FLEET tiles — same calc() grid so the 3 media tiles never wrap.
   3-across desktop + tablet, single column on mobile. Class: fleet-tiles
---------------------------------------------------------------------------- */
.fleet-tiles{ column-gap:24px !important; row-gap:44px !important; }
.fleet-tiles > *{
  flex:0 0 calc((100% - 48px) / 3) !important;
  width:calc((100% - 48px) / 3) !important;
  max-width:calc((100% - 48px) / 3) !important;
}
@media (max-width:767px){
  .fleet-tiles{ row-gap:28px !important; }
  .fleet-tiles > *{
    flex:0 0 100% !important; width:100% !important; max-width:100% !important;
  }
  .fleet-tiles .elementor-widget-text-editor p{ margin:0 !important; }
}


/* ----------------------------------------------------------------------------
   23.  LAMBO LIFT featured project
   Spec figures REUSE stat-num + stat-label — no new number class.
---------------------------------------------------------------------------- */
/* THE GRADIENT-WITHOUT-A-PHOTO BAND.
   Measured on /boat-lifts/ 2026-09-04: .lambo-section is data-id 46e3e92 and the
   SEVENTH .e-con.e-parent on the page, so Elementor's own lazy-load rule
     .e-con.e-parent:nth-of-type(n+4):not(.e-lazyloaded){background-image:none!important}
   suppresses its photograph until the IntersectionObserver adds .e-lazyloaded.
   Forcing that class restores lambo-boat-lift.jpg at cover across the full
   1032px — so the Elementor setting is right, nothing to change there.
   The problem is what shows in the meantime: the section's own background-color
   is transparent, so the ::before gradient renders over the white page and
   reads as a pale band above and below the picture. Giving the section the navy
   the gradient was drawn against means the pre-load state is invisible.
   The alternative is Elementor > Settings > Features > Lazy Load Background
   Images, off — that removes the deferral entirely, at some CWV cost on long
   pages. This is the cheaper half. */
.lambo-section{ background-color:var(--e-global-color-primary); }

/* 3-across calc grid, 2 rows of 3. Class: lambo-specs */
.lambo-specs{ column-gap:24px !important; row-gap:26px !important; }
.lambo-specs > *{
  flex:0 0 calc((100% - 48px) / 3) !important;
  width:calc((100% - 48px) / 3) !important;
  max-width:calc((100% - 48px) / 3) !important;
}
@media (max-width:767px){
  .lambo-specs{ column-gap:16px !important; }
  .lambo-specs > *{
    flex:0 0 calc((100% - 16px) / 2) !important;   /* phones: 2-across */
    width:calc((100% - 16px) / 2) !important;
    max-width:calc((100% - 16px) / 2) !important;
  }
}

/* Hairline under the description (semi-transparent rgba is the allowed case). */
.lambo-rule{
  height:1px !important; width:100% !important;
  background:rgba(255,255,255,.22) !important;
  padding:0 !important; margin:6px 0 !important;
}

/* Pull-quote + attribution. Classes: lambo-quote / lambo-cite */
.lambo-quote .elementor-heading-title,
.lambo-quote{
  font-family:"Lato 500",sans-serif; font-weight:500; font-style:italic;
  font-size:20px; line-height:1.4;
  color:var(--e-global-color-0c26593);
}
.lambo-cite{
  font-family:"Lato 800",sans-serif; font-weight:800;
  font-size:16px; letter-spacing:.02em; text-transform:uppercase;
  color:var(--e-global-color-accent);
}


/* ----------------------------------------------------------------------------
   24.  PRODUCT SPEC SECTIONS (Elevator / 4-Post / 8-Post / Jet Ski)
---------------------------------------------------------------------------- */
.prod-media{ min-height:640px; background-size:cover; background-position:center; }

/* THE PANEL CHANGES SHAPE TOO MUCH — that is the "too zoomed in" on tablet.
   Measured live 2026-09-04, the same photograph has to fill all of these:
     2560  1270x1170  ratio 1.09      1728   857x1254  ratio 0.68
     1280   633x1444  ratio 0.44      768    753x420   ratio 1.79
      390   390x280   ratio 1.39
   A 4x swing in shape. Under `cover` only the middle 49% x 50% of any source is
   guaranteed visible at every one of them, so whatever you feed it is cropped to
   a quarter of the frame somewhere — on tablet that quarter is the middle band
   of a letterbox, which reads as a hard zoom.
   On desktop the panel has to stretch: it sits beside a spec table 1200-1450
   tall and a short photo would leave a gap. Tablet and phone have no such
   partner, so they take a fixed 4:3 instead of a 420/280 floor. That lifts the
   guaranteed area to 58% x 57% and, more to the point, stops the tablet crop
   being a different photograph from the desktop one. */
@media (max-width:1024px){ .prod-media{ min-height:0; aspect-ratio:4/3; } }

.spec-rule{
  flex:1 1 auto !important; height:1px !important;
  background:var(--e-global-color-accent) !important; padding:0 !important;
  margin-left:16px !important;
}

/* No border-top on .spec-table — .spec-line's bottom border draws every rule.
   A top border duplicates the gold .spec-rule above the first row. */
.spec-line{ border-bottom:1px solid var(--e-global-color-secondary); }
.spec-key{ flex:0 0 42% !important; max-width:42% !important; }
.spec-val{ flex:0 0 58% !important; max-width:58% !important; }
.spec-key .elementor-heading-title{
  font-family:"Lato 500",sans-serif; font-weight:500; font-size:16px;
  line-height:1.45; text-transform:uppercase; color:var(--e-global-color-text);
}
.spec-val .elementor-heading-title{
  font-family:"Lato 800",sans-serif; font-weight:800; font-size:16px;
  line-height:1.45; color:var(--e-global-color-text);
}

/* Accent background from Theme Style, white label per the comp. Class: btn-white */
.btn-white .elementor-button,
.btn-white .elementor-button:visited{ color:var(--e-global-color-0c26593) !important; }
.btn-white .elementor-button .elementor-button-icon svg{ fill:var(--e-global-color-0c26593) !important; }
.btn-white .elementor-button .elementor-button-icon i{ color:var(--e-global-color-0c26593) !important; }


/* ----------------------------------------------------------------------------
   25.  GALLERY — KISS CoverFlow Slider
   Spec: APM-Gallery-Section-Handoff.md §5. Two-class .elementor-kit-19s beat the plugin
   sheet without !important on the variables.
---------------------------------------------------------------------------- */
.elementor-widget-kiss_coverflow .kiss-coverflow {
  --kiss-accent:           var(--e-global-color-accent);
  --kiss-tab-idle:         var(--e-global-color-63af1b4);
  --kiss-tab-idle-opacity: 1;
  --kiss-tab-active:       var(--e-global-color-accent);
  --kiss-tab-rule-h:       0;              /* comp has no active underline */
  --kiss-tab-gap-x:        88px;
  --kiss-tabs-mb:          91px;
  --kiss-surface:          var(--e-global-color-primary);
  --kiss-radius:           43px;
  --kiss-shadow:           4px 4px 10px 6px rgba(0, 0, 0, .25);
  --kiss-idle-opacity:     1;              /* dimming is the scrim below, not opacity */
  --kiss-focus:            var(--e-global-color-accent);
}

/* Placeholder for the CoverFlow widget on the boat-lift detail page. Holds its
   height before the widget loads so the page does not jump (CLS). Comp slider
   band is 546px tall inside a 1250px section. */
.gallery-slot{ min-height:546px; }
@media (max-width:1024px){ .gallery-slot{ min-height:380px; } }
@media (max-width:767px){  .gallery-slot{ min-height:260px; } }

/* Heading block sits on the 140px comp margin; the slider stays full-bleed. */
.gallery-head{ margin-bottom:64px; }
@media (max-width:767px){ .gallery-head{ margin-bottom:40px; } }

/* Tabs align with the heading while the slider stays full-bleed. */
.elementor-widget-kiss_coverflow .kiss-filters {
  padding-inline-start: 8.6vw;             /* 149 / 1728 */
}

/* Text-only tabs per the comp — strip the plugin's default pill.
   Lato 800 at 16, no added tracking (the plugin theme layer adds .04em). */
.elementor-widget-kiss_coverflow .kiss-filter {
  font-family: "Lato 800", sans-serif;
  font-weight: 800;
  font-size: 16px;
  letter-spacing: normal;
  background: transparent !important;
  border: 0 !important;
  padding: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  color: var(--kiss-tab-idle) !important;                 /* teal, inactive */
  transition: color .2s ease;
  cursor: pointer;
}
.elementor-widget-kiss_coverflow .kiss-filter.is-active,
.elementor-widget-kiss_coverflow .kiss-filter[aria-selected="true"],
.elementor-widget-kiss_coverflow .kiss-filter[aria-pressed="true"],
.elementor-widget-kiss_coverflow .kiss-filter:hover {
  color: var(--kiss-tab-active) !important;               /* sunshine, active */
}

/* No white card behind the slide — comp is photo + radius + shadow only. */
.elementor-widget-kiss_coverflow .kiss-frame {
  background: transparent !important;
  border: 0 !important;
  padding: 0 !important;
}

/* Figma dims neighbours with a 60% #1e1e1e scrim, not lowered opacity. */
.elementor-widget-kiss_coverflow .kiss-frame::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: rgba(30, 30, 30, .6);
  pointer-events: none;
  transition: opacity .4s ease;
}
.elementor-widget-kiss_coverflow .swiper-slide-active .kiss-frame::after { opacity: 0; }

@media (max-width: 1024px) {
  .elementor-widget-kiss_coverflow .kiss-coverflow {
    --kiss-tab-gap-x: 40px;
    --kiss-tabs-mb:   56px;
  }
}
@media (max-width: 767px) {
  .elementor-widget-kiss_coverflow .kiss-coverflow {
    --kiss-tab-gap-x: 20px;
    --kiss-tabs-mb:   32px;
    --kiss-radius:    24px;
  }
  .elementor-widget-kiss_coverflow .kiss-filters { padding-inline-start: 20px; }
}
@media (prefers-reduced-motion: reduce) {
  .elementor-widget-kiss_coverflow .kiss-frame::after { transition: none; }
}


/* ----------------------------------------------------------------------------
   26.  "NOT SURE?" CTA BAND — heading left, two stacked pills right
   The comp has both buttons at a matched 280px; Theme Style would size them to
   their labels, so the width is forced here rather than baked into the template.
---------------------------------------------------------------------------- */
.notsure-ctas .elementor-button{
  display:flex; width:280px; justify-content:center;
}
@media (max-width:767px){
  .notsure-ctas .elementor-button{ width:100%; }
}


/* ----------------------------------------------------------------------------
   27.  BOAT LIFTS — STACK OFF.  Class: stack-desktop
   Measured on the live page at a 1512px window: the four product panels are
   1214 / 1214 / 1249 / 1275px tall, and grow taller as the window narrows. Real
   viewport heights are ~780px on a 14" MBP, ~940px on a 1080p monitor, ~1300px
   at 1440p. A pinned panel does not move relative to the viewport, so a panel
   taller than the window can never scroll its spec stats and buttons into view
   — verified headless, and bottom:0 does not rescue it either. Since 1275 > 940
   on the commonest desktop, these panels do not pin anywhere the effect would
   work, so the pin is off at every size and `reveal` carries the motion.
   Put the class on the wrapper (one place) or on each panel — both match.
   ROLLBACK: remove the class, or delete this block.
---------------------------------------------------------------------------- */
.stack-desktop .apm-stack,
.apm-stack.stack-desktop{
  position:static !important;
}

/* Phones and tablets also drop the 100vh floor — short content would otherwise
   leave big empty sections. Desktop keeps it so sections still read full-bleed. */
@media (max-width:1024px){
  .stack-desktop .apm-stack,
  .apm-stack.stack-desktop{
    min-height:0 !important;
  }
}

/* To re-pin on very tall displays only, un-comment this. 1320px is the tallest
   panel plus headroom; re-measure if the spec tables change. The reveals must be
   suppressed there too, or the panel fades and pins at once.
@media (min-width:1025px) and (min-height:1320px){
  .stack-desktop .apm-stack,
  .apm-stack.stack-desktop{ position:sticky !important; }
  .stack-desktop .apm-stack .reveal,
  .apm-stack.stack-desktop .reveal{
    opacity:1 !important; transform:none !important; transition:none !important;
  }
}
*/

/* ----------------------------------------------------------------------------
   28.  "60 SECONDS" STEP SEQUENCE  (boat-lift detail pages)
   ART AND COPY ARE SEPARATE LISTS. .sixty-art holds all four drawings in one
   frame; .sixty-steps holds the four copy blocks. They are paired by the s1-s4
   classes, NOT by order — reordering one list no longer desyncs the other.
     .sixty-wrap                 scroll track (desktop only)
       .sixty-stage
         .sixty-head             eyebrow + H2
         .sixty-art              one shared art frame
           .elementor-widget-image .s1-.s4
         .sixty-steps
           .sixty-step .s1-.s4   copy block
             .sixty-copy
         .sixty-dots
   JS only sets data-step="1..4" on .sixty-stage. Every visual change is here.

   DESKTOP pins the whole stage inside a 400vh track and swaps art + copy as
   you scroll through it.
   MOBILE / TABLET does not pin at all — it is a SWIPE CAROUSEL. See the block
   below for why.

   SIZING — read before changing anything.
   The step SVGs are wide crops whose left third is only water, so fitting the
   IMAGE box makes the hull far too big. Rendering all four into the 1728x1186
   comp and thresholding ink gives the box the SOLID artwork occupies:
        x 577..1727 , y 313..995   =  1150 x 682 comp px.
   That box is sized and placed; the image hangs off it with plain percentages.
   Each SVG is its own crop, so each needs its own line — from the Figma rects
   326/313/1409x711 · 360/386/1374x634 · 500/384/1230x680 · 621/370/1110x707.
   Re-cut assets = recompute those four lines.
---------------------------------------------------------------------------- */
:root{
  --sixty-header:96px;           /* desktop sticky header — stage pins BELOW it */
  --sixty-header-m:76px;         /* mobile header — kept for section 32 anchors */
  --sixty-head-band:176px;
  --sixty-foot-band:118px;
  /* Sequenced, never cross-dissolved: the outgoing state fades out, THEN the
     incoming fades in. Overlapping shows two boats at two heights.           */
  --sixty-out:.28s;
  --sixty-in:.34s;
  --sixty-fade:.3s;
}

/* Fallback layout: a plain vertical list. */
.sixty-wrap{ position:relative; }
.sixty-stage{ display:flex; flex-direction:column; gap:40px; }
.sixty-steps{ display:flex; flex-direction:column; gap:56px; }
.sixty-copy{ display:block; }
.sixty-dots{ display:none; }

/* ---- ART: one frame, four drawings, at every size -------------------------
   max-width:none is required — Elementor's base sheet caps images at 100%.
   display:contents neutralises .elementor-widget-container when it exists;
   Elementor 3.25+ "Optimized Markup" deletes it, so nothing may depend on it. */
.apm-anim .sixty-art{ position:relative; overflow:hidden; }
/* COLD START — Core Web Vitals. All four drawings share one box, so the browser
   counts every one as visible and downloads all four before first paint: ~295 KB
   gzipped on the critical path of a page whose LCP element is the step-1
   drawing.
   `loading="lazy"` DOES NOT HELP — measured: the browser still fetched all four,
   because lazy only defers images OUTSIDE the viewport and these are inside it.
   Nor can JS help: the preload scanner queues every src during HTML parsing,
   before any end-of-body script runs.
   display:none is the one thing that stops the fetch. So steps 2-4 start
   displayed:none and the engine adds .art-warm after window.load, which swaps
   them to the opacity model and lets them download off the critical path.
   Without JS the section falls back to the plain list, which resets display
   anyway — see the reduced-motion and editor blocks. */
.apm-anim .sixty-art .elementor-widget-image{ display:none; }
.apm-anim .sixty-art .s1{ display:block; }

.apm-anim .sixty-art.art-warm .elementor-widget-image{
  display:block;
  opacity:0; visibility:hidden;
  transition:opacity var(--sixty-out) ease, visibility 0s linear var(--sixty-out);
  pointer-events:none;
}
.apm-anim .sixty-art .elementor-widget-image > .elementor-widget-container{
  display:contents;
}
.apm-anim .sixty-art .elementor-widget-image img{
  position:absolute; max-width:none; display:block;
  object-fit:fill;                /* the rect IS the artboard — no letterboxing */
}
.apm-anim .sixty-art .s1 img{ left:-21.826%; top:0.000%;  width:122.522%; height:104.252%; }
.apm-anim .sixty-art .s2 img{ left:-18.870%; top:10.704%; width:119.478%; height:92.962%; }
.apm-anim .sixty-art .s3 img{ left:-6.696%;  top:10.411%; width:106.957%; height:99.707%; }
.apm-anim .sixty-art .s4 img{ left:3.826%;   top:8.358%;  width:96.522%;  height:103.666%; }

/* One rule lights the active art AND the active copy — the s-class is on both.
   On mobile the copy half is overridden: every slide is visible there and the
   TRACK POSITION is the state. */
.apm-anim .sixty-stage[data-step="1"] .sixty-steps .s1,
.apm-anim .sixty-stage[data-step="2"] .sixty-steps .s2,
.apm-anim .sixty-stage[data-step="3"] .sixty-steps .s3,
.apm-anim .sixty-stage[data-step="4"] .sixty-steps .s4,
.apm-anim .sixty-stage[data-step="1"] .art-warm .s1,
.apm-anim .sixty-stage[data-step="2"] .art-warm .s2,
.apm-anim .sixty-stage[data-step="3"] .art-warm .s3,
.apm-anim .sixty-stage[data-step="4"] .art-warm .s4{
  opacity:1; visibility:visible;
  transition:opacity var(--sixty-in) ease var(--sixty-out), visibility 0s;
}

/* ============================ DESKTOP — pin the stage =====================
   UNCHANGED. Do not edit this block while working on mobile.               */
@media (min-width:1025px){
  .apm-anim .sixty-wrap{ height:400vh; }

  .apm-anim .sixty-stage{
    position:sticky; top:var(--sixty-header);
    height:calc(100vh - var(--sixty-header));   /* dvh upgrade below, via
                                                   @supports — a declaration
                                                   pair does NOT fall back when
                                                   the value contains var() */
    overflow:hidden; display:block;
  }
  .apm-anim .sixty-head{ position:relative; z-index:5; }
  .apm-anim .sixty-dots{
    display:flex; justify-content:center; align-items:flex-start;
    position:absolute; left:0; right:0; bottom:40px; z-index:5;
  }

  /* THE STRUCTURE BOX — width is the smaller of what is left beside the copy,
     and what the band between heading and indicator allows (1150/682=1.6862).
     One min() of two flat calcs. No nested clamp/min, no custom-property
     arithmetic — the previous version used both and Firefox rendered it far
     larger than Chromium, so this is deliberately dull.
     390 = --sixty-header 96 + --sixty-head-band 176 + --sixty-foot-band 118.
     642 = copy left 148 + copy width 430 + 64 gutter.
     Change either band and BOTH numbers must change with it. */
  .apm-anim .sixty-art{ position:absolute; inset:0; overflow:visible; z-index:0; }
  .apm-anim .sixty-art .elementor-widget-image{
    position:absolute; right:0; top:var(--sixty-head-band);
    width:min( calc(100vw - 642px),
               calc((100dvh - 390px) * 1.6862) );
    aspect-ratio:1150 / 682;
  }

  .apm-anim .sixty-steps{ position:absolute; inset:0; display:block; z-index:1; }
  .apm-anim .sixty-step{
    position:absolute; inset:0;
    opacity:0; visibility:hidden;
    transition:opacity var(--sixty-out) ease, visibility 0s linear var(--sixty-out);
  }
  .apm-anim .sixty-copy{
    position:absolute; left:clamp(24px,8vw,148px); top:50%; transform:translateY(-50%);
    width:min(30vw,430px); z-index:3;
  }
}

/* svh/dvh UPGRADE — via @supports, NOT a declaration pair.
   `height:100vh; height:100dvh;` does not fall back when the value contains
   var(): the browser cannot reject it at parse time, so an unsupported unit
   makes it invalid AT COMPUTED-VALUE TIME, which resets height to auto and
   throws away the good vh line above. */
@supports (height:1dvh){
  @media (min-width:1025px){
    .apm-anim .sixty-stage{ height:calc(100dvh - var(--sixty-header)); }
  }
}

/* ==================== MOBILE / TABLET — SWIPE CAROUSEL =====================
   NO PIN, NO SCROLL TRACK. Rewritten 2026-08-24; replaces the pinned-panel
   version and, with it, the touch-snap engine.

   WHY. Scroll-driven stepping needs a scroll position that maps predictably
   onto a step, and touch scrolling does not give you one: a gentle drag is
   ~150px, a hard flick is 2000px+, against a ~450px step. No linear mapping
   works across that range. Deriving the step from the GESTURE instead fixed
   the skipping, but you could still feel the engine deciding what you meant.
   So below 1025px the section stops driving off page scroll entirely. It is a
   normal-height section, and the four COPY blocks become a horizontal
   scroll-snap track the finger moves directly — one swipe, one panel, the
   thing under your thumb is the thing that moves. The artwork stays in one
   frame above and cross-fades with the active slide, so the boat still
   descends in place rather than sliding away sideways.

   Native scroll-snap does the physics. No momentum maths, no pin, no scroll
   hijack, and nothing for Safari's async scrolling path to fall off.
   Side effect worth knowing: the section is now ~550px tall on a phone
   instead of 3.4 screens.

   NO AUTO-ROTATE — decided 2026-08-24. An auto-advancing carousel needs a
   pause control to satisfy WCAG 2.2.2, and the client would rather not have
   one at all. Do not add rotation back without also adding a pause.
   ------------------------------------------------------------------------ */
@media (max-width:1024px){
  .apm-anim .sixty-wrap{ height:auto; }

  .apm-anim .sixty-stage{
    position:static; height:auto; overflow:visible;
    display:flex; flex-direction:column;
    /* !important because the TEMPLATE sets a flex gap on this container and
       Elementor emits it per-element, which outranks a class rule (gotcha #3).
       The desktop 40px gap was still applying here and eating ~80px of a
       phone screen — enough to push the dots below the fold. Margins below do
       the spacing instead, so they can be tuned per breakpoint. */
    gap:0 !important;
    padding:18px 24px 16px;
  }

  /* Tightened so the dots clear the fold on a phone — they were being pushed
     below the visible area on a Pixel 10 Pro. */
  .apm-anim .sixty-head{ flex:0 0 auto; margin-bottom:8px; touch-action:pan-y; }

  /* ORDER: heading, art, copy, dots, chevron. The chevron is a flex child of
     the stage and must come last, which the template cannot guarantee, so the
     order is pinned here. (The dots sat under the artwork for one revision —
     reverted at the client's call.) */
  .apm-anim .sixty-head { order:1; }
  .apm-anim .sixty-art  { order:2; }
  .apm-anim .sixty-steps{ order:3; }
  .apm-anim .sixty-dots { order:4; }
  .apm-anim .sixty-next { order:5; }

  /* HEADING FITS ON ONE LINE. Two wrapped heading lines cost ~52px, which is
     what was pushing the chevron past the fold. The eyebrow drops to 13px and
     the H2 to 34px on phones only, and both go left-aligned to match the copy
     beneath them (agreed with the client).
     The H2 rule needs !important AND the extra class: `h2-display` sets 44px
     with !important at mobile, so a plain override loses. */
  .apm-anim .sixty-head,
  .apm-anim .sixty-head .elementor-widget-heading,
  .apm-anim .sixty-head .elementor-heading-title{ text-align:left !important; }
  .apm-anim .sixty-head .eyebrow,
  .apm-anim .sixty-head .eyebrow .elementor-heading-title{
    font-size:13px; letter-spacing:.01em; line-height:1.35;
  }
  /* Target the h2 ELEMENT, not `.elementor-widget-heading` — the eyebrow is a
     heading widget too (header_size:p), so a widget-level .elementor-kit-19 hits it as
     well and blew the eyebrow up to 34px. The element .elementor-kit-19 also gives the
     specificity needed to beat `.h2-display`, which sets 44px !important. */
  .apm-anim .sixty-head h2.elementor-heading-title{
    font-size:34px !important; line-height:1 !important;
  }
  /* Step titles too — "Vessel Drives Off" wrapped at the Theme Style 30px. */
  .apm-anim .sixty-copy h3.elementor-heading-title{
    font-size:27px !important; line-height:1.1 !important;
  }

  /* One shared art frame, bled past the section padding so the hull is not a
     small picture in a wide margin. The fixed ratio reserves the height before
     the SVGs land, so the swap costs no CLS. */
  .apm-anim .sixty-art{
    position:relative; overflow:hidden;
    /* Sits inside the section padding rather than bleeding to the edges. The
       full-bleed version put the hull hard against the left of the screen —
       each SVG is its own crop and the offset rules map the solid ink to this
       frame, so a bleeding frame means bleeding ink. Symmetric gutters read
       better and cost about 40px of drawing width. */
    margin-inline:0; margin-bottom:8px;
    aspect-ratio:1150 / 682;
    /* A horizontal drag here advances one step, and a TAP advances one step
       and wraps at the end. The frame is not a scroll container, so pan-y only
       declares the intent and keeps vertical page scrolling instant. NEVER put
       this on .sixty-stage — it would block the track's own horizontal
       panning. */
    touch-action:pan-y;
    cursor:pointer;
  }
  .apm-anim .sixty-art .elementor-widget-image{
    position:absolute; inset:0; width:100%; height:100%;
  }

  /* HEIGHT-BASED CAP. At 1.686:1 a full-width frame is 579px tall on a
     1024x768 tablet and 501px on a landscape phone — taller than the room
     available, which pushed the dots and chevron off screen. Cap the WIDTH,
     never the height: the four img offset rules are percentages OF THIS FRAME,
     so changing its ratio distorts the drawings. Below the cap (every portrait
     phone) this is inert.
     width:100% is REQUIRED — an auto inline margin cancels the flex stretch,
     and this frame's only children are absolutely positioned, so without it
     the box sizes to fit-content, which is zero, and the art vanishes. */
  .apm-anim .sixty-art{
    width:100%;
    max-width:calc(46vh * 1.686);
    margin-inline:auto;
  }

  /* THE TRACK.
     overscroll-behavior-x:contain stops a swipe past the last slide handing
     the gesture to the browser's back navigation.
     scroll-snap-stop:always is what makes a hard flick advance exactly one
     panel instead of three — the whole point of the rewrite. */
  .apm-anim .sixty-steps{
    display:flex; flex-direction:row; flex-wrap:nowrap;
    gap:0; padding:0;
    overflow-x:auto; overflow-y:hidden;
    gap:0 !important;              /* same per-element-gap trap as the stage —
                                      a gap here would also leave a sliver of
                                      the next slide showing at every snap */
    scroll-snap-type:x mandatory;
    scroll-behavior:smooth;
    overscroll-behavior-x:contain;
    -webkit-overflow-scrolling:touch;
    scrollbar-width:none; -ms-overflow-style:none;
  }
  .apm-anim .sixty-steps::-webkit-scrollbar{ width:0; height:0; display:none; }

  /* Every slide is visible here — the track position is the state, not
     opacity. !important because the data-step rule above is unscoped and
     outranks a media-query rule of lower specificity. */
  .apm-anim .sixty-step{
    position:static; inset:auto;
    flex:0 0 100%; width:100%; max-width:100%;
    scroll-snap-align:start; scroll-snap-stop:always;
    opacity:1 !important; visibility:visible !important;
    transition:none !important;
  }
  .apm-anim .sixty-copy{
    position:static; width:100%; max-width:100%; transform:none;
  }

  /* Dots are the pagination AND the navigation. The engine turns each one into
     a real button (role, tabindex, aria-current, click + Enter/Space). 44px is
     the WCAG AA minimum target; the visible dot stays 9px. */
  .apm-anim .sixty-dots{
    display:flex !important; flex-direction:row !important;
    flex-wrap:nowrap !important; justify-content:center; gap:0;
    flex:0 0 auto; padding:8px 0 0;
    position:relative; z-index:4;
  }
  /* !important on the width is not defensive padding — the base rule below is
     .sixty-dot{width:139px} for the desktop comp's labelled pitch, and four of
     those is 556px, which overflows every phone and pushes the dots out of the
     viewport sideways. This must win outright. */
  .apm-anim .sixty-dot{
    width:auto !important; min-width:44px; min-height:44px;
    padding:14px 8px 0 !important; cursor:pointer;
    flex:0 0 auto;
  }
  .apm-anim .sixty-dot::before{ top:14px; left:50%; margin-left:-4.5px; }
  .apm-anim .sixty-dot::after{ display:none; }
  .apm-anim .sixty-dot .elementor-heading-title{ display:none; }
  .apm-anim .sixty-dot:focus-visible{
    outline:2px solid var(--e-global-color-accent); outline-offset:-6px;
    border-radius:6px;
  }
  .apm-anim .sixty-steps:focus-visible{
    outline:2px solid var(--e-global-color-accent); outline-offset:4px;
  }
}

/* ---- OPTIONAL: "keep going" chevron under the dots -----------------------
   NOT ACTIVE unless you add the class. Nothing on the page uses it yet.

   Why it is optional: the mobile section is no longer pinned, so an ordinary
   downward scroll leaves it at ANY step — there is no trap at step 4 and no
   gesture to translate. This is an affordance, not a fix.
   HOW: add a Button widget below the dots, icon-only (chevron-down), class
   `sixty-next`, and point its link at the next section's CSS ID (e.g.
   #explore-3d). Section 32's scroll-margin-top handles the landing offset.
   Mobile only — desktop already ends the track naturally.                  */
.sixty-next{ display:none; }
@media (max-width:1024px){
  /* CENTRING: text-align, not justify-content. `.sixty-next` is on the Button
     WIDGET, whose child is a full-width .elementor-widget-container — so
     centring the flex line just centres a 100%-wide block and the <a> stays
     hard left. That is why it rendered against the edge. text-align cascades
     to the inline-block button itself and works whether or not the wrapper
     div exists (Elementor 3.25+ Optimized Markup deletes it). */
  /* Three independent mechanisms, because text-align alone lost. Elementor's
     button alignment control emits its own text-align per-element, which
     outranks a class rule — and `.sixty-next` may sit on the button WIDGET or
     on a CONTAINER wrapping it, so the chain between the class and the <a>
     differs. Auto inline margins ignore text-align entirely, and a flex parent
     with centred alignment ignores both. At least one always holds. */
  .apm-anim .sixty-next{
    display:flex !important; flex-direction:column;
    align-items:center !important; text-align:center;
    width:100%; padding-top:2px;
  }
  .apm-anim .sixty-next > *,
  .apm-anim .sixty-next .elementor-widget-container,
  .apm-anim .sixty-next .elementor-button-wrapper{
    width:auto !important; max-width:100%; text-align:center !important;
  }
  .apm-anim .sixty-next .elementor-button{
    display:inline-flex !important; align-items:center; justify-content:center;
    margin-inline:auto !important;
    background:transparent; border:0; padding:6px 16px;
    color:var(--e-global-color-accent);
    animation:sixty-bob 1.8s ease-in-out infinite;
  }
  .apm-anim .sixty-next .elementor-button-icon svg{ width:18px; height:18px; }
}
@keyframes sixty-bob{
  0%,100%{ transform:translateY(0); }
  50%    { transform:translateY(6px); }
}
@media (prefers-reduced-motion: reduce){
  .apm-anim .sixty-next .elementor-button{ animation:none; }
}

/* Progress indicator. Dot pitch 139px per the comp (desktop). */
.sixty-dot{ position:relative; width:139px; padding-top:20px; text-align:center; }
.sixty-dot::before{
  content:""; position:absolute; top:0; left:50%;
  width:9px; height:9px; margin-left:-4.5px; border-radius:50%;
  background:rgba(255,255,255,.45);
  transition:background var(--sixty-fade) ease;
}
.sixty-dot::after{
  content:""; position:absolute; top:4px; left:calc(50% + 18px);
  width:102px; height:1px; background:rgba(255,255,255,.3);
}
.sixty-dot:last-child::after{ display:none; }

/* Dot labels are plain heading widgets — no class needed on them. */
.sixty-dot .elementor-heading-title{
  font-family:"Lato 800",sans-serif; font-weight:800;
  font-size:11px; letter-spacing:.08em; text-transform:uppercase;
  color:rgba(255,255,255,.55);
  transition:color var(--sixty-fade) ease;
}
.sixty-stage[data-step="1"] .sixty-dot:nth-child(1)::before,
.sixty-stage[data-step="2"] .sixty-dot:nth-child(2)::before,
.sixty-stage[data-step="3"] .sixty-dot:nth-child(3)::before,
.sixty-stage[data-step="4"] .sixty-dot:nth-child(4)::before{
  background:var(--e-global-color-accent);
}
.sixty-stage[data-step="1"] .sixty-dot:nth-child(1) .elementor-heading-title,
.sixty-stage[data-step="2"] .sixty-dot:nth-child(2) .elementor-heading-title,
.sixty-stage[data-step="3"] .sixty-dot:nth-child(3) .elementor-heading-title,
.sixty-stage[data-step="4"] .sixty-dot:nth-child(4) .elementor-heading-title{
  color:var(--e-global-color-accent);
}

/* Reduced motion and the Elementor editor both fall back to the plain vertical
   list — no pin, no track, no swipe. The editor needs it or the steps sit at
   opacity:0 (desktop) or inside a scroll container (mobile) and cannot be
   clicked on canvas.
   NOTE the flex-direction / overflow / scroll-snap resets: the mobile block
   above sets them without !important, so they must be undone explicitly here
   or the "plain list" is still a horizontal track. */
@media (prefers-reduced-motion: reduce){
  .apm-anim .sixty-wrap{ height:auto !important; }
  .apm-anim .sixty-stage{ position:static !important; height:auto !important; overflow:visible !important; display:flex !important; }
  .apm-anim .sixty-art{ position:static !important; height:auto !important; overflow:visible !important; aspect-ratio:auto !important; margin-inline:0 !important; }
  .apm-anim .sixty-steps,
  .apm-anim .sixty-step,
  .apm-anim .sixty-copy{
    position:static !important; inset:auto !important; transform:none !important;
    width:100% !important; max-width:none !important; min-height:0 !important;
    flex:0 0 auto !important;
    opacity:1 !important; visibility:visible !important; transition:none !important;
  }
  .apm-anim .sixty-steps{
    display:flex !important; flex-direction:column !important;
    overflow:visible !important; scroll-snap-type:none !important;
    scroll-behavior:auto !important;
  }
  .apm-anim .sixty-art .elementor-widget-image,
  .apm-anim .sixty-art .elementor-widget-image > .elementor-widget-container,
  .apm-anim .sixty-art .elementor-widget-image img{
    position:static !important; inset:auto !important; transform:none !important;
    display:block !important; opacity:1 !important; visibility:visible !important;
    width:100% !important; height:auto !important; aspect-ratio:auto !important;
  }
  .apm-anim .sixty-dots{ display:none !important; }
}
body.elementor-editor-active .sixty-wrap{ height:auto !important; }
body.elementor-editor-active .sixty-stage{
  position:static !important; height:auto !important; overflow:visible !important; display:flex !important;
}
body.elementor-editor-active .sixty-art{
  position:static !important; height:auto !important; overflow:visible !important;
  aspect-ratio:auto !important; margin-inline:0 !important;
}
body.elementor-editor-active .sixty-steps,
body.elementor-editor-active .sixty-step,
body.elementor-editor-active .sixty-copy{
  position:static !important; inset:auto !important; transform:none !important;
  width:100% !important; max-width:none !important; min-height:0 !important;
  flex:0 0 auto !important;
  opacity:1 !important; visibility:visible !important; transition:none !important;
}
body.elementor-editor-active .sixty-steps{
  display:flex !important; flex-direction:column !important;
  overflow:visible !important; scroll-snap-type:none !important;
  scroll-behavior:auto !important;
}
/* Editor: the absolutely-positioned img would otherwise be unselectable on
   canvas (gotcha #15) — reset the whole chain, wrapper present or not. */
body.elementor-editor-active .sixty-art .elementor-widget-image,
body.elementor-editor-active .sixty-art .elementor-widget-image > .elementor-widget-container,
body.elementor-editor-active .sixty-art .elementor-widget-image img{
  position:static !important; inset:auto !important; transform:none !important;
  display:block !important; opacity:1 !important; visibility:visible !important;
  width:100% !important; height:auto !important; aspect-ratio:auto !important;
}
body.elementor-editor-active .sixty-dots{ display:none !important; }


/* ----------------------------------------------------------------------------
   29.  3D VIEWER SECTION  (boat-lift detail pages)
   Heading + an empty stage the client drops the KISS 3D widget into. The stage
   reserves its height before the widget loads, so the page doesn't jump (CLS).
   Comp 1728x1117: heading top 50, stage 932 tall. The "drag to rotate" pill is
   the widget's own UI — not built here.
---------------------------------------------------------------------------- */
.threed-stage{ min-height:min(420px, 50vh); }   /* PRE-LOAD FLOOR ONLY.
              The widget sets its own height once it renders, so this must not
              reserve more than the canvas uses or the section grows a dead band
              underneath. Also keeps the section off a full screen, so there is
              always page above or below to grab. No var(), so min() needs no
              @supports. Was min(932px, 80vh) — the comp height, too tall now
              that the widget sizes itself. */
@media (max-width:1024px){ .threed-stage{ min-height:620px; } }
@media (max-width:767px){  .threed-stage{ min-height:420px; } }


/* ----------------------------------------------------------------------------
   30.  TECHNICAL SPECS TABLE  (boat-lift detail pages)
   Three columns of label/value rows on white. Comp 1728x759: columns at x140 /
   623 / 1106, each 381 wide, so the pitch is 483 and the gap 102.
   Rows are 36px, rule under every row except the last.
   NOT the same as section 24's .spec-* — that splits 42/58 and uppercases the
   label. Here the label is sentence case and the split is 61/39 (217 of 381).
---------------------------------------------------------------------------- */
.tspec-cols{ gap:102px; }
.tspec-col{ flex:1 1 0; min-width:0; }
.tspec-col > .eyebrow{ margin-bottom:26px; }

.tspec-row{
  border-bottom:1px solid var(--e-global-color-secondary);
  gap:16px;
}
.tspec-row:last-child{ border-bottom:0; }

.tspec-k{ flex:0 0 61% !important; max-width:61% !important; }
.tspec-v{ flex:1 1 auto !important; min-width:0; }

.tspec-k .elementor-heading-title{
  font-family:"Lato 500",sans-serif; font-weight:500; font-size:16px;
  line-height:36px; color:var(--e-global-color-text);
}
.tspec-v .elementor-heading-title{
  font-family:"Lato 800",sans-serif; font-weight:800; font-size:16px;
  line-height:36px; color:var(--e-global-color-text);
}

/* Three narrow columns do not fit a tablet — stack them. */
/* Stacking is set per-breakpoint in the template (flex_direction_tablet), not
   here — Elementor emits its own flex-direction at higher specificity and a
   plain class rule loses to it. This only adjusts the spacing. */
@media (max-width:1024px){
  .tspec-cols{ gap:48px; }
  .tspec-col > .eyebrow{ margin-bottom:18px; }
}


/* ----------------------------------------------------------------------------
   31.  FEATURES — PINNED BACKGROUND, SCROLLING CALLOUTS  (detail pages)
   ONE photo pinned for the whole section; three cards scroll past it.
     .feat-wrap
       .feat-stage      sticky, ONE viewport. THE PHOTO IS THIS CONTAINER'S
                        BACKGROUND (cover, no-repeat) — not an image widget.
       .feat-cards
         .feat-card     → .feat-inner (eyebrow, H2, body, 3-up stats)

   Figma `638:3048` stacks navy base + photo + gradient. Read from metadata
   alone that looks like three background states; the fills say one photo and a
   designed scrim. There is no crossfade.

   THIS IS THE SAFE USE OF STICKY. The pinned element is one viewport of
   BACKGROUND with nothing readable below its own fold, and every card scrolls
   normally past it — the dead-scroll failure of sections 14/27 cannot occur.
   The negative margin lets the cards ride over the pinned layer while still
   generating the scroll height themselves.
   Comp: bg 1728x1117, cards 442 wide at x1191.
---------------------------------------------------------------------------- */
.feat-wrap{ position:relative; }
.feat-stage{
  position:sticky; top:0;
  height:100vh;
  margin-bottom:-100vh;              /* cards ride on top, keep their own height */
  overflow:hidden; z-index:0;
}

/* NOT DOING: background-attachment:fixed to stop the photo moving as the
   section arrives. position:sticky cannot pin before its own top edge reaches
   the pin line, so that entry travel is inherent; the only cure is painting the
   photo against the viewport. Rejected because iOS Safari ignores the property
   outright, it has a real repaint-cost reputation on long pages, and the gain
   is an entry nicety. Decided 2026-08-19 — reopen only if the client asks. */

/* THE AD'S SCRIM, in CSS — do not bake it into the export.
   Figma: linear-gradient(-89.94deg, rgb(24,63,94) 0%, rgba(50,131,196,0) 100%).
   -89.94deg is 270deg for any practical purpose: navy at full strength on the
   right under the card, clear over the motor on the left. The transparent end
   is a transparent MID BLUE, not transparent navy — deliberate, it stops the
   middle of the ramp going muddy. Keep it.
   In CSS because the card moves with the viewport so the ramp must too, mobile
   needs a different axis, and a baked gradient means re-cutting the photo every
   time the art changes. */
.feat-stage::after{
  content:""; position:absolute; inset:0; pointer-events:none; z-index:1;
  background:linear-gradient(270deg, rgb(24,63,94) 0%, rgba(50,131,196,0) 100%);
}

/* Cards scroll normally over the pinned layer.
   HEIGHT WAS 100vh AND THE CONTENT SAT AT THE TOP OF IT. A card holds about
   390px of copy against a ~1000px desktop viewport, so two thirds of every
   screen was empty blue BELOW the text — the same complaint as mobile, and it
   read as three widely separated islands rather than a sequence.
   Two changes: 70vh instead of a full viewport, which cuts the section from
   three screens to about two; and the content is CENTRED in whatever height
   the card ends up with, so the remaining air is split evenly above and below
   instead of pooling underneath. Centring is what actually kills the "void"
   look — the height reduction just shortens the scroll.
   Still roughly one feature per screen, so the pinned-photo effect is intact. */
.feat-cards{ position:relative; z-index:1; }
.feat-card{
  /* display/direction declared here rather than relied on: the card IS an
     Elementor container (already a column flex), but stating it makes the
     centring self-sufficient instead of depending on that staying true.
     justify-content is the VERTICAL axis in a column flex, and it needs
     !important because the template may emit its own per-element value. */
  display:flex; flex-direction:column;
  justify-content:center !important;
  min-height:70vh; padding:80px 95px;
}
.feat-inner{ width:442px; max-width:100%; }
.feat-inner > .elementor-widget-heading + .elementor-widget-heading{ margin-top:26px; }
.feat-body{ margin:24px 0 34px; }
.feat-stats{ gap:24px; }
.feat-stat .stat-num{ margin-bottom:6px; }

/* Phones and tablets: the card goes full width, so the ramp turns vertical. */
@media (max-width:1024px){
  .feat-stage::after{
    background:linear-gradient(180deg,
      rgba(50,131,196,0) 0%,
      rgba(24,63,94,.55) 45%,
      rgb(24,63,94) 100%);
  }
  /* CARD HEIGHT IS CONTENT-DRIVEN ON MOBILE.
     A 100vh card holds ~420px of copy on a phone, so each feature sat in
     roughly 340px of dead blue and the section read as three widely separated
     islands. Padding instead of a viewport floor gives even breathing room at
     any copy length. The wrap keeps a one-viewport floor so the sticky photo
     always has something to pin against. */
  .feat-cards{ min-height:100vh; }
  .feat-card{ min-height:0; padding:56px 24px; }
  .feat-inner{ width:100%; }
  .feat-stats{ gap:12px; }
}

/* UN-GATED FROM .apm-anim 2026-09-02, matching sections 33 and 40.
   The gate exists so a JS failure cannot leave content HIDDEN. Sticky is not a
   hidden state — if it fails nothing disappears, it just stops pinning. The
   gate only ever bought one thing: the pin silently died anywhere the head
   snippet does not run, which is why the Elevator features look different in
   the template-library preview than on the page. On the live page .apm-anim is
   present, so nothing about the rendered result changes. */

/* Reduced motion and the Elementor editor: nothing pinned, plain stacked cards. */
@media (prefers-reduced-motion: reduce){
  .feat-stage{ position:static !important; height:60vh !important; margin-bottom:0 !important; }
  .feat-card{ min-height:0 !important; padding-top:56px !important; padding-bottom:56px !important; }
}
body.elementor-editor-active .feat-stage{
  position:static !important; height:60vh !important; margin-bottom:0 !important;
}
body.elementor-editor-active .feat-card{
  min-height:0 !important; padding-top:56px !important; padding-bottom:56px !important;
}


/* ----------------------------------------------------------------------------
   32.  ANCHOR LANDING OFFSET  (sticky header)
   A jump to #id lands the target flush with the top of the window, which puts
   it UNDER the sticky header. scroll-margin-top reserves that space on the
   target itself — the modern replacement for the old negative-margin
   pseudo-element hack, and it works for native jumps, :target, and
   scrollIntoView alike.

   Applied to any container that has been given a CSS ID, so adding an anchor is
   just filling in Advanced → CSS ID. Nothing else to remember.

   ⚠ --sixty-header-m IS MEASURED AT RUNTIME. The head snippet reads the sticky
   header's real height on load and resize and writes the variable onto <html>;
   the 76px in section 28 is only the pre-script fallback. It was a guess, and
   it was 26px too tall on a Pixel — which, plus the breathing room below, left
   a visible strip of the previous section under the header after every jump.

   NO BREATHING ROOM ON MOBILE. Anchors here target full-bleed SECTIONS, and a
   section should land flush under the header — any extra offset shows a strip
   of the section above it, which reads as a mis-fired jump rather than as
   spacing. Desktop keeps +24px because its anchors land on headings inside
   padded sections.
---------------------------------------------------------------------------- */
.e-con[id], .elementor-element[id]{
  scroll-margin-top: calc(var(--sixty-header) + 24px);
}
@media (max-width:1024px){
  .e-con[id], .elementor-element[id]{
    scroll-margin-top: var(--sixty-header-m);
  }
}



/* ----------------------------------------------------------------------------
   36.  INLINE LINKS ON DARK  (body copy over a navy scrim or photo)
   Class on the Text Editor WIDGET, so every <a> inside inherits it — no need to
   touch the HTML. Also works applied directly to an <a> in the code view.

   MEASURED against the navy scrim (#183F5E), and against the WHITE body copy
   the link sits inside — a link has to clear both, and the second is the one
   that usually gets forgotten:
     Sandy Lagoon  3.37:1 on navy   3.26:1 against the white text around it
     Sunshine      5.69:1 on navy   1.93:1 against that text
     Creamy Foam   8.96:1 on navy   1.23:1  ← invisible AS A LINK
     Mid Ship Blue 2.12:1 on navy               ← what was there; unreadable
   Sandy Lagoon wins because it is the only palette colour that clears 3:1
   against the surrounding white text, which is what makes it read as a link at
   all. Its own 3.37:1 is short of the 4.5:1 body-text bar, so the gold
   UNDERLINE is not decoration — it is the second, non-colour cue that carries
   identification where the scrim thins out over the photo.
   Hover/focus goes Sunshine at 5.69:1 — the old hover went navy-on-navy.

   No !important: if a link colour is ever set in the widget's Style tab,
   Elementor emits it per-element and it will win. Clear it there.
---------------------------------------------------------------------------- */
.link-on-dark a,
.link-on-dark a:visited,
a.link-on-dark,
a.link-on-dark:visited{
  color:var(--e-global-color-63af1b4);              /* Sandy Lagoon */
  text-decoration:underline;
  text-decoration-thickness:1px;
  text-underline-offset:3px;
  text-decoration-color:var(--e-global-color-accent);
  transition:color .2s ease, text-decoration-color .2s ease;
}
.link-on-dark a:hover,
.link-on-dark a:focus-visible,
a.link-on-dark:hover,
a.link-on-dark:focus-visible{
  color:var(--e-global-color-accent);               /* Sunshine */
  text-decoration-color:var(--e-global-color-accent);
}
/* Keyboard users get a visible ring — the colour change alone is not enough. */
.link-on-dark a:focus-visible,
a.link-on-dark:focus-visible{
  outline:2px solid var(--e-global-color-accent);
  outline-offset:2px; border-radius:2px;
}

/* On a LIGHT section, same idea inverted: Mid Ship Blue reads well on white
   (5.19:1) and the navy body copy stays distinct from it. Class: link-on-light */
.link-on-light a,
.link-on-light a:visited,
a.link-on-light,
a.link-on-light:visited{
  color:var(--e-global-color-secondary);
  text-decoration:underline;
  text-decoration-thickness:1px;
  text-underline-offset:3px;
  transition:color .2s ease;
}
.link-on-light a:hover,
.link-on-light a:focus-visible,
a.link-on-light:hover,
a.link-on-light:focus-visible{
  color:var(--e-global-color-primary);
}

@media (prefers-reduced-motion: reduce){
  .link-on-dark a, a.link-on-dark,
  .link-on-light a, a.link-on-light{ transition:none; }
}

/* ----------------------------------------------------------------------------
   33.  DOCKS — PINNED-PHOTO SECTIONS (testimonials)
   The photo pins for one viewport and the copy scrolls over it. Safe for the
   usual reason — the pinned layer is background only, nothing readable sits
   below its own fold. The Docks Overview section this also served is gone from
   the AD's redesign; the two new scroll groups are section 40.
---------------------------------------------------------------------------- */

/* The hero used to live here. It now belongs to section 38 (the AD's redesign).
   The old rules were still leaking a 134px margin under the copy block and a
   26px margin over the body — both survived because section 38 never reset
   them. Removed 2026-09; do not re-add hero rules to this section. */

/* --- the pin ------------------------------------------------------------- */
.dock-pin-wrap{ position:relative; }
/* Un-gated for the same reason as section 40 — .apm-anim is absent in the
   template-library preview and the pin silently stopped working there. */
.dock-pin-stage{
  position:sticky; top:0;
  height:100vh;
  margin-bottom:-100vh;                    /* copy rides over, keeps its height */
  overflow:hidden; z-index:0;
}
.dock-pin-cards{ position:relative; z-index:1; }
.dock-pin-card{ min-height:100vh; }

/* Scrims live here, never baked into the export — the copy moves with the
   viewport so the ramp must too, and mobile needs a different axis. */
.dock-overview .dock-pin-stage::after{
  content:""; position:absolute; inset:0; pointer-events:none; z-index:1;
  background:linear-gradient(270deg, rgb(24,63,94) 0%, rgba(0,157,176,.2) 100%);
}
.dock-testimonials .dock-pin-stage::after{
  content:""; position:absolute; inset:0; pointer-events:none; z-index:1;
  background:rgba(24,63,94,.8);
}
@media (max-width:1024px){
  .dock-overview .dock-pin-stage::after{
    background:linear-gradient(180deg,
      rgba(0,157,176,.2) 0%, rgba(24,63,94,.55) 45%, rgb(24,63,94) 100%);
  }
}

/* --- Built From The Inside Out — copy column, right side ------------------ */
.dock-overview .dock-pin-card{
  display:flex; align-items:flex-end; justify-content:center;
  padding:0 clamp(48px,8.1vw,140px);
}
.dock-overview-inner{ width:442px; max-width:100%; }
.dock-overview-inner .eyebrow{ margin-bottom:18px; }
.dock-overview-body{ margin:26px 0 31px; }
.dock-overview-inner .elementor-widget-heading + .elementor-widget-text-editor{ margin-top:26px; }
.dock-stats{ margin-bottom:24px; }
.dock-stats > *{ flex:1 1 0 !important; min-width:0; }
.dock-overview-inner .dock-rule{ margin-bottom:31px; }

@media (max-width:1024px){
  .dock-overview .dock-pin-card{
    align-items:flex-start; padding:96px 48px;
  }
  .dock-overview-inner{ width:100%; }
}
@media (max-width:767px){
  .dock-overview .dock-pin-card{ padding:72px 24px; }
}

/* Hairline. Semi-transparent rgba is the allowed exception to globals-only. */
.dock-rule{
  height:1px !important; width:100% !important;
  padding:0 !important; min-height:0 !important;
  background:rgba(255,255,255,.28) !important;
}


/* ----------------------------------------------------------------------------
   34.  DOCKS — ICON FEATURE GRID
   One grid serves both `Why It's The Only Choice` (8 cards on Mid Ship Blue,
   4x2) and `Your Dock. Done Right.` (4 cards on white, 1 row).
   Comp: cards 297 wide at x139 / 524 / 909 / 1294 — pitch 385, so the gutter is
   88. Row pitch 311 against a 222-tall card gives the same 88 vertically.
   calc() widths that subtract the gaps, per gotcha #3 — % + a fixed px gap
   rounds past 100% and wraps.
   Card titles reuse .step-title (H3 shrunk to 20px, Title Case) from section 20.
---------------------------------------------------------------------------- */
/* DESKTOP PADDING LIVES HERE, NOT IN THE TEMPLATE — deliberately.
   The comp's 140px margin and 88px gutter are both ~5-8% of a 1728px artboard.
   Held as fixed px they squeeze the body copy to ~184px on a 1280 laptop, so
   both scale with the viewport and hit the comp's exact numbers at 1728.
   The template sets NO desktop padding on these two sections (tablet and mobile
   are still set there, so the panel's padding control still works at those
   sizes). If Elementor emitted a desktop padding it would win on ID
   specificity and this would need !important. */
.dock-features-blue{  padding:124px clamp(48px,8.1vw,140px) 178px; }
.dock-features-white{ padding:124px clamp(48px,8.1vw,140px) 158px; }

/* Head block. The gap is !important because the template emits it per-element
   at ID specificity. Comp axes: eyebrow line 139.5, H2 line-1 196, icon 357.5.
   Verified rendered: 139.5 / 196.1 / 357.9. */
.dock-head{ gap:12px !important; margin-bottom:47px; }

.dock-grid{
  --dg:88px;                                   /* comp gutter at 1728 */
  column-gap:var(--dg) !important; row-gap:84px !important;
}
.dock-grid > *{
  flex:0 0 calc((100% - 3 * var(--dg)) / 4) !important;
  width:calc((100% - 3 * var(--dg)) / 4) !important;
  max-width:calc((100% - 3 * var(--dg)) / 4) !important;
}
/* --dg always has a value on this element, so no invalid-at-computed-value
   risk here (unlike the svh trap in section 28 — that one had no fallback). */
@media (min-width:1025px){ .dock-grid{ --dg:clamp(52px,5.09vw,88px); } }
@media (max-width:1024px){
  .dock-head{ margin-bottom:40px; }
  .dock-grid{ column-gap:48px !important; row-gap:56px !important; }
  .dock-grid > *{
    flex:0 0 calc((100% - 48px) / 2) !important;
    width:calc((100% - 48px) / 2) !important;
    max-width:calc((100% - 48px) / 2) !important;
  }
}
@media (max-width:767px){
  .dock-head{ margin-bottom:32px; }
  .dock-grid{ row-gap:32px !important; }
  .dock-grid > *{
    flex:0 0 100% !important; width:100% !important; max-width:100% !important;
  }
}

/* CARD INTERNALS — every rule here is !important on purpose.
   Elementor's widget CSS loads AFTER our stylesheet, so at equal specificity it
   wins: .elementor-widget-image{text-align:center} was centring the icons, and
   .e-con>.elementor-widget:not(:last-child){margin-block-end:0} (0,3,0) was
   eating the icon->title and title->body margins outright. Gotcha #3's sibling.

   Icons are cut SVGs assigned in the editor (the Icon widget's SVG mode crashes
   on them, gotcha #14), so they are Image widgets. The comp keeps every icon at
   its NATURAL size — 34x46, 46x53, 45x45, 47x31, 41x55 — and aligns their
   CENTRES on one axis, not their tops. So the slot is a fixed 55px box (the
   tallest comp icon) with the icon centred in it and pinned left. */
.dock-card > .dock-icon{
  display:flex !important; align-items:center; justify-content:flex-start;
  height:55px !important; text-align:left !important;
  margin-bottom:13px !important;               /* slot 385 -> title box 398.5 */
}
.dock-icon > .elementor-widget-container{ line-height:0; }
.dock-icon img{
  display:block !important; width:auto; height:auto;
  max-height:55px; max-width:100%; margin-inline:0 !important;
}
.dock-card > .elementor-widget-heading{
  margin-bottom:8px !important;                /* title box 421.5 -> body 430 */
}
.dock-card .elementor-widget-text-editor p{ margin:0; }


/* ----------------------------------------------------------------------------
   35.  DOCKS — TESTIMONIAL CARDS  (over the pinned photo)
   Comp: three 449x330 cards at x183 / 635 / 1087 — a 3px gutter, so they read
   as one band split by hairlines. The group is centred inside the standard
   140px page margin, which reproduces the comp's 43/52 side margins.
   The rule is pushed down with margin-top:auto so the names line up across all
   three cards whatever the quote lengths are.
---------------------------------------------------------------------------- */
/* Desktop padding here for the same reason as section 34 — the template sets
   only tablet and mobile. Comp: head at y+172 inside a 140px page margin. */
.dock-testi-card{ justify-content:flex-start; padding:172px clamp(48px,8.1vw,140px) 0; }

.dock-quotes{ justify-content:center; column-gap:3px !important; }
.dock-quotes > *{
  flex:0 0 calc((100% - 6px) / 3) !important;
  width:calc((100% - 6px) / 3) !important;
  max-width:449px !important;
}
@media (max-width:1024px){
  .dock-quotes{ row-gap:24px !important; }
  .dock-quotes > *{
    flex:0 0 100% !important; width:100% !important; max-width:100% !important;
  }
}

.dock-quote-card{
  display:flex; flex-direction:column;
  min-height:330px;
  padding:56px 40px 40px !important;
}
/* Same !important discipline as section 34 — Elementor's widget CSS loads after
   ours, so it centres the stars and zeroes both margins. Comp: stars flush left
   at the card's 40px padding, 25px down to the quote, 30px quote to the rule. */
.dock-quote-card > .dock-stars{ text-align:left !important; margin-bottom:25px !important; }
.dock-stars img{ height:18px; width:auto; display:block !important; margin-inline:0 !important; }
.dock-quote-card > .dock-quote{ margin-bottom:30px !important; }
.dock-quote p{
  font-family:"Lato 300",sans-serif; font-weight:300; font-style:italic;
  font-size:16px; line-height:19px; margin:0;
}
.dock-quote-card > .dock-rule{ margin-top:auto !important; margin-bottom:27px !important; }
.dock-name{
  font-family:"Lato 800",sans-serif; font-weight:800;
  font-size:16px; line-height:17px;
}
.dock-meta{
  font-family:"Lato 500",sans-serif; font-weight:500;
  font-size:16px; line-height:17px;
}
@media (max-width:767px){
  .dock-quote-card{ min-height:0; padding:40px 24px 32px !important; }
}


/* ----------------------------------------------------------------------------
   Reduced motion + Elementor editor: nothing pins, plain stacked sections.
   The editor needs this or the pinned stage sits behind the copy and the
   background container cannot be selected on canvas.
---------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce){
  .dock-pin-stage{
    position:static !important; height:60vh !important; margin-bottom:0 !important;
  }
  .dock-pin-card{
    min-height:0 !important; padding-top:72px !important; padding-bottom:72px !important;
  }
}
body.elementor-editor-active .dock-pin-stage{
  position:static !important; height:60vh !important; margin-bottom:0 !important;
}
body.elementor-editor-active .dock-pin-card{
  min-height:0 !important; padding-top:72px !important; padding-bottom:72px !important;
}


/* ----------------------------------------------------------------------------
   37.  DOCKS PAGE — SHARED
   Rebuilt 2026-09 from the AD's redesigned `Marine - Docks` frame (740:2).
   Page margin 139/140 at 1728; trust bar sits on its own wider 189 margin.
   Everything that touches a widget's align/display/margin is !important —
   Elementor's widget CSS loads after ours (gotcha #17).
---------------------------------------------------------------------------- */
:root{
  /* Not Elementor globals. --apm-wood-dark is a NEW brand colour the AD
     introduced for the composite band; ask them to register it in Site
     Settings so it becomes editable, then this token can go. */
  --apm-wood-dark:#583A22;
  --apm-field:#D9D9D9;
  --dock-gut:clamp(48px, 8.1vw, 140px);
}

/* Headline steps the comp uses beyond Theme Style (H1 100/.92, H2 60/.97). */
.h2-68 .elementor-heading-title,
.h2-68.elementor-heading-title{ font-size:68px !important; line-height:71px !important; }
.h2-56 .elementor-heading-title,
.h2-56.elementor-heading-title{ font-size:56px !important; line-height:58px !important; }
/* 1025-1279: the head column is capped by the window (942 + 2 gutters needs
   ~1110), so it lands at 859 and "BUILT TO A STANDARD," — 905px at 68 in
   Special Gothic Expanded, measured on the live site — wraps. Scale the step to
   the window across that band so it stays on two lines. */
@media (min-width:1025px) and (max-width:1279px){
  .h2-68 .elementor-heading-title{
    font-size:clamp(56px, 5.1vw, 68px) !important; line-height:1.045 !important;
  }
}
@media (max-width:1024px){
  .h2-68 .elementor-heading-title{ font-size:48px !important; line-height:52px !important; }
  .h2-56 .elementor-heading-title{ font-size:42px !important; line-height:46px !important; }
}
@media (max-width:767px){
  /* 32, not 38. At 390 the head column is 342 and "NO SHORTCUTS." is 372px at
     38px in Special Gothic Expanded — measured in the live font — so it broke to
     four lines against a design that has two. 32px puts it at 313 with 29px
     spare, and holds down to 360. */
  .h2-68 .elementor-heading-title{
    font-size:clamp(26px, 8.2vw, 32px) !important; line-height:1.09 !important;
  }
  .h2-56 .elementor-heading-title{ font-size:34px !important; line-height:37px !important; }
}

/* Section head — eyebrow then H2. Comp gap is 20px on the flat sections. */
.dock-sec-head{ gap:20px !important; }

/* Lede / intro paragraph, 16/28, capped at the comp's 684. */
.dock-lede p{ margin:0 0 28px; max-width:684px; }
.dock-lede p:last-child{ margin-bottom:0; }

/* "Biggest plus" tag — 12px, accent, uppercase (comp 806:85). */
.plus-tag{
  font-family:"Lato 800",sans-serif; font-weight:800;
  font-size:12px; letter-spacing:.04em; text-transform:uppercase;
  color:var(--e-global-color-accent);
}

/* Band paddings, from the comp's own section heights. */
.dock-ourchoice { padding:124px var(--dock-gut) 210px; }
.dock-composite { padding:184px var(--dock-gut) 278px; }
.dock-wood      { padding:254px var(--dock-gut) 377px; }
.dock-process   { padding:124px var(--dock-gut) 139px; }
.dock-gallery   { padding:115px var(--dock-gut) 198px; }
.dock-faq       { padding:124px var(--dock-gut) 239px; }
@media (max-width:1024px){
  .dock-ourchoice, .dock-composite, .dock-wood,
  .dock-process, .dock-gallery, .dock-faq{ padding:88px 48px !important; }
}
@media (max-width:767px){
  .dock-ourchoice, .dock-composite, .dock-wood,
  .dock-process, .dock-gallery, .dock-faq{ padding:64px 24px !important; }
}


/* ----------------------------------------------------------------------------
   38.  DOCKS PAGE — HERO
   Comp 740:184: photo + left-to-right navy scrim, copy block vertically
   centred, H1 at 100/92 over three lines.
---------------------------------------------------------------------------- */
.docks-hero{ position:relative; padding:0 var(--dock-gut); }

/* The AD's wash, unchanged. MEASURED off the new photograph, sampling the
   actual pixels behind each block of text: H1 10.1:1, body copy 8.9:1,
   button row 6.9:1, partner mark 10.0:1 — all comfortably past AA, so the
   overlay is not failing on contrast even though the replacement image is
   much brighter than the dusk shot it was drawn against.

   If it reads wrong to you it is an aesthetic call, not a legibility one.
   These two numbers are the whole dial — density at the midpoint, and where
   it reaches clear:
     heavier   rgba(24,63,94,.55) 38%,  rgba(1,39,45,0) 78%
     as built  (no midpoint stop),      rgba(1,39,45,0) 100%
     lighter   rgba(24,63,94,.35) 30%,  rgba(1,39,45,0) 66%   */
.docks-hero::before{
  content:""; position:absolute; inset:0; z-index:0; pointer-events:none;
  background:linear-gradient(90deg, rgb(24,63,94) 0%, rgba(1,39,45,0) 100%);
}
.docks-hero > *{ position:relative; z-index:1; }
.docks-hero-inner{ max-width:824px; }
.docks-hero-inner > .eyebrow{ margin-bottom:48px !important; }
.docks-hero-inner > .elementor-widget-heading{ margin-bottom:83px !important; }
.docks-hero-body{ max-width:544px; }
.docks-hero-inner > .docks-hero-body{ margin-bottom:62px !important; }
/* Same custom-property leak as the trust bar. The hero section sets
   justify-content:center to centre its copy block vertically; that becomes
   --justify-content:center, which inherits into the CTA row and centres the
   buttons horizontally. Measured: copy starts at x140 at 1728 and the first
   button at x301; at 768 it is x48 against x133. The comp (740:184) has the
   buttons flush with the eyebrow, headline and body. */
.hero-ctas{ gap:30px !important; justify-content:flex-start !important; }

@media (max-width:1024px){
  .docks-hero-inner{ max-width:100%; }
  /* The section's own padding is per-element from the template, so it lands at
     ID specificity and needs !important to move. */
  .docks-hero{ padding:72px 48px !important; }
  .docks-hero-inner > .eyebrow{ margin-bottom:18px !important; }
  .docks-hero-inner > .elementor-widget-heading{ margin-bottom:26px !important; }
  .docks-hero-inner > .docks-hero-body{ margin-bottom:32px !important; }
  /* An even wash instead of ramping to flat navy at 78% — that was erasing the
     bottom half of the photograph entirely. */
  .docks-hero::before{
    background:linear-gradient(180deg,
      rgba(24,63,94,.55) 0%, rgba(24,63,94,.90) 100%);
  }
}

/* Phone: the hero ran roughly 940px of content against ~780px of usable
   screen, so it needed two screenshots. Everything below is height. */
@media (max-width:767px){
  .docks-hero{ padding:44px 24px !important; }
  .docks-hero .eyebrow .elementor-heading-title{
    font-size:13px !important; line-height:1.4 !important;
    letter-spacing:.01em;                     /* 3 lines -> 2 */
  }
  /* The eyebrow is itself a heading widget, so the generic rule below ties it
     on specificity (0,2,0) and wins on source order — it was rendering at 20,
     not 14. Two classes settles it without !important games. */
  .docks-hero-inner > .eyebrow.eyebrow{ margin-bottom:14px !important; }
  .docks-hero-inner > .elementor-widget-heading{ margin-bottom:20px !important; }
  .docks-hero-body p{ line-height:26px; }
  .docks-hero-inner > .docks-hero-body{ margin-bottom:26px !important; }
  .hero-ctas{ gap:14px !important; }
  .hero-partner{ margin-top:24px !important; }
}


/* ----------------------------------------------------------------------------
   39.  DOCKS PAGE — TRUST BAR (4 items, lead + sub)
   Comp 740:336: 97 tall, 189 side margin, content-width items with hairline
   dividers, space-between. Tablet/phone fall to the 2-across model in
   section 11, which this bar already shares.
---------------------------------------------------------------------------- */
.dock-trust-bar{ padding:25px clamp(24px, 10.94vw, 189px); }
/* Below desktop the bar has to sit on the same gutter as every other band, or
   it reads as a misaligned strip. Measured at 390: the bar's own 10.94vw put
   its content at x43 while the hero, the panels and the FAQ all start at x24.
   48/24 are the same numbers section 37 gives the flat bands. */
@media (max-width:1024px){ .dock-trust-bar{ padding:25px 48px !important; } }
@media (max-width:767px) { .dock-trust-bar{ padding:22px 24px !important; } }

/* CUSTOM-PROPERTY LEAK. The row sets justify-content:space-between for the
   4-across desktop layout. Elementor writes that as --justify-content on the
   row, custom properties INHERIT, and every descendant container consumes it
   through frontend.min.css's
     .elementor-element:where(.e-con-full,.elementor-widget){justify-content:var(--justify-content)}
   Harmless while the items are content-width; the moment they take a calc()
   width it throws the icon and the label block to opposite edges. Measured at
   390: label block starting at x95 in a 305px item.
   The comp centres the two label lines inside each item (740:336), so that
   part stays — only the icon/label pair is re-tightened. */
.dock-trust-item{ justify-content:flex-start !important; }

/* At the design width the comp's own 10.94vw margin leaves 1350px of track for
   a 1294px row — 56px of slack — so from 1728 up the bar returns to the AD's
   numbers at full 16px type. Below that, section 11 caps the margin instead;
   the old switch sat at 1601, where the same row only had 1251px to sit in. */
@media (min-width:1728px){
  .dock-trust-bar{ padding:16px clamp(24px, 10.94vw, 189px) !important; }
  .dock-trust-row{ column-gap:20px !important; }
}
.dock-trust-item{ gap:10px !important; }

/* THE ICON MUST NEVER TAKE ITS OWN LINE.
   The row is set to wrap so four items become two-up and then one-up. That is
   written as --flex-wrap on the row, custom properties inherit, and each ITEM
   consumed it too — so the longest label ("MUNICIPAL - COUNTY - STATE - FEDERAL")
   pushed its own icon onto a line above. Same inheritance leak as the hero CTAs.
   nowrap on the item, min-width:0 on the label block so it shrinks and wraps its
   text instead of shoving the icon out. */
.dock-trust-item{ flex-wrap:nowrap !important; }
.dock-trust-item > .elementor-widget-image{ flex:0 0 auto !important; }
.dock-trust-copy{ min-width:0 !important; flex:1 1 auto !important; }
@media (max-width:767px){
  /* Section 11 steps these to 14 below 1150, but section 39 restates 16 further
     down the sheet and wins on source order. This is the phone-only correction:
     at 13px the longest sub-label is ~282px against a 304px label column. */
  .trust-lead, .trust-sub{ font-size:13px !important; line-height:18px !important; }
  .apm-trust-icon img{ height:24px; }
}
.trust-lead{
  font-family:"Lato 800",sans-serif; font-weight:800;
  font-size:16px; line-height:20px; text-transform:uppercase;
}
.trust-sub{
  font-family:"Lato 500",sans-serif; font-weight:500;
  font-size:16px; line-height:20px; text-transform:uppercase;
}
.apm-trust-icon img{ height:28px; }


/* Long ghost labels ("EXPLORE ALL COMPOSITE OPTIONS") overrun a 390px phone
   against the global .elementor-button{white-space:nowrap}. Release it here. */
@media (max-width:767px){
  .btn-ghost .elementor-button,
  .btn-ghost-blue .elementor-button{
    white-space:normal !important; text-align:center;
  }
}


/* ----------------------------------------------------------------------------
   40.  DOCKS PAGE — PINNED SCROLL GROUPS
   Two on this page: `BUILT TO A STANDARD, NOT TO A BID.` and
   `NO SHORTCUTS. NO EXCEPTIONS.` The AD flagged both photo layers AND both
   headlines sticky in Figma, so the whole left side pins for one viewport
   while the right-hand copy column scrolls past it.

   This is the SAFE sticky: the pinned layer is background plus one short
   headline, and nothing readable sits below its own fold, so the dead-scroll
   failure of sections 14/27 cannot happen here. Panels are NOT pinned — a
   panel taller than the window just scrolls, which is the whole point.

   Comp: panel column at x1191, first panel 303 down from the stage top,
   248 between panels. Un-pins below 1025px and stacks.
---------------------------------------------------------------------------- */
.dock-sg{ position:relative; }

/* THE PHOTO BELONGS TO .dock-sg-stage, NOT TO .dock-sg.
   Assigning it to the section root instead is silent and looks exactly like a
   broken pin: the stage still pins, but it is transparent, so the only thing
   you see is a photo scrolling with the page. It also TILES, because only the
   stage carries cover/no-repeat. Verified on staging 2026-09-02 — the pin
   itself was working the whole time.
   This makes the wrong container survivable instead of ugly. It cannot make it
   pin; check the container labels in the Navigator if the photo scrolls. */
.dock-sg{
  background-size:cover;
  background-position:center center;
  background-repeat:no-repeat;
}

/* NOT gated on .apm-anim. The gate exists for JS-driven HIDDEN states, where a
   script failure would leave content invisible. Sticky is not one of those —
   if it fails nothing is hidden, it just stops pinning. Gating it bought
   nothing and cost a whole round: in the Elementor template-library preview
   the head snippet does not run, so .apm-anim is absent, the stage collapsed
   to a plain 60vh block, and the panels fell BELOW it instead of riding over
   it (panel 1 top went 303 -> 1143). That reads as "the image doesn't pin" and
   "I can't see the first panel" — same bug, two symptoms.
   The editor hatch and reduced-motion below still un-pin where they should. */
.dock-sg-stage{
  position:sticky; top:0;
  height:100vh;
  margin-bottom:-100vh;              /* panels ride over, height still counts */
  overflow:hidden; z-index:0;
}
/* Sticky dies under an ancestor with overflow:hidden. html/body use
   overflow-x:clip site-wide, which is sticky-safe — keep it that way. */
/* Same scrim family as the home Features stage: navy full strength on the
   right under the copy, photo readable on the left under the headline. */
.dock-sg-stage::after{
  content:""; position:absolute; inset:0; pointer-events:none; z-index:1;
  background:linear-gradient(270deg,
    rgb(24,63,94) 14%, rgba(50,131,196,.39) 100%);
}

/* ============================================================================
   WHERE THE HEADLINE LIVES IS THE WHOLE MECHANIC.

   The Elevator's stage (.feat-stage) is a BARE photograph. Every word is in the
   cards that ride over it, so the photo can pin for the length of the section
   and the copy scrolls across it. That is the effect the client signed off on.

   These two groups originally put the headline INSIDE .dock-sg-stage. A child
   of a sticky box is pinned with it, so below 1025 — where the panels go full
   width instead of sitting in a right-hand column — panel copy scrolled
   straight over a headline that never moved. That is why the pin had to be
   switched off on phones, which is why nothing looked like the Elevator there.

   THE FIX IS ONE DRAG IN THE NAVIGATOR, per section:
     drag  "Pinned headline"  OUT of  ">> PHOTO GOES ON THIS CONTAINER <<"
     and drop it as the FIRST child of  "Scrolling copy panels".
   Nothing else changes — same widgets, same photo, same classes.

   Both placements are styled below so the page is never half-broken while the
   move is in progress. Old placement = desktop pin only. New placement = pinned
   at every width, exactly like the Elevator.
   ============================================================================ */

/* THE COMP'S 942 IS THE TEXT COLUMN, NOT THE BOX.
   Head frame runs x139 to x1081 at 1728 — 942px of type. This box also carries
   the page gutter as padding, and box-sizing is border-box, so `max-width:942px`
   left only 662px of text at 1728 and above. "NO SHORTCUTS." is 665px at 68px in
   Special Gothic Expanded (measured in the live font), so it broke to
   NO / SHORTCUTS. / NO / EXCEPTIONS. — four lines where the design has two. */
.dock-sg-head{
  position:relative; z-index:2;
  padding:182px var(--dock-gut) 0;
  max-width:calc(942px + 2 * var(--dock-gut));
}

/* ---- NEW PLACEMENT: headline is the first block of the scrolling column ---- */
/* Desktop keeps the comp exactly: the head is lifted out of the panel flow and
   parked at the comp's x139 / y182, so panel 1 still starts at 303 beside it.
   It now scrolls with the panels instead of being pinned — which is what the
   Elevator does, and what makes the same section work on a phone. */
@media (min-width:1025px){
  .dock-sg-panels > .dock-sg-head{
    position:absolute; top:182px; left:0; right:auto;
    padding:0 var(--dock-gut);
    width:calc(942px + 2 * var(--dock-gut));
    max-width:100%;
  }
}

.dock-sg-panels{ position:relative; z-index:1; }
.dock-sg-panels > .dock-panel{
  width:clamp(340px, 26.3vw, 454px) !important;
  max-width:calc(100% - 48px) !important;
  margin-left:auto !important;
  margin-right:clamp(24px, 4.8vw, 83px) !important;
}
.dock-sg-a .dock-sg-panels{ padding:303px 0 62px; }
.dock-sg-b .dock-sg-panels{ padding:263px 0 62px; }
.dock-sg-panels > .dock-panel + .dock-panel{ margin-top:248px !important; }

.dock-panel > .eyebrow{ margin-bottom:8px !important; }
.dock-panel > .elementor-widget-heading{ margin-bottom:40px !important; }
.panel-body p{ margin:0; max-width:433px; }
.panel-body p.bs-lbl{
  font-family:"Lato 800",sans-serif; font-weight:800;
  color:var(--e-global-color-accent);
  text-transform:uppercase; margin-top:28px;
}
.panel-body p.bs-lbl:first-child{ margin-top:0; }

/* REVEALS AND THE PIN.
   A `reveal` puts a transform on the element. A transform anywhere on or above
   a sticky element re-parents its containing block and the pin dies — same
   failure class as an ancestor with overflow:hidden. So the three containers
   that make this mechanic work opt out, exactly as .apm-stack-wrap does in
   section 14. Put `reveal` on the panels' contents (.dock-panel or the widgets
   inside it); those sit below the sticky element and animate safely. */
.dock-sg.reveal, .dock-sg-stage.reveal, .dock-sg-panels.reveal{
  opacity:1 !important; transform:none !important; transition:none !important;
}

/* PIN ON DESKTOP. FULL-BLEED PHOTO BAND BELOW 1025. Client's call, 2026-09-04.
   The Elevator's pinned stage (section 31) is a BARE photograph — every word
   lives in the cards that ride over it, so transparent cards work and the copy
   sits on the picture. The Docks stage carries the section headline as well, and
   below 1025 the panels go full width, so a pin here puts panel copy straight on
   top of the pinned headline. Measured at 390: unreadable from the first panel.
   Covering the headline with an opaque sheet fixes the collision but loses the
   thing worth having — copy over the photograph. So the pin is desktop-only and
   the band below it is a proper full-bleed photo with the headline on it, not a
   thin strip. That needs a floor: at the comp's padding the box collapsed to the
   headline's own height, 256px of a full-bleed photograph.
   To restore the pin here, the headline has to move out of .dock-sg-stage and
   into .dock-sg-panels — a template change to both scroll groups, which makes
   them structurally identical to the Elevator. */
@media (max-width:1024px){
  /* THE SCRIM. The client's phone shots showed white and Florida Sunshine sitting
     on bare sunlit water. The Elevator gets away with a transparent top because
     nothing is printed there; our headline is the first thing on the photo, so
     the wash has to start strong and finish solid navy for the panels below.
     Worst case is a blown-white photo: at 80% the ground computes #4A6580, which
     is 4.9:1 for white body and 3.1:1 for the accent at display size. */
  .dock-sg-stage::after{
    background:linear-gradient(180deg,
      rgba(24,63,94,.80) 0%, rgba(24,63,94,.62) 45%, rgb(24,63,94) 100%);
  }
  .dock-sg-panels > .dock-panel{
    width:100% !important; max-width:100% !important;
    margin-left:0 !important; margin-right:0 !important;
  }
  .dock-sg-panels > .dock-panel + .dock-panel{ margin-top:64px !important; }
  .dock-panel > .elementor-widget-heading{ margin-bottom:24px !important; }
  .panel-body p{ max-width:100%; }

  /* NEW PLACEMENT — the Elevator mechanic. Head is the first scrolling block,
     riding over a photo that stays pinned for the whole section. */
  .dock-sg-panels > .dock-sg-head{
    position:static; padding:88px 48px 56px; max-width:100%;
  }
  .dock-sg:has(.dock-sg-panels > .dock-sg-head) .dock-sg-panels{
    padding:0 0 88px !important;
  }
  .dock-sg:has(.dock-sg-panels > .dock-sg-head) .dock-sg-panels > .dock-panel{
    padding-left:48px !important; padding-right:48px !important;
  }

  /* OLD PLACEMENT — headline still inside the stage. It cannot pin without
     colliding, so that case stays a full-bleed photo band. Delete this block
     once both sections have been moved. */
  .dock-sg:has(.dock-sg-stage > .dock-sg-head) .dock-sg-stage{
    position:static; height:auto; margin-bottom:0;
    min-height:58vh; display:flex; align-items:flex-end;
  }
  .dock-sg-stage > .dock-sg-head{ padding:88px 48px 56px; max-width:100%; }
  .dock-sg:has(.dock-sg-stage > .dock-sg-head) .dock-sg-panels{
    padding:56px 48px 88px;
  }
}
@media (max-width:767px){
  .dock-sg-head{ padding:64px 24px 48px; }
  .dock-sg-panels > .dock-sg-head{ padding:64px 24px 48px; }
  .dock-sg:has(.dock-sg-panels > .dock-sg-head) .dock-sg-panels > .dock-panel{
    padding-left:24px !important; padding-right:24px !important;
  }
  .dock-sg:has(.dock-sg-stage > .dock-sg-head) .dock-sg-panels{
    padding:40px 24px 64px;
  }
}


/* ----------------------------------------------------------------------------
   41.  DOCKS PAGE — WHY IT'S OUR CHOICE   50/50 SPLIT, PORTRAIT PHOTO RIGHT
   REBUILT 2026-09-04 at the client's request. The AD's version put the photo in
   the empty right half of the upper block only and ran the four cards full
   width beneath it — a letterbox slot a portrait photograph cannot fill. The
   section is now a true half-and-half: all the copy in the left half, the
   photograph a full-bleed panel down the right, top edge to bottom edge.

   STRUCTURE (cards and button moved INSIDE .oc-copy):
     .dock-ourchoice
       .oc-split                 row, no gap, stretch
         .oc-copy                50%, carries the page gutter as padding
           .dock-sec-head / .dock-lede / .dock-cards (2x2) / .btn-ghost
         .oc-media               50%, the photograph
---------------------------------------------------------------------------- */
/* The section gives up its own desktop padding so the photo can reach the top,
   bottom and right edges; the copy column carries it instead. Section 37's
   tablet and phone padding still applies below 1025. */
@media (min-width:1025px){
  .dock-ourchoice{ padding:0 !important; }
}
.oc-split{ gap:0 !important; align-items:stretch !important; }
/* gap:0 and explicit margins, NOT a column gap. The copy column has four
   children now (head, lede, card grid, button) and a gap would add itself to
   every one of them — an earlier pass set gap:18px and the lede-to-cards
   distance came out at 96 against the 78 asked for. */
.oc-split > .oc-copy{
  flex:0 0 50%; width:50%; max-width:50%;
  gap:0 !important;
  /* left = the page gutter, right = the comp's 47px column gutter, so the copy
     keeps the same left margin as every other band and clears the photo edge. */
  /* The comp's 124/210 was drawn for a full-width band. In a half-width column
     210 of bottom padding on top of the button's own 105 leaves ~315px of empty
     ground under the last line, which reads as a mistake rather than as air.
     Squared off to the top value; the comp numbers are 124/210 if you want them
     back. */
  padding:124px 47px 124px var(--dock-gut);
}
.dock-ourchoice .dock-sec-head{ margin-bottom:18px; }  /* comp: H2 285 -> lede 303 */
.oc-split > .oc-media{ flex:0 0 50%; width:50%; max-width:50%; min-width:0; }

/* Comp 740:170 puts 10px between the eyebrow and the H2 here, not the 20 the
   other flat sections use. Scoped so the shared rule stays as measured. */
.dock-ourchoice .dock-sec-head{ gap:10px !important; }

/* The photograph fills whatever height the copy column ends up being, so the
   two halves always bottom out together. object-fit does the cropping, which is
   why the source only has to be big enough — see the crop note in the handoff. */
.oc-media{ position:relative; }
.oc-media > .oc-shot{ position:absolute; inset:0; }
.oc-media .oc-shot img{
  width:100%; height:100%;
  object-fit:cover; object-position:center;
  display:block; margin-inline:0;
}

/* Second paragraph to the first sub-heading. The comp used 78 for the same
   transition when the cards sat below the whole upper block; kept, because the
   cards now start directly under the lede and it is the one number the client
   flagged as likely to need a nudge. */
.dock-ourchoice .dock-lede{ margin-bottom:78px !important; }

/* TWO ACROSS, TWO DOWN — the grid halves because the column halved.
   Reading order runs across: Structural Grade | More Durable, then
   Safe & Comfortable | Easy To Maintain. 2px of slack per gotcha #3. */
.dock-ourchoice .dock-cards{
  column-gap:47px !important; row-gap:56px !important;
  margin-bottom:64px !important;             /* comp 105, same reason as above */
}
.dock-ourchoice .dock-cards > *{
  flex:0 0 calc((100% - 47px - 2px) / 2) !important;
  width:calc((100% - 47px - 2px) / 2) !important;
  max-width:calc((100% - 47px - 2px) / 2) !important;
}
.dock-card > .elementor-widget-heading{ margin-bottom:8px !important; }
.dock-card .elementor-widget-text-editor p{ margin:0; }

/* STACKS AT 1280, NOT 1024. Measured: at 1025 the half-column leaves 383px of
   text and 167px cards, and the photo panel becomes 513x1406 — a 0.37 ratio no
   photograph survives. 1280 is the narrowest window where the split still gives
   the copy a usable measure (489px of text, 220px cards).
   The photo goes FIRST when stacked so the band still opens on a picture rather
   than ending on one after the button, and it drops to a landscape ratio
   because a portrait crop at full phone width is most of a screen on its own. */
@media (max-width:1279px){
  .oc-split{ flex-direction:column !important; }
}
/* Only this band restores the section padding — below 1025 section 37's own
   tablet and phone values already apply and must not be overwritten. */
@media (min-width:1025px) and (max-width:1279px){
  .dock-ourchoice{ padding:124px var(--dock-gut) 210px !important; }
}
@media (max-width:1279px){
  .oc-split > .oc-copy,
  .oc-split > .oc-media{ flex:0 0 auto; width:100%; max-width:100%; }
  .oc-split > .oc-copy{ padding:0 !important; }
  .oc-media{ position:static; order:-1; margin-bottom:48px; }
  .oc-media > .oc-shot{ position:static; }
  .oc-media .oc-shot img{ aspect-ratio:3/2; height:auto; }
  .dock-ourchoice .dock-lede{ margin-bottom:56px !important; }
  .dock-ourchoice .dock-cards{
    column-gap:40px !important; row-gap:48px !important;
    margin-bottom:56px !important;
  }
  .dock-ourchoice .dock-cards > *{
    flex:0 0 calc((100% - 40px - 2px) / 2) !important;
    width:calc((100% - 40px - 2px) / 2) !important;
    max-width:calc((100% - 40px - 2px) / 2) !important;
  }
}
@media (max-width:767px){
  .oc-media{ margin-bottom:36px; }
  .oc-media .oc-shot img{ aspect-ratio:4/3; }
  .dock-ourchoice .dock-lede{ margin-bottom:40px !important; }
  .dock-ourchoice .dock-cards{ row-gap:36px !important; }
  .dock-ourchoice .dock-cards > *{
    flex:0 0 100% !important; width:100% !important; max-width:100% !important;
  }
}


/* ----------------------------------------------------------------------------
   42.  DOCKS PAGE — COMPOSITE + WOOD BANDS
   Both are a flat colour with a wood photograph over it at 40%. The photo is
   an Elementor background OVERLAY on the section, assigned in the editor —
   never baked into the template.
   Composite ground is a NEW colour the AD introduced (#583A22); it has no
   Elementor global yet, hence the token in section 37.
---------------------------------------------------------------------------- */
.dock-composite{ background-color:var(--apm-wood-dark) !important; }

/* HEAD -> COPY AIR. Measured off the comp, frame tops from each section's top:
     Composite (806:79)  eyebrow 184  H2 225 (h120)  lede 363
     Wood      (806:146) eyebrow 254  H2 295 (h120)  copy 433
   Both give a 10px eyebrow->H2 gap and an 18px H2->copy gap. We were shipping
   20 and 0 — the headline sat straight on the copy. Our H2 box is 116.4 (60px
   Theme Style at 0.97em) against the comp's 120, so 22 lands the copy on the
   comp's line. Our Choice already ran 10/18 and is the one nobody flagged. */
.dock-composite .dock-sec-head,
.dock-wood .dock-sec-head{
  gap:10px !important;
  margin-bottom:22px !important;
}

.dock-composite .dock-lede{ margin-bottom:53px !important; }
.type-cols{ column-gap:47px !important; row-gap:48px !important; }
.type-cols > *{
  flex:0 0 calc((100% - 3 * 47px - 2px) / 4) !important;
  width:calc((100% - 3 * 47px - 2px) / 4) !important;
  max-width:calc((100% - 3 * 47px - 2px) / 4) !important;
  border-top:1px solid var(--e-global-color-0c26593);
  padding-top:18px !important;
}
.type-col > .elementor-widget-heading{ margin-bottom:8px !important; }
.type-col .elementor-widget-text-editor p{ margin:0; }
.type-col .elementor-widget-text-editor p + p{ margin-top:0; }
.dock-composite .type-cols{ margin-bottom:55px !important; }
@media (max-width:1024px){
  .type-cols > *{
    flex:0 0 calc((100% - 40px - 2px) / 2) !important;
    width:calc((100% - 40px - 2px) / 2) !important;
    max-width:calc((100% - 40px - 2px) / 2) !important;
  }
  .type-cols{ column-gap:40px !important; }
}
@media (max-width:767px){
  .type-cols > *{
    flex:0 0 100% !important; width:100% !important; max-width:100% !important;
  }
}

/* Wood band — two columns, intro left / marine-grade callout right. */
.dock-wood-row{ column-gap:102px !important; row-gap:44px !important; }
.dock-wood-row > *{
  flex:0 0 calc((100% - 102px - 2px) / 2) !important;
  width:calc((100% - 102px - 2px) / 2) !important;
  max-width:calc((100% - 102px - 2px) / 2) !important;
}
.wood-callout > .elementor-widget-heading{ margin-bottom:8px !important; }
.wood-callout .elementor-widget-text-editor p{ margin:0; }
.dock-wood .dock-wood-row{ margin-bottom:77px !important; }
@media (max-width:1024px){
  .dock-wood-row > *{
    flex:0 0 100% !important; width:100% !important; max-width:100% !important;
  }
  .dock-wood .dock-wood-row{ margin-bottom:48px !important; }
}


/* ----------------------------------------------------------------------------
   43.  DOCKS PAGE — YOUR DOCK. DONE RIGHT. (6 steps, 3 x 2)
   Comp 742:116: 420 wide at x139/652/1166 — gutter 94, row pitch 266.
   Each step is a hairline, the number at 40px accent, then title and body.
---------------------------------------------------------------------------- */
.dock-process .dock-sec-head{ margin-bottom:96px !important; }
.proc-grid{ column-gap:94px !important; row-gap:41px !important; }
.proc-grid > *{
  flex:0 0 calc((100% - 2 * 94px - 2px) / 3) !important;
  width:calc((100% - 2 * 94px - 2px) / 3) !important;
  max-width:calc((100% - 2 * 94px - 2px) / 3) !important;
  border-top:1px solid var(--e-global-color-secondary);
  padding-top:13px !important;
}
.step-num{
  font-family:"Special Gothic Expanded One",sans-serif;
  font-size:40px; line-height:1.15;
}
.proc-step > .step-num{ margin-bottom:8px !important; }
.proc-step > .elementor-widget-heading{ margin-bottom:8px !important; }
.proc-step .elementor-widget-text-editor p{ margin:0; }
.dock-process .proc-grid{ margin-bottom:46px !important; }
.proc-cta{ align-items:center !important; }
@media (max-width:1024px){
  .proc-grid{ column-gap:48px !important; row-gap:36px !important; }
  .proc-grid > *{
    flex:0 0 calc((100% - 48px - 2px) / 2) !important;
    width:calc((100% - 48px - 2px) / 2) !important;
    max-width:calc((100% - 48px - 2px) / 2) !important;
  }
  .dock-process .dock-sec-head{ margin-bottom:56px !important; }
}
@media (max-width:767px){
  .proc-grid > *{
    flex:0 0 100% !important; width:100% !important; max-width:100% !important;
  }
  .step-num{ font-size:34px; }
}


/* ----------------------------------------------------------------------------
   44.  DOCKS PAGE — THE WORK (CoverFlow band)
   Comp 819:262: Mid Ship Blue under a water photo at 30%, 100px headline.
   The slider itself is the KISS CoverFlow widget — styling lives in section 25.
---------------------------------------------------------------------------- */
.dock-gallery .dock-sec-head{ margin-bottom:88px !important; }
.dock-gallery .coverflow-slot{ width:100% !important; }

/* The blue decking field behind this band is a PHOTO, not a tileable texture.
   Left at background-size:auto it paints at its own pixel size against a
   ~1713x1159 section, so `repeat` shows a seam where the tile ends and
   `no-repeat` leaves the section's ground showing past the image edge. Neither
   is a repeat problem — the missing property is `cover`.
   Assign the image in the editor as usual; this makes the sizing survivable
   whatever the editor's Background panel is left on. Same guard as .dock-sg. */
.dock-gallery{
  background-size:cover;
  background-position:center center;
  background-repeat:no-repeat;
}


/* ----------------------------------------------------------------------------
   45.  DOCKS PAGE — FAQ
   Comp 819:274: white band, 1074-wide track, 20px Special Gothic questions,
   accent +/- at the right. Native <details> — no JS, no CLS, no plugin.
---------------------------------------------------------------------------- */
/* Comp 819:274: eyebrow box 124-155, H2 top 165 -> a 10px gap here, same as
   Our Choice, not the 20 the shared rule uses. Then H2 bottom 285 to the first
   question's line box at ~366. */
.dock-faq .dock-sec-head{ gap:10px !important; margin-bottom:17px !important; }

/* ELEMENTOR ACCORDION. The client edits questions in the builder; we own the
   look from here.

   EVERY declaration below that collides with the widget is !important, and that
   is not belt-and-braces. MEASURED on the live page 2026-09-03: our kit CSS
   loads BEFORE widget-accordion.min.css, because that sheet is enqueued
   conditionally when the widget appears — the opposite of the page-level order
   in APM-Elementor-Cascade-Order.md. Every rule in it is (0,2,0), so a matching
   (0,2,0) rule of ours TIES AND LOSES. First pass shipped without !important and
   not one declaration reached the page.

   Elementor's defaults we are overriding:
     .elementor-accordion .elementor-accordion-item{border:1px solid #d5d8dc}
     .elementor-accordion .elementor-tab-title{padding:15px 20px;line-height:1}
     .elementor-accordion .elementor-tab-content{border-block-start:1px solid #d5d8dc;padding:15px 20px}
     .elementor-accordion-icon{display:inline-block;width:1.5em;float:left}
   plus Theme Style .elementor-kit-N h3 (40px, uppercase) on the title, because
   title_html_tag is h3.

   Comp 819:274, artboard 1728: track x140 w1074; question rows at
   357/516/604/690/778/864/952/1040 — pitch 88; rules at
   485/584/672/758/846/932/1020/1108, i.e. ONE AFTER EACH ITEM AND NONE ABOVE
   THE FIRST; icon 29 wide, right edge on the track edge at 1214. */
.faq-acc .elementor-accordion{ max-width:1074px; }

/* Sunshine, and horizontal only — the comp draws no box. */
.faq-acc .elementor-accordion-item{
  border:0 !important;
  border-bottom:1px solid var(--e-global-color-accent) !important;
}

/* Row: 30 + 28 line + 30 = the comp's 88 pitch. */
.faq-acc .elementor-tab-title{
  display:flex !important;
  align-items:flex-start; justify-content:space-between; gap:24px;
  background:transparent !important;
  margin:0 !important;
  padding:28px 0 29px !important;        /* + 28 line + 1 border = the comp's 88 */
  cursor:pointer;
  font-family:"Special Gothic Expanded One",sans-serif !important;
  font-size:24px !important; line-height:28px !important;
  text-transform:none !important;
  color:var(--e-global-color-primary) !important;
}
.faq-acc .elementor-accordion-title{
  flex:1 1 auto; display:block;          /* block kills the inline leading that
                                            pushed the row 2px past the pitch */
  font-family:inherit !important; font-size:inherit !important;
  line-height:inherit !important; text-transform:none !important;
  color:inherit !important; text-decoration:none;
}

/* Icons render as inline SVG sized height/width:1em, so font-size drives them.
   Elementor floats them and defaults the alignment to the LEFT — icon_align is
   set to right in the template, and order:2 keeps it right even if that control
   is ever changed in the editor. */
.faq-acc .elementor-accordion-icon{
  order:2; float:none !important;
  flex:0 0 29px !important; width:29px !important;
  text-align:right;
  color:var(--e-global-color-accent) !important;
  font-size:24px !important; line-height:28px !important;
}
.faq-acc .elementor-accordion-icon svg{ fill:currentColor; }

/* Open row: the comp runs the answer straight on from the question. */
.faq-acc .elementor-tab-title.elementor-active{ padding-bottom:6px !important; }
.faq-acc .elementor-tab-content{
  background:transparent !important;
  border:0 !important;
  padding:6px 35px 16px 0 !important;    /* comp answer 1039 in a 1074 track */
}
.faq-acc .elementor-tab-content p{
  font-family:"Lato 500",sans-serif; font-weight:500;
  font-size:16px; line-height:28px; margin:0;
  color:var(--e-global-color-primary);
}
.faq-acc .elementor-tab-title:focus-visible{
  outline:2px solid var(--e-global-color-accent); outline-offset:3px;
}
@media (max-width:767px){
  .faq-acc .elementor-tab-title{
    font-size:19px !important; line-height:24px !important;
    padding:22px 0 !important; gap:16px;
  }
  .faq-acc .elementor-accordion-icon{
    font-size:19px !important; line-height:24px !important;
    flex-basis:22px !important; width:22px !important;
  }
  .faq-acc .elementor-tab-content{ padding-right:0 !important; }
}


/* ----------------------------------------------------------------------------
   46.  DOCKS PAGE — FORM
   Comp 819:354: photo band, copy left (headline sticks while the form scrolls
   past on tall forms / short windows), fields right in a 730 track.
---------------------------------------------------------------------------- */
.dock-form-band{
  position:relative;
  padding:182px var(--dock-gut) 201px;
}
/* z-order: photo strip (::after) 0, this scrim 1, content 2. The scrim has to
   sit ABOVE the photo layer, and ::after paints after ::before by default. */
.dock-form-band::before{
  content:""; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:linear-gradient(270deg,
    rgb(24,63,94) 14%, rgba(50,131,196,.39) 100%);
}
.dock-form-band > *{ position:relative; z-index:2; }
.dock-form-row{ column-gap:147px !important; row-gap:56px !important; }
.form-copy{
  flex:0 0 572px !important; width:572px !important; max-width:572px !important;
  align-self:flex-start;
  position:sticky; top:calc(var(--sixty-header, 89px) + 24px);
}
.form-copy > .eyebrow{ margin-bottom:38px !important; }
.form-copy > .elementor-widget-heading{ margin-bottom:45px !important; }
.form-fields{ flex:1 1 0 !important; min-width:0; }
@media (max-width:1180px){
  .form-copy{
    flex:0 0 100% !important; width:100% !important; max-width:100% !important;
    position:static;
  }
  .dock-form-row{ column-gap:0 !important; }
}
/* THE PHOTO STOPS BEING A FILL AND BECOMES A HEADER STRIP BELOW 1025.
   Measured live 2026-09-04:
     1728  1713 x 1486  ratio 1.15      768  753 x 1207  ratio 0.62
      390   390 x 1357  ratio 0.29
   Under `cover` a 16:9 aerial in a 0.29 box is scaled to the box HEIGHT, so you
   see a strip 0.29/1.78 = 16% of the frame's width — a sliver through the middle.
   That is why the house and the water survive and the dock does not: it simply
   is not inside the middle sixteenth of the picture.
   A HEADER STRIP OF A KNOWN HEIGHT fixes it. `auto var(--strip)` scales the
   photograph to that height and lets the width run — cover behaviour confined
   to a band — so the whole aerial reads, dock included, with only a little off
   the sides.

   --strip DRIVES BOTH THE PHOTO AND THE FADE. The first version used
   `100% auto`, which renders at the file's native ratio: correct, but CSS
   cannot know where that lands, so the gradient could not follow it and the
   photo ended on a hard horizontal line straight across the form. One variable
   means the two can never disagree. Raise it for a taller band; the fade moves
   with it. */
/* Doubled class for weight. A plain .dock-form-band with !important still lost
   background-position on the live page — probed 2026-09-04, `50% 0%` typed in
   at (0,1,0)!important still computed as `0% 0%`, so something per-element is
   carrying !important at higher specificity. (0,2,0) settles it. If the photo
   still anchors left, set Position to Top Center on the section in Elementor for
   tablet and mobile — it is a responsive control and it removes the fight. */
@media (max-width:1024px){
  .dock-form-band.dock-form-band{
    --strip:min(62vw, 520px);
    /* The section stops painting its own background here — 0 0 hides it while
       LEAVING THE URL in the computed value, which is what ::after inherits. */
    background-size:0 0 !important;
  }
  /* THE STRIP IS ITS OWN LAYER NOW. `auto var(--strip)` scaled the photo to the
     strip's height and let the width fall where it fell — narrower than the
     screen on a source less landscape than 1.6, which is the navy down both
     edges. A pseudo-element of exactly --strip tall can take `cover` properly:
     fills edge to edge, crops whichever axis is long, never distorts.
     `background-image:inherit` pulls the photograph off the section, so the
     client still assigns it in the normal place and nothing is hard-coded. */
  .dock-form-band::after{
    content:""; position:absolute; inset:0 0 auto 0; height:var(--strip);
    background-image:inherit;
    background-size:cover;
    background-position:center;
    background-repeat:no-repeat;
    z-index:0; pointer-events:none;
  }
}
/* Navy behind the strip — also the lazy-load guard, same as .lambo-section:
   this band is a late .e-con.e-parent, so its photo is suppressed until the
   observer fires and a transparent section would flash the white page. */
.dock-form-band{ background-color:var(--e-global-color-primary); }

@media (max-width:1024px){
  .dock-form-band{ padding:88px 48px !important; }
  .form-copy > .elementor-widget-heading{ margin-bottom:28px !important; }
  /* Fades out exactly where the photograph stops, so there is no cut line. The
     copy may straddle the boundary — that is fine and reads deliberate, which a
     hard edge does not. Stays light enough over the picture for the gold eyebrow
     and white headline, solid by the time the form fields arrive. */
  .dock-form-band::before{
    background:linear-gradient(180deg,
      rgba(24,63,94,.28) 0,
      rgba(24,63,94,.44) calc(var(--strip) * .55),
      rgb(24,63,94) var(--strip)) !important;
  }
}
@media (max-width:767px){
  .dock-form-band{ padding:64px 24px !important; }
  /* Blurb to first field. 56 was the desktop two-column row gap carried down;
     stacked on a phone it read as a hole. */
  .dock-form-row{ row-gap:32px !important; }
}

/* --- GRAVITY FORMS 3.0 -----------------------------------------------------
   MEASURED on the live page 2026-09-03, not assumed:
     wrapper   .gform_wrapper.gravity-theme.gform-theme--no-framework
               (the 2.5 theme, NOT Orbital — so there is no --gf-ctrl-* surface
                to set; it has to be .elementor-kit-19 overrides)
     grid      .gform_fields is a 12-col grid; .gfield--width-half spans 6
     labels    .gfield_label.gform-field-label
     submit    <button class="gform_button button"> — GF 3.0's change, so the
               old input[type=submit] .elementor-kit-19s would never have matched
   GF's basic.min.css / theme.min.css load in an order we do not control, so
   every colliding declaration is !important. Same call as the accordion.

   Comp 819:354, artboard 1728:
     track          x858 -> 1588 (730 wide), two 354 columns, 22 gutter
     label          31 line box directly above its control, no gap
     control        65 tall, padding 17 / 27, textarea 243 tall
     row rhythm     control bottom -> next label = 33
     submit         301 x 45 ghost, 39 below the textarea, chevron right
   Everything sits on the photo band, so labels are white and the fills are
   --apm-field. */

.dock-form-band .gform_wrapper{ max-width:730px; }

.dock-form-band .gform_fields{
  column-gap:22px !important;
  row-gap:33px !important;
}

/* Field titles are SUNSHINE on this band, not white. Measured against the
   scrim at #2F4C5E: accent 4.70:1, past AA for normal text. */
.dock-form-band .gfield_label{
  font-family:"Lato 800",sans-serif !important; font-weight:800 !important;
  font-size:16px !important; line-height:31px !important;
  letter-spacing:.04em; text-transform:uppercase !important;
  color:var(--e-global-color-accent) !important;
  margin:0 !important;                    /* comp: control sits straight under */
}
.dock-form-band .gfield_required{
  color:var(--e-global-color-accent) !important; margin-left:2px;
}
/* GF hides sub-labels by class, not display — keep that working. */
.dock-form-band .screen-reader-text{ position:absolute !important; left:-9999px; }

/* --- FALLBACKS FOR SUB-LABELS AND DESCRIPTIONS ----------------------------
   This form hides them, but the client will build their own forms and GF shows
   sub-labels by default on Name, Address, Date and Time fields. Without these
   the sub-labels inherit the 16px uppercase Sunshine title above and every
   compound field reads as four more headings.
   Sub-labels are a quieter white; they are secondary to the Sunshine title. */
.dock-form-band .gform-field-label--type-sub,
.dock-form-band .ginput_complex label{
  font-family:"Lato 500",sans-serif !important; font-weight:500 !important;
  font-size:13px !important; line-height:20px !important;
  letter-spacing:0 !important; text-transform:none !important;
  color:var(--e-global-color-0c26593) !important;
  opacity:.8; margin:6px 0 0 !important;
}
/* Compound fields (name, address) are their own grid inside the field. */
.dock-form-band .ginput_complex{
  display:grid !important;
  grid-template-columns:repeat(auto-fit, minmax(0, 1fr));
  column-gap:22px !important; row-gap:12px !important;
}
.dock-form-band .ginput_complex > span{ display:block; min-width:0; }
/* Address puts city/state/zip on their own rows — let it. */
.dock-form-band .ginput_complex.ginput_container_address{
  grid-template-columns:1fr 1fr;
}
.dock-form-band .ginput_complex.ginput_container_address .address_line_1,
.dock-form-band .ginput_complex.ginput_container_address .address_line_2{
  grid-column:1 / -1;
}
.dock-form-band .gfield_description{
  font-family:"Lato 500",sans-serif !important; font-weight:500 !important;
  font-size:14px !important; line-height:22px !important;
  color:var(--e-global-color-0c26593) !important; opacity:.8;
  padding:6px 0 0 !important;
}
/* Checkboxes / radios, same reason — GF's defaults are navy on navy here. */
.dock-form-band .gfield_checkbox label,
.dock-form-band .gfield_radio label{
  font-family:"Lato 500",sans-serif !important; font-weight:500 !important;
  font-size:16px !important; line-height:28px !important;
  text-transform:none !important; letter-spacing:0 !important;
  color:var(--e-global-color-0c26593) !important;
}

.dock-form-band .gfield input[type=text],
.dock-form-band .gfield input[type=tel],
.dock-form-band .gfield input[type=email],
.dock-form-band .gfield select,
.dock-form-band .gfield textarea{
  height:65px !important; min-height:65px !important;
  padding:17px 27px !important;
  background:var(--apm-field) !important;
  border:0 !important; border-radius:4px !important;
  font-family:"Lato 500",sans-serif !important; font-weight:500 !important;
  font-size:16px !important; line-height:31px !important;
  color:var(--e-global-color-primary) !important;
  width:100% !important;
}
.dock-form-band .gfield textarea{
  height:243px !important; min-height:243px !important;
  line-height:28px !important; resize:vertical;
}
/* Placeholder is Mid Ship, as drawn — NOT navy at reduced opacity.
   The dimmed navy I shipped first was not an accessibility choice and was not
   an improvement: measured on the #D9D9D9 fill it is 2.75:1 against the comp
   blue's 3.68:1. Neither clears AA (4.5:1) for 16px text, so this is built as
   the AD drew it and the number is logged as an open item rather than quietly
   overridden. Every field carries a persistent visible label above it, so the
   placeholder is supplementary and never the accessible name.
   If AA is ever required here, #07629C is the first step down that clears it
   at 4.60:1 and still reads as the lighter blue. */
.dock-form-band .gfield ::placeholder{
  color:var(--e-global-color-secondary) !important; opacity:1;
}

/* A <select> HAS NO PLACEHOLDER. Its prompt is a real <option>, so ::placeholder
   never reaches it and the text takes the select's own `color`. Comp draws it in
   the same Mid Ship as the text placeholders, so that is the default here.

   The :has() rule keeps it right in both configurations. Today the prompt is a
   normal choice with a non-empty value, so no option[value=""] exists, nothing
   matches, and the field stays Mid Ship. If the prompt is moved into the
   field's Placeholder setting (worth doing — see below), GF renders it as
   value="" and a genuinely chosen answer then reads navy while the prompt stays
   light. Degrades to Mid Ship where :has() is unsupported, which is the comp. */
.dock-form-band .gfield select{
  color:var(--e-global-color-secondary) !important;
}
.dock-form-band .gfield select:has(option[value=""]:not(:checked)){
  color:var(--e-global-color-primary) !important;
}
/* The open dropdown is painted by the OS on its own surface — keep it navy. */
.dock-form-band .gfield select option{ color:var(--e-global-color-primary); }
.dock-form-band .gfield :is(input,select,textarea):focus-visible{
  outline:2px solid var(--e-global-color-accent) !important; outline-offset:2px;
}

/* Native select arrow off, the comp's chevron in. Inline SVG so there is no
   extra request and the colour is ours. */
.dock-form-band .gfield select{
  appearance:none !important; -webkit-appearance:none !important;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='15' height='8' viewBox='0 0 15 8'><path d='M1 1l6.5 6L14 1' fill='none' stroke='%230071B7' stroke-width='2'/></svg>") !important;
  background-repeat:no-repeat !important;
  background-position:right 35px center !important;   /* comp chevron at 1553 */
  padding-right:70px !important;
}

/* Submit. GF 3.0 renders a <button>, and the spinner now lives inside it, so
   the padding has to hold both without the label jumping. */
.dock-form-band .gform_footer,
.dock-form-band .gform-footer{
  margin:39px 0 0 !important; padding:0 !important;   /* comp: 39 under the textarea */
  display:flex !important; justify-content:flex-start !important;
}
.dock-form-band button.gform_button{
  display:inline-flex !important; align-items:center; gap:12px;
  width:auto !important; min-height:45px;
  padding:14px 28px !important;
  background:transparent !important;
  border:2px solid var(--e-global-color-accent) !important;
  border-radius:70px !important;
  font-family:"Lato 800",sans-serif !important; font-weight:800 !important;
  font-size:16px !important; line-height:1 !important;
  text-transform:uppercase !important;
  color:var(--e-global-color-accent) !important;
  transition:background .2s ease, color .2s ease;
}
.dock-form-band button.gform_button::after{
  content:""; width:8px; height:15px; flex:0 0 8px;
  background:currentColor;
  -webkit-mask:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='8' height='15'><path d='M1 1l6 6.5L1 14' fill='none' stroke='black' stroke-width='2'/></svg>") no-repeat center/contain;
  mask:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='8' height='15'><path d='M1 1l6 6.5L1 14' fill='none' stroke='black' stroke-width='2'/></svg>") no-repeat center/contain;
}
.dock-form-band button.gform_button:hover,
.dock-form-band button.gform_button:focus-visible{
  background:var(--e-global-color-accent) !important;
  color:var(--e-global-color-primary) !important;
}
/* The in-button spinner GF 3.0 introduced. */
.dock-form-band button.gform_button .gform-loader{
  border-color:currentColor !important; border-right-color:transparent !important;
}

/* Validation, so an error state does not fall back to GF's red-on-white. */
.dock-form-band .gfield_error input,
.dock-form-band .gfield_error select,
.dock-form-band .gfield_error textarea{
  outline:2px solid #E4572E !important; outline-offset:0;
}
.dock-form-band .gfield_validation_message,
.dock-form-band .validation_message{
  background:transparent !important; border:0 !important;
  padding:6px 0 0 !important;
  font-family:"Lato 500",sans-serif; font-size:14px;
  color:var(--e-global-color-accent) !important;
}
.dock-form-band .gform_validation_errors{
  background:transparent !important; border:0 !important;
  box-shadow:none !important; padding:0 0 16px !important;
}
.dock-form-band .gform_validation_errors h2{
  font-size:16px !important; color:var(--e-global-color-accent) !important;
}
.dock-form-band .gform_confirmation_message{
  font-family:"Lato 500",sans-serif; font-size:18px; line-height:30px;
  color:var(--e-global-color-0c26593);
}

@media (max-width:1024px){
  .dock-form-band .gform_wrapper{ max-width:none; }
}
@media (max-width:767px){
  .dock-form-band .gform_fields{ row-gap:24px !important; }
  .dock-form-band .gfield{ grid-column:1 / -1 !important; }
  .dock-form-band .gfield input[type=text],
  .dock-form-band .gfield input[type=tel],
  .dock-form-band .gfield input[type=email],
  .dock-form-band .gfield select{
    height:56px !important; min-height:56px !important; padding:12px 18px !important;
  }
  .dock-form-band .gfield textarea{ height:180px !important; min-height:180px !important; }
  .dock-form-band .gform_footer,
  .dock-form-band .gform-footer{ margin-top:28px !important; }
  .dock-form-band button.gform_button{ width:100% !important; justify-content:center; }
}

/* ----------------------------------------------------------------------------
   47.  DOCKS PAGE — reduced motion + Elementor editor
   Both scroll groups un-pin so the editor can select the background container
   and so nothing moves for a visitor who asked it not to.
---------------------------------------------------------------------------- */
/* THE STAGE IS AN EMPTY CONTAINER NOW.
   Once the headline moves into the panels the stage holds nothing but the
   photograph, so `height:auto` collapses it to zero — no photo for a
   reduced-motion visitor, and a strip too thin to select in the editor. Both
   hatches need an explicit body. 60vh is the same figure sections 31 and 33 use
   when they un-pin. */
@media (prefers-reduced-motion: reduce){
  .dock-sg-stage{
    position:static !important; height:auto !important;
    min-height:60vh !important; margin-bottom:0 !important;
  }
}
body.elementor-editor-active .dock-sg-stage{
  position:static !important; height:auto !important;
  min-height:60vh !important; margin-bottom:0 !important;
}


/* ----------------------------------------------------------------------------
   48.  HERO PARTNER LOCKUP  (Neptune on Boat Lifts, Decks & Docks on Docks)
   Client request, post-comp — a supply/manufacturer mark in the hero's lower
   right corner, the same idea as 4Ocean on the home page.

   ONE CLASS: `hero-partner` on the logo's CONTAINER. Nothing on the section.

   The only structural rule: that container must be a DIRECT CHILD OF THE HERO
   SECTION — a sibling of the copy block, not inside it. The copy block is a
   positioning context capped at 824px, so a logo nested inside it pins to the
   right edge of the TEXT COLUMN, about 760px short of the page edge. One level
   up in the Navigator is the whole fix.

   `:has()` gives the section its positioning anchor automatically. It is ~95%
   supported; on anything older the logo would fall back to the nearest
   positioned ancestor. `apm-hero` on the section is an optional hardening step
   if that ever matters — the Docks hero already gets it from `docks-hero`.

   `bottom` is the single number to nudge if you want the mark to sit exactly on
   the button baseline at your hero height — it is anchored to the section's
   corner, so the two only coincide at one window height by design.

   Image widget preferred over Icon: a partner mark should carry alt text, and
   cut SVGs crash the Icon widget's SVG mode (gotcha #14).
---------------------------------------------------------------------------- */
/* IN FLOW, NOT ABSOLUTE — corrected 2026-09-03.
   It was anchored to the hero's bottom-right corner, which put it 63px below
   the CTA row at 1728x1028 and pushed it under the fold once browser chrome
   was accounted for. The Boat Lifts hero does not have that problem because it
   is built in flow: the CTA row and the logo are siblings in one flex row with
   align-items:center, so their centres agree by construction. Measured there:
   0px difference.

   Docks cannot use that structure without moving the CTA row out of the copy
   block, so it gets the same RESULT arithmetically instead. The logo sits as
   the last flex child, right-aligned, pulled up by half the CTA row plus half
   its own height — which lands its centre exactly on the CTA centre, because
   the CTA row is the last thing in the copy block and therefore defines the
   copy block's bottom edge.

     logo centre = copy bottom - (cta/2 + logo/2) + logo/2
                 = copy bottom - cta/2
                 = CTA centre                        <- identity, not a nudge

   It self-corrects when the H1 rewraps, which the old `bottom` value could not.
   Taking it out of absolute adds it to the flow, so the whole block rises about
   1px. Nothing else to tune. */
:root{
  --hero-cta-h:48px;                  /* Theme Style button: 14 + 20 + 14 */
  /* Sized against the 4Ocean lockup on the home page, which the client uses as
     the reference: its container measures 121px tall and the mark inside is a
     112px SVG. 56 read as an afterthought next to it. 7vw hits 121 at the 1728
     design width and holds 121-128 across every desktop size. */
  --hero-logo-h:clamp(72px, 7vw, 128px);
}

.hero-partner{
  position:static !important;
  align-self:flex-end;
  width:auto !important;
  height:var(--hero-logo-h) !important;   /* lock it to the image, see below */
  margin-top:calc(-1 * (var(--hero-cta-h) + var(--hero-logo-h)) / 2) !important;
  z-index:2;
}
/* The height lock is load-bearing, not tidiness. The formula only holds if the
   container is exactly as tall as the logo inside it; leave it to shrink-wrap
   and a stray line box makes it a few px taller, which halves into a visible
   offset. Locking both to --hero-logo-h makes them equal by definition.

   A translateY(-50%) would also work in theory — transform percentages resolve
   against the element's own height where margin percentages resolve against
   WIDTH — but `transform` is contested on these containers (it computes to
   `none` on the live hero) and this needs no transform at all.

   VERIFIED on the live Docks hero at 1728x1028: CTA centre 843, logo centre
   843, Δ 0. */

.hero-partner img,
.hero-partner .elementor-icon svg{
  height:var(--hero-logo-h) !important;
  width:auto !important;
  display:block !important;
  margin-inline:0 !important;
  max-width:100%;
}
.hero-partner .elementor-icon{ line-height:0; }

/* Below desktop the CTAs stack, so the row is no longer one button tall and the
   negative pull would drag the mark over the buttons. Back to normal flow. */
@media (max-width:1024px){
  .hero-partner{
    align-self:flex-start;
    height:auto !important;
    margin-top:40px !important;
    width:100% !important;
  }
}


/* ----------------------------------------------------------------------------
   49.  DOCKS — MATERIALS STACK  (Composite pins, Wood scrolls over it)
   Same mechanic as the home page panels: section 14 supplies the pin (sticky,
   top:0, min-height:100vh, align-self:start). All this block does is make the
   two bands FIT the window, which is the stack's one requirement — a pinned
   panel does not move relative to the viewport, so anything below its own fold
   is unreachable.

   SELECTORS HANG OFF THE PANELS, NOT THE WRAPPER. This block used to read
   `.dock-materials > .apm-stack`, which needed a class on the Sticky Stack
   container that was never applied in the editor. With it missing, nothing
   here reached the page and the panels kept the comp's 184/278 and 254/377
   padding WHILE PINNED. Measured: 1512x780 buried 277px of composite and 326px
   of wood (the Explore button among it); 390x844 buried 369px. It only looked
   right on a 4K window, which is where it was checked.

   Measured content is 580px (composite) and 500px (wood). Clamping the block
   padding keeps the AD's air on a tall window and gives it back on a short one;
   centring moves composite ~45px off the comp's 184 and is what makes the panel
   fit at any height rather than only above 1100px.
---------------------------------------------------------------------------- */
.dock-composite.apm-stack,
.dock-wood.apm-stack{
  justify-content:center;
  padding-block:clamp(64px, 8vh, 184px) !important;
}
/* Both panels need an opaque edge-to-edge ground or the one underneath shows
   through as the next slides over it. Composite carries its flattened JPG and
   the brown from section 42; wood carries Creamy Foam plus its own JPG. */

/* A short desktop window is the same failure as a phone. Composite's tallest
   content above the breakpoint is 651px (at 1025 wide, where the type columns
   are still 4-across) and the padding floor is 64 top and bottom, so the panel
   cannot go below 779. Under a 780px window the pin comes off; the 100vh floor
   stays, so the band still reads full-bleed. Measured: 1025x640 buried 139px,
   1280x700 buried 23px. 1512x780 — the 14" MacBook — keeps the pin. */
@media (min-width:1025px) and (max-height:779px){
  .dock-composite.apm-stack,
  .dock-wood.apm-stack{ position:static !important; }
}

/* Below 1025 section 14 has already dropped the pin; these two just give the
   bands back normal band padding. */
@media (max-width:1024px){
  .dock-composite.apm-stack,
  .dock-wood.apm-stack{ min-height:0 !important; padding-block:88px !important; }
}
@media (max-width:767px){
  .dock-composite.apm-stack,
  .dock-wood.apm-stack{ padding-block:64px !important; }
}


/* ----------------------------------------------------------------------------
   50.  STRUCTURAL FALLBACK — survive a stale post-{page}.css
   Measured on the live /docks/ page 2026-09-04: the generated per-element file
   post-110.css carries 57 rules covering 49 element ids, against 219 elements
   in the DOM. 170 elements have no per-element CSS at all.

   That file is the ONLY source of a container's `--display` and
   `--flex-direction`; frontend.min.css just consumes them. With no `--display`,
   `display:var(--display)` is invalid at computed-value time and falls back to
   the initial value, `inline` — an inline box ignores height, so the No
   Shortcuts stage computed 237px instead of a full viewport and could not hold
   its photograph. With no `--flex-direction`, a column stack silently becomes a
   row.

   These rules restate the two properties for our own classes, so the layout no
   longer depends on that file existing. They are plain class .elementor-kit-19s, and
   this sheet loads after frontend.min.css, so they win on source order without
   !important; the per-element file sets only the variables, so nothing here
   fights it when it IS present.

   This is a safety net, not the fix. Regenerate the file — Elementor → Tools →
   Regenerate Files & Data, or re-save the page — so padding, gaps, widths and
   background images come back too. See rule 7 in APM-Build-Rules.
---------------------------------------------------------------------------- */
.docks-hero, .docks-hero-inner, .hero-partner,
.dock-trust-bar, .dock-trust-copy, .apm-trust-divider,
.dock-sg, .dock-sg-stage, .dock-sg-head, .dock-sg-panels, .dock-panel,
.dock-ourchoice, .oc-copy, .oc-media, .dock-card, .dock-sec-head,
.dock-composite, .type-col, .dock-wood, .wood-callout,
.dock-process, .proc-step, .proc-cta,
.dock-gallery, .coverflow-slot,
.dock-faq, .dock-form-band, .form-copy, .form-fields, .gf-slot{
  display:flex; flex-direction:column;
}
.dock-trust-row, .dock-trust-item, .oc-split, .dock-cards,
.type-cols, .dock-wood-row, .proc-grid, .dock-form-row{
  display:flex; flex-direction:row;
}


/* ----------------------------------------------------------------------------
   51.  HOME — INSTALLED FOR LIFE
   Read off the client's export + Figma 42:291. The SECTION ALREADY CARRIES THE
   SCRIM: Elementor background overlay, gradient, Creamy Foam -> #F3E7CE70 at
   45% (60% tablet), angle 90deg. Containers render that on {{WRAPPER}}::before.
   Nothing here draws a second one — an earlier pass hung a cream box on the copy
   block and it read as a hard-edged rectangle, which the comp does not have.

   THE ONE REAL PROBLEM: that overlay is HORIZONTAL. Below 1025 the copy stacks
   into the middle of the photograph and the cream is still running left-to-right,
   so the blue headline and navy paragraph sit on the busy part of the image. The
   fix is one line — turn the AD's own gradient down the page. Same colours, no
   new artwork, no edges.

   THE 70% STOP IS MEASURED, NOT PICKED. Rendered over black, the AD's own
   desktop setting leaves the cream 0.523 opaque at the far edge of the copy
   column. At 70% every width below the breakpoint lands 0.63-0.68 behind the
   last line of copy — never less cream than the design gives itself on desktop.
   Re-run ifl-real.js and alpha2 if the copy length changes.

   CLASSES (already applied): ifl-section, ifl-copy, ifl-promise,
   ifl-promise-copy. Everything else — widths, padding, gaps, colours, the card's
   row/column switch — is set in the editor and deliberately NOT repeated here.
---------------------------------------------------------------------------- */
@media (max-width:1024px){
  .ifl-section::before{
    background-image:linear-gradient(180deg,
      var(--e-global-color-893ac00) 0%, #F3E7CE70 70%) !important;
  }
}

/* The eyebrow is a Heading widget too, so a bare `.ifl-copy .elementor-heading-title`
   catches it — that is what blew the eyebrow up to headline size on phones.
   Scope every type rule here off .eyebrow. */
@media (max-width:767px){
  .ifl-copy .elementor-widget-heading:not(.eyebrow) .elementor-heading-title{
    font-size:clamp(28px, 8.4vw, 38px) !important;   /* comp H2 is 60/58 */
    line-height:.97 !important;
  }
}

/* Comp body: Lato Medium 16/28. The Text Editor has no class of its own. */
.ifl-copy .elementor-widget-text-editor p{
  font-family:"Lato 500",sans-serif; font-weight:500;
  font-size:16px; line-height:28px; color:var(--e-global-color-text);
}
@media (max-width:767px){
  .ifl-copy .elementor-widget-text-editor p{ line-height:26px; }
}

/* ---- the promise card ---------------------------------------------------- */
/* Comp height only. Padding, gaps and alignment are the editor's. */
@media (min-width:1025px){ .ifl-promise{ min-height:175px; } }
.ifl-promise img, .ifl-promise .elementor-icon svg{ display:block; }

/* THE CLIPPING: the editor switches the card to a column at MOBILE only, but at
   768 the row cannot hold icon 38 + copy + a 269px button inside 768 — measured
   839px of content. Column from 1025 down, and the button goes full width. */
@media (max-width:1024px){
  .ifl-promise{
    flex-direction:column !important;
    align-items:flex-start !important;
    height:auto !important; min-height:0 !important;
  }
  .ifl-promise-copy{ width:100% !important; }
  .ifl-promise .elementor-widget-button,
  .ifl-promise .elementor-button{ width:100% !important; }
}

/* 320px: the global .elementor-button{white-space:nowrap} makes this 23-character
   label 310px wide inside a 272px card — 15px of horizontal scroll. Measured. */
@media (max-width:374px){
  .ifl-promise .elementor-button{ font-size:14px !important; padding-inline:20px !important; }
}/* End custom CSS */
/* Start Custom Fonts CSS */@font-face {
	font-family: 'Special Gothic Expanded One';
	font-style: normal;
	font-weight: 400;
	font-display: auto;
	src: url('https://stg-allpowermarine-dev.kinsta.cloud/wp-content/uploads/2026/07/special-gothic-expanded-one-400.woff2') format('woff2'),
		url('https://stg-allpowermarine-dev.kinsta.cloud/wp-content/uploads/2026/07/special-gothic-expanded-one-400.woff') format('woff'),
		url('https://stg-allpowermarine-dev.kinsta.cloud/wp-content/uploads/2026/07/SpecialGothicExpandedOne-Regular.ttf') format('truetype');
}
/* End Custom Fonts CSS */
/* Start Custom Fonts CSS */@font-face {
	font-family: 'Lato 500';
	font-style: normal;
	font-weight: 500;
	font-display: auto;
	src: url('https://stg-allpowermarine-dev.kinsta.cloud/wp-content/uploads/2026/07/Lato-Medium.eot');
	src: url('https://stg-allpowermarine-dev.kinsta.cloud/wp-content/uploads/2026/07/Lato-Medium.eot?#iefix') format('embedded-opentype'),
		url('https://stg-allpowermarine-dev.kinsta.cloud/wp-content/uploads/2026/07/Lato-Medium.woff2') format('woff2'),
		url('https://stg-allpowermarine-dev.kinsta.cloud/wp-content/uploads/2026/07/Lato-Medium.woff') format('woff'),
		url('https://stg-allpowermarine-dev.kinsta.cloud/wp-content/uploads/2026/07/Lato-Medium.ttf') format('truetype');
}
/* End Custom Fonts CSS */
/* Start Custom Fonts CSS */@font-face {
	font-family: 'Lato 800';
	font-style: normal;
	font-weight: 800;
	font-display: auto;
	src: url('https://stg-allpowermarine-dev.kinsta.cloud/wp-content/uploads/2026/07/Lato-Heavy.eot');
	src: url('https://stg-allpowermarine-dev.kinsta.cloud/wp-content/uploads/2026/07/Lato-Heavy.eot?#iefix') format('embedded-opentype'),
		url('https://stg-allpowermarine-dev.kinsta.cloud/wp-content/uploads/2026/07/Lato-Heavy.woff2') format('woff2'),
		url('https://stg-allpowermarine-dev.kinsta.cloud/wp-content/uploads/2026/07/Lato-Heavy.woff') format('woff'),
		url('https://stg-allpowermarine-dev.kinsta.cloud/wp-content/uploads/2026/07/Lato-Heavy.ttf') format('truetype');
}
/* End Custom Fonts CSS */