/* GPDT reusable UI primitives (AV-487).
 *
 * Requires gpd-tokens.css. Every value here is a token — if you need a literal,
 * the token set is missing something; add it there.
 *
 * Every class is namespaced .gpd-*, and no existing markup uses that prefix, so
 * loading this file changes nothing that is already on screen. Element selectors
 * are deliberately absent: this app has ~35 stylesheets and an ace Bootstrap
 * build, and a bare `button {}` here would reach all of them.
 *
 * Built for reuse beyond My Learning. To extend a component, add a --modifier
 * rather than a new block, and keep the base class free of page-specific
 * geometry (widths, margins, grid placement) — that belongs to the page.
 */

/* =========================================================================
   Button
   .gpd-btn  --primary | --secondary | --ghost | --danger | --outline
             --blue | --blue-outline | --green-outline      --sm | --lg
   ========================================================================= */

.gpd-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--gpd-space-2);
  padding: var(--gpd-space-2) var(--gpd-space-4);
  border: 1px solid transparent;
  border-radius: var(--gpd-radius-sm);
  font-family: var(--gpd-font-body);
  font-size: var(--gpd-fs-base);
  font-weight: var(--gpd-fw-semi);
  line-height: var(--gpd-lh-snug);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--gpd-dur-fast) var(--gpd-ease),
              border-color var(--gpd-dur-fast) var(--gpd-ease),
              color var(--gpd-dur-fast) var(--gpd-ease);
}

.gpd-btn:hover,
.gpd-btn:focus {
  text-decoration: none;
}

/* Keyboard focus only — a mouse click on a button should not leave a ring. */
.gpd-btn:focus-visible {
  outline: none;
  box-shadow: var(--gpd-shadow-focus);
}

.gpd-btn[disabled],
.gpd-btn--disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.gpd-btn--primary {
  background: var(--gpd-green);
  color: var(--gpd-white);
}
.gpd-btn--primary:hover,
.gpd-btn--primary:focus {
  background: var(--gpd-green-hover);
  color: var(--gpd-white);
}

.gpd-btn--secondary {
  background: var(--gpd-navy);
  color: var(--gpd-white);
}
.gpd-btn--secondary:hover,
.gpd-btn--secondary:focus {
  background: var(--gpd-gray-900);
  color: var(--gpd-white);
}

.gpd-btn--ghost {
  background: transparent;
  border-color: var(--gpd-border-strong);
  color: var(--gpd-text-body);
}
.gpd-btn--ghost:hover,
.gpd-btn--ghost:focus {
  background: var(--gpd-gray-50);
  color: var(--gpd-text-heading);
}

.gpd-btn--danger {
  background: var(--gpd-danger);
  color: var(--gpd-white);
}

/* Outlined navy. Lower emphasis than --primary, higher than --ghost: used where
   an action is the point of the card but should not compete with a page CTA. */
.gpd-btn--outline {
  background: transparent;
  border-color: var(--gpd-text-heading);
  color: var(--gpd-text-heading);
}
.gpd-btn--outline:hover,
.gpd-btn--outline:focus {
  background: var(--gpd-text-heading);
  color: var(--gpd-white);
}

.gpd-btn--blue {
  background: var(--gpd-blue-deep);
  color: var(--gpd-white);
}
.gpd-btn--blue:hover,
.gpd-btn--blue:focus {
  background: var(--gpd-navy);
  color: var(--gpd-white);
}

.gpd-btn--blue-outline {
  background: transparent;
  border-color: var(--gpd-blue-deep);
  color: var(--gpd-blue-deep);
}
.gpd-btn--blue-outline:hover,
.gpd-btn--blue-outline:focus {
  background: var(--gpd-blue-deep);
  color: var(--gpd-white);
}

/* The border is the brand green; the text is the darker green that passes. */
.gpd-btn--green-outline {
  background: transparent;
  border-color: var(--gpd-green);
  color: var(--gpd-green-deep);
}
.gpd-btn--green-outline:hover,
.gpd-btn--green-outline:focus {
  background: var(--gpd-green-deep);
  border-color: var(--gpd-green-deep);
  color: var(--gpd-white);
}

.gpd-btn--sm {
  padding: var(--gpd-space-1) var(--gpd-space-3);
  font-size: var(--gpd-fs-sm);
}

.gpd-btn--lg {
  padding: var(--gpd-space-3) var(--gpd-space-5);
  font-size: var(--gpd-fs-md);
}

.gpd-btn--pill {
  border-radius: var(--gpd-radius-pill);
}

.gpd-btn--block {
  display: flex;
  width: 100%;
}

/* Icon-only. Always needs an aria-label — there is no visible text to read. */
.gpd-btn--icon {
  padding: var(--gpd-space-2);
  width: 36px;
  height: 36px;
}

/* =========================================================================
   Badge — small state pill. .gpd-badge--green | --sky | --gray | --navy
   ========================================================================= */

.gpd-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--gpd-space-1);
  padding: 3px var(--gpd-space-2);
  border-radius: var(--gpd-radius-pill);
  font-size: var(--gpd-fs-xs);
  font-weight: var(--gpd-fw-bold);
  line-height: var(--gpd-lh-snug);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  white-space: nowrap;
}

.gpd-badge--green {
  background: var(--gpd-green);
  color: var(--gpd-white);
}

/* Sky is 2.73:1 on white, so it is used as a filled background with white text
   (which passes) rather than as a foreground colour. */
.gpd-badge--sky {
  background: var(--gpd-sky);
  color: var(--gpd-white);
}

.gpd-badge--gray {
  background: var(--gpd-gray-200);
  color: var(--gpd-gray-700);
}

.gpd-badge--navy {
  background: var(--gpd-navy);
  color: var(--gpd-white);
}

/* =========================================================================
   Chip — interactive, lower emphasis than a button. --active for selection.
   ========================================================================= */

.gpd-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--gpd-space-2);
  padding: var(--gpd-space-2) var(--gpd-space-4);
  border: 1px solid var(--gpd-border-subtle);
  border-radius: var(--gpd-radius-pill);
  background: var(--gpd-white);
  color: var(--gpd-text-body);
  font-size: var(--gpd-fs-base);
  font-family: inherit;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--gpd-dur-fast) var(--gpd-ease),
              border-color var(--gpd-dur-fast) var(--gpd-ease);
}

.gpd-chip:hover,
.gpd-chip:focus {
  background: var(--gpd-gray-50);
  border-color: var(--gpd-border-strong);
  color: var(--gpd-text-heading);
  text-decoration: none;
}

.gpd-chip--active {
  background: var(--gpd-navy);
  border-color: var(--gpd-navy);
  color: var(--gpd-white);
}
.gpd-chip--active:hover,
.gpd-chip--active:focus {
  background: var(--gpd-navy);
  color: var(--gpd-white);
}

.gpd-chip__count {
  font-size: var(--gpd-fs-xs);
  font-weight: var(--gpd-fw-bold);
  opacity: 0.75;
}

/* =========================================================================
   Select — a native <select>, styled.
   Native rather than a custom menu: it is keyboard- and screen-reader-correct
   for free, and gives the right picker on mobile. The design draws a custom
   menu; the difference is the disclosure caret.
   ========================================================================= */

.gpd-select {
  /* ace.css:5031 sets a bare `select { height: 30px }`. With border-box that
     leaves ~12px for an 18px line box and clips descenders. Specificity beats
     it only for properties we actually declare, so height must be reset here
     even though nothing in this rule would otherwise mention it. */
  height: auto;
  padding: var(--gpd-space-2) var(--gpd-space-6) var(--gpd-space-2) var(--gpd-space-3);
  border: 1px solid var(--gpd-border-subtle);
  border-radius: var(--gpd-radius-sm);
  background-color: var(--gpd-white);
  color: var(--gpd-text-body);
  font-family: var(--gpd-font-body);
  font-size: var(--gpd-fs-base);
  line-height: var(--gpd-lh-snug);
  cursor: pointer;

  /* Inline SVG caret so the control matches across browsers. data: URI keeps it
     out of the network path; it inherits nothing, hence the hard-coded stroke,
     which is --gpd-gray-500. */
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23617082' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--gpd-space-3) center;
}

.gpd-select:hover {
  border-color: var(--gpd-border-strong);
}

.gpd-select:focus-visible {
  outline: none;
  border-color: var(--gpd-blue);
  box-shadow: var(--gpd-shadow-focus);
}

/* =========================================================================
   Card
   ========================================================================= */

.gpd-card {
  background: var(--gpd-surface-card);
  border-radius: var(--gpd-radius-lg);
  box-shadow: var(--gpd-shadow-md);
  padding: var(--gpd-space-5);
}

.gpd-card--flat {
  box-shadow: none;
  border: 1px solid var(--gpd-border-subtle);
}

.gpd-card--subtle {
  background: var(--gpd-surface-subtle);
  box-shadow: none;
}

.gpd-card--inverse {
  background: var(--gpd-surface-inverse);
  color: var(--gpd-text-on-dark);
}

.gpd-card--tight {
  padding: var(--gpd-space-4);
}

/* =========================================================================
   Tabs — links, not role="tab". A real tabs widget needs roving tabindex and
   arrow keys; these navigate, so they are links with aria-current="page".
   ========================================================================= */

.gpd-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gpd-space-2);
  list-style: none;
  margin: 0 0 var(--gpd-space-5);
  padding: 0;
  border-bottom: 1px solid var(--gpd-border-subtle);
}

.gpd-tabs__item {
  margin-bottom: -1px;
}

.gpd-tabs__link {
  display: inline-flex;
  align-items: center;
  gap: var(--gpd-space-2);
  /* 44px min-height is the usual touch target; the design drew 36px. */
  min-height: 44px;
  padding: var(--gpd-space-2) var(--gpd-space-4);
  border-bottom: 4px solid transparent;
  color: var(--gpd-text-muted);
  font-size: var(--gpd-fs-lg);
  font-weight: var(--gpd-fw-bold);
  text-decoration: none;
  transition: color var(--gpd-dur-fast) var(--gpd-ease),
              border-color var(--gpd-dur-fast) var(--gpd-ease);
}

.gpd-tabs__link:hover,
.gpd-tabs__link:focus {
  color: var(--gpd-text-heading);
  text-decoration: none;
}

/* Sky is fine as an indicator rule — it is not carrying the text, which stays
   navy. See the contrast note in docs/DESIGN_SYSTEM.md. */
.gpd-tabs__link[aria-current="page"] {
  color: var(--gpd-text-heading);
  border-bottom-color: var(--gpd-sky);
}

/* The count sits in its own pill rather than running on as a bare number. */
.gpd-tabs__count {
  padding: 2px var(--gpd-space-2);
  border-radius: var(--gpd-radius-pill);
  background: var(--gpd-gray-100);
  color: var(--gpd-text-muted);
  font-size: var(--gpd-fs-sm);
  font-weight: var(--gpd-fw-semi);
  line-height: var(--gpd-lh-snug);
}

/* =========================================================================
   Empty state
   ========================================================================= */

.gpd-empty {
  padding: var(--gpd-space-7) var(--gpd-space-5);
  text-align: center;
}

.gpd-empty__title {
  margin: 0 0 var(--gpd-space-3);
  color: var(--gpd-text-heading);
  font-size: var(--gpd-fs-2xl);
  font-weight: var(--gpd-fw-bold);
  line-height: var(--gpd-lh-tight);
}

.gpd-empty__body {
  max-width: 52ch;
  margin: 0 auto var(--gpd-space-5);
  color: var(--gpd-text-muted);
  font-size: var(--gpd-fs-md);
  line-height: var(--gpd-lh-normal);
}

/* =========================================================================
   Page header — the title block at the top of a page.
   .gpd-page-header > __title + __subtitle
   ========================================================================= */

/* The comps leave roughly 59px between the header chrome and the title ink;
   .page-content contributes only 8px, so the header opens the gap itself. */
.gpd-page-header {
  padding-top: var(--gpd-space-7);
  margin-bottom: var(--gpd-space-6);
}

/* Slate rather than navy: the comps put a soft display title above navy section
   headings, and making both navy collapses that hierarchy.
   Weight is semi, not the light the comps measure. The comps set Frutiger,
   whose Light still has real presence on the page; Open Sans Light at display
   size reads wispy, so matching the number rather than the impression looked
   wrong. Revisit if the Frutiger web licence lands. */
.gpd-page-header__title {
  margin: 0 0 var(--gpd-space-4);
  color: var(--gpd-text-title);
  font-family: var(--gpd-font-display);
  font-size: var(--gpd-fs-3xl);
  font-weight: var(--gpd-fw-semi);
  line-height: var(--gpd-lh-tight);
  letter-spacing: 0.005em;
}

.gpd-page-header__subtitle {
  margin: 0;
  color: var(--gpd-text-muted);
  font-size: var(--gpd-fs-md);
  font-weight: var(--gpd-fw-regular);
  line-height: var(--gpd-lh-normal);
}

@media (max-width: 768px) {
  .gpd-page-header__title {
    font-size: var(--gpd-fs-2xl);
  }
}

/* =========================================================================
   Section header — title, an optional count beside it, an optional action on
   the right. .gpd-section-header > __title + __meta + __action
   ========================================================================= */

.gpd-section-header {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--gpd-space-3);
  margin-bottom: var(--gpd-space-5);
}

.gpd-section-header__title {
  margin: 0;
  color: var(--gpd-text-heading);
  font-size: var(--gpd-fs-xl);
  font-weight: var(--gpd-fw-bold);
  line-height: var(--gpd-lh-snug);
}

/* Sits beside the title, not under it — a count, not a subtitle. */
.gpd-section-header__meta {
  color: var(--gpd-text-muted);
  font-size: var(--gpd-fs-base);
}

/* Pushed to the far right of the row. */
.gpd-section-header__action {
  margin-left: auto;
  color: var(--gpd-text-link);
  font-size: var(--gpd-fs-base);
  font-weight: var(--gpd-fw-semi);
  text-decoration: none;
}
.gpd-section-header__action:hover,
.gpd-section-header__action:focus {
  color: var(--gpd-text-link-hover);
  text-decoration: underline;
}

/* =========================================================================
   Section heading
   ========================================================================= */

.gpd-section-title {
  margin: 0 0 var(--gpd-space-4);
  color: var(--gpd-text-heading);
  font-size: var(--gpd-fs-xl);
  font-weight: var(--gpd-fw-bold);
  line-height: var(--gpd-lh-snug);
}

.gpd-section-title--muted {
  color: var(--gpd-text-muted);
  font-size: var(--gpd-fs-md);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* =========================================================================
   Utilities. Kept to the few that earn their place.
   ========================================================================= */

.gpd-muted { color: var(--gpd-text-muted); }
.gpd-meta  { color: var(--gpd-text-muted); font-size: var(--gpd-fs-sm); }

/* Visible to screen readers only — for labels the design conveys visually. */
.gpd-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Vertical rail. Same tabs, stacked — the indicator moves from the bottom edge
   to the leading edge and the active item takes a tint, because a 4px rule on
   its own reads weakly when the items are stacked rather than in a row. */
.gpd-tabs--vertical {
  flex-direction: column;
  flex-wrap: nowrap;
  gap: 0;
  margin-bottom: 0;
  border-bottom: 0;
}

.gpd-tabs--vertical .gpd-tabs__item {
  margin-bottom: 0;
}

.gpd-tabs--vertical .gpd-tabs__link {
  min-height: 40px;
  padding: var(--gpd-space-3) var(--gpd-space-4);
  border-bottom: 0;
  border-inline-start: 3px solid transparent;
  border-radius: 0 var(--gpd-radius-sm) var(--gpd-radius-sm) 0;
  font-size: var(--gpd-fs-md);
  font-weight: var(--gpd-fw-regular);
}

.gpd-tabs--vertical .gpd-tabs__link[aria-current="page"] {
  border-bottom-color: transparent;
  border-inline-start-color: var(--gpd-sky);
  background: var(--gpd-surface-subtle);
  font-weight: var(--gpd-fw-bold);
}

/* The rail's own label — "COURSE SECTIONS" above the list. */
.gpd-tabs__label {
  margin: 0 0 var(--gpd-space-2);
  padding-inline-start: var(--gpd-space-4);
  color: var(--gpd-text-muted);
  font-size: var(--gpd-fs-xs);
  font-weight: var(--gpd-fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* =========================================================================
   Modal — a short confirm dialog on Bootstrap's modal shell, so
   .modal('show'), data-dismiss and Esc keep working.
   .gpd-modal > .modal-dialog.gpd-modal__dialog > .modal-content.gpd-modal__content
     > __title + __text + __actions
   ace zeroes the content's radius and shadow; the doubled classes restore them.
   ========================================================================= */

.gpd-modal .gpd-modal__dialog {
  width: auto;
  max-width: 440px;
  margin: var(--gpd-space-8) auto;
  padding: 0 var(--gpd-space-4);
}

.gpd-modal .gpd-modal__content {
  padding: var(--gpd-space-5);
  border: 0;
  border-radius: var(--gpd-radius-lg);
  background: var(--gpd-surface-card);
  box-shadow: var(--gpd-shadow-lg);
  color: var(--gpd-text-body);
  font-family: var(--gpd-font-body);
}

.gpd-modal__title {
  margin: 0 0 var(--gpd-space-2);
  color: var(--gpd-text-heading);
  font-family: var(--gpd-font-display);
  font-size: var(--gpd-fs-xl);
  font-weight: var(--gpd-fw-semi);
  line-height: var(--gpd-lh-snug);
}

.gpd-modal__text {
  margin: 0 0 var(--gpd-space-5);
  color: var(--gpd-text-body);
  font-size: var(--gpd-fs-md);
  line-height: var(--gpd-lh-normal);
}

.gpd-modal__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--gpd-space-2);
}

@media (max-width: 540px) {
  .gpd-modal .gpd-modal__dialog {
    margin-top: var(--gpd-space-6);
  }

  .gpd-modal__actions .gpd-btn {
    flex: 1 1 auto;
  }
}
