/* ============================================================
   Shared component layer for manage.
   Loaded by header.php after the base sheets, so it can build on
   the brand tokens in styles.css (--green-light/medium/dark, --text-gray).
   The admin is a fixed light UI — no dark theme here by design.

   Goal: pages stop hand-inlining cards, dividers, grids and pills.
   Convert pages onto these classes one at a time.
   ============================================================ */

:root {
  /* Action gold (the canonical .custom-button color, tokenized) */
  --gold: #EFC234;
  --gold-hover: #F7D159;

  /* Green gradient underline (was hardcoded ~17x inline) */
  --underline-a: #137752;
  --underline-b: #ADDC91;

  /* Neutrals / lines */
  --ink: #212529;
  --line: #dee2e6;
  --line-strong: #ced4da;
  --surface: #ffffff;

  /* Semantic (consolidated from scattered inline usage) */
  --ok: #28A745;   --ok-bg: #D4EDDA;  --ok-ink: #155724;
  --danger: #DC3545; --danger-bg: #F8D7DA; --danger-ink: #721C24;
  --muted: #6C757D;
}

/* ---- White panel (design-system "card"; named .panel to avoid
   colliding with Bootstrap's .card, which forces flex-column) ---- */
.panel {
  background: var(--surface);
  border: 1px solid #e9ecef;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  padding: 1.5rem;
}

/* ---- Responsive auto-fit grid of panels. No per-page @media needed:
   columns collapse to one on narrow screens automatically. ---- */
.panel-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 2rem;
}

/* ---- Green gradient underline under section/card titles ---- */
.section-divider {
  height: 3px;
  border-radius: 2px;
  background: linear-gradient(to right, var(--underline-a), var(--underline-b));
  margin: 0.5rem 0 1rem;
}

/* ---- Sort / selection pill row (promoted from assessments.php).
   Active pill is brand green per the approved design review. ---- */
.sort-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  align-items: center;
}

.sort-label {
  display: flex;
  align-items: center;
  font-size: 1rem;
  color: var(--muted);
  margin-right: 0.5rem;
  white-space: nowrap;
}

.sort-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  padding: 0.35rem 0.85rem;
  background-color: var(--surface);
  border: 1px solid var(--line);
  border-radius: 20px;
  font-size: 1rem;
  color: var(--muted);
  cursor: pointer;
  transition: all 0.2s ease;
  white-space: nowrap;
}

.sort-pill:hover {
  background-color: #f8f9fa;
  border-color: var(--line-strong);
}

.sort-pill.active {
  background-color: var(--green-dark);
  border-color: var(--green-dark);
  color: #fff;
  font-weight: 500;
}

.sort-pill i {
  font-size: 0.8rem;
}

/* On phones the pill row scrolls horizontally and the "Sort by:" label hides. */
@media (max-width: 768px) {
  .sort-controls {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    -ms-overflow-style: none;
  }
  .sort-controls::-webkit-scrollbar { display: none; }
  .sort-label { display: none; }
  .sort-pill { flex-shrink: 0; }
}

/* ---- Status tile (LIST pages: assessments, users). A clickable colored
   tile whose background encodes status. This is deliberately NOT .panel —
   list tiles are color-coded, detail pages use the white .panel box. ---- */
.status-tile {
  background-color: var(--surface);
  border-radius: 8px;
  /* Anchor for the absolutely-positioned entity label/watermark (and the
     templates page's hover actions). Without it those escape the card. */
  position: relative;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  padding: 0.75rem;
  cursor: pointer;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.status-tile:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.15);
}

/* Cards are white. Status used to be a background tint, which meant it could
   only ever be a hint — you had to know the colour code to read it. It is now
   stated outright by .status-pill in the top-right corner, which frees the fill
   and lets the three list pages look like one family. */

.status-tile h3 {
  margin: 0 0 0.35rem 0;
  font-weight: bold;
  font-size: 1.05rem;
  padding-right: 6rem;   /* clear of the corner pill(s) */
}

.status-tile .meta {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  font-size: 0.9rem;
  color: #6b6e70;
}

.status-tile .meta span {
  display: flex;
  align-items: center;
  gap: 0.7rem;
}

.status-tile .meta i {
  width: 14px;
  text-align: center;
}

/* ---- Card identity. The three list pages share .status-tile, and its FILL is
   already spoken for — it encodes status. So "what kind of thing is this" is
   carried on other channels instead: a coloured left rail, a matching type
   label top-right, and an oversized watermark glyph in the bottom-right corner.
   Each page sets --entity to its own hue; label and watermark both render that
   hue at 20% so they read as a family rather than as content. ---- */
.status-tile--entity {
  border-left: 5px solid var(--entity);
  padding-left: 0.85rem;
  overflow: hidden;
}

/* Status / attribute pills, top-right. One pill on assessments and users; a
   template can show up to two (a non-English language, and a deprecated type).
   They occupy the slot the entity type label used to hold — the rail and the
   watermark still carry identity, and stating status is the better use of the
   corner. */
.status-pills {
  position: absolute;
  top: 0.6rem;
  right: 0.75rem;
  display: flex;
  gap: 0.3rem;
  z-index: 2;
}

.status-pill {
  display: inline-block;
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  padding: 0.08rem 0.55rem;
  border-radius: 10px;
  white-space: nowrap;
}

/* Assessment lifecycle */
.st--testing   { background: #fdf2d6; color: #8a6212; }
.st--published { background: #e4f0db; color: #3c7422; }
.st--closed    { background: #fbe0e0; color: #a33a3a; }
.st--archived  { background: #eef1f4; color: #5a6672; }
/* Users: shown only when the account is deactivated (FS-012 renamed the label;
   the stored tr_users.deleted column is unchanged) */
.st--deactivated { background: #fbe0e0; color: #a33a3a; }
/* Templates: language (only when it isn't English) and deprecated question type */
.st--lang      { background: #eef1f4; color: #5a6672; }
.st--dep       { background: #fde9d9; color: #b3541a; }

.entity-mark {
  position: absolute;
  right: -6px;
  bottom: -14px;
  font-size: 3.6rem;
  color: var(--entity);
  opacity: 0.2;
  pointer-events: none;
  z-index: 0;
}

/* The watermark is the tile's last child, so without this it would paint OVER
   a long name or meta line and tint the text. Content stays above it. */
.status-tile--entity h3,
.status-tile--entity .meta,
.status-tile--entity .tile-tags {
  position: relative;
  z-index: 1;
}

/* Entity hues. Deliberately NOT the status palette — these say what a record
   is, the background says how it is doing. */
.entity--assessment { --entity: #4C8D2B; }
.entity--user       { --entity: #2b6ea8; }
.entity--template   { --entity: #7a4ca8; }

/* ---- Destructive action button. Shared: it was previously defined only in
   response.css, which loads on that one page. ---- */
.danger-button {
  background-color: #c0392b !important;
  color: #fff !important;
  border-color: #c0392b !important;
}

.danger-button:hover {
  background-color: #a93226 !important;
  border-color: #a93226 !important;
}

/* ---- Edit pencil (fa-pencil-alt). One look everywhere; behavior stays on the
   element's own onclick handler — this class is styling only. ---- */
.edit-icon {
  cursor: pointer;
  color: #666;
  margin-left: 5px;
}

.edit-icon:hover {
  color: #333;
}

/* Disabled state for the canonical .custom-button (e.g. "Assign License" when
   the user has none available). */
.custom-button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ---- Shared single-select picker popup (js/picker.js openPicker()).
   Click an option to select + close; click the backdrop or Esc to dismiss.
   One system for group/status/template/guide/... popups. ---- */
.picker-backdrop {
  position: fixed;
  inset: 0;
  background-color: rgba(0, 0, 0, 0.5);
  z-index: 999;
}

.picker-modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: var(--surface);
  padding: 1.5rem;
  border-radius: 0.5rem;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
  z-index: 1000;
  min-width: 300px;
  max-width: 90vw;
  max-height: 80vh;
  display: flex;
  flex-direction: column;
}

.picker-title {
  margin: 0 0 1rem 0;
  font-size: 1.25rem;
  font-weight: 500;
}

.picker-options {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  overflow-y: auto;
}

.picker-option {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  border: 1px solid var(--line);
  border-radius: 0.25rem;
  cursor: pointer;
  transition: background-color 0.2s ease, border-color 0.2s ease;
}

.picker-option:hover {
  background-color: #f8f9fa;
}

/* An option that is present but unavailable, with its reason (FS-010). Greyed
   rather than hidden, so the absence never has to be guessed at. */
.picker-option.disabled {
  cursor: not-allowed;
  background-color: #fbfcfc;
  border-color: #eceff1;
  color: #adb5bd;
}

.picker-option.disabled:hover {
  background-color: #fbfcfc;
}

.picker-note {
  font-size: 0.78rem;
  color: #9aa4ac;
  text-align: right;
  flex-shrink: 1;
}

/* Multi-select check (shown only when the option is selected) */
.picker-check {
  color: var(--green-medium);
  font-weight: 700;
  opacity: 0;
  flex-shrink: 0;
}

.picker-option.selected .picker-check {
  opacity: 1;
}

.picker-footer {
  display: flex;
  justify-content: flex-end;
  margin-top: 1rem;
}

/* ---- Filter chip: a pill button that opens the shared picker and shows the
   current selection (used by the comment filters; reusable elsewhere). ---- */
.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.8rem;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  cursor: pointer;
  font: inherit;
  font-size: 0.9rem;
  color: #495057;
  white-space: nowrap;
  transition: border-color 0.2s ease, background-color 0.2s ease;
}

.filter-chip:hover {
  border-color: var(--green-medium);
}

.filter-chip-value {
  font-weight: 500;
  max-width: 16rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.filter-chip i {
  font-size: 0.7rem;
  color: var(--muted);
}

.picker-option.selected {
  border-color: var(--green-medium);
  background-color: #f0f9f0;
  font-weight: 500;
}

.picker-option:focus-visible {
  outline: 2px solid var(--green-medium);
  outline-offset: 1px;
}

/* ---- List controls row (assessments.php, users.php): sort pills + filter
   chips + search, grouped so each group wraps to a new line as one block on
   narrow screens (label stays with its controls). Replaces the old
   .controls-row / bottom Show-More/Archived toggles. ---- */
.list-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem 1.25rem;
  margin-bottom: 0.75rem;
}

.control-group {
  display: inline-flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: 0.35rem;
}

/* Several chips in one group (the Response Data and comment filters carry one
   per category) need to wrap, or they run off a narrow screen. The list pages
   keep the default nowrap: one or two short chips are better kept together. */
.control-group--wrap { flex-wrap: wrap; }

/* Group label ("Sort by:", "Filter:", "Search:"). Unlike .sort-label this stays
   visible on mobile — the groups wrap instead of scrolling. */
.control-label {
  font-size: 1rem;
  color: var(--muted);
  margin-right: 0.15rem;
  white-space: nowrap;
}

/* The search group grows to take remaining width. */
.control-group--search { flex: 1 1 260px; min-width: 200px; }

/* ---- Live search box (client-side filter on list pages) ---- */
.list-search {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  flex: 1;
  padding: 0.3rem 0.75rem;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 20px;
  transition: border-color 0.2s ease;
}

.list-search:focus-within { border-color: var(--green-medium); }

.list-search > i { color: var(--muted); font-size: 0.85rem; }

.list-search input {
  border: none;
  outline: none;
  background: transparent;
  font: inherit;
  font-size: 0.95rem;
  width: 100%;
  color: var(--ink);
}

.list-search .list-search-clear {
  cursor: pointer;
  color: var(--muted);
  font-size: 0.85rem;
  display: none;
}

.list-search.has-text .list-search-clear { display: inline; }

/* ---- Toolbar under .list-controls: the result count with the page's actions on
   the right (responses.php, comments.php, comments-multi.php). The list pages
   use a bare .list-count instead, having nothing to export. ---- */
.list-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 0.75rem;
}

.list-toolbar .list-count { margin: 0; }

.list-actions {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.list-actions .custom-button {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

/* Matches the .response-nav treatment: an <a> can't carry :disabled. */
.list-actions .custom-button.disabled {
  opacity: 0.45;
  pointer-events: none;
}

@media (max-width: 768px) {
  .list-toolbar {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* Result count under the controls. */
.list-count {
  font-size: 0.85rem;
  color: var(--muted);
  margin: 0 0 0.75rem;
}

.list-empty {
  padding: 2rem;
  text-align: center;
  color: var(--muted);
}

/* ---------------------------------------------------------------------------
   Danger zone — the permanent-delete block. Shared by the assessment page and
   the user page (FS-012). Always the LAST thing on a page, visually separated,
   so it is never adjacent to a routine control.
   --------------------------------------------------------------------------- */
.danger-zone {
    max-width: 1400px;
    margin: 3rem auto 2rem;
    padding: 1rem 1.25rem;
    display: flex;
    align-items: center;
    gap: 1.25rem;
    flex-wrap: wrap;
    border: 1px solid #f0c9c4;
    border-left: 5px solid #c0392b;
    border-radius: 8px;
    background: #fdf6f5;
}

.danger-zone-text {
    flex: 1 1 22rem;
    font-size: 0.9rem;
    color: #7a5c58;
    line-height: 1.45;
}

.danger-zone-text strong {
    display: block;
    font-weight: 500;
    color: #8c2f22;
    margin-bottom: 0.15rem;
}

/* Two actions side by side (FS-012): Reassign is an ordinary button, Delete is
   the destructive one. They wrap together rather than separating on a narrow
   screen. */
.danger-zone-actions {
    display: flex;
    gap: 0.6rem;
    flex-wrap: wrap;
    align-items: center;
}

/* What is blocking a delete, itemised. An unexplained disabled button is worse
   than no button, so this list is the point of the whole block. */
.purge-blockers {
    margin: 0.5rem 0 0;
    padding-left: 1.1rem;
    font-size: 0.88rem;
    line-height: 1.6;
}

.purge-blockers li { color: #8c2f22; }

@media (max-width: 768px) {
    .danger-zone { margin: 2rem 1rem; }
}

/* ---------------------------------------------------------------------------
   Feedback — the toast and the inline message (REL-009 R5/R6).

   Two components, because there are two situations, and the difference is
   whether the reader has to do something. A confirmation is ambient and goes
   away; anything they must act on stays until they act. See js/notify.js for
   the reasoning, including why an error is never on a timer.

   These replace four separate implementations: .detail-flash (assessment page),
   .te-flash (template editor), the box template-editor.js injected by hand, and
   ~41 browser alert() calls.
--------------------------------------------------------------------------- */

.notify-toast {
    position: fixed;
    left: 50%;
    bottom: 24px;
    transform: translateX(-50%);
    background: #2f3b45;
    color: #fff;
    padding: 0.5rem 1rem;
    border-radius: 20px;
    font-size: 0.85rem;
    max-width: min(640px, 92vw);
    text-align: center;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.25s ease;
    z-index: 1200;
}

.notify-toast.on { opacity: 1; }

/* The inline message. Deliberately NOT a floating pill: it sits in the layout,
   above the thing that failed, and pushes content down — so it cannot be missed
   and cannot cover anything. */
.notify-error {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    background: #f8d7da;
    color: #721c24;
    border: 1px solid #f1b7bc;
    border-radius: 6px;
    padding: 0.7rem 0.9rem;
    margin: 0 0 1rem;
    font-size: 0.92rem;
    line-height: 1.5;
}

.notify-error-text { flex: 1; }

/* A real dismiss control, because the reader — not a timer — decides when they
   have finished with it. */
.notify-error-close {
    flex: none;
    background: none;
    border: 0;
    color: #721c24;
    font-size: 1.25rem;
    line-height: 1;
    padding: 0 0.15rem;
    cursor: pointer;
    opacity: 0.65;
}

.notify-error-close:hover { opacity: 1; }

@media print {
    .notify-toast { display: none !important; }
}

/* ---------------------------------------------------------------------------
   Personalization slots (FS-014).

   <personalized-welcome> and <personalized-thanks> are stored INSIDE the page
   text the assessment already owns. The survey loads none of this stylesheet, so
   a participant sees an ordinary paragraph and never learns a tag was involved.
   /manage loads it, so the same stored string is visibly the owner's own words.

   That is the whole mechanism for "flag it when displaying and editing, but not
   when running the survey": one string, two stylesheets. No duplicate storage,
   no flag column, and nothing to keep in step.

   Same idea as <current> / <desired>, which the survey styles for the rating
   pages — this codebase already had the pattern.
--------------------------------------------------------------------------- */

personalized-welcome,
personalized-thanks {
    display: block;
    background: #fdf3e5;
    border-left: 3px solid #A9641B;
    border-radius: 0 4px 4px 0;
    padding: 0.5rem 0.7rem;
    margin: 0 0 0.7rem;
    color: #2f3437;
}

/* An empty slot is a slot the owner has not used. Showing an empty amber box on
   every page they look at would be noise, so it collapses — but only where it is
   genuinely empty, not merely whitespace-wrapped. */
personalized-welcome:empty,
personalized-thanks:empty {
    display: none;
}

/* In a preview, say whose words these are. The label rides on the container so
   it never becomes part of the text that gets saved back. */
.shows-personalization personalized-welcome::before,
.shows-personalization personalized-thanks::before {
    content: "Your words";
    display: block;
    font-size: 0.68rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: #A9641B;
    margin-bottom: 0.2rem;
}

/* FS-014 — the template new assessments start from, for its language. Brand
   green rather than a warning colour: it is a statement of fact about which
   template is standard, not something to act on. */
.status-pill.st--default {
    background: #eef5e8;
    color: #3c7422;
    border: 1px solid #cfe3c2;
}
