/* DMRNET Bandmeister Network — static site
   Visual language follows www.penangaprs.com: Exo-ish sans, orange action
   buttons with a sliding chevron, green-header striped tables, centered
   copyright footer. Written from scratch; no framework, no third-party fetch. */

/* Exo, latin subset, self-hosted — variable weight, one 21KB file. */
@font-face {
  font-family: Exo;
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  /* relative to this stylesheet: assets/css/ -> assets/fonts/ */
  src: url("../fonts/exo-latin.woff2") format("woff2");
}

:root {
  --orange: #f4511e;
  --orange-dark: #d03d0f;
  --green: #04aa6d;
  --teal: #006a72;   /* the banner wordmark */
  --ink: #2b2b2b;
  --muted: #666;
  --rule: #ddd;
  --stripe: #f5f5f5;
  --page: #fff;
  --max: 900px;
  /* Width at which the banner stops growing — see .masthead and .nav, which
     both key off it so the menu keeps its position on the artwork. */
  --banner-max: 1920px;
}

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

/* Column layout with a full-viewport minimum: the footer takes the leftover
   space via margin-top:auto, so it sits on the bottom edge when the page is
   short, and still flows below the content when the page is tall. dvh accounts
   for the collapsing browser chrome on mobile; vh is the fallback. */
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
  margin: 0;
  padding: 0;
  background: var(--page);
  color: var(--ink);
  font-family: Exo, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 17px;
  line-height: 1.6;
  -webkit-text-size-adjust: 100%;
}

/* ---------- layout ---------- */

.container {
  width: 100%;
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 20px;
}

/* Full-bleed hero. The banner is a background layer rather than an <img>: it is
   decoration, not a link, so it carries no click target. aspect-ratio reserves
   exactly the height the artwork needs at any width, which keeps the menu from
   jumping while the image loads. The URL is set inline on the element so it
   keeps its cache-busting stamp. */
.masthead {
  padding: 0;
  position: relative;   /* anchors the last-heard line over the artwork */
  flex: 0 0 auto;   /* never let the flex column squash the banner's aspect box */
  aspect-ratio: 2313 / 1000;
  /* The banner is the only element on the page that tracks viewport width —
     everything else rides in a centred 900px container. Because the aspect box
     derives its height from that width, an ultrawide display stretches the
     artwork past the point where it reads as a banner and pushes the menu off
     the bottom (2560px wide asks for 1107px of banner on a 1080px screen).
     Capping the width at a full-size desktop and centring the leftover space
     makes every display 1920px and wider render the banner identically to a
     24" monitor. Narrower screens are unaffected: the cap never engages. */
  width: 100%;
  max-width: var(--banner-max);
  margin-inline: auto;
  background-position: center top;
  background-repeat: no-repeat;
  background-size: 100% auto;
}

/* On a phone the artwork is only about 170px tall, far too short to hold the
   last-heard line inside it: the desktop offset resolves to roughly 143px and
   drops the line below the wordmark, inverting the order the desktop reads in
   (activity first, then the logo). Rather than shrink the text — it is already
   at its floor — give the banner a band above the artwork and sit the artwork
   on the bottom edge of it. The order then matches the desktop at every width,
   and the menu moves down with the banner because it follows in normal flow. */
@media screen and (max-width: 700px) {
  .masthead {
    /* Height of the empty band above the artwork. The header is this plus the
       artwork, so on a 390px phone 181 + 169 = 350px. Raising this is how the
       banner and, with it, the menu are moved down; the artwork keeps its own
       proportions because it is sized from the viewport width, not from here. */
    --band: 181px;
    aspect-ratio: auto;
    height: calc(100vw / 2.313 + var(--band));
    background-position: center bottom;
  }
}

/* The matching .lastheard override lives further down, immediately after the
   rule it has to beat — a media query adds no specificity, so placing it here
   would lose to the later plain .lastheard rule. */

/* ---------- navigation ---------- */

.nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  padding: 20px 0 10px;
  margin-bottom: 30px;
  /* the submenu anchors to the bar, not to its toggle - see .nav-menu */
  position: relative;
}

/* Sit the menu on top of the banner's lower band, which is pale map silhouette
   and empty space, so dark menu text stays legible over it. The offset is a
   percentage, so it resolves against the viewport width and tracks the banner's
   height as it scales: the banner is 43.2% of the width tall, so each 1% here
   is a little over 2% of the banner. Below 700px the banner is too short to
   host the menu without covering the wordmark, so the menu drops back into
   normal flow. */
@media screen and (min-width: 701px) {
  .nav {
    position: relative;
    z-index: 1;
    margin-top: -9.3%;
  }
}

/* Past the banner's cap the artwork stops growing, so this offset has to stop
   growing with it — a percentage keeps resolving against the viewport and would
   drag the menu further up the wordmark the wider the display gets (on a 2560px
   ultrawide, -238px against a banner that is still only 830px tall). Freezing it
   at the same -9.3% of the capped width holds the menu exactly where it sits on
   a 1920px monitor, for every display from here up.

   The breakpoint repeats the 1920px literal because media queries cannot read
   custom properties; it must be kept in step with --banner-max. */
@media screen and (min-width: 1920px) {
  .nav {
    margin-top: calc(var(--banner-max) * -0.093);
  }
}

.nav a {
  display: inline-block;
  padding: 8px 16px;
  border-radius: 4px;
  color: var(--ink);
  font-size: 16px;
  text-decoration: none;
  transition: background-color .2s, color .2s;
}

.nav a:hover {
  background: var(--stripe);
  color: var(--orange);
}

.nav a[aria-current="page"] {
  background: var(--orange);
  color: #fff;
}

/* ---------- navigation: grouped dropdowns ---------- */

/* Deliberately not a positioning context: the row of links is centred under the
   whole nav bar instead of under the Connect toggle, which sits near the right
   edge and would otherwise push a wide submenu off screen. */
.nav-group {
  position: static;
}

.nav-group-toggle {
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: 16px;
  cursor: pointer;
  transition: background-color .2s, color .2s;
}

.nav-group-toggle:hover,
.nav-group-toggle[aria-expanded="true"] {
  background: var(--stripe);
  color: var(--orange);
}

.nav-group.is-active > .nav-group-toggle {
  background: var(--orange);
  color: #fff;
}

.caret {
  display: inline-block;
  margin-left: 6px;
  border-top: 5px solid currentColor;
  border-right: 4px solid transparent;
  border-left: 4px solid transparent;
  vertical-align: middle;
}

/* One row of links rather than a stacked list. It is centred on its toggle and
   capped to the viewport, and the entries wrap only when a narrow screen leaves
   them no room. */
.nav-menu {
  display: none;
  position: absolute;
  top: calc(100% + 4px);
  left: 50%;
  z-index: 20;
  /* Without max-content the box is laid out in the space left of the 50% offset
     - half the bar - and the links wrap into three rows. max-content sizes it
     to the single-line width; max-width only bites on genuinely narrow screens. */
  width: max-content;
  max-width: min(94vw, 1000px);
  padding: 6px;
  transform: translateX(-50%);
  border: 1px solid var(--rule);
  border-radius: 4px;
  background: var(--page);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .12);
}

.nav-group-toggle[aria-expanded="true"] + .nav-menu,
.nav-group:hover .nav-menu,
.nav-group:focus-within .nav-menu {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 2px;
}

.nav-menu a {
  white-space: nowrap;
}

/* ---------- modal (penangaprs "Connect" pattern) ---------- */

body.modal-open {
  overflow: hidden;
}

/* The overlay itself never scrolls — it is a fixed frame with an even margin on
   all four sides. Long pages scroll inside .modal-body instead, so the box keeps
   its gap at the bottom just like the top, and the close button stays put. */
.modal-overlay {
  display: flex;
  position: fixed;
  z-index: 100;
  inset: 0;
  align-items: center;
  justify-content: center;
  padding: 40px 20px;
  overflow: hidden;
  background: rgba(0, 0, 0, .55);
}

.modal-overlay[hidden] {
  display: none;
}

.modal-box {
  display: flex;
  position: relative;
  flex-direction: column;
  width: 100%;
  max-width: 820px;
  max-height: 100%;   /* the overlay's padding becomes the gap around the box */
  padding: 30px 35px 0;
  border-radius: 6px;
  background: var(--page);
  box-shadow: 0 12px 40px rgba(0, 0, 0, .3);
  animation: modal-in .18s ease-out;
}

@keyframes modal-in {
  from {
    opacity: 0;
    transform: translateY(-12px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .modal-box {
    animation: none;
  }
}

.modal-close {
  position: absolute;
  top: 8px;
  right: 14px;
  color: #e53935;
  font-size: 30px;
  line-height: 1;
  text-decoration: none;
}

.modal-close:hover {
  color: #b71c1c;
}

/* The scrolling region. overscroll-behavior stops the page behind from taking
   over the wheel once the content hits its end. The bottom padding keeps the
   last line off the edge of the box. */
.modal-body {
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-bottom: 35px;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;      /* Firefox */
  -ms-overflow-style: none;   /* old Edge/IE */
}

/* Scrolling stays fully functional — wheel, touch, keyboard, drag — the bar is
   just not painted. WebKit/Blink need the pseudo-element; the two properties
   above cover the rest. */
.modal-body::-webkit-scrollbar {
  display: none;
}

/* With the scrollbar hidden there is nothing to say the content continues past
   the fold, so the box fades out at its bottom edge. It is toggled by script
   and only appears while there is genuinely more to scroll to, otherwise the
   last line of a finished page would sit under a permanent wash. */
.modal-box::after {
  content: "";
  position: absolute;
  right: 2px;
  bottom: 2px;
  left: 2px;
  height: 55px;
  border-radius: 0 0 6px 6px;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0), var(--page) 75%);
  opacity: 0;
  pointer-events: none;
  transition: opacity .15s ease-out;
}

.modal-box.has-more::after {
  opacity: 1;
}

.modal-body > h1:first-child {
  margin-top: 0;
  padding-right: 30px;
}

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

h1,
h2,
h3 {
  line-height: 1.25;
  margin: 1.6em 0 .5em;
  font-weight: 600;
}

h1 {
  margin-top: 0;
  font-size: 30px;
  color: var(--orange);
}

h2 {
  font-size: 23px;
}

h3 {
  font-size: 19px;
}

p {
  margin: 0 0 1em;
}

a {
  color: var(--orange);
}

a:hover {
  color: var(--orange-dark);
}

small {
  color: var(--muted);
}

ul {
  padding-left: 22px;
}

li {
  margin-bottom: .3em;
}

img {
  max-width: 100%;
  height: auto;
}

figure {
  margin: 1.5em 0;
}

blockquote {
  margin: 1.5em 0;
  padding: 15px 20px;
  border-left: 4px solid var(--green);
  background: var(--stripe);
  font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
  font-size: 14px;
  line-height: 1.5;
  overflow-x: auto;
}

blockquote p {
  margin: 0 0 1em;
}

blockquote p:last-child {
  margin-bottom: 0;
}

.email {
  vertical-align: middle;
  margin: 0 2px;
}

.note {
  padding: 12px 16px;
  border-left: 4px solid var(--orange);
  background: var(--stripe);
}

/* ---------- tables ---------- */

.table-wrap {
  overflow-x: auto;
  margin: 1.5em 0;
  -webkit-overflow-scrolling: touch;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 15px;
}

th,
td {
  padding: 8px 10px;
  border: 1px solid var(--rule);
  text-align: left;
  white-space: nowrap;
}

/* the only column that legitimately wraps */
td.wrap {
  white-space: normal;
}

/* a cell spanning several rows reads better aligned to the first of them */
td[rowspan] {
  vertical-align: top;
}

/* Supported / not supported. Colour alone would not distinguish these for a
   colour-blind reader, so the glyphs differ in shape too, and each cell carries
   a hidden "Yes"/"No" for screen readers. */
td.bool {
  text-align: center;
  font-size: 17px;
  line-height: 1;
}

td.yes {
  color: var(--green);
}

td.no {
  color: #e53935;
}

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

thead th {
  padding-top: 12px;
  padding-bottom: 12px;
  background-color: var(--teal);
  color: #fff;
  font-weight: 600;
}

tbody tr:nth-child(even) {
  background-color: var(--stripe);
}

tbody tr:hover {
  background-color: #e9e9e9;
}

/* ---------- FAQ ---------- */

.faq details {
  border-bottom: 1px solid var(--rule);
}

.faq summary {
  padding: 14px 30px 14px 0;
  position: relative;
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}

.faq summary::-webkit-details-marker {
  display: none;
}

.faq summary::after {
  content: "+";
  position: absolute;
  top: 12px;
  right: 4px;
  color: var(--orange);
  font-size: 22px;
  line-height: 1;
}

.faq details[open] summary::after {
  content: "\2013";
}

.faq summary:hover {
  color: var(--orange);
}

.faq .answer {
  padding: 0 0 16px;
  color: #444;
}

.faq .answer p:last-child {
  margin-bottom: 0;
}

/* ---------- last heard ---------- */

/* Sits in the banner's empty upper area, above the wordmark. Absolute inside
   the masthead so it rides with the artwork as the banner scales, and the
   offset is a percentage for the same reason. */
.lastheard {
  display: flex;
  position: absolute;
  right: 0;
  left: 0;
  top: calc(6% + 100pt);
  flex-direction: column;
  gap: 2px;
  font-size: 15px;
  text-align: center;
}

/* Phone: the offset above resolves to about 154px against the 350px header,
   which lands the second row — the station count — under the top edge of the
   artwork, so the wordmark prints straight through it. Fill the band instead
   and centre both rows inside it, clear of the artwork below.

   This has to sit after the rule above, not up with the .masthead media query
   where it belongs by subject: both selectors are a single class, and a media
   query contributes nothing to specificity, so whichever comes last in the file
   wins. Keep the two together if either is ever moved. */
@media screen and (max-width: 700px) {
  .lastheard {
    top: 0;
    height: var(--band);
    justify-content: center;
  }
}

/* Statistics on the About page: both figures on one line, wrapping only when
   the modal is too narrow to hold them. */
.stats-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 32px;
  margin: 0 0 1.2em;
}

.stats-item {
  color: var(--muted);
  font-size: 14px;
  letter-spacing: .04em;
  text-transform: uppercase;
}

.stats-figure {
  margin-right: 6px;
  color: var(--teal);
  font-size: 24px;
  font-weight: 700;
  letter-spacing: 0;
}

/* connected stations, directly under the last-heard line */
.stations-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: baseline;
  gap: 6px;
}

.stations-count {
  color: var(--teal);
  font-size: 16px;
  font-weight: 700;
}

.stations-label {
  color: var(--muted);
  font-size: 13px;
  letter-spacing: .06em;
  text-transform: uppercase;
}

/* one talkgroup per line, its label and callsign kept together */
.lastheard-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: baseline;
  gap: 6px 10px;
}

.lastheard-label {
  color: var(--muted);
  font-size: 13px;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.lastheard-body {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
}

.lastheard-call {
  color: var(--teal);
  font-size: 18px;
  font-weight: 700;
}

.lastheard-name,
.lastheard-when,
.lastheard-idle {
  color: var(--muted);
  font-size: 14px;
}

/* ---------- digital mode logos ---------- */

/* One row, spread across the width. The sources are 340x200 and are shown at
   35%. They wrap onto a second line only when the screen is too narrow to hold
   four across. */
.modes {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-evenly;
  align-items: center;
  gap: 16px;
  padding-top: 10px;
  padding-bottom: 10px;
}

/* Decoration, not content to be grabbed: no text selection, no drag ghost, and
   no long-press image menu on touch. */
.modes img {
  width: 119px;
  height: 70px;
  border-radius: 8px;
  user-select: none;
  -webkit-user-select: none;
  -webkit-user-drag: none;
  -webkit-touch-callout: none;
}

@media screen and (max-width: 560px) {
  /* small enough already; just tighten the gaps so four still fit a phone */
  .modes {
    gap: 8px;
  }
}

/* ---------- footer ---------- */

.site-footer {
  margin-top: auto;   /* absorbs the leftover height, pinning the footer down */
  padding: 30px 0 40px;
  color: var(--muted);
  font-size: 14px;
  text-align: center;
}

.site-footer a {
  color: var(--muted);
}

/* ---------- small screens ---------- */

@media screen and (max-width: 600px) {
  body {
    font-size: 16px;
  }

  h1 {
    font-size: 25px;
  }

  h2 {
    font-size: 20px;
  }

  .nav {
    gap: 4px;
  }

  .nav a {
    padding: 7px 11px;
    font-size: 15px;
  }

  .nav-group-toggle {
    padding: 7px 11px;
    font-size: 15px;
  }

  .modal-overlay {
    padding: 20px 12px;
  }

  .modal-box {
    padding: 25px 18px 0;
  }

  .modal-body {
    padding-bottom: 25px;
  }
}
