/* ==========================================================================
   ux-polish.css — Puroresu Project interaction polish kit (Nov 2026 audit)
   --------------------------------------------------------------------------
   Drop-in. Load LAST on archive pages (after archive-drawer-ui.css,
   vault-card-controls.css and any page stylesheet), alongside ux-polish.js.
   Everything is scoped under html.ux-tactile, which ux-polish.js sets, so
   removing the class (or the <link>) is a one-step kill switch.

   Guardrails kept:
   - No Timeline image geometry is touched (no rules on .timeline-detail__photo,
     crops, focus or image presentation values).
   - No literal z-index: --z-* tokens only.
   - Colours come from existing tokens; new values are motion/shadow tokens.
   - Every animation is removed under prefers-reduced-motion.
   ========================================================================== */

:root {
  /* Motion: "print weight". A short press-in, a slower, heavier settle.
     No overshoot or bounce: paper and card stock don't spring. */
  --ux-press-in: 70ms;
  --ux-settle: 200ms;
  --ux-ease-press: cubic-bezier(0.3, 0, 0.6, 1);
  --ux-ease-settle: cubic-bezier(0.2, 0.8, 0.2, 1);

  /* Shadows: hard, offset ink edges in place of the Material blur
     (0 1px 3px 1px / 0 4px 8px 3px) currently on wrestler, mask and vault cards. */
  --ux-shadow-rest: 0 1px 0 rgb(0 0 0 / 55%), 0 0 0 1px rgba(var(--text-primary-rgb, 244, 241, 233), 0.03);
  --ux-shadow-lift: 0 3px 0 rgb(0 0 0 / 60%), 0 12px 18px -14px rgb(0 0 0 / 80%);
  --ux-shadow-press: 0 0 0 rgb(0 0 0 / 60%);
  --ux-lift: -2px;
  --ux-press: 1px;

  /* Card corner. Left at the current 24px; 10–12px reads closer to trimmed
     card stock / magazine plates. Change here to try it on every archive card. */
  --ux-card-radius: 24px;
}

/* ---------------------------------------------------------------------------
   1. Archive cards: one set of press physics for Wrestlers, Venues, Masks,
      Voices & Officials and Vault cards.
   ------------------------------------------------------------------------ */
/* main:not(#ux-tactile-bump) adds one ID's worth of specificity so these
   rules beat the page rules (up to 0,6,0, e.g. the touch :hover reset)
   without !important. No element needs that id. */
html.ux-tactile[data-theme] body main:not(#ux-tactile-bump) :is(
  .wrestler-card,
  .venue-card[data-venue-card],
  .mask-card[data-mask-card],
  .voice-card[data-voice-card],
  .vault-card
) {
  border-radius: var(--ux-card-radius);
  box-shadow: var(--ux-shadow-rest);
  transform: translateY(0);
  transition:
    transform var(--ux-settle) var(--ux-ease-settle),
    box-shadow var(--ux-settle) var(--ux-ease-settle),
    border-color var(--duration-fast) var(--ease-out);
}

/* Hover lifts only on real hover devices. */
@media (hover: hover) and (pointer: fine) {
  html.ux-tactile[data-theme] body main:not(#ux-tactile-bump) :is(
    .wrestler-card,
    .venue-card[data-venue-card],
    .mask-card[data-mask-card],
    .voice-card[data-voice-card],
    .vault-card
  ):hover {
    box-shadow: var(--ux-shadow-lift);
    transform: translateY(var(--ux-lift));
  }
}

/* Selected = sits flat and "pulled" with a red registration rule, so it
   can't be mistaken for hover (both currently share border + lift). */
html.ux-tactile[data-theme] body main:not(#ux-tactile-bump) :is(
  .wrestler-card,
  .venue-card[data-venue-card],
  .mask-card[data-mask-card],
  .voice-card[data-voice-card]
):is(.is-active, .venue-card--active, [aria-selected="true"]) {
  border-color: var(--accent-red);
  box-shadow: inset 0 0 0 1px var(--accent-red), var(--ux-shadow-rest);
  transform: translateY(0);
}

/* Masks paints its selected card with an !important shadow taken from this
   variable, so point the variable at the same selected look. */
html.ux-tactile[data-theme] body .masks-archive {
  --mask-material-card-selected-shadow: inset 0 0 0 1px var(--accent-red), var(--ux-shadow-rest);
}

/* Press goes DOWN. The current wrestler/mask rule lifts the card -4px on
   :active, which reads backwards on touch. */
html.ux-tactile[data-theme] body main:not(#ux-tactile-bump) :is(
  .wrestler-card,
  .venue-card[data-venue-card],
  .mask-card[data-mask-card],
  .voice-card[data-voice-card],
  .vault-card
):is(:active, .ux-is-pressing) {
  box-shadow: var(--ux-shadow-press);
  transform: translateY(var(--ux-press));
  transition-duration: var(--ux-press-in);
  transition-timing-function: var(--ux-ease-press);
}

/* A small ink press on the photo while the finger is down. */
html.ux-tactile[data-theme] body main:not(#ux-tactile-bump) :is(.wrestler-card, .venue-card, .mask-card, .voice-card, .vault-card):is(:active, .ux-is-pressing) img {
  filter: brightness(0.92) contrast(1.06);
  transition: filter var(--ux-press-in) linear;
}

/* Small buttons get the same press. */
html.ux-tactile[data-theme] body :is(
  .ds-button,
  .filter-sheet-trigger,
  .filter-sheet__btn,
  .venues-view-toggle__btn,
  .wrestler-detail-panel__tab,
  .watchlist-bookmark,
  .archive-share-button
):active:not(:disabled) {
  transform: translateY(1px) !important;
  transition: transform var(--ux-press-in) var(--ux-ease-press) !important;
}

/* ---------------------------------------------------------------------------
   2. Search: focus keeps the site's own red border + ring (no extra rule, which
      stacked on it). After blur, an active query keeps the red border and a
      red icon, without the ring, so it's clear the grid is filtered.
   ------------------------------------------------------------------------ */
html.ux-tactile body .archive-toolbar .search-wrap:has(input:not(:placeholder-shown)):not(:focus-within) {
  border-color: rgba(var(--accent-red-rgb), 0.62);
}
html.ux-tactile body .archive-toolbar .search-wrap:has(input:not(:placeholder-shown)):not(:focus-within) .search-icon {
  color: var(--accent-red);
}

/* ---------------------------------------------------------------------------
   3. Count changes: the filter badge, "Show N" and the archive status line
      "tick" when their number changes (class set by ux-polish.js).
   ------------------------------------------------------------------------ */
@keyframes ux-tick {
  0%   { transform: translateY(-3px) scale(0.86); opacity: 0.4; }
  100% { transform: none; opacity: 1; }
}
@keyframes ux-flash {
  0%   { filter: brightness(1.35); }
  100% { filter: none; }
}
html.ux-tactile body .filter-sheet-trigger__badge.ux-tick {
  animation: ux-tick 260ms var(--ux-ease-settle);
}
html.ux-tactile body :is(.filter-sheet__btn, .filter-sheet__footer button).ux-tick {
  animation: ux-flash 320ms var(--ease-out);
}
html.ux-tactile body .ux-count-tick {
  display: inline-block;
  animation: ux-tick 240ms var(--ux-ease-settle);
}

/* ---------------------------------------------------------------------------
   4. Filter sheet (≤1365px): stamp-style checkboxes, animated rows, and a
      stable phone detent so opening a group doesn't jump the sheet to the top.
   ------------------------------------------------------------------------ */
@media (max-width: 1365px) {
  html.ux-tactile body [data-filter-sheet] :is(.archive-filter-option, .venue-filter-option) {
    transition:
      background-color var(--duration-fast) var(--ease-out),
      border-color var(--duration-fast) var(--ease-out),
      transform var(--ux-press-in) var(--ux-ease-press) !important;
  }
  html.ux-tactile body [data-filter-sheet] :is(.archive-filter-option, .venue-filter-option):active {
    transform: translateY(1px);
  }

  /* Stamp check in place of the native OS checkbox. The tick itself is the
     site's existing input::after check (styles.css), so it isn't redrawn here. */
  html.ux-tactile body [data-filter-sheet] :is(.archive-filter-option, .venue-filter-option) input[type="checkbox"] {
    appearance: none !important;
    -webkit-appearance: none !important;
    display: grid !important;
    place-items: center;
    width: 20px !important;
    height: 20px !important;
    border: 1.5px solid var(--color-stone-400) !important;
    border-radius: 3px !important;
    background: transparent;
    transition: background-color var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out);
  }
  html.ux-tactile body [data-filter-sheet] :is(.archive-filter-option, .venue-filter-option) input[type="checkbox"]:checked {
    background: var(--color-red-signal);
    border-color: var(--color-red-signal) !important;
    animation: ux-stamp 220ms var(--ux-ease-settle);
  }

  /* Accordion: animate height where the browser can (Chromium 129+);
     elsewhere it opens instantly, as today. */
  html.ux-tactile body [data-filter-sheet] .archive-filter-dropdown__panel {
    interpolate-size: allow-keywords;
    transition:
      height var(--duration-standard) var(--ux-ease-settle),
      opacity var(--duration-fast) var(--ease-out),
      display var(--duration-standard) allow-discrete;
  }
  /* Clip only while closed: an open panel must keep its own scrolling
     (long promotion lists scroll inside the sheet). */
  html.ux-tactile body [data-filter-sheet] .archive-filter-dropdown:not(.is-open) > .archive-filter-dropdown__panel {
    height: 0;
    opacity: 0;
    overflow: clip;
  }
  html.ux-tactile body [data-filter-sheet] .archive-filter-dropdown.is-open > .archive-filter-dropdown__panel {
    height: auto;
    opacity: 1;
  }
  @starting-style {
    html.ux-tactile body [data-filter-sheet] .archive-filter-dropdown.is-open > .archive-filter-dropdown__panel {
      height: 0;
      opacity: 0;
    }
  }
  html.ux-tactile body [data-filter-sheet] .archive-filter-dropdown__trigger::after {
    transition: transform var(--duration-standard) var(--ux-ease-settle);
  }
}

@keyframes ux-stamp {
  0%   { transform: scale(1.28) rotate(-8deg); }
  60%  { transform: scale(0.94) rotate(1deg); }
  100% { transform: none; }
}

/* Phones: open the filter sheet at a single full-height detent. The sheet
   is auto-height today, so expanding Era/Promotion snaps it from ~343px
   to 10px in one frame. Full height keeps the edge still. */
@media (max-width: 768px) {
  html.ux-tactile body [data-filter-sheet].archive-drawer--filter {
    height: calc(100dvh - var(--archive-drawer-top-gap, 10px)) !important;
  }
  html.ux-tactile body.filter-sheet-open [data-filter-sheet] .filter-sheet__body {
    flex: 1 1 auto !important;
  }
}

/* ---------------------------------------------------------------------------
   5. Mobile profile sheet: the scrim follows the drag, neighbour cards peek
      so swiping is discoverable, and tabs stay reachable in long bios.
   ------------------------------------------------------------------------ */
@media (max-width: 768px) {
  /* --sheet-progress (0 = open, 1 = fully dragged down) is written by
     archive-profile-sheet.js paint(). */
  html.ux-tactile .profile-sheet-overlay.is-visible::before {
    opacity: calc(1 - var(--sheet-progress, 0) * 0.9);
  }
  html.ux-tactile .profile-sheet-overlay:has(> .profile-sheet.is-dragging)::before {
    transition: none;
  }

  /* The neighbour peek is now the shared --drawer-gutter token (22px) in
     css/tokens.css, so Lineage and every other drawer match. */

  /* Sticky Bio / Titles / Moves under the 48px reading bar. */
  html.ux-tactile[data-theme] body .profile-sheet .wrestler-detail-panel__tabs {
    position: sticky !important;
    top: 48px;
    z-index: var(--z-raised-3);
    box-shadow: 0 1px 0 rgba(var(--text-primary-rgb, 244, 241, 233), 0.08);
  }

  /* Card position index, e.g. "12 / 237" (added by ux-polish.js). */
  html.ux-tactile .ux-sheet-index {
    position: absolute;
    top: calc(var(--drawer-top-gap) + 15px);
    left: 34px;
    z-index: var(--z-raised-4);
    padding: 3px 8px;
    border-radius: 4px;
    background: rgb(20 20 19 / 82%);
    color: var(--color-paper);
    font: 700 var(--font-size-chrome-xs)/1.3 var(--display);
    letter-spacing: var(--tracking-label, 0.06em);
    font-variant-numeric: tabular-nums;
    pointer-events: none;
  }
}

/* ---------------------------------------------------------------------------
   6. Desktop / tablet split pane: sticky tabs, and a short "page turn" when
      the selected record changes, instead of a hard cut.
   ------------------------------------------------------------------------ */
@media (min-width: 769px) {
  html.ux-tactile[data-theme] body [data-wrestler-detail]:not(.is-modal-open) .wrestler-detail-panel__tabs {
    /* Pinned below the pane's rounded top edge, on a solid band in the
       pane's own colour, so scrolled text never shows beside or above it.
       The band reaches 10px below the bar (inside the 16px gap that sits
       above the tab panel at rest), so text scrolls away with some air. */
    --ux-sticky-tabs-bg: var(--color-ink-800);
    position: sticky;
    top: 12px;
    z-index: var(--z-raised-3);
    background-color: var(--ux-sticky-tabs-bg);
    box-shadow: 0 0 0 16px var(--ux-sticky-tabs-bg);
    clip-path: inset(-12px -16px -10px -16px);
  }
  html.ux-tactile[data-theme="dark"] body [data-wrestler-detail]:not(.is-modal-open) .wrestler-detail-panel__tabs {
    --ux-sticky-tabs-bg: var(--color-ink-940);
  }
  html.ux-tactile[data-theme="light"] body [data-wrestler-detail]:not(.is-modal-open) .wrestler-detail-panel__tabs {
    --ux-sticky-tabs-bg: var(--detail-paper-start, #f1ead9);
  }
}
@keyframes ux-leaf {
  from { opacity: 0.35; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
html.ux-tactile body .archive-detail.ux-is-turning :is(
  .wrestler-detail-panel__summary,
  .wrestler-detail-panel__tab-panel:not([hidden]),
  .venue-detail__header,
  .venue-detail__stats,
  .venue-detail__section
) {
  animation: ux-leaf var(--duration-standard) var(--ux-ease-settle);
}

/* ---------------------------------------------------------------------------
   7. Phone "toolbar return": after the archive toolbar scrolls away, a
      search + filter pill sits in the thumb zone (built by ux-polish.js).
   ------------------------------------------------------------------------ */
.ux-toolbar-return { display: none; }
@media (max-width: 760px) {
  html.ux-tactile .ux-toolbar-return {
    position: fixed;
    left: 50%;
    bottom: calc(16px + env(safe-area-inset-bottom, 0px));
    z-index: var(--z-float-dock);
    display: flex;
    gap: 0;
    padding: 0;
    border: 1px solid rgb(246 241 231 / 22%);
    border-left: 3px solid var(--accent-red);
    border-radius: 8px;
    background: var(--chrome-header-surface, var(--color-ink-900));
    box-shadow: 0 3px 0 rgb(0 0 0 / 60%), 0 14px 24px -12px rgb(0 0 0 / 85%);
    transform: translate(-50%, calc(100% + 32px));
    transition: transform var(--duration-drawer) var(--ease-drawer);
  }
  html.ux-tactile .ux-toolbar-return.is-shown { transform: translate(-50%, 0); }
  html.ux-tactile:is(.profile-sheet-open) .ux-toolbar-return,
  html.ux-tactile body.filter-sheet-open .ux-toolbar-return { transform: translate(-50%, calc(100% + 32px)); }
  html.ux-tactile .ux-toolbar-return button {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-width: 56px;
    min-height: 48px;
    padding: 0 16px;
    border: 0;
    background: transparent;
    color: var(--color-paper-soft, var(--color-paper));
    font: 700 var(--font-size-chrome-md)/1 var(--display);
    text-transform: uppercase;
    touch-action: manipulation;
  }
  html.ux-tactile .ux-toolbar-return button + button { border-left: 1px solid rgb(246 241 231 / 14%); }
  html.ux-tactile .ux-toolbar-return button:active { background: var(--chrome-selected-surface, rgb(255 255 255 / 6%)); }
  html.ux-tactile .ux-toolbar-return button:focus-visible { outline: 2px solid var(--color-paper); outline-offset: -3px; }
  html.ux-tactile .ux-toolbar-return .ux-toolbar-return__badge {
    display: inline-grid; place-items: center;
    min-width: 20px; height: 20px; padding: 0 5px; border-radius: 999px;
    background: var(--accent-red); color: var(--color-white);
    font: 700 var(--font-size-chrome-xs)/1 var(--body);
  }
  html.ux-tactile .ux-toolbar-return .ux-toolbar-return__badge[hidden] { display: none; }
}

/* ---------------------------------------------------------------------------
   8. Watchlist bookmark (currently hidden behind WATCHLIST_ENABLED = false).
      Ready for when My Watchlist comes back.
   ------------------------------------------------------------------------ */
html.ux-tactile .watchlist-bookmark {
  transition: background-color var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out), transform var(--ux-press-in) var(--ux-ease-press);
}
html.ux-tactile .watchlist-bookmark.ux-stamp { animation: ux-stamp 240ms var(--ux-ease-settle); }

/* ---------------------------------------------------------------------------
   9. Reading weight: long-form prose is set in D-DIN 700–800 today. Medium
      (500) keeps the dense, inked look and reads far better in long passages.
      Ledes, bridges and display copy stay heavy.
   ------------------------------------------------------------------------ */
html.ux-tactile[data-theme] body :is(
  .wrestler-detail-panel__section > p,
  .wrestler-detail-panel__section > ul > li,
  .venue-detail__section > p,
  .timeline-detail__copy p,
  .story-proto-chapter__copy > p:not(.story-proto-bridge),
  .story-proto-beat > p
) {
  font-weight: 500;
  font-synthesis: none;
  text-wrap: pretty;
}

/* Japanese names: correct glyphs and spacing once ux-polish.js marks them
   lang="ja". Uses each OS's own Japanese UI face; nothing is downloaded. */
html.ux-tactile :lang(ja) {
  /* Not var(--font-heading): that list ends in generic sans-serif, which would
     win before any Japanese face is tried. */
  font-family: "D-DIN-PRO", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic UI", "Yu Gothic", "Meiryo", "Noto Sans JP", sans-serif;
  line-break: strict;
  text-spacing-trim: trim-start;
}

/* ---------------------------------------------------------------------------
   10. Detail-pane titles follow the pane, not the window. Today the name is
       32px in a 293–360px pane at 769–1120px, then 50–54px in a 310–341px
       pane at desktop widths. Sized in container units at the desktop ratio,
       so 1440px looks the same and tablets stop stepping down. Phones (the
       profile sheet) keep their current sizes.
   ------------------------------------------------------------------------ */
@media (min-width: 769px) {
  html.ux-tactile[data-theme] body .archive-detail:not(.is-modal-open) :is(.wrestler-detail-panel__summary, .venue-detail__header) {
    container-type: inline-size;
  }
  html.ux-tactile[data-theme] body main:not(#ux-tactile-bump) .archive-detail:not(.is-modal-open) .wrestler-detail-panel__name {
    font-size: clamp(2rem, 18.7cqi, 3.4rem) !important;
  }
  html.ux-tactile[data-theme] body main:not(#ux-tactile-bump) .archive-detail.mask-detail-panel:not(.is-modal-open) .wrestler-detail-panel__name {
    font-size: clamp(2rem, 15.5cqi, 3rem) !important;
  }
  html.ux-tactile[data-theme] body main:not(#ux-tactile-bump) .archive-detail:not(.is-modal-open) :is(.venue-detail__title, .venue-detail__header h2) {
    font-size: clamp(2rem, 13.7cqi, 2.75rem) !important;
  }
}

/* ---------------------------------------------------------------------------
   11. Card grids size their columns from the grid's own width, not the
       window. Today columns follow viewport breakpoints while the rail and
       detail pane come and go, so cards swing 164 <-> 320px (e.g. 320px at
       1121, 189px at 1280; one 309px card per row at 360). Each column is at
       least --ux-card-min wide, but never so wide that two can't sit side by
       side, so phones keep two columns. The Vault already does this.
   ------------------------------------------------------------------------ */
html.ux-tactile[data-theme] body main:not(#ux-tactile-bump) :is(.wrestler-grid, .wrestler-group__grid, .venue-grid, .mask-grid, .voices-grid) {
  --ux-card-min: 11rem;
  grid-template-columns: repeat(auto-fill, minmax(min(var(--ux-card-min), calc((100% - 1.5rem) / 2)), 1fr)) !important;
}
/* Masks keeps its larger museum plates (four across at 1280-1440px). */
html.ux-tactile[data-theme] body main:not(#ux-tactile-bump) .mask-grid {
  --ux-card-min: 12rem;
}

/* ---------------------------------------------------------------------------
   Reduced motion: keep the state changes, remove the movement.
   ------------------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  html.ux-tactile :is(.ux-tick, .ux-count-tick, .ux-stamp),
  html.ux-tactile body .archive-detail.ux-is-turning *,
  html.ux-tactile body [data-filter-sheet] input[type="checkbox"]:checked {
    animation: none !important;
  }
  html.ux-tactile[data-theme] body main:not(#ux-tactile-bump) :is(.wrestler-card, .venue-card, .mask-card, .voice-card, .vault-card) {
    transform: none !important;
    transition: box-shadow var(--duration-fast) linear, border-color var(--duration-fast) linear !important;
  }
  html.ux-tactile body [data-filter-sheet] .archive-filter-dropdown__panel { transition: none; }
  html.ux-tactile .ux-toolbar-return { transition: none; }
}
