@charset "utf-8";
/* pointpleasantfire.org - the rebuilt stylesheet.
 *
 * Replaces publicstyle.css, responsive.css, mbcsmbmcp.css (the FlexSite menu
 * widget), layerslider.css + its fullwidth skin, Window.Metro.css,
 * feature.presenter.css and instalink.css. One file, no @import, no webfont
 * from a third party.
 *
 * PALETTE - the CMS's own, unchanged, because it already passes.
 *   --navy #003787 measures 11.07:1 on white and white measures 11.07:1 on it
 *   --red  #d92823 measures  4.91:1 on white, both ways, which clears AA for
 *          normal text as well as large
 * That is unusual in this family of sites and worth saying: nothing here had
 * to be darkened to be legible, so the rebuilt site is the same two colours
 * the department has been using.
 *
 * THE SITE HAD NO VIEWPORT META TAG AT ALL, on any page, and no responsive
 * layer beyond nine `.columnN` percentage widths inside the editor's own
 * content. Everything below the masthead sat in fixed 1200px tables. A phone
 * got the desktop layout scaled to 1/3 size, or the separate `/mobile/` site
 * the CMS redirected it to - which had a different, larger menu and different
 * copy from the one it was standing in for.
 */

:root {
  --navy:        #003787;
  --navy-dark:   #002a66;
  --navy-deep:   #001b42;
  --red:         #d92823;
  --red-dark:    #b71f1a;
  --ink:         #1c1c1c;
  --ink-soft:    #4a4f57;
  --paper:       #ffffff;
  --surface:     #f4f6f9;
  --surface-2:   #e7ebf1;
  --line:        #d3d9e3;
  --focus:       #0b63d6;

  --shell:   1200px;
  --gutter:  24px;
  --measure: 72ch;
  --topbar:  40px;
  --head:    84px;
  --radius:  6px;

  --body:    "Barlow", "Segoe UI", system-ui, -apple-system, "Helvetica Neue",
             Arial, sans-serif;
  --display: "Rubik", "Segoe UI", system-ui, -apple-system, "Helvetica Neue",
             Arial, sans-serif;
}

/* ------------------------------------------------------------------ fonts */
/* The same two families the CMS used, self-hosted as woff2 instead of three
   unhinted TTFs under GUID filenames (316 KB, no font-display, render-
   blocking). Rubik v31 is a variable face: one file covers 300-900, which is
   why the display family has a weight RANGE rather than two @font-face rules.
   The CMS declared "Barlow Light" and "Barlow SemiBold" as two separate
   FAMILIES, so <strong> inside body copy had no bold to reach for and the
   browser synthesised one. */
@font-face {
  font-family: "Barlow";
  font-style: normal; font-weight: 300; font-display: swap;
  src: url(/assets/fonts/barlow-300-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Barlow";
  font-style: normal; font-weight: 600; font-display: swap;
  src: url(/assets/fonts/barlow-600-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Rubik";
  font-style: normal; font-weight: 300 900; font-display: swap;
  src: url(/assets/fonts/rubik-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ------------------------------------------------------------------ reset */
*, *::before, *::after { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* `clip`, never `hidden`: overflow-x:hidden forces overflow-y to `auto`,
     makes the root a scroll container and silently kills `position: sticky`
     on the masthead. Set on BOTH html and body - the body-to-viewport
     propagation rule does not reliably carry `clip`, and the off-canvas
     drawer parked at translateX(100%) then extends the scrollable width by
     its own 340px on about half the width/page combinations. */
  overflow-x: clip;
  scroll-padding-top: calc(var(--head) + 12px);
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}
body {
  margin: 0;
  font-family: var(--body);
  font-weight: 300;
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--ink);
  background: var(--paper);
  overflow-x: clip;
  /* A short page must still fill the screen: /authorization is one heading
     and two sentences, and on a tall phone it ran out well above the bottom
     and left a band of white under the footer. `svh` is the SMALL viewport
     height - with plain `vh` the page is sized for the phone's browser chrome
     being hidden, so the footer sits just below the fold until you scroll. */
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;
}
/* Nothing here may shrink; only `main` grows, so a short page still fills
   the screen and the footer stays at the bottom. */
body > * { flex-shrink: 0; }
main { flex: 1 0 auto; }

img, picture, svg, iframe, video { max-width: 100%; }
img { height: auto; border: 0; }
iframe { border: 0; }
a { color: var(--navy); text-decoration: underline; text-underline-offset: .16em; }
a:hover { color: var(--red-dark); }
:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
button { font: inherit; color: inherit; }

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 500;
  line-height: 1.15;
  margin: 0 0 .5em;
  color: var(--navy);
}
h1 { font-size: clamp(1.85rem, 1.35rem + 2vw, 3rem); font-weight: 600; }
h2 { font-size: clamp(1.4rem, 1.15rem + 1.1vw, 2.1rem); color: var(--red); }
h3 { font-size: clamp(1.15rem, 1.05rem + .5vw, 1.4rem); }
h4 { font-size: 1.08rem; }
p { margin: 0 0 1.1em; }
ul, ol { margin: 0 0 1.1em; padding-left: 1.35em; }
li { margin-bottom: .35em; }
strong, b { font-weight: 600; }
address { font-style: normal; }
hr { border: 0; border-top: 1px solid var(--line); margin: 2.2em 0; }

.shell {
  width: 100%; max-width: var(--shell);
  margin-inline: auto; padding-inline: var(--gutter);
}
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--paper); color: var(--navy); padding: 12px 18px;
  font-weight: 600; border: 2px solid var(--navy); text-decoration: none;
}
.skip:focus { left: 8px; top: 8px; }
.vh {
  position: absolute !important; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.ico { flex: none; fill: currentColor; vertical-align: -.15em; }

/* --------------------------------------------------------------- buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5em;
  padding: 13px 24px; border-radius: var(--radius);
  border: 2px solid transparent; font-family: var(--body); font-size: 1rem;
  font-weight: 600; line-height: 1.2; text-align: center; text-decoration: none;
  cursor: pointer; transition: background-color .18s, color .18s, border-color .18s;
}
.btn:hover, .btn:focus-visible { text-decoration: none; }
.btn-primary { background: var(--navy); color: #fff; }
.btn-primary:hover, .btn-primary:focus-visible { background: var(--red-dark); color: #fff; }
.btn-ghost { background: transparent; color: var(--navy); border-color: var(--navy); }
.btn-ghost:hover, .btn-ghost:focus-visible { background: var(--navy); color: #fff; }

/* ---------------------------------------------------------------- topbar */
.topbar { background: var(--navy-deep); color: #fff; font-size: .875rem; }
.topbar .shell {
  display: flex; justify-content: flex-end; align-items: center;
  gap: 8px 26px; min-height: var(--topbar); flex-wrap: wrap;
}
.topbar a {
  color: #fff; text-decoration: none;
  display: inline-flex; align-items: center; gap: 8px;
}
.topbar a:hover { color: #fff; text-decoration: underline; }

/* -------------------------------------------------------------- masthead */
/* SOLID WHITE, on every page including the home page, which is what the CMS
   did: `.header { position: fixed; background-color: #ffffff; width: 100% }`.
   An earlier draft made it transparent over the hero and faded it in on
   scroll; that is not what the live site looks like, so it is gone - along
   with the scroll-state class, the scrim, the negative margin that pulled the
   hero up underneath, and the white-on-photograph colour switching. `sticky`
   rather than `fixed` keeps it visible without the page having to reserve
   140px of empty table row for it the way the CMS did. */
.masthead {
  position: sticky; top: 0; z-index: 60;
  background: var(--paper);
  border-bottom: 1px solid var(--line);
}
/* NOTHING ON THIS BAR MAY CARRY backdrop-filter, filter, transform,
   perspective, contain or will-change. Each of those makes the masthead the
   containing block for its `position: fixed` descendants, and the off-canvas
   drawer is one: its `top:0; bottom:0` would then resolve against an 84px bar
   instead of the viewport and the panel collapses to a stub. It only shows on
   a SCROLLED page, so every screenshot taken at the top of a page looks
   perfect. harness/probe.html walks the drawer's ancestors and asserts it. */
.masthead > .shell {
  display: flex; align-items: center; gap: 20px; min-height: var(--head);
}

.brand {
  flex: none; display: flex; align-items: center; gap: 12px;
  text-decoration: none; color: var(--navy);
}
.brand img { width: 56px; height: auto; }
.brand-name {
  font-family: var(--display); font-weight: 500; line-height: 1.12;
  font-size: .92rem; letter-spacing: .01em; text-transform: uppercase;
  display: flex; flex-direction: column;
}
.brand-name b { font-weight: 700; font-size: 1.16rem; letter-spacing: .005em; }

/* ------------------------------------------------------------------- nav */
.nav { margin-left: auto; }
.nav > ul {
  display: flex; align-items: center; gap: 2px;
  margin: 0; padding: 0; list-style: none;
}
.nav > ul > li { position: relative; margin: 0; }
.nav-top {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 10px 12px; border: 0; background: transparent;
  color: var(--navy); font-family: var(--body); font-size: .82rem;
  font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  white-space: nowrap; cursor: pointer; border-radius: var(--radius);
  text-decoration: none;
}
.nav-top:hover, .nav-top:focus-visible { color: var(--red); text-decoration: none; }
.nav-top[aria-current="page"], .nav-top[data-current="true"] { color: var(--red); }
.nav-top[aria-current="page"]::after, .nav-top[data-current="true"]::after {
  content: ""; position: absolute; left: 12px; right: 12px; bottom: 2px;
  height: 3px; background: var(--red); border-radius: 2px;
}
.caret {
  width: 10px; height: 10px; flex: none; fill: none;
  stroke: currentColor; stroke-width: 2; transition: transform .18s;
}
.nav-top[aria-expanded="true"] .caret { transform: rotate(180deg); }

.nav-sub {
  position: absolute; top: 100%; right: 0; z-index: 5;
  min-width: 290px; padding: 18px 8px;
  background: var(--paper); border-radius: var(--radius);
  border-top: 4px solid var(--red);
  box-shadow: 0 16px 40px rgba(0, 25, 60, .26);
  opacity: 0; visibility: hidden; transform: translateY(6px);
  transition: opacity .16s, transform .16s;
}
/* A panel with four groups needs the width; one with a single group must not
   have it. COLUMNS, not a grid: as grid items the groups sit in rows, and the
   tallest group in row one (Member Resources, seven links) sets that row's
   height - so the fourth group started below all of it with 300px of white
   space above it. `columns` balances instead, and `break-inside: avoid` keeps
   a group whole. */
.nav-sub.is-wide {
  width: min(900px, calc(100vw - 2 * var(--gutter)));
  columns: 3; column-gap: 26px; padding: 22px;
}
.nav-sub.is-wide .nav-grp { break-inside: avoid; margin-bottom: 14px; }
.nav-sub[data-open="true"] { opacity: 1; visibility: visible; transform: none; }
/* Opening on HOVER is a desktop-pointer affordance and is confined to one.
   `(hover: hover)` keeps it off touch and the width query keeps it out of the
   drawer's breakpoint: a hover rule that can reach the drawer out-specifies
   the `[data-open]` rule that actually drives it, and because a tap leaves an
   element stuck in :hover it wins for as long as the finger has been near it.
   Cancelling such a rule inside the drawer does not work - scoping it so it
   can never apply there is the only fix. */
@media (hover: hover) and (min-width: 981px) {
  .nav .has-sub:hover > .nav-sub { opacity: 1; visibility: visible; transform: none; }
}
.nav-grp ul { list-style: none; margin: 0; padding: 0; }
.nav-grp h2 {
  font-family: var(--body); font-size: .7rem; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--ink-soft);
  margin: 14px 14px 6px; padding-top: 10px; border-top: 1px solid var(--line);
}
.nav-sub.is-wide .nav-grp:first-child h2,
.nav-sub .nav-grp:first-child h2 { margin-top: 0; padding-top: 0; border-top: 0; }
.nav-sub a {
  display: block; padding: 8px 14px; color: var(--ink);
  font-size: .95rem; line-height: 1.3; border-radius: 4px; text-decoration: none;
}
.nav-sub a:hover, .nav-sub a:focus-visible {
  background: var(--surface); color: var(--navy); text-decoration: underline;
}
.nav-sub a[aria-current="page"] { color: var(--red); font-weight: 600; }
.nav-sub .ext { opacity: .55; margin-left: .35em; }
.nav-util { display: none; }

.nav-toggle {
  display: none; margin-left: auto; align-items: center; gap: 10px;
  background: transparent; border: 2px solid var(--navy); border-radius: var(--radius);
  color: var(--navy); padding: 9px 14px; font-size: .78rem; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; cursor: pointer;
}
.nav-toggle .bars { position: relative; width: 20px; height: 14px; flex: none; }
.nav-toggle .bars i, .nav-toggle .bars::before, .nav-toggle .bars::after {
  position: absolute; left: 0; width: 100%; height: 2px; background: currentColor;
  content: ""; transition: transform .2s, opacity .2s;
}
.nav-toggle .bars::before { top: 0; }
.nav-toggle .bars i { top: 6px; }
.nav-toggle .bars::after { top: 12px; }
.nav-toggle[aria-expanded="true"] .bars::before { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .bars i { opacity: 0; }
.nav-toggle[aria-expanded="true"] .bars::after { transform: translateY(-6px) rotate(-45deg); }

.backdrop {
  display: none; position: fixed; inset: 0; z-index: 50;
  background: rgba(0, 12, 32, .55);
}
body.nav-open .backdrop { display: block; }

/* ------------------------------------------------------------------ hero */
.hero {
  position: relative; isolation: isolate;
  min-height: clamp(380px, 52vw, 620px);
  display: grid; align-items: center;
  color: #fff;
}
.bgimg {
  position: absolute; inset: 0; z-index: -2;
  display: block; width: 100%; height: 100%;
}
.bgimg img { width: 100%; height: 100%; object-fit: cover; }
.hero::after {
  /* The source photograph is already darkened, but not evenly: the truck's
     white flank runs behind the middle of the heading. This is the floor. */
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(90deg, rgba(0, 15, 38, .55) 0%,
                                     rgba(0, 15, 38, .32) 55%,
                                     rgba(0, 15, 38, .12) 100%);
}
.hero-copy { padding-block: 56px; }
.hero-copy h1 {
  color: #fff; text-transform: uppercase; font-weight: 700;
  max-width: 16ch; margin-bottom: .35em;
  text-shadow: 0 2px 18px rgba(0, 10, 30, .5);
}
.hero-copy p {
  font-size: clamp(1rem, .92rem + .45vw, 1.25rem); font-weight: 600;
  letter-spacing: .02em; max-width: 46ch; margin: 0;
  text-shadow: 0 2px 14px rgba(0, 10, 30, .55);
}

/* -------------------------------------------------------------- pagehead */
.pagehead { background: var(--surface); border-bottom: 1px solid var(--line); }
.pagehead .shell { padding-block: 26px 30px; }
.pagehead h1 { margin: 0; }
.crumbs { margin-bottom: 10px; }
.crumbs ol {
  display: flex; flex-wrap: wrap; gap: 4px 8px;
  list-style: none; margin: 0; padding: 0;
  font-size: .85rem; color: var(--ink-soft);
}
.crumbs li { margin: 0; display: flex; gap: 8px; align-items: center; }
.crumbs li + li::before { content: "/"; color: var(--line); }
.crumbs a { color: var(--ink-soft); }

/* ----------------------------------------------------------------- bands */
.band { padding-block: clamp(40px, 6vw, 74px); }
.band-mission { background: var(--paper); }
.mission-grid {
  display: grid; gap: 34px; align-items: start;
  grid-template-columns: minmax(0, 1fr) 300px;
}
.mission-grid .lede { font-size: 1.2rem; max-width: 52ch; }
.tribute { justify-self: end; }
/* Reserve the ROW, not just the box: the tribute is a third-party iframe and
   without a height here the mission band jumps by 300px when it arrives. */
.tribute iframe { width: 300px; height: 300px; display: block; }

.band-values { position: relative; isolation: isolate; color: #fff;
               background: var(--navy-deep); }
/* The montage is a COMPOSED image, not a photograph: navy on the left, the
   firefighter's portrait at about 12-35% and the hose crew ghosted into the
   right half. `cover` on any viewport but 1920 crops a different part of it,
   so the band keeps its own navy ground underneath and a scrim over the top -
   the copy then has a floor whatever the crop does. */
.band-values::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(90deg, rgba(0, 20, 52, .66) 0%,
                                     rgba(0, 20, 52, .54) 45%,
                                     rgba(0, 20, 52, .74) 100%);
}
.band-values h2 { color: #fff; }
.values {
  display: grid; gap: 26px 30px; list-style: none; margin: 0; padding: 0;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.values li { margin: 0; }
.values h3 {
  color: #fff; font-size: 1.35rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: .03em; margin-bottom: .3em;
}
.values p { margin: 0; color: #edf1f8; }

.band-gallery { background: var(--red); color: #fff; padding-block: 44px; }
.band-gallery h2 {
  color: #fff; text-align: center; text-transform: uppercase; margin: 0;
}
.gallery { padding-block: 0 clamp(36px, 5vw, 64px); background: var(--paper); }
.photo-strip {
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: clamp(10px, 1.6vw, 22px); list-style: none; margin: -34px 0 0; padding: 0;
}
.photo-strip li { margin: 0; }
.photo-strip img {
  width: 100%; aspect-ratio: 373 / 453; object-fit: cover;
  border-radius: var(--radius); box-shadow: 0 10px 26px rgba(0, 25, 60, .18);
  display: block;
}

.band-contact { background: var(--surface); border-top: 1px solid var(--line); }
.contact-grid {
  display: grid; gap: 22px 30px; align-items: center;
  grid-template-columns: auto repeat(2, minmax(0, 1fr)) auto;
}
.contact-grid h2 {
  margin: 0; color: var(--navy); font-weight: 700; text-transform: uppercase;
  font-size: clamp(1.6rem, 1.2rem + 1.4vw, 2.4rem);
}
.contact-item { display: flex; align-items: center; gap: 14px; }
.contact-item .ico { color: var(--red); }
.contact-item p, .contact-item address { margin: 0; }
.contact-item .fax { color: var(--ink-soft); }
.contact-grid .btn { white-space: nowrap; }

.band-map { line-height: 0; background: var(--surface-2); }
.band-map iframe { display: block; width: 100%; height: 360px; }

/* ----------------------------------------------------------------- prose */
.prose { padding-block: clamp(34px, 4.5vw, 56px); }
.prose > * { max-width: var(--measure); }
.prose > .fig, .prose > figure, .prose > table, .prose > .apparatus,
.prose > .rates, .prose > .contact-cols, .prose > .vision { max-width: none; }
.prose h2 { margin-top: 1.6em; }
.prose h2:first-child { margin-top: 0; }
.prose h3 { margin-top: 1.4em; }
.prose .ta-c { text-align: center; }
/* The one floated image the CMS has. Capped and cleared so it cannot cause
   an overlap on a narrow column, and unfloated on a phone where a 155px
   logo beside 40 characters of text is worse than a stacked one. */
.prose .fl-right, .prose .fl-left {
  max-width: 40%; height: auto; margin: .2em 0 1em 1.4em;
}
.prose .fl-right { float: right; }
.prose .fl-left { float: left; margin: .2em 1.4em 1em 0; }
/* Clear at the CONTAINER, not on every paragraph. `.prose p::after { clear }`
   stops the float escaping too, but it also cuts the wrap off at the end of
   the paragraph the image sits in - which is not what a float is for, and not
   what the CMS did. This only stops it escaping the content block. */
.prose::after { content: ""; display: block; clear: both; }
@media (max-width: 560px) {
  .prose .fl-right, .prose .fl-left {
    float: none; max-width: 100%; margin: 0 0 1em;
  }
}
.prose .fig { margin: 1.8em 0; }
.prose .fig img { border-radius: var(--radius); display: block; }
.prose .fig.ta-c, .prose .fig > a { display: block; }
.prose figcaption { font-size: .92rem; color: var(--ink-soft); margin-top: .5em; }
.prose ul { padding-left: 1.2em; }
.prose li::marker { color: var(--red); }
.prose img { border-radius: var(--radius); }
.prose a[target="_blank"]::after {
  content: ""; display: inline-block; width: .62em; height: .62em;
  margin-left: .32em; vertical-align: baseline;
  background: currentColor; opacity: .6;
  -webkit-mask: var(--ext-mask) center / contain no-repeat;
          mask: var(--ext-mask) center / contain no-repeat;
  --ext-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M14 3h7v7h-2V6.4l-8.3 8.3-1.4-1.4L17.6 5H14zM5 5h5v2H6v11h11v-4h2v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1z"/></svg>');
}
/* No marker on a link whose content is a PICTURE. The arrow is there to warn
   that a link leaves the site; on an anchor wrapping a floated logo it lands
   as a stray glyph at the start of the paragraph, because the image it was
   meant to sit beside has floated away from it. */
.prose .fig a[target="_blank"]::after,
.prose a[target="_blank"]:has(> picture)::after,
.prose a[target="_blank"]:has(> img)::after { content: none; }

/* Two halves, which only /contact-us uses. `minmax(0, 1fr)` rather than a
   bare `1fr`: a bare 1fr cannot shrink below its content's min-content width,
   and an iframe's is its width attribute. */
.contact-cols {
  display: grid; gap: 34px; grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: start;
}
.map-figure { margin: 1.6em 0 0; }
.map-figure iframe {
  display: block; width: 100%; aspect-ratio: 4 / 3; min-height: 320px;
  border-radius: var(--radius); border: 1px solid var(--line);
}

/* The EMS billing rates. The CMS painted every cell #33ccff with bold black
   text inside a fixed 727px table. */
.rates { width: 100%; border-collapse: collapse; margin: 0 0 1.6em; }
.rates caption { text-align: left; font-weight: 600; margin-bottom: .6em; }
.rates th, .rates td {
  padding: 11px 14px; border-bottom: 1px solid var(--line); text-align: left;
  vertical-align: top;
}
.rates thead th { background: var(--navy); color: #fff; border-bottom: 0; }
.rates tbody tr:nth-child(odd) { background: var(--surface); }
.rates td:last-child { text-align: right; white-space: nowrap; font-weight: 600; }

/* The apparatus fleet. The CMS laid this out as nine `width:30%; float:left`
   divs, which at any width below about 1000px wrapped into a stack of
   half-empty rows. */
.apparatus {
  display: grid; gap: 26px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  list-style: none; margin: 0 0 2em; padding: 0;
}
/* Three across, then two, then one. `repeat(auto-fit, minmax(260px, 1fr))`
   picks four at 1400px, which makes each photograph smaller than the CMS
   ever drew it; the count here is known, so it is stated. */
@media (max-width: 900px) { .apparatus { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .apparatus { grid-template-columns: minmax(0, 1fr); } }
.apparatus li { margin: 0; }
.apparatus figure { margin: 0; }
.apparatus img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: var(--radius); display: block; background: var(--surface);
}
.apparatus figcaption { margin-top: .6em; }
.apparatus .unit {
  display: block; font-family: var(--display); font-weight: 600;
  color: var(--navy); font-size: 1.1rem;
}
.apparatus .spec { color: var(--ink-soft); font-size: .95rem; }

/* The vision statement, which the CMS shipped only as a 2504x3894 JPEG - a
   picture of words, unreadable to a screen reader and to a search engine.
   The words are set here; the poster stays as the artwork it is. */
.vision { display: grid; gap: 30px; grid-template-columns: minmax(0, 1fr) 300px;
          align-items: start; }
.vision-words blockquote {
  margin: 0 0 1.2em; padding-left: 18px; border-left: 4px solid var(--red);
  font-size: 1.1rem;
}
.creed { columns: 3 9rem; column-gap: 24px; list-style: none; margin: 0 0 1.4em;
         padding: 0; }
.creed li { margin: 0 0 .25em; font-weight: 600; color: var(--navy); }
.vision-art { margin: 0; }
.vision-art img { width: 100%; display: block; border-radius: var(--radius);
                  border: 1px solid var(--line); }

/* -------------------------------------------------------------- 404 list */
.notfound ul { columns: 2 16rem; column-gap: 32px; }
.notfound li { break-inside: avoid; }

/* ---------------------------------------------------------------- footer */
.site-footer { background: var(--navy); color: #fff; padding-block: 48px 26px; }
.site-footer a { color: #dbe4f3; text-decoration: none; }
.site-footer a:hover, .site-footer a:focus-visible { color: #fff; text-decoration: underline; }
.foot-nav {
  display: grid; gap: 26px 30px; list-style: none; margin: 0 0 34px; padding: 0;
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
.foot-nav > li { margin: 0; }
.foot-nav h2 {
  color: #fff; font-family: var(--body); font-size: .74rem; font-weight: 600;
  letter-spacing: .13em; text-transform: uppercase; margin: 0 0 .9em;
  padding-bottom: .6em; border-bottom: 1px solid rgba(255, 255, 255, .22);
}
.foot-nav ul { list-style: none; margin: 0; padding: 0; font-size: .95rem; }
.foot-nav ul li { margin-bottom: .5em; }
.foot-brand {
  display: flex; align-items: center; gap: 18px;
  padding-top: 26px; border-top: 1px solid rgba(255, 255, 255, .22);
}
.foot-brand img { width: 76px; height: auto; flex: none; }
.foot-org { font-family: var(--display); font-weight: 500; font-size: 1.1rem;
            margin: 0 0 .2em; }
.foot-brand address { font-size: .95rem; color: #dbe4f3; }
.copyright { margin: 22px 0 0; font-size: .85rem; color: #b9c7de; }

/* ------------------------------------------------------------------ form */
.f-form { max-width: 620px; }
.f-field { margin-bottom: 18px; }
.f-field label { display: block; font-weight: 600; margin-bottom: 6px; }
.f-field input, .f-field textarea {
  width: 100%; padding: 11px 13px; font: inherit; color: var(--ink);
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--radius);
}
.f-field input:focus, .f-field textarea:focus {
  outline: 3px solid var(--focus); outline-offset: 1px; border-color: var(--navy);
}
.f-field textarea { min-height: 150px; resize: vertical; }
.f-req { color: var(--red-dark); }
.f-hint { font-size: .9rem; color: var(--ink-soft); }
/* The honeypot. `display:none` is skipped by some bots as an obvious tell and
   `position:absolute;left:-9999px` reads to a rect walk as an overflow, so it
   is clipped to nothing instead. */
.f-hp {
  position: absolute !important; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.f-ok, .f-err {
  padding: 16px 18px; border-radius: var(--radius); margin-bottom: 22px;
  border-left: 5px solid;
}
.f-ok { background: #eef6ee; border-color: #2f7d32; }
.f-err { background: #fdeceb; border-color: var(--red-dark); }
.f-err ul { margin: .5em 0 0; }

/* ============================== BREAKPOINTS ============================= */
/* 980px is MEASURED, not chosen: the five top-level items plus the brand
   settle at 921px of intrinsic width, so the bar has room down to about
   950 and starts crowding below it. harness/fp_probe.html re-measures and
   fails the build if the bar ever exceeds the container above this width. */
@media (max-width: 980px) {
  :root { --head: 68px; }
  .nav-toggle { display: inline-flex; }
  /* The drawer is a DESCENDANT of the masthead, so it lives inside the
     masthead's stacking context: a positioned descendant paints above every
     STATIC sibling however high the ancestor's own z-index is. Without these
     two the panel covers the logo and - worse - the burger that closes it. */
  .brand, .nav-toggle { position: relative; z-index: 61; }

  .nav {
    /* BELOW the masthead (60) and above the backdrop (50). */
    position: fixed; top: 0; right: 0; bottom: 0; z-index: 55;
    width: min(360px, 90vw); margin: 0;
    background: var(--navy-deep); color: #fff;
    /* The drawer starts BELOW the masthead. Unopened the bar is sticky under
       the utility strip; while the drawer is open ppf.js fixes it at y=0. */
    padding: calc(var(--topbar) + var(--head) + 10px) 0 40px;
    overflow-y: auto; -webkit-overflow-scrolling: touch;
    transform: translateX(100%); visibility: hidden;
    /* ONLY `transform` transitions. With `visibility` in this list the
       panel's very existence depends on an animation finishing: a throttled
       tab or an unpromoted layer leaves it `hidden` at its start value and
       the menu is half-drawn, while the cascade resolves perfectly the whole
       time. Visibility flips with the class, synchronously. */
    transition: transform .26s ease;
    will-change: transform;
    box-shadow: -10px 0 34px rgba(0, 12, 32, .45);
  }
  body.nav-open .nav { transform: none; visibility: visible; }
  /* A programmatic focus target, not a control: the ring belongs on whatever
     the visitor tabs to next. */
  .nav:focus, .nav:focus-visible { outline: none; }
  .nav > ul { display: block; }
  .nav > ul > li { border-top: 1px solid rgba(255, 255, 255, .14); }
  .nav > ul > li:first-child { border-top: 0; }
  .nav-top {
    display: flex; width: 100%; justify-content: space-between;
    padding: 15px 22px; font-size: .9rem; border-radius: 0; color: #fff;
  }
  .nav-top[aria-current="page"], .nav-top[data-current="true"] { color: #fff; }
  .nav-top[aria-current="page"]::after, .nav-top[data-current="true"]::after {
    left: 0; right: auto; top: 0; bottom: 0; width: 4px; height: auto;
    border-radius: 0;
  }
  .nav-sub, .nav-sub.is-wide {
    position: static; min-width: 0; width: auto; padding: 0; margin: 0;
    /* `columns: 1`, and it is not optional. The desktop panel is a
       three-column balanced layout; without this reset the drawer inherits it
       and renders the same links in three 100px columns inside a 360px
       panel - every label broken one word per line. A `grid-template-columns`
       reset was here and did nothing, because the desktop panel stopped being
       a grid. Reset the property you actually set. */
    columns: 1; column-gap: normal;
    display: none; grid-template-columns: none;
    background: rgba(0, 0, 0, .26); border-radius: 0; border-top: 0;
    box-shadow: none; opacity: 1; visibility: visible; transform: none;
  }
  /* NO `:hover` RULE HERE, and none may be added. `.nav li:hover > .nav-sub`
     is 0,3,1 against `.nav-sub[data-open="true"]` at 0,2,0, and a tap on a
     touch screen leaves the <li> in :hover - so every submenu would open and
     be forced shut in the same instant, on every phone, while aria-expanded
     and data-open both said "true". A synthetic .click() in a harness never
     sets :hover, so it passes every automated check. The desktop hover rule
     is scoped to (hover: hover) and min-width so there is nothing to cancel. */
  .nav-sub[data-open="true"] { display: block; }
  .nav-grp h2 {
    color: #b9c7de; margin: 16px 22px 4px; padding-top: 12px;
    border-top: 1px solid rgba(255, 255, 255, .14);
  }
  .nav-sub .nav-grp:first-child h2 { margin-top: 12px; }
  .nav-sub a { color: #e8edf6; padding: 11px 22px 11px 34px; font-size: .92rem; }
  .nav-sub a:hover, .nav-sub a:focus-visible {
    background: rgba(255, 255, 255, .08); color: #fff;
  }
  .nav-sub a[aria-current="page"] { color: #fff; font-weight: 600; }
  .nav-util {
    display: block; border-top: 1px solid rgba(255, 255, 255, .14);
    padding: 18px 22px;
  }
  .nav-util ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
  .nav-util a { color: #fff; display: flex; align-items: center; gap: 10px;
                font-size: .95rem; text-decoration: none; }
  .nav-util .ico { color: #8fb0e6; }

  /* The scroll lock cannot be html{overflow:hidden}: that takes the scroll
     offset away from the sticky masthead, which snaps to the top of the
     document, and the drawer opens under nothing. ppf.js fixes the body at
     -scrollY; this is the part the stylesheet owns. */
  body.nav-open { overflow: hidden; }
  body.nav-open .masthead {
    position: fixed; top: 0; left: 0; right: 0; margin-bottom: 0;
    background: var(--paper); border-bottom-color: var(--line);
  }
  body.nav-open .nav { padding-top: calc(var(--head) + 10px); }
  /* GIVE BACK THE SPACE THE MASTHEAD JUST VACATED.
     Switching it from sticky to fixed is necessary - a sticky bar inside a
     body that has been fixed at -scrollY has no scrollport left and reverts
     to its static position - but it also takes the bar OUT OF FLOW, and on
     every page except the home one the bar is in flow. Everything below it
     jumped up by exactly --head the moment the drawer opened, which reads as
     the page twitching under the backdrop. The home page never showed it
     while its masthead was pulled up over the hero with a negative margin, so
     it contributed nothing to flow either way. The bar is solid and in flow on
     every page now, so the compensation is unconditional. The probe found the
     original as a -69px shift on five short pages. */
  body.nav-open main { margin-top: var(--head); }

  .mission-grid, .vision { grid-template-columns: minmax(0, 1fr); }
  .tribute { justify-self: start; }
  .values { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .contact-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .contact-grid h2 { grid-column: 1 / -1; }
  .foot-nav { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .contact-cols { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 760px) {
  :root { --gutter: 18px; }
  body { font-size: 1.0625rem; }
  .topbar .shell { justify-content: center; gap: 6px 18px; font-size: .82rem; }
  .brand-name { font-size: .74rem; }
  .brand-name b { font-size: .98rem; }
  .brand img { width: 46px; }
  /* NO `vh` HERE. `min-height: 66vh` reads as 66% of whatever viewport the
     element finds itself in, so on a landscape phone the hero is 250px and
     inside any measuring harness with a tall frame it is 1320px - which is
     what the responsive probe reported, on eleven widths, as a runaway hero.
     A width-based clamp is stable in both, and it is the same shape the base
     rule already uses. */
  .hero { min-height: clamp(400px, 92vw, 540px); }
  .photo-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: -24px; }
  .photo-strip li:last-child { grid-column: 1 / -1; }
  .photo-strip li:last-child img { aspect-ratio: 16 / 9; }
  .values { grid-template-columns: minmax(0, 1fr); gap: 22px; }
  .contact-grid { grid-template-columns: minmax(0, 1fr); }
  .band-map iframe { height: 300px; }
  .creed { columns: 2 8rem; }
  .notfound ul { columns: 1; }
  /* The CMS wrote `width` and `height` in an inline style on some content
     images. Capping the width without releasing the height draws them at the
     wrong ratio; both belong INSIDE the media query, where the layout is
     fluid anyway, and not at base level where a desktop image that was
     already correct would be squashed. */
  .prose img[width][height] { height: auto; }
}

@media (max-width: 520px) {
  /* Clipped, NOT `display: none`. The badge carries `alt=""` because the
     wordmark beside it is the link's accessible name; hiding the wordmark
     outright leaves the home link with no name at all, which is exactly the
     width where a screen reader is most likely to be in use. */
  .brand-name {
    position: absolute !important; width: 1px; height: 1px; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
  }
  .brand img { width: 44px; }
  .nav-toggle span:not(.bars) { display: none; }
  .nav-toggle { padding: 10px; }
  .foot-nav { grid-template-columns: minmax(0, 1fr); }
  .foot-brand { flex-direction: column; align-items: flex-start; gap: 12px; }
  .creed { columns: 1; }
  .rates td:last-child { text-align: left; }
}
