/* ==========================================================================
   Modal
   ========================================================================== */

/* Extra iOS defense-in-depth alongside the .view-scroll lock in
   layout.css: stops the document itself from rubber-band bouncing while
   a modal is open, in case a gesture reaches past the backdrop. */
html.modal-open,
html.drawer-open {
  overscroll-behavior: none;
}

.modal-backdrop {
  position: fixed;
  /* Plain inset:0 - no explicit height. The dialog is centered (not
     edge/bottom anchored - see the mobile override below), so the
     backdrop only needs to dim + block touch across the screen; it
     doesn't need to be pixel-precise against the real visible viewport
     the way an edge-anchored sheet would. That precision requirement is
     exactly what earlier attempts (100dvh, then a JS-measured
     window.visualViewport custom property) were fighting to satisfy -
     removed in favor of just not depending on it. */
  inset: 0;
  /* Dimmed only: glass belongs to the navigation layer, not to what sits over the page. */
  background: rgba(0, 0, 0, 0.4);
  z-index: var(--z-modal-backdrop);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-6);
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease-standard);
  /* Stops a touch-drag started on the dimmed background itself from
     panning/scrolling anything underneath (iOS routes an unhandled drag
     on a fixed overlay to the nearest scrollable ancestor otherwise).
     .modal below resets this so scrolling the dialog's own content still
     works normally. */
  touch-action: none;
}

.modal-backdrop.is-open {
  opacity: 1;
}

.modal {
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-radius: 28px;
  box-shadow: var(--shadow-xl);
  width: 100%;
  max-width: 520px;
  max-height: 88vh;
  display: flex;
  flex-direction: column;
  transform: translateY(8px);
  opacity: 0;
  transition: transform var(--dur-base) var(--ease-decel),
    opacity var(--dur-base) var(--ease-standard);
  z-index: var(--z-modal);
  touch-action: auto; /* re-enable normal touch scrolling within the dialog, undoing .modal-backdrop's touch-action:none */
}

/* A dialog that holds a list with a control per row (the RiskDeck import
   preview): between the 520px form and the wide trade form. */
.modal.modal--medium {
  max-width: 640px;
}

.modal-backdrop.is-open .modal {
  transform: none;
  opacity: 1;
}

.modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-6) var(--space-6) var(--space-4);
  border-bottom: 1px solid var(--color-border);
}

.modal__title {
  font-size: var(--fs-title3);
  font-weight: var(--fw-semibold);
}

.modal__body {
  padding: var(--space-6);
  min-width: 0;
  /* Both axes stated explicitly. Setting overflow-y alone does NOT leave
     overflow-x as `visible`: per the overflow spec, when one axis is not
     visible/clip the other computes to `auto`, which silently turned this
     panel into a horizontal scroller. The width fixes above are what stop
     content from overflowing in the first place; this declares the intent
     - vertical scrolling only - so no sub-pixel rounding can reintroduce
     a sideways drag on touch. */
  overflow-x: hidden;
  overflow-y: auto;
  /* Same reservation as .view-scroll (see css/layout.css): adding a partial
     exit row can push the dialog past its max height, and without a stable
     gutter every field inside it would shift sideways at that moment. */
  scrollbar-gutter: stable;
  /* Stops scrolling the dialog's own content from "chaining" into the
     background once it hits the top/bottom edge (iOS rubber-band scroll
     otherwise bleeds through to whatever's behind the modal). */
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

.modal__footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-6) var(--space-6);
}

/* A long form on a phone is a sheet rising from the bottom (Modal.open
   phoneFull; New Trade - the operator's decision 2026-10-16, item 20, v12
   "Telefon: New trade jako arkusz od dołu"): rounded top corners, a grab
   handle, a scrolling body, clear of the status bar above and the home
   indicator below. The sheet is as tall as the backdrop minus a strip of the
   page at the top; Cancel / title / Save sit in the head at its top, so
   Save is on screen whenever the sheet is. The backdrop is pinned to the
   VISIBLE viewport by Modal.open while a keyboard is up (visualViewport),
   which is what keeps that head from being scrolled away. Up to 880 px (the
   phone shell's own limit; look stage 2, audit point 41), rounded top 22px
   and a 36 x 5 handle; computers keep the panel at the right edge. */
.modal__grab {
  display: none;
}

@media (max-width: 880px) {
  .modal-backdrop.modal-backdrop--phone-full {
    padding: 0;
    align-items: flex-end;
    justify-content: stretch;
  }
  :root[data-look] .modal-backdrop--phone-full .modal {
    max-width: none;
    max-height: none;
    height: calc(100% - 44px - env(safe-area-inset-top));
    border: 0;
    border-radius: 22px 22px 0 0;
    background: var(--desk, var(--color-surface));
    box-shadow: 0 -20px 50px -10px rgba(0, 0, 0, 0.5);
    transform: translateY(100%);
    opacity: 1;
    transition: transform var(--dur-base) var(--ease-standard);
  }
  :root[data-look] .modal-backdrop--phone-full.is-open .modal {
    transform: none;
  }
  .modal-backdrop--phone-full .modal.is-dragging {
    transition: none;
  }
  .modal-backdrop--phone-full .modal__grab {
    display: block;
    flex: none;
    /* The visible bar is 5 px; the 44 px strip around it is the touch target. */
    height: 44px;
    margin-top: 0;
    padding: 20px 0 19px;
    touch-action: none;
    cursor: grab;
  }
  .modal-backdrop--phone-full .modal__grab::before {
    content: "";
    display: block;
    width: 36px;
    height: 5px;
    margin: 0 auto;
    border-radius: 999px;
    background: var(--tile-2, var(--color-border-strong));
  }
  .modal-backdrop--phone-full .modal__body {
    flex: 1;
    min-height: 0;
  }
}

@media (max-width: 880px) and (prefers-reduced-motion: reduce) {
  :root[data-look] .modal-backdrop--phone-full .modal {
    transition: none;
  }
}

/* "Discard your changes?" - shown instead of closing when a dirty form is
   dismissed by Escape / the X / the backdrop (Modal.open isDirty). */
.modal__discard {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  margin: 0 var(--space-6) var(--space-5);
  padding: var(--space-3) var(--space-4);
  border-radius: 12px;
  background: var(--color-warning-soft);
  border: 1px solid color-mix(in srgb, var(--warn) 35%, transparent);
}

.modal__discard-text {
  flex: 1 1 160px;
  font-size: var(--fs-footnote);
  font-weight: var(--fw-medium);
}

/* ---- Mobile: smaller, capped-height dialog ----
   Simplest stable fix: instead of trying to precisely anchor a full-bleed
   sheet to the real edge of the screen (which needs exact viewport
   math - 100dvh, then a JS-measured window.visualViewport var, both
   proved unreliable on real devices), the mobile dialog just stays the
   same *kind* of box as desktop - centered, all corners rounded, same
   scale+fade entrance - only smaller and margined so it comfortably
   fits with room to spare. Content taller than the cap scrolls inside
   .modal__body (overflow-y: auto, already set above); the dialog box
   itself never needs to know the exact pixel height of the viewport.
   Breakpoint matches the mobile shell's own (880px, see layout.css). */
@media (max-width: 880px) {
  .modal-backdrop {
    padding: var(--space-4);
  }

  .modal {
    max-width: 100%;
    max-height: 70vh;
    min-width: 0; /* without this, a flex item's implicit min-content width can win over max-width:100% and force the dialog wider than the viewport */
  }

  .modal__header {
    padding: var(--space-5) var(--space-5) var(--space-3);
  }

  .modal__body {
    padding: var(--space-4) var(--space-5);
  }

  .modal__footer {
    padding: var(--space-3) var(--space-5) calc(var(--space-5) + env(safe-area-inset-bottom));
  }
}


/* ==========================================================================
   v12 (REDESIGN-PLAN section 4 "Okna i komunikaty")
   Computer: a form or detail is a panel along the right edge, full height,
   sliding in a short way; the page stays visible to its left. A question
   before a rare, irreversible loss is a small centred alert: the title says
   what will happen, the button is the verb, Cancel always there.
   Phones keep the centred box above (the bottom-anchored sheet was
   unreliable on real iPhones - see the 880px block); the sheet with a grab
   handle waits for a test on the operator's iPhone.
   ========================================================================== */
@media (min-width: 881px) {
  .modal-backdrop--panel {
    justify-content: flex-end;
    align-items: stretch;
    padding: 12px;
    background: rgba(0, 0, 0, 0.32);
  }

  :root[data-look] .modal-backdrop--panel .modal {
    max-height: none;
    height: 100%;
    border-radius: 28px;
    background: var(--desk);
    border-color: var(--line);
    box-shadow: var(--shadow-lg);
    transform: translateX(24px);
  }

  :root[data-look] .modal-backdrop--panel.is-open .modal {
    transform: none;
  }

  .modal-backdrop--panel .modal__body {
    flex: 1;
  }
}

/* :root[data-look] outranks look-tapebook.css's ":root[data-look] .modal". */
:root[data-look] .modal.modal--alert {
  max-width: 360px;
  border-radius: 22px;
  background: var(--desk);
  text-align: center;
}

.modal--alert .modal__header {
  justify-content: center;
  border-bottom: 0;
  padding-bottom: var(--space-2);
}

.modal--alert [data-modal-close] {
  display: none;
}

.modal--alert .modal__body {
  padding-top: 0;
  padding-bottom: var(--space-4);
}

.modal--alert .modal__footer {
  justify-content: stretch;
}

.modal--alert .modal__footer > .btn {
  flex: 1;
}

@media (prefers-reduced-motion: reduce) {
  :root[data-look] .modal-backdrop--panel .modal {
    transform: none;
  }
}

/* The verb of an irreversible step: filled in the loss colour, its label
   in the page's own ink (white on the dark theme's pink-red is 2.9:1). */
.modal--alert .modal__footer > .btn--danger,
.modal--alert .modal__footer > .btn--danger:hover {
  background: var(--loss);
  border-color: transparent;
  color: var(--undo-fg);
}

.modal--alert .modal__footer > .btn--danger:hover {
  filter: brightness(1.08);
}

/* ==========================================================================
   The consent window before the first free-text note
   (js/components/notes-consent.js): its own layer above every dialog - the
   trade form's included, which must survive the question - and below the
   toasts. A centred box on every screen; the policy link under the buttons.
   ========================================================================== */
.modal-backdrop.nc-layer {
  z-index: calc(var(--z-dropdown) + 10);
}

:root[data-look] .nc-layer .modal.nc-dialog {
  max-width: 480px;
}

.nc-text {
  margin: 0 0 var(--space-4);
  font-size: var(--fs-footnote);
  line-height: 1.5;
  color: var(--color-text-secondary);
}

/* Two classes: outranks touch.css's centred .acct-check - a long sentence keeps its box at the first line. */
.nc-check.acct-check {
  align-items: flex-start;
  font-size: var(--fs-footnote);
  line-height: 1.5;
  color: var(--color-text-primary);
  cursor: pointer;
}

.nc-dialog .modal__footer {
  padding-bottom: var(--space-3);
}

.nc-foot {
  margin: 0;
  padding: 0 var(--space-6) var(--space-6);
  text-align: right;
  font-size: var(--fs-caption);
}

/* The withdrawal (Settings > Journaling): three verbs, one under the other. */
.modal--alert.nc-withdraw .modal__footer {
  flex-direction: column;
}

/* A locked free-text field (no consent yet) reads as text, not as a field waiting for typing. */
[data-free-text][readonly] {
  cursor: pointer;
}

@media (max-width: 880px) {
  .nc-foot {
    padding: 0 var(--space-5) calc(var(--space-5) + env(safe-area-inset-bottom));
  }
  .nc-dialog .modal__footer {
    padding-bottom: var(--space-3);
  }
}
