/* ==========================================================================
   Catalogue Portal - interaction states
   Additive only. app.css is the approved design system and is kept
   byte-identical to design/assets/app.css; the static mockups have no error
   or flash states, so the few that a live application needs live here and are
   built from the same custom properties.
   ========================================================================== */

.alert {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  font-size: 13px;
  margin-bottom: 16px;
  border: 1px solid transparent;
}
.alert-danger { background: var(--danger-soft); color: var(--danger); border-color: #fecaca; }
.alert-ok     { background: var(--ok-soft);     color: var(--ok);     border-color: #a7f3d0; }
.alert-warn   { background: var(--warn-soft);   color: var(--warn);   border-color: #fde68a; }
.alert ul { margin: 0; padding-left: 16px; }
.alert p:last-child { margin-bottom: 0; }

.input.is-invalid,
.select.is-invalid,
textarea.input.is-invalid {
  border-color: var(--danger);
  background: var(--danger-soft);
}
.input.is-invalid:focus {
  border-color: var(--danger);
  box-shadow: 0 0 0 3px rgba(220, 38, 38, .12);
}

.field .error {
  display: block;
  margin-top: 5px;
  font-size: 12px;
  color: var(--danger);
}

/* The mockups draw the checkbox as a static span; a real form needs an input. */
.check-input { position: absolute; opacity: 0; width: 0; height: 0; }
.check-label { display: flex; align-items: center; gap: 9px; cursor: pointer; }
.check-input:focus-visible + .check { box-shadow: 0 0 0 3px rgba(37, 99, 235, .25); }
.check-input + .check svg { visibility: hidden; }
.check-input:checked + .check { background: var(--brand); border-color: var(--brand); color: #fff; }
.check-input:checked + .check svg { visibility: visible; }

/* ---------- brand logo ---------------------------------------------------
   The PCi Analytics wordmark is dark, multi-colour artwork on transparency,
   so it cannot be inverted to white and cannot sit directly on the navy
   sidebar or the login art panel. It gets a light plate on dark surfaces.
   ------------------------------------------------------------------------ */

.brand-logo {
  display: inline-grid;
  place-items: center;
  background: #fff;
  border-radius: var(--r-sm);
  padding: 7px 10px;
  flex: 0 0 auto;
  line-height: 0;
}
.brand-logo img {
  display: block;
  height: 26px;
  width: auto;
  max-width: 100%;
}

/* Sidebar: stack the plate above the product name - 244px is too narrow to
   sit a 184x70 wordmark beside text. */
.brand.brand-stacked {
  flex-direction: column;
  align-items: flex-start;
  gap: 11px;
}
.brand.brand-stacked .brand-logo { padding: 8px 11px; }
.brand.brand-stacked .brand-logo img { height: 28px; }

/* Login art panel: room to run horizontally. */
.auth-art .brand-logo { padding: 9px 13px; }
.auth-art .brand-logo img { height: 32px; }

/* Login form column is already white - no plate needed there. */
.auth-form .brand-logo { background: transparent; padding: 0; }

/* ---------- upload: employee picker + file rows --------------------------
   The mockup drew these with inline styles; they are lifted here verbatim so
   the markup stays clean and app.css stays byte-identical.
   ------------------------------------------------------------------------ */

.picker { border: 1px solid var(--line-2); border-radius: var(--r-sm); overflow: hidden; }
.picker-head {
  padding: 8px 10px;
  border-bottom: 1px solid var(--line);
  display: flex; align-items: center; gap: 9px;
  background: var(--surface-2);
}
.picker-head input {
  border: 0; outline: 0; background: transparent;
  font-size: 13.5px; font-family: inherit; flex: 1; min-width: 0;
}
.picker-list { max-height: 186px; overflow: auto; }
.picker-row {
  display: flex; align-items: center; gap: 11px;
  padding: 9px 12px;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
}
.picker-row:last-child { border-bottom: 0; }
.picker-row:hover { background: var(--surface-2); }
.picker-row[hidden] { display: none; }

.file-rows { border: 1px solid var(--line); border-radius: var(--r); margin-top: 16px; }
.upload-row .fmeta .input { height: 32px; font-weight: 600; }
.upload-row.is-error .ftype { background: var(--danger-soft); color: var(--danger); }

.dropzone.is-dragover { border-color: var(--brand); background: var(--brand-soft); }

/* ---------- print blocking ----------------------------------------------
   app.css already hides .viewer-shell when printing. This goes further: on a
   viewer page nothing renders at all, and a print-time notice replaces it, so
   "Print to PDF" cannot be used to lift a document out of the portal.
   Client-side only - see viewer-guard.js for the honest caveat.
   ------------------------------------------------------------------------ */

@media print {
  body.noselect > * { display: none !important; }

  body.noselect::after {
    content: "This document is view-only and cannot be printed. Every view is recorded against your account.";
    display: block;
    padding: 40px;
    font-family: var(--font);
    font-size: 14px;
    color: #000;
  }
}

html[data-printing="true"] .viewer-stage { visibility: hidden; }

/* ---------- switch -------------------------------------------------------
   app.css draws the switch as a static span pair, so the knob only ever sat
   in the "on" position and an .off class had to be painted server-side. In a
   real form the knob has to follow the checkbox the moment it is clicked, so
   the state is driven off :checked here and the .off class is only the
   first-paint hint. The input itself is offscreen but focusable, which is why
   the ring is drawn on the track instead.
   ------------------------------------------------------------------------ */

.switch { position: relative; }

.switch .check-input:checked ~ .track { background: var(--brand); }
.switch .check-input:checked ~ .track::after { left: 19.5px; }
.switch .check-input:not(:checked) ~ .track { background: var(--line-2); }
.switch .check-input:not(:checked) ~ .track::after { left: 2.5px; }
.switch .check-input:focus-visible ~ .track { box-shadow: 0 0 0 3px rgba(37, 99, 235, .25); }

/* One label per state - the wording has to change with the knob, or the row
   reads "Active" while the switch says otherwise. */
.switch .on-text, .switch .off-text { display: none; }
.switch .check-input:checked ~ .on-text { display: inline; }
.switch .check-input:not(:checked) ~ .off-text { display: inline; }

/* ---------- upload screen ------------------------------------------------
   The mockup draws the dropzone as a <div>. It has to be a <label> here so a
   click reaches the hidden file input - and a label is display:inline, which
   shatters the dashed border into fragments down the left edge. Making it a
   block puts the border back around the box.
   ------------------------------------------------------------------------ */

.dropzone { display: block; }

/* Two columns on a wide screen. The mockup used .content.narrow, which left
   most of the width empty once the sidebar was in place. */
.upload-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 16px;
  align-items: start;
}
.upload-grid > .card.mt-16 { margin-top: 0; }

/* The employee picker scrolls, so the left column can get tall - keep the
   dropzone and the Publish button in view while the admin scrolls it. */
.upload-grid > .card:last-child { position: sticky; top: 16px; }

@media (max-width: 1180px) {
  .upload-grid { grid-template-columns: minmax(0, 1fr); }
  .upload-grid > .card:last-child { position: static; }
}

/* ---------- password show / hide ----------------------------------------
   The wrapper is injected by password-toggle.js, so these rules only ever
   apply where the button actually exists.
   ------------------------------------------------------------------------ */

.pw-wrap { position: relative; display: block; }
.pw-wrap .input { padding-right: 40px; }

.pw-toggle {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
  width: 30px; height: 30px;
  display: grid; place-items: center;
  padding: 0;
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--faint);
  cursor: pointer;
  transition: color .15s, background .15s;
}
.pw-toggle:hover { color: var(--ink-2); background: var(--surface-2); }
.pw-toggle:focus-visible {
  outline: 0;
  color: var(--brand);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, .25);
}

/* ---------- build credit ------------------------------------------------- */

.built-by { margin-top: 6px; font-size: 12px; color: var(--faint); text-align: center; }
.built-by b { font-weight: 600; color: var(--muted); }

/* ---------- dashboard ----------------------------------------------------
   Three of the four stat cards are links through to the screen that owns the
   number. The mockup drew them as plain divs, so the anchor has to be talked
   back out of its default colour and underline.
   ------------------------------------------------------------------------ */

a.card.stat {
  display: block;
  color: inherit;
  text-decoration: none;
  transition: border-color .15s, box-shadow .15s, transform .15s;
}
a.card.stat:hover {
  border-color: var(--line-2);
  box-shadow: 0 2px 10px rgba(15, 23, 42, .06);
}
a.card.stat:focus-visible {
  outline: 0;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, .22);
}

/* ---------- employee password reset -------------------------------------- */

.pw-reset-form { display: flex; align-items: center; gap: 7px; justify-content: flex-end; }
.pw-reset-form .input-sm {
  width: 168px;
  padding: 6px 9px;
  font-size: 12.5px;
  border-radius: var(--r-sm);
}
.pw-reset-form .btn { white-space: nowrap; }

.pw-issued { display: flex; align-items: center; gap: 9px; margin: 6px 0 4px; }
.pw-issued code {
  font-size: 15px;
  font-weight: 650;
  letter-spacing: .04em;
  padding: 5px 11px;
  border-radius: var(--r-sm);
  background: var(--surface);
  border: 1px solid var(--line-2);
  user-select: all;
}

@media (max-width: 1100px) {
  .pw-reset-form { flex-wrap: wrap; }
  .pw-reset-form .input-sm { width: 130px; }
}

/* The switch is a <label> so that clicking it reaches the checkbox, and it
   sits directly inside .field - which means app.css's

       .field > label { display: block; font-size: 12.5px; font-weight: 600; }

   wins on specificity (0,1,1 against .switch's 0,1,0) and turns the flex row
   into a block. The track span then becomes an inline box, inline boxes ignore
   width and height, the 38x21 pill collapses to nothing, and the knob ends up
   painted over the label text. Restated here at (0,2,1) so the switch keeps
   the appearance app.css intends for it. */

.field > label.switch {
  display: inline-flex;
  font-size: 13.5px;
  font-weight: 400;
  color: inherit;
  margin-bottom: 0;
}

/* Made the switch read as a control rather than a sentence with a dot next to
   it. Without the frame it was not obvious there was anything to click. */

.field > label.switch {
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  transition: border-color .15s, background .15s;
}
.field > label.switch:hover {
  border-color: var(--brand);
  background: var(--brand-soft);
}
.field > label.switch b { font-weight: 650; }
