/* drop.css — The empty-state drop zone and the stage error cards.
   Cascade position 10 of 18. Order is load-bearing and is asserted by
   verify-fixtures.mjs; index.html links these explicitly (never @import) because Caddy's
   try_files turns a missing file into a 200 text/html SPA shell.
   Owner after Step 1: section (e).

   Items 50, 69, 76, 78, 79, 137. REFERENCE-STUDY §13 (Craftcloud, Tripo) supplies the
   anatomy — dashed edge, icon, headline, a sub-label carrying the constraint, a REAL
   button inside the zone, 120ms dragover and nothing moving — and DESIGN-SPEC §5.1/§4.7
   supplies the size, because §13's boxes sit inside a normal page and ours sits alone in
   a stage that measured 94% empty.

   `dashed` appears exactly once in this file, on .drop__target. It is the signal that
   this is a drop target, not decoration; nothing else in section (e) may use it. */

/* ══ The empty-state card (items 50, 79, 137) ══════════════════════════════════════
   `inset: 0` + `margin: auto` with an explicit width and height centres the card on
   both axes without a transform, so the shared `:active { transform: translateY(1px) }`
   press in css/base.css is still the only transform this element ever carries. */
.drop {
  position: absolute; inset: 0; margin: auto; z-index: 4;
  width: min(960px, 90vw);
  /* DESIGN-SPEC §5.1 sizes the card against a stage that is the WHOLE pane, which it
     only becomes once section (o) consumes `body.is-empty`. Until that merges the rail
     is still drawn, so at 1280 the stage measures 870.4px and a flat 960px card would
     hang 89.6px over its edge. This clamp bites only while that is true. */
  max-width: calc(100% - var(--sn-space-5) * 2);
  height: min(560px, calc(100% - var(--sn-space-7)));
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--sn-space-6);
  padding: var(--sn-space-6);
  border-radius: var(--sn-radius-md);
  background: var(--sn-surface-1);
  box-shadow: inset 0 0 0 1px var(--sn-line);
  text-align: left;
  cursor: pointer;
}

/* The left column is the target itself: the ONE dashed edge in section (e). It carries
   no box-shadow, so it never has a border and a spread ring at once
   (REFERENCE-STUDY §18, "elevation is one property"). */
.drop__target {
  display: grid; align-content: center; justify-items: center; gap: var(--sn-space-3);
  padding: var(--sn-space-5);
  border: 2px dashed var(--sn-line-strong);
  border-radius: var(--sn-radius-md);
  background: var(--sn-surface-2);
  text-align: center;
  transition: border-color var(--sn-dur-fast) var(--sn-ease-out),
              background-color var(--sn-dur-fast) var(--sn-ease-out);
}
.drop__ring {
  width: 72px; height: 72px; border-radius: var(--sn-radius-md);
  display: grid; place-items: center;
  background: var(--sn-surface-1);
  box-shadow: inset 0 0 0 1px var(--sn-line-strong);
}
.drop__ring svg { width: 32px; height: 32px; stroke: var(--sn-accent); }
.drop__title { font-size: var(--sn-text-lg); line-height: var(--sn-lh-lg); text-wrap: pretty; }
.drop__lede {
  font-size: var(--sn-text-sm); line-height: var(--sn-lh-sm);
  color: var(--sn-ink-dim); max-width: 34ch; text-wrap: pretty;
}
/* §13: the constraint lives in the sub-label, one size down and muted. `--sn-ink-mute`
   is 5.71:1 on this fill — item 75's replacement for the 3.99:1 grey. */
.drop__limits {
  font-size: var(--sn-text-xs); line-height: var(--sn-lh-xs); color: var(--sn-ink-mute);
}

/* The right column answers "what am I about to get", which is what the 94%-empty plane
   was failing to say. It is what takes the content bounding box past 25% of the stage. */
.drop__aside {
  display: grid; align-content: center; gap: var(--sn-space-5);
  padding-right: var(--sn-space-2);
}
.drop__aside-title {
  font-size: var(--sn-text-md); line-height: var(--sn-lh-md); color: var(--sn-ink);
}
.drop__steps {
  display: grid; gap: var(--sn-space-2);
  margin: 0; padding-left: var(--sn-space-4);
  font-size: var(--sn-text-sm); line-height: var(--sn-lh-sm); color: var(--sn-ink-soft);
}
.drop__steps::marker, .drop__steps li::marker { color: var(--sn-accent); font-weight: 700; }
.drop__spec {
  display: grid; gap: var(--sn-space-2);
  font-size: var(--sn-text-xs); line-height: var(--sn-lh-xs);
  padding-top: var(--sn-space-4);
  border-top: 1px solid var(--sn-line);
}
.drop__spec > div { display: grid; grid-template-columns: 84px minmax(0, 1fr); gap: var(--sn-space-3); }
.drop__spec dt { color: var(--sn-ink-mute); }
.drop__spec dd { margin: 0; color: var(--sn-ink-soft); }

/* ── dragover: colour only, over 120ms, and nothing moves (§13) ───────────────────
   The shipped rule scaled .drop__ring by 1.08, which is exactly the "something else
   moved" §13 rules out and the transform REFERENCE-STUDY §18 bans. */
.stage.dragging .drop__target {
  border-color: var(--sn-accent);
  background: var(--sn-accent-tint);
}
/* UI Quiet: the viewer lane's veil (js/viewport-ui.js, `.vp-veil`) is the one drag
   surface now — DESIGN §4.1, a full-viewport accent tint with a 2 px inset edge — so the
   old inset ring that stood here would draw a second edge 12 px inside it. */

/* ── a model is loaded (item 79) ──────────────────────────────────────────────────
   The card goes, the heading stays. `.drop.hide` becomes a visually-hidden box that
   carries nothing but the <h1>; js/intake.js rewrites that heading to name the file and
   drops the card's tabindex/role, so the page keeps exactly one <h1> in every state and
   gains no phantom tab stop. This is deliberately NOT `display: none`: hiding the card
   that way is what left the loaded page with no <h1> at all. */
.drop.hide, .drop.is-superseded {
  inset: auto auto 0 0; margin: 0;
  width: 1px; height: 1px; padding: 0; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
  background: none; box-shadow: none; cursor: default;
}
.drop:is(.hide, .is-superseded) > :not(.drop__target) { display: none; }
.drop:is(.hide, .is-superseded) .drop__target { display: contents; }
.drop:is(.hide, .is-superseded) .drop__target > :not(.drop__title) { display: none; }
.drop:is(.hide, .is-superseded) .drop__title { font-size: var(--sn-text-sm); }
/* UI Quiet (DESIGN §4.1): `.is-superseded` is the empty state while the viewer lane's
   card sits on the bed. The old card collapses exactly as it does for a loaded model,
   keeping only its <h1>; js/intake.js removes its role and tabindex at the same moment. */

/* ══ The stage error card (items 69, 78, 135's surface) ════════════════════════════
   Item 69 measured 979 x 844 px of black with `innerText === ''` while three different
   messages described the one problem somewhere else. This card is the ONE surviving
   guard: a glyph, one sentence naming the file and the accepted format, and the way
   out. It sits above the intake veil (`.busy`, z-index 6) because the veil is what was
   showing when the stage went blank.

   `hidden` is left to the single authoritative `[hidden] { display: none !important }`
   in css/base.css (item 91) — there is no competing display rule here. */
.stage__error {
  position: absolute; inset: 0; margin: auto; z-index: 7;
  width: min(560px, 90vw); height: max-content;
  max-height: calc(100% - var(--sn-space-7));
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: var(--sn-space-3);
  align-items: start;
  padding: var(--sn-space-5);
  border-radius: var(--sn-radius-md);
  background: var(--sn-surface-1);
  box-shadow: inset 0 0 0 1px var(--sn-bad-edge), var(--sn-shadow-raised);
  overflow: auto; overscroll-behavior: contain;
}
.stage__error-glyph {
  width: 32px; height: 32px; border-radius: var(--sn-radius-sm);
  display: grid; place-items: center;
  background: var(--sn-bad-tint); color: var(--sn-bad);
}
.stage__error-glyph svg { width: 18px; height: 18px; }
.stage__error-body {
  font-size: var(--sn-text-sm); line-height: var(--sn-lh-sm);
  color: var(--sn-bad-ink); text-wrap: pretty;
}
.stage__error-body b { color: var(--sn-bad-title); font-weight: 600; }
.stage__error-actions {
  grid-column: 2; display: flex; flex-wrap: wrap; gap: var(--sn-space-2);
}

/* ── narrow: one column, and the card gives up its fixed height ──────────────────
   Section (o) owns the shell; this only stops section (e)'s own two columns from
   surviving into a 390px viewport. */
@media (max-width: 940px) {
  .drop {
    grid-template-columns: minmax(0, 1fr);
    height: max-content; max-height: calc(100% - var(--sn-space-5));
    gap: var(--sn-space-5); padding: var(--sn-space-5);
    overflow: auto; overscroll-behavior: contain;
  }
  .drop__aside { gap: var(--sn-space-3); }
  .stage__error { padding: var(--sn-space-4); }
}
