/**
 * <slot-tile> canonical styles — Wave 18A Step 2
 *
 * Visual treatment per _specs/slot_tile.md §3, modeled on the Concept
 * Detail page's existing .cell / .cell-frame / .cell-num / .cell-cap
 * combo (the canonical look Martin prefers — clean card with a
 * thumbnail-filled frame inside).
 *
 * Custom Element uses Light DOM, so these global selectors apply
 * to elements rendered anywhere on the page (Detail, Summary, Canvas).
 * The element-name selector `slot-tile` scopes the BEM-style classes
 * to this component without leaking to the rest of the page.
 *
 * Token references fall back to safe defaults so the dev page works
 * even if styles.css doesn't load first.
 */

/* ============================================================
 * Card body — the outer container is the card itself.
 * White background, rounded corners, soft shadow, hover lift.
 * Cap width at 160px on canvas; surface CSS can override via
 * a width / min-width rule on the parent grid for Detail / Summary.
 * ============================================================ */
slot-tile {
  display: inline-block;
  position: relative; /* anchor for the absolutely-positioned slot menu */
  /* Width is driven by the parent (flex / grid). Detail uses 200px flex
     items, Canvas uses 160px grid columns, Summary uses 200px-capped flex.
     Without explicit sizing, slot-tile fills 100% of its container. */
  width: 100%;
  vertical-align: top;
  background: var(--surface, #FFFFFF);
  border-radius: var(--radius-sm, 8px);
  box-shadow: var(--shadow-soft, 0 1px 2px rgba(31,27,22,0.04), 0 4px 12px rgba(31,27,22,0.05));
  /* overflow stays VISIBLE so the menu (which renders above the top edge
     at top:-14px) doesn't get clipped by the card boundary. The frame
     element below has its own overflow:hidden for the thumbnail clip. */
  transition: box-shadow 0.18s ease, transform 0.18s ease;
  cursor: pointer;
  /* Wave 18A round 3 / spec §6.2: reserve vertical room INSIDE the
     primitive for the menu protrusion (top: -14px). The padding-top
     keeps the menu poke inside the tile's own bounding box so parent
     containers (Summary's overflow-x scroll, Canvas's React Flow node
     clip) don't need to know about the protrusion. */
  padding-top: 28px;
  box-sizing: border-box;
}

slot-tile:hover {
  box-shadow: var(--shadow-lift, 0 2px 4px rgba(31,27,22,0.05), 0 10px 24px rgba(31,27,22,0.08));
  transform: translateY(-2px);
}

/* Active slot marker — Canvas / Detail / Summary set data-active="true"
   on the slot-tile that's focused in the right-panel (Canvas) or the
   current detail row (Detail / Summary). Replaces the per-surface
   `is-current` class pattern from Wave 18A round 2 — primitive owns
   its state attribute, surfaces just toggle the value. Spec §5.3. */
slot-tile[data-active="true"] {
  box-shadow:
    0 0 0 2px var(--accent-deep, #A85E3B),
    0 2px 8px rgba(168, 94, 59, 0.18);
}

slot-tile.slot-tile--empty {
  box-shadow: none;
  background: var(--canvas-deep, #F1ECE3);
  cursor: default;
}

slot-tile.slot-tile--empty:hover {
  transform: none;
}

/* Loading state. While the video element is downloading the first frame
   (hover-play just started, network hasn't delivered enough bytes to
   begin playback), Martin can't tell if hover-play is working or broken.
   The .is-loading class gives the thumbnail a subtle pulse animation;
   the JS removes the class as soon as the video fires `playing` or
   `loadeddata`. The pulse is short and quiet — not a spinner, more of
   a "we heard you" signal. */
@keyframes slot-tile-pulse {
  0%   { filter: brightness(1.0); }
  50%  { filter: brightness(1.15); }
  100% { filter: brightness(1.0); }
}
slot-tile.is-loading .slot-tile__thumb {
  animation: slot-tile-pulse 0.9s ease-in-out infinite;
}
slot-tile.is-loading {
  cursor: progress;
}

/* ============================================================
 * Frame — the 9:16 thumbnail area inside the card. Holds the
 * thumbnail (via background-image), the index badge, the AI /
 * LINKED badge, and (Step 3) the hover-play video + scrub bar.
 * ============================================================ */
.slot-tile__frame {
  position: relative;
  width: 100%;
  aspect-ratio: 9 / 16;
  background: var(--canvas-deep, #F1ECE3);
  /* Rounded top corners to match the card's top rounding. Bottom corners
     stay square because the caption sits below the frame inside the same
     card; the card's own bottom-corner rounding shows through. */
  border-radius: var(--radius-sm, 8px) var(--radius-sm, 8px) 0 0;
  overflow: hidden;
}

.slot-tile__thumb {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

.slot-tile__thumb--missing {
  background: linear-gradient(135deg, #2a221c 0%, #1f1b16 100%);
}

.slot-tile__thumb--missing::after {
  content: 'missing';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono, monospace);
  font-size: 10px;
  color: var(--ink-faint, #B5ADA3);
  letter-spacing: 0.04em;
}

/* ============================================================
 * Index badge — top-left, white pill with dark text (matches Detail).
 * Square brackets are part of the rendered text (e.g., "[01]").
 * ============================================================ */
.slot-tile__index {
  position: absolute;
  top: 6px;
  left: 6px;
  z-index: 2;
  min-width: 18px;
  padding: 1px 5px;
  background: rgba(255, 255, 255, 0.92);
  color: var(--ink, #1F1B16);
  border-radius: var(--radius-pill, 999px);
  font-family: var(--mono, monospace);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0;
  text-align: center;
  line-height: 1.4;
}

/* ============================================================
 * Caption — sits inside the card, below the frame. 3-line clamp
 * with hard height so all tiles in a row align bottom-to-bottom.
 * ============================================================ */
.slot-tile__caption {
  padding: 10px 12px 12px;
  font-size: 12px;
  color: var(--ink-soft, #5E564C);
  line-height: 1.4;
  height: 64px;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
  box-sizing: border-box;
}

.slot-tile--empty .slot-tile__caption {
  color: var(--ink-faint, #B5ADA3);
}

/* ============================================================
 * Caption edit affordance (Wave 19A2 P1).
 * Active only when slot-tile[data-edit-caption="true"] (Detail
 * surface sets this; Summary + Canvas keep captions read-only).
 *
 * Affordances:
 *   - cursor: text on the editable caption
 *   - subtle accent ring on focus
 *   - tiny "saving" / "saved" / "error" indicators added via JS
 *     classes on the caption element
 * ============================================================ */
slot-tile[data-edit-caption="true"] .slot-tile__caption {
  cursor: text;
  /* While editing we lift the line-clamp so the user can see all of
     their text. The fixed height stays so the surrounding layout
     doesn't jump as they type. */
  transition: box-shadow 0.15s ease, background 0.15s ease;
  border-radius: var(--radius-sm, 6px);
}
slot-tile[data-edit-caption="true"] .slot-tile__caption:hover {
  background: var(--canvas, #FBF7F1);
}
slot-tile[data-edit-caption="true"] .slot-tile__caption:focus,
slot-tile[data-edit-caption="true"] .slot-tile__caption.is-editing {
  outline: none;
  background: var(--surface, #FFFFFF);
  box-shadow: inset 0 0 0 2px var(--accent-deep, #A85E3B);
  /* Drop the 3-line clamp so the editor can see what they're typing. */
  -webkit-line-clamp: unset;
  overflow: auto;
}
.slot-tile__caption.is-saving {
  box-shadow: inset 0 0 0 2px var(--ink-ghost, #ECE3D8);
  background: var(--canvas, #FBF7F1);
}
.slot-tile__caption.is-saved {
  box-shadow: inset 0 0 0 2px var(--good, #5C7A4A);
}
.slot-tile__caption.is-error {
  box-shadow: inset 0 0 0 2px var(--err, #9B4B3F);
}

/* ============================================================
 * AI / LINKED badge — top-right of the frame, mirrors the index
 * badge on the left but uses an accent-tinted background. Step 1
 * stubs this; Step 2 reserves the visual (the conditional render
 * lives in slot_tile.js once we add the AI/LINKED logic in a later
 * commit — see _specs/slot_tile.md §3.4).
 * ============================================================ */
.slot-tile__badge-ai {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 2;
  padding: 2px 7px;
  background: var(--accent-soft, #F4E2D5);
  color: var(--accent-deep, #A85E3B);
  border-radius: var(--radius-pill, 999px);
  font-family: var(--mono, monospace);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  display: none; /* Reveals via the .slot-tile--ai modifier when slot.is_ai. */
}

slot-tile.slot-tile--ai .slot-tile__badge-ai {
  display: inline-block;
}

/* ============================================================
 * Slot action menu — top edge of the tile, appears on hover.
 * Four buttons: + (insert before), 🗑 (delete), 🔄 (replace),
 * + (insert after). Ported from canvas.css .cv-slot-menu.
 *
 * Hidden by default (opacity 0, pointer-events none) and reveals
 * on slot-tile:hover with a small upward translate. Pointer-events
 * disabled in the hidden state so the menu doesn't block hover-play
 * detection on the frame below.
 * ============================================================ */
.slot-tile__menu {
  position: absolute;
  /* Wave 18A round 3 / spec §6.2: menu sits at top 0 of slot-tile (i.e.,
     inside the host's padding-top: 28px reservation). The visible menu
     occupies the top ~28px strip of the slot-tile, which previously was
     overflow above the box (top: -14px). Now no container needs to
     handle menu overflow — the menu lives entirely inside the tile. */
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 4px;
  padding: 3px 5px;
  background: var(--surface, #FFFFFF);
  border: 1px solid var(--ink-ghost, #D6D0C6);
  border-radius: 14px;
  box-shadow: 0 4px 10px rgba(31, 27, 22, 0.18);
  z-index: 6;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.12s, transform 0.12s;
}

slot-tile:hover .slot-tile__menu,
.slot-tile__menu:hover {
  opacity: 1;
  pointer-events: auto;
  /* Wave 18A round 3: menu no longer protrudes above the tile — it lives
     inside the padding-top reservation. The hover affordance is a subtle
     2px DOWNWARD nudge (the menu settles into place); no upward lift. */
  transform: translateX(-50%) translateY(2px);
}

/* Hover-buffer pseudo-element. The menu used to live ABOVE the tile
   (top: -14px), so this pseudo extended the hover hit-area upward.
   Now the menu lives INSIDE the tile's padding-top, so the buffer is no
   longer needed for hover continuity. The pseudo is kept at z-index: -1
   (Wave 18A round 3 / spec §7.7) so it can't intercept menu button
   clicks. The transparent strip is harmless — the rule could be deleted
   in a future cleanup pass once we confirm no surface relies on it. */
slot-tile::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 28px;
  pointer-events: none;
  z-index: -1;
  /* No visible styling — purely a hit-area extension. */
}

.slot-tile__menu-btn {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: var(--ink-muted, #7A7269);
  font-size: 12px;
  line-height: 22px;
  padding: 0;
  cursor: pointer;
  transition: background 0.12s, color 0.12s;
  font-family: var(--body, sans-serif);
}

.slot-tile__menu-btn:hover {
  background: var(--accent-tint, #FBF1E8);
  color: var(--accent-deep, #A85E3B);
}

.slot-tile__menu-delete:hover {
  background: rgba(201, 67, 74, 0.15);
  color: var(--err, #9B4B3F);
}

.slot-tile__menu-insert-l,
.slot-tile__menu-insert-r {
  font-family: var(--mono, monospace);
  font-weight: 700;
  color: var(--accent-deep, #A85E3B);
}

/* Surface-context sizing rules used to live here (`.storyboard-strip
   slot-tile`, `.summary-strip slot-tile`). Phase 2 moved sizing into
   `slot_grid.css` under `slot-grid[data-mode="..."]`. Per spec §5.4
   the scaffold/molecule layer owns container sizing, not the atom.
   The atom's intrinsic `width: 100%` lets the grid mode drive width. */

/* Canvas surface — the cv-slot-group wrapper around each slot-tile is
   now a pure positioning anchor for the React Flow Handle, not a card.
   Strip its background, border, padding so slot-tile owns the visual.
   Wave 18A round 3: switched from :has(slot-tile) to an explicit
   .has-slot-tile marker class (set in canvas.html). :has() works in
   modern browsers but isn't a stacking-context-friendly selector and
   was firing inconsistently across re-renders — the marker is the
   reliable signal. Same applies to is-current override below. */
.cv-slot-group.has-slot-tile {
  background: transparent !important;
  box-shadow: none !important;
  border-radius: 0;
  padding: 0;
  cursor: default;
}
.cv-slot-group.has-slot-tile.is-current {
  box-shadow: none !important;
}
.cv-slot-group.has-slot-tile.is-drop-target {
  outline: 2px dashed var(--accent-deep);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* Summary-strip rules removed in Phase 2: <slot-grid data-mode="summary">
   owns horizontal scroll + 28px top padding for the menu protrusion. */

/* ============================================================
 * Hover-play scrub bar — full CANONICAL rules, scoped under slot-tile.
 *
 * Per surface_architecture.md §5.1, hover-scrub rules used to live in
 * styles.css unscoped, AND in canvas.css with a different fill model
 * (width vs transform). The drift caused F1 (Canvas red fill never
 * appeared). Resolution: the canonical rules below own .hover-scrub*
 * inside <slot-tile>. canvas.css keeps a separate scoped copy for the
 * `.cv-slot-thumb` / `.cv-video-thumb` mini-thumb hover-play (which is
 * NOT a slot-tile — that's the Canvas `attachHoverPlay` function). And
 * styles.css keeps a separate scoped copy for `.cell-frame` contexts
 * (the legacy Detail-page non-slot-tile cells). Three scoped copies, no
 * unscoped duplicates. Each owns its scope.
 * ============================================================ */
slot-tile .hover-scrub {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  /* Outer band is tall (Wave 19A2 P5: 38px hit zone, up from 28) — the
     visible "bar" sits centered inside via the ::before pseudo. The big
     invisible band means the cursor stays "in" the scrub region even
     when it drifts a few px. */
  height: 38px;
  background: transparent;
  z-index: 3;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.12s ease;
}
slot-tile .hover-scrub::before {
  /* The visible track. Auto-sized inside the hit zone. */
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 8px;
  background: rgba(255, 255, 255, 0.72);
  transition: height 0.12s ease, background 0.12s ease;
  pointer-events: none;
}
slot-tile:hover .hover-scrub { opacity: 1; }
slot-tile .hover-scrub:hover::before,
slot-tile .hover-scrub.is-active::before {
  height: 13px;
  background: rgba(255, 255, 255, 0.92);
}
/* Wave 17 round 3: force opacity:1 while scrubbing. The :hover-driven
   opacity goes false the moment the cursor drifts off the thin bar —
   without this override the bar visibly fades during a horizontal drag. */
slot-tile .hover-scrub.is-active { opacity: 1 !important; }
slot-tile .hover-scrub-fill {
  /* Wave 17 round 5: scaleX transform (compositor-only, no layout) so
     cursor moves update the fill in the same frame. height transition
     stays for the hover grow-from-8-to-13px choreography. */
  position: absolute;
  left: 0; bottom: 0;
  height: 8px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left center;
  background: #D33B2C;
  transition: height 0.12s ease;
  pointer-events: none;
  will-change: transform;
}
slot-tile .hover-scrub:hover .hover-scrub-fill,
slot-tile .hover-scrub.is-active .hover-scrub-fill {
  height: 13px;
}
slot-tile .hover-scrub-knob {
  position: absolute;
  bottom: 6.5px;
  left: 0;
  transform: translate(-50%, 50%);
  /* Wave 19A2 P5: knob 20px -> 26px so it's easier to grab. */
  width: 26px; height: 26px;
  background: #D33B2C;
  border: 2.5px solid #FFF;
  border-radius: 50%;
  box-shadow: 0 1px 5px rgba(0,0,0,0.45);
  opacity: 0;
  transition: opacity 0.12s, transform 0.12s, bottom 0.12s;
  pointer-events: none;
}
/* Invisible 10px grab pseudo around the knob — extends the hit area
   without changing the visible knob size. Wave 19A2-FIX P5: pointer-
   events default to NONE so this 46x46 pseudo doesn't sit as a dead
   zone over the bottom-left of every slot tile when the scrub bar is
   hidden (which would partially undo Wave 19A2 P0's drag-engine fix).
   Only the active state (hover/is-active on the scrub bar) flips
   pointer-events to auto. */
slot-tile .hover-scrub-knob::after {
  content: '';
  position: absolute;
  inset: -10px;
  border-radius: 50%;
  pointer-events: none;
}
slot-tile .hover-scrub:hover .hover-scrub-knob::after,
slot-tile .hover-scrub.is-active .hover-scrub-knob::after {
  pointer-events: auto;
}
slot-tile .hover-scrub:hover .hover-scrub-knob,
slot-tile .hover-scrub.is-active .hover-scrub-knob {
  opacity: 1;
  pointer-events: auto;
  bottom: 4.5px;
}
slot-tile .hover-scrub-knob:hover {
  transform: translate(-50%, 50%) scale(1.2);
}

/* ============================================================
 * Drag-state placeholders (Wave 18B will populate). Documented here
 * so the contract is visible from Step 2: per _specs/slot_tile.md
 * §6 the engine applies transforms to slot-tile elements directly;
 * the CSS below sets the rules those transforms work under.
 *
 * - .slot-tile--is-dragging-source : the tile being moved (follows cursor)
 * - .slot-tile--is-drop-target     : sibling currently shifted by drag
 * - body.is-dragging-slot          : global drag state (suppress sibling hover-play
 *                                    via pointer-events: none on non-source tiles)
 * ============================================================ */
slot-tile.slot-tile--is-dragging-source {
  z-index: 10;
  cursor: grabbing;
  transition: transform 0.05s linear;
}

slot-tile.slot-tile--is-drop-target {
  transition: transform 0.18s ease-out;
}

body.is-dragging-slot slot-tile:not(.slot-tile--is-dragging-source) {
  pointer-events: none;
}
