/* player.css: what the three live pages share around the stage (visuals/stage.css draws inside it):
   the page, the place bar's room, the Read's fine print under the story, and the TV's lower third. */
:root { --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; --mono: ui-monospace, Menlo, monospace; color-scheme: dark;
  --barh: calc(58px + env(safe-area-inset-top)); }        /* the place bar over the top of the story (appkit.js bar()) */
html, body { margin: 0; background: #05090d; color: #f2efe4; font-family: var(--sans); -webkit-font-smoothing: antialiased; }
a { color: #9fe3f5; }
.stage .sizer { width: 100%; height: 100dvh; }
/* A region (body.my) and Southern California's story (body.coasts), and the California selector (body.home, its regions' tab): the story full screen above a slim tab and the 320×50 anchor,
   never under them; what's inside (the region's spots every three hours, appkit.js myRead; Southern California's regions,
   appkit.js regionRead) opens from the tab: a sheet from the bottom on a phone or an upright tablet, from 900 px wide a
   panel from the right edge (appkit.js turns its tab at the same width). */
:is(body.my, body.coasts, body.home) { --tab: 52px; --ad: 58px; --tabw: 46px; --rail: 400px; }
:is(body.my, body.coasts, body.home) .stage .sizer { height: calc(100dvh - var(--tab) - var(--ad)); }
.stage.covered .ov, .stage.covered .annos { visibility: hidden; }
.stage.covered.held .annos { visibility: visible; }     /* a fine print ending: its quotes stay up to be read under the end card (player.js end) */
.stage.dark .ak-story .low { background: none; }         /* no pictures yet: the words alone */
/* A shared read's own page (/r/…): which forecast it is, under the top bar, and the way to the current one. */
.saved { position: absolute; z-index: 7; top: calc(var(--barh) + 6px); left: 50%; transform: translateX(-50%); max-width: calc(100% - 24px); box-sizing: border-box; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; padding: 6px 12px; border-radius: 999px; background: rgba(5,10,16,.74); border: 1px solid rgba(242,239,228,.22);
  color: #f2efe4; font: 650 12.5px var(--sans); text-decoration: none; } .saved b { margin-left: 6px; color: #9fe3f5; }
.voiceonly { display: none; }       /* Voice only is gone (Kurtis, 2026-10-03); pages rendered before it (frozen shares, /r/…) still carry its screen */
/* The page's words (words.py; the templates' #words): the story, the spots, the hazards and the bulletins as text, the page itself
   without a script. On the page it reads like the fine print; inside the spots panel (player.js moves it there) its table and
   title step aside for the grid already drawn above it. */
.words { max-width: 560px; margin: 0 auto; padding: 18px 16px 8px; color: #f2efe4; }
.words h1 { font-size: 22px; line-height: 1.2; margin: 6px 0 4px; letter-spacing: -.01em; }
.words h2 { margin: 20px 0 6px; font-size: 12px; text-transform: uppercase; letter-spacing: .07em; color: #9aa8a4; }
.words p, .words li { font-size: 14.5px; line-height: 1.5; margin: 6px 0; } .words ul { padding-left: 18px; }
.words .when, .words .note, .words .foot { font-size: 12.5px; color: #9aa8a4; } .words .lead { font-weight: 650; font-size: 16px; }
.words .regions span { color: #9aa8a4; font-size: 13px; }
.words table.spots { width: 100%; border-collapse: collapse; font-size: 13px; line-height: 1.35; margin: 4px 0; }
.words table.spots th, .words table.spots td { padding: 6px 6px 6px 0; border-bottom: 1px solid rgba(242,239,228,.12); text-align: left; vertical-align: top; font-weight: 500; }
.words table.spots thead th { color: #9aa8a4; font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em; } .words table.spots thead small { display: block; text-transform: none; letter-spacing: 0; }
.words table.spots th[scope=row] { font-weight: 700; } .words table.spots td small { display: block; color: #9aa8a4; font-size: 11.5px; }
.ak-body .words { padding: 0 16px 8px; max-width: none; } .ak-body .words h1, .ak-body .words .when, .ak-body .words table.spots, .ak-body .words .note { display: none; }
.ak-body .words.beats .lead, .ak-body .words.beats .w-more { display: none; }   /* the panel shows the story's beats alone (config/story.json words.panel "beats"; Kurtis, 2026-10-23): the grid, the tide chart and Later this week above already say the rest */
/* The Read: under the story, the read in lines, an ad, and the fine print. */
.more { max-width: 560px; margin: 0 auto; padding: 18px 16px 40px; }
.more h4 { margin: 22px 0 8px; font-size: 12px; text-transform: uppercase; letter-spacing: .07em; color: #9aa8a4; }
.more p, .more li { font-size: 14.5px; line-height: 1.5; margin: 6px 0; } .more ul { padding-left: 18px; }
.more .src { display: inline-block; margin: 0 6px 6px 0; padding: 5px 9px; border: 1px solid rgba(242,239,228,.18); border-radius: 999px; font-size: 12.5px; text-decoration: none; }
.more .fresh { font-size: 12.5px; color: #9aa8a4; } .more .fresh b { color: #f2efe4; font-weight: 650; } #conf b { text-transform: capitalize; }
:is(body.my, body.coasts, body.home) .more { position: fixed; z-index: 40; left: 0; right: 0; bottom: var(--ad); height: calc(100dvh - var(--ad) - var(--barh)); max-width: none; padding: 0;
  display: flex; flex-direction: column; border-radius: 16px 16px 0 0; box-shadow: 0 -6px 22px rgba(0,0,0,.4); transform: translateY(calc(100% - var(--tab)));
  transition: transform .28s ease; }
:is(body.my, body.coasts, body.home) .more.open { transform: none; }
@media (min-width: 900px) {      /* the story the whole width; the panel off the right edge, its gold tab showing (appkit.js; trial nav-tabs) */
  :is(body.my, body.coasts, body.home) .stage .sizer { height: calc(100dvh - var(--ad)); }
  :is(body.my, body.coasts, body.home) .more { top: 0; padding-top: var(--barh); box-sizing: border-box; left: auto; width: var(--rail); height: auto; flex-direction: row; border-radius: 0; transform: translateX(100%); }
  /* to the top edge, no strip of map over it (Kurtis, 2026-10-04: "the gap is annoying"): the place bar's buttons sit on its dark top (the bar is above it) */
}
@media (min-width: 900px) {       /* the story beside an open panel (appkit.js tabbed; player.js sets data-stage at each beat, so it's measured then) */
  :is(body.my, body.coasts)[data-stage="open"] .stage { margin-right: var(--rail); }
  body.home.ak-regs-in main:not(.more) { margin-right: auto; }        /* the front page's regions are in its card: no rail to keep clear */
}
@media (prefers-reduced-motion: reduce) { :is(body.my, body.coasts, body.home) .more { transition: none; } }
/* The TV: the act and the clock up top, the line in a lower third, the venue's logo, a way onto a phone. */
body.tv { overflow: hidden; }
.ov { position: absolute; z-index: 3; text-shadow: 0 1px 3px rgba(0,0,0,.9); pointer-events: none; translate: var(--sx, 0) var(--sy, 0); }
.ov.act { left: 3vmin; top: 3vmin; font: 800 2.2vmin var(--sans); letter-spacing: .1em; text-transform: uppercase; }
.ov.act span { display: block; font: 600 2.4vmin var(--sans); letter-spacing: 0; text-transform: none; opacity: .85; margin-top: .4vmin; }
.ov.clock { right: 3vmin; bottom: 15vmin; font: 700 2.2vmin var(--mono); opacity: .8; }
.ov.third { left: 0; right: 0; bottom: 0; padding: 8vmin 3vmin 4vmin; background: linear-gradient(transparent, rgba(5,10,16,.88) 40%); translate: none; }
.ov.third .line { font: 750 4.4vmin/1.25 var(--sans); max-width: 70vw; translate: var(--sx, 0) var(--sy, 0); }
.ov.third .line mark { background: rgba(224,168,74,.28); color: inherit; border-radius: .6vmin; padding: 0 .5vmin; }
.ov.venue { right: 3vmin; top: 3vmin; z-index: 4; display: flex; gap: 1.4vmin; align-items: center; font: 750 2.6vmin var(--sans); }
.ov.venue img { max-height: 8vmin; max-width: 22vmin; object-fit: contain; }
.ov.venue .logo-ph { display: grid; place-items: center; width: 18vmin; height: 8vmin; border: .25vmin dashed rgba(242,239,228,.55); border-radius: 1vmin;
  font: 700 1.6vmin var(--sans); letter-spacing: .12em; text-transform: uppercase; opacity: .7; text-shadow: none; }     /* the free screen: where a shop's logo goes */
.ov.venue .logo-ph[hidden] { display: none; }
.ov.qr { right: 3vmin; bottom: 4vmin; z-index: 4; display: flex; gap: 1.4vmin; align-items: center; font: 650 1.9vmin var(--sans); }
.ov.qr #qr { width: 10vmin; height: 10vmin; background: #fff; border-radius: .8vmin; } .ov.qr #qr svg { width: 100%; height: 100%; display: block; }
@media (max-width: 600px) { .ov.qr { display: none; } .ov.third .line { max-width: none; } }      /* /tv on a phone: it is the phone already */
/* The wall, read across a room (Kurtis, 2026-10-12: /tv "shall showcase the best points"): the story's timeline at the foot of every beat,
   the line lifted over it as the story has it, the bulletins it comes from under the line, the advisories' calendar and the tracker clip;
   and everything pinned on the map at a size a room can read. --k is the room's scale, by the screen's height. */
body.tv { --k: 1; --kc: 1; } @media (min-height: 700px) { body.tv { --k: 1.3; --kc: 1.15; } } @media (min-height: 1000px) { body.tv { --k: 1.55; --kc: 1.3; } }      /* --kc: what's pinned on the map (a board's nine cards must fit) */
body.tv .ov.third { transition: padding-bottom .45s ease; }
body.tv .stage.tl-on .ov.third { padding-bottom: calc(6.5vmin + var(--tv-lift, 0px)); }
body.tv .stage.tl-on .ov.clock { opacity: 0; }                       /* the timeline's own clock says it, big */
body.tv .ov.clock { transition: opacity .4s; }
body.tv .ov.third .from { display: flex; align-items: center; gap: 1vmin; margin-top: 1.3vmin; font: 650 1.9vmin var(--sans); color: rgba(242,239,228,.8); }
body.tv .ov.third .from[hidden] { display: none; }
body.tv .ov.third .from::before { content: '✓'; display: inline-grid; place-items: center; width: 2.5vmin; height: 2.5vmin; border-radius: 50%; background: #ffd678; color: #0b1117; font: 900 1.5vmin/1 var(--sans); text-shadow: none; }
body.tv .ov.third .from i { font-style: normal; opacity: .5; }
/* the panels (stage.js trackGantt, alertPanel) drawn at desktop size and scaled up for the room from their foot, left; clear of the QR */
body.tv .stage .tg { left: 3vmin; right: auto; width: calc(60vw / var(--k)); max-width: none; transform: scale(var(--k)); transform-origin: 0 100%; }
body.tv .stage .tg .tgo { display: none; }
/* a phone with the chart off (config/story.json phone.chart; player.js chartOff): no swell line chart (.tg.tl) on any beat, the tracker
   beat's included; the windows and advisory panels (.tg.wp, .tg.ag) stay. Its height reads as 0, so the words sit at the foot and the
   cards and the camera (core.js portraitView) get the room */
body.no-chart .stage .tg.tl { display: none; }
/* the beat's clock on the map (stage.js clockChip), at the wall's scale; the corner clock stands down while the chip is up */
body.tv .ck b { font-size: calc(18px * var(--kc)); } body.tv .ck .tr { font-size: calc(11px * var(--kc)); }
body.tv .stage:has(.ck.on) ~ .ov.clock, body.tv .stage:has(.ck.on) .ov.clock { opacity: 0; }
/* what's pinned on the map: the cards, the places, the buoys, the advisories' surf, the forecasters' quotes */
body.tv .card { font-size: calc(12px * var(--kc)); padding: calc(6px * var(--kc)) calc(9px * var(--kc)) calc(7px * var(--kc)); border-radius: calc(10px * var(--kc)); }
body.tv .card .nm { font-size: calc(10.5px * var(--kc)); margin-bottom: calc(4px * var(--kc)); }
body.tv .card .ch { font-size: calc(13px * var(--kc)); padding: calc(2px * var(--kc)) calc(7px * var(--kc)); border-radius: calc(6px * var(--kc)); }
body.tv .card .bd { font-size: calc(11px * var(--kc)); margin-top: calc(4px * var(--kc)); }
body.tv .card.slim { padding: calc(4px * var(--kc)) calc(7px * var(--kc)) calc(5px * var(--kc)); }
body.tv .card.slim .nm { font-size: calc(9.5px * var(--kc)); } body.tv .card.slim .ch { font-size: calc(12px * var(--kc)); } body.tv .card.slim .bd { font-size: calc(10px * var(--kc)); }
body.tv .city span { font-size: calc(11px * var(--kc)); top: calc(-8px * var(--kc)); } body.tv .city.big span { font-size: calc(12px * var(--kc)); }
body.tv .buoy span { font-size: calc(10.5px * var(--kc)); }
body.tv .ac b { font-size: calc(13px * var(--kc)); } body.tv .ac span { font-size: calc(10px * var(--kc)); }
body.tv .quote { padding: calc(12px * var(--k)) calc(14px * var(--k)) calc(10px * var(--k)); }
body.tv .quote blockquote { font-size: calc(17px * var(--k)); } body.tv .quote figcaption { font-size: calc(10.5px * var(--k)); }
body.tv .quote figcaption .go { display: none; }                      /* nothing to tap on a wall */
/* A shop's spots (player.js spots(), trial shop-screen): each its own page in a frame (explore.js ?tv=1), over the map and its cards,
   under the venue and the QR; the TV's own words stand down while one plays. */
.stage .tvspots { position: absolute; inset: 0; z-index: 2; }
.stage .tvspots iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; opacity: 0; transition: opacity .7s ease; pointer-events: none; }
.stage .tvspots iframe.on { opacity: 1; }
.stage.spotting .ov.act, .stage.spotting .ov.third, .stage.spotting .ov.clock { visibility: hidden; }
/* The ad break (player.js adBreak; config/ads.json tv.break): one 16:9 slot over the whole stage, under the corner and the QR. */
.stage .tv-ad { position: absolute; inset: 0; z-index: 3; display: grid; place-items: center; background: #05090d; animation: ak-up .6s ease both; }
.stage .tv-ad img { width: 100%; height: 100%; object-fit: contain; }
.stage .tv-ad .ph { width: min(72vw, 128vh); aspect-ratio: 16 / 9; display: grid; place-items: center; border: 2px dashed #c9a400;
  background: repeating-linear-gradient(45deg, #fff8dc, #fff8dc 12px, #fff3c4 12px, #fff3c4 24px); color: #7a6200; font: 800 4vmin var(--sans); letter-spacing: .1em; }
.stage:has(.tv-ad) .ov.act, .stage:has(.tv-ad) .ov.third, .stage:has(.tv-ad) .ov.clock { visibility: hidden; }
/* ?embed=1: the story alone, filling a frame on another page. */
body.embed .more, body.embed .ak-foot-ad { display: none; } body.embed .stage .sizer, body.embed:is(.my, .coasts) .stage .sizer { height: 100dvh; } body.embed:is(.my, .coasts) .stage { margin-right: 0; }
/* The California selector's "Play its story ›" (narrate.home_html; home.html's own rule under it): the gold button the story's own buttons are
   (trial nav-tabs, Kurtis 2026-10-04: "same treatment for Play Its Story that needs to be the button thingy"). */
body.home .coast .go { display: inline-flex; align-items: center; gap: 9px; margin-top: 0; padding: 6px 18px 6px 6px; border: 1.5px solid #ffd678; border-radius: 999px;
  background: rgba(11,17,23,.8); color: #ffd678; font: 800 15px/1.2 var(--sans); }
body.home .coast .go::before { content: '▶'; display: grid; place-items: center; width: 26px; height: 26px; border-radius: 50%; background: #ffd678; color: #0b1117; font-size: 11px; padding-left: 2px; box-sizing: border-box; }
body.home .coast.live:hover .go { background: rgba(255,214,120,.16); }
/* Play is the card's one main action (trial brand-pass; Kurtis, 2026-10-05: the natural path is play the story first): filled gold */
body.home .coast .acts .go { background: #ffd678; color: #0b1117; } body.home .coast .acts .go::before { background: #0b1117; color: #ffd678; }
body.home .coast .acts .go:hover, body.home .coast.live:hover .acts .go { background: #ffe39b; }
