/* ===================================================================== modals
   Four dialogs and an acknowledgement. Each one is a point where somebody
   states something about a live railway — this earth is off the wire, this
   is the count in my hand, this earth is gone and here is why — so they are
   built to be read carefully rather than dismissed quickly.

   On a phone they are a sheet rising from the bottom edge, where a thumb
   already is. Past 560px they become a centred card, because a sheet stuck
   to the bottom of a laptop screen is just a strip.

   The state of a dialog is carried the same way as everywhere else in the
   app: green confirms, amber is the unverified path, red cannot be undone.
   -------------------------------------------------------------------- */

.modal-bg {
  position: fixed; inset: 0; z-index: 80;
  display: none; align-items: flex-end; justify-content: center;
  /* a tall sheet stops short of the status bar rather than sliding under it */
  padding: var(--sa-top) 0 0;
  /* A plain dark wash, not backdrop-filter. The blur put the backdrop on its
     own compositor layer and the sheet above it stopped being painted in
     some capture paths; a dialog that might not draw is not worth a blur on
     a phone that has to work at 3am beside a live railway. */
  background: rgba(3, 6, 4, .8);
}
.modal-bg.show { display: flex; animation: modal-bg-in .22s ease-out both; }
.modal-bg.closing { display: flex; animation: modal-bg-out .2s ease-in both; }

@keyframes modal-bg-in  { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-bg-out { from { opacity: 1; } to { opacity: 0; } }

.modal {
  position: relative;
  display: flex; flex-direction: column; gap: 16px;
  width: 100%; max-width: 480px;
  max-height: calc(92vh - var(--sa-top)); overflow-y: auto; overscroll-behavior: contain;
  padding: 10px 18px 20px;
  padding-bottom: calc(20px + var(--sa-bottom));
  border-radius: 24px 24px 0 0;
  color: #eef3ee;
  background:
    linear-gradient(170deg, rgba(255, 255, 255, .06), rgba(255, 255, 255, .018) 46%),
    #0b100d;
  border: 1px solid rgba(255, 255, 255, .13);
  border-bottom: 0;
  box-shadow: 0 -22px 60px rgba(0, 0, 0, .7);
}
.modal-bg.show .modal { animation: modal-in .3s cubic-bezier(.22, 1, .3, 1) both; }
.modal-bg.closing .modal { animation: modal-out .2s cubic-bezier(.4, 0, .8, .4) both; }

@keyframes modal-in  { from { transform: translateY(26px); } to { transform: none; } }
@keyframes modal-out { from { transform: none; } to { transform: translateY(26px); } }

/* the lit edge every surface in this app carries */
.modal::before {
  content: ""; position: absolute; top: -1px; left: 20%; right: 20%; height: 2px;
  border-radius: 2px; pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .5) 50%, transparent);
  opacity: .5;
}

/* the handle that says this sheet can be pushed back down */
.modal-grip {
  align-self: center; flex: 0 0 auto;
  width: 42px; height: 4px; border-radius: 999px;
  background: rgba(255, 255, 255, .22);
  margin-bottom: 2px;
}

/* ------------------------------------------------------------------ head */
.modal-head { display: flex; align-items: flex-start; gap: 13px; }
.modal-ico {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 46px; height: 46px; border-radius: 14px;
  background: rgba(255, 255, 255, .06);
  border: 1px solid rgba(255, 255, 255, .13);
  color: #c7d3c9;
}
.modal-ico svg { width: 23px; height: 23px; }
.modal-text { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.modal-text b {
  font-family: var(--font-display, inherit);
  font-size: 18px; font-weight: 800; letter-spacing: -.2px; line-height: 1.25;
  color: #fff; overflow-wrap: anywhere;
}
.modal-text i {
  font-style: normal; font-size: 13px; line-height: 1.5; color: #93a899;
}

.modal-body { display: flex; flex-direction: column; gap: 14px; }

/* ------------------------------------------------------------------ foot */
.modal-foot { display: flex; gap: 10px; }
.modal-foot .nf-submit { flex: 1 1 0; margin-top: 0; min-height: 56px; }
/* Cancel is deliberately the smaller half: on these dialogs the considered
   action is the one being confirmed, not the one backing out. */
.modal-foot .nf-submit.ghost { flex: 0 1 34%; }

/* --------------------------------------------------------------- states */
.modal-bg.ok .modal { border-color: rgba(47, 227, 106, .4); }
.modal-bg.ok .modal::before {
  background: linear-gradient(90deg, transparent, #6bffa0 50%, transparent);
  opacity: 1; box-shadow: 0 0 14px rgba(47, 227, 106, .7);
}
.modal-bg.ok .modal-ico {
  background: rgba(47, 227, 106, .15); border-color: rgba(47, 227, 106, .48); color: #6bffa0;
}

/* a typed serial is not proof the earth came off the wire */
.modal-bg.warn .modal { border-color: rgba(201, 135, 42, .5); }
.modal-bg.warn .modal::before {
  background: linear-gradient(90deg, transparent, #e8a84a 50%, transparent);
  opacity: 1; box-shadow: 0 0 14px rgba(201, 135, 42, .65);
}
.modal-bg.warn .modal-ico {
  background: rgba(201, 135, 42, .17); border-color: rgba(201, 135, 42, .55); color: #e8a84a;
}
.modal-bg.warn .nf-input:focus-within {
  border-color: rgba(201, 135, 42, .62);
  background: rgba(201, 135, 42, .06);
  box-shadow: 0 0 0 4px rgba(201, 135, 42, .1);
}
.modal-bg.warn .nf-input > svg { color: #e8a84a; }

/* permanent in the audit log, the register and the PDF */
.modal-bg.danger .modal {
  border-color: rgba(229, 67, 60, .55);
  background:
    linear-gradient(170deg, rgba(229, 67, 60, .14), rgba(229, 67, 60, .035) 48%),
    #120a09;
}
.modal-bg.danger .modal::before {
  background: linear-gradient(90deg, transparent, #ff8178 50%, transparent);
  opacity: 1; box-shadow: 0 0 14px rgba(229, 67, 60, .75);
}
.modal-bg.danger .modal-ico {
  background: rgba(229, 67, 60, .2); border-color: rgba(229, 67, 60, .55); color: #ff8178;
}
.modal-bg.danger .modal-text b { color: #ff8178; }
.modal-bg.danger .nf-input:focus-within {
  border-color: rgba(229, 67, 60, .62);
  background: rgba(229, 67, 60, .06);
  box-shadow: 0 0 0 4px rgba(229, 67, 60, .1);
}
.modal-bg.danger .nf-input > svg { color: #ff8178; }

/* ----------------------------------------------------------- the notice
   A line the dialog needs read before the button is pressed. */
.modal-note {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 13px 14px; border-radius: 15px;
  font-size: 13px; line-height: 1.5;
  background: rgba(255, 255, 255, .045);
  border: 1px solid rgba(255, 255, 255, .11);
  color: #c2d0c6;
}
.modal-note svg { width: 18px; height: 18px; flex: 0 0 auto; margin-top: 1px; color: #9fb3a6; }
.modal-note b { color: #eef3ee; font-weight: 700; }
.modal-note.ok {
  background: rgba(47, 227, 106, .11); border-color: rgba(47, 227, 106, .4); color: #cfeedb;
}
.modal-note.ok svg { color: #6bffa0; }
.modal-note.ok b { color: #9affc2; }
.modal-note.warn {
  background: rgba(201, 135, 42, .13); border-color: rgba(201, 135, 42, .45); color: #e4cfab;
}
.modal-note.warn svg, .modal-note.warn b { color: #e8a84a; }
.modal-note.danger {
  background: rgba(229, 67, 60, .14); border-color: rgba(229, 67, 60, .48); color: #f0cdca;
}
.modal-note.danger svg, .modal-note.danger b { color: #ff8178; }

/* ------------------------------------------------------------ the photo
   A native file input is an operating system control in the middle of a
   dialog about a live railway. This is a field like every other field, and
   it shows the photograph back so you can see you took the right one. */
.photo-pick {
  display: flex; align-items: center; gap: 13px;
  min-height: 66px; padding: 11px 13px;
  border-radius: 15px; cursor: pointer;
  background: rgba(255, 255, 255, .045);
  border: 1px dashed rgba(255, 255, 255, .2);
  transition: border-color .15s, background .15s;
}
.photo-pick:hover { background: rgba(255, 255, 255, .07); border-color: rgba(255, 255, 255, .34); }
.photo-pick input[type="file"] { display: none; }

.pp-ico {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 42px; height: 42px; border-radius: 13px;
  background: rgba(255, 255, 255, .07);
  border: 1px solid rgba(255, 255, 255, .13);
  color: #9fb3a6;
  overflow: hidden;
}
.pp-ico svg { width: 21px; height: 21px; }
.pp-ico img { width: 100%; height: 100%; object-fit: cover; }

.pp-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.pp-text b {
  font-size: 14px; font-weight: 700; line-height: 1.3; color: #eef3ee; overflow-wrap: anywhere;
}
.pp-text i { font-style: normal; font-size: 12px; line-height: 1.4; color: #8fa094; }

.photo-pick.has {
  border-style: solid;
  border-color: rgba(47, 227, 106, .5);
  background: rgba(47, 227, 106, .07);
}
.photo-pick.has .pp-ico { border-color: rgba(47, 227, 106, .5); }
.photo-pick.has .pp-text b { color: #9affc2; }

/* required and still empty, once they have tried to confirm */
.photo-pick.missing {
  border-color: rgba(229, 67, 60, .6);
  background: rgba(229, 67, 60, .08);
}
.photo-pick.missing .pp-ico {
  border-color: rgba(229, 67, 60, .5); background: rgba(229, 67, 60, .14); color: #ff8178;
}
.photo-pick.missing .pp-text b { color: #ff8178; }

/* ------------------------------------------------ the reason, as you type
   Force close and manual entry both demand a written reason. The field says
   how far off it is rather than letting the server refuse it afterwards. */
.nf-count {
  align-self: flex-end;
  font-size: 11.5px; font-weight: 600; letter-spacing: .3px;
  color: #74867b; font-variant-numeric: tabular-nums;
}
.nf-count.short { color: #e8a84a; }
.nf-count.ok { color: #6bffa0; }

/* -------------------------------------------------------------- the info
   Temporary PINs and order results: an acknowledgement, not a decision. */
#infoBody { font-size: 14px; line-height: 1.6; color: #c2d0c6; }
#infoBody b, #infoBody strong { color: #fff; }
#infoBody p { margin: 0 0 9px; }
#infoBody p:last-child { margin-bottom: 0; }
#infoBody .muted { color: #8fa094; font-size: 13px; }

/* a one-time PIN is read aloud off this screen — it gets its own line */
#infoBody .pin { display: block; width: fit-content; margin: 2px 0 12px; }
#infoBody code, #infoBody .pin {
  display: inline-block;
  font-family: var(--font-mono, monospace);
  font-size: 19px; font-weight: 700; letter-spacing: 2px;
  padding: 9px 15px; margin: 4px 0;
  border-radius: 12px;
  background: rgba(47, 227, 106, .13);
  border: 1px solid rgba(47, 227, 106, .42);
  color: #9affc2;
}

/* ------------------------------------------------------------- wide view */
@media (min-width: 560px) {
  .modal-bg {
    align-items: center;
    padding: calc(24px + var(--sa-top)) calc(24px + var(--sa-right))
             calc(24px + var(--sa-bottom)) calc(24px + var(--sa-left));
  }
  .modal {
    border-radius: 24px; border-bottom: 1px solid rgba(255, 255, 255, .13);
    max-height: 86vh;
    box-shadow: 0 26px 70px rgba(0, 0, 0, .72);
  }
  .modal-grip { display: none; }
  .modal-bg.show .modal { animation: modal-in-centre .3s cubic-bezier(.22, 1, .3, 1) both; }
  .modal-bg.closing .modal { animation: modal-out-centre .2s cubic-bezier(.4, 0, .8, .4) both; }
  @keyframes modal-in-centre  { from { transform: translateY(14px) scale(.97); } to { transform: none; } }
  @keyframes modal-out-centre { from { transform: none; } to { transform: translateY(10px) scale(.98); } }
}

@media (max-width: 400px) {
  .modal {
    padding: 10px 14px 17px; gap: 14px;
    padding-bottom: calc(17px + var(--sa-bottom));
  }
  .modal-ico { width: 42px; height: 42px; }
  .modal-text b { font-size: 16.5px; }
  .modal-foot { flex-wrap: wrap; }
  .modal-foot .nf-submit.ghost { flex: 0 1 32%; }
}

@media (prefers-reduced-motion: reduce) {
  .modal-bg.show, .modal-bg.closing,
  .modal-bg.show .modal, .modal-bg.closing .modal { animation: none; }
}

/* The unverified path does not get the green button. Pressing it records a
   return that carries no proof the earth came off the wire, and the control
   should say so rather than look like the confirmed one. */
.modal-bg.warn .modal-foot .nf-submit:not(.ghost) {
  color: #2a1a05;
  background: linear-gradient(100deg, #d99526, #f5c061 52%, #d99526);
}
.modal-bg.warn .modal-foot .nf-submit:not(.ghost) svg { color: #2a1a05; }
