/*
 * ME-SBG Color System v2
 * See tmp/mockups/color_scheme_styleguide_v2.html for full documentation
 *
 * STRATEGY:
 * - Bootstrap classes (bg-primary, btn-success, etc.) remain unchanged
 * - Custom outcome-* classes are used exclusively for outcome levels
 * - Custom ui-* classes for app-specific branding (navbar, etc.)
 */

:root {
  /* === OUTCOME LEVELS (Reserved - Never use for other purposes) === */
  --outcome-high: #2563eb;        /* Blue - Highly Proficient (Level 1 - highest) */
  --outcome-high-light: #dbeafe;
  --outcome-high-dark: #1d4ed8;

  --outcome-mid: #16a34a;         /* Green - Proficient (Level 2) */
  --outcome-mid-light: #dcfce7;
  --outcome-mid-dark: #15803d;

  --outcome-low: #eab308;         /* Yellow - Not Yet Proficient (Level 3) */
  --outcome-low-light: #fef9c3;
  --outcome-low-dark: #ca8a04;

  --outcome-beginning: #f97316;   /* Orange - Beginning (Level 4 - lowest, optional) */
  --outcome-beginning-light: #fed7aa;
  --outcome-beginning-dark: #c2410c;

  --outcome-none: #9ca3af;        /* Gray - Not Assessed */
  --outcome-none-light: #f3f4f6;
  --outcome-none-dark: #6b7280;

  /* === UI COLORS (For app branding) === */
  --ui-primary: #0f766e;          /* Teal */
  --ui-primary-light: #ccfbf1;
  --ui-primary-dark: #115e59;

  /* === TEACHER NOTES === One envelope, one color, for teachers and students
     alike, so "look for the teal envelope" means the same thing to both. */
  --note-color: var(--ui-primary);
  --note-color-dark: var(--ui-primary-dark);

  /* === UI COLORS (Secondary and Accent) === */
  --ui-secondary: #64748b;        /* Slate */
  --ui-secondary-light: #f1f5f9;
  --ui-secondary-dark: #475569;

  --ui-accent: #be185d;           /* Rose */
  --ui-accent-light: #fce7f3;
  --ui-accent-dark: #9d174d;

  /* === FEEDBACK COLORS === */
  --feedback-info: #0891b2;       /* Cyan */
  --feedback-info-light: #cffafe;
  --feedback-info-dark: #0e7490;

  --feedback-success: #059669;    /* Emerald */
  --feedback-success-light: #d1fae5;
  --feedback-success-dark: #047857;

  --feedback-warning: #ea580c;    /* Orange */
  --feedback-warning-light: #ffedd5;
  --feedback-warning-dark: #c2410c;

  --feedback-error: #dc2626;      /* Red */
  --feedback-error-light: #fee2e2;
  --feedback-error-dark: #b91c1c;

  /* === NEUTRAL COLORS === */
  --neutral-50: #fafafa;
  --neutral-100: #f4f4f5;
  --neutral-200: #e4e4e7;
  --neutral-300: #d4d4d8;
  --neutral-400: #a1a1aa;
  --neutral-500: #71717a;
  --neutral-600: #52525b;
  --neutral-700: #3f3f46;
  --neutral-800: #27272a;
  --neutral-900: #18181b;
}

/* Bootstrap's Reboot opts the whole document into smooth scrolling
   (:root { scroll-behavior: smooth }). That makes Turbo animate its
   scroll restoration on Back-navigation, which is jarring for students,
   and animate its jump to the top of every new page, which shows the new
   page at the old page's offset first. Override it so all scrolling —
   including Back — is instant.
   html:root rather than :root: the layout's stylesheet_link_tag :app loads
   bootstrap.min.css again after this file, and at equal specificity the
   later rule would win. */
html:root {
  scroll-behavior: auto;
}

/* === NAVBAR STYLING === */

.navbar-mesbg {
  background-color: var(--ui-primary) !important;
}

.navbar-mesbg .navbar-brand,
.navbar-mesbg .nav-link {
  color: rgba(255, 255, 255, 0.9) !important;
}

.navbar-mesbg .navbar-brand:hover,
.navbar-mesbg .nav-link:hover {
  color: white !important;
}

.navbar-mesbg .navbar-toggler {
  border-color: rgba(255, 255, 255, 0.5);
}

.navbar-mesbg .navbar-toggler-icon {
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
}

/* Navbar brand text next to logo */
.me-sbg-brand-text {
  color: rgba(255, 255, 255, 0.95);
  line-height: 1.05;
}

.me-sbg-brand-line1 {
  font-weight: 700;
  font-size: 0.95rem;
}

.me-sbg-brand-line2 {
  font-weight: 700;
  font-size: 0.95rem;
}

@media (max-width: 576px) {
  .me-sbg-brand-line1,
  .me-sbg-brand-line2 {
    font-size: 0.8rem;
  }
}

/* On mobile / short viewports the expanded hamburger menu can exceed the
   visible viewport (notably in landscape). The fixed-top navbar doesn't
   scroll the page, so the tail of the menu (Log out) becomes unreachable.
   Bound the collapsed content's height and let it scroll internally. */
@media (max-width: 991.98px) {
  .navbar-mesbg .navbar-collapse {
    max-height: calc(100vh - 60px);
    overflow-y: auto;
    overscroll-behavior: contain;
  }
}

/* === OUTCOME LEVEL CLASSES (Reserved for outcome levels only) === */

/* Level 1 - Highly Proficient (Blue) - highest */
.outcome-high {
  background-color: var(--outcome-high) !important;
  color: white !important;
}

.outcome-high-bg {
  background-color: var(--outcome-high-light) !important;
  color: var(--outcome-high-dark) !important;
}

.outcome-high-text {
  color: var(--outcome-high) !important;
}

.outcome-high-border {
  border-color: var(--outcome-high) !important;
}

/* Level 2 - Proficient (Green) */
.outcome-mid {
  background-color: var(--outcome-mid) !important;
  color: white !important;
}

.outcome-mid-bg {
  background-color: var(--outcome-mid-light) !important;
  color: var(--outcome-mid-dark) !important;
}

.outcome-mid-text {
  color: var(--outcome-mid) !important;
}

.outcome-mid-border {
  border-color: var(--outcome-mid) !important;
}

/* Level 3 - Not Yet Proficient (Yellow) */
.outcome-low {
  background-color: var(--outcome-low) !important;
  color: var(--neutral-800) !important;
}

.outcome-low-bg {
  background-color: var(--outcome-low-light) !important;
  color: var(--outcome-low-dark) !important;
}

.outcome-low-text {
  color: var(--outcome-low-dark) !important;
}

.outcome-low-border {
  border-color: var(--outcome-low) !important;
}

/* Level 4 - Beginning (Orange) - lowest (optional) */
.outcome-beginning {
  background-color: var(--outcome-beginning) !important;
  color: white !important;
}

.outcome-beginning-bg {
  background-color: var(--outcome-beginning-light) !important;
  color: var(--outcome-beginning-dark) !important;
}

.outcome-beginning-text {
  color: var(--outcome-beginning) !important;
}

.outcome-beginning-border {
  border-color: var(--outcome-beginning) !important;
}

/* Not Assessed (Gray) */
.outcome-none {
  background-color: var(--outcome-none) !important;
  color: white !important;
}

.outcome-none-bg {
  background-color: var(--outcome-none-light) !important;
  color: var(--outcome-none-dark) !important;
}

.outcome-none-text {
  color: var(--outcome-none) !important;
}

.outcome-none-border {
  border-color: var(--outcome-none) !important;
}

/* === UI PRIMARY CLASSES (Teal) === */

.btn-ui-primary {
  background-color: var(--ui-primary) !important;
  border-color: var(--ui-primary) !important;
  color: white !important;
}

.btn-ui-primary:hover {
  background-color: var(--ui-primary-dark) !important;
  border-color: var(--ui-primary-dark) !important;
  color: white !important;
}

.btn-outline-ui-primary {
  background-color: transparent !important;
  border-color: var(--ui-primary) !important;
  color: var(--ui-primary) !important;
}

.btn-outline-ui-primary:hover {
  background-color: var(--ui-primary) !important;
  color: white !important;
}

.bg-ui-primary {
  background-color: var(--ui-primary) !important;
  color: white !important;
}

.bg-ui-primary-light {
  background-color: var(--ui-primary-light) !important;
  color: var(--ui-primary-dark) !important;
}

.text-ui-primary {
  color: var(--ui-primary) !important;
}

.border-ui-primary {
  border-color: var(--ui-primary) !important;
}

/* === UI SECONDARY CLASSES (Slate) === */

.btn-ui-secondary {
  background-color: var(--ui-secondary) !important;
  border-color: var(--ui-secondary) !important;
  color: white !important;
}

.btn-ui-secondary:hover {
  background-color: var(--ui-secondary-dark) !important;
  border-color: var(--ui-secondary-dark) !important;
  color: white !important;
}

.btn-outline-ui-secondary {
  background-color: transparent !important;
  border-color: var(--ui-secondary) !important;
  color: var(--ui-secondary) !important;
}

.btn-outline-ui-secondary:hover {
  background-color: var(--ui-secondary) !important;
  color: white !important;
}

.bg-ui-secondary {
  background-color: var(--ui-secondary) !important;
  color: white !important;
}

.bg-ui-secondary-light {
  background-color: var(--ui-secondary-light) !important;
  color: var(--ui-secondary-dark) !important;
}

.text-ui-secondary {
  color: var(--ui-secondary) !important;
}

/* === UI ACCENT CLASSES (Rose) === */

.btn-ui-accent {
  background-color: var(--ui-accent) !important;
  border-color: var(--ui-accent) !important;
  color: white !important;
}

.btn-ui-accent:hover {
  background-color: var(--ui-accent-dark) !important;
  border-color: var(--ui-accent-dark) !important;
  color: white !important;
}

.bg-ui-accent {
  background-color: var(--ui-accent) !important;
  color: white !important;
}

.bg-ui-accent-light {
  background-color: var(--ui-accent-light) !important;
  color: var(--ui-accent-dark) !important;
}

/* === FEEDBACK CLASSES === */

/* Info (Cyan) */
.btn-feedback-info {
  background-color: var(--feedback-info) !important;
  border-color: var(--feedback-info) !important;
  color: white !important;
}

.bg-feedback-info {
  background-color: var(--feedback-info) !important;
  color: white !important;
}

.bg-feedback-info-light {
  background-color: var(--feedback-info-light) !important;
  color: var(--feedback-info-dark) !important;
}

.text-feedback-info {
  color: var(--feedback-info) !important;
}

/* Success (Emerald) */
.btn-feedback-success {
  background-color: var(--feedback-success) !important;
  border-color: var(--feedback-success) !important;
  color: white !important;
}

.bg-feedback-success {
  background-color: var(--feedback-success) !important;
  color: white !important;
}

.bg-feedback-success-light {
  background-color: var(--feedback-success-light) !important;
  color: var(--feedback-success-dark) !important;
}

.text-feedback-success {
  color: var(--feedback-success) !important;
}

.btn-outline-feedback-success {
  background-color: transparent !important;
  border-color: var(--feedback-success) !important;
  color: var(--feedback-success) !important;
}

.btn-outline-feedback-success:hover {
  background-color: var(--feedback-success) !important;
  color: white !important;
}

/* Warning (Orange) */
.btn-feedback-warning {
  background-color: var(--feedback-warning) !important;
  border-color: var(--feedback-warning) !important;
  color: white !important;
}

.bg-feedback-warning {
  background-color: var(--feedback-warning) !important;
  color: white !important;
}

.bg-feedback-warning-light {
  background-color: var(--feedback-warning-light) !important;
  color: var(--feedback-warning-dark) !important;
}

.text-feedback-warning {
  color: var(--feedback-warning) !important;
}

/* Error/Danger (Red) */
.btn-feedback-error {
  background-color: var(--feedback-error) !important;
  border-color: var(--feedback-error) !important;
  color: white !important;
}

.btn-feedback-error:hover {
  background-color: var(--feedback-error-dark) !important;
  border-color: var(--feedback-error-dark) !important;
  color: white !important;
}

.btn-outline-feedback-error {
  background-color: transparent !important;
  border-color: var(--feedback-error) !important;
  color: var(--feedback-error) !important;
}

.btn-outline-feedback-error:hover {
  background-color: var(--feedback-error) !important;
  color: white !important;
}

.bg-feedback-error {
  background-color: var(--feedback-error) !important;
  color: white !important;
}

.bg-feedback-error-light {
  background-color: var(--feedback-error-light) !important;
  color: var(--feedback-error-dark) !important;
}

.text-feedback-error {
  color: var(--feedback-error) !important;
}

/* Chart.js external tooltip (prevents clipping inside small canvases) */
.chartjs-external-tooltip {
  position: absolute;
  z-index: 1080; /* above Bootstrap popovers/tooltips */
  background: rgba(17, 24, 39, 0.95);
  color: rgba(255, 255, 255, 0.95);
  padding: 0.35rem 0.5rem;
  border-radius: 0.5rem;
  font-size: 0.75rem;
  line-height: 1.1;
  white-space: nowrap;
  pointer-events: none;
  transform: translate(-50%, -110%);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.25);
}

/* === STANDARDS REORDER DRAG-AND-DROP === */
.drag-handle {
  padding: 0.5rem;
  cursor: grab;
  color: var(--ui-secondary);
  /* Prevent the browser from scrolling when a touch starts on the handle. */
  touch-action: none;
}

.drag-handle:hover {
  color: var(--ui-primary);
}

.drag-handle:active {
  cursor: grabbing;
}

/* Touch devices: enlarge drag-handle + adjacent checkbox to a 44x44 target. */
@media (pointer: coarse) {
  .drag-handle {
    padding: 0.75rem;
    min-width: 44px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  .form-check-input.reorder-select {
    width: 1.25rem;
    height: 1.25rem;
    margin-right: 0.5rem;
  }
}

/* Selected item highlight for multi-select */
.list-group-item.selected {
  background-color: var(--ui-primary-light);
  border-left: 3px solid var(--ui-primary);
}

/* Selected roster row highlight (Student Assessments multi-select). Uses an
   inset box-shadow instead of border-left to avoid row layout shift, and wins
   over Bootstrap's .table-hover state background. */
.table-hover > tbody > tr.roster-row-selected,
tr.roster-row-selected {
  background-color: var(--ui-primary-light);
  box-shadow: inset 3px 0 0 var(--ui-primary);
}

/* Decorative color dot for the "Select…" smart-select menu items; the level
   name is the accessible label (the dot is aria-hidden). */
.smart-select-dot {
  display: inline-block;
  width: 0.7rem;
  height: 0.7rem;
  border-radius: 50%;
  margin-right: 0.35rem;
  vertical-align: middle;
}

/* Sticky bulk-action bar above the roster (selection count + bulk set + smart
   select). Sticks to the top of the scroll area so actions stay reachable. */
.roster-action-bar {
  position: sticky;
  top: 0;
  z-index: 1020;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  background-color: #fff;
  border: 1px solid var(--neutral-200);
  border-radius: 0.5rem;
}

/* A row with a staged (unsaved) outcome-level change: soft yellow, matching the
   "New Assessment" pending state. Wins over .table-hover; when a row is both
   selected and staged, show both the teal (selection) and amber (staged) bars. */
.table-hover > tbody > tr.roster-row-staged,
tr.roster-row-staged {
  background-color: var(--outcome-low-light);
  box-shadow: inset 3px 0 0 var(--outcome-low);
}

.table-hover > tbody > tr.roster-row-selected.roster-row-staged,
tr.roster-row-selected.roster-row-staged {
  box-shadow: inset 3px 0 0 var(--ui-primary), inset 6px 0 0 var(--outcome-low);
}

/* One-click quick-set level pills (per row). Each pill carries its level color
   in --pill-color; the active pill (the student's effective level) fills with it.
   The compact "previous" pill in the progression display reuses .is-active. */
.level-pills {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
}

.level-pill {
  border: 1px solid var(--neutral-200);
  background-color: #fff;
  color: var(--neutral-500);
  border-radius: 2rem;
  padding: 0.15rem 0.55rem;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 1.4;
  white-space: nowrap;
  cursor: pointer;
}

.level-pill:hover {
  border-color: var(--neutral-500);
  color: var(--neutral-700);
}

.level-pill.is-active {
  background-color: var(--pill-color);
  border-color: var(--pill-color);
  color: #fff;
}

.level-pill--static {
  cursor: default;
}

.level-pill-clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.45rem;
  height: 1.45rem;
  padding: 0;
  border: 1px solid var(--neutral-200);
  border-radius: 50%;
  background-color: #fff;
  color: var(--neutral-500);
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
}

.level-pill-clear:hover {
  border-color: var(--feedback-warning);
  color: var(--feedback-warning);
}

/* Arrow between the previous and new level in the progression display. */
.pending-arrow {
  color: var(--neutral-500);
  margin: 0 0.3rem;
}

/* Note column: envelope buttons (add / view) + a remove ×. */
.note-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.15rem 0.3rem;
  border: 2px solid transparent; /* reserve room so the outlined state doesn't shift */
  border-radius: 0.375rem;
  background: none;
  color: var(--note-color);
  font-size: 0.95rem;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
}
.note-btn:hover {
  color: var(--note-color-dark);
}
/* The "add" envelope (no note yet) is muted until hovered. */
.note-add {
  color: var(--ui-secondary);
}
/* A new (staged) note: outline the envelope in the assessed level's color. The
   envelope itself stays the note color, so it matches what the student sees. */
.note-edit {
  border-color: var(--note-accent, var(--note-color));
}
.note-x {
  border: 0;
  background: none;
  padding: 0 0.15rem;
  color: var(--ui-secondary);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}
.note-x:hover {
  color: var(--feedback-danger, #dc3545);
}

/* A teacher note on the student's standard card. White with a note-colored edge,
   so it stands apart from both the pale Proficiency Guide alert and the tinted
   level box it sits in. */
.teacher-note {
  display: flex;
  padding: 0.75rem 1rem;
  margin-bottom: 1rem;
  background-color: #fff;
  border: 1px solid var(--neutral-200);
  border-left: 4px solid var(--note-color);
  border-radius: 0.5rem;
}
.teacher-note__icon {
  color: var(--note-color);
}

/* The student summary table's Note column: the envelope plus the note's date. */
.note-indicator {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  color: var(--note-color);
  white-space: nowrap;
}
.note-indicator__date {
  font-size: 0.8rem;
  color: var(--neutral-600);
}

/* Amber "unsaved" tag shown in the Last-updated cell while a row is staged. */
.staged-tag {
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--outcome-low-dark);
}

/* Recipient chips in the "Send note" composer. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.15rem 0.6rem;
  background-color: var(--ui-secondary-light);
  border: 1px solid var(--neutral-200);
  border-radius: 2rem;
  font-size: 0.8rem;
  font-weight: 600;
}

.chip-remove {
  border: 0;
  background: none;
  padding: 0 0 0 0.1rem;
  color: var(--neutral-500);
  line-height: 1;
  cursor: pointer;
}

.chip-remove:hover {
  color: var(--feedback-warning);
}

/* A single note in the notes-viewer modal. */
.note-card {
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--neutral-200);
  border-radius: 0.5rem;
}

.note-card + .note-card {
  margin-top: 0.75rem;
}

/* Unsaved-changes bar at the bottom of the assessments card. */
.pending-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
  padding: 0.6rem 0.9rem;
  background-color: var(--outcome-low-light);
  border: 1px solid var(--outcome-low);
  border-radius: 0.5rem;
}

/* Non-assessment mode: the class-page standard rows have no Class Progress bar,
   so tighten their vertical padding for a slimmer, denser list. */
.class-standard-row--compact {
  padding-top: 0.4rem;
  padding-bottom: 0.4rem;
}

/* Whole-card drag (used on the LMS classes index) — prevent the browser
   from treating the mouse-drag as a text selection. The card is the drag
   target; users don't expect to select its inner text. */
[data-class-order-target="card"] {
  user-select: none;
  -webkit-user-select: none;
  cursor: grab;
}

[data-class-order-target="card"]:active,
[data-class-order-target="card"].sortable-chosen,
[data-class-order-target="card"].sortable-drag {
  cursor: grabbing;
}

/* Standards reorder rows — same text-selection suppression. With
   forceFallback: true on SortableJS, the browser still kicks off its
   native text-selection gesture while dragging unless we opt out.
   Matches whether data-controller sits on the .list-group (class-show)
   or on an outer wrapper (Manage Standards hub). */
[data-controller="standards-reorder"] .list-group-item {
  user-select: none;
  -webkit-user-select: none;
}

/* Sortable.js drag states */
.sortable-ghost {
  opacity: 0.4;
  background-color: var(--ui-secondary-light);
}

.sortable-chosen {
  background-color: var(--ui-primary-light);
}

.sortable-drag {
  background-color: white;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

/* Multi-drag: rows selected for group-move. */
.sortable-selected {
  background-color: var(--ui-primary-light) !important;
  outline: 2px solid var(--ui-primary);
  outline-offset: -2px;
}

/* === MOBILE FOUNDATION === */

/* Wrapper that offsets content below the fixed-top navbar.
   env(safe-area-inset-top) handles notches / dynamic islands.
   Replaces an inline style on the layout's wrapper div. */
.navbar-content-offset {
  padding-top: calc(env(safe-area-inset-top, 0px) + 70px);
}

/* Mobile: the navbar wraps the brand text under the logo and grows to
   ~90-100px tall. Bump the offset so the flash + page heading aren't
   hidden under the navbar. */
@media (max-width: 991.98px) {
  .navbar-content-offset {
    padding-top: calc(env(safe-area-inset-top, 0px) + 100px);
  }
}

/* Scroll offset for in-page jump targets. The pie chart on Standards#show links
   down to the Student Assessments roster; without this the fixed navbar covers
   the card's header on arrival. Values track .navbar-content-offset above and
   .back-overlay below, so all three move together if the navbar height changes. */
#student-assessments-card {
  scroll-margin-top: calc(env(safe-area-inset-top, 0px) + 78px);
}

/* Mobile: same taller-navbar bump as the two rules that bracket this one. */
@media (max-width: 991.98px) {
  #student-assessments-card {
    scroll-margin-top: calc(env(safe-area-inset-top, 0px) + 108px);
  }
}

/* Returning from a student preview anchors on that student's row, so it needs
   the same navbar clearance as the card above. */
[id^="student-row-"] {
  scroll-margin-top: calc(env(safe-area-inset-top, 0px) + 78px);
}

@media (max-width: 991.98px) {
  [id^="student-row-"] {
    scroll-margin-top: calc(env(safe-area-inset-top, 0px) + 108px);
  }
}

/* Floating Back control: a deterministic real link (works with JS disabled),
   pinned just below the fixed navbar at top-left. CSS handles the floating; the
   markup is a plain <a href>, so no JavaScript is required to navigate. */
.back-overlay {
  position: fixed;
  top: calc(env(safe-area-inset-top, 0px) + 78px);
  left: 0.5rem;
  z-index: 1020;
}

/* A plain link, not a button. The control floats over page content and over the
   teacher-preview banner, and the opaque white pill it used to carry punched a
   hole in both. (The old padding here never applied anyway -- the anchor carries
   Bootstrap's p-0, which is !important. border was redundant: .btn-link already
   sets a transparent border-colour. border-radius only shaped the focus ring.)

   The colour is deliberately not Bootstrap's link blue. #0d6efd is 4.50:1 on
   white but only 4.09:1 on alert-warning (the preview banner) and 3.37:1 on
   alert-danger -- below AA everywhere this control can land on an alert. Once
   the white backing is gone that matters, and --ui-primary-dark clears 5.2:1 on
   every one of them while matching the navbar.

   The :hover/:focus/:active selectors are NOT redundant: the layout loads
   bootstrap.min.css a second time via stylesheet_link_tag :app, i.e. AFTER this
   file, so `.btn:hover` ties on specificity and wins on source order. Without
   them the colour flips back to blue mid-interaction. Same reason as the
   html:root note at the top of this file. */
.back-overlay .btn,
.back-overlay .btn:hover,
.back-overlay .btn:focus,
.back-overlay .btn:active {
  color: var(--ui-primary-dark);
}

/* Reads as a link: underlined on hover and on keyboard focus. */
.back-overlay .btn:hover,
.back-overlay .btn:focus-visible {
  text-decoration: underline;
}

/* With the pill gone, .btn-link's faint box-shadow ring is hard to see against a
   pale background, so give keyboard focus a solid outline instead. */
.back-overlay .btn:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
  box-shadow: none;
}

@media (max-width: 991.98px) {
  .back-overlay {
    top: calc(env(safe-area-inset-top, 0px) + 108px);
  }
}

/* The floating Back control is fixed at the same height as this full-bleed
   banner, so the banner's own content has to start clear of it. Previously the
   control's opaque white pill simply covered whatever it landed on, which hid
   the collision rather than avoiding it. 4.5rem clears the control's ~3.6rem
   width plus its 0.5rem offset. The banner only renders while previewing a
   student, where the Back control is always present, so this needs no guard. */
.preview-banner .container {
  padding-left: 4.5rem;
}

/* The banner rides with the navbar instead of scrolling away. A teacher reading
   a student's page is looking at the student's view pixel for pixel, so the
   reminder of whose page it is has to survive scrolling -- that is the whole
   reason the banner exists, and it was only true at the top of the page.

   Sticky rather than fixed: it keeps its space in normal flow, so nothing below
   needs a compensating offset, and it can never double up with the navbar's own
   spacing. top: is the 78px/108px the navbar actually measures -- the same pair
   .back-overlay and the scroll-margin rules above already use, and part of the
   set the comments there say must move together. (.navbar-content-offset's
   70px/100px padding is 8px shy of that; sticking at 70px tucks the banner's top
   edge behind the navbar, which outranks it at z-index 1030.)

   z-index sits BELOW .back-overlay's 1020 on purpose. The banner spans the full
   width, including the strip the floating Back control occupies, and it comes
   later in the DOM -- at an equal or higher value it would paint over the Back
   link and swallow the control.

   Selector is .alert.preview-banner, not .preview-banner: Bootstrap's own
   `.alert { position: relative }` ties on specificity and wins on source order,
   because the layout loads bootstrap.min.css again via stylesheet_link_tag :app
   after this file. A single class here computes to position: relative and the
   banner scrolls away. Same trap as the .back-overlay colour rules above. */
.alert.preview-banner {
  position: sticky;
  top: calc(env(safe-area-inset-top, 0px) + 78px);
  z-index: 1010;
}

@media (max-width: 991.98px) {
  .alert.preview-banner {
    top: calc(env(safe-area-inset-top, 0px) + 108px);
  }
}

/* Prevent iOS Safari from zooming the page when focusing a form input.
   iOS auto-zooms when the input's computed font-size is < 16px;
   Bootstrap's form-select-sm / form-control-sm both set 0.875rem
   (≈ 14px), which trips the zoom. Force 16px on small viewports
   so the picker renders in place without a viewport shift. Desktop
   is unaffected. */
@media (max-width: 991.98px) {
  .form-select,
  .form-select-sm,
  .form-control,
  .form-control-sm,
  textarea,
  input[type="text"],
  input[type="email"],
  input[type="password"],
  input[type="search"],
  input[type="number"],
  input[type="tel"],
  input[type="url"],
  input[type="date"] {
    font-size: 16px;
  }
}

/* Force native <select> rendering on mobile.
   Bootstrap's .form-select sets `appearance: none` to draw its own
   chevron via background-image. On Android Chrome that triggers a
   broken inline-fallback popup (tiny, floats at the top-left of the
   content area instead of anchored to the <select>). Forcing
   `appearance: auto` makes the browser use its native picker UI.
   We pay the cost of the browser's default arrow (in place of
   Bootstrap's custom chevron) on mobile only — desktop keeps the
   curated Bootstrap visual. Tag-qualified selector (`select.…`)
   guarantees we beat Bootstrap's class-only rule on specificity. */
@media (max-width: 991.98px) {
  select.form-select,
  select.form-select-sm {
    appearance: auto !important;
    -webkit-appearance: auto !important;
    -moz-appearance: auto !important;
    background-image: none !important;
    padding-right: 0.75rem !important;
  }
}

/* Long URLs inside alert cards (e.g. External Resource block on resources/show)
   wrap instead of overflowing. */
.alert a,
.alert-link {
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* Tables that should collapse to stacked "cards" below 576px.
   Each <tr> becomes a block; each <td> shows its column label via data-label. */
@media (max-width: 575.98px) {
  .table-stack-sm thead {
    border: 0;
    clip: rect(0 0 0 0);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    width: 1px;
  }

  .table-stack-sm,
  .table-stack-sm tbody,
  .table-stack-sm tr,
  .table-stack-sm td {
    display: block;
    width: 100% !important;
  }

  .table-stack-sm tr {
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: 0.5rem;
    margin-bottom: 0.75rem;
    padding: 0.5rem 0.75rem;
    background-color: #fff;
  }

  .table-stack-sm td {
    border: 0;
    padding: 0.4rem 0;
  }

  .table-stack-sm td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-weight: 600;
    font-size: 0.75rem;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--ui-secondary);
    margin-bottom: 0.15rem;
  }
}

/* Right-edge fade shadow on .table-responsive containers that are scrolling
   horizontally — hints at off-screen columns on mobile. */
.table-scroll-shadow {
  position: relative;
}

.table-scroll-shadow::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 2rem;
  pointer-events: none;
  background: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(0, 0, 0, 0.08));
  opacity: 1;
  transition: opacity 150ms linear;
}

.table-scroll-shadow.at-right-edge::after {
  opacity: 0;
}

/* Add-standards / Copy / class-picker sheets: a right-side drawer on desktop,
   a bottom sheet on mobile (see the media query below). The class-picker sheet
   reuses these rules via the shared .add-standards-picker class + its own id. */
.add-standards-picker,
#manage-class-picker-sheet {
  width: min(28rem, 100vw);
}

/* The form wraps the body + footer, so it (not the body) is the offcanvas's
   flex child. Make it fill the panel as a column so the body scrolls and the
   footer (with the submit button) stays pinned to the bottom. Without this the
   body doesn't scroll and the footer is pushed off-screen. */
.add-standards-picker form {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}

.add-standards-picker .offcanvas-body {
  min-height: 0;
}

.add-standards-picker .standards-picker-row.is-added {
  opacity: 0.6;
}

/* On small screens, repurpose the offcanvas-end drawer as a bottom sheet by
   re-anchoring it and flipping the slide-in transform to slide up. Bootstrap
   toggles .showing/.show to clear the transform. */
@media (max-width: 767.98px) {
  .add-standards-picker,
  #manage-class-picker-sheet {
    width: 100%;
    height: auto;
    max-height: 85vh;
    top: auto;
    right: 0;
    left: 0;
    bottom: 0;
    border-top-left-radius: var(--bs-border-radius-lg, 0.5rem);
    border-top-right-radius: var(--bs-border-radius-lg, 0.5rem);
    transform: translateY(100%);
  }

  .add-standards-picker.showing,
  .add-standards-picker.show,
  #manage-class-picker-sheet.showing,
  #manage-class-picker-sheet.show {
    transform: none;
  }
}

/* Manage Standards hub — standard row layout.
   Desktop reproduces the original look: code + badges + muted title wrap inline
   on one line, with the Class Progress bar forced onto its own line below. */
.standards-row-content {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: 0.5rem;
}

.standards-row-content > .standards-row-progress {
  flex: 0 0 100%;
}

/* Mobile (<768px): stacked card. The content wrapper dissolves (display:contents)
   so its children join the row's flex line alongside the checkbox, drag handle,
   and remove ×; order + full-width basis lay them out as:
   [check, handle, code, ×] on top, then title, then the progress bar. */
@media (max-width: 767.98px) {
  [data-controller="standards-reorder"] .list-group-item {
    flex-wrap: wrap;
    align-items: center !important; /* beats the .align-items-start utility */
    column-gap: 0.5rem;
  }

  .standards-row-content {
    display: contents;
  }

  .standards-row-check { order: 0; }
  .standards-row-handle { order: 1; }
  .standards-row-code {
    order: 2;
    flex: 1 1 auto;
    min-width: 0;
  }
  .standards-row-remove {
    order: 3;
    margin-left: 0 !important;
  }
  .standards-row-title { order: 4; flex: 0 0 100%; }
  .standards-row-progress { order: 5; flex: 0 0 100%; }

  /* The action bar is always visible; it floats at the bottom of the viewport
     on mobile. position:fixed is independent of display, so no JS change needed. */
  .manage-action-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1030;
    margin-bottom: 0 !important;
    border-radius: 0 !important;
    box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.12);
    padding-bottom: calc(0.5rem + env(safe-area-inset-bottom, 0px)) !important;
  }

  /* Reserve space so the floating bar never hides the last row. */
  [data-controller="standards-reorder"] {
    padding-bottom: calc(4.5rem + env(safe-area-inset-bottom, 0px));
  }
}

/* Desktop: the action bar sticks to the top of the standards list as the
   teacher scrolls, so a selection stays actionable on a long list without
   scrolling back up to reach the buttons. Below 768px it is already fixed to
   the bottom of the viewport (rule above), so this starts where that stops.

   The bar is a child of the [data-controller="standards-reorder"] wrapper,
   which also holds the list, so it travels with the list and scrolls away at
   the end of it rather than following the user down the whole page.

   top: clears the fixed navbar, tracking the same values as
   .navbar-content-offset and .back-overlay above. Sticking at top: 0 would
   slide the bar under the navbar, which is what .roster-action-bar does. */
@media (min-width: 768px) {
  .manage-action-bar {
    position: sticky;
    top: calc(env(safe-area-inset-top, 0px) + 108px);
    z-index: 1020;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
  }
}

/* The navbar drops back to a single row at 992px, matching the breakpoint on
   .navbar-content-offset, so the bar can sit higher. */
@media (min-width: 992px) {
  .manage-action-bar {
    top: calc(env(safe-area-inset-top, 0px) + 78px);
  }
}

/* ============================================================
   Resource entries — rich (expanded) vs. compact (collapsed)
   density, used in the standards outcome-level view.
   ============================================================ */
.resource-entry {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  padding: 0.4rem 0.5rem;
  border-radius: 0.375rem;
  transition: background-color 120ms linear;
}
.resource-entry + .resource-entry {
  border-top: 1px solid var(--bs-border-color, #dee2e6);
}
.resource-entry:hover {
  background-color: var(--ui-secondary-light, #f1f3f5);
}

/* Shared checkbox column — always visible in both densities. */
.resource-entry__check {
  flex: 0 0 auto;
  width: 1.5rem;
  padding-top: 0.15rem;
}

/* min-width:0 lets the text-truncate children actually ellipsize inside flex. */
.resource-entry__presentations,
.resource-entry__body {
  min-width: 0;
}

.resource-entry__title {
  display: inline-block;
  max-width: 100%;
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.25;
  text-decoration: none;
}
.resource-entry__title:hover {
  text-decoration: underline;
}

.resource-entry__thumb {
  width: 128px;
  height: 72px;
  overflow: hidden;
  border-radius: 0.375rem;
  background-color: var(--ui-secondary-light, #f1f3f5);
}
.resource-entry__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.resource-entry__modality {
  position: absolute;
  left: 0.25rem;
  bottom: 0.25rem;
  padding: 0.05rem 0.35rem;
  font-size: 0.65rem;
  font-weight: 600;
  color: #fff;
  background-color: rgba(0, 0, 0, 0.65);
  border-radius: 0.25rem;
  text-transform: capitalize;
}
.resource-entry__preview {
  max-width: 100%;
}

.resource-entry__rich {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
}

/* Density switching. A collapsed level section (.is-compact, toggled by the
   level-collapse Stimulus controller) shows its rows as compact one-liners instead
   of rich rows. Custom flex (not the d-flex utility) so display:none can win. */
.resource-entry__compact {
  display: none;
}
.is-compact .resource-entry {
  align-items: center;
}
.is-compact .resource-entry__rich {
  display: none;
}
.is-compact .resource-entry__compact {
  display: block;
}

/* Visible keyboard focus for interactive children. */
.resource-entry a:focus-visible,
.resource-entry input:focus-visible {
  outline: 2px solid var(--ui-primary, #0d6efd);
  outline-offset: 2px;
}

/* Below ~640px: smaller thumbnail, drop the secondary meta column. */
@media (max-width: 639.98px) {
  .resource-entry__thumb {
    width: 88px;
    height: 50px;
  }
  .resource-entry__meta {
    display: none;
  }
  .resource-entry__title {
    font-size: 1rem;
  }
}

/* One-line "Additional resources" disclosure: folds every non-current outcome
   level behind a single toggle below the student's current-rating section. Uses
   Bootstrap collapse (aria-expanded lives on the button); the chevron rotates to
   match, mirroring the .level-header chevron pattern. */
.additional-resources {
  margin-bottom: 0.75rem;
}
.additional-resources__toggle {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.5rem 0.85rem;
  background: transparent;
  border: 0;
  text-align: left;
  color: var(--ui-secondary-dark, #475569);
  font-weight: 600;
  cursor: pointer;
}
.additional-resources__toggle:hover {
  color: var(--bs-body-color, #212529);
}
.additional-resources__toggle:focus-visible {
  outline: 2px solid var(--ui-primary, #0d6efd);
  outline-offset: -2px;
}
.additional-resources__toggle .chevron {
  font-size: 0.8rem;
  color: var(--ui-secondary, #6c757d);
  transition: transform 150ms ease;
  transform: rotate(-90deg);
}
.additional-resources__toggle[aria-expanded="true"] .chevron {
  transform: rotate(0deg);
}

/* ---- Collapsible proficiency-level sections ---- */
.level-section {
  border: 1px solid var(--bs-border-color, #dee2e6);
  border-left: 4px solid var(--ui-secondary, #6c757d); /* color overridden inline per --outcome-* */
  border-radius: 0.375rem;
  margin-bottom: 0.75rem;
  overflow: hidden;
}
.level-header {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  width: 100%;
  padding: 0.6rem 0.85rem;
  background-color: #f8f9fa;
  border: 0;
  text-align: left;
  font-size: 1.1rem;
  font-weight: 600;
  color: inherit;
  cursor: pointer;
}

/* Per-type count badges: only while the level is collapsed, wrapping on narrow
   screens. Modality counts belong on the group sub-headers (Story 9), not here. */
.level-header__type-counts {
  display: none;
}
.level-section.is-compact .level-header__type-counts {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.75rem;
  font-weight: 400;
}
.level-header:hover {
  background-color: var(--ui-secondary-light, #f1f3f5);
}
.level-header:focus-visible {
  outline: 2px solid var(--ui-primary, #0d6efd);
  outline-offset: -2px;
}
.level-header .chevron {
  font-size: 0.8rem;
  color: var(--ui-secondary, #6c757d);
  transition: transform 150ms ease;
}
.level-section.is-compact .level-header .chevron {
  transform: rotate(-90deg);
}
.level-header__note {
  font-size: 0.8rem;
}
.level-header__count {
  margin-left: auto;
  font-weight: 600;
}
.level-body {
  padding: 0.35rem 0.85rem 0.5rem;
}

/* Student's assessed level: the whole box is outlined (thicker left edge) and filled
   in the assessed level's color — that color is the "which rating did I get?" signal.
   --level-accent / --level-accent-light are set inline per level. */
.level-section--assessed {
  border: 2px solid var(--level-accent, var(--ui-secondary));
  border-left-width: 8px;
  background-color: var(--level-accent-light, var(--ui-secondary-light));
}
.level-section--assessed .level-header {
  background-color: transparent;
}
.level-header__pill {
  margin-left: 0.25rem;
  font-weight: 600;
}
/* Rating chips in a merged Beginning + Not Yet Proficient header. */
.level-chip {
  margin-right: 0.3rem;
  font-size: 0.9rem;
  vertical-align: middle;
}
.level-section__description {
  padding: 0 0.85rem 0.4rem;
}

/* Modality sub-headers within a level (shown in both densities). */
.modality-group + .modality-group {
  margin-top: 0.4rem;
}
.modality-group__header {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.15rem 0.25rem;
  border-bottom: 1px solid var(--bs-border-color, #dee2e6);
  color: var(--ui-secondary-dark, #475569);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}
.modality-group__count {
  min-width: 1.2rem;
  padding: 0 0.35rem;
  border-radius: 0.75rem;
  background-color: var(--ui-secondary-light, #f1f5f9);
  color: var(--ui-secondary-dark, #475569);
  text-align: center;
  font-size: 0.68rem;
}
.modality-group__select-all {
  margin: 0;
  cursor: pointer;
}
