html, body { background: #f5f5f4; }
body { font-feature-settings: "cv11", "ss01"; -webkit-font-smoothing: antialiased; }
.label { font-size: 10.5px; font-weight: 500; letter-spacing: .06em; text-transform: uppercase; color: #737373; }
.hint { font-size: 11.5px; color: #737373; line-height: 1.45; margin-top: 5px; }
.num { font-family: "JetBrains Mono", ui-monospace, monospace; font-variant-numeric: tabular-nums; }
.field { height: 32px; border: 1px solid #e5e5e5; border-radius: 6px; background: #fff; padding: 0 10px; font-size: 13px;
         transition: border-color .15s, box-shadow .15s; }
.field:hover { border-color: #d4d4d4; }
.field:focus { outline: none; border-color: #525252; box-shadow: 0 0 0 3px rgba(82,82,82,.12); }
.seg { display: inline-flex; background: #f5f5f5; border: 1px solid #e5e5e5; border-radius: 7px; padding: 2px; gap: 2px; }
.seg button { height: 26px; min-width: 32px; padding: 0 9px; border-radius: 5px; font-size: 12px; color: #525252;
              transition: background .15s, color .15s, box-shadow .15s; }
.seg button:hover { color: #171717; }
.seg button:disabled { opacity: .45; cursor: default; }
.seg button[aria-pressed="true"] { background: #fff; color: #171717; box-shadow: 0 1px 2px rgba(0,0,0,.08), 0 0 0 1px #e5e5e5; }
.card { background: #fff; border: 1px solid #e7e5e4; border-radius: 10px; }
.cell { cursor: pointer; transition: fill-opacity .25s; }
.cell:hover { stroke: #171717; stroke-width: 1.5; }
.cell:focus { outline: none; }  /* the map draws its own ring, which the frame doesn't cut (see drawFocusRing) */
/* The card for a cell: its ratings as badges, a line or two, and what a click or a key does. */
#cellCard .cc-head { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; }
#cellCard .cc-head > span { display: inline-flex; align-items: center; gap: 6px; color: #525252; }
#cellCard .cc-line { margin-top: 5px; color: #404040; }
#cellCard .cc-hint { margin-top: 7px; padding-top: 6px; border-top: 1px solid #f0efee; font-size: 11px; color: #737373; }
input[type=range] { accent-color: #262626; }
.switch { position: relative; width: 30px; height: 18px; border-radius: 9px; background: #d4d4d4; transition: background .15s; flex-shrink: 0; }
.switch::after { content: ""; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: #fff;
                 box-shadow: 0 1px 2px rgba(0,0,0,.2); transition: transform .15s; }
.switch[aria-checked="true"] { background: #262626; }
.switch[aria-checked="true"]::after { transform: translateX(12px); }
.fade-in { animation: fade .25s ease; }
.cellshade, .cell-label, .tiles { transition: fill-opacity .3s ease, opacity .3s ease; }
@media screen {
  #map.map-front .cellshade { fill-opacity: .06 !important; }
  #map.map-front .cell-label { opacity: 0; }
  #map.map-front .tiles { opacity: 1; }
}
.cellgroup { transition: opacity .3s ease; }
/* A result being replaced (stale) stays in colour, faded, so a change reads as before and after; one kept after a
   failed run turns grey. Neither can be clicked. */
#map.stale .cellgroup { opacity: .6; transition: opacity .2s; }
#map.failed .cellgroup { filter: url(#stale); opacity: .55; }
#map.stale .cell { pointer-events: none; }
body.focus #leftPanel, body.focus #rightPanel, body.focus header { display: none; }
body.focus #layout { grid-template-columns: minmax(0, 1fr); height: 100vh; }
.pending { fill: #737373; fill-opacity: .03; animation: pending 1.4s ease-in-out infinite both; pointer-events: none; }
@keyframes pending { 0%, 100% { fill-opacity: .03; } 45% { fill-opacity: .26; } }
.reveal { animation: reveal .4s ease backwards; }  /* backwards: hold the start until the delay ends, then let styles take over */
@keyframes reveal { from { opacity: 0; } to { opacity: 1; } }
@keyframes fade { from { opacity: 0; transform: translateY(2px); } to { opacity: 1; transform: none; } }
.scroll-thin::-webkit-scrollbar { width: 6px; } .scroll-thin::-webkit-scrollbar-thumb { background: #d4d4d4; border-radius: 3px; }
details > summary { list-style: none; cursor: pointer; } details > summary::-webkit-details-marker { display: none; }
details[open] .chev { transform: rotate(90deg); }

/* The analysis log in the Result grows from the bottom of the space the verdict will take; once it is full, older lines
   fade out at the top. */
#resultLog.full { -webkit-mask-image: linear-gradient(to bottom, transparent, #000 50%); mask-image: linear-gradient(to bottom, transparent, #000 50%); }
@media screen { #resultLog { height: 111px; } }  /* the verdict and its four-line text */

/* "?" buttons with a short explanation (see explain.js). They look 14 px wide but take clicks 24 px wide. */
.info { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; flex-shrink: 0;
        border-radius: 9999px; border: 1px solid #d4d4d4; background: #fff; color: #8a8a8a; font-size: 9.5px; font-weight: 500;
        line-height: 1; letter-spacing: 0; text-transform: none; }
.info::before { content: ""; position: absolute; inset: -6px; border-radius: 9999px; }
.info:hover, .info[aria-expanded="true"] { border-color: #525252; color: #171717; }

/* How to read this lists every key once, each drawn as a key. */
#helpPop kbd { font-size: 11px; line-height: 15px; color: #404040; border: 1px solid #e5e5e5; border-radius: 4px; padding: 0 4px; }

/* An hour earlier and later, either side of the When button. */
.step-hour { display: flex; align-items: center; justify-content: center; flex-shrink: 0; width: 24px; height: 32px; border-radius: 6px;
             border: 1px solid #e5e5e5; color: #525252; transition: border-color .15s, color .15s; }
.step-hour:hover:not([aria-disabled="true"]) { border-color: #a3a3a3; color: #171717; }
.step-hour[aria-disabled="true"] { color: #d4d4d4; cursor: default; }

/* The map card's head, above the frame and lined up with the street map's edges (alignMapHead in map.js): on the left
   what the map shows, on the right the toolbar, one white pill of borderless buttons with hairline dividers. The pill is
   as tall as the head; the drawing starts just above the frame's ticks, so the frame sits about 10 px below it.
   fitMapHead sets how much the pill shows (data-fit): labels and key hints, labels, Zoom in's label only, or icons. Each
   button has a tip that shows at once, under it: its label and key, or why it is off. */
#mapHead { position: relative; z-index: 25; display: flex; align-items: center; justify-content: space-between; gap: 12px;
           flex-shrink: 0; height: 30px; margin-bottom: 4px; }
#mapLabel { display: flex; align-items: center; gap: 6px; min-width: 0; font-size: 12px; line-height: 16px; color: #737373; }
#mapLabelText { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#toolbar { display: flex; align-items: center; gap: 1px; padding: 2px; border: 1px solid #e7e5e4; border-radius: 8px; background: #fff; }
#toolbar:not(:has(> button:not(.hidden))) { display: none; }  /* no city yet */
#toolbar > button { position: relative; display: flex; align-items: center; justify-content: center; gap: 6px; height: 24px;
                    padding: 0 8px; border-radius: 6px; font-size: 12px; color: #404040; white-space: nowrap;
                    transition: background-color .12s, color .12s; }
#toolbar > button.hidden { display: none; }
#toolbar > button:hover { background-color: #f5f5f4; color: #171717; }
#toolbar > button:is([aria-expanded="true"], [data-on="true"]) { background-color: #ebeae7; color: #171717; }
#toolbar > button:focus-visible { outline: 2px solid #525252; outline-offset: -2px; }
#toolbar > button[aria-disabled="true"] { cursor: default; background-color: transparent; color: #404040; }
#toolbar > button[aria-disabled="true"] > * { opacity: .45; }  /* not its tip */
#toolbar > button:not(.hidden) ~ button:not(.hidden)::before { content: ""; position: absolute; left: -1px; top: 6px; bottom: 6px;
  width: 1px; background: #e7e5e4; pointer-events: none; }
#toolbar kbd { font-size: 10px; line-height: 14px; color: #737373; border: 1px solid #e5e5e5; border-radius: 4px; padding: 0 4px; }
#mapTools:not([data-fit="keys"]) #toolbar kbd { display: none; }
#mapTools[data-fit="zoom"] #toolbar > button:not(#zoomButton), #mapTools[data-fit="icons"] #toolbar > button { width: 28px; padding: 0; }
#mapTools[data-fit="zoom"] #toolbar > button:not(#zoomButton) > span, #mapTools[data-fit="icons"] #toolbar > button > span {
  position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; }
#toolbar > button[data-tip]::after { content: attr(data-tip); position: absolute; z-index: 60; top: calc(100% + 8px); left: 50%;
  transform: translateX(-50%); padding: 4px 8px; border-radius: 6px; background: #1c1917; color: #fafaf9; font-size: 11.5px;
  line-height: 16px; font-weight: 500; white-space: nowrap; pointer-events: none; box-shadow: 0 4px 14px rgba(0,0,0,.16);
  opacity: 0; visibility: hidden; transition: opacity .1s, visibility .1s; }
#toolbar > button:last-of-type::after { left: auto; right: 0; transform: none; }  /* inside the window in Full view */
#toolbar > button:is(:hover, :focus-visible)::after { opacity: 1; visibility: visible; transition-delay: .3s; }
#toolbar > button[aria-expanded="true"]::after { display: none; }
/* On narrow screens the toolbar sits at the right edge: tips open leftwards and wrap, so they never widen the page. */
@media (max-width: 1023px) {
  #toolbar > button[data-tip]::after { left: auto; right: 0; transform: none; width: max-content; max-width: min(260px, 70vw);
                                       white-space: normal; }
}

/* Next 12 hours: play the ribbon on the sky plot. The button lines up with the ribbon's blocks. */
.play { display: flex; align-items: center; justify-content: center; flex-shrink: 0; width: 22px; height: 18px; border-radius: 4px;
        border: 1px solid #d4d4d4; background: #fff; color: #404040; transition: border-color .15s, color .15s, background .15s; }
.play:hover:not(:disabled) { border-color: #525252; color: #171717; }
.play[aria-pressed="true"] { background: #262626; border-color: #262626; color: #fff; }
.play:disabled { color: #d4d4d4; cursor: default; }
#ribbon:focus-visible { outline: 2px solid #525252; outline-offset: 2px; border-radius: 2px; }
/* A finger sliding along the ribbon previews, rather than scrolling the page sideways; up and down still scrolls. */
#ribbon { touch-action: pan-y; }
/* Words for a mouse, or for a touch screen (pointer: coarse), where there is no hover. */
.on-coarse { display: none; }
@media (pointer: coarse) {
  .on-fine { display: none; }
  .on-coarse { display: inline; }
}
/* While a step is previewed, the sky plot's satellites glide from one step to the next (see report.js). */
#sats.glide > g { transition: transform .12s linear; }

/* Lines of the report that some spots don't have (the comparison, the worst and best stretches) leave no gap. */
#nowCompare:empty, #nextWindows:empty { display: none; }

/* The report's spot switch: three cards with the spot and its rating; the one in the report is outlined. */
.spot { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; min-width: 0; padding: 7px 10px; text-align: left;
        background: #fafafa; border: 1px solid #e5e5e5; border-radius: 7px; transition: border-color .15s, background .15s, box-shadow .15s; }
.spot:hover { border-color: #a3a3a3; }
.spot[aria-pressed="true"] { background: #fff; border-color: #262626; box-shadow: inset 0 0 0 1px #262626; }
.spot-name { font-size: 11px; line-height: 1.3; color: #737373; }
.spot[aria-pressed="true"] .spot-name { color: #171717; font-weight: 500; }
.spotBadge { display: flex; align-items: center; gap: 6px; height: 18px; font-size: 13px; line-height: 18px; font-weight: 500; color: #171717; white-space: nowrap; }

/* Number boxes: the number on top, the label under it, so numbers line up however the labels wrap. */
.stat { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding: 6px 8px; background: #fafafa; border: 1px solid #e5e5e5; border-radius: 6px; }
.stat dd { order: -1; font-family: "JetBrains Mono", ui-monospace, monospace; font-variant-numeric: tabular-nums; font-size: 15px;
           line-height: 1.25; font-weight: 500; color: #171717; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stat dt { font-size: 10.5px; line-height: 1.25; color: #737373; }
.stat-of { font-size: 11px; color: #737373; }

/* Skeletons: light grey bars in the shape of what is coming, pulsing with the map's pending cells. */
.sk { display: inline-block; vertical-align: middle; width: var(--w, 100%); max-width: 100%; height: .75em; border-radius: 3px;
      background: #e7e5e4; animation: sk 1.4s ease-in-out infinite; }
.sk-box { background: #e7e5e4 !important; color: transparent !important; animation: sk 1.4s ease-in-out infinite; }
.sk-fill { fill: #e7e5e4; animation: sk 1.4s ease-in-out infinite; }
@keyframes sk { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
@media (prefers-reduced-motion: reduce) {
  .sk, .sk-box, .sk-fill, .reveal, .fade-in { animation: none; }
  .pending { animation: none; fill-opacity: .12; }
  #sats.glide > g { transition: none; }  /* a preview steps without moving in between */
}
/* Room for the texts that replace skeletons in the heads, so the map and the spot cards don't jump when results
   arrive. The Result and the report's body keep none: room for their longest texts left gaps under the usual short
   ones. Their skeletons are sized for the common case instead, and a longer text pushes what is below down a little.
   Screen only: print has its own layout. */
@media screen {
  #areaSub { min-height: 1.5em; }
  #placeWhat { min-height: 3em; }  /* two lines */
  #legend { min-height: 38px; }
  /* Next 12 hours: its key above the ribbon, so the ribbon sits just above the sky plot it previews. Print keeps the
     ribbon first. */
  #nextSection { display: flex; flex-direction: column; }
  #nextBreakdown { order: 1; }
  #ribbonRow, #ribbonHint { order: 2; }
}

/* Printing: the live view becomes a two-page report. Page 1 is the area, page 2 the selected spot. */
.print-only, .print-inline { display: none; }
@media print {
  @page { margin: 12mm; }
  html, body { height: auto !important; overflow: visible !important; background: #fff; }
  body { display: block !important; font-size: 12.5px; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
  .no-print { display: none !important; }
  .print-only { display: block; }
  .print-inline { display: inline; }
  #layout, #leftPanel, #leftScroll, main, #rightPanel, #mapCard { display: block !important; height: auto !important; min-height: 0 !important;
    overflow: visible !important; border: 0 !important; padding: 0 !important; position: static !important; }
  body.focus #leftPanel, body.focus #rightPanel { display: block !important; }
  #areaStats { margin-top: 3mm; break-inside: avoid; }
  #mapCard { margin-top: 3mm; }
  #map { width: 106mm !important; height: 111.7mm !important; max-height: none !important; margin: 0 auto; }
  #legend { justify-content: center; margin-top: 2mm; break-inside: avoid; }
  #rightPanel { break-before: page; }
  #rightPanel > .sticky { position: static !important; padding: 0 0 3mm !important; backdrop-filter: none; }
  #placeName, #placeSub { white-space: normal !important; overflow: visible !important; }
  #report { padding: 0 !important; }
  #report > * + * { margin-top: 3mm !important; }
  #ribbonRow { display: block !important; }
  #ribbon { width: 125mm !important; }
  #report section, #printFoot > * { break-inside: avoid; }
  /* What blocks the sky: text and key on the left, the sky plot on the right */
  #whySection { display: grid; grid-template-columns: minmax(0, 1fr) 50mm; grid-template-rows: auto auto auto 1fr; column-gap: 6mm; align-items: start; }
  #whySection > * { grid-column: 1; }
  #whySection > .skyWrap { display: contents; }
  #sky { grid-column: 2; grid-row: 1 / span 4; }
  #whySection .skyHint { grid-row: 3; }
  #whySection .skyKey { grid-column: 1; grid-row: 4; justify-content: flex-start; gap: 4mm !important; margin-top: 1.5mm; }
  #printFoot { margin-top: 3mm !important; padding-top: 2mm; border-top: 1px solid #e5e5e5; }
  #ratingKey { columns: 2; column-gap: 6mm; }
  #ratingKey > li { break-inside: avoid; margin-bottom: 1mm; }
  #printSources { break-inside: avoid; }
  /* Print-only markup is written just before printing, too late for the Tailwind CDN to style it. */
  #printHead > div:first-child { padding-bottom: 6px; }
  #printHead h1 { font-size: 22px; }
  #printSources > .label { margin-right: 6px; }
}

/* When and Analysis settings: sheets from the bottom on narrow screens; on wide ones, drawers over the left panel, so
   the map stays in view (and can be used) while a change re-runs it. The status line at the foot says what the map shows. */
@media (max-width: 1023px) {
  .drawer { position: fixed !important; left: 0 !important; right: 0 !important; top: auto !important; bottom: 0;
            width: auto !important; max-height: 62vh !important; overflow-y: auto; z-index: 50;
            border-radius: 14px 14px 0 0; border-bottom: 0; box-shadow: 0 -8px 28px rgba(0,0,0,.16); animation: sheet .2s ease; }
  .drawer::before { content: ""; display: block; width: 36px; height: 4px; margin: -6px auto 10px; border-radius: 2px; background: #d6d3d1; }
  .drawer .drawer-foot { position: sticky; bottom: -16px; margin: 0 -16px -16px; padding: 10px 16px 12px; background: #fff; }
}
@keyframes sheet { from { transform: translateY(24px); opacity: 0; } to { transform: none; opacity: 1; } }
@media (min-width: 1024px) {
  .drawer { left: 0 !important; top: 0 !important; width: 100% !important; height: 100%; max-height: none !important;
            overflow-y: auto; border: 0; border-right: 1px solid #e7e5e4; border-radius: 0;
            box-shadow: 6px 0 18px -10px rgba(0,0,0,.18); animation: drawer .2s ease; }
  .drawer .drawer-foot { position: sticky; bottom: -16px; margin: 0 -16px -16px; padding: 10px 16px 12px; background: #fff; }
}
@keyframes drawer { from { opacity: 0; transform: translateX(-10px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .drawer { animation: none; } }

