/* Motion Prompt #077 · MIT License (c) 2026 Shohei Ohtaki · https://showheyohtaki.github.io/motion-prompt/#077 */
/* Motion Prompt #073 · MIT License (c) 2026 Shohei Ohtaki · https://showheyohtaki.github.io/motion-prompt/#073 */
/* Selected work: the "Frames | Index" toggle in the section head, the credits-style index table and its
   preview pane (assets/js/site/work-index.js). index.html only; requires tokens.css, base.css, site.css.
   html[data-work-view] (frames | index) says which view shows: the inline head script sets it before the
   first paint, so the view chosen last is the one that paints. Without JavaScript the table is the
   filmography (the frames are palettes until scripts paint their stills).
   Columns by width: under 720 Year · Title · Format · Aspect; from 720 No and Director join; from 1100
   the sticky preview pane sits beside the table; from 1800 Camera / Lens, Production / Platform and
   Premiere, so every column. Nine columns need 860–910 px (their min-content, measured), and beside
   the pane there are 647 px at 1100, 841 at 1440 and 1046 at 1800: any sooner and the cells wrap word
   by word, or the table is cut off (Camera / Lens alone would wrap the titles, and six rows would no
   longer fit the first screen at 1440 × 900). Without the pane (no JavaScript) the table has the full
   width and every column from 1100; print shows them all.
   Phones and tablets (no desktop layer): each card's gate wipes open as it scrolls in, the film strip's
   gate wipe (motion/work.js, numbers only: inset(0 100% 0 0) → inset(0), left to right) driven by the
   scroll instead of a clock, from 10 % into its entry to 35 % of its cover; CSS only, where
   animation-timeline: view() exists, and never with motion off. */

/* --- The view toggle, at the end of the section head's slate row ----------------------------------- */
.work-view {
  display: inline-flex; gap: 2px; padding: 2px;
  margin-block: -7px;   /* a 34 px pill in the ~20 px slate row: the head (and the pinned strip) is no taller */
  border: 1px solid var(--line-strong); border-radius: var(--radius-pill);
}
.work-view__btn {
  position: relative; min-height: 28px; padding: 0 var(--s3);
  border: 0; border-radius: var(--radius-pill); background: transparent; color: var(--paper-3);
  font: inherit; letter-spacing: inherit; text-transform: inherit; line-height: 1;
  transition: color var(--dur-1) var(--ease-ui), background-color var(--dur-1) var(--ease-ui);
}
.work-view__btn::after { content: ""; position: absolute; inset: -8px 0; }   /* 44 px hit area */
.work-view__btn:hover { color: var(--paper); }
/* Pressed: filled, in tungsten, and shown by shape too (the Motion toggle's dot, site.css). Drawn from
   html[data-work-view], so it is right from the first paint; aria-pressed follows when main.js mounts the
   index. Forced colours use the same selectors, so they win by coming later. */
html:not([data-work-view="index"]) .work-view__btn[data-view="frames"],
html[data-work-view="index"] .work-view__btn[data-view="index"] { background: var(--ink-3); color: var(--tungsten); }
html:not([data-work-view="index"]) .work-view__btn[data-view="frames"]::before,
html[data-work-view="index"] .work-view__btn[data-view="index"]::before {
  content: ""; display: inline-block; width: 6px; height: 6px; margin-right: var(--s2); border-radius: 50%;
  background: currentColor; vertical-align: 0.05em;
}
@media (forced-colors: active) {
  html:not([data-work-view="index"]) .work-view__btn[data-view="frames"],
  html[data-work-view="index"] .work-view__btn[data-view="index"] { forced-color-adjust: none; background: Highlight; color: HighlightText; }
}
@media (max-width: 639px) {
  /* Phones: the slate breaks after "Selected work"; "6 films · 2023–2026" and the toggle share line two. */
  #work .section-head__slate { row-gap: var(--s1); }
  #work .section-head__slate::after { content: ""; flex-basis: 100%; order: 1; }
  #work :is(.section-head__aside, .section-head__tools) { order: 2; }
  #work .section-head__aside { flex-basis: auto; }
}

/* --- One view at a time ------------------------------------------------------------------------- */
html[data-work-view="index"] #work .work-grid, html:not(.js) #work .work-grid { display: none; }
html.js:not([data-work-view="index"]) .work-index, html:not(.js) .work-view, html:not(.js) .work-index__preview { display: none; }
/* The lede ("hover or focus one for the camera move that defines it") holds for the cards, which play the
   move, and for the index's preview pane, which names it: it goes where neither is, the index under 1100 px
   (no pane) and without JavaScript. */
html:not(.js) #work .section-head__lede { display: none; }
@media (max-width: 1099px) { html[data-work-view="index"] #work .section-head__lede { display: none; } }

/* --- The index table ------------------------------------------------------------------------------ */
/* The list reaches a cell's padding past the content edges (the text lines up with the heading), and
   clips the rows' link areas to the table. */
.work-index__list { margin-inline: calc(-1 * var(--s3)); overflow: hidden; overflow: clip; }
.work-index__table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.work-index__table :is(th, td) {
  padding: 18px var(--s3);   /* rows 64–72 px with the title's line */
  text-align: left; vertical-align: baseline; font-weight: 400;
  border-bottom: 1px solid var(--line);
}
.work-index__table thead th {
  padding-block: 0 var(--s3); vertical-align: bottom;
  font-family: var(--font-mono); font-size: 0.66rem; letter-spacing: var(--tracking-mono); text-transform: uppercase;
  color: var(--paper-3); border-bottom-color: var(--line-strong);
}
.work-index__table td {
  font-family: var(--font-mono); font-size: 0.72rem; line-height: 1.5; letter-spacing: var(--tracking-mono); text-transform: uppercase;
  color: var(--paper-2); text-wrap: pretty;
}
/* The camera over the lens, each wide enough to break once at most (a block's min-width widens the column). */
.work-index__line { display: block; min-width: 21ch; }
.work-index__line + .work-index__line { color: var(--paper-3); }
.work-index__none { color: var(--paper-3); }   /* an empty cell's dash: quiet, but there (5.6:1) */
.work-index__row { transition: background-color 200ms var(--ease-ui); }
.work-index__row:is(:hover, :focus-within) { background: var(--ink-2); }
td.work-index__no { color: var(--paper-3); transition: color 200ms var(--ease-ui); }
.work-index__row:is(:hover, :focus-within) td.work-index__no { color: var(--tungsten); }
.work-index__year, .work-index__aspect { white-space: nowrap; }

/* The title: the row's header and its one link, whose area covers the whole row. A sample's badge rides
   on the title's line (the space in the markup parts them), so a row is one line of title tall. */
.work-index__film { position: relative; text-wrap: balance; }
.work-index__link { color: var(--paper); text-decoration: none; }
.work-index__link::after { content: ""; position: absolute; inset: 0 -100vw; }
.work-index__title {
  font-family: var(--font-display); font-weight: 500; font-size: clamp(1.35rem, 1rem + 0.9vw, 2.2rem); line-height: 1.1;
  background: linear-gradient(var(--tungsten), var(--tungsten)) 100% 100% / 0 1px no-repeat;
  transition: background-size 450ms var(--ease-io-expo);
}
.work-index__row:hover .work-index__title, .work-index__link:focus-visible .work-index__title { background-size: 100% 1px; background-position-x: 0; }
/* The focus ring is the title's: the link's area (its ::after) can sit on an empty line after a wrapped
   title, and the link's own ring would trace that empty fragment as a stray bracket. */
.work-index__link:focus-visible { outline: 0; }
.work-index__link:focus-visible .work-index__title { outline: var(--focus-ring); outline-offset: var(--focus-offset); }
@media (forced-colors: active) { .work-index__link:focus-visible .work-index__title { outline-color: Highlight; } }
.work-index__film .badge-sample { margin: 0; vertical-align: 0.35em; font-size: 0.62rem; padding: 1px 6px; }

/* Columns by width (see the top): what a width cannot hold waits for a wider one. Without JavaScript
   there is no pane, so from 1100 the table has the full width and every column. */
@media (max-width: 1799px) {
  html.js .work-index :is(.work-index__prod, .work-index__kit, .work-index__premiere) { display: none; }
}
/* With Camera / Lens (two or three lines of it) a row is taller: a tighter padding keeps all six rows on the
   first screen under the head. */
@media (min-width: 1800px) {
  .work-index__table tbody :is(th, td) { padding-block: 14px; }
}
@media (max-width: 1099px) {
  .work-index :is(.work-index__prod, .work-index__kit, .work-index__premiere) { display: none; }
}
@media (max-width: 719px) {
  .work-index :is(.work-index__no, .work-index__dir) { display: none; }
  /* A narrow window (320 px is a 1280 px screen at 400 %) or wider text spacing can need more than the
     width: the table scrolls sideways instead of cutting off Aspect, and the title cell is the link's area.
     The edge with more of the table beyond it carries a soft light (fixed to the box), which a cover in
     the page's ink (carried with the table) hides once that edge is reached: a table that fits shows none. */
  .work-index__list {
    margin-inline: calc(-1 * var(--s2)); overflow-x: auto;
    background:
      linear-gradient(to right, var(--ink-1) 50%, rgb(12 13 16 / 0)) left / 28px 100% no-repeat local,
      linear-gradient(to left, var(--ink-1) 50%, rgb(12 13 16 / 0)) right / 28px 100% no-repeat local,
      radial-gradient(farthest-side at 0 50%, rgb(236 230 218 / 0.16), rgb(236 230 218 / 0)) left / 14px 100% no-repeat scroll,
      radial-gradient(farthest-side at 100% 50%, rgb(236 230 218 / 0.16), rgb(236 230 218 / 0)) right / 14px 100% no-repeat scroll;
  }
  .work-index__link::after { inset: 0; }
  .work-index__table :is(th, td) { padding: 14px var(--s2); }
  .work-index__table thead th { padding-block: 0 var(--s2); }
  .work-index__title { font-size: 1.35rem; }
  /* A sample's badge under the title, in every row (inline, it would ride on some titles' lines only). */
  .work-index__film .badge-sample { display: block; width: max-content; margin-top: 6px; }
}

/* Rack focus: on a pointer with motion on, the rows the pointer is not on go soft. Hover only: keyboard
   focus moves the preview but never blurs text (nor does a focused row ever blur). */
@media (hover: hover) and (pointer: fine) and (min-width: 1024px) and (prefers-contrast: no-preference) {
  html[data-motion="on"] .work-index__row > * { transition: filter 350ms var(--ease-ui), opacity 350ms var(--ease-ui); }
  html[data-motion="on"] .work-index tbody:has(tr:hover) tr:not(:hover):not(:focus-within) > * { filter: blur(1.5px); opacity: 0.5; }
}

/* --- The preview pane (from 1100 px) -------------------------------------------------------------- */
.work-index__preview { display: none; }
@media (min-width: 1100px) {
  html.js .work-index { display: grid; grid-template-columns: minmax(0, 1fr) clamp(320px, 30vw, 640px); column-gap: clamp(32px, 3vw, 96px); align-items: start; }
  .work-index__preview { display: grid; gap: var(--s4); position: sticky; top: 96px; }
  .work-index__table :is(th, td) { padding-inline: 10px; }
  .work-index__list { margin-inline: -10px; }
}
/* A 16:9 gate on black; the film's frame sits in it at its own aspect, letterboxed, never cropped. */
.work-index__gate {
  position: relative; aspect-ratio: 16 / 9; display: grid; place-items: center; overflow: hidden;
  background: #030304; outline: 1px solid var(--line); outline-offset: -1px; cursor: pointer;
}
.work-index__shot { grid-area: 1 / 1; width: min(100%, calc(var(--ar) * 56.25%)); transition: opacity 300ms var(--ease-ui); }
.work-index__shot > img { object-fit: contain; }
.work-index__shot.is-leaving { opacity: 0; pointer-events: none; }   /* fades off the incoming frame below it */
.work-index__tag {
  position: absolute; right: var(--s2); bottom: var(--s2); z-index: 2;
  padding: 1px 6px; background: rgb(7 8 10 / 0.85); border-radius: var(--radius-1);   /* 4.5:1 on white too */
  font-family: var(--font-mono); font-size: 0.58rem; letter-spacing: var(--tracking-mono); text-transform: uppercase; color: var(--paper-2);
}
.work-index__logline {
  font-family: var(--font-display); font-style: italic; font-size: var(--step-1); line-height: 1.35; color: var(--paper-2);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden;
}
@media (forced-colors: active) {
  .work-index__gate { outline-color: CanvasText; }
}

/* --- Hover previews (main.js): the film's own clip over its card's still ----------------------------- */
.work-card__preview { z-index: 1; opacity: 0; pointer-events: none; transition: opacity 250ms var(--ease-ui); }
.work-card__preview.is-playing { opacity: 1; transition: opacity 600ms var(--ease-out-expo); }

/* --- Phones and tablets: the gates open with the scroll ---------------------------------------------- */
@supports (animation-timeline: view()) {
  html:not(.motion-ready)[data-motion="on"] .work-card__gate {
    animation: work-gate-open linear both;
    animation-timeline: view();
    animation-range: entry 10% cover 35%;
  }
  @keyframes work-gate-open {
    from { clip-path: inset(0 100% 0 0); }
    to { clip-path: inset(0 0 0 0); }
  }
}
