/* ── Drawer — siarheimardovich.com v2 (site-v-mimo-drawers) ── */
/* A right-to-left sliding panel that carries the heavy payload of a case: the live
   prototype, an interactive insertion, a large diagram, or a full-bleed illustration.
   The page keeps a lightweight screenshot placeholder; the drawer holds the real thing.

   Aesthetic contract, inherited from tokens.css and components.css:
   pitch-black ground, hairline rules, mono uppercase labels, emphasis by weight and rule
   rather than colour. Accent appears only on focus rings, matching base.css.

   Width is content-driven. Every trigger declares what its content needs via
   data-drawer-width, and drawer.js writes it to --drawer-w. Images that declare nothing
   are measured at their natural width and clamped to the viewport. */

/* ══ Trigger vocabulary ══════════════════════════════════════════════════ */
/* 4 trigger shapes so a drawer can be opened from wherever the argument needs it,
   without inventing a new control each time. */

/* Three labels, three promises, so a reader can tell from the chip what a click does:
     OPEN PROTOTYPE  the case's main working prototype, 1 per case
     OPEN TOOL       a distinct secondary instrument or interactive figure, live
     VIEW FULL SIZE  static artwork, or a view of a prototype opened elsewhere
   Only the last is a picture. The first 2 both load a running artifact. */

/* Shared: triggers are buttons, so they reset the UA button skin. */
.dt {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-align: left;
}

/* ── 1. Figure trigger — a screenshot placeholder that opens the real artifact ── */
.dt-figure {
  display: flex;
  align-items: center;
  width: 100%;
  position: relative;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--paper-2);
  /* Floor so the affordance chip always has somewhere to sit. Ordinary figures are
     far taller than this and are unaffected; an extreme panorama like the service
     blueprint (11955x374, about 32:1) would otherwise render a 40px sliver with the
     chip hanging outside its own trigger. */
  min-height: 116px;
}
.dt-figure img { display: block; width: 100%; }

/* The affordance rides on top of the shot: a mono label in a hairline chip.
   Always present (touch has no hover), and it firms up on hover and focus. */
.dt-figure-affordance {
  position: absolute;
  right: var(--space-12);
  bottom: var(--space-12);
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
  padding: var(--space-8) var(--space-12);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-2);
  background: rgba(0, 0, 0, 0.78);
  border: 1px solid var(--hairline-2);
  border-radius: var(--radius-sm);
  transition: color 160ms ease, border-color 160ms ease, background-color 160ms ease;
}
.dt-figure-affordance .dt-arrow {
  /* the glyph points the way the panel travels: in from the right */
  font-size: var(--text-xs);
  color: var(--ink-3);
  transition: transform 160ms ease, color 160ms ease;
}
.dt-figure:hover .dt-figure-affordance,
.dt-figure:focus-visible .dt-figure-affordance {
  color: var(--ink);
  border-color: var(--ink-3);
  background: rgba(0, 0, 0, 0.9);
}
.dt-figure:hover .dt-arrow { transform: translateX(-2px); color: var(--ink); }

/* A hairline brightens on the whole frame, so the target reads as one object. */
.dt-figure:hover, .dt-figure:focus-visible { border-color: var(--ink-3); }

/* ── 2. Inline trigger — opens an artifact from inside a sentence ── */
.dt-inline {
  display: inline;
  font-weight: var(--fw-semibold);
  border-bottom: 1px solid var(--ink-3);
  padding-bottom: 1px;
  transition: border-color 160ms ease;
}
.dt-inline::after {
  content: ' \2197'; /* north-east arrow, matches the outward move */
  font-family: var(--font-mono);
  font-size: 0.85em;
  color: var(--ink-3);
}
.dt-inline:hover { border-bottom-color: var(--ink); }
.dt-inline:hover::after { color: var(--ink); }

/* ── 3. Row trigger — an index of instruments, 1 line each ── */
.dt-rows { list-style: none; padding: 0; margin: 0; }
.dt-rows li { margin-top: 0; }
.dt-row {
  display: grid;
  grid-template-columns: 3rem minmax(0, 1fr) auto;
  align-items: baseline;
  gap: var(--space-16);
  width: 100%;
  padding-block: var(--space-16);
  border-top: 1px solid var(--hairline);
  transition: border-color 160ms ease;
}
.dt-rows li:last-child .dt-row { border-bottom: 1px solid var(--hairline); }
.dt-row-num {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--ink-3);
}
.dt-row-title { font-weight: var(--fw-medium); }
.dt-row-note {
  display: block;
  font-size: var(--text-sm);
  color: var(--ink-2);
  margin-top: var(--space-4);
  max-width: var(--measure);
}
.dt-row-open {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--ink-3);
  white-space: nowrap;
  transition: color 160ms ease;
}
.dt-row:hover { border-top-color: var(--ink-3); }
.dt-row:hover .dt-row-title { text-decoration: underline; text-underline-offset: 3px; }
.dt-row:hover .dt-row-open { color: var(--ink); }

/* ── 4. Button trigger — a standalone call to open ── */
.dt-button {
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
  padding: var(--space-12) var(--space-16);
  border: 1px solid var(--ink-3);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--ink);
  transition: background-color 160ms ease, border-color 160ms ease;
}
.dt-button:hover { background: var(--paper-2); border-color: var(--ink); }
.dt-button .dt-arrow { color: var(--ink-3); transition: transform 160ms ease; }
.dt-button:hover .dt-arrow { transform: translateX(-2px); color: var(--ink); }

/* ══ The drawer itself ═══════════════════════════════════════════════════ */

.drawer-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.72);
  opacity: 0;
  pointer-events: none;
  transition: opacity 240ms ease;
  z-index: var(--z-drawer-backdrop);
}
.drawer-backdrop[data-open='true'] { opacity: 1; pointer-events: auto; }

.drawer {
  position: fixed;
  inset-block: 0;
  right: 0;
  /* Content-driven: --drawer-w is written per drawer by drawer.js.
     It never exceeds the viewport, so the page body never scrolls sideways. */
  width: min(var(--drawer-w, var(--drawer-xl)), 100vw);
  max-width: 100vw;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border-left: 1px solid var(--hairline-2);
  transform: translateX(100%);
  transition: transform 280ms cubic-bezier(0.32, 0.72, 0, 1);
  z-index: var(--z-drawer);
  will-change: transform;
}
.drawer[data-open='true'] { transform: translateX(0); }

/* ── Drawer header ── */
.drawer-head {
  flex: none;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--space-16);
  padding: var(--space-20) var(--space-24);
  border-bottom: 1px solid var(--hairline);
  background: var(--paper-2);
}
.drawer-kind {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--ink-3);
  margin-bottom: var(--space-4);
}
.drawer-title {
  font-size: var(--text-lg);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--track-tight);
  line-height: var(--lh-heading);
}

.drawer-actions { display: flex; align-items: center; gap: var(--space-8); }

.drawer-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-8);
  height: 32px;
  padding-inline: var(--space-12);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--ink-2);
  background: none;
  border: 1px solid var(--hairline-2);
  border-radius: var(--radius-sm);
  cursor: pointer;
  white-space: nowrap;
  transition: color 160ms ease, border-color 160ms ease;
}
.drawer-action:hover { color: var(--ink); border-color: var(--ink-3); }

/* The close control keeps a square footprint so it reads as a control, not a word. */
.drawer-close { width: 32px; padding-inline: 0; font-size: var(--text-sm); }

/* ── Drawer body ── */
.drawer-body {
  position: relative;      /* anchors the loading overlay */
  flex: 1;
  min-height: 0;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--paper);
}

/* A prototype fills the panel. The body scrolls in both directions: vertically when
   the prototype is taller than the panel, horizontally when the panel is narrower
   than a dense workspace can honestly render. */
.drawer-body[data-fit='frame'] { overflow: auto; }
.drawer-body[data-fit='frame'] iframe {
  display: block;
  width: 100%;
  height: 100%;
  min-height: 100%;
  border: 0;
}
/* Only on real screens. Under 900px the panel is full-bleed and the prototype
   should reflow, not force a sideways drag across a phone. */
@media (min-width: 900px) {
  .drawer-body[data-fit='frame'] iframe { min-width: var(--drawer-frame-min); }
}

/* A diagram or illustration opens in a lightbox: contained in the panel by default,
   zoomable to 1:1 and beyond, pannable by drag. The body itself never scrolls here,
   because the viewport is the frame the artwork is read through. */
.drawer-body[data-fit='image'] {
  display: flex;
  flex-direction: column;
  padding: var(--space-24);
  overflow: hidden;
}
.drawer-body[data-fit='image'] .drawer-figure {
  margin: 0;
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  width: 100%;
  max-width: none;
}

/* The viewport. Centring both axes is what keeps a wide, short strip from reading as
   a broken panel with dead space under it.

   No border or ground of its own: a 32:1 blueprint in a full-height panel can never
   fill the frame, and drawing a box around the leftover space turns unavoidable
   emptiness into a container that looks broken. The rule goes on the artwork, so what
   is left over reads as panel rather than as an empty well. */
.drawer-view {
  flex: 1;
  min-height: 0;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  touch-action: none;
}
.drawer-view[data-pannable='true'] { cursor: grab; }
.drawer-view[data-dragging='true'] { cursor: grabbing; }

.drawer-img {
  display: block;
  width: auto;
  max-width: none;
  height: auto;
  transform-origin: center center;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  background: var(--paper-2);
  user-select: none;
  -webkit-user-drag: none;
}

.drawer-body[data-fit='image'] .drawer-note {
  flex: none;
  width: min(var(--measure), 100%);
}

/* ── Zoom controls ── */
.drawer-zoom {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin-right: var(--space-8);
}

/* The controls belong to artwork and must disappear for anything else. Setting the
   `hidden` property in JS is not enough on its own: the browser's `[hidden]`
   rule is a user-agent style, and the author `display: flex` above outranks it, so the
   controls stayed on screen over every prototype drawer while reporting themselves
   hidden. Restate it here, where it can win. */
.drawer-zoom[hidden] { display: none; }
.drawer-zoom-level {
  min-width: 4.5ch;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--track-label);
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
/* Square footprints, matching .drawer-close: these read as controls, not words. */
.drawer-zoom-step { width: 32px; padding-inline: 0; font-size: var(--text-sm); }
.drawer-zoom-word { font-variant-numeric: tabular-nums; }
.drawer-zoom .drawer-action[disabled] { opacity: 0.35; cursor: default; }
.drawer-zoom .drawer-action[aria-pressed='true'] { color: var(--ink); border-color: var(--hairline-2); }

/* Below 900px the panel is full-bleed and the header is competing for a phone's width
   against the title. The step buttons stay, because they are the control; the word
   buttons and the readout go, because the artwork already shows the result and a
   3-line wrapped title costs more than they are worth. */
@media (max-width: 899px) {
  .drawer-zoom-word,
  .drawer-zoom-level { display: none; }
}

.drawer-note {
  margin-top: var(--space-16);
  font-size: var(--text-sm);
  color: var(--ink-2);
  max-width: var(--measure);
}

/* ── Loading state — a mono tick, not a spinner ──
   An overlay, never a block in the flow. It used to be a sibling above the iframe with
   height 100%, which pushed the prototype a full panel-height down: the reader saw a
   black box saying "loading" and had to scroll to find the thing that had already
   loaded. Taking it out of the flow means the frame owns the panel from the first
   frame and the tick simply sits on top until the prototype paints. */
.drawer-loading {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  background: var(--paper);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--ink-3);
  pointer-events: none;
}

/* The failure notice reuses the tick's footprint but has to be reachable: its whole
   point is the way out to a tab. */
.drawer-failed {
  gap: 0.35em;
  pointer-events: auto;
}

.drawer-failed a {
  color: var(--ink-2);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.drawer-failed a:hover {
  color: var(--ink);
}

/* ── Footer: provenance line, mirrors .stack-note voice ── */
.drawer-foot {
  flex: none;
  padding: var(--space-12) var(--space-24);
  border-top: 1px solid var(--hairline);
  background: var(--paper-2);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--ink-3);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4) var(--space-16);
  align-items: center;
  justify-content: space-between;
}
.drawer-foot a { color: var(--ink-2); }
.drawer-foot a:hover { color: var(--ink); }

/* ── Grab rail: a 4px hairline handle hinting the panel edge is draggable-adjacent.
   Purely decorative on desktop; the swipe target on touch is the header. ── */
.drawer-rail {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 48px;
  border-radius: 999px;
  background: var(--hairline-2);
  pointer-events: none;
}

/* ── Focus sentinels — focusable, zero-size, never painted ── */
[data-drawer-sentinel] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
/* No focus ring: landing here is a transient bounce, not a stop. */
[data-drawer-sentinel]:focus,
[data-drawer-sentinel]:focus-visible { outline: none; }

/* ── Body scroll lock ── */
body[data-drawer-open='true'] { overflow: hidden; }

/* ── Responsive: below the medium breakpoint the panel takes the full width,
   because a 720px panel on a 390px phone is just a covered screen with a seam. ── */
@media (max-width: 899px) {
  .drawer { width: 100vw; border-left: 0; }
  .drawer-head { padding: var(--space-16); }
  .drawer-body[data-fit='image'] { padding: var(--space-16); }
  .drawer-foot { padding: var(--space-12) var(--space-16); }
  .dt-row { grid-template-columns: 2.5rem minmax(0, 1fr); }
  .dt-row-open { display: none; }
}

/* ── Motion: the drawer is the page's one orchestrated moment. Honour the opt-out. ── */
@media (prefers-reduced-motion: reduce) {
  .drawer { transition: none; }
  .drawer-backdrop { transition: none; }
}

/* ── Print: a drawer is screen furniture ── */
@media print {
  .drawer, .drawer-backdrop { display: none; }
  .dt-figure-affordance { display: none; }
}
