/* components/upload-modal/upload-modal.css */
/* Upload modal with smooth fade animations - Mobile-first */

.upload-modal {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;

  /* Hidden by default */
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.upload-modal[data-state="open"] {
  opacity: 1;
  pointer-events: auto;
}

/* Overlay */
.upload-modal-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(4px);
}

/* Modal content */
.upload-modal-content {
  position: relative;
  background: white;
  border-radius: var(--radius-xl, 12px);
  max-width: 500px;
  width: 100%;
  max-height: 90vh;
  overflow-y: auto;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
  transform: scale(0.95);
  transition: transform 0.3s ease;
}

.upload-modal[data-state="open"] .upload-modal-content {
  transform: scale(1);
}

/* Header */
.upload-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.5rem;
  border-bottom: 1px solid var(--color-border, #E0E0E0);
}

.upload-modal-header h2 {
  margin: 0;
  font-size: 1.25rem;
  font-weight: 600;
  color: var(--color-text, #333);
}

.upload-modal-close {
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.5rem;
  border-radius: var(--radius-md, 6px);
  color: var(--color-text-light, #666);
  transition: all 0.2s;
}

.upload-modal-close:hover {
  background: var(--color-background, #F8F9FA);
  color: var(--color-text, #333);
}

/* Form */
#uploadForm {
  padding: 1.5rem;
}

/* Drop zone */
.upload-drop-zone {
  border: 3px dashed #4A90E2;
  border-radius: var(--radius-lg, 8px);
  padding: 2rem;
  margin: 0.75rem calc(1.5rem + 10px);
  text-align: center;
  transition: all 0.3s;
  cursor: pointer;
  position: relative;
}

.upload-drop-zone:hover {
  border-color: var(--color-blue, #4A90E2);
  background: var(--color-blue-light, #E3F2FD);
}

.upload-drop-zone.drag-over {
  border-color: var(--color-accent, #2ECC71);
  background: rgba(46, 204, 113, 0.1);
  transform: scale(1.02);
}

.drop-zone-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
}

.upload-icon {
  color: var(--color-text-light, #666);
}

.drop-zone-text {
  font-size: 1rem;
  font-weight: 500;
  color: var(--color-text, #333);
  margin: 0;
}

.drop-zone-subtext {
  font-size: 0.875rem;
  color: var(--color-text-light, #666);
  margin: 0;
}

.drop-zone-mobile-text {
  display: none;
  font-size: 0.92rem;
  font-weight: 500;
  color: var(--color-text, #333);
  margin: 0;
}

.drop-zone-hint {
  font-size: 0.78rem;
  color: var(--color-text-light, #888);
  margin: 0.15rem 0 0;
}

.upload-btn-row {
  display: flex;
  gap: 0.6rem;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 0.5rem;
}

.btn-take-photo {
  display: none;
  /* shown only on mobile via media query */
  /* Square icon button — height matches .btn-browse via same padding */
  padding: 0.6rem;
  width: 2.6rem;
  height: 2.6rem;
  flex-shrink: 0;
  background: var(--color-text-light, #666);
  color: white;
  border: none;
  border-radius: var(--radius-md, 6px);
  cursor: pointer;
  transition: background 0.2s;
  display: none;
  align-items: center;
  justify-content: center;
  line-height: 0;
}

.btn-take-photo:hover {
  background: #444;
}

.btn-browse {
  margin-top: 0.5rem;
  padding: 0.6rem 1.5rem;
  background: var(--color-blue, #4A90E2);
  color: white;
  border: none;
  border-radius: var(--radius-md, 6px);
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s;
}

.btn-browse:hover {
  background: #357ABD;
  transform: translateY(-1px);
}

@media (max-width: 767px) {
  .upload-drop-zone {
    border-style: solid;
    border-width: 1px;
    border-color: var(--color-border, #E0E0E0);
    background: #F8FAFD;
    padding: 0.85rem 1rem;
    margin: 0.5rem 0.75rem;
  }

  .upload-drop-zone.drag-over {
    transform: none;
  }

  .upload-icon,
  .drop-zone-subtext,
  .drop-zone-text {
    display: none;
  }

  .drop-zone-mobile-text {
    display: block;
  }

  .btn-browse {
    margin-top: 0;
    flex: 1 1 auto;
    max-width: 160px;
    padding: 0.65rem 0.75rem;
    font-size: 0.9rem;
  }

  .btn-take-photo {
    display: flex;
    flex-shrink: 0;
    width: 2.55rem;
    height: 2.55rem;
    padding: 0;
  }

  .drop-zone-hint {
    margin-top: 0.5rem;
  }
}

/* Very short screens (e.g. landscape phone) */
@media (max-width: 767px) and (max-height: 500px) {
  .upload-drop-zone {
    padding: 0.55rem 0.75rem;
    margin: 0.3rem 0.75rem;
  }

  .drop-zone-mobile-text {
    font-size: 0.85rem;
  }

  .btn-browse {
    padding: 0.5rem 0.6rem;
    font-size: 0.85rem;
  }

  .btn-take-photo {
    width: 2.3rem;
    height: 2.3rem;
  }
}

@media (min-width: 768px) {
  .drop-zone-mobile-text {
    display: none;
  }

  .btn-take-photo {
    display: none;
  }

  .upload-btn-row {
    margin-top: 0.5rem;
  }
}

/* Preview */
.upload-preview {
  position: relative;
}

.upload-preview img {
  width: 100%;
  height: auto;
  border-radius: var(--radius-lg, 8px);
}

.btn-remove-preview {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  background: rgba(0, 0, 0, 0.7);
  color: white;
  border: none;
  border-radius: 50%;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.2s;
}

.btn-remove-preview:hover {
  background: rgba(0, 0, 0, 0.9);
  transform: scale(1.1);
}

/* Details */
.upload-details {
  margin-top: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.form-group {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.form-group label {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--color-text, #333);
}

.form-group input,
.form-group textarea {
  padding: 0.75rem;
  border: 1px solid var(--color-border, #E0E0E0);
  border-radius: var(--radius-md, 6px);
  font-size: 0.95rem;
  font-family: inherit;
  transition: all 0.2s;
}

.form-group input:focus,
.form-group textarea:focus {
  outline: none;
  border-color: var(--color-blue, #4A90E2);
  box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
}

.form-group textarea {
  resize: vertical;
  min-height: 60px;
}

/* File info */
.file-info {
  display: flex;
  justify-content: space-between;
  font-size: 0.875rem;
  color: var(--color-text-light, #666);
  padding: 0.75rem;
  background: var(--color-background, #F8F9FA);
  border-radius: var(--radius-md, 6px);
}

/* Error */
.upload-error {
  padding: 0.75rem;
  background: #FEE;
  border: 1px solid #FCC;
  color: #C33;
  border-radius: var(--radius-md, 6px);
  font-size: 0.875rem;
  margin-top: 1rem;
}

/* Progress */
.upload-progress {
  margin-top: 1rem;
}

.progress-bar {
  height: 6px;
  background: var(--color-background, #F8F9FA);
  border-radius: 3px;
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background: var(--color-accent, #2ECC71);
  width: 0%;
  transition: width 0.3s ease;
}

.progress-text {
  display: block;
  text-align: center;
  margin-top: 0.5rem;
  font-size: 0.875rem;
  color: var(--color-text-light, #666);
}

/* File list */
.upload-file-list {
  list-style: none;
  margin: 1.5rem 0 0;
  padding: 0;
  max-height: 300px;
  overflow-y: auto;
}

/* Two-row grid: row 1 = thumbnail | details | [Resume/Retry] | X, row 2 = the
   error/status message under the text column (see .file-error-message). The
   message used to live inside .file-details, so it was squeezed into the narrow
   strip between the thumbnail and the buttons and wrapped into 3-4 lines.
   Spacing is margin-based, not gap-based: the Resume/Retry button only exists
   on failed rows, and an empty fourth column would still add a gap. */
.upload-file-item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  align-items: center;
  padding: 0.75rem;
  background: var(--color-background, #F8F9FA);
  border-radius: var(--radius-md, 6px);
  margin-bottom: 0.75rem;
}

.file-icon {
  width: 44px;
  height: 44px;
  margin-right: 0.6rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-blue, #4A90E2);
  color: white;
  border-radius: var(--radius-md, 6px);
  font-size: 0.8rem;
  font-weight: 700;
  flex-shrink: 0;
}

/* Real photo thumbnail, swapped in once its blob is available — replaces
   the extension-text square above rather than sitting alongside it.
   Falls back to the plain extension square (untouched) if no local blob
   exists for this attempt (different device, or blob already cleaned up). */
.file-icon--thumb {
  background: var(--color-background, #F8F9FA);
  padding: 0;
  overflow: hidden;
}

.file-icon--thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.file-details {
  min-width: 0;
  margin-right: 0.35rem;
}

.file-name {
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--color-text, #333);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 0.25rem;
}

.file-meta {
  display: grid;
  grid-template-columns: auto auto 1fr;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.75rem;
  color: var(--color-text-light, #666);
  margin-bottom: 0.35rem;
}

/* auto-sized, not 1fr — this must never be the column that gives up space
   under pressure. A byte count silently losing digits to an ellipsis is
   worse than a status word getting a bit tight on the right.
   grid-row/column pinned explicitly on all three items below (not just
   .file-status--wide) so nothing is left to auto-placement: an
   explicitly-positioned item (.file-status--wide claiming columns 2-3)
   resolves before auto-placed ones, so an unpinned, empty .file-percent
   would find its "natural" column already taken and get silently bumped
   into a brand-new implicit row instead — invisible content, but a very
   visible empty line, which is exactly the bug this pin prevents. */
.file-size {
  grid-column: 1;
  grid-row: 1;
  text-align: left;
  white-space: nowrap;
}

.file-percent {
  grid-column: 2;
  grid-row: 1;
  text-align: center;
  color: var(--color-accent, #2ECC71);
  font-weight: 600;
  white-space: nowrap;
}

.file-status {
  grid-column: 3;
  grid-row: 1;
  text-align: right;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Once bytes are fully sent (processing), a percentage has nothing
   meaningful left to say — it would just be a static "100%" forever. That
   center column is reclaimed by the status label itself, which still
   right-aligns but now within the doubled space; text-overflow above
   truncates it with an ellipsis ("Processing f…") if it still doesn't fit. */
.file-status--wide {
  grid-column: 2 / 4;
  grid-row: 1;
}

.file-progress-bar {
  height: 4px;
  background: var(--color-border, #E0E0E0);
  border-radius: 2px;
  overflow: hidden;
}

.file-progress {
  height: 100%;
  background: var(--color-accent, #2ECC71);
  transition: width 0.3s ease;
}

/* "Processing file..." — the dots are a real ::after so they stay in the
   layout (no width jitter); clip-path reveals them one at a time. */
.file-status--processing::after {
  content: "...";
}

@media (prefers-reduced-motion: no-preference) {
  .file-status--processing {
    animation: upload-processing-flash 1.1s ease-in-out infinite;
  }
}

@keyframes upload-processing-flash {

  0%,
  100% {
    opacity: 1;
  }

  50% {
    opacity: 0.25;
  }
}

.file-cancel {
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.35rem;
  color: var(--color-text-light, #666);
  border-radius: var(--radius-md, 6px);
  transition: all 0.2s;
  flex-shrink: 0;
}

.file-cancel[hidden],
.file-done-icon[hidden] {
  display: none;
}

.file-done-icon {
  display: flex;
  align-items: center;
  padding: 0.5rem;
  flex-shrink: 0;
  color: var(--color-success, #2ecc71);
}

.file-cancel:hover {
  background: rgba(0, 0, 0, 0.05);
  color: var(--color-text, #333);
}

/* Error/status explanation — its own row below the progress bar, separate
   from the compact .file-meta line (filename size + short status word).
   Color is set inline per failureReason (offline/retrying/server), so no
   color rule here — this only owns typography and spacing. */
.file-error-message {
  grid-column: 2 / -1;
  grid-row: 2;
  align-self: start;
  font-size: 0.75rem;
  line-height: 1.4;
  margin-top: 0.4rem;
  overflow-wrap: break-word;
}

.file-error-message.is-hidden {
  display: none;
}

.file-retry {
  margin-right: 0.1rem;
  border: none;
  border-radius: var(--radius-md, 6px);
  padding: 0.3rem 0.6rem;
  font-size: 0.8125rem;
  font-weight: 600;
  cursor: pointer;
  transition: opacity 0.2s, background 0.2s;
}

/* Resume — continuing a network-shaped failure (offline, or an exhausted
   auto-retry). Same green fill as before; this is a positive, low-stakes
   action since tus-js-client already has everything needed to continue. */
.file-retry--resume {
  background: var(--color-accent, #2ECC71);
  color: #fff;
}

.file-retry--resume:hover {
  opacity: 0.85;
}

/* Retry — a definitive server rejection (quota, bad file). A green fill
   here reads as mismatched on what's actually a failure state, so this
   gets an outlined red treatment instead of the success-green fill. */
.file-retry--retry {
  background: #fff;
  color: #E74C3C;
  border: 1.5px solid #E74C3C;
}

.file-retry--retry:hover {
  background: #FEF3F2;
}

/* Narrow phones: the size/percent line is nowrap and must never run under the
   Resume/Retry button, so give the details column more room by trimming the
   thumbnail, button padding and meta text rather than letting them collide. */
@media (max-width: 400px) {
  .upload-file-item {
    padding: 0.6rem;
  }

  .file-icon {
    width: 36px;
    height: 36px;
    margin-right: 0.5rem;
    font-size: 0.7rem;
  }

  .file-meta {
    gap: 0.35rem;
    font-size: 0.7rem;
  }

  .file-retry {
    padding: 0.28rem 0.5rem;
    font-size: 0.75rem;
  }

  .file-cancel {
    padding: 0.25rem;
  }
}

/* Upload status */
.upload-files-status {
  text-align: center;
  font-size: 0.875rem;
  color: var(--color-text-light, #666);
  margin-top: 1rem;
  padding: 0.75rem;
  background: var(--color-background, #F8F9FA);
  border-radius: var(--radius-md, 6px);
}

/* Actions */
.upload-actions {
  display: flex;
  gap: 0.75rem;
  margin-top: 1.5rem;
}

.btn-cancel {
  flex: 1;
  padding: 0.75rem;
  background: white;
  border: 1px solid var(--color-border, #E0E0E0);
  border-radius: var(--radius-md, 6px);
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s;
}

.btn-cancel:hover {
  background: var(--color-background, #F8F9FA);
}

.btn-upload {
  flex: 2;
  padding: 0.75rem;
  background: var(--color-accent, #2ECC71);
  color: white;
  border: none;
  border-radius: var(--radius-md, 6px);
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s;
}

.btn-upload:hover:not(:disabled) {
  background: var(--color-accent-dark, #27AE60);
  transform: translateY(-1px);
}

.btn-upload:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Mobile adjustments */
@media screen and (max-width: 640px) {
  .upload-modal-content {
    max-height: 95vh;
  }

  .upload-drop-zone {
    padding: 1.5rem;
  }

  #uploadForm {
    padding: 1rem;
  }
}

/* =============================================================
   ADD these rules to the bottom of:
   /components/upload-modal/upload-modal.css

   Quota display — shown below the modal header.
   Quota error — shown above the file list when limit is hit.
   ============================================================= */

/* ── Quota status display (below header) ──────────────────── */
.upload-quota-display {
  padding: 0.5rem 1.5rem;
  font-size: 0.85rem;
  text-align: right;
  min-height: 1.5rem;
  /* reserve space so layout doesn't jump on load */
  border-bottom: 1px solid var(--color-border, #E0E0E0);
}

.upload-quota__text {
  font-weight: 500;
}

/* ── Quota error banner (above file list when limit hit) ───── */
.upload-quota-error {
  margin: 1rem 0 0;
  padding: 0.75rem 1rem;
  background: #FEF3F2;
  border: 1px solid #FECACA;
  border-radius: var(--radius-md, 6px);
  color: #B91C1C;
  font-size: 0.875rem;
  font-weight: 500;
  text-align: center;
}

/* =============================================================
   APPEND to: components/upload-modal/upload-modal.css
   
   Quota display, quota error banner, and disabled drop zone state.
   ============================================================= */

/* ── Quota status row (below modal header) ────────────────────
   Reserves min-height so the layout doesn't jump when JS
   populates it after the fetch completes.
   ──────────────────────────────────────────────────────────── */
.upload-quota-display {
  padding: 0.4rem 1.5rem;
  font-size: 0.82rem;
  text-align: right;
  min-height: 1.6rem;
  border-bottom: 1px solid var(--color-border, #E0E0E0);
}

.upload-quota__text {
  font-weight: 500;
}

/* ── Quota error banner (above file list when limit is hit) ───
   Styled as a soft red alert to be noticeable but not alarming.
   ──────────────────────────────────────────────────────────── */
.upload-quota-error {
  margin: 1rem 0 0;
  padding: 0.75rem 1rem;
  background: #FEF3F2;
  border: 1px solid #FECACA;
  border-radius: var(--radius-md, 6px);
  color: #B91C1C;
  font-size: 0.875rem;
  font-weight: 500;
  text-align: center;
}

/* ── Disabled drop zone (quota reached) ───────────────────────
   Visually muted so the user understands uploads are blocked.
   Pointer events still fire so we can silently ignore drops
   in JS rather than letting the browser handle them oddly.
   ──────────────────────────────────────────────────────────── */
.upload-drop-zone.is-disabled {
  opacity: 0.45;
  cursor: not-allowed;
  border-color: var(--color-border, #E0E0E0);
  background: #FAFAFA;
}

/* Prevent hover styles activating on a disabled drop zone */
.upload-drop-zone.is-disabled:hover {
  border-color: var(--color-border, #E0E0E0);
  background: #FAFAFA;
  transform: none;
}

/* Browse button inherits disabled opacity from drop zone,
   but we also set pointer-events to reinforce non-interactivity */
.upload-drop-zone.is-disabled .btn-browse {
  pointer-events: none;
}

/* ── Permission consent row ───────────────────────────────────
   Sits between the quota bar and the drop zone.
   The checkbox uses a custom styled indicator to keep it legible
   on both light and dark themes and easy to tap on mobile.
   ──────────────────────────────────────────────────────────── */
.upload-consent {
  padding: 0.75rem 1.5rem 0;
}

.upload-consent__label {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  cursor: pointer;
  user-select: none;
}

/* Native checkbox: accessible but visually hidden — indicator span does the rendering */
.upload-consent__checkbox {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
  pointer-events: none;
}

/* Custom visual indicator — sized and styled independently of browser UA */
.upload-consent__indicator {
  flex-shrink: 0;
  display: inline-block;
  width: 1.175rem;
  height: 1.175rem;
  margin-top: 0.15rem;
  border: 1.5px solid var(--color-border, #CCC);
  border-radius: 3px;
  background: #fff;
  transition: border-color 0.15s, background 0.15s;
  position: relative;
}

/* Checked state: driven by the hidden sibling checkbox */
.upload-consent__checkbox:checked+.upload-consent__indicator {
  background: var(--color-accent, #2ECC71);
  border-color: var(--color-accent, #2ECC71);
}

/* Checkmark tick — centred in the 1.175rem box. box-sizing is explicit so
   the nudge below is exact: a 5px-wide tick rotated 45deg has its visual
   centre 0.354 * 5px = ~1.8px below the element's own centre, so it is
   lifted by that amount after being centred. Change the width and this
   nudge must change with it. */
.upload-consent__checkbox:checked+.upload-consent__indicator::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  box-sizing: border-box;
  width: 5px;
  height: 10px;
  border: solid #fff;
  border-width: 0 2px 2px 0;
  transform: translate(-50%, -50%) translateY(-1.8px) rotate(45deg);
}

/* Focus ring on the indicator when the hidden checkbox is focused */
.upload-consent__checkbox:focus-visible+.upload-consent__indicator {
  outline: 2px solid var(--color-blue, #4A90E2);
  outline-offset: 2px;
}

.upload-consent__text {
  font-size: 0.875rem;
  color: var(--color-text, #333);
  line-height: 1.4;
}

/* ── Quota banner: offline variant ────────────────────────────
   Same banner element as the red quota error, but amber: being
   offline is a pause, not a failure. Matches the amber used for
   the "Paused" row status. Declared last so it wins over the
   base .upload-quota-error rules (equal specificity).
   ──────────────────────────────────────────────────────────── */
.upload-quota-error--offline {
  background: #FFFBEB;
  border-color: #FDE68A;
  color: #92400E;
}
