/* =====================================================================
   Nantucket Community Television — site styles
   ---------------------------------------------------------------------
   One stylesheet for the whole site. Colors live in :root below, so you
   can re-theme the entire site by editing a few values there.
   ===================================================================== */

:root{
  /* Brand + coastal palette */
  --fog:        #E9ECEA;   /* page background (cool Nantucket fog)      */
  --paper:      #FAFBF9;   /* cards / raised surfaces                   */
  --ink:        #15263B;   /* primary text + structure (deep navy)     */
  --ink-soft:   #4A5A6E;   /* secondary text                           */
  --green:      #71C26D;   /* NCTV brand green (play button)           */
  --green-deep: #2C8A43;   /* green for text on light backgrounds      */
  --sand:       #D6D0C2;   /* hairline rules / weathered dividers      */
  --navy-deep:  #0C1826;   /* dark sections (hero scrim, footer)       */
  --nav-bg:     #0C1826;   /* the header bar -- same as the footer, so   */
                           /* the page is bookended dark at both ends    */
  --nav-ink:    #CFDCD6;   /* nav link text on that bar                  */

  --maxw: 1200px;
  --gut: clamp(20px, 5vw, 64px);

  --serif: "Fraunces", Georgia, "Times New Roman", serif;
  --sans:  "Hanken Grotesk", system-ui, -apple-system, sans-serif;
  --mono:  "Space Mono", ui-monospace, "Courier New", monospace;

  --ease: cubic-bezier(.22,.61,.36,1);
}

/* ---------- reset ---------- */
*,*::before,*::after{box-sizing:border-box}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%;text-size-adjust:100%}
body{
  margin:0;
  background:var(--fog);
  color:var(--ink);
  font-family:var(--sans);
  font-size:20px;
  line-height:1.65;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
img{max-width:100%;display:block}
a{color:inherit}
h1,h2,h3,h4{font-family:var(--serif);font-weight:560;line-height:1.05;margin:0;
  font-optical-sizing:auto}
p{margin:0 0 1.1em}

.wrap{max-width:var(--maxw);margin:0 auto;padding-inline:var(--gut)}

/* mono broadcast eyebrow used throughout */
.eyebrow{
  font-family:var(--mono);
  font-size:1.44rem;
  letter-spacing:.22em;
  text-transform:uppercase;
  color:var(--green-deep);
  display:inline-flex;align-items:center;gap:.6em;
}
.eyebrow .dot{
  width:8px;height:8px;border-radius:50%;background:var(--green);
  box-shadow:0 0 0 0 rgba(79,179,94,.6);
  animation:pulse 2.4s var(--ease) infinite;
}
@keyframes pulse{
  0%{box-shadow:0 0 0 0 rgba(79,179,94,.55)}
  70%{box-shadow:0 0 0 7px rgba(79,179,94,0)}
  100%{box-shadow:0 0 0 0 rgba(79,179,94,0)}
}

/* =====================================================================
   NAV
   ===================================================================== */
/* Dark bar, the footer's colour, since 2026-10-29. It used to be a near-white
   translucent pane over the page -- which at 86% of the page's own background
   barely read as a band at all, and leaned on the dark status strip above it
   for the header to have any weight. The strip is gone, so the bar carries
   that weight itself. One token, --nav-bg, is the whole of the colour. */
.nav{
  position:sticky;top:0;z-index:60;
  background:var(--nav-bg);
  border-bottom:1px solid rgba(255,255,255,.10);
}
/* The header is the one row that does not keep to the 1200px page column.
   Logo, six links and the search box do not fit in that column -- the logo
   was left less width than its artwork and the first link landed on top of
   it -- so the nav spans the window and keeps only the page gutter. */
.nav .wrap{display:flex;align-items:center;gap:20px;height:106px;max-width:none}
.nav__brand{display:flex;align-items:center;flex:0 0 auto}
.nav__brand img{height:clamp(48px,4.1vw,62px);width:auto}
.nav__brand .full{display:block}
/* The links sit against the logo; the search box is pushed to the far end of
   the same row. Until 2026-10-29 the menu took the auto margin and the whole
   group -- links and box together -- travelled right as a block. Now the menu
   grows to fill the row and the box takes the margin, so the links stay left
   and the box stays where it was. */
.nav__menu{flex:1 1 auto;display:flex;align-items:center;gap:2px}
.nav__item{position:relative}
.nav__link{
  position:relative;
  font-family:var(--sans);font-weight:800;
  font-size:clamp(1.04rem,1.42vw,1.44rem);
  letter-spacing:-.015em;color:var(--nav-ink);white-space:nowrap;
  text-decoration:none;padding:9px 9px;border-radius:8px;
  display:inline-flex;align-items:center;gap:8px;cursor:pointer;
  background:none;border:0;
  transition:color .25s var(--ease);
}
/* animated underline that sweeps in on hover / for the current page */
.nav__link::after{
  content:"";position:absolute;left:12px;right:12px;bottom:2px;height:3px;
  background:var(--green);border-radius:3px;
  transform:scaleX(0);transform-origin:left center;
  transition:transform .3s var(--ease);
}
/* On the dark bar the green that reads as "active" on paper goes muddy, so
   the current and hovered links go to white and the green stays in the
   underline, which is where it has the room to be seen. */
.nav__link:hover{color:#fff}
.nav__link:hover::after{transform:scaleX(1)}
.nav__link.is-current{color:#fff}
.nav__link.is-current::after{transform:scaleX(1)}
.nav__link .chev{width:11px;height:11px;border-right:2.5px solid currentColor;
  border-bottom:2.5px solid currentColor;transform:rotate(45deg) translateY(-2px);
  transition:transform .2s var(--ease);opacity:.75}
.nav__item.open .chev{transform:rotate(225deg) translateY(0)}

/* desktop only: bouncy lift on hover for an eye-catching pop */
@media (hover:hover) and (min-width:1201px){
  .nav__link{transition:color .25s var(--ease),
    transform .4s cubic-bezier(.34,1.56,.64,1)}
  .nav__link:hover{transform:translateY(-5px) scale(1.06)}
}

/* dropdown */
.nav__panel{
  position:absolute;top:calc(100% + 8px);left:50%;transform:translateX(-50%) translateY(6px);
  min-width:248px;background:var(--paper);
  border:1px solid var(--sand);border-radius:14px;
  box-shadow:0 20px 50px -24px rgba(12,24,38,.45);
  padding:8px;opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .22s var(--ease),transform .22s var(--ease),visibility .22s;
}
/* invisible bridge: keeps the hover connected across the gap so the menu
   doesn't flicker/close when the mouse travels from the trigger to the panel */
.nav__panel::before{content:"";position:absolute;left:0;right:0;top:-16px;height:16px}
.nav__item.open .nav__panel{opacity:1;visibility:visible;pointer-events:auto;
  transform:translateX(-50%) translateY(0)}
/* desktop: open on hover or keyboard focus (no JS toggle needed) */
@media (hover:hover) and (min-width:1201px){
  .nav__item:hover > .nav__panel,
  .nav__item:focus-within > .nav__panel{opacity:1;visibility:visible;
    pointer-events:auto;transform:translateX(-50%) translateY(0)}
  .nav__item:hover .chev,
  .nav__item:focus-within .chev{transform:rotate(225deg) translateY(0)}
}
.nav__panel a{
  display:flex;align-items:center;gap:10px;text-decoration:none;
  padding:11px 13px;border-radius:9px;font-size:.92rem;font-weight:550;
  color:var(--ink);transition:background .16s var(--ease),color .16s var(--ease)}
.nav__panel a::before{content:"";width:7px;height:7px;border-radius:50%;
  background:var(--sand);flex:0 0 auto;transition:background .16s var(--ease)}
.nav__panel a:hover{background:rgba(79,179,94,.1)}
.nav__panel a:hover::before,.nav__panel a.is-current::before{background:var(--green)}
.nav__panel a.is-current{color:var(--green-deep)}

/* hamburger */
/* Search box, last in the menu row and so in the header's top right corner.
   It stays a quiet outline until focused, so it does not compete with the
   nav links beside it. */
.nav__search{flex:0 0 auto;display:flex;align-items:center;gap:2px;margin-left:auto;
  background:rgba(255,255,255,.09);border:1px solid rgba(255,255,255,.22);
  border-radius:999px;
  padding:3px 4px 3px 12px;
  /* Hard against the right edge of the header. The row now runs the full
     width of the window, so all that stands to the right of it is the page
     gutter; the box is shifted out over that and left 20px clear -- the
     gutter's own floor, so the shift is never negative. It is an offset, not
     a margin, so the box keeps its slot in the row and the links beside it
     do not move; a negative margin would have shortened the row and slid the
     whole menu right with it. */
  position:relative;
  left:calc(var(--gut) - 20px);
  transition:border-color .2s var(--ease),box-shadow .2s var(--ease)}
.nav__search:focus-within{border-color:var(--green);
  box-shadow:0 0 0 3px rgba(113,194,109,.25)}
.nav__search-input{border:0;background:none;outline:none;
  font-family:var(--sans);font-size:1.02rem;color:#fff;
  width:clamp(92px,8vw,152px);padding:6px 0}
.nav__search-input::placeholder{color:rgba(255,255,255,.62);opacity:1}
.nav__search-input::-webkit-search-cancel-button{cursor:pointer}
.nav__search-btn{flex:0 0 auto;display:grid;place-items:center;
  width:32px;height:32px;border:0;border-radius:50%;cursor:pointer;
  background:var(--green);color:#06210d;
  transition:background .2s var(--ease)}
.nav__search-btn:hover{background:#5cc06b}
.nav__search-btn svg{width:16px;height:16px}
.nav__burger{display:none;margin-left:auto;background:none;border:0;cursor:pointer;
  width:44px;height:44px;border-radius:10px}
.nav__burger span{display:block;width:24px;height:2px;background:#fff;
  margin:5px auto;transition:transform .25s var(--ease),opacity .2s var(--ease)}
.nav.is-open .nav__burger span:nth-child(1){transform:translateY(7px) rotate(45deg)}
.nav.is-open .nav__burger span:nth-child(2){opacity:0}
.nav.is-open .nav__burger span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}

/* The drawer takes over at 1200px, not 1100px. The band between those two
   was always the tight one -- it had a rule of its own robbing the header of
   its gutter to buy forty pixels, because the logo, six links and the search
   box did not fit in it. A logo half again as tall and type a size up make
   that band unwinnable rather than tight, so the hamburger starts there
   instead and the gutter-robbing rule is gone. Above 1200px the row fits on
   its own: measured at 1201, 1280, 1440 and 1920 on 2026-10-29. */
@media (max-width:1200px){
  .nav .wrap{height:84px}
  .nav__brand{flex:0 1 auto;min-width:0;overflow:hidden}
  .nav__brand img{height:auto;max-height:48px;max-width:100%}
  .nav__burger{display:block;flex:0 0 auto}
  .nav__menu{
    position:fixed;inset:84px 0 auto 0;flex-direction:column;align-items:stretch;
    gap:0;background:var(--nav-bg);border-bottom:1px solid rgba(255,255,255,.12);
    padding:0 var(--gut);margin:0;
    max-height:0;overflow:hidden;
    transition:max-height .35s var(--ease),padding .35s var(--ease);
    box-shadow:0 24px 40px -28px rgba(12,24,38,.5)}
  /* The padding has to collapse with the panel. max-height:0 cannot squeeze
     padding away, so a closed menu kept a 32px band in which the top of its
     first row -- since the search box, a bordered green button -- showed
     through. */
  .nav.is-open .nav__menu{max-height:92vh;overflow:auto;padding:10px var(--gut) 22px}
  .nav__item{width:100%}
  .nav__link{width:100%;justify-content:space-between;padding:16px 6px;
    font-size:1.6rem;
    border-bottom:1px solid rgba(255,255,255,.12)}
  .nav__link::after{display:none}
  .nav__panel{position:static;transform:none;opacity:1;visibility:visible;
    pointer-events:auto;box-shadow:none;border:0;min-width:0;background:none;
    max-height:0;overflow:hidden;padding:0 0 0 14px;transition:max-height .3s var(--ease)}
  .nav__item.open .nav__panel{transform:none;max-height:520px;padding:4px 0 10px 14px}
  /* The menu is a column here, so the search box goes to the top of it
     rather than trailing the links at the bottom. */
  .nav__panel a{color:var(--nav-ink)}
  .nav__panel a.is-current{color:#fff}
  .nav__panel a:hover{background:rgba(255,255,255,.08)}
  .nav__search{order:-1;margin:2px 0 10px;width:100%;padding:4px 5px 4px 14px;
    position:static}
  .nav__search-input{flex:1 1 auto;width:auto;font-size:1.1rem;padding:9px 0}
  .nav__search-btn{width:38px;height:38px}
  .nav__search-btn svg{width:18px;height:18px}
}

/* =====================================================================
   SEARCH PAGE
   ===================================================================== */
.searchbox{display:flex;align-items:center;gap:10px;max-width:640px;
  background:var(--paper);border:1px solid var(--sand);border-radius:999px;
  padding:5px 6px 5px 20px;
  transition:border-color .2s var(--ease),box-shadow .2s var(--ease)}
.searchbox:focus-within{border-color:var(--green);
  box-shadow:0 0 0 3px rgba(113,194,109,.25)}
.searchbox__input{flex:1 1 auto;min-width:0;border:0;background:none;outline:none;
  font-family:var(--sans);font-size:clamp(1.02rem,1.3vw,1.16rem);color:var(--ink);
  padding:11px 0}
.searchbox__input::placeholder{color:var(--ink-soft);opacity:.75}
.searchbox__btn{flex:0 0 auto;border:0;cursor:pointer;border-radius:999px;
  font-family:var(--mono);font-size:.86rem;letter-spacing:.12em;text-transform:uppercase;
  padding:12px 22px;background:var(--green-deep);color:#fff;
  transition:background .2s var(--ease)}
.searchbox__btn:hover{background:var(--ink)}
/* 404 page: somewhere to go when the address was wrong */
.notfound__links{display:flex;flex-wrap:wrap;gap:12px;margin-top:26px}
.search-status{margin:clamp(18px,2.4vw,26px) 0 0;color:var(--ink-soft);
  font-size:1.02rem;line-height:1.6}
.search-empty{margin:10px 0 0;color:var(--ink-soft)}
/* Results reuse the .watch-episode card the rest of the site uses, with a
   smaller thumbnail so a long list still scans. */
.search-result{margin-top:clamp(26px,3.4vw,40px);
  padding-top:clamp(26px,3.4vw,40px);border-top:1px solid var(--sand)}
.search-result .watch-episode__thumb{width:clamp(220px,26vw,300px)}
.search-result__where{margin:0 0 16px;font-family:var(--mono);font-size:.8rem;
  letter-spacing:.1em;text-transform:uppercase;color:var(--ink-soft)}
.search-result__where a{color:var(--green-deep);text-decoration:none;
  border-bottom:1px solid var(--green)}
.search-result__where a:hover{color:var(--ink);border-color:var(--ink)}
.search-result mark{background:rgba(113,194,109,.34);color:inherit;
  padding:0 2px;border-radius:3px}

/* =====================================================================
   HERO (home)
   ===================================================================== */
.hero{position:relative;min-height:min(86vh,760px);display:flex;align-items:flex-end;
  overflow:hidden;background:var(--navy-deep)}
.hero__media{position:absolute;inset:0;overflow:hidden;z-index:0}
/* fallback photo — always present behind the video */
/* object-position must stay centred: the video iframe is centred by its own
   transform, and each fallback is that video's first frame. Bias the photo and
   the two stop matching, so the cross-fade jumps. It was center 38% while the
   fallback was an unrelated photo of the building. */
.hero__fallback{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:center;
  z-index:2;opacity:1;transition:opacity .4s var(--ease)}
/* width/height as well as inset:0 on purpose. Its sibling .hero__fallback
   has always carried both and has never collapsed; this box, with inset
   alone, measured 0x0 in Safari on every banner page after the first. */
.hero__video{position:absolute;inset:0;width:100%;height:100%;
  overflow:hidden;pointer-events:none;z-index:1}
.hero__media.is-playing .hero__fallback{opacity:0}
/* A Vimeo background embed letterboxes inside its frame, and an iframe has no
   object-fit. So oversize the iframe past the hero on whichever axis is short
   and let .hero__media clip it -- the same cover crop, done by hand.

   The cover maths is done in JS, in _HERO_SCRIPT, from the measured hero box.
   It used to live here, as container query units against a container-type:size
   on .hero__video. Do not put that back. WebKit resolved those units to zero
   on every banner page after the first in a session: the video played, the
   player reported ready, playing and an advancing currentTime, and it did all
   of that inside an iframe computed at 0x0, so the banner showed the hero's
   own background and looked for all the world like a video that would not
   load. Chromium resolved them correctly throughout, so it reproduced nowhere
   but Safari. The 100% pair below is the floor the script sizes up from, and
   what a browser would show if the script never ran: visible, merely
   letterboxed, instead of invisible. */
.hero__video iframe{
  position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  width:100%;height:100%;
  border:0;pointer-events:none}
.hero__scrim{position:absolute;inset:0;
  background:
    linear-gradient(180deg,rgba(12,24,38,.55) 0%,rgba(12,24,38,.2) 38%,rgba(12,24,38,.82) 100%),
    radial-gradient(120% 80% at 20% 100%,rgba(12,24,38,.7),transparent 60%)}
.hero__inner{position:relative;z-index:2;width:100%;padding-block:54px 60px}

.hero h1{color:#fff;font-size:clamp(2.6rem,7.2vw,6rem);letter-spacing:-.02em;
  max-width:16ch;text-wrap:balance}
.hero h1 em{font-style:italic;color:var(--green)}
/* OURnctv wordmark */
.hero__wordmark{font-family:var(--sans);font-weight:800;letter-spacing:-.03em;
  font-size:clamp(3.4rem,12vw,8.5rem);line-height:.92;
  filter:drop-shadow(0 6px 26px rgba(0,0,0,.4));max-width:none}
.hero__wordmark .our{color:#71C26D}
.hero__wordmark .nctv{color:#fff}
.hero__sub{color:#dfe7ea;font-size:clamp(1rem,2vw,1.25rem);max-width:58ch;margin-top:22px}

/* "Click to Watch:" label + channel logo buttons (one row) */
.hero__watch{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin-top:32px}
.hero__watch-label{color:#fff;font-weight:800;font-family:var(--sans);
  font-size:clamp(1.2rem,2vw,1.7rem);letter-spacing:-.01em;margin-right:4px}
.hero-chip{background:#fff;border-radius:16px;height:108px;padding:9px;
  display:inline-flex;align-items:center;justify-content:center;
  box-shadow:0 12px 28px -14px rgba(0,0,0,.6);
  transition:transform .25s var(--ease),box-shadow .25s var(--ease)}
.hero-chip img{max-height:90px;max-width:300px;width:auto;height:auto;object-fit:contain;display:block}
.hero-chip:hover{transform:translateY(-4px);box-shadow:0 18px 34px -14px rgba(0,0,0,.65)}

/* video hero banner for channel pages (reuses hero media/fallback/scrim) */
.vhero{position:relative;min-height:min(58vh,540px);display:flex;align-items:flex-end;
  overflow:hidden;background:var(--navy-deep)}
.vhero .hero__inner{position:relative;z-index:2;width:100%;padding-block:46px 54px}
.vhero .eyebrow{color:#aee0b2}
.vhero__title{color:#fff;font-family:var(--serif);font-weight:560;line-height:1.02;
  font-size:clamp(2.2rem,5.6vw,4.2rem);letter-spacing:-.02em;margin-top:12px}
.vhero .hero__sub{color:#dfe7ea;margin-top:18px}

/* buttons */
.btn{display:inline-flex;align-items:center;gap:10px;font-weight:650;
  font-size:.96rem;text-decoration:none;padding:14px 24px;border-radius:999px;
  cursor:pointer;border:1.5px solid transparent;transition:transform .2s var(--ease),
  background .2s var(--ease),border-color .2s var(--ease),box-shadow .2s var(--ease)}
.btn:hover{transform:translateY(-2px)}
.btn--green{background:var(--green);color:#06210d;box-shadow:0 12px 30px -12px rgba(79,179,94,.7)}
.btn--green:hover{background:#5cc06b}
.btn--ink{background:var(--ink);color:#fff}
.btn--ink:hover{background:#1d3552}
.btn .play{width:0;height:0;border-left:11px solid currentColor;
  border-top:7px solid transparent;border-bottom:7px solid transparent;margin-right:-2px}

/* =====================================================================
   GENERIC PAGE HEADER (interior pages)
   ===================================================================== */
.pagehead{position:relative;background:var(--navy-deep);color:#fff;overflow:hidden}
.pagehead::after{content:"";position:absolute;right:-80px;top:-80px;width:320px;height:320px;
  border:2px solid rgba(79,179,94,.25);border-radius:50%}
.pagehead::before{content:"";position:absolute;right:10px;top:10px;width:150px;height:150px;
  border:2px solid rgba(79,179,94,.18);border-radius:50%}
.pagehead .wrap{position:relative;z-index:2;padding-block:clamp(56px,9vw,104px)}
.pagehead h1{font-size:clamp(2.3rem,5.5vw,4.2rem);color:#fff;margin-top:14px;letter-spacing:-.02em}
.pagehead p{color:#cdd7dc;max-width:60ch;margin-top:18px;font-size:1.05rem}
/* A one-sentence deck rather than the start of a column: 60ch cut this one at
   "TV show" and left it 564px under an 889px heading. 48rem clears the
   sentence's own 751px, so it sits on one line beneath the title on a desktop
   and still wraps on a narrow window. */
.pagehead p.pagehead__sub--wide{max-width:48rem}
.pagehead .eyebrow{color:var(--green)}

/* =====================================================================
   CUSTOM CHANNEL HERO (Watch dropdown pages)
   ===================================================================== */
.chero{position:relative;overflow:hidden;color:#fff}
.chero::after{content:"";position:absolute;right:-90px;top:-90px;width:340px;height:340px;
  border:2px solid rgba(255,255,255,.18);border-radius:50%}
.chero::before{content:"";position:absolute;right:30px;top:30px;width:170px;height:170px;
  border:2px solid rgba(255,255,255,.12);border-radius:50%}
.chero__inner{position:relative;z-index:2;display:flex;align-items:center;
  gap:clamp(26px,4vw,56px);flex-wrap:wrap;padding-block:clamp(44px,7vw,80px)}
.chero__card{background:#fff;border-radius:22px;padding:20px 28px;flex:0 0 auto;
  display:inline-flex;align-items:center;justify-content:center;
  box-shadow:0 26px 54px -26px rgba(0,0,0,.55)}
.chero__card img{height:clamp(94px,12vw,148px);width:auto;max-width:340px;
  object-fit:contain;display:block}
.chero__card svg{height:clamp(86px,11vw,124px);width:auto;display:block}
.chero__text{flex:1 1 320px;min-width:0}
.chero__title{font-family:var(--serif);color:#fff;margin:0;
  font-size:clamp(2.2rem,5vw,3.7rem);line-height:1.04;letter-spacing:-.02em}
.chero__sub{margin:14px 0 0;max-width:54ch;color:rgba(255,255,255,.92);
  font-size:clamp(1rem,1.5vw,1.18rem);line-height:1.5}
/* brand gradients */
/* Every banner fades between exactly two colours (Frank, 2026-10-26). The
   25 that ran three or four stops were reduced to their first and last, so
   each keeps the range it was designed around and only the interpolation
   changes. Add a banner the same way: a dark end under the logo card, the
   organization's own colour at the other. */
/* Dreamland — deep navy to aqua, picking up the navy in the logo */
.chero--dreamland{background:linear-gradient(135deg,#0a1f36 0%,#4bb3c4 100%)}
/* visually-hidden (kept for screen readers / page structure) */
.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: the first thing the Tab key reaches on every page, so a keyboard
   or screen-reader visitor can jump the nine nav links and the search box and
   go straight to the content. It sits off the top edge until it is focused,
   then drops into the corner. Not .sr-only, which cannot be made visible. */
.skip-link{position:absolute;top:-60px;left:14px;z-index:200;
  padding:12px 20px;border-radius:0 0 12px 12px;
  background:var(--green-deep);color:#fff;font-weight:650;text-decoration:none;
  transition:top .15s var(--ease)}
.skip-link:focus{top:0}
/* The element the skip link lands on is the page's own hero or banner, made
   focusable with tabindex="-1" so the keyboard really moves there. It is not
   a control, so it should not draw a focus ring the width of the page; the
   skip link itself is the visible cue that focus moved. */
#main:focus{outline:none}
/* Sports page top: two sections stacked left, NSC Student Crew banner down the right */
/* Sports Connection: the same film strip treatment as .civic-banner, which is
   where the reasoning is written out -- the 2px hairline because this strip is
   painted the nav's own colour and the two run together without it, and no
   background of its own because the sprocket holes are transparent and show
   whatever is behind them. Keep the two rules in step; they are the same
   artwork template cut to the same widths. */
.sports-banner{padding-top:2px}
.sports-banner picture{display:block}
.sports-banner img{display:block;width:100%;height:auto}
.section.sports-intro{padding-block:25px 14px}
.section.sports-sponsors{padding-block:12px 40px}
/* The closing banner follows the Signup block, so it takes the same gap the
   blocks above it use rather than the 12px that suits the top banner sitting
   under the intro. */
.section.sports-sponsors--end{padding-top:clamp(48px,6vw,100px)}
.sports-sponsors__img{display:block;width:100%;height:auto;border-radius:12px}
/* Clickable sponsor logos sit over the banner image, as the film-poster map
   does on the Shorts Fest page. Most logos are discs, so the ring is an
   ellipse inscribed in the hotspot; one that is a rounded rectangle overrides
   the radius inline. White rather than green, to read against the banner. */
.sponsormap{position:relative;display:block}
.sponsormap__btn{position:absolute;display:block;border-radius:50%;
  transition:background .18s var(--ease),box-shadow .18s var(--ease)}
.sponsormap__btn:hover,.sponsormap__btn:focus-visible{outline:none;
  background:rgba(255,255,255,.22);box-shadow:0 0 0 3px #fff}
/* ---- Nantucket Life + Nonprofit Videos pages (shared banner/intro layout) ---- */
.nl-banner img,.np-banner img{display:block;width:100%;height:auto}
/* Both of these are film strips now, like .civic-banner and .sports-banner,
   so they take their two rules as well: the 2px hairline because the strip is
   painted the nav's own colour, and no background of its own because the
   sprocket holes are transparent and show whatever is behind them. All four
   banners want these in step -- see CLAUDE.md. */
.nl-banner,.np-banner{padding-top:2px}
.nl-banner picture,.np-banner picture{display:block}
[data-page="videos-nantucket-life.html"] .section,
[data-page="videos-partner-programs.html"] .section{padding-block:clamp(30px,4vw,58px)}
.section.nl-intro,.section.np-intro{padding-block:25px 14px}
.nl-intro__grid,.np-intro__grid{display:flex;flex-wrap:wrap;align-items:center;gap:clamp(24px,4vw,54px)}
.nl-intro__logo,.np-intro__logo{width:clamp(185px,23vw,250px);height:auto;flex:0 0 auto;display:block}
.nl-intro__text,.np-intro__text{flex:1 1 340px;min-width:0;margin:0;
  font-size:20px;line-height:1.6;color:var(--ink-soft)}
.nl-intro__lead,.np-intro__lead{font-family:var(--serif);font-weight:600;color:var(--green-deep);
  font-size:1.24em;line-height:1.3;display:inline-block;margin-bottom:6px}
/* Sponsor banner — matches the New Moon Fest sponsors treatment */
.section.nl-sponsors{padding-top:12px}
.nl-sponsors__img{display:block;width:100%;height:auto;border-radius:12px}
/* ---- Dreamland partner page ---- */
/* The line back to the Nonprofit Videos hub, directly under a partner
   page's banner. Same size and colour as the website link at the foot of
   the mission, so the two read as the same kind of line. Its spacing is
   padding on the section rather than a margin on the paragraph, so the
   mission below keeps its own. */
.section.dl-backlink{padding-block:clamp(18px,2.4vw,28px) 0}
.dl-backlink__text{margin:0;font-size:clamp(1.05rem,1.35vw,1.22rem);color:var(--ink-soft)}
.section.dl-mission{padding-block:clamp(28px,4vw,46px) 0}
.dl-mission__text{margin:0;font-size:20px;
  line-height:1.65;color:var(--ink-soft)}
/* Matches the lead-line treatment used on Nantucket Life, Shorts Fest and
   New Moon Fest, so section leads read consistently across the site. */
.dl-mission__lead{font-family:var(--serif);font-weight:600;color:var(--green-deep);
  font-size:1.08em}
.dl-mission__link{margin:14px 0 0;font-size:clamp(1.05rem,1.35vw,1.22rem);color:var(--ink-soft)}
/* An aside under the intro -- its own line, set italic so it reads as a note
   rather than another sentence of the paragraph above. */
.dl-mission__note{margin:14px 0 0;font-style:italic;
  font-size:clamp(1rem,1.25vw,1.12rem);color:var(--ink-soft)}
.dl-group__body{padding-bottom:clamp(18px,2.4vw,28px)}
.dl-group__body .watch-episode:first-of-type{margin-top:6px}
/* Year picker for lecture archives (Atheneum). Buttons share the movie-btn
   pill look; one year's panel is shown at a time. */
.yearpick__btns{display:flex;flex-wrap:wrap;gap:10px;padding:2px 0 clamp(16px,2.2vw,24px)}
.year-btn,.live-btn{font-family:var(--mono);font-size:.95rem;padding:9px 16px;border-radius:20px;
  border:1px solid var(--sand);background:var(--paper);color:var(--ink);cursor:pointer;
  transition:border-color .18s var(--ease),background .18s var(--ease),color .18s var(--ease)}
.year-btn:hover,.live-btn:hover{border-color:var(--green)}
.year-btn.is-active,.live-btn.is-active{background:var(--green-deep);color:#fff;
  border-color:var(--green-deep)}
/* A year that has no photos yet. Kept visible so the archive's full span is
   obvious, but dashed and dimmed so it plainly is not a live control. The
   button carries the real disabled attribute, so this is appearance only. */
.year-btn:disabled{opacity:.45;cursor:default;border-style:dashed}
.year-btn:disabled:hover{border-color:var(--sand)}
/* A picker whose buttons carry words rather than a year: the NHA's "Browse
   by Topic" and "Browse by NHA Program". Sixteen subject names in the mono
   face at the year size run far too wide, so these take the sans face and
   wrap as a block of choices. Everything else about the pill -- border,
   radius, hover, active state -- is the year button's.

   The child combinators matter: several of these panels hold a year picker
   of their own, and a descendant selector would put the real years in the
   sans face too. */
.yearpick--labels > .yearpick__btns{gap:8px 10px}
.yearpick--labels > .yearpick__btns > .year-btn{font-family:var(--sans);
  font-size:1rem;font-weight:500;padding:9px 18px;text-align:left}
.year-panel[hidden]{display:none}
.year-panel .watch-episode:first-of-type,
.show-episodes .watch-episode:first-of-type{margin-top:0}
/* With no year buttons above them the episodes would start hard against the
   row's rule, so the list carries the same inset at the top as the cell has
   at the bottom. */
.show-episodes{padding-top:clamp(18px,2.4vw,30px)}
.dl-cosponsor{font-family:var(--sans);font-size:.56em;color:var(--ink-soft);
  font-weight:400;letter-spacing:0}
.dl-empty{margin:0;padding:2px 0 8px;color:var(--ink-soft);font-style:italic}
/* A note set once at the top of a section, for text that would otherwise be
   repeated on every card in it -- the Arts Council says the same paragraph
   about the Emergence series on all four episodes. Sized and coloured like a
   card description so it does not read as a second heading. */
.dl-group__intro{margin:0 0 clamp(14px,1.8vw,20px);max-width:72ch;line-height:1.6;
  color:var(--ink-soft);font-size:clamp(1rem,1.2vw,1.12rem)}
/* Linda Loring — the logo's purple deepening into the green of its leaf mark */
.chero--lindaloring{background:linear-gradient(135deg,#2A0E42 0%,#7E9433 100%)}
/* Atheneum — the deep navy of its wordmark, warming toward a lamplit gold */
.chero--atheneum{background:linear-gradient(135deg,#00143C 0%,#9C7B3F 100%)}
/* Book Festival — the logo is black on a white card, so the gradient is free to
   be warm; burgundy to amber keeps it distinct from the navy
   Atheneum and Dreamland heroes */
.chero--bookfest{background:linear-gradient(135deg,#2E0F1B 0%,#D98C3F 100%)}
/* NHA — the logo is dark slate, so the hero follows it: deep slate out to
   weathered shingle grey, the colours of the island's old houses.
   Cool and quiet where the Book Festival is warm, and greyer than the navy
   Atheneum and Dreamland heroes */
.chero--nha{background:linear-gradient(135deg,#1C222B 0%,#8D9AA6 100%)}
/* Past TV Shows table — the first table on the site, so it sets the pattern.
   Fixed layout so the columns keep the proportions set here rather than being
   sized by their contents: Description is the widest and is the one that wraps,
   while the two date columns stay narrow. Below roughly 720px four columns
   cannot hold their shape, so the table keeps its width and the wrapper
   scrolls sideways instead of crushing every cell. */
/* Sort hint over the table. Quieter than the intro's note above it, and not
   italic, because it explains the controls rather than adding an aside to the
   text. Its margin is the only gap over the header row, whose padding-top is 0. */
.shows__hint{margin:0 0 clamp(12px,1.6vw,18px);color:var(--ink-soft);
  font-size:clamp(.95rem,1.1vw,1.05rem)}
.shows__scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
.shows__table{width:100%;min-width:760px;border-collapse:collapse;table-layout:fixed}
.shows__table th,.shows__table td{text-align:left;vertical-align:top;
  padding:clamp(12px,1.6vw,18px) clamp(10px,1.2vw,16px);
  border-bottom:1px solid var(--sand)}
/* No nowrap: the headings carry their own <br>, so they break where they are meant
   to and wrap further only when a line will not fit -- which is what happens to
   "Ep. Date" once the table is down to its minimum width on a phone. */
.shows__table thead th{font-family:var(--mono);font-size:.82rem;letter-spacing:.11em;
  text-transform:uppercase;color:var(--green-deep);border-bottom-width:2px;
  padding-top:0}
/* A sortable heading is a real button, so it can be reached by keyboard. It
   inherits the heading's type rather than the browser's. The caret shows
   which way the column is sorted, and sits faint until it is the active one. */
/* A show name opens its episodes, so it is a green pill in the same language as
   the sport and year buttons elsewhere on the site: outlined at rest, filled
   while its episodes are open. The caret turns to match. */
.shows__name{font-family:var(--mono);font-size:.95rem;letter-spacing:.04em;line-height:1;
  color:var(--ink);background:var(--paper);border:1px solid var(--sand);border-radius:999px;
  padding:10px 16px;cursor:pointer;text-align:left;display:inline-flex;align-items:center;gap:9px;
  transition:background .18s var(--ease),color .18s var(--ease),
             border-color .18s var(--ease),transform .18s var(--ease)}
.shows__name::after{content:"";width:7px;height:7px;flex:0 0 auto;
  border-right:2px solid currentColor;border-bottom:2px solid currentColor;
  transform:translateY(-2px) rotate(45deg);transition:transform .2s var(--ease)}
.shows__name:hover,.shows__name:focus-visible{background:var(--green);border-color:var(--green);
  color:#04210f;transform:translateY(-2px);outline:none}
.shows__name[aria-expanded="true"]{background:var(--green-deep);border-color:var(--green-deep);
  color:#fff;transform:none}
.shows__name[aria-expanded="true"]::after{transform:translateY(1px) rotate(-135deg)}
/* The episodes span the whole table, so the rest of the rows carry on below. */
.shows__panel>td{padding:0 0 clamp(18px,2.4vw,30px)}
.shows__panel[hidden]{display:none}
.shows__sort{font:inherit;letter-spacing:inherit;text-transform:inherit;color:inherit;
  background:none;border:0;padding:0;cursor:pointer;display:inline-flex;align-items:center;
  gap:7px;text-align:left}
.shows__sort::after{content:"";width:7px;height:7px;flex:0 0 auto;opacity:.33;
  border-right:2px solid currentColor;border-bottom:2px solid currentColor;
  transform:translateY(-2px) rotate(45deg);transition:transform .18s var(--ease),opacity .18s var(--ease)}
.shows__sort:hover::after{opacity:.7}
th[aria-sort="ascending"] .shows__sort::after{opacity:1;transform:translateY(1px) rotate(-135deg)}
th[aria-sort="descending"] .shows__sort::after{opacity:1}
.shows__table tbody th{font-family:var(--serif);font-weight:400;
  font-size:clamp(1.1rem,1.5vw,1.3rem);letter-spacing:-.01em;color:var(--ink)}
.shows__table td{font-size:clamp(.98rem,1.2vw,1.08rem);line-height:1.55;color:var(--ink-soft)}
/* The date headings break before "Ep.", so each column need only hold "Ep. Date"
   rather than "First Ep." -- 10px narrower apiece, which goes to Description,
   the widest column now that Topic sits between it and the name. */
.shows__table thead th:nth-child(1){width:20%}
.shows__table thead th:nth-child(2){width:13%}
.shows__table thead th:nth-child(3){width:44%}
/* 11.5% is what "Ep. Date" needs beside its sort caret: 76px of text, 7px of
   caret, a 7px gap and 31px of cell padding. Narrower and the heading wraps to
   three lines on a desktop, which is what the <br> was meant to avoid. */
.shows__table thead th:nth-child(4),.shows__table thead th:nth-child(5){width:11.5%}
/* Once the table is down to its 760px minimum the percentages leave the first two
   columns short: "Independence" inside its pill wants 187px and the name column
   has 152px, and "Conservation" wants 104px against 99px. Neither word can break,
   so the two columns take what they need from Description, which wraps freely. */
@media (max-width:1100px){
  .shows__table thead th:nth-child(1){width:25%}
  .shows__table thead th:nth-child(2){width:14%}
  .shows__table thead th:nth-child(3){width:38%}
}
/* NCTV's own programming: the house navy running up into the brand green,
   so the green play mark on the white card sits against its own colour. */
/* Live TV. NCTV's own banner, so it is the house navy fading to the house
   green rather than an outside organization's colours, and the wordmark sits
   straight on it -- the white card the partner banners use is there to give a
   coloured logo something to sit on, and this one is already white. */
/* The light end is --green-deep rather than the --green the Past TV Shows
   banner fades to. This is the one banner whose subtitle carries coloured
   text, and at #71C26D the right-hand end of that line sits on a background
   bright enough that white itself only reaches 3.07:1 -- measured off the
   rendered page, not estimated -- so nothing could be added beside it that
   stayed legible. Pulled back to #2C8A43 the same line runs 5.1:1 to 8.3:1.
   Still two stops, still dark to the house green. */
.chero--live{background:linear-gradient(135deg,#0C1826 0%,#2C8A43 100%)}
/* NCTV green lightened until it clears the green behind it. The brand green
   itself reads at 2.1:1 there, which is a colour you can see but not read. */
.chero--live .chero__ch{color:#9FE8A8;font-weight:700;white-space:nowrap}
.chero--live .chero__card{background:none;padding:0;box-shadow:none;border-radius:0}
.chero--live .chero__card img{height:clamp(84px,11vw,140px);max-width:none}

/* The embedded player. The frame holds its 16:9 whatever the window does, so
   the page does not reflow when the stream's own size is known, and the black
   under it is what shows while TelVue is still connecting. */
.livetv{padding-block:clamp(26px,3.6vw,46px)}
.livetv__picker{display:flex;flex-wrap:wrap;gap:10px;margin:0 0 16px}
.livetv__frame{position:relative;aspect-ratio:16/9;width:100%;background:#000;
  border:1px solid var(--sand);border-radius:16px;overflow:hidden;
  box-shadow:0 26px 60px -34px rgba(12,24,38,.6)}
.livetv__frame iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
.livetv__note{margin:16px 0 0;font-size:1.02rem;color:var(--ink-soft);max-width:68ch}
.livetv__note a{color:var(--green-deep);font-weight:600}

.chero--pastshows{background:linear-gradient(135deg,#0C1826 0%,#71C26D 100%)}
/* This logo is the full lockup, and its wordmark is white -- on the white
   card every partner logo sits on, the words vanish. So no card here: the
   mark goes straight onto the gradient, a little larger to carry the type. */
.chero--pastshows .chero__card{background:none;padding:0;box-shadow:none;border-radius:0}
.chero--pastshows .chero__card img{height:clamp(132px,17vw,208px);max-width:none}
/* Civic League: the island's moors, deep pine to dune grass.
   The logo is pure black line art, so the dark end of the gradient sits
   under the logo card where the two would otherwise fight. */
.chero--civicleague{background:linear-gradient(135deg,#0E2318 0%,#8FA86B 100%)}
/* Golf Club Foundation: drawn from the logo itself — the navy of the oval
   running out to the sand of the dune grass beneath the flag. Deliberately
   not another plain blue: the logo is already blue, so the banner carries
   its secondary colors instead. */
.chero--ngcf{background:linear-gradient(135deg,#0A2A4A 0%,#E0C169 100%)}
/* WPI crimson, read off the logo artwork itself (#C20F2E). */
.chero--wpi{background:linear-gradient(135deg,#3F0710 0%,#C20F2E 100%)}
/* Remain: the wordmark is a slate blue over a brick red, with a grey
   wharf-post mark between the two lower words. The run goes red to blue in
   that order so the banner ends on the colour the name itself is set in.
   #803938 and #4E8ABD are sampled from the logo file itself. */
.chero--remain{background:linear-gradient(135deg,#4A2120 0%,#4E8ABD 100%)}

/* Community Foundation: the 20th-anniversary mark is a navy ring (#092A6C)
   around a yellow sunburst (#F6D737), both sampled from the logo file. The run
   goes navy to gold so the banner finishes on the sunburst rather than the
   ring. The gold is pulled back from the logo's value, as on the Nantucket
   Golf Club Foundation banner, so white hero text still holds at the far end. */
.chero--cfn{background:linear-gradient(135deg,#04193F 0%,#DCC055 100%)}

/* NFFRA: the house mark is one flat blue (#398EB6) with a coral heart in it
   (#F0596C), both read off the logo file. The run goes deep harbour blue to
   the heart, pulled down a shade from the logo's coral so white hero text
   still holds. The coral end is what keeps it apart from the Cottage Hospital
   and Land Council banners, which open on a similar blue. */
.chero--nffra{background:linear-gradient(135deg,#0E2B3A 0%,#E8697A 100%)}

/* Biodiversity Initiative: the logo is a pen-and-ink drawing, black on white,
   so there is nothing in it to sample. The run comes from what it draws --
   Nantucket, Tuckernuck and Muskeget and their waters, with a harrier over the
   sandplain grassland -- so it runs from deep water to the gold of that
   grassland in autumn. The deep teal start is what
   keeps it off the Golf Club Foundation banner, which arrives at a brighter
   gold from navy, and the gold end off the Civic League's run of pure greens. */
.chero--biodiversity{background:linear-gradient(135deg,#0B2A2E 0%,#B3A05C 100%)}
/* Two stops, not the four the other org banners use: Frank asked for a
   straight fade between two colours. Both are sampled from the Pond
   Coalition's own seal -- the navy of the water below the surface, and
   the green of the ring. */
.chero--pondcoalition{background:linear-gradient(135deg,#152445 0%,#0F8B55 100%)}

/* Arts Council: two stops again. #CD0512 is the single red the whole
   wordmark is set in -- there is no second colour in the mark to run to,
   so the fade is that red out of a darkened version of itself. */
.chero--artscouncil{background:linear-gradient(135deg,#3C0409 0%,#CD0512 100%)}

/* Rossini Club: two stops, both the Club's own. #1F325B is the navy its
   site is built on, and the end is the blush it pairs with that navy
   (#E9B5AA) taken down to a readable depth -- the blush itself is far too
   light to carry the white banner title. */
.chero--rossini{background:linear-gradient(135deg,#1F325B 0%,#9A3C28 100%)}

/* Conservation Foundation: the mark is a single cranberry red (#900020 over
   nearly half the artwork), which is also WPI's family of reds, so the run
   ends in heath green instead of brightening. Cranberry into moorland is the
   Foundation's own ground -- it farms the Milestone bogs and manages the
   grasslands around them -- and the green end keeps it apart from the WPI
   banner at a glance. */
.chero--conservation{background:linear-gradient(135deg,#38000F 0%,#6F8B4E 100%)}
/* Chamber blue and navy, both read off the logo artwork. */
.chero--chamber{background:linear-gradient(135deg,#00183F 0%,#2869D5 100%)}
/* Cottage Hospital: built around the shield blue sampled from the logo
   (#306090), running from slate navy up to a pale mist. Kept desaturated on
   purpose — it reads calm rather than corporate, and stays clear of the
   vivid blue used for Nantucket Life. */
.chero--cottagehospital{background:linear-gradient(135deg,#0F1E2E 0%,#9FBBD2 100%)}
/* Land & Water Council: the periwinkle-indigo of the seal, opening deep and
   running out to the eelgrass green of the moors — land and water, in that
   order. The indigo start keeps it clear of the navy-to-emerald used on the
   nonprofit index page. */
.chero--landwater{background:linear-gradient(135deg,#171C3A 0%,#7E9B76 100%)}
/* Film Festival: the logo is black line art with no colour of its own, so the
   banner is dusk over the water — a screening-under-the-stars run from
   near-black to a rose horizon. The warm end is rose rather
   than the amber the Book Festival uses, so the two read apart. */
.chero--filmfest{background:linear-gradient(135deg,#0B0D18 0%,#C58A7A 100%)}
/* School Videos. The three school logos are all black-and-white island
   silhouettes, so the banners carry the colour: charcoal to a pale brass,
   for the lamp in the district seal. */
.chero--school{background:linear-gradient(135deg,#14181F 0%,#C9B486 100%)}
/* The two school banners sit inside the page rather than atop it, so they are
   shorter, flatter and without the hero's decorative rings. Each keeps a tint
   of its own so the eye can tell the sections apart while scrolling. */
.chero--nhs{background:linear-gradient(135deg,#1B2A3A 0%,#52788F 100%)}
.chero--cps{background:linear-gradient(135deg,#22303A 0%,#5E8288 100%)}
.chero--org .chero__inner{padding-block:clamp(24px,3.4vw,40px)}
.chero--org .chero__card{padding:14px 20px;border-radius:18px}
.chero--org .chero__card img{height:clamp(64px,7.5vw,92px)}
/* one step down from the page hero's title, to match the smaller banner */
.chero--org .chero__title{font-size:clamp(1.5rem,3.2vw,2.35rem)}
.chero--org::before,.chero--org::after{display:none}
/* The Biodiversity Initiative's mark is a pen drawing, mostly white space, with
   the lettering only a third of the artwork, so at the shared 92px it reads far
   smaller than the wordmark logos on the other org banners. Given its own
   height. Must come after .chero--org above: same specificity, later wins. */
.chero--biodiversity .chero__card img{height:clamp(88px,11vw,136px)}
/* The Pond Coalition's mark is a circular seal with its name set around the
   ring, so at the shared 92px the lettering is too small to read. Same
   placement rule as the line above: after .chero--org, equal specificity. */
.chero--pondcoalition .chero__card img{height:clamp(92px,11.5vw,142px)}
/* The Arts Council's artwork is a two-line wordmark sitting in the middle
   third of its canvas -- 87px of ink in 240px -- so at the shared 92px the
   lettering draws about 33px tall, half the size of the other fund marks.
   Raised until its ink matches theirs. Same placement rule: after
   .chero--org, equal specificity. */
.chero--artscouncil .chero__card img{height:clamp(88px,11.5vw,138px)}
/* Watch Now — episode cards */
.watch-episode{display:flex;flex-wrap:wrap;align-items:flex-start;gap:clamp(20px,3vw,38px);
  margin-top:clamp(28px,4vw,44px)}
.watch-episode:first-of-type{margin-top:0}
.watch-episode__thumb{position:relative;flex:0 0 auto;width:clamp(280px,40vw,440px);
  aspect-ratio:16/9;border-radius:12px;overflow:hidden;display:block;background:#0b1622;
  box-shadow:0 16px 36px -26px rgba(12,24,38,.55)}
/* Absolute, not a percentage height: inside a <table> (the Past TV Shows list)
   Safari resolves height:100% against the table row, which made object-fit:cover
   enlarge the image ~3x and overflow:hidden clip it to a sliver. */
.watch-episode__thumb img{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;display:block}
.watch-episode__text{flex:1 1 320px;min-width:0}
.watch-episode__title{font-family:var(--serif);font-size:clamp(1.4rem,2.4vw,1.9rem);
  letter-spacing:-.01em;margin:0 0 10px;line-height:1.15}
/* Telly Award trophy — scales with the title it sits beside */
.award-trophy{width:.95em;height:.95em;vertical-align:-.10em;margin-left:.32em;
  flex:0 0 auto}
.watch-episode__desc,.watch-episode__note{margin:0 0 16px;line-height:1.6;
  color:var(--ink-soft);font-size:clamp(1rem,1.2vw,1.12rem)}
/* The line that introduces a document button sitting under the title rather
   than beside the watch link -- the vote summary does, because it is what the
   meeting decided. It reads as a description but is never clamped: it is one
   sentence, and the button it points at has to stay with it. */
.watch-episode__note{margin-bottom:10px}
.watch-episode__note+.watch-episode__doc-btn{margin-bottom:16px}
/* <cite> marks titles of works (books, films). Browsers italicize it by
   default, but say so explicitly so the look can't drift. */
.watch-episode__desc cite{font-style:italic}
/* A line of provenance at the foot of a description -- where the footage came
   from someone other than the video's publisher. A span rather than <em>,
   which a screen reader reads with vocal stress: this is an aside, not
   emphasis. Same reasoning as <cite> above. */
.watch-episode__desc .desc-credit{font-style:italic}
/* A production credit under the thumbnail, for the few videos NCTV did not
   make itself. These marks are square, so the logo is set two lines tall and
   the wording stacks to its left rather than running alongside at text size.
   The mono face and .9rem match "Click to See More" and the watch pill, the
   other two small controls in the same card.

   width:fit-content so the block is only as wide as its contents: the media
   column is as wide as the thumbnail, and a stretched credit would put the
   logo far out to the right of the words. 2.9em is the two lines the text
   occupies at this line-height, which is what keeps the mark square-on with
   them. */
.video-credit{display:flex;align-items:center;gap:12px;width:fit-content;
  font-family:var(--mono);font-size:1rem;
  letter-spacing:.02em;line-height:1.45;color:var(--ink-soft);
  /* The media column is as wide as the thumbnail and stacks its children at
     the left; this one sits at the right instead, so the mark lines up with
     the thumbnail's right edge. */
  align-self:flex-end}
/* Right-aligned so both lines end on the logo's left edge rather than
   leaving the shorter one short of it. */
.video-credit__text{text-align:right}
/* Only this line is clickable -- the wording above it and the mark beside it
   are not -- so the hover sits here rather than on the whole block. It keeps
   the block's own colour so the look does not change; the underline is what
   marks it as the link. */
.video-credit__cta{color:inherit;text-decoration:underline;
  text-underline-offset:3px}
.video-credit__cta:hover{color:var(--ink)}
.video-credit__logo{flex:0 0 auto;height:2.9em;width:auto;border-radius:4px}
/* The Town's wording runs to 33 characters against Yellow's 17, so at the
   shared size its block came within 40px of the thumbnail's full width and
   read as a second caption rather than a credit. Only the font-size moves:
   the mark is 2.9em and the gap is set in px, so the whole block steps down
   together. Frank asked for it smaller, 2026-10-25.

   The size is what keeps "Created by the Town of Nantucket's" on one line, so
   it has to track the column the block sits in: .watch-episode__media is
   clamp(280px,40vw,440px), and the line gets that less the 2.9em mark and the
   12px gap. The ends are measured from the longer line at each limit, with a
   little headroom; in between it follows the column's own 40vw ramp. Frank
   asked for two lines on 2026-10-27, when it was running to three on a
   desktop and five in a narrow window.

   Compound selector because the type scale further down this file sets
   .video-credit to 1.18rem. That is one class, like this modifier, and it
   comes later, so a single .video-credit--sm lost to it and the block had
   been rendering at full size everywhere. */
.video-credit.video-credit--sm{font-size:clamp(10.6px,1.52vw,16.8px)}

/* Government 101 blurbs close with a link to the department's own page; no
   meeting description carries one, so the rule starts here. */
.watch-episode__desc a{color:var(--green-deep);text-decoration:underline;text-underline-offset:3px}
.watch-episode__desc a:hover{color:var(--ink)}
/* Long descriptions collapse to ten lines with a toggle beneath. The limit is
   CSS so it reflows with the viewport; site.js only decides whether a given
   description actually overflows and needs the control. */
.watch-episode__desc.is-clamped{display:-webkit-box;-webkit-box-orient:vertical;
  -webkit-line-clamp:10;overflow:hidden}
/* block, so "Click here to watch" drops to the line beneath rather than
   sitting alongside; width:fit-content keeps the hit area to the text */
.watch-episode__more{display:block;width:fit-content;margin:-10px 0 16px;
  padding:0;background:none;border:0;text-align:left;
  font-family:var(--mono);font-size:.9rem;letter-spacing:.02em;
  color:var(--green-deep);cursor:pointer}
.watch-episode__more:hover{text-decoration:underline}
/* Both rules above set `display`, which outranks the browser's own
   [hidden]{display:none} -- so the agenda button could unhide the agenda but
   not hide a clamped description or its toggle. Spell it out here so the swap
   is a real swap and not a pile-up. */
.watch-episode__desc[hidden],.watch-episode__more[hidden]{display:none}
.watch-episode__link{display:inline-block;font-family:var(--mono);font-size:.9rem;
  letter-spacing:.02em;color:#fff;background:var(--green-deep);padding:11px 20px;
  border-radius:24px;text-decoration:none;transition:background .18s var(--ease)}
.watch-episode__link:hover{background:var(--ink)}
/* A second pill beside "Click here to watch" that swaps the description for
   the meeting agenda. Same pill as the watch link; the gap keeps the two from
   running together, and flex-wrap drops it below on a narrow card. */
.watch-episode__actions{display:flex;flex-wrap:wrap;gap:10px;align-items:center}
/* Cards that carry an agenda stack the watch link under the thumbnail, which
   frees the spot beneath the description for the agenda button. The column
   takes the width the thumbnail used to set, so the image is unchanged. */
.watch-episode__media{flex:0 0 auto;display:flex;flex-direction:column;
  align-items:flex-start;gap:14px;width:clamp(280px,40vw,440px)}
/* A divider under a card that needs a little more air beneath it than the
   usual gap gives. Fades out at both ends so it reads as decoration rather
   than as the hard structural border the accordion rows use. */
.watch-episode__rule{border:0;height:1px;margin:clamp(30px,4vw,46px) 0 0;
  background:linear-gradient(90deg,transparent,var(--sand) 18%,
    var(--sand) 82%,transparent)}
.watch-episode__media .watch-episode__thumb{width:100%}
.watch-episode__link--alt{border:0;cursor:pointer;font-family:var(--mono)}
/* The agenda itself. Same colour and measure as a description, but it is a
   nested list rather than prose and is never line-clamped: the reader asked
   for it, so show the whole thing. */
.watch-episode__agenda{margin:0 0 16px;line-height:1.55;color:var(--ink-soft);
  font-size:clamp(1rem,1.2vw,1.12rem)}
.watch-episode__agenda p{margin:0 0 12px}
.watch-episode__agenda ol{margin:0;padding-left:1.5em}
.watch-episode__agenda>ol{list-style:upper-roman}
.watch-episode__agenda ol ol{list-style:lower-alpha;margin:6px 0 10px;
  padding-left:1.4em}
.watch-episode__agenda ol ol ol{list-style:decimal}
.watch-episode__agenda li{margin:0 0 6px}
.sports-intro__grid{display:flex;flex-wrap:wrap;align-items:center;gap:clamp(24px,4vw,50px)}
.sports-intro__logo{width:clamp(250px,32vw,360px);height:auto;flex:0 0 auto;display:block}
.sports-intro__text{flex:1 1 320px;min-width:0;margin:0;
  font-size:20px;line-height:1.55;color:var(--ink-soft)}
.sports-top{padding:30px 0 0}
/* The blocks used to be flex children of a column that supplied this gap;
   with the column gone they space themselves. */
.sports-block + .sports-block{margin-top:clamp(48px,6vw,100px)}
.sports-block .section__head{margin-bottom:clamp(18px,2.4vw,26px)}
/* SIGNUP — small text-only block */
.signup__text{font-family:var(--mono);font-size:20px;line-height:1.6;
  color:var(--ink-soft);margin:0}
.signup__text a{color:var(--green);text-decoration:underline;text-underline-offset:3px}
.signup__text a:hover{color:var(--ink)}
/* Civic TV Archive — subtitle groups of playlist buttons */
.archive-group{margin-top:clamp(30px,4.5vw,52px)}
.archive-group:first-of-type{margin-top:0}
/* Same size and weight as the subtitles at .section__head h2 -- this heading sits
   in an .archive-group, not a .section__head, so that rule cannot reach it. Kept a
   separate rule because its margins differ; keep the two sizes in step. */
.archive-group h2{font-size:1.4rem;font-weight:400;letter-spacing:-.01em;
  margin:0 0 clamp(14px,2vw,20px)}
/* Civic TV: clean banner image (no fade), with logo + text moved below it.
   The <picture> wrapper is inline by default, which would leave a text
   descender's worth of gap under a full-bleed hero; the img rule alone
   cannot reach it. Four crops of the film strip are swapped by width --
   see civic_banner() in build.py for the frame geometry. */
/* 2px of daylight between the nav bar and the film strip, asked for on
   2026-10-30 once the strip was painted --nav-bg and the two ran together.
   Set at 5px first and trimmed to 2px the same day, so treat it as a measured
   value rather than a round number someone picked -- it is a hairline on
   purpose, not a gap that wants rounding up.
   Padding, not margin, so it cannot collapse into anything above it. The band
   shows the page background -- the same --fog the transparent sprocket holes
   show -- so it reads as part of the perforation rather than as a rule drawn
   under the nav. Which is the other reason .civic-banner must stay without a
   background of its own: give it one and the gap and the holes both change. */
.civic-banner{padding-top:2px}
.civic-banner picture{display:block}
.civic-banner img{display:block;width:100%;height:auto}
.civic-intro{padding-block:clamp(22px,3vw,38px)}
.section.civic-intro{padding-block:25px 14px}
.civic-intro__grid{display:flex;flex-wrap:wrap;align-items:center;gap:clamp(24px,4vw,52px)}
.civic-intro__logo{width:clamp(128px,15vw,185px);height:auto;flex:0 0 auto;display:block}
.civic-intro__text{flex:1 1 340px;min-width:0;margin:0;
  font-size:20px;line-height:1.55;color:var(--ink-soft)}
/* Helpful Links is a full-width band. It was a narrow column beside the
   archive until 2026-10-11, when the site owner asked for the row; it moved
   below Government 101 the same day. Being last, it closes the page, and its
   top matches the gap Government 101 takes above it. */
.civic-top{padding:clamp(38px,5.2vw,68px) 0 clamp(56px,8vw,104px)}
.civic-links{background:#0B2F80;border-radius:16px;padding:clamp(20px,2.4vw,26px);
  display:flex;flex-direction:column;gap:clamp(12px,1.6vw,18px)}
/* Columns in proportion to the art, not equal ones. Each button's art is
   trimmed to its own label, so a column sized to the widest would set the
   shortest label adrift in empty space -- and equal columns would make the
   longest label the smallest, which is the one thing these buttons cannot do.
   Weighted fr units give all three a single display scale, so one type size
   runs across the row. `--cols` is written by helpful_links_panel() from the
   same widths the art was built at. */
.civic-links__row{display:grid;gap:clamp(12px,1.8vw,22px);
  grid-template-columns:var(--cols,1fr)}
/* Below about 1100px three across would squeeze the lettering under 11px --
   the same width at which the old equal-column grid dropped to two. It stacks
   instead, and each button keeps its share of the width (`--pct`, also written
   by helpful_links_panel()) so the single scale survives the change. */
@media (max-width:1100px){
  .civic-links__row{grid-template-columns:1fr}
  .civic-links__btn{width:var(--pct,100%)}
}
.civic-links__title{color:#fff;font-family:var(--serif);font-size:clamp(1.7rem,2.6vw,2.2rem);
  letter-spacing:-.01em;margin:0 0 6px}
/* The archive opens the page's content, close under the intro rather than a
   full section gap away. Each section below sets its own top, so this one
   gives up its bottom and the page's closing space belongs to Helpful Links. */
.section.civic-archive{padding-block:clamp(20px,2.8vw,34px) 0}
/* The eyebrow and the heading under it are one label, so they sit close. Both
   sides are set because the head's bottom margin and the group's top margin
   collapse together and the larger would otherwise win. */
.civic-archive .section__head{margin-bottom:clamp(10px,1.4vw,18px)}
.civic-archive .archive-group{margin-top:0}
/* Nantucket Government 101 — the same head-to-group spacing as the archive it
   follows. A plain section gap between the two would be the sum of both
   paddings, so the archive gives up its bottom and this one sets the whole
   distance; being last, it also closes the page. */
.section.civic-govt101{padding-block:clamp(38px,5.2vw,68px) 0}
.civic-govt101 .section__head{margin-bottom:clamp(10px,1.4vw,18px)}
.civic-govt101 .archive-group{margin-top:0}
/* The section's intro runs the full width of a card -- thumbnail and text
   together -- rather than the 72ch measure .dl-group__intro sets for a note
   beside a list. Frank, 2026-10-25. Scoped to this section so the partner
   pages' section notes keep their reading measure. */
.civic-govt101 .dl-group__intro{max-width:none;font-style:italic}
/* The label is baked into the art, so the button's rendered width is what
   decides whether it can be read: at 140px it came out 28px tall and was
   unreadable. Three proportional columns put the widest near 430px and the
   narrowest near 290px on a full-width panel, which sets every label at about
   12px -- a shade larger than the equal-column grid managed, and larger again
   once the row stacks. */
.civic-links__btn{min-width:0;display:block;border-radius:8px;cursor:pointer;
  transition:opacity .18s var(--ease),transform .18s var(--ease)}
.civic-links__btn img{width:100%;height:auto;display:block;pointer-events:none}
.civic-links__btn:hover,.civic-links__btn:focus-visible{opacity:.88;transform:translateY(-2px)}
/* Recent Videos — stacked, each with a label above it */
@media (max-width:760px){
  .civic-links__row{gap:14px}
}
/* featured video sits tighter under the top block */
.sport-featured{padding-block:clamp(46px,6vw,82px) clamp(24px,3.4vw,44px)}
/* The 64ch cap on a section head is sized for paragraphs; this heading is a
   single title and breaks across two lines inside it, so it gets the width. */
.sport-featured .section__head{max-width:none}
/* ---- Shorts Fest page ---- */
.vhero--bare{align-items:stretch;min-height:min(56vh,520px)}
/* intro: logo + text */
.shorts-intro__grid{display:flex;flex-wrap:wrap;align-items:center;gap:clamp(24px,4vw,54px)}
.shorts-intro__logo{width:clamp(150px,18vw,225px);height:auto;flex:0 0 auto;display:block}
.shorts-intro__text{flex:1 1 340px;min-width:0;margin:0;
  font-size:20px;line-height:1.6;color:var(--ink-soft)}
.shorts-intro__lead{font-family:var(--serif);font-weight:600;color:var(--green-deep);
  font-size:1.24em;line-height:1.3;display:inline-block;margin-bottom:6px}
/* The invitation above Encore Screenings, and -- since Frank asked on
   2026-10-30 for the home page's mailing-list sentence to be set the same
   way -- .newsreel__signup with it. They share these selectors rather than
   each carrying a copy of the declarations, so "the same format" stays true
   without anyone having to remember the other one.

   Green, and in the mono face the
   Awards captions use, so it stands out from the serif intro above it.
   It was italic for part of 2026-10-29 and Frank then had the italics
   removed -- the font link lost Space Mono's italic face with them, so do
   not reintroduce font-style:italic here without putting it back; the
   browser would skew the upright face and it looks crude at this size.
   It carries NO max-width, on purpose: Frank asked on 2026-10-29 that it
   span the page, so it runs the full width of .wrap like a section heading
   rather than being held to a reading measure the way body copy is. */
.shorts-notice__text,.newsreel__signup{margin:0;font-family:var(--mono);
  font-size:20px;line-height:1.65;color:var(--green-deep)}
.shorts-notice__text a,.newsreel__signup a{color:var(--green-deep);text-decoration:underline;
  text-underline-offset:2px}
.shorts-notice__text a:hover,.shorts-notice__text a:focus-visible,
.newsreel__signup a:hover,.newsreel__signup a:focus-visible{color:var(--ink)}
/* 37px is 4px plus one 33px line of the notice: Frank asked on 2026-10-29
   for a clear line of space between it and the intro paragraph above. */
[data-page="events-shorts-fest.html"] .section.shorts-notice{padding-block:24px 10px}
/* submission criteria outline */
.criteria h3{font-family:var(--serif);font-size:clamp(1.2rem,2.2vw,1.55rem);margin:0 0 16px;color:var(--ink)}
.criteria__list{margin:0;padding:0;list-style:none;line-height:1.55;color:var(--ink-soft);
  columns:2;column-gap:clamp(32px,5vw,60px)}
.criteria__list li{break-inside:avoid;position:relative;padding-left:1.3em;margin-bottom:10px}
.criteria__list li::before{content:"\2022";position:absolute;left:.15em;color:var(--green);font-weight:700}
@media (max-width:640px){ .criteria__list{columns:1} }
.criteria__list a{color:var(--green);text-decoration:underline;text-underline-offset:3px}
.criteria__list a:hover{color:var(--ink)}
/* Encore Screenings section */
.encore-link{color:var(--green);text-decoration:underline;text-underline-offset:3px}
.encore-link:hover{color:var(--ink)}
.encore-img{display:block;width:100%;height:auto;max-width:960px;border-radius:14px;
  margin-inline:auto}
/* The graphic is a link to the screening page. The anchor is a block so it
   wraps the image exactly, with no baseline gap under it, and carries the
   same cap the image has. Focus ring matches the festival photo grid. */
.encore-img-link{display:block;width:100%;max-width:960px;margin-inline:auto}
.encore-img-link:focus-visible{outline:2px solid var(--green);outline-offset:3px}
/* Festival photos. Masonry columns rather than a fixed grid: these are
   red-carpet portraits mixed with one landscape, and cropping them to a
   common aspect ratio cuts the tops off people's heads. Columns let every
   photo keep the framing it was shot with. */
/* Both of these put a collapsible heading straight under the eyebrow, so the
   usual gap below a section head is far too much. */
.shorts-photos .section__head,
.shorts-pastfilms .section__head,
.nmf-photos .section__head,
.nmf-auction .section__head{margin-bottom:clamp(10px,1.6vw,18px)}
/* Three New Moon headings set at the collapsible summary's size rather than
   the section heading's -- Frank, 2026-10-25, taking "See the latest New Moon
   updates." as the measure. The clamp is copied from .pastsel__year>summary
   below, so the four track each other at every width: change one, change both.
   All three sections are on the New Moon page only, so nothing else moves.
   All four are overridden together at the foot of this file, by the
   2026-10-26 experiment that puts the titles above the subtitles.

   The sponsors heading used to carry a size of its own: one long sentence over
   a full-width flyer, which at the shared h2 size wanted 1272px in a 1072px
   section, so text-wrap:balance split it into two short lines. This size is
   smaller again, so it still sets on one line and that rule is gone. */
/* Photographer's credit. Sits above the grid, and the same markup is cloned
   into the viewer, so the wording only exists in one place. */
.photo-credit{margin:0 0 clamp(12px,1.6vw,18px);color:var(--ink-soft);
  font-size:clamp(.95rem,1.1vw,1.05rem)}
.photo-credit a{color:var(--green-deep);text-decoration:underline;
  text-underline-offset:2px}
.photo-credit a:hover{color:var(--ink)}
.photo-grid{column-width:260px;column-gap:14px;padding:4px 0 clamp(8px,1.4vw,16px)}
.photo-grid__item{display:block;width:100%;margin:0 0 14px;padding:0;border:0;
  background:none;cursor:zoom-in;border-radius:12px;overflow:hidden;line-height:0;
  break-inside:avoid;-webkit-column-break-inside:avoid}
.photo-grid__item img{width:100%;height:auto;display:block;
  transition:transform .3s var(--ease),filter .3s var(--ease)}
.photo-grid__item:hover img{transform:scale(1.03);filter:brightness(1.05)}
.photo-grid__item:focus-visible{outline:2px solid var(--green);outline-offset:3px}

/* Lightbox. Sits above the sticky header, which tops out at z-index 60. */
body.is-lightboxed{overflow:hidden}
.lightbox{position:fixed;inset:0;z-index:200;display:flex;align-items:center;
  justify-content:center;padding:clamp(14px,3.5vw,48px);background:rgba(8,20,38,.93)}
.lightbox[hidden]{display:none}
/* Column flex so the caption keeps its height and the photo takes the rest;
   min-height:0 is what lets the image actually shrink inside the column. */
.lightbox__fig{margin:0;display:flex;flex-direction:column;align-items:center;
  gap:12px;max-width:100%;max-height:100%}
.lightbox__img{display:block;flex:1 1 auto;min-height:0;max-width:100%;
  width:auto;height:auto;object-fit:contain;border-radius:8px;
  box-shadow:0 24px 60px rgba(0,0,0,.5)}
.lightbox__credit{flex:0 0 auto;margin:0;text-align:center;max-width:62ch;
  color:rgba(255,255,255,.82);font-size:clamp(.9rem,1.05vw,1rem)}
.lightbox__credit[hidden]{display:none}
.lightbox__credit a{color:#fff;text-decoration:underline;text-underline-offset:2px}
.lightbox__credit a:hover{color:var(--green)}
.lightbox__close{position:absolute;top:clamp(10px,2vw,22px);right:clamp(10px,2vw,22px);
  width:44px;height:44px;border-radius:50%;cursor:pointer;color:#fff;font-size:1.7rem;
  line-height:1;display:flex;align-items:center;justify-content:center;
  border:1px solid rgba(255,255,255,.35);background:rgba(255,255,255,.12)}
.lightbox__close:hover{background:rgba(255,255,255,.24)}
.lightbox__close:focus-visible{outline:2px solid #fff;outline-offset:2px}

/* Document overlay. A card can carry a whole document instead of a posted
   agenda -- the Town Meeting warrant -- and it opens over the page rather
   than inside the card. Same stacking as the lightbox: above the sticky
   header, which tops out at z-index 60. */
body.is-docopen{overflow:hidden}
.docmodal{position:fixed;inset:0;z-index:200;display:flex;align-items:center;
  justify-content:center;padding:clamp(0px,3vw,40px);background:rgba(8,20,38,.93)}
.docmodal[hidden]{display:none}
.docmodal__panel{display:flex;flex-direction:column;background:var(--paper);
  width:min(100%,980px);height:min(100%,92vh);border-radius:10px;overflow:hidden;
  box-shadow:0 24px 60px rgba(0,0,0,.5)}
.docmodal__bar{flex:0 0 auto;display:flex;align-items:center;gap:16px;
  padding:14px clamp(16px,3vw,30px);background:var(--ink);color:#fff}
.docmodal__title{flex:1 1 auto;margin:0;font-family:var(--serif);font-weight:600;
  font-size:clamp(1rem,2vw,1.3rem);line-height:1.3;letter-spacing:-.01em}
.docmodal__close{flex:0 0 auto;cursor:pointer;font-family:var(--mono);font-size:.8rem;
  letter-spacing:.06em;text-transform:uppercase;color:#fff;padding:9px 16px;
  border:1px solid rgba(255,255,255,.4);border-radius:999px;background:transparent}
.docmodal__close:hover{background:rgba(255,255,255,.16)}
.docmodal__close:focus-visible{outline:2px solid #fff;outline-offset:2px}
/* -webkit-overflow-scrolling keeps the momentum scroll on iOS, where the
   overlay is the full screen and the warrant is 74 pages long. */
.docmodal__body{flex:1 1 auto;min-height:0;overflow-y:auto;
  -webkit-overflow-scrolling:touch;padding:clamp(18px,3vw,36px)}

/* The warrant itself. It is a legal document, so it is set smaller and
   tighter than the site's body copy and given a reading measure. */
/* break-word is for the signature rules at the end, which are fifty-odd
   underscores with nowhere to wrap and scrolled the whole document sideways
   on a phone. */
.warrant-doc{max-width:68ch;margin:0 auto;font-size:17px;line-height:1.6;
  overflow-wrap:break-word}
.warrant-doc p{margin:0 0 1em}
.warrant-doc__cover{margin:0 0 2em;padding:0 0 1.4em;text-align:center;
  border-bottom:1px solid var(--sand)}
.warrant-doc__cover p{margin:0;line-height:1.5}
.warrant-doc__art{margin:1.8em 0 .7em;font-family:var(--serif);font-weight:600;
  font-size:1.15rem;line-height:1.3;letter-spacing:-.01em;
  padding-top:.9em;border-top:1px solid var(--sand)}
.warrant-doc__art span{display:block;font-size:.95rem;font-weight:500;color:var(--ink-soft)}
.warrant-doc__by{font-family:var(--mono);font-size:.78rem;color:var(--ink-soft)}
/* A defined term, which the bylaws set in capitals above its definition. */
.warrant-doc__term{margin-bottom:.2em;font-weight:600;letter-spacing:.01em}
/* The warrant says in every zoning article that new language is shown
   highlighted and deleted language struck through, so the two have to read
   that way here or the articles describe something the reader cannot see. */
.warrant-doc del{background:transparent;color:var(--ink-soft);text-decoration:line-through}
.warrant-doc ins{background:#DFE3DE;text-decoration:none}
.warrant-doc__scroll{margin:0 0 1.2em;overflow-x:auto;-webkit-overflow-scrolling:touch}
.warrant-doc__grid{width:100%;border-collapse:collapse;font-size:.88rem}
.warrant-doc__grid td{padding:5px 10px 5px 0;border-bottom:1px solid var(--sand);
  vertical-align:top}
.warrant-doc__grid td:first-child{padding-left:0}

@media (prefers-reduced-motion:reduce){
  .photo-grid__item img{transition:none}
  .photo-grid__item:hover img{transform:none}
}
.shorts-encore .section__head{margin-bottom:clamp(14px,2vw,20px)}
.encore-cta{font-size:clamp(1.4rem,2.5vw,1.9rem);letter-spacing:-.01em;font-weight:600;
  margin:clamp(16px,2.4vw,24px) 0 0}
/* Watch Past Films — the year picker supplies the heading now, so the block
   is just the film map and the PPV rental link. */
.pastfilms-block{margin-top:clamp(28px,4vw,46px)}
.pastfilms-block:first-of-type{margin-top:0}
/* awards: two winners side by side, caption above each */
.awards-grid{display:flex;flex-wrap:wrap;gap:clamp(24px,4vw,48px)}
.award{flex:1 1 340px;min-width:0;margin:0}
.award__cap{font-family:var(--mono);font-size:clamp(.95rem,1.2vw,1.05rem);line-height:1.5;
  color:var(--ink);margin:0 0 12px}
.award img{width:100%;height:auto;border-radius:14px;display:block}
.award__label{font-weight:700}
.award__ico{width:1.1em;height:1.1em;vertical-align:-.16em;margin-right:6px;color:var(--green-deep)}
/* tighter spacing between the Shorts Fest sections */
[data-page="events-shorts-fest.html"] .section{padding-block:clamp(30px,4vw,58px)}
[data-page="events-shorts-fest.html"] .section.shorts-intro{padding-block:25px 14px}
[data-page="events-shorts-fest.html"] .shorts-intro+.section.shorts-sponsors{padding-block:12px 0}
[data-page="events-shorts-fest.html"] .section.shorts-sponsors{padding-bottom:0}
[data-page="events-shorts-fest.html"] .section.shorts-submit{padding-top:12px}
.shorts-submit .section__head{max-width:none}
.shorts-awards .section__head{max-width:none}
.nmf-sponsors2026 .section__head{max-width:none}
/* These two carry a heading and nothing else, so the 64ch reading measure
   only served to wrap them in half the available width. */
.nmf-awards .section__head{max-width:none}
.pastsel .section__head{max-width:none}
/* Collapsible subtitles on the New Moon Fest page, matched to the Shorts Fest
   subtitles (.dl-group--static>.dl-group__title). Size, weight, family and
   padding already agree; a <summary> is not a heading, so it misses the
   line-height:1.05 that h1-h4 get and inherits the body's 1.65 instead. */
.nmf-sub>summary{line-height:1.05}
/* And the same tight gap under the eyebrow those sections use, in place of the
   default section-head spacing. */
.nmf-news .section__head,
.nmf-rules .section__head,
.nmf-history .section__head{margin-bottom:clamp(10px,1.6vw,18px)}
/* The history is 27 paragraphs of continuous reading -- the longest prose on
   the page -- so it gets paragraph rhythm of its own rather than the one-off
   <p> spacing the shorter blocks here get away with. The two lines Frank
   marked for bold open their halves of the piece, so they take a larger gap
   above and the full ink colour; --head is the gap, <strong> is his bold. */
.nmf-history__p{margin:0 0 clamp(14px,1.8vw,20px);line-height:1.6;color:var(--ink-soft)}
.nmf-history__p:last-child{margin-bottom:0}
.nmf-history__p--head{margin-top:clamp(22px,2.8vw,32px);color:var(--ink)}
.nmf-history .dl-group__body>.nmf-history__p--head:first-child{margin-top:0}
/* One heading directly under another -- "LUNAFEST in Nantucket" and the
   "Under Theatre Workshop" line beneath it -- is a title and its section
   line, not two separated headings, so the pair closes up. */
.nmf-history__p--head+.nmf-history__p--head{margin-top:clamp(8px,1vw,12px)}
/* No <sup> anywhere else on the site. line-height:0 keeps the footnote
   marker from pushing its own line taller than the ones around it -- in the
   prose, and in the toggle label at the foot of the section. */
.nmf-history sup{font-size:.62em;line-height:0;vertical-align:super}
/* That toggle. .pastsel__year>summary is a flex row, so the label is wrapped
   in a <span> -- loose, the <sup> would become a flex item of its own, lose
   its baseline and take the 14px chevron gap as a word space. The note sits
   off the last paragraph, under the one rule .pastsel__year draws for it. */
.nmf-history__note{margin-top:clamp(10px,1.4vw,16px)}
.nmf-history__note>summary{line-height:1.3}
/* ---- New Moon Fest page ---- */
/* The banner stands at the home hero's height, not the shorter one the two
   festival banners shared -- Frank, 2026-10-30, with the new highlights reel.
   A class of its own: .vhero--bare is Shorts Fest's too, and the two pages
   are allowed to look different. Safe to raise here because this video has
   no baked-in letterbox bars; the old one had 150px at the top, which a
   taller cover crop would have put on screen. */
.vhero--tall{min-height:min(86vh,760px)}
/* The banner carries the festival's title card -- logo and standfirst over
   the footage -- in place of the band that used to sit under it (Frank asked
   to see it this way, 2026-10-30). Centred, not bottom-left like the home
   hero: a mark and two sentences read as a title card, where the home hero's
   job is a wordmark with a row of channel buttons beside it.

   The default scrim is lightest at 38% down, which is exactly where centred
   type lands, so this one is even across the middle and heavier at the foot.
   Enough to hold white type over a bright daylight exterior; the footage is
   still clearly footage. */
.vhero--overlay{align-items:center}
/* Both festival banners now draw it, so the logo's size is per page: New
   Moon's canoe mark is wide and low, Shorts Fest's clapperboard is nearly
   square and goes heavy fast. */
.vhero--overlay .hero__inner{--card-logo:clamp(220px,30vw,420px)}
[data-page="events-shorts-fest.html"] .vhero--overlay .hero__inner{--card-logo:clamp(190px,24vw,320px)}
.vhero--overlay .hero__scrim{background:
  linear-gradient(180deg,rgba(12,24,38,.6) 0%,rgba(12,24,38,.56) 42%,rgba(12,24,38,.8) 100%)}
.vhero--overlay .hero__inner{display:flex;flex-direction:column;align-items:center;
  text-align:center;gap:clamp(16px,2.4vw,28px);padding-block:clamp(34px,5vw,60px)}
.vhero-card__logo{width:var(--card-logo);height:auto;display:block;
  filter:drop-shadow(0 8px 28px rgba(0,0,0,.45))}
.vhero-card__text{margin:0;max-width:60ch;color:#e9eff3;line-height:1.6;
  text-shadow:0 2px 16px rgba(8,18,30,.55)}
.vhero-card__lead{display:inline-block;margin-bottom:12px;color:#fff;
  font-family:var(--serif);font-weight:600;line-height:1.25}

.newmoon-intro__grid{display:flex;flex-wrap:wrap;align-items:center;gap:clamp(24px,4vw,54px)}
.newmoon-intro__logo{width:clamp(200px,25vw,285px);height:auto;flex:0 0 auto;display:block}
.newmoon-intro__text{flex:1 1 340px;min-width:0;margin:0;
  font-size:20px;line-height:1.6;color:var(--ink-soft)}
.newmoon-intro__lead{font-family:var(--serif);font-weight:600;color:var(--green-deep);
  font-size:1.24em;line-height:1.3;display:inline-block;margin-bottom:6px}
[data-page="events-new-moon-fest.html"] .section{padding-block:clamp(30px,4vw,58px)}
.section.newmoon-intro{padding-block:25px 14px}
/* The sponsor band closed up under the intro band's text. With the intro
   moved onto the banner it sits straight under the hero, where 12px reads as
   a mistake, so the override is scoped to the case it was tuned for: present
   only while the intro band is. Put that band back and this comes with it. */
.newmoon-intro+.section.newmoon-sponsors{padding-top:12px}
.newmoon-sponsors__img,.shorts-sponsors__img{display:block;width:100%;height:auto;border-radius:12px}
/* Clickable logos laid over the sponsor banner, the same technique as the
   past-films maps. Each hotspot is square in the artwork's pixels, so the 50%
   radius traces the logo's disc rather than an ellipse. */
.sponsor-map{position:relative;display:block}
.sponsor-map__btn{position:absolute;display:block;border-radius:50%;
  transition:background .15s var(--ease),box-shadow .15s var(--ease)}
.sponsor-map__btn:hover,.sponsor-map__btn:focus-visible{outline:none;
  background:rgba(255,255,255,.14);box-shadow:0 0 0 3px rgba(255,255,255,.75)}
/* Official Film Selections — year picker + movie picker */
.pastsel__year{border-top:1px solid var(--sand)}
.pastsel__year:last-of-type{border-bottom:1px solid var(--sand)}
/* Those two rules divide a stack of accordion rows from one another. The New
   Moon Fest collapsibles stand alone under their own eyebrow, so there is
   nothing to divide and the lines just read as stray rules. Placed after the
   rules it overrides, since .pastsel__year:last-of-type matches it for
   specificity and source order would otherwise decide the wrong way. */
.nmf-sub.pastsel__year,
.nmf-sub.pastsel__year:last-of-type{border-top:0;border-bottom:0}
.pastsel__year>summary,.dl-link{list-style:none;cursor:pointer;padding:clamp(14px,2vw,20px) 0;
  font-family:var(--serif);font-size:1.4rem;letter-spacing:-.01em;
  color:var(--ink);display:flex;align-items:center;gap:14px}
.pastsel__year>summary::-webkit-details-marker{display:none}
.pastsel__year>summary::before{content:"";width:11px;height:11px;flex:0 0 auto;
  border-right:2.5px solid var(--green-deep);border-bottom:2.5px solid var(--green-deep);
  transform:rotate(-45deg);transition:transform .2s var(--ease)}
.pastsel__year[open]>summary::before{transform:rotate(45deg)}
/* The New Moon Fest subtitles can run to several lines, where a vertically
   centred caret floats beside the middle line instead of marking where the
   sentence starts. Align it to the first line. The offset re-centres its 11px
   box against that line, so the one-line subtitles do not move: half of the
   1.05 line box less half the 11px caret, which tracks the clamped font size
   down to mobile instead of fixing one offset for the desktop size. Placed after
   the rules it overrides and carrying .pastsel__year, which matches
   .nmf-sub>summary for specificity. */
.nmf-sub.pastsel__year>summary{align-items:flex-start}
.nmf-sub.pastsel__year>summary::before{margin-top:calc(.525em - 5.5px)}
/* The auction note and its partner list, behind that collapsible. The note is
   body copy, not the oversized summary, so it resets the inherited size. */
/* No max-width here: the note is meant to span the same width as the partner
   list under it, not the narrower measure body copy usually takes. */
/* Set apart from the partner rows below it rather than bolded: the serif the
   headings use, at full-strength ink and a little larger, which is the same
   move the __lead lines make elsewhere on the site. Bold was tried first and
   reversed -- Frank, 2026-10-25. Line-height comes down from the sans 1.66
   because Fraunces sets looser at the same measure. */
.auction-note{margin:0 0 clamp(18px,2.4vw,26px);font-family:var(--serif);
  font-size:clamp(1.1rem,1.45vw,1.26rem);line-height:1.55;color:var(--ink)}
.auction-note a{color:var(--ink);text-decoration:none;
  border-bottom:1px solid var(--green);padding-bottom:1px}
.auction-note a:hover,.auction-note a:focus-visible{color:var(--green-deep)}
/* Each partner is one row: who they are, what they sell, and the way out to
   them. Three columns on a wide screen; on a narrow one the Shop link drops
   under the description rather than squeezing the two text columns. */
/* The list sits on a paper panel, the site's own raised surface -- same fill,
   hairline and radius as the partner logo tiles -- so the forty rows read as
   one block against the fog rather than running loose down the page. Frank
   asked for a background in the site's colours, 2026-10-25.

   The rows already draw their own hairlines, so the first and last lose theirs
   to the panel's edge; keeping them would double the line top and bottom. */
.auction-partners{list-style:none;margin:0;background:var(--paper);
  border:1px solid var(--sand);border-radius:16px;
  padding:clamp(4px,1vw,10px) clamp(16px,2.4vw,28px)}
.auction-partners__row{display:grid;grid-template-columns:minmax(0,15em) minmax(0,1fr) auto;
  gap:6px 22px;align-items:baseline;padding:14px 0;border-bottom:1px solid var(--sand)}
.auction-partners__row:last-child{border-bottom:0}
.auction-partners__name{font-family:var(--serif);font-size:1.18rem;line-height:1.25;color:var(--ink)}
.auction-partners__what{font-size:1rem;line-height:1.5;color:var(--ink-soft)}
.auction-partners__shop{font-family:var(--mono);font-size:.82rem;letter-spacing:.14em;
  text-transform:uppercase;text-decoration:none;white-space:nowrap;
  color:var(--green-deep);border-bottom:1px solid var(--green);padding-bottom:2px}
.auction-partners__shop:hover,.auction-partners__shop:focus-visible{color:var(--ink);border-color:var(--ink)}
@media (max-width:680px){
  .auction-partners__row{grid-template-columns:1fr;gap:4px;padding:16px 0}
  .auction-partners__shop{justify-self:start;margin-top:6px}
}
/* a row that looks like an accordion but navigates instead of opening: no
   caret, since there is nothing to expand, and no border-top because the
   details above it already draws one as :last-of-type. */
.dl-link{border-bottom:1px solid var(--sand);text-decoration:none}
.dl-link:hover,.dl-link:focus-visible{color:var(--green-deep)}
/* A closing sentence under the last group of a list -- same size and colour as
   the link line under a mission statement, but it follows a bordered accordion
   row rather than a paragraph, so it takes a little more air above it. */
.dl-programs__after{margin:clamp(18px,2.2vw,24px) 0 0;
  font-size:clamp(1.05rem,1.35vw,1.22rem);color:var(--ink-soft)}
/* nested child sections (NHA "Browse by Topic") — the same accordion one level
   in: indented, a size smaller, and with a smaller chevron, so the parent
   still reads as the heading of the pair. The first child needs no top rule;
   the parent's own summary already draws the line above it. */
.dl-group--sub{margin-left:clamp(12px,2vw,26px)}
.dl-group--sub>summary{padding:clamp(10px,1.3vw,14px) 0;gap:11px;
  font-size:clamp(1.12rem,1.8vw,1.42rem)}
.dl-group--sub>summary::before{width:8px;height:8px;border-right-width:2px;
  border-bottom-width:2px}
.dl-group__body>.dl-group--sub:first-child{border-top:0}
.dl-group__body>.dl-group--sub:last-child{border-bottom:0}

/* always-open group (Book Festival archive): same heading as a summary, but no
   toggle and no chevron, since there is nothing to expand or collapse */
.dl-group--static>.dl-group__title{margin:0;padding:clamp(14px,2vw,20px) 0;
  font-family:var(--serif);font-size:1.4rem;letter-spacing:-.01em;
  font-weight:400;color:var(--ink)}
.pastsel__movies{display:flex;flex-wrap:wrap;gap:10px;padding:2px 0 clamp(18px,2.4vw,26px)}
.movie-btn{font-family:var(--mono);font-size:.95rem;padding:9px 16px;border-radius:20px;
  border:1px solid var(--sand);background:var(--paper);color:var(--ink);cursor:pointer;
  transition:border-color .18s var(--ease),background .18s var(--ease),color .18s var(--ease)}
.movie-btn:hover{border-color:var(--green)}
.movie-btn.is-active{background:var(--green-deep);color:#fff;border-color:var(--green-deep)}
.pastsel__panels{padding-bottom:clamp(6px,1.2vw,14px)}
.movie-panel{display:flex;flex-wrap:wrap;align-items:flex-start;gap:clamp(24px,4vw,44px);padding-bottom:clamp(24px,3vw,36px)}
.movie-panel[hidden]{display:none}
.movie-poster{width:clamp(220px,26vw,300px);height:auto;flex:0 0 auto;align-self:flex-start;
  object-fit:contain;border-radius:10px;display:block}
.movie-text{flex:1 1 340px;min-width:0}
.movie-title{font-family:var(--serif);font-size:clamp(1.5rem,3vw,2.2rem);letter-spacing:-.01em;margin:0 0 8px}
.movie-meta{font-family:var(--mono);font-size:.86rem;letter-spacing:.03em;color:var(--green-deep);
  margin:0 0 16px;text-transform:uppercase}
.movie-synopsis{margin:0 0 16px;line-height:1.6;color:var(--ink-soft)}
/* The award note on a winning film's panel. Deliberately the same mono,
   weight and icon as .award__cap in the Awards section further down, so the
   two read as one thing said twice rather than two different claims. It is
   pulled up under the meta line, which it belongs with. */
.movie-award{font-family:var(--mono);font-size:clamp(.95rem,1.2vw,1.05rem);
  font-weight:700;line-height:1.5;color:var(--green-deep);margin:-6px 0 16px}
.movie-award__ico{width:1.1em;height:1.1em;vertical-align:-.16em;margin-right:6px;
  color:var(--green-deep)}
.movie-quote{margin:0 0 16px;line-height:1.6;color:var(--ink-soft);font-style:italic;
  border-left:3px solid var(--sand);padding-left:16px}
.movie-credits-h{font-family:var(--mono);font-size:.8rem;letter-spacing:.1em;text-transform:uppercase;
  margin:0 0 8px;color:var(--ink)}
/* Credits set in two columns -- a cast and crew list runs to fifteen lines and
   pushed the poster and synopsis far up the panel. Each credit is its own
   block, so one that wraps cannot be split down the middle of the gap.
   The columns are a container query on the credits block itself rather than a
   @media width, because what decides this is how much room the credits have,
   and the panel they sit in is not a fixed fraction of the window.
   It has to be a query of some kind: build.py marks the crew/cast boundary
   with a FORCED column break, and a forced break makes a second column even
   where only one fits, which put the cast off the side of a phone screen. */
.movie-credits{margin:0;line-height:1.75;color:var(--ink-soft);font-size:.98rem}
.movie-credits span{display:block;break-inside:avoid}
/* The credits are the panel's third child and claim a row of their own under
   the poster and the synopsis, which is what gives the two columns the full
   width of the panel to run across. */
.movie-credits-wrap{flex:1 0 100%;container-type:inline-size}
/* The column count steps with the room available, not in one jump. The
   longest ordinary credit -- "Director of Photography: Greg Shephard" -- sets
   at about 300px, so three columns need roughly 990px of block and two need
   about 650px. Below that a credit wraps mid-name and the list stops being
   readable as a list. */
@container (min-width:640px){
  .movie-credits-wrap--cols .movie-credits{column-count:2;
    column-gap:clamp(24px,3vw,46px)}
  .movie-credits__col{-webkit-column-break-before:always;break-before:column}
  /* A short list sets in one column, at the width the first column would
     have had. Left to run the whole panel it would be a single 1072px line
     of "Editor: Rich Blundell" with eight hundred pixels of air after it,
     and it would not line up with the columned panels above and below. */
  .movie-credits-wrap:not(.movie-credits-wrap--cols) .movie-credits{
    max-width:calc((100% - clamp(24px,3vw,46px)) / 2)}
}
@container (min-width:960px){
  /* A tighter gap than the two-column one on purpose. Three columns across
     the 1072px panel leaves 329px each at the wider gap, and
     "Director of Photography: Greg Shephard" wraps at 329px but not at 341,
     so the 18px bought back here is what keeps the crew credits on one line
     -- and what rebalances the cast 6/4 across the last two columns instead
     of 8/2. */
  .movie-credits-wrap--cols .movie-credits{column-count:3;column-gap:24px}
  .movie-credits-wrap:not(.movie-credits-wrap--cols) .movie-credits{
    max-width:calc((100% - 48px) / 3)}
}
.movie-directed{margin:16px 0 0;color:var(--ink);font-weight:600;font-size:1.02rem}
/* Shorts Fest posters are 16:9 frame grabs rather than portrait one-sheets, so
   at the shared width they read as a thumbnail beside the text. They get their
   own, larger size; the New Moon one-sheets keep theirs, and keep the 2x
   encoding they were made at. assets/*-poster.webp for this page is encoded at
   920px by tools/film-poster.py, twice the 460px maximum here. */
.shorts-selection .movie-poster{width:clamp(280px,40vw,460px)}
/* Awards — winner graphic reveal + explanatory text */
.awards-panel{padding:clamp(4px,1.2vw,12px) 0 clamp(24px,3vw,36px)}
.awards-img{display:block;width:100%;height:auto;border-radius:12px}
.awards-text{margin:clamp(16px,2.4vw,26px) 0 0;max-width:78ch;line-height:1.6;
  color:var(--ink-soft);font-size:clamp(1.02rem,1.25vw,1.16rem)}
.nmf-awards .year-panel:not([hidden]) .awards-panel{animation:awardReveal .65s var(--ease) both}
@keyframes awardReveal{
  from{opacity:0;transform:translateY(28px) scale(.985);filter:blur(9px)}
  60%{filter:blur(0)}
  to{opacity:1;transform:none;filter:blur(0)}
}
@media (prefers-reduced-motion:reduce){
  .nmf-awards .year-panel:not([hidden]) .awards-panel{animation:none}}
/* Recent News — dated entries */
.news-item{margin-top:clamp(26px,3.5vw,42px)}
.news-item:first-of-type{margin-top:0}
.news-date{font-family:var(--serif);font-size:clamp(1.5rem,2.8vw,2.1rem);letter-spacing:-.01em;
  margin:0 0 clamp(8px,1.2vw,12px)}

.news-sign{margin:clamp(14px,2vw,20px) 0 0;line-height:1.7;color:var(--ink-soft);
  font-size:clamp(1.02rem,1.25vw,1.16rem)}
/* A news item can carry a link now that the submissions notice does. Same
   green underline the Shorts Fest criteria bullets use. Covers both shapes a
   news entry takes: the dated .news-item paragraph and the .news-list bullet. */
.news-list a{color:var(--green);text-decoration:underline;text-underline-offset:3px}
.news-list a:hover{color:var(--ink)}
/* The date that prefaces a news bullet. Serif at full ink, a quiet echo of the
   .news-date heading the dated items use, so it reads as a label rather than
   running into the sentence after the em dash. */
.news-list__date{font-family:var(--serif);color:var(--ink);font-weight:600}
/* New Moon Fest submission rules, behind the Learn More summary. The call to
   action and the lead sentence sit above the list; the list itself is modelled
   on the Shorts Fest .criteria__list bullets but stays in ONE column, because
   several of these items run to a full paragraph and break-inside:avoid cannot
   balance a 200-word item against a six-word one. Sub-items indent and take a
   dash, so the two levels read apart without a second bullet glyph. */
.nmf-rules__submit{margin:0 0 clamp(10px,1.4vw,14px);font-family:var(--serif);
  font-size:clamp(1.1rem,1.45vw,1.26rem);line-height:1.55;color:var(--ink)}
.nmf-rules__submit a{color:var(--ink);text-decoration:none;
  border-bottom:1px solid var(--green);padding-bottom:1px}
.nmf-rules__submit a:hover,.nmf-rules__submit a:focus-visible{color:var(--green-deep)}
/* The FilmFreeway Gold button, added 2026-10-30: first at the end of the
   submissions bullet, then in place of the "click here" above the rules. The
   supplied artwork is a transparent lockup, so on the page's own background it
   would read as a stray inline image rather than something to click -- the
   white card, the hairline and the lift on hover are what make it a button.

   It must sit AFTER both .news-list a and .nmf-rules__submit a, and the
   selector must be a.ff-btn rather than .ff-btn, because those two rules are
   (0,1,1) and dress a link for words: an underline in one, a green
   border-bottom and a 1px bottom padding in the other. A bare .ff-btn is
   (0,1,0) and loses to them, which would put a green line under the card and
   squash it off centre. Equal specificity plus later position is what wins
   here, so do not move this block up or drop the element from the selector.

   It sits inline at the end of the sentence, so the bottom margin is what
   keeps it off the line below when the sentence wraps and the button lands on
   its own line. */
a.ff-btn{display:inline-block;vertical-align:middle;margin:0 0 2px 4px;padding:6px 10px;
  background:#fff;border:1px solid rgba(0,0,0,.14);border-radius:10px;
  text-decoration:none;box-shadow:0 6px 16px -10px rgba(0,0,0,.5);
  transition:transform .2s var(--ease),box-shadow .2s var(--ease)}
a.ff-btn:hover,a.ff-btn:focus-visible{transform:translateY(-2px);color:inherit;
  box-shadow:0 12px 22px -12px rgba(0,0,0,.6)}
a.ff-btn img{display:block;width:210px;height:auto}
.nmf-rules__lead{margin:0 0 clamp(14px,1.8vw,20px);line-height:1.6;color:var(--ink-soft);
  font-size:clamp(1.02rem,1.25vw,1.16rem)}
.nmf-rules__list,.news-list,.svc-list{margin:0;padding:0;list-style:none;line-height:1.6;
  color:var(--ink-soft)}
.nmf-rules__list li,.news-list li,.svc-list li{position:relative;padding-left:1.3em;
  margin-bottom:12px}
.nmf-rules__list li::before,.news-list li::before,
.svc-list li::before{content:"\2022";position:absolute;left:.15em;
  color:var(--green);font-weight:700}
/* ---- Professional Services ----
   The head's closing line is a colon pointing straight at the list, so it
   keeps a fraction of the 34-56px a section head normally leaves. Written
   .section__head.svc-head rather than .svc-head alone: the base rule is a
   single class too and sits further down this file, so it would win on
   source order -- the same trap as the logo cards' hover. */
.section__head.svc-head{margin-bottom:clamp(14px,1.8vw,20px)}
/* the colon line is a lead-in, so it drops a paragraph's trailing 1.1em */
.svc-head>p:last-child{margin-bottom:0}
.svc-list{max-width:78ch}
.svc-list li{font-size:20px}
.nmf-rules__list ul{list-style:none;margin:12px 0 0;padding:0}
.nmf-rules__list ul li::before{content:"\2013";font-weight:400}
.nmf-rules__list a{color:var(--green);text-decoration:underline;text-underline-offset:3px}
.nmf-rules__list a:hover{color:var(--ink)}
/* 2026 Sponsors flyer (full width). The margin lives on the wrapper, not the
   image, because the hotspots are positioned against the wrapper and a margin
   on the image would shift the picture out from under them. */
.sponsor-flyer{margin-top:clamp(6px,1.4vw,16px);margin-inline:auto}
.sponsor-flyer>img{display:block;width:100%;height:auto;border-radius:12px}
/* The flyer's logos are rectangles rather than the discs on the banner above,
   so they take a rounded box in place of .sponsor-map__btn's circle. Same
   hover treatment -- both sit on the same navy artwork. */
.sponsor-map__box{position:absolute;display:block;border-radius:8px;
  transition:background .15s var(--ease),box-shadow .15s var(--ease)}
.sponsor-map__box:hover,.sponsor-map__box:focus-visible{outline:none;
  background:rgba(255,255,255,.14);box-shadow:0 0 0 3px rgba(255,255,255,.75)}
/* ...except the Shorts Fest flyer, which is cream rather than navy. A white
   wash and a white ring are invisible on it, so that one inverts them. */
.shorts-flyer .sponsor-map__box:hover,
.shorts-flyer .sponsor-map__box:focus-visible{
  background:rgba(12,24,38,.10);box-shadow:0 0 0 3px rgba(12,24,38,.45)}
/* past films image map with invisible clickable buttons */
.filmmap{position:relative;display:block;max-width:1100px;margin:0 auto}
.filmmap>img{width:100%;height:auto;display:block;border-radius:14px}
.filmmap__btn{position:absolute;display:block;border-radius:10px;
  transition:background .15s var(--ease),box-shadow .15s var(--ease)}
.filmmap__btn:hover,.filmmap__btn:focus-visible{outline:none;
  background:rgba(113,194,109,.16);box-shadow:0 0 0 3px var(--green)}
.sport-links{display:flex;flex-wrap:wrap;gap:10px}
.sport-link{display:inline-block;padding:10px 18px;border-radius:999px;
  font-family:var(--mono);font-size:.98rem;letter-spacing:.04em;line-height:1;
  color:var(--ink);text-decoration:none;background:var(--paper);
  border:1px solid var(--sand);
  transition:background .18s var(--ease),color .18s var(--ease),
             border-color .18s var(--ease),transform .18s var(--ease)}
.sport-link:hover,.sport-link:focus-visible{background:var(--green);
  border-color:var(--green);color:#04210f;transform:translateY(-2px)}
/* ---- committee picker (civic archive) ----
   A .board-btn is a <button> wearing .sport-link, so it needs the element
   defaults reset that an <a> never had. The chosen board keeps the same filled
   treatment as an active year button, so the two levels read as one control. */
button.sport-link{cursor:pointer;font:inherit;font-family:var(--mono);
  font-size:.98rem;letter-spacing:.04em;line-height:1;text-align:left}
.board-btn.is-active,.sport-btn.is-active{background:var(--green-deep);
  border-color:var(--green-deep);color:#fff;transform:none}
.board-btn.is-active:hover,.sport-btn.is-active:hover{background:var(--green-deep);color:#fff}
.board-panel,.sport-panel{margin-top:clamp(20px,2.6vw,30px)}
.board-panel[hidden],.sport-panel[hidden]{display:none}
/* The three seasons stand side by side, each a column listing its own sports,
   with a hairline under them separating the picker from what it opens. The
   column rules are scoped to .sportpick because .sport-links is shared with
   the civic board picker, which wants its buttons in a wrapping row. */
.sport-seasons{display:grid;gap:clamp(18px,2.6vw,40px);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,190px),1fr))}
.sportpick .sport-season{margin-bottom:0}
.sportpick .sport-links{flex-direction:column;flex-wrap:nowrap;align-items:flex-start}
.sportpick__panels{margin-top:clamp(20px,2.8vw,32px);padding-top:clamp(20px,2.8vw,32px);
  border-top:1px solid var(--sand)}
.sportpick__panels .sport-panel{margin-top:0}
/* The student-crew graphic carries its own navy panel and gold border, so it
   only needs sizing. */
.crew-photo{width:100%;height:auto;display:block;border-radius:16px}
/* An Instagram highlight reel. The embed is a fixed-layout widget that does
   not size itself without Meta's script, so the height is set here: 400x720
   fits the reel plus Instagram's own header and footer without clipping. */
/* the relocated title sits under the buttons, in the thumbnail's column */
.watch-episode__media .watch-episode__title{margin:16px 0 0}
.reel{display:block;border:0;width:100%;max-width:400px;height:720px;
  border-radius:10px;background:var(--paper)}
.watch-episode__soon{margin:0;font-family:var(--mono);font-size:.95rem;color:var(--ink-soft)}
/* quarter row: the third level, one step quieter than the year buttons above
   it so the hierarchy reads top to bottom. A quarter with no meetings that
   year stays in place, greyed, rather than leaving a gap in the row. */
.quarterpick{margin-top:clamp(16px,2vw,24px)}
.quarterpick__btns{display:flex;flex-wrap:wrap;gap:8px}
.quarter-btn{font-family:var(--mono);font-size:.88rem;padding:7px 14px;
  border-radius:20px;background:var(--paper);border:1px solid var(--sand);
  color:var(--ink-soft);cursor:pointer;line-height:1;
  transition:background .18s var(--ease),color .18s var(--ease),
             border-color .18s var(--ease)}
.quarter-btn:hover:not(:disabled){border-color:var(--green)}
.quarter-btn.is-active{background:var(--green-deep);color:#fff;
  border-color:var(--green-deep)}
.quarter-btn:disabled{opacity:.38;cursor:default}
/* The AI note went from above the quarter buttons, to below them (Frank,
   2026-10-26), to inside the quarter panel itself (2026-10-27), so it is only
   read once a quarter is open. There it is the panel's first child and needs
   no rule of its own: .quarter-panel supplies the gap above it and
   .dl-group__intro's own bottom margin the gap down to the first card. */
.quarter-panel{margin-top:clamp(20px,2.6vw,30px)}
.quarter-panel[hidden]{display:none}
/* the agenda control is a placeholder until the agendas are wired up: it keeps
   its shape in the row but says plainly that there is nothing behind it yet */
.watch-episode__agenda-btn--pending{border:0;cursor:default;opacity:.45;
  font-family:var(--mono)}
.watch-episode__agenda-btn--pending:hover{background:var(--green-deep)}
/* season grouping */
.sport-season{margin-bottom:clamp(18px,2.6vw,28px)}
.sport-season:last-child{margin-bottom:0}
.sport-season__label{display:inline-flex;align-items:center;gap:9px;margin-bottom:12px;
  font-family:var(--mono);font-size:.9rem;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-soft)}
.sport-season__label svg{width:20px;height:20px;flex:0 0 auto;color:var(--green)}
/* Upcoming Broadcasts */
@media (max-width:560px){
  .chero__card{padding:16px 20px}
  .chero__card img{height:84px}
}

/* =====================================================================
   SECTIONS
   ===================================================================== */
.section{padding-block:clamp(56px,8vw,104px)}
/* Every section boundary is two of those paddings stacked, about 205px at a
   desktop width. That is right where one block of reading ends and the next
   begins, but it left too much air under the news reel's arrows (Frank,
   2026-10-30), so the section below them keeps only a token of its own. */
.section--tight-top{padding-block-start:clamp(12px,1.6vw,22px)}
.section--paper{background:var(--paper)}
.section__head{max-width:64ch;margin-bottom:clamp(34px,5vw,56px)}
.section__head h2{font-size:1.4rem;font-weight:400;letter-spacing:-.01em;margin-top:12px}
/* Even the lines of a heading rather than leaving a one-word last line.
   Balance alone is not enough for a name: at phone width it was happy to break
   "New Moon Fest" across two lines, so that heading also carries non-breaking
   spaces. Unsupported browsers just wrap normally. */
.section__head h2,.dl-group__title{text-wrap:balance}
.section__head p{color:var(--ink-soft);margin-top:16px;font-size:1.08rem}
/* The only link that lives in a section head today: the sponsorship
   address under the Shorts Fest sponsor flyer. a{color:inherit} would
   leave a bare mailto looking like plain text, so it takes the same
   treatment the address further up that page already has. */
.section__head p a,.section__head h2 a{color:var(--green-deep);text-decoration:underline;
  text-underline-offset:3px}
.section__head p a:hover,.section__head p a:focus-visible,
.section__head h2 a:hover,.section__head h2 a:focus-visible{color:var(--ink)}
/* For a heading that is a line of short sentences rather than a phrase: the
   shared 64ch measure broke "Free gear. Free studio time. Free membership."
   after "studio" and left it two-thirds across the page. Heading and the
   sentence under it both run the full page column here; the sentence is one
   line of summary rather than a column of reading, so the long measure that
   would be wrong for body copy is right for it. */
.section__head--wide{max-width:none}
/* For a head that is an eyebrow on its own, with no heading under it: the
   full gap is sized for a label plus a sentence, and leaves a hole above
   the news reel's first card (Frank, 2026-10-30). */
.section__head--tight{margin-bottom:clamp(14px,1.8vw,24px)}
/* At the full measure the sentence runs 62px past one line, so it breaks with a
   word or two on the second -- `pretty` keeps that tail from shrinking to the
   single word "Nantucket." Browsers without it wrap normally. */
.section__head--wide p{text-wrap:pretty}
.lead{font-size:1.18rem;color:var(--ink-soft)}

/* feature cards (home) */
.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:22px}
.card{background:var(--paper);border:1px solid var(--sand);border-radius:18px;
  padding:30px 26px 28px;text-decoration:none;color:var(--ink);position:relative;
  overflow:hidden;transition:transform .3s var(--ease),box-shadow .3s var(--ease),
  border-color .3s var(--ease)}
.card:hover{transform:translateY(-5px);box-shadow:0 26px 50px -30px rgba(12,24,38,.5);
  border-color:color-mix(in srgb,var(--green) 50%,var(--sand))}

.card h3{font-size:1.5rem;margin:14px 0 8px}
.card p{color:var(--ink-soft);font-size:.98rem;margin:0}
/* program tiles (home) — large clickable logos, no labels */
.programs{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:18px}

/* "Our Channels" heading row with the island artwork beside it */
.channels-head{display:flex;align-items:center;justify-content:space-between;
  gap:clamp(24px,4vw,56px);flex-wrap:wrap;margin-bottom:clamp(34px,5vw,56px)}
.channels-head .section__head{margin-bottom:0;flex:1 1 360px}
.channels-art-wrap{flex:0 1 400px;max-width:400px;min-width:240px;
  display:flex;justify-content:flex-end;margin-left:auto}
.channels-art{width:100%;height:auto;animation:home-float 6.5s ease-in-out infinite}
@keyframes home-float{0%,100%{transform:translateY(0)}50%{transform:translateY(-9px)}}

/* entrance animation when the artwork scrolls into view */
.channels-art-wrap[data-reveal]{opacity:0;transform:translateY(28px) scale(.9)}
.channels-art-wrap[data-reveal].in{opacity:1;transform:none;
  transition:opacity 1s var(--ease),transform 1.05s cubic-bezier(.18,.89,.32,1.12)}
@media (max-width:760px){
  .channels-art-wrap{margin-inline:auto;justify-content:center;max-width:340px}
}

/* centered section head (Featured Video) */
.featured__desc{max-width:70ch;margin:26px auto 0;text-align:center;
  overflow-wrap:anywhere;
  font-family:var(--serif);font-size:clamp(1.425rem,3vw,2.25rem);letter-spacing:-.01em;color:var(--ink-soft)}
.featured__desc a{color:var(--green-deep);text-decoration:none;
  border-bottom:1px solid var(--green);padding-bottom:1px}
.featured__desc a:hover{color:var(--ink)}

/* =====================================================================
   PARTNER BUTTONS (logo tiles -> partner video pages)
   ===================================================================== */
.partners{display:grid;grid-template-columns:repeat(5,1fr);gap:16px}
@media (max-width:1100px){.partners{grid-template-columns:repeat(3,1fr)}}
@media (max-width:720px){.partners{grid-template-columns:repeat(2,1fr)}}
@media (max-width:460px){.partners{grid-template-columns:1fr}}
.partner{background:var(--paper);border:1px solid var(--sand);border-radius:16px;
  padding:12px;min-height:148px;display:flex;align-items:center;justify-content:center;
  text-decoration:none;position:relative;
  transition:transform .26s var(--ease),box-shadow .26s var(--ease),
    border-color .26s var(--ease),background-color .26s var(--ease)}
/* A logo card gives no other sign that it is a link, so this state is the
   whole affordance -- Frank, 2026-10-30: "users won't know the logos are
   clickable". It is loud on purpose. The card springs up and grows, a green
   ring draws itself around it, the paper warms green, and the logo steps up a
   size. The ring is a box-shadow rather than a thicker border, so nothing in
   the grid reflows, and it follows the card's own 16px radius.

   **The leading `a` is load-bearing.** These tiles carry data-reveal, and
   `[data-reveal].in{transform:none}` near the foot of this file has the same
   specificity as a bare `.partner:hover`, so it won on source order -- which
   is what had been silently cancelling the lift this rule replaces. The
   element is always an anchor, so the type selector buys the specificity
   without a hack. Measure the computed transform in a browser before trusting
   any hover rule that sits above that block. */
a.partner:hover,a.partner:focus-visible,
a.cfn-funds__mark:hover,a.cfn-funds__mark:focus-visible{
  z-index:2;transform:translateY(-8px) scale(1.04);
  background:color-mix(in srgb,var(--green) 10%,var(--paper));
  border-color:var(--green);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--green) 60%,transparent),
    0 26px 44px -20px rgba(12,24,38,.45);
  animation:logo-pick .34s var(--ease)}
/* Keyboard focus keeps the real outline -- it survives forced-colours mode,
   where a box-shadow does not -- so the ring above would only double it. The
   16px puts back the card's own radius, which the global :focus-visible rule
   squares to 4px for the small controls it was written for. */
a.partner:focus-visible,a.cfn-funds__mark:focus-visible{border-radius:16px;
  box-shadow:0 26px 44px -20px rgba(12,24,38,.45)}
@keyframes logo-pick{
  0%{transform:translateY(0) scale(1)}
  58%{transform:translateY(-11px) scale(1.065)}
  100%{transform:translateY(-8px) scale(1.04)}
}
.partner__logo{max-height:120px;max-width:94%;width:auto;height:auto;object-fit:contain;
  transition:transform .26s var(--ease)}
a.partner:hover .partner__logo,
a.partner:focus-visible .partner__logo{transform:scale(1.09)}
/* ---- Community Foundation initiative funds (nonprofit hub) ---- */
.section.cfn-funds{padding-block:clamp(30px,4vw,52px) 0}
.cfn-funds__grid{display:flex;flex-wrap:wrap;align-items:center;
  gap:clamp(24px,4vw,54px)}
/* the same card as .partner, at a larger size: this is the Foundation itself
   and the four funds below belong to it, so it should read as the same kind of
   button rather than a bare image */
/* The Foundation's own mark takes the same selected state as the cards above
   it -- the rule for both is up with .partner. */
.cfn-funds__mark{flex:0 0 auto;display:flex;align-items:center;
  justify-content:center;padding:clamp(14px,1.6vw,20px);
  background:var(--paper);border:1px solid var(--sand);border-radius:16px;
  text-decoration:none;position:relative;
  transition:transform .26s var(--ease),box-shadow .26s var(--ease),
    border-color .26s var(--ease),background-color .26s var(--ease)}
.cfn-funds__mark img{display:block;width:clamp(118px,13vw,158px);height:auto;
  transition:transform .26s var(--ease)}
a.cfn-funds__mark:hover img,
a.cfn-funds__mark:focus-visible img{transform:scale(1.09)}
/* Deliberately the same size as .np-intro__text above it: the two paragraphs
   introduce the page one after the other, so keep them in step. */
.cfn-funds__text{flex:1 1 340px;min-width:0;margin:0;
  font-size:20px;line-height:1.55;color:var(--ink-soft)}
/* Four of these logos are JPEG/WebP with no alpha, so they carry their own pure
   white, which reads as a bright rectangle against the card's warmer --paper.
   Multiplying leaves white exactly equal to whatever is behind it and barely
   touches the artwork, --paper being 98% bright. `isolation` keeps the blend
   inside the card. */
.cfn-funds__mark,.cfn-fund{isolation:isolate}
.cfn-funds__mark img,.cfn-fund .partner__logo{mix-blend-mode:multiply}
.cfn-funds__list{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;
  margin-top:clamp(24px,3vw,38px)}
@media (max-width:900px){.cfn-funds__list{grid-template-columns:repeat(2,1fr)}}
@media (max-width:460px){.cfn-funds__list{grid-template-columns:1fr}}

/* =====================================================================
   COLLAPSIBLE BIO (staff & board)
   ===================================================================== */
.bio{margin-top:2px}
.bio>summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:8px;
  font-family:var(--mono);font-size:1.08rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--green-deep);font-weight:700;padding:6px 0;
  transition:color .2s var(--ease)}
.bio>summary::-webkit-details-marker{display:none}
.bio>summary::before{content:"";width:9px;height:9px;border-right:2px solid currentColor;
  border-bottom:2px solid currentColor;transform:rotate(-45deg);transition:transform .25s var(--ease)}
.bio[open]>summary::before{transform:rotate(45deg)}
.bio>summary:hover{color:var(--ink)}
.bio .bio__close{display:none}
.bio[open] .bio__open{display:none}
.bio[open] .bio__close{display:inline}
.bio .person__bio{margin-top:12px}

/* =====================================================================
   LATEST NCTV NEWS (home)
   ---------------------------------------------------------------------
   One card at a time, centred, with the card before it and the card after
   it small on either side. Its paragraph is centred underneath, then the
   arrows and dots. site.js turns the cards over every seven seconds; the
   first card carries .is-current from build.py, so with JavaScript off the
   section is that card rather than an empty box.

   The cards are STACKED in one grid cell instead of being hidden, so the
   box is as tall as the longest card and nothing below it moves when the
   card changes. Same for the paragraphs under them. visibility (not
   opacity alone) is what takes a card that is off screen out of the tab
   order and away from a screen reader.
   ===================================================================== */
/* The middle track is sized by the GRID, not by its own width: an auto
   column asks the image for its max-content width, gets the file's 1080px
   and takes the whole row, leaving the two small cards at zero. */
/* The mailing-list sentence above the section's own label. It is set like the
   Shorts Fest notice -- see .shorts-notice__text further up, which it shares
   its selectors with -- so all that is left here is the gap to the label
   under it. This rule comes after that one, so it wins on margin. */
.newsreel__signup{margin-bottom:calc(clamp(20px,2.6vw,32px) + 10px)}
/* Frank asked on 2026-10-30 for the sentence to sit closer to the hero. It is
   the first thing in this section, so the section's own top padding was the
   whole gap -- clamp(56px,8vw,104px) from .section, which is 104px at desktop
   width. Shortening the top padding here moves the sentence up and the news
   under it follows, which keeps the rhythm; raising the paragraph on its own
   would have left a hole between it and the label. The bottom padding is
   untouched, so the footer side of the section is unchanged.
   Frank then asked for 10px more above and below the sentence, so both gaps
   are the clamp plus a flat 10px rather than a rewritten clamp -- that way it
   is exactly ten more at every width, and the original value stays readable
   if he wants to move it again. */
.section.home-news{padding-top:calc(clamp(18px,2.4vw,30px) + 10px)}

.newsreel__stage{display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,520px) minmax(0,1fr);
  align-items:center;justify-items:center;gap:clamp(10px,2vw,26px)}
.newsreel__track{display:grid;margin:0;padding:0;list-style:none;width:100%}
.newsreel__slide{grid-area:1/1;opacity:0;visibility:hidden;
  transition:opacity .5s var(--ease),visibility .5s var(--ease)}
.newsreel__slide.is-current{opacity:1;visibility:visible}
/* The graphics are 1080px wide, so 520 is the largest the card can be drawn
   and still have two pixels of image per pixel of screen.

   drop-shadow, NOT box-shadow: the polaroid is cut out of its background,
   with transparent corners and a slightly ragged edge, so a box shadow
   would draw a hard rectangle in the gaps. drop-shadow follows the cut. */
.newsreel__img{width:100%;height:auto;
  filter:drop-shadow(0 18px 26px rgba(12,24,38,.28));
  transition:transform .25s var(--ease),filter .25s var(--ease)}
/* The card is a link to wherever its paragraph's first "click here" goes.
   One card -- Chris Morris -- has no link in its copy, so it is a plain
   picture and quite deliberately does not lift under the pointer. */
.newsreel__link{display:block}
.newsreel__link:hover .newsreel__img{transform:translateY(-6px);
  filter:drop-shadow(0 26px 34px rgba(12,24,38,.34))}
.newsreel__link:focus-visible{outline:2px solid var(--green-deep);
  outline-offset:6px;border-radius:2px}

/* The card before and the card after. A mouse can click them to go that way;
   they are out of the tab order and hidden from screen readers, which have
   the arrows below, so the same move is not offered twice. */
.newsreel__peek{width:min(200px,100%);padding:0;border:0;background:none;
  display:block;cursor:pointer;opacity:.6;
  transition:opacity .3s var(--ease),transform .3s var(--ease)}
.newsreel__peek img{width:100%;height:auto;
  filter:drop-shadow(0 12px 18px rgba(12,24,38,.22))}
.newsreel__peek:hover{opacity:1;transform:translateY(-4px)}

/* The paragraph runs the full page column, centred. 1.4rem is the size the
   section headings are set at -- the one over the partner logos, for
   instance -- so the two read as the same rank of text (Frank, 2026-10-30). */
.newsreel__copies{display:grid;margin:clamp(26px,3.5vw,40px) 0 0;padding:0;
  list-style:none}
.newsreel__copy{grid-area:1/1;text-align:center;opacity:0;visibility:hidden;
  transition:opacity .5s var(--ease),visibility .5s var(--ease)}
.newsreel__copy.is-current{opacity:1;visibility:visible}
.newsreel__copy p{margin:0;font-size:1.4rem;color:var(--ink-soft);text-wrap:pretty}
/* The date each card is printed with, repeated at the head of its paragraph.
   Same treatment the dated news bullets on the New Moon page already use. */
.newsreel__date{font-family:var(--serif);color:var(--ink);font-weight:600}

.newsreel__controls{display:flex;align-items:center;justify-content:center;
  gap:clamp(14px,2.5vw,26px);margin-top:clamp(26px,3.5vw,40px)}
.newsreel__arrow{flex:0 0 auto;width:52px;height:52px;border-radius:50%;padding:0;
  display:grid;place-items:center;cursor:pointer;color:var(--ink);
  background:var(--paper);border:1px solid var(--sand);
  transition:transform .2s var(--ease),border-color .2s var(--ease),
  box-shadow .2s var(--ease)}
.newsreel__arrow svg{width:22px;height:22px}
/* One chevron drawn once, pointing left, and turned around for the other. */
.newsreel__arrow--next svg{transform:rotate(180deg)}
.newsreel__arrow:hover{transform:translateY(-2px);border-color:var(--green);
  box-shadow:0 16px 30px -22px rgba(12,24,38,.5)}
.newsreel__arrow:focus-visible{outline:2px solid var(--green-deep);outline-offset:3px}
.newsreel__dots{display:flex;align-items:center;gap:10px}
.newsreel__dot{width:11px;height:11px;padding:0;border-radius:50%;cursor:pointer;
  background:transparent;border:1.5px solid var(--ink-soft);
  transition:background .2s var(--ease),border-color .2s var(--ease),
  transform .2s var(--ease)}
.newsreel__dot:hover{border-color:var(--green-deep)}
.newsreel__dot.is-current{background:var(--ink);border-color:var(--ink);
  transform:scale(1.15)}
.newsreel__dot:focus-visible{outline:2px solid var(--green-deep);outline-offset:3px}

/* Below this the three cards have to share a column too narrow to read the
   big one in, so the neighbours drop and the card takes the full width. */
@media (max-width:900px){
  .newsreel__stage{grid-template-columns:minmax(0,520px);justify-content:center}
  .newsreel__peek{display:none}
}
@media (prefers-reduced-motion:reduce){
  .newsreel__slide,.newsreel__copy,.newsreel__peek{transition:none}
}

.program{background:var(--paper);border:1px solid var(--sand);border-radius:16px;
  padding:18px;display:flex;align-items:center;justify-content:center;
  text-decoration:none;color:var(--ink);min-height:150px;
  transition:transform .3s var(--ease),box-shadow .3s var(--ease),border-color .3s var(--ease)}
.program:hover{transform:translateY(-4px);box-shadow:0 24px 46px -30px rgba(12,24,38,.5);
  border-color:color-mix(in srgb,var(--green) 45%,var(--sand))}
/* =====================================================================
   VIDEO GRID  (embedded YouTube)
   ===================================================================== */
/* =====================================================================
   VIDEO LIST  (embedded YouTube — large, one per row, centered)
   ===================================================================== */
.videos{display:flex;flex-direction:column;align-items:center;gap:clamp(34px,5vw,56px);
  width:100%}
.video{width:100%;max-width:1350px}
@media (min-width:1200px){
  .videos{width:min(1350px,calc(100vw - 40px));margin-left:50%;transform:translateX(-50%)}
}
.video__frame{position:relative;aspect-ratio:16/9;border-radius:14px;overflow:hidden;
  background:#0b1622;border:1px solid var(--sand);
  box-shadow:0 16px 36px -26px rgba(12,24,38,.55)}
.video__frame iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
.video__title{font-family:var(--serif);font-size:1.3rem;margin:16px 2px 4px;line-height:1.2;
  text-align:center}
.video__title--above{margin:0 2px 16px;font-size:clamp(1.4rem,2.6vw,1.9rem)}
.video__meta{font-family:var(--mono);font-size:1.05rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-soft);margin:0 2px;text-align:center}

/* empty-state (classes) */
.empty{background:var(--paper);border:1px dashed var(--sand);border-radius:20px;
  padding:clamp(44px,7vw,80px);text-align:center;max-width:680px;margin-inline:auto}

.empty h2{font-size:1.8rem;margin-bottom:14px}
.empty p{color:var(--ink-soft);max-width:46ch;margin-inline:auto}

/* =====================================================================
   STAFF & BOARD  (directory rows — monogram + name on the left, bio right)
   ===================================================================== */
.roster{display:flex;flex-direction:column;border-top:1px solid var(--sand)}
/* One column, at every width. It was 288px for the name and role with the bio
   in a second column beside them, which gave a job title a 288px measure and
   broke the longer ones over three lines: "SPORTS / BROADCAST /
   HOST/PRODUCER". Frank asked for the titles to have the page (2026-10-30),
   so the row stacks and Read bio sits under the title instead of beside it.
   The gap is the one the stacked phone layout already used. */
.person{display:grid;grid-template-columns:1fr;gap:14px;align-items:start;
  padding:30px 8px;border-bottom:1px solid var(--sand);
  transition:background .25s var(--ease)}
.person:hover{background:color-mix(in srgb,var(--paper) 65%,transparent)}
.person__head{display:flex;align-items:center;gap:14px}
.monogram{flex:0 0 auto;width:54px;height:54px;border-radius:50%;
  background:linear-gradient(155deg,#21456b,#0c1826);color:var(--fog);
  display:grid;place-items:center;font-family:var(--serif);font-size:1.2rem;
  letter-spacing:.02em;box-shadow:inset 0 0 0 1px rgba(255,255,255,.06)}
/* Name and email share a line (Frank, 2026-10-30). Baseline rather than
   centre, so the two sit on one baseline rather than the address floating in
   the middle of the name's line box. It wraps where it has to: both halves
   are the same size now, so the pair is wide, and "JohnCarl McGrady" plus his
   address is the first to break at about 640px. Four have broken by 500px and
   all seven by 375px, where the row reads as name, address, title stacked.
   Nothing overflows at any of those widths -- that is what the wrap buys. */
.person__line{display:flex;align-items:baseline;flex-wrap:wrap;
  column-gap:12px;row-gap:2px}
/* Same face and size for both (Frank, 2026-10-31), so the address shares the
   name's rule instead of holding a copy of it: restyle one and the other
   follows. Colour is what separates them now -- the name --ink against the
   address --ink-soft -- since size no longer does. */
.person__name,.person__email,.person__sep{font-family:var(--serif);
  font-size:1.34rem;line-height:1.12}
/* The divider Frank asked for on 2026-10-31. --sand is the token the row
   rules themselves use, so the bar reads as the same hairline family rather
   than as a third piece of text. It is in the shared size rule above so its
   cap height matches the name's exactly; set at any other size it sits
   visibly short or tall between them. */
.person__sep{color:var(--sand);-webkit-user-select:none;user-select:none}
.person__role{font-family:var(--mono);font-size:0.99rem;letter-spacing:.15em;
  text-transform:uppercase;color:var(--green-deep);margin-top:6px}
.person__email{margin:0}
.person__email a{color:var(--ink-soft);text-decoration:none;
  border-bottom:1px solid var(--green);padding-bottom:1px}
.person__email a:hover{color:var(--green-deep)}
.person__bio{max-width:74ch;color:var(--ink-soft);font-size:1rem;line-height:1.66}
.person__bio p{margin:0 0 .85em}
.person__bio p:last-child{margin-bottom:0}
@media (max-width:760px){
  /* The columns and the gap are the default now; only the padding differs. */
  .person{padding:26px 0}
  /* Narrow enough that the pair cannot share a row -- the monogram takes 68px
     and the address alone runs about 200px at this size -- so stack them
     outright instead of letting flex-wrap do it per person. Wrapping would
     leave the bar stranded at the head of the address's own line, and it
     would strand at a different width for every name. */
  .person__line{flex-direction:column;flex-wrap:nowrap;align-items:flex-start}
  .person__sep{display:none}
}

/* =====================================================================
   CONTACT
   ===================================================================== */
.contact{display:grid;grid-template-columns:1.1fr .9fr;gap:48px;align-items:start}
@media (max-width:820px){.contact{grid-template-columns:1fr;gap:32px}}
.infolist{list-style:none;padding:0;margin:0;display:grid;gap:2px}
.infolist li{padding:22px 0;border-bottom:1px solid var(--sand);display:grid;
  grid-template-columns:170px 1fr;gap:18px;align-items:baseline}
@media (max-width:560px){.infolist li{grid-template-columns:1fr;gap:4px}}
.infolist .k{font-family:var(--mono);font-size:1.08rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--green-deep)}
.infolist .v{font-size:1.08rem}
.infolist .v a{color:var(--ink);text-decoration:none;border-bottom:1px solid var(--green);
  padding-bottom:1px}
.infolist .v a:hover{color:var(--green-deep)}
.appt{background:var(--navy-deep);color:#fff;border-radius:20px;padding:34px 32px;
  position:relative;overflow:hidden}
.appt::after{content:"";position:absolute;right:-60px;bottom:-60px;width:200px;height:200px;
  border:2px solid rgba(79,179,94,.25);border-radius:50%}
.appt h3{color:#fff;font-size:1.6rem;position:relative}
.appt p{color:#cdd7dc;margin:14px 0 24px;position:relative}
.channels{display:flex;gap:14px;margin-top:26px;position:relative;flex-wrap:wrap}
.chip{font-family:var(--mono);font-size:1.2rem;letter-spacing:.1em;color:#cfe6d4;
  border:1px solid rgba(79,179,94,.45);border-radius:999px;padding:8px 16px}

/* =====================================================================
   CREATE
   ===================================================================== */
.create-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px;margin-top:8px}
@media (max-width:1000px){.create-grid{grid-template-columns:1fr 1fr}}
@media (max-width:620px){.create-grid{grid-template-columns:1fr}}
.signup{background:var(--paper);border:1px solid var(--sand);border-radius:20px;
  padding:34px 32px;display:flex;flex-direction:column;transition:transform .3s var(--ease),
  box-shadow .3s var(--ease)}
.signup:hover{transform:translateY(-4px);box-shadow:0 26px 50px -32px rgba(12,24,38,.5)}
.signup__tag{font-family:var(--mono);font-size:1.08rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--green-deep)}
.signup h3{font-size:1.7rem;margin:12px 0 10px}
.signup p{color:var(--ink-soft);font-size:1rem;flex:1}
/* All three pictures are cut to 4:5 at export, which is the Member Kits
   graphic's own shape, so the cards line up and nothing is cropped twice.
   object-fit is only insurance if one is ever replaced at another ratio. */
.signup__photo{display:block;width:100%;height:auto;aspect-ratio:4/5;object-fit:cover;
  border-radius:14px;margin-bottom:20px;background:var(--fog)}
/* The gear card's button is a label, not a link: there is nothing to open, it
   just gives the address to write to. Keeping it a span rather than a mailto
   is deliberate, so it drops the hover lift and the pointer with it. */
.btn--static{border-color:var(--ink);color:var(--ink);cursor:default}
.btn--static:hover{transform:none;background:transparent;color:var(--ink)}

/* =====================================================================
   FOOTER
   ===================================================================== */
.footer{background:var(--navy-deep);color:#aec0c8;padding-block:60px 38px;margin-top:0}
.footer a{color:#cfe6d4;text-decoration:none}
.footer a:hover{color:#fff}
.footer__top{display:flex;align-items:center;justify-content:space-between;
  gap:30px;flex-wrap:wrap}
.footer__addr{font-size:.97rem;line-height:1.75;max-width:40ch;margin:0}
.footer__brand{display:inline-flex;align-items:center}
.footer__brand img{height:62px;width:auto;display:block}
/* Facebook and Instagram, inside .footer__addr. A <span> rather than a <div>
   because it sits inside a paragraph, which a div may not. */
/* align-items:center arrived with the label on 2026-10-31: flex items stretch
   by default, which left the words sitting at the top of the 42px icons. The
   wrap is for a narrow phone, where the label plus two icons is about 230px
   against a column that can be narrower. */
.footer__social{display:flex;align-items:center;flex-wrap:wrap;gap:12px;margin-top:18px}
.footer__social a{display:inline-flex;align-items:center;justify-content:center;
  width:42px;height:42px;border-radius:50%;border:1px solid rgba(255,255,255,.22);
  transition:background .15s var(--ease),border-color .15s var(--ease),color .15s var(--ease)}
.footer__social a:hover{background:var(--green-deep);border-color:var(--green-deep);color:#fff}
.footer__social svg{width:20px;height:20px;display:block}
@media (max-width:600px){
  .footer__top{gap:24px}
  .footer__brand img{height:50px}
}
.footer__bar{display:flex;flex-wrap:wrap;gap:14px;justify-content:space-between;
  align-items:center;margin-top:46px;padding-top:22px;border-top:1px solid rgba(255,255,255,.1);
  font-family:var(--mono);font-size:1.08rem;letter-spacing:.1em;color:#6f8593}

/* =====================================================================
   SCROLL REVEAL  + reduced motion
   ===================================================================== */
[data-reveal]{opacity:0;transform:translateY(22px);
  transition:opacity .7s var(--ease),transform .7s var(--ease)}
[data-reveal].in{opacity:1;transform:none}
[data-reveal-d="1"]{transition-delay:.08s}
[data-reveal-d="2"]{transition-delay:.16s}
[data-reveal-d="3"]{transition-delay:.24s}
[data-reveal-d="4"]{transition-delay:.32s}

.hero__inner > *{opacity:0;animation:rise .9s var(--ease) forwards}
.hero__inner > *:nth-child(1){animation-delay:.15s}
.hero__inner > *:nth-child(2){animation-delay:.30s}
.hero__inner > *:nth-child(3){animation-delay:.45s}
.hero__inner > *:nth-child(4){animation-delay:.60s}
.hero__inner > *:nth-child(5){animation-delay:.72s}
@keyframes rise{to{opacity:1;transform:none}}

:focus-visible{outline:3px solid var(--green);outline-offset:3px;border-radius:4px}
/* ...which squares off whatever it lands on, since it carries its own 4px
   radius. A text input matches :focus-visible on a plain click, so clicking
   either search bar drew a near-rectangular ring inside a pill. The bars
   already show focus as a whole through :focus-within, so their inputs drop
   the ring; the round buttons keep theirs, shaped like themselves. Written
   with the pseudo-class so it wins on specificity wherever this rule sits. */
.nav__search-input:focus-visible,
.searchbox__input:focus-visible{outline:none}
.nav__search-btn:focus-visible{border-radius:50%}
.searchbox__btn:focus-visible{border-radius:999px}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation:none!important;transition:none!important;
    scroll-behavior:auto!important}
  [data-reveal]{opacity:1;transform:none}
  .hero__inner > *{opacity:1}
}

/* =====================================================================
   SITE TYPE SCALE -- standardised 2026-10-26 at Frank's request
   ---------------------------------------------------------------------
   Section title above a smaller subtitle, and a 20px body. Tried on the
   New Moon Fest page first, then adopted on all 33. It reverses what the
   site did before, where a 1.44rem mono eyebrow sat over a 2.1rem serif
   line.

   The order title > subtitle > body must hold at EVERY viewport width,
   not only a wide one. That is why the subtitles are a flat 1.4rem: their
   old clamp floor of 1.15rem fell below the 20px body, which put a
   subtitle under its own paragraph on any window below about 1320px.
   Titles never drop under 1.6rem, so the three stay in order everywhere.
   ===================================================================== */

/* Section titles. Fraunces 700 small caps; weight 700 is requested in the
   font URL in build.py -- without it the browser fakes the bold and the
   letters smear at this size. Scoped to .section__head so the hero and
   page-head eyebrows, which are a kicker on a photograph rather than a
   section title, keep the mono they have always had. */
.section__head .eyebrow{font-family:var(--serif);font-weight:700;
  font-size:clamp(1.6rem,2.45vw,2.1rem);letter-spacing:.1em;align-items:flex-start;
  line-height:1.65}
/* The dot is a fixed 8px elsewhere, a speck beside a title this size. A
   title that wraps -- and the long ones do, on a phone -- left the dot
   beside the middle line, so it is pinned to the first: half the 1.65 line
   box less half the dot, in em so it tracks the clamped size down. */
.section__head .eyebrow .dot{width:11px;height:11px;margin-top:calc(.825em - 5.5px)}
/* A head carrying only a title and a subtitle has no reading measure to
   keep, and the bigger title wants the room before it wraps. Heads that
   also carry body copy keep the 64ch measure, which is what :has() tests. */
.section__head:not(:has(p)){max-width:none}

/* ---------------------------------------------------------------------
   Prose that sets a size of its own, moved by the same 20/17 the body
   moved by. Without this each would have kept a size chosen against a
   17px body and read as a different page's type beside a 20px one.
   --------------------------------------------------------------------- */
/* Lead and description paragraphs. These ran *below* 20px once the body
   moved, so a lead would have been smaller than the text it introduces. */
.lead{font-size:1.39rem}
.section__head p{font-size:1.27rem}
.pagehead p{font-size:1.24rem}
/* "To return to the main Nonprofit Videos page, click here." and "To
   visit their website, click here." -- sentences, not lead-ins, so they
   sit at the body size rather than a step above it. .dl-programs__after
   is the same closing-sentence shape and comes with them. */
.dl-backlink__text,.dl-mission__link,.dl-programs__after{font-size:20px}
.news-sign,.awards-text{font-size:clamp(1.2rem,1.47vw,1.36rem)}
.watch-episode__desc,.watch-episode__note{font-size:clamp(1.18rem,1.41vw,1.32rem)}
.photo-credit{font-size:clamp(1.12rem,1.29vw,1.24rem)}
.card p{font-size:1.15rem}
.person__bio,.signup p{font-size:1.18rem}
/* A nested sub-summary sits under a subtitle, so it stays below 1.4rem --
   but its floor was under the body size too. */
.dl-group--sub>summary{font-size:1.25rem}
/* Table copy, kept in step with the rows around it. */
.shows__table td{font-size:clamp(1.15rem,1.41vw,1.27rem)}
.shows__table tbody th{font-size:clamp(1.29rem,1.76vw,1.53rem)}
/* Video and person cards. */
.video__title{font-size:1.53rem}
.video__meta{font-size:1.24rem}
.person__name,.person__email,.person__sep{font-size:1.58rem}
.person__role{font-size:1.16rem}
/* New Moon Fest's own blocks: the auction note and rules lead-in, the
   partner rows, and the film-card metadata under each title. */
.auction-note,.nmf-rules__submit{font-size:clamp(1.29rem,1.71vw,1.48rem)}
.auction-partners__name{font-size:1.39rem}
.auction-partners__what{font-size:1.18rem}
.movie-meta{font-size:1.01rem}
.movie-award{font-size:1.08rem}
.movie-credits{font-size:1.15rem}
.movie-credits-h{font-size:.94rem}
.movie-directed{font-size:1.2rem}
/* Notes, intros and the agendas. The agenda is the largest body of reading
   on the site -- nine thousand list items on Civic TV alone -- and it sat
   4px under the new body size, so it moves with everything else. */
.dl-group__intro,.watch-episode__agenda,
.nmf-history__p{font-size:clamp(1.18rem,1.41vw,1.32rem)}
/* The three headings that open a part of the history sit two steps above that
   prose, at every width: 1.18-1.32rem to 1.25-1.40 to 1.32-1.48, the same
   ladder .news-sign and .auction-note climb. Frank asked for the two steps on
   2026-10-30. The two section lines inside them stay at prose size and are
   told apart by their weight, so the piece reads at three levels, not two. */
.nmf-history__p--title{font-size:clamp(1.32rem,1.58vw,1.48rem)}
/* The banner's title card. The standfirst is NOT given .hero__sub's clamp,
   whose 1rem floor would put this paragraph at 16px on a phone: it is the
   page's introduction, the same 54 words that sat at a flat 20px in the band
   under the banner, and a hero is no reason to shrink them. The floor holds
   it near the body size and the ceiling keeps it under it. The lead above is
   the loudest line of type on the page after the logo. */
.vhero-card__text{font-size:clamp(1.15rem,1.55vw,1.3rem)}
.vhero-card__lead{font-size:clamp(1.6rem,3vw,2.4rem)}
.dl-mission__note{font-size:clamp(1.18rem,1.47vw,1.32rem)}
.video-credit{font-size:1.18rem}

/* ---------------------------------------------------------------------
   The line that opens a mission block reads as that section's title:
   "The Nantucket Golf Club Foundation's Mission:" on the nonprofit
   pages, the school name on School Videos. Same family, weight, colour,
   size and tracking as .section__head .eyebrow; no dot, because that is
   markup inside a section head rather than a style.

   :first-child is what separates the heading from the sub-headings that
   share this class *inside* a mission statement -- "Grantmaker",
   "Environment", "The Nantucket Food Pantry" on the Community
   Foundation, Remain and NFFRA pages. Those are not section titles, and
   Frank said so explicitly on 2026-10-26. Every one of the 21 mission
   blocks opens with its heading as the paragraph's first child, and no
   sub-heading ever is, so the position tells them apart without a second
   class in the markup.

   The tight line-height stops a wrapped heading opening a 1.65 gap, and
   the space under it replaces what the smaller lead got from its line
   box.
   --------------------------------------------------------------------- */
.dl-mission__text > .dl-mission__lead:first-child{font-weight:700;
  font-size:clamp(1.6rem,2.45vw,2.1rem);letter-spacing:.1em;text-transform:uppercase;
  line-height:1.2;display:inline-block;margin-bottom:10px}

/* ---- A button behaves like a button, never like text ---------------------
   Frank, 2026-10-31: clicking a logo button -- the Book Festival one in the
   home page's nonprofit grid -- sometimes turned the pointer into an I-beam
   and the click did not land.

   Nothing on the site declares `cursor:text`; every control already computed
   `pointer`. The cause is the press itself. With `user-select:auto` a click
   that drifts a pixel or two stops being a click and becomes a text
   selection, and over a logo `<img>` it can instead start an image drag --
   either way the pointer changes mid-gesture and the activation is lost.
   Safari begins both more eagerly than Chromium, which is why it shows on
   Frank's machine and not in the preview pane.

   So each control states all three: the hand, no selection, no image drag.
   `cursor:pointer` is belt and braces -- it was already correct everywhere --
   but it means a control added later cannot inherit an I-beam by omission.

   The list is explicit rather than a blanket `a` rule because body copy, the
   footer address and the mailto/tel links have to stay selectable: people
   copy those. `.btn--static` is excluded for the same reason -- it is the
   span reading "Email info@ournctv.org", which is there to be read off. */
button,
summary,
.btn:not(.btn--static),
.nav__link, .nav__brand, .skip-link,
.watch-episode__link, .watch-episode__more,
.sport-link, .partner, .cfn-fund, .cfn-funds__mark,
.ff-btn, .hero-chip, .civic-links__btn, .filmmap__btn,
.newsreel__link, .encore-img-link,
.sponsor-map__box, .sponsor-map__btn, .sponsormap__btn,
.auction-partners__shop, .video-credit__cta,
.footer__social a{
  cursor:pointer;
  -webkit-user-select:none;
  user-select:none;
}

/* A greyed control keeps the arrow. This has to be restated: the 2,243
   pending agenda buttons carry `.watch-episode__link` too, and that selector
   is listed above and sits later in the file, so it would otherwise take
   `cursor:default` away from them. `:disabled` outranks both.
   `.photo-grid__item` needs no restating -- its own `cursor:zoom-in` already
   outranks the bare `button` above -- and `.year-btn:disabled` and
   `.quarter-btn:disabled` outrank everything here. */
button:disabled{cursor:default}

/* A logo is the whole face of its button; peeling it off as a dragged image
   is never what the click meant. Applies to every linked image, including
   the ones not listed above. */
a img, button img{-webkit-user-drag:none;user-drag:none}
