/* ---- tokens.css ---- */
/* ============================================================================
   TOKENS — Raisin River Marine

   Values are taken from the original site's generated Porto stylesheet
   (theme_css_vars.css) and from getComputedStyle on the live page — not
   estimated from screenshots. Where a value below differs from Porto's own,
   the measured value won and the reason is noted inline.

   Porto switched sizes abruptly at 575px. Everything here interpolates
   smoothly between Porto's ≤575px value and its ≥576px value instead, so the
   endpoints match the original exactly and nothing jumps in between.
   Formula:  clamp(MIN, <intercept>rem + <slope>vw, MAX)  over 360px → 576px.
   ========================================================================= */

:root {
  /* ---- brand ----------------------------------------------------------
     Porto: --porto-primary-color #1c5fa8, --porto-secondary-color #e36159,
     --porto-tertiary-color #2baab1, --porto-quaternary-color #383f48. */
  --blue: #1c5fa8;         /* primary — nav accents, links, buttons */
  --blue-dark: #195393;    /* porto primary-dark-5, button hover */
  --blue-darker: #15477d;  /* porto primary-dark-10 */
  --blue-light: #206cbe;   /* porto primary-light-5 */
  --coral: #e36159;        /* secondary — CTA / highlight */
  --coral-dark: #e04d44;   /* porto secondary-dark-5 */
  --teal: #2baab1;         /* tertiary */
  --slate: #383f48;        /* quaternary — dark bands */

  /* ---- neutrals ------------------------------------------------------- */
  --ink: #222529;          /* headings (--porto-heading-color) */
  --ink-alt: #212529;      /* dark bands, footer (--porto-dark-color) */
  --body: #777777;         /* body copy (--porto-body-color) */
  --muted: #999999;        /* --porto-gray-6 */
  --white: #ffffff;
  --grey-band: #f7f7f7;    /* MEASURED — alternating section bands */
  --grey-slide: #e7e7e7;   /* --porto-gray-2 */
  --dark-band: #333333;    /* MEASURED — footer contact band */
  --grey-soft: #f4f4f4;    /* --porto-gray-1 */
  --grey-panel: #fbfbfb;   /* --porto-widget-bgc */
  --grey-title: #f5f5f5;   /* --porto-title-bgc */
  --line: #dddddd;         /* --porto-widget-bc */
  --line-soft: rgba(0, 0, 0, 0.06);   /* --porto-normal-bc */
  --input-border: rgba(0, 0, 0, 0.08); /* --porto-input-bc */

  /* ---- inventory-specific --------------------------------------------- */
  --price: #444444;        /* --porto-color-price */
  --sale: #e27c7c;         /* --porto-sale-color */
  --sold: #6c757d;         /* new: badge for sold/unavailable stock */

  /* ---- type ------------------------------------------------------------
     Porto loaded Poppins 300–800 from Google Fonts. Self-hosted here in the
     six weights the theme actually uses (800 added 2026-09-29), so the site has no external
     dependency. Porto's --porto-alt-ff "Shadows Into Light" is referenced by
     exactly one theme rule that this site never matches — not loaded. */
  --font: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;

  /* body 13px ≤575 → 14px ≥576 */
  --fs-body: clamp(0.8125rem, 0.7083rem + 0.463vw, 0.875rem);
  /* Inner-page banner title. RE-MEASURED on the live site: h1.page-title is
     32px/40px/ls -1.6px on every template that shows one. The 36px this used to
     carry came from Porto's variables, not from the page. 29.7px at ≤575 via
     Porto's 0.9286 mobile scale. */
  --fs-h1: clamp(1.8563rem, 1.6167rem + 1.065vw, 2rem);
  /* Section h2. RE-MEASURED: 30.8px/30.8px/-1.54px — exactly Porto's variables.
     The 32.2px/44px previously here belongs to the HOMEPAGE HERO heading, which
     has its own tokens below; applying it here made every section heading a
     little large and every line 13px too tall. 28.6px at ≤575. */
  --fs-h2: clamp(1.7875rem, 1.5583rem + 1.019vw, 1.925rem);
  /* h3 14.3px → 15.4px */
  --fs-h3: clamp(0.89375rem, 0.7792rem + 0.51vw, 0.9625rem);
  /* Eyebrow/h4 MEASURED at 18.9px, not Porto's 20px. 17.55px at ≤575. */
  --fs-h4: clamp(1.0969rem, 0.9563rem + 0.62vw, 1.1812rem);
  /* h5/h6 13px → 14px */
  --fs-h5: clamp(0.8125rem, 0.7083rem + 0.463vw, 0.875rem);
  --fs-small: 0.75rem;     /* 12px — meta, badges, breadcrumb */
  --fs-lead: clamp(0.9375rem, 0.8333rem + 0.463vw, 1rem);
  /* Homepage hero heading — MEASURED 32.2px/44px/-1.61px. Its own token so that
     correcting the section h2 above can never drag it off again. */
  --fs-hero: clamp(1.8688rem, 1.6293rem + 1.06vw, 2.0125rem);
  --ls-hero: -0.05em;

  /* Porto line-heights, expressed unitless so they survive the fluid sizes:
     body 26/14, h1 44/36, h2 30.8/30.8, h3 20.02/15.4, h4 27/20, h5 18/14 */
  --lh-body: 1.857;        /* 26px at 14px */
  --lh-h1: 1.25;           /* MEASURED 40px at 32px */
  --lh-h2: 1;              /* MEASURED 30.8px at 30.8px — Porto's vars were right */
  --lh-h3: 1.3;            /* 20.02px at 15.4px */
  --lh-h4: 1.7;            /* MEASURED 32.13px at 18.9px (hero eyebrow) */
  --lh-h5: 1.286;          /* 18px at 14px */

  /* Porto sets these in px against a fixed size; -0.05em is the same ratio
     and holds as the fluid size changes. h4/h5 are `normal`. */
  --ls-h1: -0.05em;        /* MEASURED -1.6px at 32px */
  --ls-h2: -0.05em;        /* -1.54px at 30.8px */
  --ls-h3: -0.05em;        /* -0.77px at 15.4px */
  --ls-body: 0;

  --fw-body: 400;
  --fw-h1: 400;
  --fw-h2: 700;
  --fw-h3: 400;
  --fw-strong: 600;

  /* ---- spacing -------------------------------------------------------- */
  /* MEASURED: section bands run 48–50px top/bottom at desktop. */
  --section-y: clamp(2rem, 1.571rem + 1.9vw, 3.125rem);      /* 32 → 50 */
  --section-y-tight: clamp(1.25rem, 1.036rem + 0.95vw, 1.75rem);
  --gap: 30px;             /* --porto-grid-gutter-width */
  --gap-col: 15px;         /* --porto-column-spacing */

  /* .container is max-width 1200px WITH 15px padding each side in Porto's
     bootstrap, so the content box is 1170px — not 1200. That holds only from
     1230px up. RE-MEASURED 2026-09-29 at 17 widths: the original steps to
     960px (930 content) from 992px, and below 992px it is full width with
     30px side padding (20px below 576px). This used to be one fluid 1200px
     box with 15px padding, which matched at 1256px and nowhere below it — the
     cause of "Our Services is not full width" and three service cards
     dropping to two in the client review. The steps are in base/layout.css. */
  --container: 1200px;
  --container-lg: 960px;
  --gutter: 15px;

  /* ---- grid minimums --------------------------------------------------
     Tuned against the 1170px content box with a 30px gap:
     4 cols → (1170 - 90)/4 = 270; 3 → 370; 2 → 570. Minimums sit just under
     each so the column count drops on its own without a media query. */
  --col-min-2: 460px;
  --col-min-3: 340px;
  --col-min-4: 255px;
  --col-min-gallery: 255px;
  /* The inventory grid is not fluid any more: it steps 2 / 3 / 4 across at the
     original's 768px and 1230px (components/inventory.css). */

  /* ---- chrome ----------------------------------------------------------
     Porto: --porto-logo-mw 123px ≥992px, 110px ≤991px — a step, not a fluid
     size (re-measured 2026-09-29). The logo asset is 2560×1956 (ratio 1.309),
     so it renders 123×94 and 110×84; header.css sets both widths.
     MEASURED: top bar 54px + main bar 121px = 175px total.
     Main bar = 13px padding + 94px logo + 13px padding + 1px rule. */
  --logo-ratio: 1.309;
  --header-pad-y: 13px;
  --header-border: rgba(234, 234, 234, 0.5);

  /* MEASURED on the live buttons: 12px. Porto's square-corner default does not
     apply on this site — every button is rounded. */
  --radius: 12px;
  --radius-badge: 2px;

  /* Button metrics, measured: primary 21px/48px padding at 14px/700 → 64px tall;
     outline variant carries a 2px border and 38.4px side padding. */
  --btn-pad-y: 21px;
  --btn-pad-x: 48px;
  --btn-pad-x-outline: 38.4px;
  --btn-fs: 0.875rem;
  --btn-fw: 700;

  /* Separator under section headings. RE-MEASURED on the live site: every one is
     4px tall, brand blue, and exactly as wide as its container — 570px, 1170px
     and 770px on the homepage, all matching the column they sit in. None is
     animated. The 60px fixed width and the 1s grow animation recorded here
     before were not on the page. */
  --rule-h: 4px;
  /* Width of the narrow centred column the "New Inventory" heading sits in. */
  --col-narrow: 770px;

  --shadow-card: 0 0 12px rgba(0, 0, 0, 0.08);
  --shadow-card-hover: 0 6px 20px rgba(0, 0, 0, 0.14);

  --transition: 0.25s ease;
  --transition-slow: 0.5s ease;

  /* ---- the nav breakpoint ---------------------------------------------
     Porto collapses its nav to a drawer at 991px. The container and grids
     also step at 576 / 768 / 992 / 1230, the original's own breakpoints. */
  --bp-nav: 991px;
}

/* Self-hosted Poppins. `swap` so text is readable before the font arrives —
   on a business site a visible fallback always beats invisible copy. */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/assets/fonts/poppins-300.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/poppins-400.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/fonts/poppins-500.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/fonts/poppins-600.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/poppins-700.woff2") format("woff2");
}
/* 800: the testimonial names. Added 2026-09-29 with the client review. The
   file is the same Google Fonts latin subset as the five above (this repo's
   400 is byte-identical to the-walker-runner's), copied from that repo. */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url("/assets/fonts/poppins-800.woff2") format("woff2");
}

/* ---- base/reset.css ---- */
/* ---- reset & document defaults ------------------------------------------ */

*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: var(--lh-body);
  color: var(--body);
  background: var(--white);
  /* No -webkit-font-smoothing: antialiased here. The original leaves it at
     `auto` (measured 2026-09-29), and on a Mac `antialiased` draws every
     glyph visibly thinner — part of what the client review saw as "the
     letters are smaller than the original". */
  overflow-x: hidden;
}

img {
  max-width: 100%;
  height: auto;
  display: block;
  border: 0;
}

a {
  color: var(--blue);
  text-decoration: none;
  transition: color var(--transition);
}
a:hover { color: var(--blue-dark); }

p { margin: 0 0 1rem; }
p:last-child { margin-bottom: 0; }

ul, ol { margin: 0 0 1rem; padding-left: 1.25rem; }

/* Keyboard focus was invisible in the original theme. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: -60px;
  left: 12px;
  z-index: 2000;
  padding: 10px 18px;
  background: var(--ink-alt);
  color: #fff;
  font-weight: 600;
  transition: top var(--transition);
}
.skip-link:focus { top: 12px; color: #fff; }

/* ---- base/typography.css ---- */
/* ---- typography ----------------------------------------------------------
   Body sizes are fluid via clamp(). Section headings step at 576px as the
   original's do (since the client review, 2026-09-29), and a few components
   carry the original's own phone-width sizes in their files.
   -------------------------------------------------------------------------- */

/* The heading elements carry their sizes directly. The shared template put
   them on a `.section-title` class instead, which meant a bare <h2> fell all
   the way back to the browser default — measured at 21px against the
   original's 32.2px before this was fixed. Sizes are the measured ones. */
h1, h2, h3, h4, h5, h6 {
  margin: 0 0 1rem;
  color: var(--ink);
}

/* Measured: 32px / 700 / −0.05em / lh 40px on the inner-page banner. */
h1 {
  font-size: var(--fs-h1);
  font-weight: var(--fw-h1);
  line-height: var(--lh-h1);
  letter-spacing: var(--ls-h1);
}

/* Measured: 30.8px / 700 / −0.05em / lh 30.8px / #212529 */
/* `.h2` is the same face on an element that is not an h2 — the About and
   Contact pages keep their first heading as the page's h1 (README defect #9)
   but the original draws it as a section h2. The client review of 2026-09-29
   ("the headings are not like the original") found them at h1's 32px / 400.
   Below 576px the original steps to 28.6px on a 40px line (measured at 390
   and 575). */
h2,
.h2 {
  font-size: var(--fs-h2);
  font-weight: var(--fw-h2);
  line-height: var(--lh-h2);
  letter-spacing: var(--ls-h2);
  color: var(--ink-alt);
}
@media (max-width: 575px) {
  /* Porto keeps letter-spacing in px, so it does not shrink with the size. */
  h2, .h2 { font-size: 1.7875rem; line-height: 40px; letter-spacing: -1.54px; }
}

h3 {
  font-size: var(--fs-h3);
  font-weight: var(--fw-h3);
  line-height: var(--lh-h3);
  letter-spacing: var(--ls-h3);
}

h4 {
  font-size: var(--fs-h4);
  font-weight: 600;
  line-height: var(--lh-h4);
}

h5, h6 {
  font-size: var(--fs-h5);
  font-weight: 600;
  line-height: var(--lh-h5);
}

/* Utility forms, for the places the original used a heading level for weight
   rather than for document structure. */
.h3 { font-size: var(--fs-h3); font-weight: 500; line-height: var(--lh-h3); }
.h4 { font-size: var(--fs-h4); font-weight: 600; line-height: var(--lh-h4); letter-spacing: normal; }

/* The hero kicker. Measured 18.9px / 700 / −0.05em / lh 32.13px / #969696 —
   grey and plain. The shared template's version was a blue uppercase label
   with a highlighter bar behind it, which belongs to a different client. */
.eyebrow {
  margin: 0 0 0.75rem;
  color: var(--muted);
  font-size: var(--fs-h4);
  font-weight: 700;
  line-height: var(--lh-h4);
  letter-spacing: -0.05em;
}

.section-title {
  margin: 0 0 18px;
  font-size: var(--fs-h2);
  font-weight: 600;
  line-height: var(--lh-h2);
  letter-spacing: var(--ls-h2);
  color: var(--ink);
}

.section-intro {
  max-width: 700px;
  margin: 0 auto;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--body);
}

.section-head { margin-bottom: clamp(2rem, 1.5rem + 2.2vw, 3.125rem); }
.section-head--center { text-align: center; }

/* The original's opening paragraphs — first under "Over Thirty Years", the
   testimonial and inventory subheads — are 15.4px LIGHT (300) on a 26px line,
   at every width. The rebuild had them at body size and weight, which is what
   the client review meant by "the letters are smaller than the original". */
.lead { font-size: 0.9625rem; font-weight: 300; line-height: 26px; }

/* Red zigzag rule under card titles and team names. */
.zigzag {
  display: block;
  width: 46px;
  height: 8px;
  margin-top: 8px;
  background-repeat: no-repeat;
  background-size: 46px 8px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='46' height='8' viewBox='0 0 46 8'%3E%3Cpath d='M1 6.5 L6.5 1.5 L12 6.5 L17.5 1.5 L23 6.5 L28.5 1.5 L34 6.5 L39.5 1.5 L45 6.5' fill='none' stroke='%23ff0000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
.zigzag--center { margin-left: auto; margin-right: auto; }

/* The angled band divider lives in components/shape-divider.css. */

/* ---- base/layout.css ---- */
/* ---- layout primitives ---------------------------------------------------
   The container steps at the original's own breakpoints (576 / 992 / 1230),
   because every column on the original is a share of THAT box. It used to be
   one fluid 1200px box, which matched only from 1230px up: at 1024px the
   original's content is 930px wide and this one's was 994px, so the About
   page's full-width "Our Services" bar and its three service cards could not
   reflow the way the client saw them reflow (client review, 2026-09-29).
   -------------------------------------------------------------------------- */

.container {
  width: 100%;
  margin: 0 auto;
  padding: 0 20px;
}
@media (min-width: 576px) {
  .container { padding: 0 30px; }
}
@media (min-width: 992px) {
  .container { max-width: var(--container-lg); padding: 0 var(--gutter); }
}
@media (min-width: 1230px) {
  .container { max-width: var(--container); }
}

.section { padding: var(--section-y) 0; position: relative; }
.section--tight { padding: var(--section-y-tight) 0; }
.section--grey { background: var(--grey-band); }
.section--soft { background: var(--grey-soft); }
.section--dark { background: var(--ink-alt); }

.row {
  display: flex;
  flex-wrap: wrap;
  margin: 0 -15px;
}
.row > * { padding: 0 15px; }

/* min(…, 100%) stops a column from ever being wider than its container,
   which is what would otherwise cause horizontal scroll on small phones. */
.grid { display: grid; gap: var(--gap); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(var(--col-min-2), 100%), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(var(--col-min-3), 100%), 1fr)); }
.grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(var(--col-min-4), 100%), 1fr)); }

/* Two-column content splits (text beside an image). Collapse by width, not
   by breakpoint: below ~760px the pair no longer fits and stacks itself. */
.split {
  display: grid;
  gap: clamp(2rem, 1rem + 4vw, 3.75rem);
  align-items: center;
  grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr));
}

/* ---- components/button.css ---- */
/* ---- buttons -------------------------------------------------------------
   Measured from the live site, not inherited from the template. Porto's
   buttons here are FLAT with a 12px radius — there is no offset shadow, which
   the shared template assumed.

   Primary : bg #1c5fa8, white, 21px/48px padding, 14px/700 → 64px tall
   Outline : transparent, #1c5fa8 text, 2px border, 21px/38.4px → 66px tall
   Light   : transparent, white text, 2px border, 12.8px/700
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  padding: var(--btn-pad-y) var(--btn-pad-x);
  border: 1px solid transparent;
  border-radius: var(--radius);
  font-family: inherit;
  font-size: var(--btn-fs);
  font-weight: var(--btn-fw);
  /* Porto's 1.42857: 20px at 14px, so a primary button is 64px tall. */
  line-height: 1.42857;
  text-align: center;
  text-decoration: none;
  /* Every button label on the original is in capitals — VIEW MORE, CONTACT US,
     OUR SERVICES, CALL NOW! — and the rebuild had them in title case (client
     review 2026-09-29). The words stay title case in the markup. */
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color var(--transition), color var(--transition),
    border-color var(--transition);
}

.btn--primary {
  background: var(--blue);
  border-color: var(--blue);
  color: var(--white);
}
.btn--primary:hover,
.btn--primary:focus-visible {
  background: var(--blue-dark);
  border-color: var(--blue-dark);
  color: var(--white);
}

/* The About page's "Our Services": from 992px it fills its column — the full
   width under the copy, at every width (930px at 992px–1229px, the whole
   content box from 1230px) — as the original's w-lg-100pct / vc_btn3-block do
   up to 1229px; the original's 210px column from 1230px is not reproduced
   (sections.css). Below 992px it is an ordinary button. */
.btn--bar { padding-inline: 38.4px; }
@media (min-width: 992px) {
  .btn--bar { display: flex; width: 100%; }
}

.btn--outline {
  padding: var(--btn-pad-y) var(--btn-pad-x-outline);
  background: transparent;
  border: 2px solid var(--blue);
  color: var(--blue);
}
.btn--outline:hover,
.btn--outline:focus-visible {
  background: var(--blue);
  color: var(--white);
}

.btn--outline-light {
  padding: 20.5px var(--btn-pad-x-outline);
  background: transparent;
  border: 2px solid var(--white);
  color: var(--white);
  font-size: 0.8rem;
}
.btn--outline-light:hover,
.btn--outline-light:focus-visible {
  background: var(--white);
  color: var(--blue);
}

/* Phone block: small uppercase label above the number. Used in the header,
   the dark CTA bands and beside "View More". */
.phone-block {
  display: inline-flex;
  flex-direction: column;
  gap: 2px;
  padding-block: 4px;
  text-decoration: none;
  line-height: 1.2;
}
/* RE-MEASURED 2026-09-29: label 11.2px / 600 / #777, number 18.9px / 700 /
   #333 — as the original's "CALL US NOW" blocks. */
.phone-block__label {
  font-size: 0.7rem;
  font-weight: 600;
  line-height: 13.44px;
  text-transform: uppercase;
  color: var(--body);
}
.phone-block__number {
  font-size: 1.18125rem;
  font-weight: 700;
  line-height: 1.2;
  color: #333;
}
.phone-block:hover .phone-block__number { color: var(--blue); }

/* Beside "View More" on the homepage the original puts a phone glyph in
   front of the two lines. */
.phone-block--icon { flex-direction: row; align-items: center; gap: 4px; color: var(--ink-alt); }
.phone-block--icon svg { flex: none; width: 43px; height: 43px; padding: 6px; }
.phone-block__text { display: flex; flex-direction: column; gap: 2px; }

.phone-block--light .phone-block__label { color: rgba(255, 255, 255, 0.72); }
.phone-block--light .phone-block__number { color: var(--white); }
.phone-block--light:hover .phone-block__number { color: var(--white); }

.cta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gap);
  margin-top: var(--gap);
}
/* The original separated the phone block from the button with a hairline. */
.cta-row .phone-block {
  padding-left: var(--gap);
  border-left: 1px solid #dee2e6;
}
/* On a phone the original stacks the call block under the button, with no
   hairline and no indent. */
@media (max-width: 575px) {
  .cta-row { gap: 16px; }
  .cta-row .phone-block { padding-left: 0; border-left: 0; }
}

/* Below 576px Porto shrinks its rem-based sizes by 0.9286, buttons included:
   13px on an 18.57px line, 19.5px × 44.57px of padding (11.89px and
   19.05px × 35.66px for the light outline one). */
@media (max-width: 575px) {
  .btn { padding: 19.5px 44.57px; font-size: 0.8125rem; line-height: 18.57px; }
  .btn--outline,
  .btn--bar { padding-inline: 35.66px; }
  .btn--outline-light { padding: 19.05px 35.66px; font-size: 0.743rem; line-height: 16.98px; }
}

/* ---- components/topbar.css ---- */
/* ---- top bar -------------------------------------------------------------
   Measured on the original: a full-width WHITE band, 7.3px top/bottom padding
   (54px tall), with a 1px bottom border of rgba(0,0,0,0.06). Email and the
   opening hours sit left, the Facebook link right.

   RE-MEASURED 2026-09-29 for the client review. Each item is 14px / 500 /
   −0.5px / #222529 with a #212529 glyph 8px before it: an envelope for the
   email (16.8px), a clock for each of the two hours items (14px). A 16px
   hairline follows the email. The hours and the hairline show from 768px up
   and the Facebook link from 576px up — the original's d-md-flex / d-sm-block —
   so a phone sees the email alone. The rebuild used to keep the hours on
   phones too (README defect #20); the review asked for the original back.

   The shared template's version was a skewed two-tone parallelogram carried
   over from a previous client — nothing like this site. Replaced.
   -------------------------------------------------------------------------- */

.topbar {
  position: relative;
  padding-block: 7.3px;
  background: var(--white);
  border-bottom: 1px solid var(--line-soft);
  color: var(--ink);
}

.topbar .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap);
}

.topbar-contact {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
}

.topbar-item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.875rem;
  font-weight: 500;
  letter-spacing: -0.5px;
  line-height: 24px;
  color: var(--ink);
  text-decoration: none;
}
a.topbar-item:hover { color: var(--blue); }
.topbar-icon { flex: none; color: var(--ink-alt); }

/* Spacing measured between the pieces: email → hairline 21px, hairline →
   first clock 18px, first hours → second clock 18px. The envelope sits in a
   20px box, as the original's icon wrapper. */
a.topbar-item { margin-right: 21px; }
a.topbar-item .topbar-icon { box-sizing: content-box; padding-right: 3px; }
.topbar-sep {
  width: 1px;
  height: 16px;
  margin-right: 14px;
  background: rgba(0, 0, 0, 0.08);
}
.topbar-hours { margin-left: 4px; }
.topbar-hours + .topbar-hours { margin-left: 18px; }

.topbar-sep,
.topbar-hours { display: none; }

@media (min-width: 768px) {
  .topbar-sep { display: block; }
  .topbar-hours { display: inline-flex; }
}

.topbar-social {
  display: none;
  align-items: center;
  gap: 10px;
}
@media (min-width: 576px) {
  .topbar-social { display: flex; }
}

/* The original's link is a 38px white disc — invisible on this white band —
   around a 21px #777 glyph. The client asked for Facebook's own logo instead
   (2026-09-29): 24px, about the glyph's size, inside the same 38px target. */
.topbar-social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  transition: opacity var(--transition);
}
.topbar-social-link svg { width: 24px; height: 24px; }
.topbar-social-link:hover { opacity: 0.85; }

/* ---- components/header.css ---- */
/* ---- header & navigation -------------------------------------------------
   The 991px breakpoint is where the horizontal nav becomes a drawer, a
   genuine change of layout. The call block also hides below 1230px, as the
   original's does; the sheet as a whole steps at the original's 576 / 768 /
   992 / 1230.

   (Media queries can't read CSS custom properties, so --bp-nav in tokens.css
   documents the value; the query below must repeat it literally.)

   RE-MEASURED 2026-09-29 for the client review, at 1440 / 1024 / 768 / 390:
   · the bar is 13px + a 94px logo box + 13px, with a 1px rgba(234,234,234,.5)
     rule under it — 121px at 992px and up, 111px below (the logo is 110×84);
   · at 992px and up the logo painted is the square "bleed" version at
     125×125, overhanging the bar's bottom edge by 17px;
   · nav links carry 30px × 14.5px of padding, #444, blue when current;
   · a 23px #ccc hairline after the nav, then — from 1230px only — the
     "CALL US NOW" block (32px glyph, 11.2px/600 #777 label, 16.8px/700 #333
     number) and a 28px #dee2e6 hairline;
   · below 992px the menu button is a 37×34 blue square with white bars.
   -------------------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 1000;
  background: var(--white);
  border-bottom: 1px solid var(--header-border);
  transition: box-shadow 0.25s ease;
}
.site-header.is-stuck { box-shadow: 0 2px 14px rgba(0, 0, 0, 0.1); }

.header-inner {
  display: flex;
  align-items: center;
  padding-block: var(--header-pad-y);
  transition: padding 0.25s ease;
}
.site-header.is-stuck .header-inner { padding-block: 4px; }

.brand { position: relative; display: block; flex: none; }
.brand__logo { width: 110px; height: auto; }
.brand__overlay { display: none; }

@media (min-width: 992px) {
  .brand__logo { width: 123px; }
  .site-header:not(.is-stuck) .brand__logo { visibility: hidden; }
  .site-header:not(.is-stuck) .brand__overlay {
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    width: 125px;
    max-width: none;
    height: 125px;
  }
}

.nav-toggle {
  display: none;
  width: 37px; height: 34px;
  margin-left: auto;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: var(--blue);
  color: var(--white);
  cursor: pointer;
}
.nav-toggle svg { margin: 0 auto; }
.nav-toggle:hover { background: var(--blue-dark); }

/* At desktop the shell has no box — the nav lays out as if it were not there. */
.nav-shell { display: contents; }

.main-nav { margin-left: auto; }
.nav-list {
  display: flex;
  align-items: center;
  margin: 0;
  padding: 0;
  list-style: none;
}
.nav-list > li { position: relative; }

.nav-list > li > a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 30px 14.5px;
  color: #444;
  /* Measured on the original: 13px / 600 / ls −0.5px / lh 24px / uppercase. */
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 24px;
  letter-spacing: -0.5px;
  text-transform: uppercase;
  white-space: nowrap;
}
.nav-list > li > a:hover,
.nav-list > li.is-active > a { color: var(--blue); }

.has-sub > a::after {
  content: "";
  width: 5px; height: 5px;
  border-right: 1.6px solid currentColor;
  border-bottom: 1.6px solid currentColor;
  transform: rotate(45deg) translateY(-2px);
}

/* The submenu's own control. At desktop the menu opens on hover and on
   focus-within, so the button is display:none — which also keeps it out of the
   tab order rather than leaving a focusable control with nothing to do. */
.nav-caret { display: none; }

.sub-nav {
  position: absolute;
  top: 100%;
  left: -20px;
  min-width: 218px;
  margin: 0;
  padding: 10px 0;
  list-style: none;
  background: var(--white);
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.13);
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: opacity var(--transition), transform var(--transition), visibility var(--transition);
}
.has-sub:hover > .sub-nav,
.has-sub:focus-within > .sub-nav {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.sub-nav a {
  display: block;
  padding: 8px 22px;
  color: var(--ink-alt);
  font-size: var(--fs-body);
  font-weight: 500;
}
.sub-nav a:hover { color: var(--blue); background: var(--grey-soft); }

/* ---- the call block and its hairlines ---------------------------------- */
.header-sep {
  flex: none;
  width: 1px;
  height: 23px;
  margin-left: 14px;
  background: #ccc;
}
.header-sep--end {
  height: 28px;
  margin-left: 20px;
  margin-right: 14px;
  background: #dee2e6;
}

.header-call {
  display: inline-flex;
  flex: none;
  align-items: center;
  margin-left: 14px;
  color: var(--ink-alt);
  text-decoration: none;
}
/* The glyph is 32px in a 38px box, as the original's icon wrapper. */
.header-call__icon { flex: none; box-sizing: content-box; padding-inline: 3px; margin-right: 10px; }
.header-call__text { display: flex; flex-direction: column; }
.header-call__label {
  font-size: 0.7rem;          /* 11.2px */
  font-weight: 600;
  line-height: 1.2;           /* 13.44px */
  text-transform: uppercase;
  color: var(--body);
}
.header-call__number {
  font-size: 1.05rem;         /* 16.8px */
  font-weight: 700;
  line-height: 1.3;           /* 21.84px */
  color: #333;
}
.header-call:hover .header-call__number { color: var(--blue); }

@media (max-width: 1229px) {
  .header-call,
  .header-sep--end { display: none; }
}
/* With the call block hidden, "Shop" is the last thing in the bar and its
   218px submenu, opening 20px left of it, ran 61px past a 1024px window
   (hidden, but still page width). Between 992px and 1229px it opens
   right-aligned instead. */
@media (min-width: 992px) and (max-width: 1229px) {
  .nav-list > li:last-child > .sub-nav { left: auto; right: 0; }
}

.nav-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1100;
  background: rgba(0, 0, 0, 0.45);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, visibility 0.3s;
}

/* ---- drawer ------------------------------------------------------------ */
@media (max-width: 991px) {
  .nav-toggle { display: inline-flex; align-items: center; justify-content: center; order: 3; }
  .header-sep { display: none; }

  /* Clips the closed drawer. Without it the translated panel sits off the
     right edge as real, scrollable page width — measured at 149px of
     horizontal overflow on all 45 pages at 360px before this was added.
     pointer-events:none so the shell never intercepts taps; the drawer itself
     turns them back on. */
  .nav-shell {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 1200;
    overflow: hidden;
    pointer-events: none;
  }

  /* ABSOLUTE, not fixed. A position:fixed element is laid out against the
     viewport, so an ancestor's `overflow: hidden` does not clip it — the first
     attempt at this fix kept the full 149px of overflow for exactly that
     reason. Positioned absolutely inside the fixed shell, the closed drawer is
     clipped properly. */
  .main-nav {
    position: absolute;
    inset: 0 0 0 auto;
    width: min(320px, 86vw);
    z-index: 1200;
    pointer-events: auto;
    padding: 84px 26px 40px;
    background: var(--white);
    box-shadow: -8px 0 40px rgba(0, 0, 0, 0.2);
    transform: translateX(100%);
    transition: transform 0.3s ease;
    overflow-y: auto;
  }
  .main-nav.is-open { transform: none; }

  /* `.site-header` is sticky with z-index 1000, which opens a stacking
     context — so the drawer's z-index counts only against its siblings inside
     the header, while `.nav-backdrop` (z-index 1100) is a body-level sibling
     of the header itself. Left alone, the backdrop paints OVER the open menu
     and every real tap closes it instead of following the link. Lifting the
     whole header above the backdrop while the drawer is open is the fix. */
  .nav-is-open .site-header { z-index: 1200; }

  .nav-list { flex-direction: column; align-items: stretch; gap: 0; }

  /* Label and caret share a row; the submenu takes the full width below them.
     The label keeps its own href — tapping "Shop" goes to /shop/, tapping the
     caret opens the submenu, which is how the original behaves. */
  .nav-list > li {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    border-bottom: 1px solid var(--line);
  }
  .nav-list > li > a { flex: 1 1 auto; padding: 14px 0; color: var(--ink-alt); }
  .has-sub > a::after { display: none; }   /* the caret button draws it now */

  .nav-caret {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 44px; height: 44px;             /* WCAG 2.2 target size */
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--ink-alt);
    cursor: pointer;
  }
  .nav-caret::after {
    content: "";
    width: 7px; height: 7px;
    border-right: 1.8px solid currentColor;
    border-bottom: 1.8px solid currentColor;
    transform: rotate(45deg) translateY(-2px);
    transition: transform 0.2s ease;
  }
  .has-sub.is-open > .nav-caret::after { transform: rotate(-135deg) translateY(-2px); }

  .sub-nav { flex-basis: 100%; }

  .sub-nav {
    position: static;
    opacity: 1;
    visibility: visible;
    transform: none;
    box-shadow: none;
    padding: 0 0 10px;
    display: none;
  }
  .has-sub.is-open > .sub-nav { display: block; }
  .sub-nav a { padding: 9px 14px; }

  .nav-backdrop.is-open { opacity: 1; visibility: visible; }
}

/* ---- components/page-banner.css ---- */
/* ---- inner-page banner + breadcrumb --------------------------------------
   RE-MEASURED on the live site at 1440px: the band is 165px tall on a page with
   a title and 151px without one, #f7f7f7, with the title on the LEFT at the
   container edge and the breadcrumb on the RIGHT of the same row — 62.5px of
   space above and below that row in both cases.

   This was previously a 239px centred stack, built from the 36px h1 that
   `--fs-h1` used to carry. Both numbers came from the theme's variables rather
   than from the page.
   -------------------------------------------------------------------------- */

.page-banner {
  position: relative;
  padding: 62.5px 0;
  background: var(--grey-band);
}

/* One row: title left, breadcrumb right. Below 992px they stack, title first,
   both left-aligned, with no gap between them — as the original does. */
.page-banner__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0 var(--gap);
}

.page-banner h1 {
  margin: 0;
  font-size: var(--fs-h1);
  font-weight: 700;
  letter-spacing: var(--ls-h1);
  line-height: var(--lh-h1);
  color: var(--ink);
}

/* With no title the row holds only the breadcrumb, which then sits right —
   matching /about/ and /contact/ on the original, where the theme's
   `hide-title` class suppresses the heading but keeps the band. */
/* RE-MEASURED 2026-09-29 (client review): 12px, UPPERCASE, #777, the links in
   brand blue, the steps divided by a small chevron — not "/" in sentence case.
   Below 992px the original stacks the title over the breadcrumb, both left. */
.breadcrumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  margin: 0 0 0 auto;
  padding: 0;
  list-style: none;
  font-size: var(--fs-small);
  line-height: 26px;
  text-transform: uppercase;
  color: var(--body);
}
.breadcrumb a {
  display: inline-flex;
  align-items: center;
  min-height: 28px;   /* WCAG 2.2 target size */
  color: var(--blue);
}
.breadcrumb a:hover { color: var(--blue-dark); }
.breadcrumb li + li::before {
  content: "";
  display: inline-block;
  width: 5px;
  height: 5px;
  margin: 0 12px 1px 11px;
  border-top: 1px solid currentColor;
  border-right: 1px solid currentColor;
  transform: rotate(45deg);
  color: var(--body);
}

@media (max-width: 991px) {
  .page-banner__row { flex-direction: column; align-items: flex-start; }
  .breadcrumb { margin-left: 0; }
}

/* ---- components/hero.css ---- */
/* ---- hero ----------------------------------------------------------------
   RE-MEASURED 2026-09-29 at 1440 / 1024 / 768 / 390, from the original's own
   markup and CSS. The rebuild had a white box over a full-width photo; the
   original is this:
   · the aerial photo behind the whole band, with a 30s Ken Burns zoom-out
     from the right (scale 1.2 → 1);
   · a white field covering the left 19% of the container and everything to
     its left (the original's .container::after, right: 81%);
   · a white rounded diamond, 640 × 570, its top 148px above the copy and its
     left edge 15px outside the copy's column, whose right-hand corner is the
     point of the chevron; a thin blue line runs along its right edge and
     draws itself in over 5s;
   · the band is 524px tall: 48px margin + 48px padding each side of the copy;
   · below 576px there is no photo and no diamond — the copy sits on white,
     44.57px from the header.
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  overflow: hidden;
  background: var(--white);
}

.hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.hero__media picture { display: block; height: 100%; }
.hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center center;
  transform-origin: right center;
  animation: hero-kenburns 30s linear both;
}
@keyframes hero-kenburns {
  from { transform: scale(1.2); }
  to { transform: scale(1); }
}
@media (max-width: 575px) {
  .hero__media { display: none; }
}

.hero__row { position: relative; margin: 44.57px 0; }
@media (min-width: 576px) {
  .hero__row { margin: 48px 0; padding: 48px 0; }
}

/* flow-root, so the copy's 48px bottom margin stays inside this box: the
   white field below is sized from it, and with the margin collapsed out the
   field stopped 24px short of the band's bottom and let the photo show. */
.hero__inner { position: relative; display: flow-root; }

.hero__shape { display: none; }
@media (min-width: 576px) {
  .hero__inner::after {
    content: "";
    position: absolute;
    top: 50%;
    right: 81%;
    z-index: 0;
    width: 100vw;
    height: calc(100% + 240px);
    background: var(--white);
    transform: translateY(-50%);
  }
  .hero__shape {
    display: block;
    position: absolute;
    top: -148px;
    left: 15px;
    z-index: 0;
    width: 640px;
    height: auto;
    color: var(--blue);
  }
}
@media (min-width: 992px) {
  .hero__shape { left: 0; }
}

.hero__line {
  stroke-dasharray: 2500;
  stroke-dashoffset: 1600;
  animation: hero-line 5s 0.3s ease both;
}
@keyframes hero-line {
  from { stroke-dasharray: 1600; stroke-dashoffset: 1600; }
  to { stroke-dasharray: 2500; stroke-dashoffset: 1600; }
}

/* The copy column: 8/12 of the row from 768px, 6/12 from 992px, 5/12 from
   1230px — 462px / 450px / 470px of text — and full width below. */
.hero__copy {
  position: relative;
  z-index: 1;
  margin-bottom: 48px;
}
@media (max-width: 575px) {
  .hero__copy { margin-bottom: 44.57px; }
}
@media (min-width: 768px) {
  .hero__copy { width: calc((100% + 30px) * 8 / 12 - 30px); }
}
@media (min-width: 992px) {
  .hero__copy { width: calc((100% + 30px) * 6 / 12 - 30px); }
}
@media (min-width: 1230px) {
  .hero__copy { width: calc((100% + 30px) * 5 / 12 - 30px); }
}

/* The hero heading is its own size on the original (32.2px on a 44px line),
   larger and looser than a section h2 (30.8px/30.8px): --fs-hero, never the
   h2 token. The 44px line is literal because it stays 44px when the size
   drops to 29.9px below 576px. */
.hero__title {
  margin: 0;
  padding-bottom: 8px;
  margin-bottom: 24px;
  font-size: var(--fs-hero);
  font-weight: var(--fw-h2);
  line-height: 44px;
  letter-spacing: var(--ls-hero);
  color: var(--ink-alt);
}

/* Measured: 18.9px / 700 / −0.945px / lh 1.7 / #969696, 4px above the title. */
.hero .eyebrow {
  margin: 0 0 4px;
  color: #969696;
}
/* Porto scales both by 0.9286 below 576px: 17.55px on a 29.83px line, and
   29.9px. */
@media (max-width: 575px) {
  .hero .eyebrow { font-size: 1.097rem; line-height: 29.83px; letter-spacing: -0.945px; }
  .hero__title { font-size: 1.869rem; letter-spacing: -1.61px; }
}

/* ---- components/sections.css ---- */
/* ---- page section furniture ---------------------------------------------
   The repeating blocks the original built out of WPBakery rows: alternating
   grey bands, the copy/photo split, the two-column CTA, the animated rule,
   posters and the sale list.
   -------------------------------------------------------------------------- */

/* Measured: alternating bands are #f7f7f7. */
.section--band { background: var(--grey-band); }

.stack-center { text-align: center; }
.stack-center > * { margin-left: auto; margin-right: auto; }
.stack-center p { max-width: 70ch; }

/* ---- separator under a section heading -----------------------------------
   RE-MEASURED on the live site: every bar is 4px tall, #1c5fa8, and exactly as
   wide as the column it sits in — 570px under the left-aligned "Over Thirty
   Years" heading, 1170px under the full-width centred ones, 770px under "New
   Inventory" in its narrower column. None of them is animated.

   This previously carried a fixed 60px width and a 1s grow animation, neither
   of which is on the original. The animation could never run in any case: it
   was gated on `.is-visible`, which only the scroll-reveal script applied, and
   no page ever carried a `.reveal` element for it to observe. */
.rule {
  width: 100%;
  height: var(--rule-h);
  /* 16px under the heading's own 16px margin collapses to 16px above; 16px
     below — the original's separator is my-3 under a heading with mb-0. */
  margin: 16px 0;
  border: 0;
  background: var(--blue);
}

.rule--center { margin-inline: auto; }

/* The "New Inventory" heading block sits in a 770px centred column on the
   original, which is why its rule measures 770px and not the container's 1170. */
.col-narrow {
  max-width: var(--col-narrow);
  margin-inline: auto;
}

/* ---- copy beside a photo -------------------------------------------------
   Home and About. Two halves from 992px; below that the copy sits over the
   photo, 48px apart (72px from 576px — the original's mb-5 plus pb-sm-4).
   Paragraphs are 24px apart, as the original's mb-4. */
.media-split {
  display: grid;
  row-gap: 48px;
  column-gap: var(--gap);
  align-items: center;
}
@media (min-width: 576px) {
  .media-split { row-gap: 72px; }
}
@media (min-width: 992px) {
  .media-split { grid-template-columns: 1fr 1fr; }
}
.media-split__copy p { margin: 0 0 24px; }

.media-split__media img {
  width: 100%;
  height: auto;
}

/* ---- the original's row spacing -------------------------------------------
   The original spaces its rows with Porto's margin utilities, not one section
   padding, and the rebuild's even 50px put the About page's rows 18–90px from
   where they are (measured 2026-09-29). These reproduce its rows:
   · --intro: the copy/photo row, 72px under the banner (mt-5 pt-4), 30px
     before the next;
   · --flush: the service-shop copy, straight after it, 48px before the cards;
   · --cards: the three service cards, 24px above, 56px below (pb-2 mb-5). */
.section.section--intro { padding: 72px 0 30px; }
.section.section--flush { padding: 0 0 48px; }
.section.section--cards { padding: 24px 0 56px; }
@media (max-width: 575px) {
  .section.section--intro { padding-top: 66.86px; }
}
/* The homepage's rows, measured the same way:
   · --poster: the hours poster, 32px above (an empty-space block) and
     the image's own 35px below;
   · --sale: the sale graphic and list, 32px above and below;
   · --cta: the "Full-service marina" band, 50px each side;
   · --split: "Over Thirty Years", 48px each side (my-5);
   · --inventory: "New Inventory", 110.77px each side, 144px from the
     subhead to the cards. */
.section.section--poster { padding: 32px 0 35px; }
.section.section--sale { padding: 32px 0; }
.section.section--cta { padding: 50px 0; }
.section.section--split { padding: 48px 0; }
.section.section--inventory { padding: 110.77px 0; }
.section--inventory .boat-grid { margin-top: 144px; }

/* ---- the marina photo with its three RR marks ----------------------------
   The photo column is not the full half on the original. MEASURED 2026-09-29:
   from 992px the photo is inset 33px each side of its half (504px at 1440);
   from 768px it is 75% of the row less 63px, centred, then 16.5px left (the
   column's padding is 15px left, 48px right); below 768px the same at
   83.33%. The marks are the original's .auto-1/2/3, each translated back by
   half its own size so the percentages place its centre. */
.photo-marks { position: relative; }
@media (min-width: 992px) {
  .photo-marks { margin-inline: 33px; }
}
@media (min-width: 768px) and (max-width: 991px) {
  .photo-marks { width: calc((100% + 30px) * 0.75 - 63px); margin-inline: auto; left: -16.5px; }
}
@media (max-width: 767px) {
  .photo-marks { width: calc((100% + 30px) * 0.8333 - 63px); margin-inline: auto; left: -16.5px; }
}
.photo-marks__photo img { width: 100%; height: auto; }

.photo-marks__mark {
  position: absolute;
  display: block;
  transform: translate(-50%, -50%);
  pointer-events: none;
}
.photo-marks__mark > span { display: block; }
/* 96px, narrowed only by the room beside it. Two classes deep so the
   column's "photo fills the width" rule above cannot stretch it. */
.photo-marks .photo-marks__mark img { display: block; width: 96px; max-width: 100%; height: auto; }
.photo-marks__mark--1 { top: 25%; left: 7%; }
.photo-marks__mark--2 { top: 32%; left: 85%; }
.photo-marks__mark--3 { top: 90%; left: 19%; }
@media (max-width: 991px) {
  .photo-marks__mark--1 { top: 17%; left: 12%; }
  .photo-marks__mark--3 { top: 81%; }
}

/* ---- two-column CTA band ------------------------------------------------- */
.split-cta {
  display: grid;
  gap: var(--gap);
  align-items: center;
}

@media (min-width: 992px) {
  .split-cta { grid-template-columns: 7fr 5fr; }
  .split-cta__copy { text-align: right; }
  .split-cta__action { padding-left: var(--gap); }
}
/* Stacked, the homepage's band centres both, as the original does. */
@media (max-width: 991px) {
  .split-cta:not(.split-cta--wide) { text-align: center; }
  .split-cta:not(.split-cta--wide) .split-cta__action { justify-content: center; }
}

/* The /about/ instance is not the homepage's. MEASURED on the original: copy
   LEFT-aligned. From 992px the copy is full width and the button a full-width
   bar under it, at every width (the client review's "Our Services does not
   fill the page like the original"); below 992px the button is an ordinary one
   under the copy. From 1230px the original instead put 930px of copy beside a
   210px column holding the button; this site stopped doing that on 2026-09-30
   (client request: the bar, as at 992px–1229px, at every larger width). */
.split-cta--wide { align-items: start; row-gap: 0; }
.split-cta--wide .split-cta__copy { text-align: left; }
.split-cta--wide .split-cta__copy p { margin: 0 0 24px; }
@media (min-width: 992px) {
  .split-cta--wide { grid-template-columns: 1fr; }
  .split-cta--wide .split-cta__action { padding-left: 0; }
}

.split-cta__copy > :first-child { margin-top: 0; }
.split-cta__copy > :last-child { margin-bottom: 0; }

.split-cta__action {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gap);
}

.section--dark .split-cta__copy h2,
.section--dark .split-cta__copy p { color: var(--white); }

/* The homepage's "Full-service marina…" band. MEASURED: the heading is
   28px / 700 / −1.4px in brand blue on a 28px line, the line under it
   16.8px / 700 grey. */
.split-cta__title {
  margin: 0 0 0.5rem;
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -1.4px;
  color: var(--blue);
}
.split-cta__sub {
  font-size: 1.05rem;
  font-weight: 700;
  line-height: 26px;
}

/* ---- posters -------------------------------------------------------------
   The hours poster, centred, as the original. Since 2026-10-31 it is the
   client's second fall-hours poster, landscape (1600x1200), shown up to
   800px wide so its script text stays readable; the portrait posters
   before it were shown up to 600px.
   The original's second one, the sale graphic, was removed at the client's
   request (2026-09-29). */
.poster {
  display: block;
  width: 100%;
  max-width: 800px;
  height: auto;
  margin-inline: auto;
}

/* ---- homepage sale list --------------------------------------------------
   RE-MEASURED 2026-09-29: "Included in this sale" and "Call dealer for
   pricing." are the original's two h1s, 36px / 400 on a 44px line — not a
   section h2. The list is 18px on a 26px line.
   The original's 35px above the title was its gap from the sale graphic.
   With the graphic removed at the client's request (2026-09-29) it would
   leave 102px under the hours poster; without it the gap is 67px,
   what the poster had above the graphic. */
.sale-title {
  margin: 0 0 64px;
  font-size: 2.25rem;
  font-weight: 400;
  line-height: 44px;
  letter-spacing: normal;
  color: var(--ink);
}
.sale-list {
  margin: 0 auto;
  padding: 0;
  list-style: none;
  font-size: 1.125rem;
  line-height: 26px;
  color: #000;
}
.sale-list li { padding: 0.5px 0; }
/* The original set the sold lines in bold red. */
.sale-list .is-sold {
  font-weight: 700;
  color: #ff0000;
}

.sale-callout {
  margin: 35px 0 32px;
  font-size: 2.25rem;
  font-weight: 400;
  line-height: 44px;
  color: var(--ink);
}
.sale-financing {
  margin: 0;
  font-size: var(--fs-h2);
  font-weight: 700;
  line-height: var(--lh-h2);
  letter-spacing: var(--ls-h2);
  color: var(--ink-alt);
}
/* Below 576px, the original's sizes: the two h1s 33.43px on 40.6px (so "Included
   in this sale" stays on one line), the list on 24px, and the h2 28.6px on 40px. */
@media (max-width: 575px) {
  .sale-title,
  .sale-callout { font-size: 2.089rem; line-height: 40.6px; }
  .sale-title { margin-bottom: 59.4px; }
  .sale-list { line-height: 24px; }
  .sale-financing { font-size: 1.7875rem; line-height: 40px; letter-spacing: -1.54px; }
  .section.section--inventory { padding: 102.86px 0; }
  .section--inventory .boat-grid { margin-top: 133.7px; }
}

/* ---- components/card.css ---- */
/* ---- service cards and tiles ---------------------------------------------
   Two shapes: the About page's icon-in-a-diamond cards, and the Services
   page's image tiles.
   -------------------------------------------------------------------------- */

/* RE-MEASURED 2026-09-29 (client review: "the Our Services icons are not the
   original's"). Three columns from 992px, each with 33px of inner space either
   side of its 30px gap — 304px of text at 1440, 224px at 1024 — and one per
   row, 48px apart, below. The icon is the original's own drawing, 95×95, in
   front of a 95×95 blue-bordered square turned 45° (so the diamond is
   134px corner to corner); 30px under it, the title at 18.9px / 700 /
   −0.945px, then the text. */
.service-cards {
  display: grid;
  row-gap: 48px;
  margin: 0;
  padding: 0;
  list-style: none;
}
@media (min-width: 992px) {
  .service-cards { grid-template-columns: repeat(3, 1fr); column-gap: 30px; }
  .service-card { padding-inline: 33px; }
}

.service-card { text-align: center; }

.service-card__icon {
  position: relative;
  display: block;
  width: 95px;
  height: 95px;
  margin: 0 auto 30px;
  color: #152e52;
}
.service-card__icon::before {
  content: "";
  position: absolute;
  inset: 0;
  border: 2px solid var(--blue);
  border-radius: 7px;
  transform: rotate(45deg);
  transition: background-color 0.2s ease;
}
.service-card__icon svg { position: relative; display: block; transition: color 0.2s ease; }

.service-card:hover .service-card__icon::before { background: var(--blue); }
.service-card:hover .service-card__icon { color: var(--white); }

.service-card h3 {
  margin: 8px 0;
  font-size: 1.18125rem;     /* 18.9px */
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: -0.945px;
}
.service-card h3 a { color: var(--ink-alt); text-decoration: none; }
.service-card:hover h3 a { color: var(--blue); }
.service-card p { margin: 0 0 20px; line-height: 26px; color: var(--body); }

/* ---- services page tiles ------------------------------------------------- */
.service-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(var(--col-min-3), 100%), 1fr));
  gap: var(--gap);
  margin: var(--section-y-tight) 0 0;
  padding: 0;
  list-style: none;
}

/* The Services page. MEASURED 2026-09-29: the copy starts 68px under the
   banner and its first line is 16.8px / 600, not the light lead; paragraphs
   are 24px apart with 4px of padding under each; 86px under the tiles. */
.section.section--services { padding: 68px 0 86px; }
.section--services .container > p { margin: 0 0 24px; padding-bottom: 4px; }
.services-lead { font-size: 1.05rem; font-weight: 600; line-height: 26px; }

.service-tile a {
  display: block;
  text-decoration: none;
  color: inherit;
}

.service-tile img {
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  background: var(--grey-soft);
  transition: transform var(--transition);
}

.service-tile a:hover img { transform: scale(1.04); }

/* The tile image zooms inside a fixed frame rather than pushing the layout. */
.service-tile a { overflow: hidden; }

/* MEASURED 2026-09-29: the original's tile titles are 21px / 700 / −1.05px on
   a 24px line (the rebuild had 18.9px / 600). */
.service-tile__title {
  margin: 0.85rem 0 0;
  text-align: center;
  font-size: 1.3125rem;
  font-weight: 700;
  line-height: 24px;
  letter-spacing: -1.05px;
  color: var(--ink-alt);
}
.service-tile a:hover .service-tile__title { color: var(--blue); }

/* ---- components/testimonial.css ---- */
/* ---- testimonials --------------------------------------------------------
   The original runs these in an Owl carousel: three cards from 992px, two
   from 768px, one below, 15px apart, an arrow either side. RE-MEASURED
   2026-09-29 for the client review — the rebuild had them as a left-aligned
   grid in grey body type, with the fourth card alone on a second row.

   Rebuilt as a scroll-snap row. With no script it is still a row that scrolls
   by touch, trackpad or keyboard (the track is focusable); 35-testimonials.js adds
   the two arrows, which scroll by one card. From 1230px the arrows sit 50px
   outside the row (from 1300px here, where they fit), below that 6px / 10px
   inside.

   Card: white, 1px rgba(0,0,0,.06) border, 7px corners, 32px padding. Quote
   14px / 300 / 26px, #212529, centred, with a 20px blue quotation glyph at
   its top left; name 16px / 800, #111.
   -------------------------------------------------------------------------- */

/* The band's spacing, measured: 98px above the heading (the row's 50px plus
   the column's 48px margin), 114px under the cards. */
.section.testimonials-section { padding: 98px 0 114px; }
@media (max-width: 575px) {
  .section.testimonials-section { padding: 94.57px 0 109.43px; }
}
.testimonials-section .stack-center > p { max-width: none; }
.testimonials-lead {
  margin: 0 0 4px;
  padding-top: 8px;
  font-size: 0.9625rem;      /* 15.4px */
  font-weight: 700;
  line-height: 26px;
}
.testimonials-sub {
  margin: 0 0 24px;
  padding-bottom: 16px;
  font-size: 0.9625rem;
  font-weight: 300;
  line-height: 26px;
}

.carousel { position: relative; text-align: left; }

/* The soft grey glow behind the middle cards, from 1230px (the original's
   custom-carousel-box-shadow-1). */
@media (min-width: 1230px) {
  .carousel::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 65%;
    height: 0;
    box-shadow: 0 0 40px 120px rgba(0, 0, 0, 0.07);
    transform: translate(-50%, -50%);
    pointer-events: none;
  }
}

.carousel__track {
  position: relative;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 100%;
  column-gap: 15px;
  align-items: start;
  margin: 0;
  padding: 0;
  list-style: none;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.carousel__track::-webkit-scrollbar { display: none; }
@media (min-width: 768px) {
  .carousel__track { grid-auto-columns: calc((100% - 15px) / 2); }
}
@media (min-width: 992px) {
  .carousel__track { grid-auto-columns: calc((100% - 30px) / 3); }
}
@media (prefers-reduced-motion: no-preference) {
  .carousel__track { scroll-behavior: smooth; }
}

.testimonial {
  scroll-snap-align: start;
  padding: 32px;
  background: var(--white);
  border: 1px solid rgba(0, 0, 0, 0.06);
  border-radius: 7px;
  text-align: center;
}
@media (max-width: 575px) {
  .testimonial { padding: 29.7px; }
}

.testimonial blockquote {
  position: relative;
  margin: 0;
  padding: 5px 20px;
}
.testimonial blockquote::before {
  content: "";
  position: absolute;
  top: 3px;
  left: 0;
  width: 20px;
  height: 16px;
  /* This site's own drawing of an opening quotation mark, in the brand blue. */
  background: no-repeat center / contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 32'%3E%3Cpath fill='%231c5fa8' d='M0 32V19C0 9 5 2.5 15 0l2 4.2C12 6.2 9.4 9.3 9 14h8v18zM22 32V19c0-10 5-16.5 15-19l2 4.2c-5 2-7.6 5.1-8 9.8h8v18z'/%3E%3C/svg%3E");
}
@media (max-width: 1229px) {
  .testimonial blockquote::before { left: -10px; }
}

.testimonial blockquote p {
  margin: 0;
  font-size: 0.875rem;
  font-weight: 300;
  line-height: 26px;
  color: var(--ink-alt);
}

.testimonial__author {
  margin: 14px 0 2px;
  font-size: 1rem;
  font-weight: 800;
  line-height: 19.2px;
  color: #111;
}
@media (max-width: 575px) {
  .testimonial__author { font-size: 0.9286rem; line-height: 17.83px; }
}

/* ---- arrows (added by 35-testimonials.js) ------------------------------------ */
.carousel__btn {
  position: absolute;
  top: 50%;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 44px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ink-alt);
  cursor: pointer;
  transform: translateY(-50%);
}
.carousel__btn:hover { color: var(--blue); }
.carousel__btn[aria-disabled="true"] { opacity: 0.45; cursor: default; }
.carousel__btn--prev { left: 6px; }
.carousel__btn--next { right: 10px; }
/* Outside the row, as the original, only from 1300px: from 1230px (where the
   original moves them out) the container's 15px gutter leaves them off the
   screen until about 1264px — about 1280 with a classic scrollbar. */
@media (min-width: 1300px) {
  .carousel__btn--prev { left: -55px; }
  .carousel__btn--next { right: -53px; }
}

/* ---- components/cta-band.css ---- */
/* ---- "LOOKING FOR HONEST AND RELIABLE SERVICES?" band ----------------------
   The original's full-width blue band above the footer on the home, About,
   Services, Shop and boat pages — missing from all but the homepage in the
   rebuild, and there as a dark band in different type (client review,
   2026-09-29). Measured at 1440 / 1024 / 768 / 390:
   · #1c5fa8, 73.85px above and below (68.57px below 576px);
   · the copy in 7/12 of the row from 1230px and half from 992px, the call
     block and button spread across the rest; below 992px everything stacks
     and centres, the button under the call block;
   · kicker 15.4px / 500 / uppercase, heading 32.2px / 700 / −1.61px, both on
     a line-height of 1;
   · the call block is a 28.8px glyph in a 43px box, "CALL US NOW" at
     11.2px / 600 and the number at 18.9px / 700;
   · the button is the light outline button at 12.8px / 700.
   -------------------------------------------------------------------------- */

.cta-band {
  padding: 73.85px 0;
  background: var(--blue);
  color: var(--white);
}
@media (max-width: 575px) {
  .cta-band { padding: 68.57px 0; }
}

.cta-band__row {
  display: grid;
  row-gap: 24px;
  align-items: center;
  text-align: center;
}
@media (min-width: 992px) {
  .cta-band__row { grid-template-columns: 1fr 1fr; column-gap: 30px; text-align: left; }
}
@media (min-width: 1230px) {
  .cta-band__row { grid-template-columns: 7fr 5fr; }
}

.cta-band__kicker {
  margin: 0 0 8px;
  font-size: 0.9625rem;      /* 15.4px */
  font-weight: 500;
  line-height: 1;
  text-transform: uppercase;
  color: var(--white);
}
.cta-band__title {
  margin: 0 0 4px;
  font-size: 2.0125rem;      /* 32.2px */
  font-weight: 700;
  line-height: 1;
  letter-spacing: -1.61px;
  color: var(--white);
}

.cta-band__actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}
@media (min-width: 992px) {
  .cta-band__actions { flex-direction: row; justify-content: space-between; }
}

.cta-band__call {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--white);
  text-align: left;
  text-decoration: none;
}
.cta-band__call svg { flex: none; width: 43px; height: 43px; padding: 6px; }
.cta-band__call > span { display: flex; flex-direction: column; }
.cta-band__label {
  margin-bottom: 4px;
  font-size: 0.7rem;         /* 11.2px */
  font-weight: 600;
  line-height: 13.44px;
  text-transform: uppercase;
}
.cta-band__number {
  font-size: 1.18125rem;     /* 18.9px */
  font-weight: 700;
  line-height: 1.2;
}
.cta-band__call:hover { color: var(--white); }
.cta-band__call:hover .cta-band__number,
.cta-band__call:focus-visible .cta-band__number { text-decoration: underline; }
/* The site's focus ring is brand blue, which vanishes on this band. */
.cta-band a:focus-visible { outline-color: var(--white); }

/* ---- components/inventory.css ---- */
/* ---- inventory: cards, grid, pagination, single boat ---------------------
   RE-MEASURED 2026-09-29 on the live archives (client review: "the sold
   information in Shop looks very different on the original"). The cards are
   the original's porto-tb-item: two to a row below 768px, three from 768px,
   four from 1230px, 30px apart; the photo 270×180 at 1440, the 3:2 of the
   1600×1067 boat photos (the original gave the portrait used-stock photos
   tall cards; the photo box below no longer does); the categories over the
   title; the title on one line; a white
   SOLD box across the middle of a sold boat's photo; 64px of space under the
   price before the next row's 30px gap. The rebuild used to crop every photo
   square, print "Sold / unavailable" under the price and a "-%" ribbon over
   the photo — none of which the original's cards do.
   -------------------------------------------------------------------------- */

.boat-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: var(--gap);
  margin: var(--gap) 0 0;
  padding: 0;
  list-style: none;
  text-align: left;
}
@media (min-width: 768px) {
  .boat-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 1230px) {
  .boat-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.boat-card {
  display: flex;
  flex-direction: column;
  min-width: 0;
  margin-bottom: 30px;
  padding-bottom: 64px;
}

/* The photo box. Every card's photo sits in the same 3:2 box — the shape of
   the 1600×1067 new-stock photos, so those cards are unchanged — and is cropped
   to fill it from the centre (client request 2026-09-30). The used and
   consignment photos are 432×960, 960×432 and 240×320, and used to make cards
   of three different heights in one row. The whole photo is on the boat's own
   page: its gallery shows each photo at its own shape (.boat-gallery__main).
   The box takes its height from `aspect-ratio`; the photos are laid over it. */
.boat-card__media { position: relative; }
.boat-card__media > a {
  position: relative;
  display: block;
  aspect-ratio: 1600 / 1067;
  overflow: hidden;
}
.boat-card__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The hover image is stacked over the first and cross-fades, which is how the
   original swaps -01 for -02 on hover. */
.boat-card__img--hover {
  opacity: 0;
  transition: opacity var(--transition);
}
@media (hover: hover) {
  .boat-card:hover .boat-card__img--hover { opacity: 1; }
}

/* Measured: 140×42, white, #222529, 14px / 600 / uppercase, dead centre of
   the photo (130×39 and 13px below 576px). */
.boat-card__sold {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 140px;
  height: 42px;
  margin: auto;
  background: var(--white);
  color: var(--ink);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 42px;
  text-align: center;
  text-transform: uppercase;
  pointer-events: none;
}

.boat-card__cats {
  margin: 16px 0 0;
  overflow: hidden;
  font-size: 0.625rem;       /* 10px */
  line-height: 17px;
  text-overflow: ellipsis;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--body);
}
.boat-card__cats a { color: var(--body); }
.boat-card__cats a:hover { color: var(--blue); }

.boat-card__title {
  margin: 0 0 7px;
  overflow: hidden;
  font-size: 0.9375rem;      /* 15px */
  font-weight: 400;
  line-height: 1.35;         /* 20.25px */
  letter-spacing: -0.01em;   /* -0.15px */
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--ink-alt);
}
.boat-card__title a { color: inherit; }
.boat-card__title a:hover { color: var(--blue); }

.boat-card .price { margin: 0; line-height: 18px; }

@media (max-width: 575px) {
  .boat-card__sold { width: 130px; height: 39px; font-size: 0.8125rem; line-height: 39px; }
  .boat-card__cats { font-size: 0.58rem; line-height: 15.8px; }
  .boat-card__title { font-size: 0.87rem; }
  .boat-card .price { font-size: 1.045rem; }   /* 16.7px: both prices fit a 160px card */
}

/* ---- price ---------------------------------------------------------------
   Measured: 18px / 600 / #444, the struck list price 14.4px / 400 / #a7a7a7
   beside it whenever the two differ. */
.price {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--price);
}
.price del {
  margin-right: 0.4em;
  font-size: 0.8em;
  font-weight: 400;
  color: #a7a7a7;
  text-decoration: line-through;
}
.price ins { text-decoration: none; color: var(--price); }

.empty { margin: var(--gap) 0; color: var(--body); }

/* ---- pagination ----------------------------------------------------------
   The original's: 33px squares with a #e7e7e7 border, 15px / 700 / #777, the
   current page outlined in blue, chevron squares for previous and next, on
   the right under a hairline across the grid. */
.pagination {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 5px;
  margin-top: 0;
  padding-top: 25px;
  border-top: 1px solid #e7e7e7;
}
.pagination a,
.pagination span.page-current {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 33px;
  height: 33px;
  padding: 0 7.5px;
  border: 1px solid #e7e7e7;
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
  color: var(--body);
}
.pagination a:hover { border-color: var(--blue); color: var(--blue); }
.pagination .page-current { border-color: var(--blue); }
.pagination .page-prev::before,
.pagination .page-next::before {
  content: "";
  width: 7px;
  height: 7px;
  border-top: 1.6px solid currentColor;
  border-right: 1.6px solid currentColor;
}
.pagination .page-next::before { transform: translateX(-2px) rotate(45deg); }
.pagination .page-prev::before { transform: translateX(2px) rotate(-135deg); }

/* The original ends every archive with a "Show: 8" / pagination row; this has
   no "Show" control (nothing on a static site could act on it), so the space
   it took is kept instead — 53px, measured on /shop/, /shop/page/2/ and
   /product-category/new-inventory/. */
.section.section--archive { padding-bottom: calc(var(--section-y) + 53px); }

/* ---- related products (boat pages) --------------------------------------- */
.boat-related { margin-top: var(--section-y); }
.boat-related__title {
  margin: 0;
  padding-bottom: 14px;
  border-bottom: 2px solid #e7e7e7;
  font-size: 1rem;
  font-weight: 700;
  line-height: 22px;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: var(--ink-alt);
}
.boat-related .boat-grid { margin-top: 35px; }

/* ---- single boat ---------------------------------------------------------
   Gallery left, summary right — the original's col-md-5 / col-md-7 split.
   One breakpoint, because this is a genuine structural change. */
.boat-single__grid {
  display: grid;
  gap: var(--gap);
  align-items: start;
}

@media (min-width: 768px) {
  .boat-single__grid { grid-template-columns: 5fr 7fr; }
}

/* The main photo is shown whole, at its own shape (client request 2026-09-30:
   it was cropped to 3:2). Its box follows the photo — the width and height
   attributes, which the gallery script updates on every swap. A tall portrait
   would be over 1000px high at this column's width, so the height is capped
   and `contain` leaves the soft grey either side of it. The thumbnails below
   stay 3:2 crops, like the cards. */
.boat-gallery__main {
  display: block;
  width: 100%;
  height: auto;
  max-height: 640px;
  object-fit: contain;
  background: var(--grey-soft);
}

.boat-gallery__thumbs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(90px, 25%), 1fr));
  gap: 10px;
  margin: 10px 0 0;
  padding: 0;
  list-style: none;
}

.boat-thumb {
  display: block;
  width: 100%;
  padding: 0;
  border: 2px solid transparent;
  background: none;
  cursor: pointer;
  line-height: 0;
}
.boat-thumb img {
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}
.boat-thumb.is-active { border-color: var(--blue); }
.boat-thumb:hover { border-color: var(--blue-light); }

.boat-summary .price { font-size: 1.5rem; }

.boat-stock {
  margin: 0.25rem 0 1rem;
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--blue);
}
.boat-stock.is-sold { color: var(--sold); }

.boat-short p { margin: 0 0 1em; }

.boat-meta {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 1.25rem 0;
  padding-top: 1rem;
  border-top: 1px solid var(--line-soft);
  font-size: var(--fs-small);
  color: var(--body);
}
/* Category and brand links measured 17px tall — under the WCAG 2.2 minimum of
   24x24. `padding-block` gives the hit area without `display: inline-flex`,
   which would stop a long term like "Consignement Inventory" from wrapping and
   push the page sideways at 360px. */
.boat-meta a {
  color: var(--blue);
  padding-block: 5px;
}
.boat-meta__row { display: block; }

.boat-cta {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 1.25rem;
}

/* ---- detail panels -------------------------------------------------------
   The original used a single-tab strip plus a three-panel accordion. With one
   tab the tab UI carried no information, so the panels are simply stacked. */
.boat-detail {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: var(--gap);
  margin-top: var(--section-y);
}

.boat-panel {
  padding: var(--gap);
  background: var(--grey-panel);
  border: 1px solid var(--line-soft);
}
.boat-panel h2 {
  margin: 0 0 0.75rem;
  font-size: var(--fs-h4);
  line-height: 1.3;
  letter-spacing: normal;
}

.spec-list,
.option-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.spec-list li,
.option-list li {
  padding: 6px 0;
  border-bottom: 1px solid var(--line-soft);
}
.spec-list li:last-child,
.option-list li:last-child { border-bottom: 0; }

/* A line the original prints after the options list rather than inside it. */
.option-note {
  margin: 0.75rem 0 0;
  padding-top: 0.75rem;
  border-top: 1px solid var(--line-soft);
  color: var(--body);
}
.option-list li::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 10px;
  background: var(--blue);
  vertical-align: middle;
}

.boat-panel--value { text-align: center; }
.boat-value-price {
  margin: 0 0 0.5rem;
  font-size: var(--fs-h1);
  font-weight: 700;
  color: var(--ink);
}
.boat-value-note {
  margin: 0;
  font-size: var(--fs-small);
  color: var(--body);
}

/* ---- discount ribbon -----------------------------------------------------
   The original's `div.onsale`. Since 2026-09-29 it appears only on the boat
   pages, beside the price (the rule below), and only while the boat is
   available — the archive cards carry none, as the original's do not. */
.sale-badge {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 1;
  padding: 3px 9px;
  background: var(--sale);
  border-radius: var(--radius-badge);
  color: var(--white);
  font-size: var(--fs-small);
  font-weight: 600;
  line-height: 1.6;
}

/* On the single-boat page the badge sits inline beside the price rather than
   over the gallery, so it reads as part of the pricing. */
.boat-summary .sale-badge {
  position: static;
  display: inline-block;
  margin-left: 10px;
  vertical-align: middle;
}

/* ---- components/service-page.css ---- */
/* ---- service detail pages ------------------------------------------------
   Sidebar left (All Services menu + CTA card), content right — the original's
   col-md-3 / col-md-9 split. One breakpoint: below it the sidebar stacks
   under the copy, so the service content leads on a phone.
   -------------------------------------------------------------------------- */

.service-layout {
  display: grid;
  gap: var(--gap);
  align-items: start;
}

@media (min-width: 992px) {
  .service-layout { grid-template-columns: 3fr 9fr; }
  .service-sidebar { order: -1; }
}

.sidebar-card {
  padding: 2rem 1.5rem;
  margin-bottom: var(--gap);
  background: var(--white);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
}

.sidebar-card__title {
  margin: 0 0 1rem;
  font-size: var(--fs-h4);
  letter-spacing: normal;
  color: var(--ink);
}

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

.sidebar-menu li + li { border-top: 1px solid var(--line-soft); }

.sidebar-menu a {
  display: block;
  padding: 10px 0;
  color: var(--body);
  text-decoration: none;
}
.sidebar-menu a:hover { color: var(--blue); }
.sidebar-menu a[aria-current="page"] {
  color: var(--blue);
  font-weight: 600;
}

.sidebar-card--cta {
  background: var(--blue);
  color: var(--white);
  text-align: center;
}

.sidebar-card--cta h3 {
  margin: 0 0 0.5rem;
  font-size: var(--fs-h3);
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: normal;
  text-transform: uppercase;
  color: var(--white);
}

.sidebar-card__sub {
  margin: 0 0 1.25rem;
  font-size: var(--fs-h4);
  font-weight: 700;
  color: var(--white);
}

.sidebar-card--cta .phone-block { margin-bottom: 1rem; align-items: center; }

.service-main > :first-child { margin-top: 0; }

.service-photo {
  width: 100%;
  max-width: 420px;
  height: auto;
  margin: var(--gap) 0;
}

/* ---- components/contact.css ---- */
/* ---- contact page ---------------------------------------------------------
   The original's Contact page, measured 2026-09-29 at 1440 / 1024 / 390:
   the details in a 370px column and the photo beside it, both vertically
   centred. From 1230px the details start 100px in (offset-xl-1) and the photo
   is 470px wide, 130px after them; from 992px the details start at the edge
   and the photo is 450px, 110px after. Below 992px they stack, 48px apart,
   and the photo fills the width. 24px above, 57px below.
   -------------------------------------------------------------------------- */

.section.contact-page { padding: 24px 0 57px; }

.contact-split {
  display: grid;
  row-gap: 48px;
  align-items: center;
}
@media (min-width: 992px) {
  .contact-split { grid-template-columns: 370px 450px; column-gap: 110px; }
}
@media (min-width: 1230px) {
  .contact-split { grid-template-columns: 370px 470px; column-gap: 130px; padding-left: 100px; }
}

/* The original's image block keeps its 35px bottom margin, which is part of
   what the two columns centre against. */
.contact-split__photo img { width: 100%; height: auto; margin-bottom: 35px; }

/* The first heading of the page, drawn as the original's 23.1px / 700 h2. */
.contact-title {
  margin: 0;
  font-size: 1.44375rem;     /* 23.1px */
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: -0.05em;
  color: var(--ink-alt);
}

.contact-directions {
  margin: 0 0 17px;
  font-size: 0.9625rem;      /* 15.4px */
  font-weight: 700;
  line-height: 26px;
  text-transform: uppercase;
}
.contact-directions a { padding-bottom: 3px; color: var(--blue); }
.contact-directions a:hover { color: var(--blue-dark); }

.contact-list { margin: 0 0 32px; padding: 16px 0 0; list-style: none; }
.contact-list li + li { margin-top: 8px; }
/* WCAG 2.2 target size — the rows are 24px tall on the original. */
.contact-list__link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 24px;
  font-size: 1.05rem;        /* 16.8px */
  font-weight: 700;
  line-height: 24px;
  color: var(--ink-alt);
}
.contact-list__link:hover { color: var(--blue); }
.contact-list svg { flex: none; color: var(--ink-alt); }

.contact-split__info p:last-child { margin-bottom: 10px; }

/* ---- components/form.css ---- */
/* ---- forms ----------------------------------------------------------------
   The Appointment page's form. The Contact page has none since the client
   review of 2026-09-29; its layout is components/contact.css. */

.form-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: 18px;
}

.field { margin-bottom: 18px; }
.field label {
  display: block;
  margin-bottom: 6px;
  color: var(--ink);
  font-size: var(--fs-small);
  font-weight: 600;
}
.field .req { color: var(--blue); }

.field input,
.field textarea,
.field select {
  width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--white);
  font-family: inherit;
  /* 16px minimum: anything smaller makes iOS Safari zoom on focus. */
  font-size: 1rem;
  color: var(--ink);
  transition: border-color var(--transition);
}
.field input:focus,
.field textarea:focus,
.field select:focus {
  border-color: var(--blue);
  outline: none;
}
.field textarea { min-height: 150px; resize: vertical; }

.form-note { font-size: 0.78125rem; color: var(--muted); }

.form-status {
  margin-top: 16px;
  padding: 12px 16px;
  font-size: var(--fs-body);
  display: none;
}
.form-status.is-ok { display: block; background: #e8f5ec; color: #1c6b3a; }
.form-status.is-err { display: block; background: #fdecea; color: #a32218; }

.map-embed {
  width: 100%;
  height: clamp(240px, 30vw, 380px);
  border: 0;
  display: block;
  filter: grayscale(1) contrast(1.05);
  transition: filter 0.3s ease;
}
.map-embed:hover { filter: none; }

/* The honeypot's wrapper. A CLASS and never a style attribute: this template
   ships 'unsafe-inline' in style-src, but several sites built from it have
   since tightened that to a bare `style-src 'self'`, where an inline style is
   dropped by the browser and the field it was hiding becomes a visible
   "Company" box on every contact page. A class works under both.
   Positioned off-canvas rather than `display:none` — some bots skip what is
   displayed none, and the whole point is that they fill it. */
.form-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Turnstile renders its own iframe into this div, so the box is not ours to
   style — but its SIZE is ours to reserve. Without a reserved box the div is
   0px until api.js loads and then jumps to 300x65, shoving the submit button
   down the page just as someone reaches for it. 300x65 is the "normal" widget,
   the default when data-size is not set. */
.cf-turnstile {
  min-height: 65px;
  margin: 4px 0;
}

/* ---- components/footer.css ---- */
/* ---- footer --------------------------------------------------------------
   Rebuilt 2026-09-29 from the original's footer markup and measured at 1440 /
   1024 / 768 / 390 — the client review found "the end of every page" differed
   in layout, type and icons, and the Facebook icon too small. The rebuild had
   carried the shared template's footer (a "Raisin River Marine" heading with
   a call link, a contact list and a 34px social dot) instead of this one.
   -------------------------------------------------------------------------- */

/* ---- brand strip ---------------------------------------------------------
   White, 75px above and below. Six greyscale logos: two per row below 768px,
   three from 768px, six from 1230px, each at the width the original gives it
   (site.json `brands[].width`), 48px between rows until they share one. */
.brands-band {
  position: relative;
  padding: 75px 0;
  background: var(--white);
}

.footer-brands {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  row-gap: 48px;
  align-items: center;
  justify-items: center;
}
@media (min-width: 768px) {
  .footer-brands { grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 1230px) {
  /* 53px: the line box the original's inline logos sit in, 40px tall at most. */
  .footer-brands { grid-template-columns: repeat(6, 1fr); row-gap: 0; min-height: 53px; }
}

.brand-logo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 28px;
}
.brand-logo img { max-width: 100%; height: auto; }

/* The blue corner shape at the right edge of the strip: the original's inline
   SVG, 80px wide from 576px and 150px from 1440px, its bottom 150px / 222px
   below the strip's CONTENT box (so 75px / 147px below the strip, whose
   padding is 75px). It runs down into the dark footer, which is why nothing
   after it in the footer is positioned: a positioned sibling would paint over
   it. Anchored to the full-width strip rather than the centred container, so
   `right: 0` is the page edge at any scrollbar width. Hidden below 576px. */
.brands-band__shape {
  position: absolute;
  right: 0;
  display: none;
  color: var(--blue);
  pointer-events: none;
}
@media (min-width: 576px) {
  .brands-band__shape { display: block; width: 80px; bottom: -75px; }
}
@media (min-width: 1440px) {
  .brands-band__shape { width: 150px; bottom: -147px; }
}

/* ---- dark contact rows --------------------------------------------------- */
.site-footer {
  padding-bottom: 48px;
  background: var(--dark-band);
  color: var(--white);
}

/* Each row is ruled across the page, 30px in from each edge (20px below
   576px), with 48px of space above and below its boxes. */
.footer-row {
  margin: -1px 20px;
  padding: 48px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}
@media (min-width: 576px) {
  .footer-row { margin-inline: 30px; }
}
.footer-row > .container { padding-inline: 0; }
@media (min-width: 992px) {
  .footer-row > .container { padding-inline: 15px; }
}

.footer-row__grid { display: grid; }
@media (min-width: 768px) {
  .footer-row__grid { grid-template-columns: 1fr 1fr; column-gap: 30px; }
  .footer-row__grid--single { grid-template-columns: 1fr; }
}

.footer-box {
  display: block;
  /* The original's rows measure 17px taller than their boxes account for,
     all of it under the text (253px row, 108px box). */
  padding: 16px 0 33px;
  text-align: center;
  color: var(--white);
  text-decoration: none;
}
.footer-box__icon { display: block; margin: 0 auto 15px; color: var(--white); }
.footer-box h2 {
  margin: 0 0 10px;
  font-size: 1.18125rem;     /* 18.9px */
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0;
  color: var(--white);
}
.footer-box--address h2 { margin-bottom: 8px; }
.footer-box__text {
  margin: 0;
  font-size: 0.945rem;       /* 15.12px */
  font-weight: 400;
  line-height: 1.4;
  color: var(--white);
}
.footer-box__text--light { font-weight: 300; }
.footer-box__text a { color: inherit; text-decoration: none; }
a.footer-box:hover h2,
a.footer-box:hover .footer-box__text,
.footer-box__text a:hover { color: #9ec5ee; }

/* ---- logo / Facebook / hours --------------------------------------------
   48px above and below, 24px padding. Three columns from 768px (3 / 3 / 6 of
   twelve), stacked and centred below it. The logo fills its column — 270px at
   1440, the full width on a phone — and the Facebook link is 75px across,
   the size of the original's white disc. The disc now IS Facebook's own
   logo, the client's request of 2026-09-29 (tools/build.js, FACEBOOK_LOGO). */
.footer-middle {
  display: grid;
  align-items: center;
  row-gap: 48px;
  margin-block: 48px;
  padding-block: 24px;
  text-align: center;
}
@media (min-width: 768px) {
  /* Bootstrap's 3 / 3 / 6 of twelve, gutters included: 270 / 270 / 570px of
     content in the 1170px box. */
  .footer-middle {
    grid-template-columns: calc((100% + 30px) / 4 - 30px) calc((100% + 30px) / 4 - 30px) calc((100% + 30px) / 2 - 30px);
    column-gap: 30px;
    text-align: left;
  }
}
@media (min-width: 992px) {
  .footer-middle { row-gap: 0; }
  .footer-middle__logo { text-align: center; }
}

.footer-middle__logo img { width: 100%; height: auto; }

.footer-middle__social { display: flex; justify-content: center; }
@media (min-width: 768px) {
  .footer-middle__social { justify-content: flex-start; }
}
.footer-social-link {
  display: inline-flex;
  width: 75px;
  height: 75px;
  border-radius: 50%;
  transition: opacity var(--transition);
}
.footer-social-link svg { width: 100%; height: 100%; }
.footer-social-link:hover { opacity: 0.85; }

.footer-hours h2 {
  margin: 0 0 24px;
  font-size: 1.063rem;       /* 17.01px */
  font-weight: 700;
  line-height: 18px;
  letter-spacing: -0.05em;
  color: var(--white);
}
.footer-hours ul {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.7875rem;      /* 12.6px */
  line-height: 24px;
  color: #888;
}
/* The original sets each line in its own block; the second sits 40px below
   the first from 768px, 19px below it when the footer stacks. */
.footer-hours li { padding-bottom: 10px; }
.footer-hours li + li { margin-top: 19px; padding-top: 10px; }
@media (min-width: 768px) {
  .footer-hours li + li { margin-top: 40px; }
}
/* The original's hours block carries 20px of empty paragraphs under it, which
   lifts it 10px when the row centres it beside the logo. */
.footer-hours { padding-bottom: 20px; }

/* ---- copyright bar ------------------------------------------------------- */
.footer-copy {
  padding: 24px 20px;
  background: var(--white);
  text-align: center;
}
.footer-copy p {
  margin: 0;
  padding-block: 8px;
  font-size: 0.7875rem;      /* 12.6px */
  line-height: 26px;
  color: #555;
}
/* AdLiBb's logo, 90×104 (the file is 269×312, three times that, for phones). */
.footer-copy__credit { display: block; width: 90px; margin: 0 auto 35px; }
.footer-copy__credit img { display: block; width: 100%; height: auto; }

/* ---- floating controls -------------------------------------------------- */
/* Call button on touch/small screens, back-to-top on larger ones. */
.call-fab {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 900;
  display: none;
  align-items: center;
  justify-content: center;
  width: 54px; height: 54px;
  border-radius: 50%;
  background: var(--blue);
  color: #fff;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.28);
}
.call-fab:hover { background: var(--blue-dark); color: #fff; }

.to-top {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 900;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px; height: 40px;
  border: 0;
  background: rgba(34, 37, 41, 0.72);
  color: #fff;
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.25s ease, visibility 0.25s, background var(--transition);
}
.to-top.is-visible { opacity: 1; visibility: visible; }
.to-top:hover { background: var(--blue); }

@media (max-width: 991px) {
  .call-fab { display: inline-flex; }
  .to-top { display: none; }
}

/* ---- components/dark-band.css ---- */
/* ---- dark band contents --------------------------------------------------
   `.section--dark` only sets a background colour, so anything inside it would
   otherwise inherit the light-background text colours and be unreadable.
   No page uses `.section--dark` since the client review (2026-09-29) replaced
   the homepage's dark call band with the original's blue one; `.narrow` below
   is still used, by the Appointment page.
   -------------------------------------------------------------------------- */

/* `isolation` gives the band its own stacking context so `.eyebrow::before`
   (z-index: -1) lands above the band's background rather than behind it. */
.section--dark {
  color: rgba(255, 255, 255, 0.72);
  isolation: isolate;
}

.section--dark .section-title,
.section--dark h2,
.section--dark h3 { color: #fff; }

.section--dark .section-intro { color: rgba(255, 255, 255, 0.72); }
.section--dark .field label { color: #fff; }

/* The brand red fails contrast against #212529 at this size — lift it for
   this band only, and raise the highlighter bar so it still reads. */
.section--dark .eyebrow { color: #ff5a4d; }
.section--dark .eyebrow::before { background: #ff5a4d; opacity: 0.28; }

/* Readable measure for a form or block of copy inside a full-width band. */
.narrow {
  max-width: 720px;
  margin-inline: auto;
}

/* ---- utilities.css ---- */
/* ---- utilities, motion, print ------------------------------------------- */

/* Any phone link anywhere is a tap target, including one written directly into
   page content. Enforce the WCAG 2.2 minimum (24x24) globally so a bare
   `tel:` link can never ship too small to hit on a phone — which would be a
   particularly bad failure on a business whose phone number is the product. */
/* `padding-block` — NOT `display: inline-flex`. The display form sets a
   property other rules legitimately control, and because this file is last in
   the cascade it silently won every time. Here it re-showed `.header-cta`,
   which header.css hides below 991px: the "Call Us Now 613-347-2098" button
   came back at 284px wide and pushed 149px past a 360px viewport on all 45
   pages. Padding gives the same hit area.

   ONLY CLASS-LESS LINKS. "Overrides nothing" was not true either: an
   attribute selector is (0,1,1) and beats any single class, so on 2026-09-29,
   when the hero "Contact" button and the blue band's "CALL NOW!" started
   dialling the phone (client review), this rule replaced their 21px button
   padding with 6px and the band's button shrank from 63px to 35px tall.
   Every styled phone link — buttons, the header and band call blocks, the
   footer boxes, the floating call button — sizes itself; this is for a bare
   number written into running text. */
a[href^="tel:"]:not([class]) {
  padding-block: 6px;
}

/* There is no scroll-reveal system. The template shipped one — `.js .reveal`
   plus an IntersectionObserver — but no page in this site ever carried a
   `.reveal` element, so the script observed an empty list and the CSS never
   matched anything. The original doesn't fade its sections in either. Removed
   rather than wired up. */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

@media print {
  .topbar,
  .site-header,
  .page-footer,
  .call-fab,
  .to-top,
  .gallery-filters,
  .skip-link { display: none; }

  body { color: #000; background: #fff; }
  .section { padding: 1rem 0; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.75em; }
}

/* 404 action row — replaces the inline styles the template shipped, so the
   CSP can drop 'unsafe-inline' from style-src entirely. */
.notfound-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
  margin-top: 32px;
}
