/* ============================================================
   report-dialog.css — The modal that gates the full report.

   A native <dialog> opened with showModal(), so the focus trap, the
   ::backdrop, Escape-to-close and the inertness of the page behind all
   come from the browser rather than from us. It also lands in the top
   layer, which paints above every stacking context regardless of
   z-index — which is why nothing here touches the --z-* scale even
   though the dialog has to clear the fixed header.

   The one thing the browser does NOT give us is a scroll lock; see
   html.has-modal at the bottom.

   Structure. The <dialog> itself is the full-viewport hit target that
   backdrop clicks are detected on, and is deliberately transparent and
   unpadded. Everything visible is .report-dialog__panel inside it.
   ============================================================ */

/* ── Sizing ─────────────────────────────────────────────────
   Two measured facts about the embedded form drive all of this.

   It is ONE COLUMN at every width a modal can plausibly be. Its fields
   are `flex: 0 1 50%` in a wrapping row with no media query, so they
   only pair once half the container clears their min-content width —
   which does not happen until well past 760px. Measured at 320, 560 and
   760px: ten fields, ten rows, every time. So a wider dialog does not
   buy a shorter form, it only buys a worse line length. 560px is the
   ceiling and there is no reason to exceed it.

   It is TALL — about 1,200px of content in one column. That is more
   than any viewport minus this dialog's own chrome, so the frame is
   going to scroll internally on essentially every device. Which makes
   HEIGHT the dimension worth being generous with: every pixel of panel
   height is a pixel of form the reader does not have to scroll to.

   Hence: width capped and gutter-driven, height as much of the viewport
   as the device can spare.
   ============================================================ */

.report-dialog {
  /* Horizontal breathing room, and the reason the width is written as a
     subtraction rather than a percentage. Zero on a phone: the form is
     built down to a 320px floor and no further, so on a 320px screen
     every pixel of gutter would push it under that floor. It only opens
     up once there is room to spare. */
  --rd-gutter: clamp(0px, calc((100vw - 320px) / 6), var(--space-5));
  /* Vertical, and independent: a landscape phone is wide enough for a
     side gutter while having no height at all to give away. Zero until
     480px tall, which is where a phone on its side stops needing every
     pixel. */
  --rd-gutter-y: clamp(0px, calc((100dvh - 480px) / 12), var(--space-5));
  --rd-max-w: 560px;
  /* Comfortably past a laptop's usable height, so on a large display the
     panel keeps growing instead of sitting in the middle of the screen
     at some arbitrary size. Below the form's ~1,200px content height on
     purpose — past that the panel would stop being a dialog. */
  --rd-max-h: 1000px;

  /* The UA stylesheet ships <dialog> with a border, padding, a
     background and max-width/max-height of calc(100% - 6px - 2em). All
     of it has to go. padding: 0 is load-bearing beyond looks: a click on
     dialog padding reports target === dialog, which is exactly how the
     backdrop click is detected in js/report-dialog.js, so padding here
     would make the dialog close on its own edge. */
  width: min(var(--rd-max-w), calc(100vw - 2 * var(--rd-gutter)));
  max-width: none;
  max-height: none;
  padding: 0;
  border: 0;
  background: none;
  overflow: visible;
  color: var(--text);
}

/* Both gutters interpolate rather than step, and that is a correctness
   choice, not a stylistic one. Stepping them made the dialog get SMALLER
   as the screen got bigger: crossing a 600px breakpoint added 24px of
   gutter to each side at once, so a 600px-tall window showed a 564px
   panel where a 599px one showed 599px. Growing the gutter continuously
   means every extra pixel of screen adds panel, never subtracts it.

   Both are also unitless divisions of a length, so they need no media
   query at all — which is why there are only two below, and both are
   about type and padding rather than size. */

.report-dialog::backdrop { background: var(--overlay-scrim); }

/* ── The visible panel ──────────────────────────────────────── */
.report-dialog__panel {
  display: flex;
  flex-direction: column;
  /* Eases in with the gutter: a full 24px radius on a full-bleed panel
     would cut the corners off the screen rather than round them. */
  border-radius: clamp(0px, calc((100vw - 320px) / 4), var(--radius-lg));
  border: 1px solid var(--line-strong);
  background: var(--surface-1);
  box-shadow: var(--shadow-pop);
  overflow: hidden;

  /* dvh, not vh: on iOS the collapsing URL bar sits INSIDE 100vh, so a
     panel sized to it puts the Submit button under browser chrome — the
     one control this dialog exists to reach. The vh line first, as the
     fallback for a browser that does not know dvh. */
  max-height: min(var(--rd-max-h), calc(100vh - 2 * var(--rd-gutter-y)));
  max-height: min(var(--rd-max-h), calc(100dvh - 2 * var(--rd-gutter-y)));
}


/* ── Heading strip ──────────────────────────────────────────── */
.report-dialog__head {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-4) var(--space-3);
}

.report-dialog__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 700;
  line-height: 1.35;
  color: var(--text);
}

/* 44px hit target on a 20px glyph. Focus is left to the global ring in
   base.css — no :focus rule here, on purpose. */
.report-dialog__close {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin: -10px -10px 0 0;
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.report-dialog__close:hover {
  color: var(--text);
  background: var(--hover-tint);
}

/* ── The embedded form ──────────────────────────────────────── */
.report-dialog__body {
  /* 0 1 auto, not 1 1 auto: the body takes the height it asks for and
     SHRINKS when the panel hits its cap — it never grows to fill. That
     is what lets the panel wrap a short form (the post-submit thank-you)
     instead of floating one in a tall box. min-height: 0 or the iframe
     refuses to shrink at all. */
  flex: 0 1 auto;
  min-height: 0;

  /* The zero-message height. The form answers a postMessage height probe,
     but only for a parent on its own origin allowlist — so on localhost,
     and on any preview host, this value is the whole layout and has to
     be right on its own.

     Viewport-relative rather than a flat number, because the form's
     ~1,200px of content exceeds every screen: the honest fallback is
     "as much as this device can show", not a fixed guess. The clamp
     keeps it sane at both ends — a landscape phone does not get a
     200px slot, a large monitor does not get a panel taller than the
     form itself. The panel's max-height still has the final say. */
  height: var(--report-form-h, clamp(240px, 82dvh, 900px));

  display: flex;
  /* The inlay margin interpolates alongside the gutters. A flat 18px
     here costs 36px of frame width, which at 320px would put the form
     under the width it is built for — so the inlay treatment fades in
     as the screen earns it. */
  margin: 0 clamp(0px, calc((100vw - 320px) / 8), var(--space-4));
  border: 1px solid var(--embed-paper-line);
  border-radius: var(--radius-md);
  background: var(--embed-paper);
  overflow: hidden;
}

/* The form is a cross-origin document with black label ink baked in and
   a transparent body — it is built to inherit a light host and cannot be
   restyled from here. So it is presented as a sheet of paper inset into
   the dialog: its own radius, its own hairline, themed surface all the
   way around it. On dark theme that reads as a document on a desk rather
   than as the dialog's lower half being the wrong colour. */
.report-dialog__frame {
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;
  display: block;
  border: 0;
  background: var(--embed-paper);
  /* Best effort at keeping the frame's UA-styled widgets — select
     popups, the scrollbar — light on a dark-mode OS. The frame declares
     no color-scheme of its own, and this is the only lever a parent has
     on a cross-origin document. */
  color-scheme: light;
}

/* The way out when a frame blocker eats the embed, and the "open in a
   new tab" affordance for anyone who wants the form on its own. */
.report-dialog__escape {
  flex: 0 0 auto;
  margin: 0;
  padding: var(--space-3) var(--space-4) var(--space-4);
  font-size: var(--text-sm);
  color: var(--muted);
}
.report-dialog__escape a { color: var(--primary-bright); }

/* ── Narrow viewports ──────────────────────────────────────
   Full-bleed below 400px, and the paper goes edge-to-edge with it.
   That last part is not cosmetic: the inset margin below costs 36px of
   frame width, which at a 320px viewport would hand the form 282px —
   under the 320px it is built to. The widest thing on the screen has to
   be the form, so at this size the inlay treatment is what gives way.

   This block sits AFTER the rules it overrides on purpose: a media
   query adds no specificity, so against the same single-class
   selectors it wins on source order and nothing else. */
/* The last four pixels. At full bleed the gutters and the inlay margin
   have already interpolated to zero, but two 1px side borders — the
   panel's and the paper's — still stand between the frame and 320px.
   On a 320px screen that is the difference between the form getting the
   width it was built for and not, so at this size the borders go too.
   Nothing is lost: a hairline drawn along the edge of the screen was
   never visible anyway. */
@media (max-width: 360px) {
  .report-dialog__panel {
    border-radius: 0;
    border-left: 0;
    border-right: 0;
  }
  .report-dialog__body {
    border-left: 0;
    border-right: 0;
    border-radius: 0;
  }
}

/* Four lines of heading on a 568px-tall phone is most of the screen.
   One step down the scale buys back a field and a half. */
@media (max-width: 399px) {
  .report-dialog__title { font-size: var(--text-md); }
}

/* ── Short viewports ────────────────────────────────────────
   A landscape phone is ~375px tall. Full-size chrome would leave the
   form barely two fields of room, so the heading, the close button and
   the escape line all give back what they can. Keyed to height alone,
   because this is about the axis that ran out — a short desktop window
   deserves the same treatment as a phone on its side. */
@media (max-height: 560px) {
  .report-dialog__head {
    padding: var(--space-3) var(--space-3) var(--space-2);
  }
  .report-dialog__title {
    font-size: var(--text-md);
    line-height: 1.3;
  }
  .report-dialog__close {
    width: 36px;
    height: 36px;
    margin: -6px -6px 0 0;
  }
  .report-dialog__body { margin: 0 var(--space-3); }
  .report-dialog__escape {
    padding: var(--space-2) var(--space-3) var(--space-3);
    font-size: var(--text-xs);
  }
}

/* ── Motion ─────────────────────────────────────────────────
   Open is CSS: showModal(), then .is-open on the next frame. Close is
   JS-timed, because dialog.close() is synchronous and would cut a
   fade-out off at the knees — see requestClose() in the module. */
.report-dialog {
  opacity: 0;
  transform: translateY(10px) scale(0.99);
}
.report-dialog::backdrop { opacity: 0; }
.report-dialog.is-open { opacity: 1; transform: none; }
.report-dialog.is-open::backdrop { opacity: 1; }

@media (prefers-reduced-motion: no-preference) {
  .report-dialog {
    transition: opacity var(--dur-fast) var(--ease-out),
                transform var(--dur-med) var(--ease-out);
  }
  .report-dialog::backdrop {
    transition: opacity var(--dur-fast) var(--ease-out);
  }
  /* Only measurements AFTER the first one animate. The first lands a
     beat after open, and a dialog that visibly grows on arrival reads
     as a bug rather than as a fit. */
  .report-dialog.can-animate-height .report-dialog__body {
    transition: height var(--dur-med) var(--ease-out);
  }
}

/* ── Scroll lock ────────────────────────────────────────────
   A native modal <dialog> makes the document inert but does NOT stop it
   scrolling, in any current browser. A JS-toggled class rather than
   :has(), matching how header-offset.js already writes state onto the
   root element. */
html.has-modal { overflow: hidden; }
