/* ============================================================
   vth-reports.css — Reports module additions on top of vth-reskin.css
   Namespaced `.vth-*`, only paints inside `.vth`. Requires vth-tokens.css,
   vth-fonts.css, vth-reset.css, vth-reskin.css to be loaded first.
   Adds only what vth-reskin.css doesn't already have (dropdown/empty-state/
   stepped builder/segmented control/toast/pagination), per
   .claude/skills/vth-reskin/references/components.md.
   ============================================================ */

/* ============================================================
   Corrections — two layers fight vth-reskin.css's component styling inside `.vth`,
   both confirmed by reading the actual cascade (not guessed):

   1) vth-reset.css resets raw elements with real specificity, not just placeholder
      values: `.vth button{background:none;border:none;}` is (0,1,1), and
      `.vth input[type=text],...,.vth select{border:none;background:transparent;...}`
      is (0,2,1) (the [type=x] attribute selector counts same as a class). Every
      single-class `.vth-btn--*`/`.vth-input`/`.vth-select` rule in vth-reskin.css is
      (0,1,0) — LOWER specificity — so it silently loses regardless of source order
      (specificity beats source order whenever they differ). Net effect: real
      <button>/<input>/<select> elements rendered with no background/border at all,
      not just the "wrong" metrics reported earlier.
   2) `.vth a{color:var(--text-link)}` is (0,1,1), beating `.vth-btn--primary{color:
      var(--text-on-blue)}` at (0,1,0) — so a <button>-styled <a> (table row actions,
      "Report on this group") got blue text/icons regardless of variant; on a blue
      background that's invisible.

   Fixed below with compound/ancestor-doubled selectors sized to comfortably clear
   each reset's specificity (button-only conflicts need (0,2,0); the input/select
   conflict needs (0,3,0) to clear its (0,2,1)) — without editing vth-reset.css or
   vth-reskin.css. Sizing values are copied from the Claude Design source's
   .btn/.field/.inp/.selreal/.seg rules, not guessed.
   ============================================================ */
.vth-btn{gap:9px;border-radius:12px;}
/* border-STYLE, not just color, needs restoring: `.vth button{border:none}` zeroes
   out style+width+color together, so a variant that only sets border-color (below)
   would still show no border at all without this — color alone can't paint a border
   whose style is "none". */
.vth-btn.vth-btn{border-style:solid;border-width:1px;}
.vth-btn--sm{height:40px;padding:0 16px;font-size:14px;border-radius:10px;}
.vth-btn--md{height:48px;padding:0 22px;font-size:15px;}
.vth-btn--xs{height:34px;padding:0 12px;font-size:13px;border-radius:9px;gap:6px;}
.vth-btn.vth-btn--primary{background:var(--vth-blue);color:var(--text-on-blue);border-color:var(--vth-blue);}
.vth-btn.vth-btn--primary:hover{background:var(--vth-blue-hover);color:var(--text-on-blue);border-color:var(--vth-blue-hover);}
.vth-btn.vth-btn--secondary{background:transparent;color:var(--vth-blue);border-color:var(--vth-blue);}
.vth-btn.vth-btn--ghost{background:#fff;color:var(--text-secondary);border-color:var(--border-default);}
.vth-btn.vth-btn--ghost:hover{background:var(--surface-muted);}
.vth-btn.vth-btn--danger{background:var(--color-error);color:#fff;border-color:var(--color-error);}

.vth-label{font-size:13px;font-weight:var(--weight-medium);color:var(--text-primary);}
.vth .vth-input.vth-input,.vth .vth-select.vth-select,.vth .vth-textarea.vth-textarea{
  height:44px;padding:0 12px;border:1.5px solid var(--border-default);border-radius:10px;
  font-size:14px;background:#fff;box-shadow:none;
}
.vth .vth-textarea.vth-textarea{height:auto;min-height:96px;padding:10px 12px;}
.vth .vth-input.vth-input:focus,.vth .vth-select.vth-select:focus,.vth .vth-textarea.vth-textarea:focus{
  border-color:var(--vth-blue);box-shadow:0 0 0 3px rgba(25,42,193,.12);
}

.vth-seg__btn{border-radius:9px;line-height:1;}

/* vth-reset.css sets `.vth{line-height:1.5}` for body copy — correct for
   paragraphs, but it also cascades into every small pill/badge that doesn't set
   its own line-height, inflating their vertical padding well past what the design
   intends (a 12.5px badge at line-height:1.5 renders ~19px tall before padding is
   even added). Design's own CSS never sets a page-wide line-height, so these need
   an explicit tight value to match. */
.vth-infobar__facts > span{line-height:1;}
.vth-kicker,.vth-steplbl{line-height:1;}
.vth-fsum__chip{line-height:1;}

/* The dropdown trigger and its internal search box are real <button>/<input type=
   "text"> elements too — same fix, same reasoning as above. The search box gets its
   own class (vth-dropdown__search-input, added in vthSearchSelect.js's template)
   since ".vth-dropdown__search input" alone is only (0,1,1) — a class+element combo
   still can't clear the input reset's (0,2,1). */
.vth-dropdown__btn.vth-dropdown__btn{background:#fff;border:1.5px solid var(--border-default);border-radius:10px;}
.vth-dropdown__btn.vth-dropdown__btn:hover{border-color:var(--vth-blue);}
.vth-dropdown__btn.vth-dropdown__btn.is-open{border-color:var(--vth-blue);box-shadow:0 0 0 3px rgba(25,42,193,.12);}
.vth .vth-dropdown__search-input.vth-dropdown__search-input{
  height:38px;border:1.5px solid var(--border-default);border-radius:9px;background:#fff;
  padding:0 10px 0 36px;font-size:13.5px;
}
.vth .vth-dropdown__search-input.vth-dropdown__search-input:focus{border-color:var(--vth-blue);}

/* `.vth-qcard` (the "ask a question" tiles) is a real <button> on the Organisation
   reports page (it's an <a> on Overview, which is why this bug didn't show up
   there — .vth a doesn't touch background/border, only .vth button does). Same
   (0,1,1)-vs-(0,1,0) issue as everywhere else in this file: the button reset zeroed
   both the card's background and its entire border (style, not just color — a
   hover/active rule that only sets border-color can't paint anything if the base
   border-style already lost to "none"). */
.vth-qcard.vth-qcard{background:#fff;border:1.5px solid var(--border-default);}
.vth-qcard.vth-qcard:hover{border-color:var(--vth-blue);}
.vth-qcard.vth-qcard.is-active{border-color:var(--vth-blue);}

/* ---- Hero banner ---- */
.vth-hero{display:flex;align-items:center;gap:var(--space-5);background:linear-gradient(120deg,var(--vth-blue-dark),var(--vth-blue));color:#fff;border-radius:var(--radius-xl);padding:var(--space-6) var(--space-8);}
.vth-hero__icon{width:54px;height:54px;border-radius:var(--radius-lg);background:rgba(255,255,255,.15);display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;}
/* color set explicitly (not inherited) — Materialize styles h1-h6 directly, and a
   directly-matched declaration always beats an inherited one regardless of specificity */
.vth-hero h2{margin:0 0 4px;font-size:24px;line-height:30px;font-weight:var(--weight-semibold);color:#fff;}
.vth-hero p{margin:0;font-size:var(--type-size-xs);line-height:1.5;color:rgba(255,255,255,.82);max-width:640px;}

/* ---- Card title (design's ".h-sub": 16px/24px/600 — smaller than the vth-h1..h4
   typography scale, which starts at 24px, so it needs its own class here) ---- */
.vth-card-title{margin:0;font-size:16px;line-height:24px;font-weight:var(--weight-semibold);color:var(--text-primary);}

/* ---- Segmented control ---- */
.vth-seg{display:inline-flex;gap:4px;background:var(--surface-muted);border-radius:var(--radius-lg);padding:4px;}
.vth-seg__btn{border:none;background:none;font-family:var(--font-sans);font-size:var(--type-size-xs);font-weight:var(--weight-medium);color:var(--text-subtle);padding:8px 18px;border-radius:var(--radius-md);cursor:pointer;display:inline-flex;align-items:center;gap:7px;}
.vth-seg__btn.is-active{background:#fff;color:var(--vth-blue);box-shadow:var(--shadow-xs);}
/* Full-width variant for narrow columns (the Learner Lookup sidebar is 340px).
   The default 18px side padding is too generous there: three options overflowed
   the track and "Young People" wrapped out of its pill. Segments share the width
   equally and stay on one line instead. */
/* max-width has no effect in the 340px sidebar; it stops the segments stretching
   to absurd widths once that sidebar goes full-width in the stacked layout. */
.vth-seg--fill{display:flex;width:100%;max-width:520px;}
.vth-seg--fill .vth-seg__btn{flex:1 1 0;min-width:0;justify-content:center;padding:8px 10px;font-size:12px;white-space:nowrap;}
/* No small-screen shrink rule: measured, the three age-group segments need 264px
   of content in the 280px box a 320px phone gives — they fit at this size. */

/* ---- Question cards ("ask a question" tiles) ---- */
.vth-qcards{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--space-4);}
@media (max-width:1080px){.vth-qcards{grid-template-columns:minmax(0,1fr);}}
.vth-qcard{text-align:left;background:#fff;border:1.5px solid var(--border-default);border-radius:var(--radius-lg);padding:var(--space-5);display:flex;flex-direction:column;gap:10px;cursor:pointer;font-family:var(--font-sans);transition:border-color .16s ease,box-shadow .16s ease,transform .16s ease;}
.vth-qcard:hover{border-color:var(--vth-blue);transform:translateY(-2px);box-shadow:var(--shadow-md);}
.vth-qcard.is-active{border-color:var(--vth-blue);box-shadow:var(--shadow-focus-blue);}
.vth-qcard__icon{width:40px;height:40px;border-radius:var(--radius-md);background:var(--surface-blue-soft);color:var(--vth-blue);display:inline-flex;align-items:center;justify-content:center;}
.vth-qcard b{font-size:var(--type-size-sm);line-height:var(--type-leading-sm);font-weight:var(--weight-semibold);color:var(--text-primary);}
.vth-qcard span{font-size:var(--type-size-2xs);line-height:var(--type-leading-2xs);color:var(--text-subtle);}

/* ---- Field grid / stepped builder ---- */
.vth-fieldgrid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--space-4);}
@media (max-width:1040px){.vth-fieldgrid{grid-template-columns:repeat(2,minmax(0,1fr));}}
@media (max-width:560px){.vth-fieldgrid{grid-template-columns:minmax(0,1fr);}}
/* Column-count modifiers. These exist because a media query CANNOT override an
   inline style — `style="grid-template-columns:repeat(4,1fr)"` on a .vth-fieldgrid
   pinned it to four columns at every width, including phones, and silently defeated
   the two breakpoints above. Never set grid-template-columns inline on this class;
   add a modifier here instead. Declared after the base rule and its media queries
   so the cascade resolves in the intended order. */
.vth-fieldgrid--4{grid-template-columns:repeat(4,minmax(0,1fr));}
@media (max-width:1040px){.vth-fieldgrid--4{grid-template-columns:repeat(2,minmax(0,1fr));}}
@media (max-width:560px){.vth-fieldgrid--4{grid-template-columns:minmax(0,1fr);}}
.vth-fieldgrid--2-1{grid-template-columns:minmax(0,2fr) minmax(0,1fr);}
@media (max-width:760px){.vth-fieldgrid--2-1{grid-template-columns:minmax(0,1fr);}}

.vth-stepbox{border:1px solid var(--border-light);border-radius:var(--radius-lg);padding:var(--space-5);display:flex;flex-direction:column;gap:var(--space-4);}
.vth-stepbox--dashed{border-style:dashed;}
.vth-steplbl{display:flex;align-items:center;gap:10px;font-size:var(--type-size-2xs);font-weight:var(--weight-medium);letter-spacing:.05em;text-transform:uppercase;color:var(--text-muted);}
.vth-steplbl i{width:22px;height:22px;border-radius:50%;background:var(--vth-blue);color:#fff;font-size:11px;font-weight:var(--weight-medium);display:inline-flex;align-items:center;justify-content:center;font-style:normal;flex-shrink:0;}
.vth-disclose{border:none;background:none;font-family:var(--font-sans);font-size:var(--type-size-xs);font-weight:var(--weight-semibold);color:var(--vth-blue);display:inline-flex;align-items:center;gap:8px;cursor:pointer;padding:0;}

/* ---- Info / intro banner ---- */
.vth-infobar{display:flex;align-items:flex-start;gap:var(--space-4);padding:var(--space-5);border-radius:var(--radius-lg);background:var(--surface-blue-soft);border:1px solid rgba(25,42,193,.10);}
.vth-infobar__icon{width:44px;height:44px;border-radius:var(--radius-md);background:#fff;color:var(--vth-blue);display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:var(--shadow-xs);}
.vth-infobar b{font-size:var(--type-size-sm);line-height:var(--type-leading-sm);font-weight:var(--weight-semibold);color:var(--text-primary);}
.vth-infobar p{margin:4px 0 0;font-size:var(--type-size-xs);line-height:1.5;color:var(--text-secondary);max-width:760px;}
.vth-infobar__facts{display:flex;flex-wrap:wrap;gap:8px;margin-top:6px;}
/* DIRECT CHILDREN ONLY. As a descendant selector this also matched the <span>
   that vth.components.icon wraps its SVG in, so each icon became its own white
   pill with 5px/12px padding inside a 14px box — collapsing it to nothing. The
   design source doesn't hit this because its <Icon> emits a bare <svg>; ours
   wraps it. Any rule targeting a chip in here must use `>`. */
.vth-infobar__facts > span{display:inline-flex;align-items:center;gap:6px;background:#fff;border-radius:var(--radius-pill);padding:5px 12px;font-size:var(--type-size-2xs);font-weight:var(--weight-medium);color:var(--vth-blue);}

.vth-infobar__text{display:flex;flex-direction:column;gap:4px;min-width:0;}

/* ---- Checkbox rows ----
   Legacy global CSS (public/css/early_years.css) contains a bare, page-wide
   `[type="checkbox"] { opacity:0; position:absolute !important; height:100%; width:100% }`
   which leaks straight into `.vth` and renders any native checkbox INVISIBLE.
   These rules restore a real, visible control: the ancestor-qualified selector
   clears its (0,1,0) specificity, and `!important` on `position` is required
   because the legacy rule uses `!important` too. Do not "simplify" this. */
.vth-checkrow{display:flex;align-items:center;gap:10px;cursor:pointer;}
.vth-checkrow span{font-size:var(--type-size-xs);color:var(--text-secondary);}
.vth .vth-checkrow input[type="checkbox"]{
  position:static !important;
  opacity:1;
  width:18px;height:18px;
  min-width:18px;
  margin:0;
  cursor:pointer;
  accent-color:var(--vth-blue);
}

/* ---- Learner Lookup: chat-style two-pane layout ---- */
.vth-lookup{display:grid;grid-template-columns:340px minmax(0,1fr);gap:var(--space-5);align-items:start;}
@media (max-width:1080px){.vth-lookup{grid-template-columns:minmax(0,1fr);}}
.vth-lookup__list{position:sticky;top:16px;}
@media (max-width:1080px){.vth-lookup__list{position:static;}}
/* Bounded so the learner list scrolls rather than pushing the record off-screen.
   This is also the scroll-paging container — vth-infinite-scroll listens here, so
   it must keep its own overflow rather than letting the page scroll instead. */
.vth-lookup__scroll{max-height:520px;overflow-y:auto;}
/* Stacked, the sidebar sits ABOVE the record, so a 520px list means scrolling past
   the whole picker before any of the answer is visible. */
@media (max-width:1080px){.vth-lookup__scroll{max-height:300px;}}
.vth-lookup__note{margin:8px 0 0;padding:0 12px;}

/* "Recent" marker on a recently-viewed learner in the sidebar. */
.vth-pick__tag{flex-shrink:0;font-size:10px;font-weight:var(--weight-semibold);letter-spacing:.04em;text-transform:uppercase;color:var(--vth-blue);background:var(--surface-blue-soft);border-radius:var(--radius-pill);padding:3px 8px;}

/* The course filter sits in a flex row beside the learner's name. Flex items are
   content-sized, so without a fixed basis a long course title stretches the whole
   control (and pushes the name cluster around) the moment it is selected. */
.vth-lookup__coursefilter{flex:0 0 280px;width:280px;max-width:100%;margin:0;}
/* Once the header row wraps, a 280px basis leaves an odd short control against a
   full-width name cluster — let it span instead. */
@media (max-width:760px){.vth-lookup__coursefilter{flex:1 1 100%;width:100%;}}

/* ---- Card overflow utility — .vth-card sets overflow:hidden (vth-reskin.css),
   which clips any dropdown popover that opens past the card's edge. Apply this
   modifier to any .vth-card that contains a .vth-dropdown/.vth-search-select. ---- */
.vth-card--overflow-visible{overflow:visible;}

/* ---- Searchable dropdown ("sdrop") ---- */
.vth-dropdown{position:relative;}
.vth-dropdown__btn{width:100%;height:44px;border:1.5px solid var(--border-default);border-radius:10px;padding:0 var(--space-3);background:#fff;font-family:var(--font-sans);font-size:var(--type-size-xs);color:var(--text-primary);display:flex;align-items:center;gap:8px;cursor:pointer;text-align:left;}
.vth-dropdown__btn:hover{border-color:var(--vth-blue);}
.vth-dropdown__btn.is-open{border-color:var(--vth-blue);box-shadow:0 0 0 3px rgba(25,42,193,.12);}
.vth-dropdown__btn .v{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.vth-dropdown__menu{position:absolute;left:0;right:0;top:calc(100% + 6px);background:#fff;border:1px solid var(--border-light);border-radius:14px;box-shadow:var(--shadow-lg);z-index:65;padding:var(--space-2);display:flex;flex-direction:column;gap:6px;}
.vth-dropdown__search{position:relative;}
.vth-dropdown__search .vth-icon{position:absolute;left:11px;top:50%;transform:translateY(-50%);color:var(--text-muted);}
.vth-dropdown__search input{width:100%;height:38px;border:1.5px solid var(--border-default);border-radius:var(--radius-sm);padding:0 10px 0 36px;font-family:var(--font-sans);font-size:13.5px;}
.vth-dropdown__search input:focus{outline:none;border-color:var(--vth-blue);}
.vth-dropdown__list{max-height:216px;overflow-y:auto;display:flex;flex-direction:column;gap:2px;}
.vth-dropdown__item{border:none;background:none;font-family:var(--font-sans);font-size:13.5px;color:var(--text-secondary);padding:9px 11px;border-radius:var(--radius-sm);cursor:pointer;text-align:left;display:flex;align-items:center;gap:9px;width:100%;}
.vth-dropdown__item:hover{background:var(--surface-muted);color:var(--text-primary);}
.vth-dropdown__item.is-active{background:var(--surface-blue-soft);color:var(--vth-blue);font-weight:var(--weight-semibold);}
.vth-dropdown__none{padding:14px 11px;font-size:var(--type-size-xs);color:var(--text-subtle);}

/* ---- Empty state ---- */
.vth-empty{display:flex;flex-direction:column;align-items:center;text-align:center;gap:var(--space-3);padding:44px var(--space-6);}
.vth-empty__icon{width:60px;height:60px;border-radius:var(--radius-lg);background:var(--surface-muted);color:var(--text-muted);display:inline-flex;align-items:center;justify-content:center;}
.vth-empty h4{margin:0;font-size:var(--type-size-lg);font-weight:var(--weight-semibold);color:var(--text-primary);}
.vth-empty p{margin:0;max-width:520px;color:var(--text-subtle);font-size:var(--type-size-xs);}

/* ---- Processing banner (instant vs background export) ---- */
.vth-procbar{display:flex;align-items:center;gap:var(--space-4);padding:14px 18px;border-radius:var(--radius-lg);font-size:var(--type-size-xs);}
.vth-procbar--now{background:#DDFBE7;color:#186336;}
.vth-procbar--bg{background:#FFF2D1;color:#7C3F0B;}
.vth-procbar__dial{width:64px;height:64px;border-radius:50%;background:rgba(255,255,255,.72);display:grid;place-items:center;flex-shrink:0;line-height:1.1;text-align:center;}
.vth-procbar__dial b{display:block;font-size:17px;font-weight:var(--weight-bold);}
.vth-procbar__dial i{display:block;font-size:10px;font-style:normal;opacity:.75;font-weight:var(--weight-semibold);}

/* ---- Filter-summary chips (applied-filters row above results) ---- */
.vth-fsum{display:flex;align-items:center;gap:10px;flex-wrap:wrap;background:var(--surface-blue-soft);border-radius:var(--radius-lg);padding:12px 14px;}
.vth-fsum__chip{display:inline-flex;align-items:center;gap:7px;background:#fff;border-radius:var(--radius-pill);padding:5px 6px 5px 12px;font-size:var(--type-size-2xs);font-weight:var(--weight-medium);color:var(--vth-blue);}
.vth-fsum__chip button{border:none;background:none;cursor:pointer;color:var(--text-muted);display:inline-flex;padding:0;}

/* ---- Misc text helpers ---- */
.vth-kicker{font-size:11.5px;font-weight:var(--weight-medium);letter-spacing:.05em;text-transform:uppercase;color:var(--text-muted);}
.vth-pick{display:flex;align-items:center;gap:11px;padding:11px 12px;border-radius:var(--radius-md);cursor:pointer;border:1px solid transparent;}
.vth-pick:hover{background:var(--surface-muted);}
.vth-pick.is-active{background:var(--surface-blue-soft);border-color:rgba(25,42,193,.18);}
.vth-cklist{display:flex;flex-direction:column;gap:2px;overflow-y:auto;}
.vth-lnk{color:var(--vth-blue);font-weight:var(--weight-semibold);cursor:pointer;background:none;border:none;font-family:var(--font-sans);font-size:var(--type-size-xs);display:inline-flex;align-items:center;gap:6px;padding:0;}
.vth-lnk:hover{text-decoration:underline;}

/* ---- Toast ---- */
.vth-toast{position:fixed;left:50%;bottom:28px;transform:translateX(-50%);background:var(--text-primary);color:#fff;padding:13px 22px;border-radius:var(--radius-md);font-size:var(--type-size-xs);font-weight:var(--weight-semibold);display:flex;align-items:center;gap:9px;z-index:1100;box-shadow:var(--shadow-lg);animation:vth-toast-in .28s ease;}
@keyframes vth-toast-in{from{opacity:0;transform:translateX(-50%) translateY(8px);}to{opacity:1;transform:translateX(-50%) translateY(0);}}

/* ---- Report table (extends .vth-table from vth-reskin.css — that one is left
   untouched; this is a modifier + a "who" avatar/name/email cluster for learner
   rows, matching the design's .tbl/.who/.av/.whoname/.whomail) ---- */
.vth-table--report th{background:none;text-transform:uppercase;letter-spacing:.04em;font-size:12px;font-weight:var(--weight-bold);color:var(--text-muted);border-bottom:1.5px solid var(--border-light);white-space:nowrap;}
.vth-table--report td{font-size:14px;color:var(--text-secondary);vertical-align:middle;}
.vth-table--report tr:last-child td{border-bottom:none;}
/* Documents column: fixed so the widest cell contents can't drive the layout.
   The "Available once completed" placeholder is longer than any real value here,
   and with an auto-width column it claimed the space the course title needs. The
   trigger button stays on one line; only the placeholder sentence wraps. */
.vth-table--report .vth-table__docs{width:200px;}
/* Short, atomic values — a wrapped "2022-\n12-16" reads as two dates. The course
   title is the only column that should absorb the slack. */
.vth-table--report .vth-table__score,.vth-table--report .vth-table__when{white-space:nowrap;}
.vth-table--report td.vth-table__docs{white-space:normal;}
.vth-table--report td.vth-table__docs .vth-lnk{white-space:nowrap;}
.vth-who{display:flex;align-items:center;gap:11px;}
.vth-who__avatar{width:36px;height:36px;border-radius:50%;background:var(--surface-blue-soft);color:var(--vth-blue);display:inline-flex;align-items:center;justify-content:center;font-size:12.5px;font-weight:var(--weight-bold);flex-shrink:0;}
.vth-who__name{font-size:14px;font-weight:var(--weight-semibold);color:var(--text-primary);}
.vth-who__email{font-size:12px;color:var(--text-subtle);}
.vth-qstate{display:inline-flex;align-items:center;gap:7px;font-size:12.5px;font-weight:var(--weight-medium);color:var(--text-subtle);}

/* ---- Pagination lives in vth-reskin.css now: it is an app-wide component
   (see public/js/directives/vthPagination.js), not a reports-only one. ---- */

/* ============================================================
   Course lists — VTH card list + Internal table
   Values copied from the design source (ui_kits/platform/reports.html, .cpv*/.cc*),
   not eyeballed. The two tabs render deliberately differently: VTH is a browsable
   catalogue with imagery, Internal is a compact table of the company's own courses.
   ============================================================ */
/* Design's .cpv gap is 16px exactly. */
.vth-cpv{display:flex;flex-direction:column;gap:16px;}
.vth-cpvcard{display:flex;gap:var(--space-6);background:#fff;border-radius:20px;padding:var(--space-4);box-shadow:0 6px 22px rgba(16,24,40,.07);}
.vth-cpvcard__img{position:relative;width:356px;height:238px;border-radius:14px;background:var(--surface-muted) center/cover no-repeat;flex-shrink:0;overflow:hidden;}
.vth-cpvcard__sec{position:absolute;left:14px;top:14px;background:var(--vth-blue);color:#fff;border-radius:var(--radius-pill);padding:8px 16px;font-size:13px;font-weight:var(--weight-medium);line-height:1.2;}
.vth-cpvcard__bd{flex:1;min-width:0;display:flex;flex-direction:column;gap:12px;padding:8px 8px 8px 0;}
.vth-cpvcard__bd h4{margin:0;font-size:22px;line-height:30px;font-weight:var(--weight-medium);color:var(--text-primary);}
.vth-cpvcard__bd p{margin:0;font-size:14px;line-height:22px;color:var(--text-secondary);}
.vth-cpvcard__modes{display:flex;gap:9px;margin-top:auto;flex-wrap:wrap;}
.vth-cpvmode{height:32px;border-radius:17px;display:inline-flex;align-items:center;gap:7px;padding:0 12px;color:rgb(19,19,19);font-size:12px;font-weight:var(--weight-medium);line-height:1;}
/* Stack the image above the text before it gets too narrow to read beside it. */
@media (max-width:980px){
  .vth-cpvcard{flex-direction:column;}
  .vth-cpvcard__img{width:100%;height:210px;}
  .vth-cpvcard__bd{padding:0;}
  .vth-cpvcard__bd h4{font-size:19px;line-height:26px;}
}

/* Course chips (level / CPD minutes / draft) */
.vth-ccard__chips{display:flex;flex-wrap:wrap;gap:7px;}
.vth-cc{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;line-height:1;font-weight:var(--weight-medium);padding:5px 10px;border-radius:var(--radius-pill);white-space:nowrap;}
.vth-cc--b{background:rgb(211,237,255);color:#1D2C92;}
.vth-cc--y{background:rgb(255,218,121);color:#4A2300;}
.vth-cc--g{background:rgb(137,236,174);color:#16512D;}
.vth-cc--n{background:var(--surface-muted);color:var(--text-subtle);}

/* Action row above the results — wraps rather than overflowing on narrow screens. */
.vth-listbar{display:flex;align-items:center;justify-content:space-between;gap:var(--space-3);flex-wrap:wrap;}
.vth-listbar__actions{display:flex;gap:10px;flex-wrap:wrap;position:relative;align-items:center;}

/* Internal tab: a compact table. Scrolls inside itself so the page never does. */
.vth-tblwrap{overflow-x:auto;}

/* Favourite toggle on a card's image. Values from the design's .cpvcard-fav.
   This is a favourite, NOT a download selection — downloads follow the filters. */
.vth-cpvcard__fav{position:absolute;right:14px;top:14px;width:32px;height:32px;border-radius:50%;background:rgba(19,19,19,.45);color:#fff;display:grid;place-items:center;border:none;cursor:pointer;padding:0;transition:background .15s ease,color .15s ease;}
.vth-cpvcard__fav:hover{background:rgba(19,19,19,.65);}
.vth-cpvcard__fav.is-on{background:#fff;color:var(--color-error);}
.vth-cpvcard__fav svg{display:block;}

/* ==========================================================================
   Verify training (/reports/verify-training + the public /verify-certificate)
   Values copied from the design source's own CSS (ui_kits/platform/reports.html:
   .linkbox, .reducer, and the ResultCard banner), not eyeballed.

   Everything else this page needs is REUSED: .vth-fieldgrid--4 + .vth-stat-card
   for the results tiles, .vth-badge--* for outcome chips, .vth-alert--info/
   --warning for the design's .note, .vth-empty for its .zero, and
   .vth-procbar/.vth-procbar__dial for the "prepared in the background" panel.
   ========================================================================== */

/* Upload dropzone — the design's .linkbox.
   The real <input type="file"> is taken out of the layout rather than styled: it
   is not in vth-reset.css's input list, so it would otherwise pick up whatever
   Materialize/legacy CSS says about file inputs. The <label> is the control. */
.vth-dropzone{display:flex;align-items:center;gap:var(--space-3);background:var(--surface-muted);border:1.5px dashed var(--border-default);border-radius:var(--radius-lg);padding:10px 10px 10px 14px;cursor:pointer;margin:0;}
.vth-dropzone:hover{border-color:var(--vth-blue);}
.vth-dropzone.is-dragging{border-color:var(--vth-blue);background:var(--surface-blue-soft);}
.vth-dropzone__label{flex:1;min-width:0;font-family:ui-monospace,Menlo,monospace;font-size:13px;color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.vth-dropzone__input{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0;}
/* Not a real <button>, so it needs the .vth-btn look without the reset fight. */
.vth-dropzone__cta{display:inline-flex;align-items:center;gap:6px;background:#fff;border:1px solid var(--border-default);border-radius:var(--radius-md);padding:6px 12px;font-size:12.5px;font-weight:var(--weight-medium);color:var(--text-primary);line-height:1;flex-shrink:0;}

/* Small action button that sits ON a coloured .vth-procbar — borrows the bar's
   own text colour, so it can't be a .vth-btn variant. Two classes to clear
   vth-reset.css's `.vth button{background:none;border:none}` (0,1,1). */
.vth-reducer.vth-reducer{border:1px solid currentColor;background:rgba(255,255,255,.6);border-radius:var(--radius-md);padding:7px 12px;font-family:var(--font-sans);font-size:12.5px;font-weight:var(--weight-medium);color:inherit;cursor:pointer;display:inline-flex;align-items:center;gap:7px;line-height:1;}
.vth-reducer.vth-reducer:hover{background:#fff;}

/* ---- The result card ----------------------------------------------------
   Validity and record state are shown as two SEPARATE strips, never merged.
   An archived record is usually also lapsed (in this database, always), and one
   combined banner can only ever show one of those two facts — which is the bug
   on the legacy page, where an archived, three-years-lapsed certificate
   rendered as a plain green "Certificate Verified". ---------------------- */
.vth-verify__banner{display:flex;align-items:center;gap:var(--space-3);border-radius:13px;padding:14px 16px;}
.vth-verify__banner b{display:block;font-size:17px;line-height:23px;}
.vth-verify__banner span{font-size:13px;opacity:.9;}
.vth-verify__banner svg{flex-shrink:0;}
.vth-verify--valid{background:#DDFBE7;color:#186336;}
.vth-verify--lapsed{background:#FFF2D1;color:#7C3F0B;}
.vth-verify--missing{background:#FEE2E2;color:#EB3939;}
.vth-verify--unknown{background:var(--surface-muted);color:var(--text-secondary);}

/* The archived strip. Deliberately neutral, not red: an archived record means
   the learner's record was archived by their organisation, NOT that the
   certificate was withdrawn — the training still took place. */
.vth-verify__state{display:flex;align-items:flex-start;gap:11px;border-radius:12px;padding:13px 16px;background:var(--surface-muted);color:var(--text-secondary);font-size:13.5px;line-height:1.55;border:1px solid var(--border-default);}
.vth-verify__state svg{flex-shrink:0;margin-top:1px;}
.vth-verify__state b{display:block;color:var(--text-primary);font-weight:var(--weight-semibold);margin-bottom:2px;}

/* Codes are case-sensitive base62 — never text-transform them. */
.vth-mono{font-family:ui-monospace,Menlo,monospace;letter-spacing:.06em;}
.vth-code-input.vth-code-input{font-family:ui-monospace,Menlo,monospace;letter-spacing:.06em;font-size:16px;height:52px;}

/* Bulk preview/results tables keep the code column narrow and unwrapped. */
.vth-verify__codecell{font-family:ui-monospace,Menlo,monospace;font-size:13px;white-space:nowrap;}

/* Verify training's tab strip. `.vth-row` (vth-reskin.css, shared) is a bare
   `display:flex` with no wrap, so the three tabs plus the hint text overflowed the
   page below ~560px — measured, not guessed. Fixed here rather than by adding wrap
   to `.vth-row`, which every other page relies on as-is. */
.vth-verify__tabs{flex-wrap:wrap;align-items:center;}
.vth-verify__hint{margin-left:auto;align-self:center;}
@media (max-width:760px){
  /* Hint drops onto its own line before the tabs are squeezed. */
  .vth-verify__hint{margin-left:0;flex:1 1 100%;}
}
@media (max-width:560px){
  .vth-verify__tabs .vth-seg{display:flex;width:100%;}
  .vth-verify__tabs .vth-seg__btn{flex:1 1 0;min-width:0;justify-content:center;padding:8px 6px;font-size:12px;}
  /* The log tab's count badge is the last 5px that won't fit at 500px, and it is
     decoration — the tab label carries the meaning. */
  .vth-verify__tabs .vth-seg__btn .vth-badge{display:none;}
}

/* Search field with a leading icon — the design's `.srch`.
   `.vth-search` was used by the markup but had NO rule anywhere, so the icon simply
   sat in the normal flow above the input instead of inside it.
   The icon partial wraps its SVG in `<span class="vth-icon">`, so that span is what
   has to be positioned — not the svg. The input's left padding needs (0,3,0) to
   clear vth-reset.css's `.vth input[type=text]{padding:0}`, which is (0,2,1). */
.vth-search{position:relative;}
.vth-search > .vth-icon{position:absolute;left:13px;top:50%;transform:translateY(-50%);color:var(--text-muted);pointer-events:none;z-index:1;}
.vth .vth-search .vth-input.vth-input{padding-left:40px;}

/* Action popover anchored to a button, rather than filling a form field's width.
   `.vth-dropdown__menu` is `left:0;right:0` for the search-select case. */
.vth-dropdown__menu--auto{left:auto;right:0;min-width:190px;}
.vth-dropdown__menu--auto .vth-dropdown__item{white-space:nowrap;}

/* ============================================================
   Learner — Certificates & documents (/learner-course/access-certificate)
   Values copied from the design source (ui_kits/platform/learner-training.html,
   section L3: .hero/.stats/.crow/.dbtn), not eyeballed.
   ============================================================ */

/* Stat tiles: 4-up, reflowing. A modifier class, never an inline
   grid-template-columns — an inline style beats every media query. */
.vth-statgrid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px;}
@media (max-width:900px){.vth-statgrid{grid-template-columns:repeat(2,minmax(0,1fr));}}
@media (max-width:520px){.vth-statgrid{grid-template-columns:minmax(0,1fr);}}
.vth-stat{border:1px solid var(--border-light);border-radius:14px;padding:16px;}
.vth-stat__n{font-size:26px;font-weight:var(--weight-bold);color:var(--text-primary);line-height:1;}
.vth-stat__l{font-size:12.5px;line-height:1.3;color:var(--text-subtle);margin-top:6px;}

/* Completed-course rows */
.vth-crows{display:flex;flex-direction:column;}
.vth-crow{display:grid;grid-template-columns:44px minmax(0,1fr) auto;gap:16px;align-items:center;padding:16px 4px;border-bottom:1px solid var(--border-light);}
.vth-crow:last-child{border-bottom:none;}
.vth-crow__i{width:44px;height:44px;border-radius:14px;display:grid;place-items:center;background:#DDFBE7;color:#186336;}
.vth-crow__main{min-width:0;}
.vth-crow__main b{display:block;font-size:15.5px;line-height:22px;font-weight:var(--weight-medium);color:var(--text-primary);}
.vth-crow__meta{font-size:13px;line-height:19px;color:var(--text-subtle);margin-top:3px;}
.vth-crow__chips{display:flex;gap:6px;flex-wrap:wrap;margin-top:8px;}
.vth-crow__acts{display:flex;gap:8px;flex-wrap:wrap;justify-content:flex-end;}
/* Below this the three-column row cannot hold a name and three buttons side by
   side; stack so the actions sit under the course rather than squeezing it. */
@media (max-width:760px){
  .vth-crow{grid-template-columns:44px minmax(0,1fr);row-gap:12px;}
  .vth-crow__acts{grid-column:1 / -1;justify-content:flex-start;}
}

/* Document buttons — real <button>/<a> elements, so they need the compound
   selector that clears vth-reset.css (see css-gotchas.md). */
.vth-dbtn.vth-dbtn{display:inline-flex;align-items:center;gap:7px;height:36px;padding:0 13px;border-radius:10px;border:1px solid var(--border-default);background:#fff;font-family:var(--font-sans);font-size:13px;font-weight:var(--weight-medium);color:var(--text-secondary);cursor:pointer;white-space:nowrap;text-decoration:none;}
.vth-dbtn.vth-dbtn:hover{border-color:var(--vth-blue);color:var(--vth-blue);}

/* "Loading 6 more…" sentinel */
.vth-loadmore{display:flex;align-items:center;justify-content:center;gap:10px;padding:18px 0 6px;font-size:13px;color:var(--text-subtle);}
.vth-loadmore__spin{width:16px;height:16px;border-radius:50%;border:2px solid var(--border-default);border-top-color:var(--vth-blue);animation:vth-spin .7s linear infinite;}
@keyframes vth-spin{to{transform:rotate(360deg);}}

/* Header row of the record card: identity left, actions right, wrapping cleanly. */
.vth-recordbar{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;flex-wrap:wrap;}
.vth-recordbar__acts{display:flex;gap:10px;align-items:center;flex-wrap:wrap;position:relative;}

/* Filter row above the list. */
.vth-filterrow{display:flex;gap:12px;flex-wrap:wrap;align-items:flex-end;border-top:1px solid var(--border-light);padding-top:16px;}
.vth-filterrow__search{flex:1 1 240px;min-width:210px;margin:0;}
.vth-filterrow__f{flex:0 1 180px;min-width:150px;margin:0;}

/* ---- Learner — Share my training ---- */
/* Two columns on desktop, stacked once the form would get too narrow to fill in. */
.vth-sharegrid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:var(--space-6);}
@media (max-width:860px){.vth-sharegrid{grid-template-columns:minmax(0,1fr);}}
.vth-sharegrid__aside{display:flex;flex-direction:column;gap:14px;}

/* The generated link, ready to copy. Values from the design's .linkbox.
   `min-width:0` lets the <code> shrink and ellipsis rather than forcing the row
   wider than its column. */
.vth-linkbox{display:flex;align-items:center;gap:10px;background:var(--surface-muted);border:1.5px dashed var(--border-default);border-radius:12px;padding:10px 10px 10px 14px;}
.vth-linkbox code{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;color:var(--text-primary);}

/* Preview of the email the recipient actually receives (design's .emailtpl). */
.vth-emailtpl{border:1px solid var(--border-light);border-radius:14px;overflow:hidden;}
.vth-emailtpl__head{background:var(--surface-subtle);padding:12px 16px;border-bottom:1px solid var(--border-light);font-size:13px;line-height:1.4;color:var(--text-subtle);}
.vth-emailtpl__body{padding:18px 18px 20px;font-size:14px;line-height:1.65;color:var(--text-secondary);}
/* The stored template is real email HTML — keep it from breaking the panel. */
.vth-emailtpl__body img{max-width:100%;height:auto;}
.vth-emailtpl__body table{width:100%!important;max-width:100%;border-collapse:collapse;}
.vth-emailtpl__body a{color:var(--vth-blue);}
.vth-emailtpl__scroll{max-height:360px;overflow-y:auto;}

/* Inline validation message under a field. */
.vth-field__error{display:block;margin-top:6px;font-size:12.5px;line-height:1.3;color:var(--color-error);}
.vth .vth-input.is-error{border-color:var(--color-error);}

/* ---- Activity table (learner) ----
   Column widths from the design's L4 table: a fixed, non-wrapping timestamp and a
   40% activity-type column, leaving the description the remaining space. */
.vth-table--activity .vth-table__when{width:150px;white-space:nowrap;}
.vth-table--activity .vth-table__acttype{width:40%;color:var(--text-primary);}
/* `action`/`message` are server-rendered HTML; keep long unbroken strings from
   forcing the table wider than its scroll container. */
.vth-table--activity td{overflow-wrap:anywhere;}
.vth-table--activity td b{font-weight:var(--weight-medium);color:var(--text-primary);}
