/* Wallpapers (WP-4): the studio, as the owner approved it at Gate 1 (2026-10-13).
 *
 * Carried over from the approved design's stylesheet (design-handoff/wallpapers/src/
 * wallpapers.css) and layered over fonts, tokens, shell and styles: every colour, radius,
 * space and type size is a Weather Hub token. The only literal colours sit on satellite
 * pixels (the veil outside the frame, the frame's edge, the credit's shadow) and the hatch
 * that marks ground outside the satellite's view; those must read the same over imagery in
 * either theme, and none is ever drawn into a saved file except the credit line.
 *
 * The map is live: MapLibre draws GIBS's tiles into `.wp-canvas`, and where GIBS serves no
 * imagery its tiles are transparent, so the stage's own hatch shows through exactly there. */

.wp [hidden] { display: none !important; }

/* One lift for everything that floats over satellite pixels: the frame's tag, the map's
   buttons and the notes laid on the map. Pixels are dark or bright regardless of theme. */
:root { --wp-lift: 0 2px 6px rgb(0 0 0 / .35); }

main.wp { max-width: var(--hub-width); width: calc(100% - 2 * var(--hub-gutter)); margin: 0 auto; padding: var(--sp-6) 0 var(--sp-8); }
/* The stage and its caption hold still beside the panel while the reader works down it, so
   the map, the meter and Save are on screen together: a change in the panel is seen on the
   map, and a move on the map is read in the meter. It sits under the sticky masthead at the
   height shell.js measures (--masthead-h), sized to fit the window with its caption. */
.wp-studio { display: grid; grid-template-columns: minmax(0, 1fr) 388px; gap: var(--sp-6); align-items: start; }
.wp-view { position: sticky; top: calc(var(--masthead-h) + var(--sp-4)); }

/* ---- The stage: the map with the frame drawn on it -------------------------------------- */

.wp-view { margin: 0; min-width: 0; }
.wp-map {
  position: relative; overflow: hidden; container-type: size;
  height: clamp(440px, calc(100vh - 360px), 820px);
  border-radius: var(--radius-surface);
  /* Ground outside the satellite's view: a hatch, never black, so it cannot be read as
     night or ocean on the map. A frame that reaches into it cannot be saved (Gate 1,
     decision 6 (b)). */
  background: repeating-linear-gradient(135deg, #45525f 0 6px, #222c37 6px 14px);
  /* The frame's on-screen width: as large as the stage allows at the file's own shape. */
  --fw: min(calc(var(--fill) * 100cqw), calc(var(--fill) * 100cqh * var(--aspect)));
}
.wp-map:focus-visible, .wp-map[data-focus] { outline: var(--focus-ring); outline-offset: 3px; }
.wp-canvas { position: absolute; inset: 0; }
/* Earth from space (WP-10): one picture of the whole disk, moved and scaled under the frame.
   Black is space here, as it is in the saved file, and the caption says so: it is not the
   map's ground outside the satellite's view, which stays hatched. */
.wp-disk { position: absolute; inset: 0; overflow: hidden; background: #000; }
.wp-disk[hidden] { display: none; }
.wp-disk img { position: absolute; left: 0; top: 0; max-width: none; transform-origin: 0 0; user-select: none; -webkit-user-drag: none; pointer-events: none; }
.wp-map[data-mode="disk"] { background: #000; cursor: grab; touch-action: none; }
.wp-map[data-mode="disk"].is-dragging { cursor: grabbing; }
.wp-map[data-mode="disk"] .wp-canvas { visibility: hidden; }
.wp-map--loading .wp-disk img, .wp-map--empty .wp-disk { visibility: hidden; }
.wp-canvas .maplibregl-canvas { outline: none; }
.wp-map--loading .wp-canvas, .wp-map--empty .wp-canvas { visibility: hidden; }
.wp-frame {
  position: absolute; left: 50%; top: 50%; width: var(--fw); aspect-ratio: var(--aw) / var(--ah);
  translate: -50% -50%;
  outline: 2px solid #fff; outline-offset: 0;
  /* The veil: everything outside the frame is dimmed, so the picture reads as the picture. */
  box-shadow: 0 0 0 1px rgb(0 0 0 / .6), 0 0 0 100vmax rgb(4 12 22 / .58);
}
.wp-frame::before, .wp-frame::after {
  content: ""; position: absolute; width: 18px; height: 18px; border: 0 solid #fff;
}
.wp-frame::before { left: -6px; top: -6px; border-left-width: 4px; border-top-width: 4px; }
.wp-frame::after { right: -6px; bottom: -6px; border-right-width: 4px; border-bottom-width: 4px; }
.wp-frame-tag {
  position: absolute; left: -2px; bottom: calc(100% + 10px); white-space: nowrap;
  padding: 3px 10px; border-radius: var(--radius-control);
  background: var(--surface); color: var(--ink); font: 700 var(--fs-small)/1.5 var(--font-body);
  box-shadow: var(--wp-lift);
}
.wp-frame-tag .wp-num { font-weight: 600; color: var(--ink-2); }
/* The credit line, drawn to the scale it will have in the file: Manrope 600, white with a
   legibility shadow, its height 1.6% of the file's short side (14 px at least), set in from
   the bottom-right corner by twice its own height. */
.wp-credit {
  position: absolute; right: calc(var(--fw) * var(--cr) * 2); bottom: calc(var(--fw) * var(--cr) * 2);
  font: 600 max(4px, calc(var(--fw) * var(--cr)))/1.2 var(--font-body); color: rgb(255 255 255 / .92);
  text-shadow: 0 1px 2px rgb(0 0 0 / .7); white-space: nowrap;
}
.wp-outside {
  position: absolute; max-width: 9em; padding: 5px 8px; border-radius: var(--radius-control);
  background: var(--surface); color: var(--ink); font: 700 var(--fs-small)/1.4 var(--font-body);
  box-shadow: var(--wp-lift);
}
.wp-outside[data-side="east"] { right: var(--sp-3); top: 50%; translate: 0 -50%; }
.wp-outside[data-side="west"] { left: var(--sp-3); top: 50%; translate: 0 -50%; }
.wp-outside[data-side="north"] { top: var(--sp-3); left: 50%; translate: -50% 0; }
.wp-outside[data-side="south"] { bottom: var(--sp-3); left: 50%; translate: -50% 0; }

.wp-mapctl { position: absolute; z-index: 2; top: var(--sp-3); right: var(--sp-3); display: grid; gap: 6px; }
.wp-mapbtn {
  width: 44px; height: 44px; display: grid; place-items: center; padding: 0;
  background: var(--surface); color: var(--ink); border: 1px solid var(--line);
  border-radius: var(--radius-control); box-shadow: var(--wp-lift); cursor: pointer;
}
.wp-mapbtn svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.wp-mapbtn:disabled, .wp-mapbtn[aria-disabled="true"] { color: var(--muted); box-shadow: none; opacity: .72; cursor: not-allowed; }
.wp-mapbtn:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }

.wp-lock {
  position: absolute; left: 50%; bottom: var(--sp-3); translate: -50% 0; white-space: nowrap;
  padding: 6px 12px; border-radius: var(--radius-control); background: var(--surface); color: var(--ink);
  font: 700 var(--fs-small)/1.4 var(--font-body); box-shadow: var(--wp-lift);
}

/* Keyboard help, shown while the map has focus. */
.wp-keys {
  position: absolute; left: var(--sp-3); bottom: var(--sp-3); max-width: min(360px, calc(100% - 2 * var(--sp-3)));
  padding: var(--sp-3) var(--sp-4); border-radius: var(--radius-surface);
  background: var(--surface); color: var(--ink); box-shadow: 0 4px 14px rgb(0 0 0 / .35);
}
.wp-keys h3 { margin: 0 0 var(--sp-2); font-size: var(--fs-remarks); }
.wp-keys dl { margin: 0; display: grid; grid-template-columns: auto 1fr; gap: 6px var(--sp-3); font-size: var(--fs-small); }
.wp-keys dt { white-space: nowrap; }
.wp-keys dd { margin: 0; color: var(--ink-2); }
kbd {
  display: inline-block; min-width: 1.6em; padding: 0 5px; text-align: center;
  font: 600 var(--fs-micro)/1.6 var(--font-mono); color: var(--ink);
  background: var(--paper); border: 1px solid var(--edge); border-bottom-width: 2px; border-radius: var(--radius-preview);
}

/* The stage when there are no pixels to show. Pale and hatched, with words: never dark,
   never empty, so it cannot pass for a clear sky or a night ocean. */
.wp-map--empty { background: repeating-linear-gradient(135deg, var(--intro) 0 10px, color-mix(in srgb, var(--intro) 70%, var(--surface)) 10px 20px); }
.wp-map--loading { background: var(--intro); }
.wp-map--loading .wp-frame, .wp-map--empty .wp-frame { outline-style: dashed; outline-color: var(--edge); box-shadow: none; }
.wp-map--loading .wp-frame::before, .wp-map--loading .wp-frame::after, .wp-map--empty .wp-frame::before, .wp-map--empty .wp-frame::after { border-color: var(--edge); }
.wp-map--loading .wp-frame-tag, .wp-map--empty .wp-frame-tag { box-shadow: none; border: 1px solid var(--line); }
.wp-map--loading::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(100deg, transparent 30%, color-mix(in srgb, var(--surface) 70%, transparent) 50%, transparent 70%);
  background-size: 250% 100%; background-position: 50% 0;
}
/* Loading moves, so a slow frame never looks like a stuck one: a sheen across the stage and a
   turning mark beside the title. Still for a reader who asks for less motion; the title says it. */
.wp-spinner {
  flex: none; inline-size: 1em; block-size: 1em; border-radius: 50%;
  border: 2px solid var(--line); border-top-color: var(--enamel);
}
@media (prefers-reduced-motion: no-preference) {
  .wp-map--loading::after { animation: wp-sheen 1.8s ease-in-out infinite; }
  .wp-spinner { animation: wp-spin 0.9s linear infinite; }
}
@keyframes wp-sheen { from { background-position: 100% 0; } to { background-position: 0 0; } }
@keyframes wp-spin { to { transform: rotate(1turn); } }
.wp-stagebox {
  position: absolute; left: 50%; top: 50%; translate: -50% -50%; z-index: 1;
  width: min(460px, calc(100% - 2 * var(--sp-5))); padding: var(--sp-5) var(--sp-6);
  border-radius: var(--radius-surface); background: var(--surface); color: var(--ink); border: 1px solid var(--line);
  box-shadow: 0 6px 20px rgb(16 42 67 / .14);
}
.wp-stagebox h2 { margin: 0 0 var(--sp-2); font-size: var(--fs-subhead); display: flex; gap: var(--sp-2); align-items: center; }
.wp-stagebox p { margin: 0 0 var(--sp-2); color: var(--ink-2); }
.wp-stagebox .wp-actions { margin-top: var(--sp-3); }

/* ---- The caption ------------------------------------------------------------------------ */

.wp-view figcaption { padding: var(--sp-4) 0 0; color: var(--ink-2); }
.wp-view figcaption p { margin: var(--sp-1) 0; max-width: var(--wrap-prose); }
.wp-capline { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-1) var(--sp-4); color: var(--ink); }
.wp-capline strong { font-size: var(--fs-lead); }
.wp-capline .wp-time { font-weight: 700; }
.wp-capline .wp-age { color: var(--ink-2); }
.wp-credit-text { color: var(--ink); font-weight: 600; }
.wp-ack, .wp-official { font-size: var(--fs-small); }

/* ---- The panel: the recipe, top to bottom ------------------------------------------------ */

.wp-panel {
  background: var(--intro);
  border: 1px solid var(--line); border-radius: var(--radius-surface); padding: var(--sp-2) var(--sp-5) var(--sp-5);
}
.wp-sec { padding: var(--sp-5) 0 var(--sp-4); border-bottom: 1px solid var(--divider); }
.wp-sec:last-child { border-bottom: 0; padding-bottom: 0; }
.wp-sec > h2, .wp-sec > fieldset > legend {
  margin: 0 0 var(--sp-3); padding: 0; font-size: var(--fs-lead); font-weight: 700; color: var(--ink); line-height: var(--lh-lead);
}
.wp-sec fieldset { border: 0; margin: 0; padding: 0; min-width: 0; }
.wp-pair { margin-top: var(--sp-3); }
.wp-hint { margin: var(--sp-2) 0 0; font-size: var(--fs-small); color: var(--ink-2); line-height: 1.5; }
.wp-num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: .94em; }

/* Group chips: Desktop, Ultrawide, Phone, Tablet, Custom. */
.wp-groups { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 var(--sp-3); padding: 0; border: 0; }
.wp-chip { position: relative; }
.wp-chip input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.wp-chip span {
  display: inline-flex; align-items: center; min-height: 40px; padding: 0 14px;
  border: 1px solid var(--edge); border-radius: var(--radius-node); background: var(--surface);
  color: var(--ink); font-weight: 600; font-size: var(--fs-bulletin);
}
.wp-chip input:checked + span { background: var(--enamel); border-color: var(--enamel); color: var(--on-enamel); }
.wp-chip input:focus-visible + span { outline: var(--focus-ring); outline-offset: 2px; }

/* A list of sizes, or of satellites: one radio row each. */
.wp-opts { display: grid; gap: 6px; }
.wp-opt { position: relative; }
.wp-opt input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.wp-opt > span {
  display: grid; grid-template-columns: 18px 1fr auto; align-items: center; gap: 2px var(--sp-3);
  min-height: 44px; padding: 8px var(--sp-3); border: 1px solid var(--line); border-radius: var(--radius-control);
  background: var(--surface); color: var(--ink);
}
.wp-opt > span::before {
  content: ""; grid-row: 1 / span 2; width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid var(--edge); background: var(--surface); box-sizing: border-box;
}
.wp-opt input:checked + span { background: var(--briefing); border-color: var(--teal); }
.wp-opt input:checked + span::before { border: 5px solid var(--enamel); }
.wp-opt input:focus-visible + span { outline: var(--focus-ring); outline-offset: 2px; }
.wp-opt-name { font-weight: 700; }
.wp-opt-dim { justify-self: end; color: var(--ink); }
.wp-opt-sub { grid-column: 2 / -1; font-size: var(--fs-small); color: var(--ink-2); }

.wp-custom { display: grid; grid-template-columns: 1fr auto 1fr; align-items: end; gap: var(--sp-2); }
.wp-field { display: grid; gap: 4px; font-size: var(--fs-small); font-weight: 700; color: var(--ink); }
.wp-field .input { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.wp-field select.input { font-family: var(--font-body); }
.wp-by { padding-bottom: 10px; color: var(--ink-2); font-weight: 700; }
/* One above the other: a frame time from our own archive reads "02:00 (newest) · MaverickWX frame". */
.wp-pair { display: grid; grid-template-columns: 1fr; gap: var(--sp-2); }
.wp-trio { display: grid; grid-template-columns: 1fr 1fr 0.8fr; gap: var(--sp-2); }
.wp-source { margin: var(--sp-3) 0 0; padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-control); background: var(--surface); border: 1px solid var(--line); font-size: var(--fs-small); color: var(--ink-2); }
.wp-source strong { color: var(--ink); }

.wp-position summary { cursor: pointer; display: grid; gap: 2px; min-height: 44px; padding: 4px 0; font-weight: 700; color: var(--link); }
.wp-position summary .wp-now { color: var(--ink-2); font-weight: 500; font-size: var(--fs-small); }
.wp-position[open] summary { margin-bottom: var(--sp-2); }
.wp-position .btn { margin-top: var(--sp-3); }

/* The quality meter: a word first, the number beside it, and a scale with three named
   zones. The word carries the reading; the marker only repeats it. */
.wp-reading { margin: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px var(--sp-3); }
.wp-reading-word { font-size: var(--fs-subhead); font-weight: 800; color: var(--ink); }
.wp-reading-num { color: var(--ink-2); }
.wp-scale { position: relative; margin: var(--sp-3) 0 var(--sp-1); }
.wp-scale-track { display: grid; grid-template-columns: 1fr 1fr 1.4fr; gap: 3px; }
.wp-scale-track span { height: 8px; border-radius: var(--radius-node); background: var(--wash-strong); }
.wp-scale-track span.is-on { background: var(--ink); }
.wp-scale-marker {
  position: absolute; top: -5px; left: var(--at); translate: -50% 0; width: 4px; height: 18px;
  border-radius: var(--radius-node); background: var(--ink); box-shadow: 0 0 0 2px var(--surface);
}
.wp-scale-labels { display: grid; grid-template-columns: 1fr 1fr 1.4fr; gap: 3px; margin-top: 6px; font-size: var(--fs-micro); color: var(--ink-2); }
.wp-scale-labels span.is-on { color: var(--ink); font-weight: 800; }
.wp-scale-labels span:nth-child(2) { text-align: center; }
.wp-scale-labels span:nth-child(3) { text-align: right; }
.wp-detail .btn { margin-top: var(--sp-3); }
.wp-save .btn--secondary { width: 100%; }
.wp-field .input[aria-invalid="true"] { border-color: var(--ink); border-width: 2px; }

/* Format: two options side by side. */
.wp-formats { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.wp-formats .wp-opt > span { grid-template-columns: 18px 1fr; }

/* The credit switch. A checkbox with role="switch": the state is a word as well as a
   position, so it is not colour alone. */
.wp-switch { display: flex; align-items: center; gap: var(--sp-3); min-height: 44px; margin-top: var(--sp-4); cursor: pointer; font-weight: 700; color: var(--ink); }
.wp-switch input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.wp-switch-track {
  position: relative; flex: none; width: 44px; height: 26px; border-radius: var(--radius-node);
  background: var(--surface); border: 2px solid var(--edge); box-sizing: border-box;
}
.wp-switch-track::after {
  content: ""; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: var(--edge);
}
.wp-switch input:checked + .wp-switch-track { background: var(--enamel); border-color: var(--enamel); }
.wp-switch input:checked + .wp-switch-track::after { left: 21px; background: var(--on-enamel); }
.wp-switch input:focus-visible + .wp-switch-track { outline: var(--focus-ring); outline-offset: 2px; }
.wp-switch-state { margin-left: auto; font-weight: 600; color: var(--ink-2); font-size: var(--fs-small); }
.wp-creditprev {
  margin: var(--sp-2) 0 0; padding: 22px 12px 8px; border-radius: var(--radius-preview); text-align: right;
  /* A crop of the frame's own imagery once it has loaded (the page sets the tile); slate
     until then, never a picture from anywhere else. */
  background: #1d2a38 var(--wp-prev, none) center / cover no-repeat; overflow: hidden;
}
.wp-creditprev span { font: 600 var(--fs-micro)/1.3 var(--font-body); color: #fff; text-shadow: 0 1px 2px rgb(0 0 0 / .8); }

/* Save: the one filled action on the page. */
.wp-save { display: grid; gap: var(--sp-2); }
/* Switch text and fill together when imagery makes Save available. Animating only
   the fill briefly puts the enabled white label on the disabled pale background.
   This exception also overrides the shell's reduced-motion colour transitions. */
.wp-save .btn--primary { width: 100%; min-height: 50px; font-size: var(--fs-remarks); font-weight: 800; transition-property: border-color !important; }
.wp-save .btn--primary svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.wp-save .btn[disabled] { background: var(--wash-strong); border-color: var(--line); color: var(--ink-2); cursor: not-allowed; }
.wp-file { margin: 0; font-size: var(--fs-small); color: var(--ink-2); overflow-wrap: anywhere; }
.wp-file .wp-num { color: var(--ink); }
.wp-why { margin: 0; font-size: var(--fs-small); color: var(--ink); font-weight: 600; }

/* Outcomes and notices: an icon, a word and the reason. Never colour alone. */
.wp-outcome {
  display: grid; grid-template-columns: 24px 1fr; gap: var(--sp-1) var(--sp-3); align-items: start;
  padding: var(--sp-3) var(--sp-4); border-radius: var(--radius-control); background: var(--surface); border: 1px solid var(--line); color: var(--ink);
}
.wp-outcome svg, .wp-stagebox h2 svg, .wp-notice svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; flex: none; }
.wp-outcome p { margin: 0; font-size: var(--fs-bulletin); color: var(--ink-2); }
.wp-outcome p strong { color: var(--ink); }
.wp-outcome .wp-outcome-body { display: grid; gap: var(--sp-1); }
.wp-outcome--done { background: var(--briefing); border-color: var(--teal); }
.wp-outcome--failed { border-color: var(--ink); border-width: 2px; }
.wp-outcome--blocked { background: var(--archive); border-color: var(--edge); }
.wp-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

.wp-notice {
  display: grid; grid-template-columns: 22px 1fr; gap: var(--sp-3); align-items: start; margin: var(--sp-3) 0 0;
  padding: var(--sp-3); border-radius: var(--radius-control); background: var(--archive); color: var(--ink); font-size: var(--fs-small);
}
.wp-notice p { margin: 0; }

.wp-progress { display: grid; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4); border-radius: var(--radius-control); background: var(--surface); border: 1px solid var(--line); }
.wp-progress-head { margin: 0; display: flex; justify-content: space-between; gap: var(--sp-3); color: var(--ink); }
.wp-progress progress { width: 100%; height: 10px; appearance: none; border: 0; border-radius: 5px; background: var(--wash-strong); overflow: hidden; accent-color: var(--enamel); }
.wp-progress progress::-webkit-progress-bar { background: var(--wash-strong); border-radius: 5px; }
.wp-progress progress::-webkit-progress-value { background: var(--enamel); border-radius: 5px; }
.wp-progress p { margin: 0; font-size: var(--fs-small); color: var(--ink-2); }
.wp-steps { margin: 0; padding: 0; list-style: none; display: grid; gap: 4px; font-size: var(--fs-small); color: var(--ink-2); }
.wp-steps li { display: grid; grid-template-columns: 16px 1fr; gap: var(--sp-2); align-items: center; }
.wp-steps li svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.wp-steps li.is-done, .wp-steps li.is-now { color: var(--ink); }
.wp-steps li.is-now { font-weight: 700; }

.wp-disabled { opacity: .62; }

@media (max-width: 1023px) {
  .wp-studio { grid-template-columns: 1fr; gap: var(--sp-5); }
  .wp-view { position: static; }
  .wp-map { height: clamp(420px, 66svh, 600px); }
}
@media (max-width: 760px) {
  main.wp { width: calc(100% - 32px); padding-top: var(--sp-4); }
  .wp-panel { padding-inline: var(--sp-4); }
  /* Save stays in reach while the reader works through the panel. */
  .wp-sec--save { position: sticky; bottom: 0; z-index: 2; margin: 0 calc(-1 * var(--sp-4)) calc(-1 * var(--sp-5)); padding: var(--sp-3) var(--sp-4) var(--sp-4); background: var(--intro); border-top: 1px solid var(--line); border-radius: 0 0 var(--radius-surface) var(--radius-surface); }
  .wp-mapctl { top: var(--sp-2); right: var(--sp-2); }
  .wp-keys { left: var(--sp-2); bottom: var(--sp-2); }
}
@media (max-width: 360px) {
  .wp-formats { grid-template-columns: 1fr; }
  .wp-trio { grid-template-columns: 1fr 1fr; }
}
