/* Media pages (photos, videos). Only what site.css lacks: .gallery, .ph, .play, .dur,
   .badges and dialog come from site.css. Colours come from tokens.css, except the
   placeholder scene's own palette below (the prototype's PHOTOS/VIDEOS pairs), which is
   an illustration, not UI. */

/* ── Scene tokens ─────────────────────────────────────────────────────────── */
:root{
  --scene-sky-0:#CFE3F2;--scene-hill-0:#8FC7A4;
  --scene-sky-1:#FCE9A4;--scene-hill-1:#C9D96B;
  --scene-sky-2:#FBE1E9;--scene-hill-2:#F4A9C0;
  --scene-sky-3:#DFF2E6;--scene-hill-3:#7FB08F;
  --scene-sky-4:#FCE1C7;--scene-hill-4:#F2A65A;
  --scene-sky-5:#E0ECF9;--scene-hill-5:#9CC6F2;
  --scene-sky-6:#ECE5FB;--scene-hill-6:#C8B6F2;
  --scene-sky-7:#FCE9A4;--scene-hill-7:#F7C719;
  --scene-sky-8:#DFF2E6;--scene-hill-8:#9ED7B2;
  --scene-sun:#FFFFFF;
  --scene-stem:#2A6A4A;--scene-flower:#F7C719;
}
.scene{display:block;width:100%;height:auto}
.scene[data-tone="0"]{--sky:var(--scene-sky-0);--hill:var(--scene-hill-0)}
.scene[data-tone="1"]{--sky:var(--scene-sky-1);--hill:var(--scene-hill-1)}
.scene[data-tone="2"]{--sky:var(--scene-sky-2);--hill:var(--scene-hill-2)}
.scene[data-tone="3"]{--sky:var(--scene-sky-3);--hill:var(--scene-hill-3)}
.scene[data-tone="4"]{--sky:var(--scene-sky-4);--hill:var(--scene-hill-4)}
.scene[data-tone="5"]{--sky:var(--scene-sky-5);--hill:var(--scene-hill-5)}
.scene[data-tone="6"]{--sky:var(--scene-sky-6);--hill:var(--scene-hill-6)}
.scene[data-tone="7"]{--sky:var(--scene-sky-7);--hill:var(--scene-hill-7)}
.scene[data-tone="8"]{--sky:var(--scene-sky-8);--hill:var(--scene-hill-8)}
.scene .sky{fill:var(--sky)}
.scene .sun{fill:var(--scene-sun);opacity:.75}
.scene .hill{fill:var(--hill)}
.scene .hill.back{opacity:.6}
.scene .flowers path{stroke:var(--scene-stem);stroke-width:2}
.scene .flowers circle{fill:var(--scene-flower)}
/* Yellow hills: white, ringed heads (seed puffs) so they do not vanish as the prototype's do. */
.scene[data-ring] .flowers circle{fill:var(--scene-sun);stroke:var(--scene-stem);stroke-width:1.5}
.media-placeholder{display:block}

/* ── Albums and videos (ADR-0021) ─────────────────────────────────────────── */
/* Row-major grid for albums, an album's photos and videos (PAR-18): site.css's CSS columns
   fill top to bottom, so the eye read row by row while Tab went down each column. In a grid
   the visual, reading and Tab order are the same. An album tile and a photo tile are one
   size everywhere: a fixed 4:3 box with the whole picture inside (contain, never cropped)
   on the neutral --sunk; videos are uniform 16:9 tiles. */
.gallery.videos,.album-grid,.photo-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,max(260px,calc((100% - 32px) / 3))),1fr));gap:16px;align-items:start;list-style:none;margin:0;padding:0}
.album-grid,.photo-grid{row-gap:28px}
.gallery.videos{columns:auto}
.gallery.videos figure,.album-tile,.photo-tile{margin:0;min-width:0}
/* Phones: albums and photos two to a row, as phone galleries are (ADR-0017 decision 13): a
   320px screen showed one picture per screen. Videos stay one wide 16:9 row each. */
@media (max-width:37.5em){.album-grid,.photo-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:20px 12px}}
.gallery figure{position:relative}
/* <picture> (WebP source + original img, R4-XB-08) is inline by default: make it a plain
   block so the img rules below lay out exactly as without it. */
.ph picture{display:block}
.album-tile .ph,.photo-tile .ph{aspect-ratio:4/3;background:var(--sunk)}
.album-tile .ph :is(picture,img,.media-placeholder,.scene),.photo-tile .ph :is(picture,img,.media-placeholder,.scene){display:block;width:100%;height:100%}
.album-tile .ph img,.photo-tile .ph img{object-fit:contain}
.gallery.videos .ph img{display:block;width:100%;height:auto;aspect-ratio:16/9;object-fit:cover}
.album-name{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;margin-top:10px;font-size:1.0625rem;font-weight:600;line-height:1.45;overflow-wrap:anywhere}
.album-meta{display:block;margin-top:2px;font-size:.9375rem;color:var(--muted);font-variant-numeric:tabular-nums}
.album-info{margin:0 0 20px;color:var(--muted);font-variant-numeric:tabular-nums}
ul.badges{list-style:none;padding:0;margin:6px 0 0}
.badges span{font-size:.8rem;padding:3px 9px}
.dur{font-size:.8rem;font-variant-numeric:tabular-nums}
.gallery figcaption small{font-variant-numeric:tabular-nums}
.nw{white-space:nowrap}

/* The whole card is one link (an album tile, a photo, a video); badges stay text. */
.media-link{display:block;text-decoration:none;color:inherit;border-radius:18px;cursor:pointer}
.photo-link{cursor:zoom-in}
.album-link:focus-visible,.photo-link:focus-visible{outline:3px solid var(--focus);outline-offset:4px}
.gallery .media-link::after{content:"";position:absolute;inset:0;border-radius:18px;z-index:1}
.gallery .media-link:focus-visible{outline:none;box-shadow:none}
.gallery .media-link:focus-visible::after{outline:3px solid var(--focus);outline-offset:4px}
.media-link .ph{transition:transform 120ms cubic-bezier(.2,.8,.2,1)}
.media-link:active .ph{transform:scale(.98)}
.media-link:focus-visible .play i{transform:scale(1.1)}
@media (hover:hover) and (pointer:fine){
  .media-link:hover .play i{transform:scale(1.1)}
  :is(.album-link,.photo-link):hover .ph{box-shadow:0 10px 24px -14px var(--shadow,rgba(0,0,0,.35))}
}

/* Placeholder note and the "opening" pill share the .dur look (bottom-left / centre). */
.ph-note,.ph-busy{position:absolute;background:rgba(0,0,0,.72);color:#fff;font-family:var(--sans);font-size:.8rem;font-weight:600;padding:2px 9px;border-radius:8px;pointer-events:none}
.ph-note{left:12px;bottom:12px}
.ph-busy{left:50%;top:12px;transform:translateX(-50%);visibility:hidden;opacity:0}
.media-link.htmx-request .ph-busy,.media-link[aria-busy="true"] .ph-busy{visibility:visible;opacity:1;animation:ph-busy-in 120ms 150ms both}
@keyframes ph-busy-in{from{visibility:hidden;opacity:0}to{visibility:visible;opacity:1}}

/* ── Detail page and dialog (one partial, prototype .dx layout on both) ─────── */
/* The video page's card is a 900px column in the middle of the page, like the other pages' text
   columns (it hung at the left with a blank strip at its right). The photo page's card is as
   wide as the album page's grid, so the two pages share their edges; the picture stays the
   900px box that `sizes` (media/constants.py PHOTO_SIZES["detail"]) says it is, centred on the
   neutral background that fills the card's width. */
.media-detail{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);overflow:hidden;max-width:900px;margin-inline:auto}
.media-detail[data-album-viewer]{max-width:none}
.media-detail[data-album-viewer] .ph{background:var(--sunk)}
.media-detail[data-album-viewer] .ph :is(img,.scene){max-width:900px;margin-inline:auto}
.media-detail .ph{border-radius:0;touch-action:pan-y pinch-zoom}
.media-detail .ph img{display:block;width:100%;height:auto;max-height:min(70vh,720px);object-fit:contain;background:var(--sunk)}
.media-detail .ph .scene{max-height:min(60vh,560px)}
.media-detail .ph.video .scene,.media-detail .ph.video img{aspect-ratio:16/9;height:auto;max-height:none;object-fit:cover}
.media-detail .dx{padding:20px 24px;display:flex;justify-content:space-between;gap:16px;align-items:start}
.media-detail .dx>div{min-width:0;flex:1}
.media-detail h2{font-size:1.4rem}
.media-alt,.media-desc,.media-ready-soon{margin-top:10px}
.media-player{position:relative;aspect-ratio:16/9;background:var(--deep)}
.media-player iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
.media-back{margin-top:24px}
.media-detail:not([data-album-viewer])~.media-back{max-width:900px;margin-inline:auto}

/* Text alternative for the video (WCAG 1.2.1/1.2.3/1.2.8): the full transcript. */
.media-transcript{margin-top:18px;padding-top:16px;border-top:1px solid var(--line)}
.media-transcript h2,.media-transcript h3{font-size:1.05rem}
/* A full 44px target (--target-min), label centred; display:flex drops the native
   marker, so a drawn chevron shows the open/closed state (PAR-19). */
.media-transcript summary{list-style:none;cursor:pointer;font-weight:600;margin-top:8px;min-height:var(--target-min);display:flex;align-items:center;gap:10px}
.media-transcript summary::-webkit-details-marker{display:none}
.media-transcript summary::before{content:"";flex:none;width:.45em;height:.45em;border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:translateY(-2px) rotate(-45deg);margin-inline:2px 4px}
.media-transcript details[open]>summary::before{transform:translateY(-2px) rotate(45deg)}
.media-transcript .prose{margin-top:10px;max-width:none;font-size:1rem;line-height:1.9}

/* Dialog (WAI-ARIA APG modal): 닫기 sits in the .dx row, as in the prototype. */
.media-dialog{overscroll-behavior:contain;max-height:calc(100dvh - 32px)}
.media-dialog .media-detail{border:0;border-radius:0;max-width:none}
.media-dialog [tabindex="-1"]:focus{outline:none;box-shadow:none} /* the title takes focus on opening: no ring (site.css :focus-visible's shadow neither) */
.media-close{flex:none}
/* Narrow screens (R5-MT-10, PAR-19): beside 닫기 the text column would be squeezed, and
   under a tall photo or player 닫기 would be off screen. So 닫기 becomes the dialog's
   first row, sticky at the top right while the content scrolls, and the text gets the
   full width. .dx dissolves (display:contents) so its two children join the article's
   column; 닫기 is ordered first. Wider screens keep the prototype's row. */
@media (max-width:560px){
  /* overflow:visible: .media-detail's overflow:hidden would trap the sticky row (the
     dialog is the scroller); the dialog itself rounds and clips the corners. */
  .media-dialog .media-detail{display:flex;flex-direction:column;overflow:visible}
  .media-dialog .media-detail .dx{display:contents}
  .media-dialog .media-detail .dx>div{padding:16px 20px 20px}
  .media-dialog .media-close{order:-1;position:sticky;top:0;z-index:2;display:flex;justify-content:flex-end;padding:8px 12px;background:var(--surface);border-bottom:1px solid var(--line)}
}
/* Phones: the accessibility badges, the photo's status note and a video's length at the
   site's 15px floor for information (site.css, ADR-0017 decision 13). */
@media (max-width:640px){.badges span,.ph-note,.dur{font-size:.9375rem}}
html:has(dialog.media-dialog:modal){overflow:hidden;scrollbar-gutter:stable}
.media-dialog[open]{animation:media-dlg-in 160ms cubic-bezier(.2,.8,.2,1)}
.media-dialog[open]::backdrop{animation:media-fade-in 160ms ease-out}
.media-dialog[data-instant][open],.media-dialog[data-instant][open]::backdrop{animation:none}
@keyframes media-dlg-in{from{opacity:0;transform:translateY(8px) scale(.98)}}
@keyframes media-fade-in{from{opacity:0}}

/* ── Photo viewer: header, stage, strip (ADR-0021 decision 4) ─────────────────────── */
/* One markup, two places (media/photo_detail.html): the photo's own page, where it is a card
   in the flow, and the dialog, where it is the whole window. Top to bottom: the header (album
   title and date, the place "3 / 12", 닫기 in the dialog), the stage (the picture whole in
   the middle, a round 이전 사진 and 다음 사진 at its sides), the photo's own description, and
   the strip (every photo of the album as a small picture in a row that scrolls sideways). */
.photo-viewer{--pv-arrow:48px;--pv-edge:12px;--pv-pad:24px;--pv-thumb-w:72px;--pv-thumb-h:54px}
.pv-head{display:grid;grid-template-columns:minmax(0,1fr) auto auto;grid-template-areas:"title count close" "date count close";align-items:center;column-gap:12px;padding:12px 16px 12px var(--pv-pad)}
.pv-head .pv-title{grid-area:title;margin:0;font-size:1.25rem;line-height:1.35;overflow-wrap:anywhere;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
.pv-date{grid-area:date;margin:0;font-size:.9375rem;color:var(--muted)}
.pv-count{grid-area:count;margin:0;min-width:7ch;text-align:right;font-size:1rem;font-weight:600;font-variant-numeric:tabular-nums;color:var(--ink-2);white-space:nowrap}
.pv-head .media-close{grid-area:close}
.pv-stage{position:relative;background:var(--sunk)}
/* A round button over the stage's side, on the semi-opaque white of the header glass (its
   text keeps 4.5:1 over any picture). An arrow with nowhere to go is not drawn at all: the
   picture does not wait for it. */
.pv-arrow{position:absolute;top:calc(50% - var(--pv-arrow) / 2);z-index:1;display:grid;place-items:center;width:var(--pv-arrow);height:var(--pv-arrow);border:1.5px solid var(--line-strong);border-radius:50%;background:var(--glass);color:var(--ink);text-decoration:none;box-shadow:0 6px 14px -8px var(--shadow);transition:background-color var(--dur-ui) var(--ease-out),border-color var(--dur-ui) var(--ease-out)}
.pv-prev{left:var(--pv-edge)}
.pv-next{right:var(--pv-edge)}
.pv-arrow:focus-visible{outline:3px solid var(--focus);outline-offset:3px;box-shadow:0 0 0 3px var(--surface)}
.pv-arrow:active{background:var(--surface)}
@media (hover:hover) and (pointer:fine){.pv-arrow:hover{background:var(--surface);border-color:var(--ink)}}
.pv-alt{margin:0;padding:12px var(--pv-pad);font-size:.9375rem;line-height:1.55;overflow-wrap:anywhere}
/* The strip. Each place is a fixed 4:3 box with the whole picture inside (never cropped) on
   the neutral --sunk; the shown photo has a 3px outline (and aria-current, media.js keeps
   both). The row scrolls sideways and does not hand its overscroll to the page or the
   dialog; the snap only helps a finger come to rest on a thumbnail (proximity). The row's
   padding leaves room for the outline and the focus ring, which the row would clip. */
.pv-strip{border-top:1px solid var(--line);background:var(--surface)}
.pv-strip ol{position:relative;display:flex;gap:8px;list-style:none;margin:0;padding:8px 16px;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;scroll-snap-type:x proximity;scroll-padding-inline:16px;scrollbar-width:thin;user-select:none;-webkit-user-select:none}
.pv-strip li{flex:none}
.pv-thumb{position:relative;display:block;width:var(--pv-thumb-w);height:var(--pv-thumb-h);border-radius:8px;overflow:hidden;background:var(--sunk);scroll-snap-align:center}
.pv-thumb :is(picture,img,.media-placeholder,.scene){display:block;width:100%;height:100%}
.pv-thumb img{object-fit:contain}
.pv-thumb[aria-current="true"]{outline:3px solid var(--leaf);outline-offset:0}
.pv-thumb:focus-visible{outline:3px solid var(--focus);outline-offset:3px}
@media (hover:hover) and (pointer:fine){.pv-strip ol{cursor:grab}.pv-strip ol.is-dragging{cursor:grabbing}}
.pv-strip ol.is-dragging{scroll-snap-type:none}
/* The dialog: the whole window, a column of header, stage (takes what is left), description
   and strip. A fixed height, so the stage is the same box for every picture and a photo of
   another shape moves nothing. Wide: a modal at most 1100px wide and 92% of the height, the
   buttons beside the picture. Phones and short screens: the whole screen (safe areas
   respected), the buttons over the picture's edges. */
.media-dialog[data-viewer]{max-width:none;max-height:none;overflow:hidden}
.media-dialog[data-viewer][open]{display:flex;flex-direction:column;width:min(1100px,96vw);height:min(92vh,56rem);height:min(92dvh,56rem)}
.media-dialog[data-viewer] #media-dialog-body,.media-dialog[data-viewer] .photo-viewer,.media-dialog[data-viewer] .pv-view{display:flex;flex-direction:column;flex:1 1 auto;min-height:0}
.media-dialog[data-viewer] .photo-viewer{--pv-side:calc(var(--pv-arrow) + 2 * var(--pv-edge));margin:0;max-width:none;border:0;border-radius:0;overflow:hidden}
.media-dialog[data-viewer] .pv-head,.media-dialog[data-viewer] .pv-alt,.media-dialog[data-viewer] .pv-strip{flex:none}
.media-dialog[data-viewer] .pv-stage{flex:1 1 0;min-height:0}
.media-dialog[data-viewer] .pv-stage .ph{position:absolute;inset:0 var(--pv-side)}
.media-dialog[data-viewer] .pv-stage .ph :is(picture,img,.media-placeholder,.scene){display:block;width:100%;height:100%;max-width:none;max-height:none;margin:0}
.media-dialog[data-viewer] .pv-alt{margin:10px var(--pv-pad);padding:0;min-height:calc(2 * 1.55em);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
.media-dialog[data-viewer] .media-close{order:0;position:static;display:block;padding:0;border:0;background:none}
@media (max-width:44.9375em),(max-height:35em){
  .media-dialog[data-viewer][open]{width:100%;height:100vh;height:100dvh;border-radius:0}
  .media-dialog[data-viewer] .photo-viewer{--pv-arrow:44px;--pv-edge:8px;--pv-pad:16px;--pv-side:0px;--pv-thumb-w:64px;--pv-thumb-h:48px;padding:env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)}
}
/* A phone's header: the title and 닫기 on the first row, the date and the place on the
   second, so a long title keeps the width. */
@media (max-width:44.9375em){
  .photo-viewer{--pv-arrow:44px;--pv-edge:8px;--pv-pad:16px;--pv-thumb-w:64px;--pv-thumb-h:48px}
  .pv-head{grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"title close" "date count";column-gap:8px;padding:8px 8px 8px var(--pv-pad)}
}

/* Video filter (전체 · 수어 · 자막 · 화면해설) above the grid. */
.media-filter{margin-bottom:24px}
.media-filter .n{font-variant-numeric:tabular-nums;font-weight:500;opacity:.8}

/* ── Staff video upload page ──────────────────────────────────────────────── */
.media-notice{padding:14px 18px;border-radius:14px;background:var(--yellow-soft);color:var(--yellow-ink);font-weight:600}
.media-narrow{max-width:760px}
.media-sync,.media-reissue{margin-top:18px}
.media-reissue[hidden]{display:none}
/* Step 2 when no new upload URL could be had: the same card look as form.form. */
.media-panel{display:grid;gap:18px;background:var(--surface);border:1px solid var(--line);border-radius:var(--r);padding:clamp(22px,4vw,36px)}
.media-progress{width:100%;height:12px;accent-color:var(--leaf)}
.media-actions{display:flex;flex-wrap:wrap;gap:10px}
.media-actions [aria-disabled="true"]{opacity:.7;cursor:progress}
.media-steps{list-style:none;margin:0 0 20px;padding:0;display:flex;flex-wrap:wrap;gap:8px}
.media-steps li{display:inline-flex;align-items:center;gap:8px;padding:6px 14px 6px 6px;border-radius:999px;border:1.5px solid var(--line);color:var(--muted);font-weight:600;font-size:.92rem}
.media-steps b{display:inline-grid;place-items:center;width:1.7em;height:1.7em;border-radius:50%;background:var(--sunk);color:var(--ink);font-family:var(--mono);font-size:.82rem}
.media-steps [aria-current="step"]{border-color:var(--ink);color:var(--ink)}
.media-steps [aria-current="step"] b{background:var(--ink);color:var(--bg)}
.media-error[hidden]{display:none}

/* D16: the request e-mail inside the "대본 준비 중" sentence is a touch target for P-15
   (tablet, large text). Vertical padding on an inline box does not move the line, so the
   sentence keeps its layout while the link's box reaches --target-min. The padding assumes
   only a 1em content area (ascent + descent; text fonts measure about 1em or more), so the
   box does not fall short whichever system sans-serif draws the sentence (--sans: Malgun
   Gothic measures ~1.3em); a taller content area only makes the box a little taller.
   Invisible: the link has no background. */
.media-transcript .help a{padding-block:calc((var(--target-min) - 1em) / 2)}
