/* ============================================================
   DESIGN TOKENS
   Palette: bright editorial ground (white / light grey), black
   condensed headlines, red as the single accent color.
   ============================================================ */
:root {
  --bg: #FFFFFF;
  --bg-alt: #F4F4F5;
  --surface: #FFFFFF;
  --surface-2: #ECECEE;
  --ink: #141414;
  --ink-soft: #333335; /* long-form body copy — softer than --ink, darker than --muted */
  --muted: #6B6B70;
  --line: #E4E4E7;

  --red: #E1261C;
  --red-dim: #B81E16;
  --success: #2E7D32;
  --gold: #B8912A; /* Quadro de Honra only — a deliberate one-off exception to red-as-the-only-accent */
  --badge-navy: #083165; /* exact background colour baked into the rank-insignia PNGs */

  --footer-bg: #3A3A3D;
  --footer-ink: #F2F1EA;
  --footer-line: #4C4C50;
  --footer-muted: #9A9A9E;

  --font-display: "Barlow Condensed", sans-serif;
  --font-body: "Inter", sans-serif;
  --font-mono: "JetBrains Mono", monospace;

  --radius: 4px;
  --wrap: 1180px;
  --wrap-narrow: 760px;
}

@media (prefers-reduced-motion: no-preference) {
  :root { --transition-base: 220ms cubic-bezier(.4,0,.2,1); --transition-slide: 600ms ease; }
}
@media (prefers-reduced-motion: reduce) {
  :root { --transition-base: 0ms; --transition-slide: 0ms; }
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  line-height: 1.05;
  margin: 0 0 0.4em;
  color: var(--ink);
}
h1 { font-size: clamp(2.6rem, 6vw, 4.6rem); font-weight: 800; }
h2 { font-size: clamp(1.7rem, 3.2vw, 2.4rem); }
h3 { font-size: 1.15rem; text-transform: none; letter-spacing: 0; }

p { margin: 0 0 1em; }
a { color: var(--red); text-decoration: none; }
a:hover { text-decoration: underline; }
/* height:auto is the required companion to max-width:100% now that images carry
   intrinsic width/height attributes — without it, an image shrunk by max-width
   keeps the attribute's height and distorts. Rules that genuinely need a fixed
   height (.card__media img, .brand__mark, hero media) set it explicitly and win
   on specificity. */
img { max-width: 100%; height: auto; display: block; }

:focus-visible {
  outline: 3px solid var(--red);
  outline-offset: 2px;
}

.sr-only {
  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; left: -999px; top: 0; z-index: 1000;
  background: var(--red); color: #fff; padding: 10px 16px;
  font-weight: 600;
}
.skip-link:focus { left: 0; }

.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 24px; }
.wrap--narrow { max-width: var(--wrap-narrow); }

.eyebrow {
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 0.78rem;
  color: var(--red);
  margin: 0 0 0.6em;
}
.muted { color: var(--muted); }
.small { font-size: 0.85rem; }
/* No max-width here — page-header ledes should fill the same margins as
   everything else on the page (the .wrap they sit in already caps line
   length site-wide), not stop short and leave the right side of the
   heading block looking oddly narrower than the content below it. */
.lede { font-size: 1.15rem; color: var(--muted); }

/* ---- Buttons ---- */
.btn {
  display: inline-block;
  font-family: var(--font-display);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 700;
  font-size: 1rem;
  padding: 14px 28px;
  border-radius: var(--radius);
  border: 2px solid transparent;
  transition: transform var(--transition-base), background var(--transition-base), color var(--transition-base);
}
.btn:hover { text-decoration: none; transform: translateY(-2px); }
.btn--sm { font-weight: 600; font-size: 0.8rem; padding: 9px 20px; }
.btn--primary { background: var(--red); color: #fff; }
.btn--primary:hover { background: var(--red-dim); }
.btn--ghost { background: transparent; border-color: var(--ink); color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: #fff; }

.link-arrow {
  display: inline-block;
  margin-top: 28px;
  font-family: var(--font-mono);
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--red);
}

/* ---- Header / nav ---- */
/* Sticky so it stays visible on scroll, with the same dark background as the
   footer (bookending the page) — every color below that was tuned for the
   header's old white background is flipped to the footer's --footer-* tokens
   so it stays readable against the dark bar. The two dropdown panels (desktop
   floating submenu, mobile slide-down panel) deliberately stay light/white —
   overridden back in their own rules — since a light popover under a dark bar
   is the more common, easier-to-read pattern than an all-dark menu. */
.site-header {
  background: var(--footer-bg); border-bottom: 1px solid var(--footer-line);
  position: sticky; top: 0; z-index: 100;
}
.site-header__inner {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  column-gap: 24px; padding: 16px 24px;
}
.brand { display: flex; align-items: center; gap: 10px; color: var(--footer-ink); justify-self: start; }
.brand:hover { text-decoration: none; }
.brand__mark {
  height: 64px; width: auto;
  flex-shrink: 0;
}
.brand__text {
  font-family: var(--font-display); font-weight: 800; font-size: 1.5rem;
  text-transform: uppercase; letter-spacing: 0.03em; line-height: 1;
  display: flex; flex-direction: column;
}
.brand__sub {
  font-family: var(--font-mono); font-size: 0.6rem; font-weight: 500;
  text-transform: none; letter-spacing: 0.02em; color: var(--muted);
}
.brand__lines {
  display: flex; flex-direction: column; justify-content: space-between;
  height: 64px; /* matches .brand__mark so the two lines top/bottom-align to the logo */
}
.brand__line {
  font-family: var(--font-display); font-weight: 800; font-size: 1.7rem;
  text-transform: uppercase; white-space: nowrap; line-height: 1;
}
/* No letter-spacing tricks: "Bombeiros" (9 letters) and "Valongo" (7)
   are matched to the same ink width by scaling VALONGO's font-size up
   instead, measured from each word's natural (normal-spacing) width. */
.brand__line--black { color: var(--footer-ink); }
.brand__line--red { color: var(--red); font-size: 2.091rem; position: relative; top: -4px; }
.nav { justify-self: center; }
.header-aside { justify-self: end; display: flex; align-items: center; gap: 20px; }
.social-links { display: flex; align-items: center; gap: 14px; }
.social-links a { color: var(--ink); display: flex; }
.social-links a:hover { color: var(--red); }
.social-links svg { width: auto; height: 18px; fill: currentColor; }
.phone-link {
  display: flex; align-items: center; gap: 7px; color: var(--footer-ink);
  font-family: var(--font-mono); font-weight: 500; font-size: 0.95rem; white-space: nowrap;
}
.phone-link:hover { color: var(--red); text-decoration: none; }
.phone-link svg { width: 18px; height: 18px; fill: currentColor; flex-shrink: 0; }
.nav__menu {
  list-style: none; display: flex; gap: 28px; margin: 0; padding: 0;
  font-family: var(--font-mono); font-size: 0.85rem; text-transform: uppercase;
  letter-spacing: 0.05em; align-items: center;
}
.nav__menu a { color: var(--footer-ink); }
.nav__menu a:hover { color: var(--red); text-decoration: none; }
.nav__toggle { display: none; }

.nav__item--dropdown { position: relative; }
.nav__dropdown-toggle {
  background: none; border: none; padding: 0; margin: 0; cursor: pointer;
  font: inherit; text-transform: inherit; letter-spacing: inherit; color: var(--footer-ink);
  display: inline-flex; align-items: center; gap: 4px;
}
.nav__dropdown-toggle:hover { color: var(--red); }
.nav__caret { width: 12px; height: 12px; flex-shrink: 0; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; transition: transform var(--transition-base); }
.nav__dropdown-toggle[aria-expanded="true"] .nav__caret { transform: rotate(180deg); }
.nav__submenu {
  list-style: none; margin: 14px 0 0; padding: 8px 0; position: absolute; top: 100%; left: 0;
  min-width: 230px; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: 0 12px 24px rgba(20,20,20,0.12);
  display: none; z-index: 60;
}
.nav__item--dropdown.is-open .nav__submenu { display: block; }
.nav__submenu a {
  display: block; padding: 10px 18px; text-transform: none; letter-spacing: 0;
  font-family: var(--font-body); font-size: 0.9rem; white-space: nowrap;
  /* Overrides .nav__menu a's footer-ink: the submenu panel itself is always
     light (white on desktop, --bg-alt on the mobile accordion), so its links
     need dark text in both contexts — unlike the dark bar around them. */
  color: var(--ink);
}
.nav__submenu a:hover { background: var(--bg-alt); }

/* ---- Hero ---- */
/* min-height:78vh alone grows without limit on a tall/portrait viewport
   (a portrait monitor, a narrow-but-tall window) — the hero can end up
   1500px+ tall, mostly empty space around the vertically-centered text.
   A separate max-height doesn't fix this: per spec, min-height always wins
   when the two conflict, so max-height gets silently ignored whenever it's
   smaller than 78vh. height:min(...) picks whichever value is actually
   smaller, which is the real fix — 78vh on typical short screens, 820px
   as a hard ceiling on tall ones. */
.hero-carousel {
  position: relative; overflow: hidden;
  height: min(78vh, 820px);
  /* Floor beneath the vh-based height above: the text stack (padding +
     eyebrow + 2-line title + 2-line lede + button) plus room for the
     controls bar below it needs ~525px in the worst case — the title's
     6vw clamp grows it from ~429px on a narrow phone up to ~509px once
     the viewport is wide enough to hit the clamp's 4.6rem ceiling. Below
     this floor, the flex-centered content in .hero-slide overflows top
     and bottom and the button ends up under the controls. min-height
     always wins over the height formula when it's larger, so this only
     kicks in on short viewports and never fights the max-height cap on
     tall ones. */
  min-height: 540px;
  background: var(--bg);
}
.hero-slide {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; justify-content: center;
  opacity: 0; pointer-events: none;
  transition: opacity var(--transition-slide, 600ms ease);
}
.hero-slide.is-active { opacity: 1; pointer-events: auto; z-index: 1; }
/* Right-side panel — diagonal stripe background (or video/image, clipped
   to the same shape), exactly as it originally was. */
.hero-slide__media {
  position: absolute; top: 0; right: 0; bottom: 0;
  /* Text keeps its own left position/max-width (.hero__title etc.) — this
     just pulls the media panel's boundary closer to it (was 62%/860px) so
     the empty gap between text and video/image shrinks and media gets the
     freed-up width, without moving the text column itself. */
  left: max(58%, 720px); overflow: hidden;
  background:
    linear-gradient(100deg, var(--bg) 0%, transparent 12%),
    repeating-linear-gradient(135deg, var(--red) 0 3px, var(--red-dim) 3px 6px);
  /* Fixed 90px lean, not the original 15%-of-box-width: with the new left
     panel's box being a different width than this one, "15% of each box's
     own width" produces two different absolute slopes — they'd only look
     parallel by coincidence at whatever width made both boxes equally
     wide. A shared fixed-px lean is the only way to guarantee the same
     angle regardless of how wide either box actually is. */
  clip-path: polygon(90px 0, 100% 0, 100% 100%, 0% 100%);
  opacity: 0.94;
}
.hero-slide__video, .hero-slide__image { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* Mirrored stripe panel on the left, diagonal edge parallel to the right
   panel's — grows with .wrap's own centering margin on wide viewports and
   shrinks to nothing on narrower ones, so it can never reach far enough
   right to touch the text: the boundary is derived from the same "how far
   left can text go" formula .hero-slide__inner's centering uses, minus a
   40px safety margin, with the same 90px top/bottom lean as the right
   panel so the two cuts read as genuinely parallel. */
.hero-slide::before {
  content: "";
  position: absolute; top: 0; left: 0; bottom: 0;
  width: max(0px, calc((100vw - 1180px) / 2 + 24px - 40px));
  background: repeating-linear-gradient(135deg, var(--red) 0 3px, var(--red-dim) 3px 6px);
  clip-path: polygon(0 0, 100% 0, calc(100% - 90px) 100%, 0 100%);
  opacity: 0.94;
}
.hero-slide__scrim { position: absolute; inset: 0; background: linear-gradient(0deg, var(--bg) 0%, transparent 22%); }
/* width:100% is required here: .wrap's margin:0 auto disables flexbox's
   default cross-axis stretch (per spec, auto margins on the cross axis
   opt an item out of stretch), so without an explicit width this shrinks
   to fit each slide's own text instead of the row — different title
   lengths per slide then centered to different widths, producing a
   different left edge per slide instead of a consistent one. */
.hero-slide__inner { position: relative; width: 100%; padding-top: 80px; padding-bottom: 60px; }
/* Cap each text block so a long admin entry never blows up the slide: eyebrow
   to 1 line, title/summary to 2 — anything past that ellipses. min-height is
   the other half of this: it reserves that same space (in em, so it scales
   with each element's own font-size) even when a slide's actual text is
   shorter or its lede is empty, so every slide occupies the same block
   height and the CTA button doesn't jump up/down as the carousel advances
   between slides with different amounts of text. */
.hero-slide__inner .eyebrow {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  min-height: 1.6em; /* 1 line at this element's inherited line-height: 1.6 */
}
/* Carries the size/weight that the h1 element rule used to supply — the slide
   headline is an h2 now (the page's single h1 is the sr-only one at the top of
   home.php), so the visual scale has to come from the class instead. */
.hero__title {
  max-width: 620px;
  font-size: clamp(2.6rem, 6vw, 4.6rem); font-weight: 800;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  min-height: 2.1em; /* 2 lines at the h1/h2/h3 line-height: 1.05 */
}
.hero__lede {
  font-size: 1.2rem; color: var(--muted); max-width: 540px; margin-bottom: 2em;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  min-height: 3.2em; /* 2 lines at the inherited body line-height: 1.6 */
}
.hero__actions { display: flex; gap: 16px; flex-wrap: wrap; }
/* A longer cta_label wrapping to 2 lines was the last source of height
   difference between slides (109px vs 83px) — the button grows wider
   instead, which is the normal way a button handles longer text. */
.hero__actions .btn { white-space: nowrap; }

/* ---- Carousel controls ---- */
/* Positioned between the two side panels' actual edges (not just viewport-
   center) since they're different widths — reuses the same boundary
   formulas as .hero-slide::before (left) and .hero-slide__media (right)
   so this tracks them exactly at any viewport width. Overrides the .wrap
   class already on this element in the markup: margin/max-width/padding
   are reset here since positioning is fully explicit instead. */
.hero-carousel__controls {
  position: absolute; bottom: 28px; z-index: 2;
  left: max(0px, calc((100vw - 1180px) / 2 - 16px));
  right: calc(100vw - max(58vw, 720px));
  margin: 0; max-width: none; padding: 0;
  display: flex; align-items: center; justify-content: center; gap: 20px;
}
.hero-carousel__arrow {
  background: transparent; border: 1px solid var(--line); border-radius: 50%;
  width: 40px; height: 40px; display: flex; align-items: center; justify-content: center;
  color: var(--ink); cursor: pointer; flex-shrink: 0;
  transition: background var(--transition-base), border-color var(--transition-base);
}
.hero-carousel__arrow:hover { background: var(--ink); color: #fff; border-color: var(--ink); }
.hero-carousel__arrow svg { width: 18px; height: 18px; }
.hero-carousel__dots { display: flex; gap: 10px; }
.hero-carousel__dot {
  width: 10px; height: 10px; border-radius: 50%; padding: 0;
  background: var(--line); border: none; cursor: pointer;
  transition: background var(--transition-base), transform var(--transition-base);
}
.hero-carousel__dot:hover { background: var(--muted); }
.hero-carousel__dot.is-active { background: var(--red); transform: scale(1.2); }

.hero__ticker {
  position: relative; z-index: 1;
  border-top: 1px solid var(--line);
  background: var(--bg-alt);
}
.hero__ticker-inner { display: flex; gap: 0; }
.ticker-item {
  flex: 1; padding: 28px 24px; text-align: center;
}
.ticker-item__icon {
  width: 48px; height: 48px; margin: 0 auto 14px; display: block;
  fill: none; stroke: var(--muted); stroke-width: 4;
  stroke-linecap: round; stroke-linejoin: round;
}
.ticker-item__value {
  display: block; font-family: var(--font-display); font-size: 2rem;
  font-weight: 800; color: var(--red); margin-bottom: 6px;
}
.ticker-item__label {
  display: block; font-size: 0.75rem; text-transform: uppercase;
  letter-spacing: 0.08em; color: var(--muted);
}

/* ---- Sections ---- */
.section { padding: 72px 0; }
.section--alt { background: var(--bg-alt); }
.section__head { margin-bottom: 36px; }
.page-header { padding: 64px 0 40px; background: var(--bg-alt); }
.two-col { display: grid; grid-template-columns: 2fr 1fr; gap: 48px; }

/* ---- Homepage services row ---- */
/* Centered icon above text like the hero__ticker/counters band, but on the
   page's own background (no gray strip) with a slim divider between items
   instead — icons in red, title using the ticker label's plain/uppercase
   treatment rather than the display font, and a smaller .btn since this
   section reads at a smaller scale than the hero carousel. */
.services-row { display: flex; gap: 0; }
.services-row__item {
  flex: 1; padding: 40px 32px; text-align: center;
  border-right: 1px solid var(--line);
}
.services-row__item:last-child { border-right: none; }
.services-row__icon {
  display: block; width: 48px; height: 48px; margin: 0 auto 16px;
  fill: none; stroke: var(--red); stroke-width: 4;
  stroke-linecap: round; stroke-linejoin: round;
}
.services-row__item h3 {
  font-family: var(--font-body); font-size: 0.75rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink);
  margin: 0 0 20px;
}

/* ---- /corpo-de-bombeiros/bombeiros — rank hierarchy ---- */
/* Quadro de Comando: same "icon/count/label above a divider" shape as the
   services row and homepage ticker, but the rank-insignia image standing in
   for the icon and a real headcount standing in for the ticker's stat. */
.ranks-command { display: flex; gap: 0; }
.ranks-command__item {
  flex: 1; padding: 36px 24px; text-align: center;
  border-right: 1px solid var(--line);
}
.ranks-command__item:last-child { border-right: none; }
.ranks-command__badge {
  display: block; height: 108px; width: auto; margin: 0 auto 18px;
  border-radius: var(--radius); box-shadow: 0 1px 3px rgba(20, 20, 20, 0.15);
}
/* Cadete/Infante/etc. with no artwork yet — same footprint as a real badge
   (width guessed at the ~0.63 aspect ratio the actual insignia PNGs share). */
.ranks-command__badge--placeholder {
  width: 68px;
  background: repeating-linear-gradient(135deg, var(--surface-2) 0 8px, var(--bg-alt) 8px 16px);
}
.ranks-command__count {
  display: block; font-family: var(--font-display); font-size: 2rem;
  font-weight: 800; color: var(--red); margin-bottom: 6px;
}
.ranks-command__name {
  display: block; font-size: 0.75rem; text-transform: uppercase;
  letter-spacing: 0.08em; color: var(--muted);
}

/* Quadro Ativo: one column per career path, each a vertical "ladder" reading
   senior (top) to estagiário (bottom) — a thin line strung behind the badges
   is what actually reads as hierarchy, not just a stack of equal rows. */
.ranks-active { display: grid; grid-template-columns: repeat(3, 1fr); gap: 40px; }
.ranks-active__head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  margin: 0 0 22px; padding-bottom: 12px; border-bottom: 2px solid var(--red);
}
.ranks-active__title {
  font-family: var(--font-body); font-size: 0.85rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink);
  margin: 0;
}
/* Career total — same scale as the Quadro de Comando counts, so the two
   sections read as the same kind of number even though this one sums a
   whole column instead of labelling a single badge. */
.ranks-active__total {
  font-family: var(--font-display); font-size: 2rem; font-weight: 800;
  color: var(--red); line-height: 1; flex-shrink: 0;
}
.ranks-active__ladder { list-style: none; margin: 0; padding: 0; position: relative; }
.ranks-active__ladder::before {
  content: ""; position: absolute; left: 21px; top: 4px; bottom: 4px;
  width: 1px; background: var(--line);
}
.ranks-active__tier {
  position: relative; display: flex; align-items: center; gap: 16px; padding: 9px 0;
}
.ranks-active__badge {
  position: relative; z-index: 1; flex-shrink: 0;
  width: 42px; height: 67px; object-fit: cover; border-radius: var(--radius);
  /* Halo matches this section's own background (section--alt), so the
     connector line reads as passing behind the badge, not through it. */
  box-shadow: 0 0 0 4px var(--bg-alt);
}
/* Cadetes, Infantes and any future entry with no rank-insignia artwork yet —
   same footprint as a real badge so the ladder's line/spacing don't shift. */
.ranks-active__badge--placeholder {
  background: repeating-linear-gradient(135deg, var(--surface-2) 0 6px, var(--bg-alt) 6px 12px);
}
.ranks-active__body {
  display: flex; align-items: baseline; justify-content: space-between;
  flex: 1; gap: 12px; min-width: 0;
}
.ranks-active__name { font-size: 0.92rem; color: var(--ink); }
.ranks-active__tier-count {
  font-family: var(--font-display); font-size: 1.1rem; font-weight: 800;
  color: var(--red); flex-shrink: 0;
}

/* Quadro de Honra / Quadro de Reserva: a single figure, not a rank — same
   structure for both, side by side in one section, Honra breaking from
   red-as-the-only-accent into gold since that's the distinction being
   marked, Reserva staying on-brand red via the --red modifier below. */
.honor-boards { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; }
.honor-board { text-align: center; }
.honor-board--red .honor-board__count { color: var(--red); }
.honor-board .section__head { margin-bottom: 8px; }
/* "Quadro de Honra" and "Quadro de Reserva" are different lengths — left to
   wrap naturally, one can fold to a second line before the other does at
   some in-between viewport width, pushing its badge/count down a row out
   of line with its neighbour. Locking both to one line guarantees the two
   columns always match, at every width. */
.honor-board .eyebrow, .honor-board h2 { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Backdrop matches the rank-badge PNGs' own navy and the buttons' corner
   radius, so the transparent honra.png symbol reads as part of the same
   badge family instead of floating loose on the section background. */
.honor-board__symbol-wrap {
  display: flex; align-items: center; justify-content: center;
  width: 140px; height: 140px; margin: 0 auto 8px;
  background: var(--badge-navy); border-radius: var(--radius);
}
.honor-board__symbol { display: block; width: 100px; height: 100px; }
.honor-board__count {
  display: block; font-family: var(--font-display); font-size: 4rem;
  font-weight: 800; line-height: 1; color: var(--gold);
}

/* ---- Cards / grids ---- */
.grid { display: grid; gap: 24px; }
.grid--vehicles { grid-template-columns: repeat(3, 1fr); }
.grid--news { grid-template-columns: repeat(3, 1fr); }
.grid--events { grid-template-columns: repeat(3, 1fr); }
.grid--events-preview { grid-template-columns: repeat(4, 1fr); }

.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden;
  box-shadow: 0 1px 2px rgba(20,20,20,0.04);
  transition: transform var(--transition-base), box-shadow var(--transition-base);
}
.card:hover { transform: translateY(-4px); box-shadow: 0 12px 24px rgba(20,20,20,0.1); }
.card__media { position: relative; aspect-ratio: 4/3; background: var(--surface-2); overflow: hidden; }
.card__media img { width: 100%; height: 100%; object-fit: cover; }
.card__media--placeholder {
  width: 100%; height: 100%;
  background: repeating-linear-gradient(135deg, var(--surface-2) 0 14px, var(--bg-alt) 14px 28px);
}
.card .tag {
  position: absolute; top: 12px; left: 12px;
  background: var(--red); color: #fff; font-family: var(--font-mono);
  font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em;
  padding: 4px 10px; border-radius: 2px;
}
.card__body { padding: 18px; }
/* One treatment for every content-card title (news, veículos, eventos). News
   and event titles each declared this separately while vehicle cards silently
   kept the condensed display font — same component, three different headings.
   Declared once here so any future card type inherits it automatically. */
.card__body h3 { margin-bottom: 6px; font-family: var(--font-body); font-weight: 700; }
.card__body a { color: var(--ink); }

/* Whole card is clickable, not just the title — the title link grows an
   invisible ::after covering the card (the "stretched link" pattern), so
   there's still only one real <a>, no nested/duplicate links. */
.card--news { position: relative; }
.card--news h3 a::after { content: ""; position: absolute; inset: 0; }
.card--event .card__date {
  text-align: center; padding: 18px; background: var(--bg-alt);
  border-bottom: 1px solid var(--line);
}
.card--event .card__date .day {
  display: block; font-family: var(--font-display); font-size: 2rem;
  font-weight: 800; color: var(--red); line-height: 1;
}
.card--event .card__date .month {
  display: block; font-size: 0.75rem; letter-spacing: 0.08em;
  color: var(--muted); margin-top: 4px;
}
.card--event .card__body .event-list__location { margin-bottom: 8px; }
.card--event .card__body p:last-child { margin-bottom: 0; }

/* Every event card lines up on title/time/location regardless of text
   length — clamp the title to 2 lines (reserving that height even when
   the title is short) and truncate the single-line time to fit. */
.card--event__title {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; min-height: 2.3em;
}
.event-list__time { flex-wrap: nowrap; }
.event-list__time .event-list__text {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
/* Homepage preview cards have no description, so location is also capped
   to a single truncated line to keep every card the same height. */
.grid--events-preview .event-list__location { flex-wrap: nowrap; }
.grid--events-preview .event-list__location .event-list__text {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
/* Full events page has more room: let location wrap up to 2 lines
   (ellipsis beyond that), with the pin icon pinned to the first line
   instead of centering across both. */
.grid--events .event-list__location {
  display: grid; grid-template-columns: 14px 1fr; align-items: start; gap: 6px;
}
.grid--events .event-list__location .event-list__icon { margin-top: 3px; }
.grid--events .event-list__location .event-list__text {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  min-height: 3.2em; /* reserves 2 lines even for 1-line locations, so the divider below always lands at the same height */
}
.card--event__desc { font-family: var(--font-body); font-size: 1rem; }
.card--event__divider { border: none; border-top: 1px solid var(--line); margin: 14px 0; }

/* ---- Event list ---- */
.event-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 1px; background: var(--line); }
.event-list__item { display: flex; gap: 20px; background: var(--surface); padding: 18px 20px; align-items: flex-start; }
.event-list__date {
  font-family: var(--font-mono); text-align: center; min-width: 56px;
  background: var(--bg-alt); border-radius: var(--radius); padding: 8px 0; flex-shrink: 0;
}
.event-list__date .day { display: block; font-size: 1.3rem; color: var(--red); font-weight: 700; }
.event-list__date .month { display: block; font-size: 0.7rem; color: var(--muted); letter-spacing: 0.08em; }
.event-list__time, .event-list__location {
  display: flex; align-items: center; gap: 6px; margin: 0 0 4px;
}
.event-list__location { margin-bottom: 8px; }
.event-list__icon {
  width: 14px; height: 14px; flex-shrink: 0;
  fill: none; stroke: var(--muted); stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}
.event-list__body { display: flex; flex-wrap: wrap; gap: 8px 32px; flex: 1; min-width: 0; }
.event-list__meta { flex: 1 1 220px; min-width: 200px; }
.event-list__desc { flex: 2 1 320px; margin: 0; color: var(--muted); }

/* ---- Forms ---- */
.form { display: flex; flex-direction: column; gap: 18px; margin-top: 8px; }
.form__row { display: flex; flex-direction: column; gap: 6px; }
.form__row label { font-size: 0.85rem; font-weight: 600; }
.form__row input[type="text"],
.form__row input[type="email"],
.form__row textarea {
  background: var(--surface); border: 1px solid var(--line); color: var(--ink);
  padding: 12px 14px; border-radius: var(--radius); font-family: var(--font-body); font-size: 1rem;
}
/* Border tint is an extra affordance, NOT the focus indicator — `outline: none`
   used to leave keyboard users with only this subtle colour shift to go on.
   The global :focus-visible ring now applies here like everywhere else. */
.form__row input:focus, .form__row textarea:focus { border-color: var(--red); }
.form__row--checkbox { flex-direction: row; align-items: flex-start; gap: 10px; font-size: 0.9rem; color: var(--muted); }
.form__row--checkbox input { margin-top: 4px; }

/* Honeypot: visually hidden but present in the DOM/tab order excluded. */
.hp-field { position: absolute; left: -9999px; top: -9999px; }

.alert { padding: 16px 18px; border-radius: var(--radius); margin-bottom: 20px; }
.alert--success { background: rgba(46,125,50,0.08); border: 1px solid var(--success); color: #1E5221; }
.alert--error { background: rgba(225,38,28,0.06); border: 1px solid var(--red); color: var(--red-dim); }
.alert ul { margin: 0; padding-left: 20px; }

/* ---- Footer ----
   Deliberately dark against an otherwise light site — an anchor at
   the bottom of the page and the one place the old charcoal palette
   survives, purely for contrast. */
.site-footer { background: var(--footer-bg); border-top: 1px solid var(--footer-line); color: var(--footer-ink); }
.site-footer .brand__text { color: var(--footer-ink); }
.site-footer .brand__sub { color: var(--footer-muted); }
.footer-accred__mark { max-width: 220px; height: auto; }
.site-footer__inner {
  display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 32px;
  padding: 48px 24px;
}
.footer-col h3 {
  font-family: var(--font-mono); font-size: 0.8rem; text-transform: uppercase;
  letter-spacing: 0.08em; color: var(--footer-muted); margin-bottom: 12px;
}
.footer-col ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.footer-col ul a { color: var(--footer-ink); }
.footer-col .muted { color: var(--footer-muted); }
.site-footer__legal { padding: 16px 24px; border-top: 1px solid var(--footer-line); font-size: 0.8rem; color: var(--footer-muted); }

/* Contact column: icon + text rows (address can wrap to 2 lines, icon
   pinned to the first one — same grid-alignment trick as the event cards'
   location line), then the social icons as their own row underneath. */
.footer-contact__item {
  display: grid; grid-template-columns: 16px 1fr; align-items: start; gap: 10px;
  margin: 0 0 14px; font-size: 0.9rem; color: var(--footer-ink);
}
.footer-contact__item:last-of-type { margin-bottom: 20px; }
.footer-contact__item a { color: var(--footer-ink); }
.footer-contact__icon {
  width: 16px; height: 16px; margin-top: 2px; flex-shrink: 0;
  fill: none; stroke: var(--footer-muted); stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}
.site-footer .social-links a { color: var(--footer-ink); }

/* ---- Prose (news article body) ---- */
.prose { font-size: 1.05rem; }
.prose__cover { border-radius: var(--radius); margin-bottom: 28px; }
.prose h2 { margin-top: 1.4em; }
.prose p { color: var(--ink-soft); }
.attachment-link { margin-top: 2em; }
.attachment-link a {
  display: inline-block; color: var(--ink); background: var(--bg-alt);
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 10px 16px; font-weight: 600; font-size: 0.9rem;
}
.attachment-link a:hover { border-color: var(--red); text-decoration: none; }

/* ---- Responsive ---- */
@media (max-width: 900px) {
  .grid--vehicles, .grid--news, .grid--events, .grid--events-preview { grid-template-columns: repeat(2, 1fr); }
  .two-col { grid-template-columns: 1fr; }
  .services-row { flex-direction: column; }
  .services-row__item { border-right: none; border-top: 1px solid var(--line); }
  .services-row__item:first-child { border-top: none; }
  .ranks-command { flex-direction: column; }
  .ranks-command__item { border-right: none; border-top: 1px solid var(--line); }
  .ranks-command__item:first-child { border-top: none; }
  .ranks-active { grid-template-columns: 1fr; gap: 32px; }
  .honor-boards { grid-template-columns: 1fr; gap: 40px; }
  .site-footer__inner { grid-template-columns: 1fr 1fr; }
  /* left:40% used to be the rule here, but the math never works: the title/
     lede can extend to ~644px from the left edge (see .hero__title's own
     max-width), and 40% of anything ≤900px tops out at 360px — guaranteed
     overlap, not just at one unlucky width. Hiding the panel below the same
     900px breakpoint the nav already collapses at removes the fragile
     partial-width zone entirely instead of chasing a percentage that fits. */
  .hero-slide__media, .hero-slide::before { display: none; }
  .hero-carousel { height: min(60vh, 680px); }
  /* No side panels at this width, so the desktop between-the-two-panels
     math doesn't apply — just center in the full row like everything
     else does at this breakpoint. */
  .hero-carousel__controls { left: 0; right: 0; }
}

/* Header collapses to a hamburger at its own, wider breakpoint — the nav
   now carries two dropdowns ("Associação", "Corpo de Bombeiros") plus
   Notícias/Eventos/Contactos, so its natural width no longer fits next to
   the logo and phone number below ~1000px (measured: brand ~174px + nav
   ~604px + phone ~125px + gaps, against the 1180px wrap). Below that, text
   was wrapping inside the nav items ("Corpo de Bombeiros" onto 2 lines)
   and overlapping the logo instead of collapsing cleanly, since flex items
   without white-space:nowrap shrink-wrap their text before the row itself
   would ever wrap. Give it real margin at 1100px rather than 900px. */
@media (max-width: 1100px) {
  .nav__menu {
    position: absolute; top: 100%; left: 0; right: 0; z-index: 50;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--bg); border-top: 1px solid var(--line);
    box-shadow: 0 8px 16px rgba(20,20,20,0.08);
    display: none;
  }
  .nav__menu.is-open { display: flex; }
  .nav__menu li { border-bottom: 1px solid var(--line); }
  /* This panel is still light (see .nav__menu background above), but the base
     rule now sets --footer-ink for the dark header bar — put it back to dark
     text here since these links render against the white panel, not the bar. */
  .nav__menu a { display: block; padding: 16px 24px; color: var(--ink); }
  /* The submenu is a floating card on desktop; here it's just an inline
     accordion under its own toggle, inside the same full-width mobile panel. */
  .nav__item--dropdown { position: static; }
  .nav__dropdown-toggle { width: 100%; justify-content: space-between; padding: 16px 24px; color: var(--ink); }
  .nav__submenu {
    position: static; margin: 0; padding: 0; background: var(--bg-alt);
    border: none; border-radius: 0; box-shadow: none;
  }
  .nav__submenu li { border-bottom: 1px solid var(--line); }
  .nav__submenu li:last-child { border-bottom: none; }
  .nav__submenu a { padding: 14px 24px 14px 36px; }
  .nav__toggle {
    display: flex; flex-direction: column; gap: 4px; background: none; border: none;
    padding: 8px; cursor: pointer;
  }
  /* The toggle button itself sits in the dark bar (not the white panel it
     opens), so its bars need the light color, unlike the links above. */
  .nav__toggle span { width: 22px; height: 2px; background: var(--footer-ink); }

  /* The centered "auto" nav column only works when brand/aside are also
     "auto"-sized against 1fr — otherwise there isn't enough room for the
     full brand lockup AND a centered column, and the toggle button ends up
     overlapping the logo. Give brand/aside their natural width and let the
     (now much smaller, toggle-only) nav float in the remaining flexible
     space instead of trying to center it. */
  .site-header__inner { grid-template-columns: auto 1fr auto; column-gap: 12px; }
  .nav { justify-self: end; }
}
@media (max-width: 640px) {
  .grid--vehicles, .grid--news, .grid--events, .grid--events-preview { grid-template-columns: 1fr; }
  .hero__ticker-inner { flex-direction: column; }
  .ticker-item { border-bottom: 1px solid var(--line); }
  .ticker-item:last-child { border-bottom: none; }
  .hero-carousel__controls { bottom: 16px; }
  .site-footer__inner { grid-template-columns: 1fr; }

  /* Keep the emergency phone number reachable even at the smallest sizes
     in the cramped header row (the footer's own .social-links, a separate
     full-width row, has plenty of room and stays visible). */
  .phone-link__number { display: none; }
  .header-aside { gap: 12px; }
}
