/*
 * mobile.css — SUrriculum mobile UI layer.
 *
 * FROZEN-DESKTOP RULE: every selector in this file MUST be scoped under
 * `body.is-mobile`. Nothing here may affect the desktop build. The
 * `is-mobile` class is toggled by the viewport-mode controller composed by
 * mobile.js, and the active screen is tracked by the `data-mobile-tab` attribute on
 * <body> (values: planner | controls).
 *
 * Sections are added here one at a time: shell/nav (below), then planner,
 * controls, progress, scheduler.
 */

/* ============================================================
 * SHELL — compact header, screen switching, bottom tab bar
 * ============================================================ */

/* Hide desktop-only chrome that the mobile shell replaces. */
body.is-mobile .sidebar-toggle { display: none; }
body.is-mobile .mobile-notice { display: none !important; }
body.is-mobile .footer { display: none; }

/* The desktop shell is `.app { height: 100vh }` with the injected bottom nav as
   its last flex child. On mobile browsers 100vh is the *large* viewport (as if
   the URL bar were hidden), so the nav lands below the visible area and only
   appears once the URL bar retracts. Size the shell to the dynamic viewport
   height so the nav is always on-screen; 100vh stays as a fallback. */
body.is-mobile .app {
    height: 100vh;
    height: 100dvh;
}

/* --- Compact header + collapsible actions across the whole mobile range
 * (mirrors the existing <=640px behaviour, but keyed on is-mobile). --- */
body.is-mobile .header {
    height: 56px;
    padding: 0 12px;
    gap: 10px;
}
body.is-mobile .header-title {
    font-size: 1.1rem;
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
body.is-mobile .header-controls {
    justify-content: flex-end;
    gap: 8px;
}
body.is-mobile .header-more {
    display: inline-flex;
}
body.is-mobile .header-actions {
    display: none;
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    width: min(92vw, 420px);
    padding: 12px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    z-index: 120;
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
}
body.is-mobile .header-controls.is-open .header-actions {
    display: flex;
}
body.is-mobile .header-actions .btn {
    width: 100%;
    justify-content: center;
}
body.is-mobile .header-actions .plan-dropdown,
body.is-mobile .header-actions .import-dropdown {
    position: static;
    width: 100%;
    right: auto;
    top: auto;
    margin-top: 10px;
}

/* --- Screen switching: Planner shows the board, Controls shows the
 * sidebar full-screen. Only one is visible at a time. --- */
body.is-mobile[data-mobile-tab="planner"] .sidebar { display: none; }
body.is-mobile[data-mobile-tab="planner"] .board {
    margin-left: 0;
    width: 100%;
    /* The desktop board animates its sidebar offset. Mobile screen switching
       has no sidebar beside the planner, so carrying that transition across
       briefly squeezes the board from --sidebar-width down to zero during
       startup/resizes and can make otherwise valid headers overlap. */
    transition: none;
}

body.is-mobile[data-mobile-tab="controls"] .board { display: none; }
body.is-mobile[data-mobile-tab="controls"] .sidebar {
    display: flex;
    position: absolute;
    inset: 0;
    width: 100%;
    transform: none;
    border-right: none;
    z-index: 6;
}

/* --- Bottom tab bar (injected by navigation-progress.js). Hidden on desktop. --- */
.m-nav { display: none; }
body.is-mobile .m-nav {
    display: flex;
    flex-shrink: 0;
    height: 58px;
    background: var(--bg-card);
    border-top: 1px solid var(--border);
    z-index: 50;
}
.m-nav-item {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    padding: 6px 0;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text-muted);
    font-size: 0.68rem;
    font-weight: 500;
    font-family: inherit;
    transition: color 0.15s ease;
}
.m-nav-item i {
    font-size: 1.2rem;
    pointer-events: none;
}
.m-nav-item.active {
    color: var(--mobile-nav-active-text);
}

/* ============================================================
 * PLANNER — vertical accordion of semesters
 * ============================================================ */

/* Board: horizontal column strip -> vertical scrolling stack. */
body.is-mobile[data-mobile-tab="planner"] .board {
    flex-direction: column;
    flex-wrap: nowrap;
    overflow-x: hidden;
    overflow-y: auto;
    gap: 12px;
    padding: 12px;
}

/* Each semester becomes a full-width stacked card (was a fixed-width,
   full-height column). */
body.is-mobile[data-mobile-tab="planner"] .container_semester {
    flex: 0 0 auto;
    width: 100%;
    height: auto;
    overflow: visible;
    margin: 0;
    /* planner-accordion.js negates the persisted/desktop index so the latest semester is
       presented first on the vertical planner without mutating saved order. */
    order: var(--m-order, 0);
}
body.is-mobile[data-mobile-tab="planner"] .add-semester-ghost {
    flex: 0 0 auto;
    width: 100%;
    height: auto;
    min-height: 56px;
    margin: 0;
    /* Adding a semester is the first planner action on mobile, immediately
       above the newest-first card stack. */
    order: -9999;
}

/* Header = colored credits bar + name row (both always visible). */
body.is-mobile .subcontainer_semester {
    padding: 10px 12px;
    gap: 8px;
    overflow: visible;
    /* Content-sized (desktop uses flex:1 to fill the column height) so the
       box encloses all courses + add-course and the credits footer lands
       truly last. */
    flex: 0 0 auto;
}
body.is-mobile .subcontainer_semester .date {
    cursor: pointer;
    padding: 2px 0;
}
body.is-mobile .container_semester .total_credit {
    cursor: pointer;
}
body.is-mobile .subcontainer_semester .date p {
    font-size: 0.95rem;
}

/* Semester cards already expose explicit up/down actions on mobile. The drag
   grip belongs to the horizontal desktop board and only crowds the accordion
   header when it is shown on a phone. */
body.is-mobile .subcontainer_semester .semester_drag {
    display: none !important;
}

body.is-mobile .course_drag,
body.is-mobile .course-drop-placeholder {
    display: none !important;
}

body.is-mobile .course.course-dragging,
body.is-mobile .container_semester.course-drop-target,
body.is-mobile .container_semester.semester-dragging,
body.is-mobile .container_semester.semester-drop-target {
    opacity: 1;
    box-shadow: var(--shadow-sm);
}

body.is-mobile .container_semester.semester-drop-target::before,
body.is-mobile .container_semester.semester-drop-target::after {
    display: none !important;
}

/* Chevron affordance (injected into .icons by planner-accordion.js). */
.m-sem-chevron {
    display: none;
}
/* Font Awesome is loaded after this stylesheet and gives every `.fa-solid`
   icon an inline display value. Use a mode-qualified selector so its generic
   rule cannot expose this mobile-only accordion affordance on desktop. */
body:not(.is-mobile) .m-sem-chevron {
    display: none;
}
body.is-mobile .m-sem-chevron {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--text-muted);
    font: inherit;
    cursor: pointer;
    transition: transform 0.2s ease;
}
body.is-mobile .m-sem-chevron:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}
body.is-mobile .container_semester:not(.m-collapsed) .m-sem-chevron {
    transform: rotate(180deg);
}

/* Escape desktop's fixed-height, internally-scrolling column model: each card
   and its body size to content in normal block flow, so the course list and
   Add-course button can't overflow their card. */
body.is-mobile[data-mobile-tab="planner"] .container_semester,
body.is-mobile[data-mobile-tab="planner"] .subcontainer_semester {
    display: block;
    height: auto;
    overflow: visible;
}
body.is-mobile[data-mobile-tab="planner"] .subcontainer_semester .semester {
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex: none;
    height: auto;
    min-height: 0;
    overflow: visible;
}
/* Empty semester = a slim drop area, not a large void. */
body.is-mobile[data-mobile-tab="planner"] .subcontainer_semester .semester:empty {
    min-height: 6px;
}
/* Block flow drops the flex gap, so space the header / courses / add-course.
   Expanded only — a collapsed card is just the header row, which must stay
   vertically centered (no trailing margin). */
body.is-mobile[data-mobile-tab="planner"] .container_semester:not(.m-collapsed) .subcontainer_semester > * {
    margin-bottom: 8px;
}
body.is-mobile[data-mobile-tab="planner"] .container_semester:not(.m-collapsed) .subcontainer_semester > *:last-child {
    margin-bottom: 0;
}

/* Collapsed: hide the body (courses + add-course), keep the header. */
body.is-mobile[data-mobile-tab="planner"] .container_semester.m-collapsed .semester,
body.is-mobile[data-mobile-tab="planner"] .container_semester.m-collapsed .addCourse {
    display: none;
}

/* --- SLIM credits variant: the bold full-width bar becomes a compact pill,
 * with the chevron as a left-edge accordion affordance, so a collapsed
 * semester is a single clean line. Remove this block to fall back to the
 * bold bar. --- */
body.is-mobile[data-mobile-tab="planner"] .container_semester {
    position: relative;
    /* Long split labels such as `5.5 SU (2.5 N/A)` need more room than the
       former total-only pill. Keep one shared reserve for every collapsed
       header instead of relying on the label's old approximate width. */
    --m-semester-credit-reserve: 132px;
}
body.is-mobile[data-mobile-tab="planner"] .container_semester .total_credit_line {
    display: none;
}

/* Chevron: left-edge accordion affordance (pulled out of the icons row),
 * vertically centered on the name row via the relatively-positioned .date. */
body.is-mobile[data-mobile-tab="planner"] .subcontainer_semester .date {
    position: relative;
    padding-left: 26px;
}
body.is-mobile[data-mobile-tab="planner"] .m-sem-chevron {
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
}
body.is-mobile[data-mobile-tab="planner"] .container_semester:not(.m-collapsed) .m-sem-chevron {
    transform: translateY(-50%) rotate(180deg);
}

/* Credits pill: only shown while collapsed, so 50% of the card centers it
 * on the single header row. */
body.is-mobile[data-mobile-tab="planner"] .container_semester .total_credit {
    position: absolute;
    top: 50%;
    right: 12px;
    transform: translateY(-50%);
    width: auto;
    padding: 0;
    background: transparent;
    z-index: 2;
}
body.is-mobile[data-mobile-tab="planner"] .container_semester .total_credit_text {
    padding: 2px 9px;
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--text-secondary);
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: 10px;
    white-space: nowrap;
}
body.is-mobile[data-mobile-tab="planner"] .container_semester.current-term .total_credit_text {
    color: var(--color-white);
    background: var(--accent);
    border-color: transparent;
}
/* Edit/delete icons only while expanded (collapsed row stays clean). */
body.is-mobile[data-mobile-tab="planner"] .container_semester.m-collapsed .semester_date_edit,
body.is-mobile[data-mobile-tab="planner"] .container_semester.m-collapsed .semester-move-controls,
body.is-mobile[data-mobile-tab="planner"] .container_semester.m-collapsed .delete_semester {
    display: none;
}

/* Credits pill stays top-right in BOTH states so the total is visible while
   expanded too. Collapsed centers via 50% of the single-row card (rule above);
   expanded pins it to the header row instead of the tall card's middle. */
body.is-mobile[data-mobile-tab="planner"] .container_semester:not(.m-collapsed) .total_credit {
    top: 11px;
    transform: none;
}

/* Reserve room on the name row for the pill (and the icons when expanded). */
body.is-mobile[data-mobile-tab="planner"] .subcontainer_semester .date {
    padding-right: var(--m-semester-credit-reserve);
}

/* Expanded cards keep their identity, actions and workload on one compact
   line. Scale only this dense header chrome with the available phone width;
   the collapsed header retains the roomier typography and fixed credit
   reserve above. The explicit up/down controls make the hidden drag grip
   unnecessary here. */
body.is-mobile[data-mobile-tab="planner"]
    .container_semester:not(.m-collapsed) {
    --m-semester-expanded-credit-reserve: clamp(80px, 22vw, 92px);
    --m-semester-action-width: 24px;
}

body.is-mobile[data-mobile-tab="planner"]
    .container_semester:not(.m-collapsed)
    .date:not(:has(.select-control)) {
    align-items: center;
    gap: 3px;
    margin-inline: -4px;
    padding-left: 22px;
    padding-right: var(--m-semester-expanded-credit-reserve);
}

body.is-mobile[data-mobile-tab="planner"]
    .container_semester:not(.m-collapsed)
    .date:not(:has(.select-control)) > p {
    flex: 1 1 auto;
    min-width: 0;
    max-width: 100%;
    font-size: clamp(0.66rem, 2.9vw, 0.78rem);
    line-height: 1.2;
    white-space: nowrap;
}

body.is-mobile[data-mobile-tab="planner"]
    .container_semester:not(.m-collapsed)
    .date:not(:has(.select-control)) > .icons {
    flex: 0 0 auto;
    min-width: 0;
    align-items: center;
    gap: 3px;
}

body.is-mobile[data-mobile-tab="planner"]
    .container_semester:not(.m-collapsed)
    .date:not(:has(.select-control)) .semester-move-controls {
    gap: 2px;
}

body.is-mobile[data-mobile-tab="planner"]
    .container_semester:not(.m-collapsed)
    .date:not(:has(.select-control)) .semester_date_edit,
body.is-mobile[data-mobile-tab="planner"]
    .container_semester:not(.m-collapsed)
    .date:not(:has(.select-control)) .semester_move,
body.is-mobile[data-mobile-tab="planner"]
    .container_semester:not(.m-collapsed)
    .date:not(:has(.select-control)) .delete_semester {
    width: var(--m-semester-action-width);
    height: 24px;
    flex: 0 0 var(--m-semester-action-width);
}

body.is-mobile[data-mobile-tab="planner"]
    .container_semester:not(.m-collapsed) .total_credit_text {
    padding: 2px 3px;
    font-size: clamp(0.56rem, 2.4vw, 0.63rem);
}

/* The current term is signalled by its green credits pill + green card border
   (see .current-term rules), so no separate text tag is needed — a tag here
   made the name wrap to a second line and crowd the header. */

/* Date-edit mode: the term <p> is swapped for a <select> + a .tick confirm.
   Hide the credits pill and relax the reserved padding so the dropdown gets
   the full row; :has() auto-reverts once editing ends. */
body.is-mobile[data-mobile-tab="planner"] .container_semester:has(.date .select-control) .total_credit {
    display: none;
}
body.is-mobile[data-mobile-tab="planner"] .subcontainer_semester .date:has(.select-control) {
    padding-right: 12px;
    gap: 8px;
}
body.is-mobile[data-mobile-tab="planner"] .date .select-control {
    flex: 1 1 auto;
    min-width: 0;
}
body.is-mobile[data-mobile-tab="planner"] .date .tick {
    flex-shrink: 0;
}

/* At 320px there is not enough horizontal room for the longest term, the
   N/A workload pill and four actions without making the controls illegible.
   Keep every control on the same row and allow only the term label to use a
   second line; 360px and wider remain strictly single-line. */
@media (max-width: 340px) {
    body.is-mobile[data-mobile-tab="planner"]
        .container_semester:not(.m-collapsed)
        .date:not(:has(.select-control)) > p {
        font-size: 0.6rem;
        line-height: 1.1;
        white-space: normal;
    }
}

/* Planner course filters use the same fixed portal as desktop so a semester's
   scroll area cannot crop them.  On phones the panel becomes a viewport-width
   sheet-like popover with touch-sized fields and its own scrolling. */
body.is-mobile .planner-course-filter-menu {
    left: 8px !important;
    right: 8px !important;
    width: auto !important;
    max-width: none;
    max-height: min(72dvh, 560px);
    padding: 12px;
}

body.is-mobile .planner-course-filter-btn {
    min-width: 42px;
    height: 40px;
    padding-inline: 9px;
}

body.is-mobile .planner-course-filter-close {
    width: 44px;
    height: 44px;
    min-height: 44px;
}

body.is-mobile .input_container input,
body.is-mobile .planner-filter-control .select-control {
    min-height: 36px;
}

body.is-mobile .planner-filter-toggle {
    min-height: 40px;
}

body.is-mobile .planner-filter-toggle input {
    width: 20px;
    height: 20px;
}

body.is-mobile .planner-course-filter-footer {
    position: sticky;
    bottom: -12px;
    margin-inline: -12px;
    padding: 10px 12px 12px;
    background: var(--bg-card);
}

body.is-mobile .planner-filter-reset {
    min-height: 36px;
}

@media (max-width: 350px) {
    body.is-mobile .planner-filter-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    body.is-mobile .planner-filter-control.is-wide {
        grid-column: auto;
    }
}

/* ============================================================
 * CONTROLS — the sidebar reorganized into mobile sections. Semantic group
 * classes keep these cards stable when another action is added to Controls.
 * ============================================================ */

body.is-mobile[data-mobile-tab="controls"] .sidebar-header {
    padding: 14px 16px;
}
body.is-mobile[data-mobile-tab="controls"] .sidebar-content {
    padding: 12px 14px 14px;
}
/* The last card doesn't need an inter-card margin above the bottom nav. */
body.is-mobile[data-mobile-tab="controls"] .sidebar-content > .control-group:last-child {
    margin-bottom: 0;
}

/* Hide the nav-duplicate group (New Semester / Check Graduation / Summary /
   Scheduler) — those live on the Planner, Progress, and Scheduler tabs. */
body.is-mobile[data-mobile-tab="controls"] .sidebar-content > .control-group-navigation {
    display: none;
}

/* Each group becomes a card. */
body.is-mobile[data-mobile-tab="controls"] .control-group {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 12px 14px;
    margin-bottom: 12px;
}

/* Section headers. */
body.is-mobile[data-mobile-tab="controls"] .control-group-courses::before,
body.is-mobile[data-mobile-tab="controls"] .control-group-danger::before {
    display: block;
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    margin-bottom: 10px;
}
body.is-mobile[data-mobile-tab="controls"] .control-group-courses::before { content: "Courses"; }
body.is-mobile[data-mobile-tab="controls"] .control-group-danger::before { content: "Danger zone"; }

body.is-mobile[data-mobile-tab="controls"] .program-controls-heading {
    margin-bottom: 10px;
}

body.is-mobile[data-mobile-tab="controls"] .program-controls-heading .sidebar-section-heading {
    font-size: 0.68rem;
}

body.is-mobile[data-mobile-tab="controls"] .admit-term-help-button {
    width: 44px;
    height: 44px;
    font-size: 1rem;
}

body.is-mobile[data-mobile-tab="controls"] .sidebar-options-heading {
    margin: 0 0 6px;
}

body.is-mobile[data-mobile-tab="controls"] .sidebar-section-description {
    margin: 0 0 8px;
}

/* Merge the four single-toggle groups into one picker-defaults card. */
body.is-mobile[data-mobile-tab="controls"] .control-group-option {
    border-radius: 0;
    margin-bottom: 0;
}
body.is-mobile[data-mobile-tab="controls"] .control-group-option:not(.control-group-options-end) {
    border-bottom: none;
}
body.is-mobile[data-mobile-tab="controls"] .control-group-options-start {
    border-top-left-radius: var(--radius-md);
    border-top-right-radius: var(--radius-md);
}
body.is-mobile[data-mobile-tab="controls"] .control-group-options-end {
    border-bottom-left-radius: var(--radius-md);
    border-bottom-right-radius: var(--radius-md);
    margin-bottom: 12px;
}

/* Stack program + admit-term selects full-width; keep toggle rows horizontal. */
body.is-mobile[data-mobile-tab="controls"] .control-row {
    flex-direction: column;
    flex-wrap: nowrap;
    gap: 8px;
}
body.is-mobile[data-mobile-tab="controls"] .control-row.toggle-row {
    flex-direction: row;
    align-items: center;
}
body.is-mobile[data-mobile-tab="controls"] .control-row .select-control {
    width: 100%;
    flex: none;
}
body.is-mobile[data-mobile-tab="controls"] .control-group .btn {
    width: 100%;
}

/* The long guide takes over the available phone viewport while keeping its
   header and Close action fixed around a single scrollable body. */
body.is-mobile .help-info-overlay {
    align-items: stretch;
    padding: 8px;
}

body.is-mobile .help-info-modal {
    width: 100%;
    max-width: none;
    height: 100%;
    max-height: none;
    padding: 14px 12px 12px;
}

body.is-mobile .help-info-modal-body {
    padding-right: 2px;
}

body.is-mobile .help-info-disclaimer {
    padding: 10px 11px;
}

body.is-mobile .help-info-layout {
    display: block;
}

body.is-mobile .help-info-nav {
    position: static;
    flex-direction: row;
    gap: 6px;
    margin-bottom: 12px;
    padding: 6px;
    overflow-x: auto;
    overscroll-behavior-inline: contain;
    scrollbar-width: thin;
}

body.is-mobile .help-info-nav-link {
    flex: 0 0 auto;
    padding: 8px 9px;
    white-space: nowrap;
}

body.is-mobile .help-info-section {
    padding: 13px;
}

body.is-mobile .help-info-modal .app-modal-footer .btn {
    width: 100%;
}

body.is-mobile .admit-term-help-overlay {
    align-items: center;
    padding: 12px;
}

body.is-mobile .admit-term-help-modal {
    width: 100%;
    max-width: none;
    max-height: calc(100dvh - 24px);
    padding: 14px 12px 12px;
}

body.is-mobile .admit-term-help-modal .app-modal-footer .btn {
    width: 100%;
    min-height: 44px;
}

body.is-mobile .release-update-overlay {
    align-items: center;
    padding: 12px;
}

body.is-mobile .release-update-modal {
    width: 100%;
    max-width: none;
    max-height: calc(100dvh - 24px);
    padding: 14px 12px 12px;
}

body.is-mobile .release-update-modal-body {
    padding-right: 2px;
}

body.is-mobile .release-update-modal .app-modal-footer {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

body.is-mobile .release-update-modal .app-modal-footer .btn {
    width: 100%;
}

/* ============================================================
 * PROGRESS — merged graduation/summary screen (built by navigation-progress.js,
 * reusing the desktop summary computation). Phase 1: per-program
 * overview cards (credit progress + category stats).
 * ============================================================ */
.m-progress { display: none; }
body.is-mobile[data-mobile-tab="progress"] .board,
body.is-mobile[data-mobile-tab="progress"] .sidebar {
    display: none;
}
body.is-mobile[data-mobile-tab="progress"] .m-progress {
    display: block;
    position: absolute;
    inset: 0;
    overflow-y: auto;
    overflow-x: hidden;
    box-sizing: border-box;
    padding: 14px;
    background: var(--bg-main);
}

/* Swipe carousel: cards scroll-snap horizontally with the next one peeking;
   pagination dots below. Degrades to a single full-width card. */
.m-progress .m-prog-carousel {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    gap: 10px;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}
.m-progress .m-prog-carousel::-webkit-scrollbar { display: none; }
.m-progress .m-prog-card {
    flex: 0 0 100%;
    box-sizing: border-box;
    scroll-snap-align: start;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 14px;
}
.m-progress .m-prog-carousel.is-multi .m-prog-card {
    flex-basis: 86%;
}
.m-progress .m-prog-dots {
    display: flex;
    justify-content: center;
    gap: 6px;
    margin-top: 12px;
}
.m-progress .m-prog-dots.is-single { display: none; }
.m-progress .m-prog-dot {
    width: 7px;
    height: 7px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: var(--border);
    cursor: pointer;
    transition: width 0.2s ease, background 0.2s ease;
}
.m-progress .m-prog-dot.active {
    width: 18px;
    border-radius: 4px;
    background: var(--primary);
}
.m-progress .m-prog-dot:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 3px;
}

/* Detail accordion: the relocated .major-summary / .minor-summary, with each
   .ms-section header toggling its course list. */
.m-progress .m-prog-detail {
    margin-top: 16px;
}
.m-progress .m-prog-detail .major-summary,
.m-progress .m-prog-detail .minor-summary {
    width: 100%;
    max-width: none;
}
.m-progress .m-prog-detail .ms-header {
    display: flex;
    align-items: center;
    width: 100%;
    margin: 0 0 6px;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
    gap: 8px;
}
.m-progress .m-prog-detail .ms-header:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 4px;
    border-radius: var(--radius-sm);
}
/* Fixed-width title column so the "N courses • X/Y SU" info lines up across
   sections regardless of the category name's length. */
.m-progress .m-prog-detail .ms-header .ms-title {
    flex: 0 0 100px;
}
.m-progress .m-prog-detail .ms-header .ms-req {
    flex: 1 1 auto;
    text-align: left;
}
.m-progress .m-prog-detail .ms-header::after {
    content: "\25BE";
    color: var(--text-muted);
    font-size: 0.8rem;
    flex-shrink: 0;
    transition: transform 0.2s ease;
}
.m-progress .m-prog-detail .ms-section:not(.m-sec-collapsed) > .ms-header::after {
    transform: rotate(180deg);
}
.m-progress .m-prog-detail .ms-section.m-sec-collapsed > .ms-subheader,
.m-progress .m-prog-detail .ms-section.m-sec-collapsed > .ms-rules,
.m-progress .m-prog-detail .ms-section.m-sec-collapsed > .ms-list,
.m-progress .m-prog-detail .ms-section.m-sec-collapsed > .ms-group-list,
.m-progress .m-prog-detail .ms-section.m-sec-collapsed > .ms-untaken-toggle {
    display: none;
}
/* A desktop Summary that remains open while the viewport crosses into the
   mobile shell must become a contained, single-column surface. This preserves
   the selected program/detail view instead of closing and rebuilding it. */
body.is-mobile .summary_modal_overlay {
    inset: 0;
    width: auto;
    height: auto;
    align-items: stretch;
    justify-content: stretch;
    overflow: hidden;
    padding: 8px;
    box-sizing: border-box;
}

body.is-mobile .summary_overlay_content {
    width: 100%;
    max-width: none;
    min-width: 0;
    height: 100%;
    max-height: none;
    overflow: hidden;
    border-radius: var(--radius-md);
}

body.is-mobile .summary_header_row {
    flex: 0 0 auto;
    min-width: 0;
    padding: 10px 12px;
}

body.is-mobile .summary_surface_header_copy,
body.is-mobile .summary_cards_row,
body.is-mobile .summary_program_section,
body.is-mobile .summary_program_grid,
body.is-mobile .summary_program_card,
body.is-mobile .summary_major_panel,
body.is-mobile .summary_minor_panel,
body.is-mobile .summary_minor_panel_body,
body.is-mobile .summary_overview_identity,
body.is-mobile .summary_program_identity_copy,
body.is-mobile .summary_overview_hero,
body.is-mobile .summary_overview_snapshot,
body.is-mobile .summary_overview_requirements,
body.is-mobile .summary_overview_requirements_grid,
body.is-mobile .summary_overview_snapshot_grid {
    min-width: 0;
    max-width: 100%;
    box-sizing: border-box;
}

body.is-mobile .summary_cards_row,
body.is-mobile .summary_major_panel,
body.is-mobile .summary_minor_panel {
    flex: 1 1 auto;
    width: 100%;
    max-height: none;
    overflow-x: hidden;
    overflow-y: auto;
    padding: 12px;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    overscroll-behavior: contain;
}

body.is-mobile .summary_program_card {
    display: none;
    width: 100%;
    margin: 0;
    padding: 12px;
    overflow: visible;
    font-size: 0.95rem;
}

body.is-mobile .summary_program_card.is-active {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 14px;
}

body.is-mobile .summary_overview_identity,
body.is-mobile .summary_overview_hero,
body.is-mobile .summary_overview_snapshot,
body.is-mobile .summary_overview_requirements,
body.is-mobile .summary_overview_notice {
    grid-column: 1;
}

body.is-mobile .summary_overview_identity {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 10px;
}

body.is-mobile .summary_program_card_heading {
    grid-template-columns: minmax(0, 1fr);
}

body.is-mobile .summary_overview_identity .summary_program_card_footer {
    grid-column: 1;
    grid-row: auto;
    justify-self: stretch;
}

body.is-mobile .summary_overview_requirements_grid,
body.is-mobile .summary_overview_snapshot_grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 8px;
}

body.is-mobile .summary_overview_section_copy {
    display: grid;
    gap: 3px;
}

body.is-mobile .summary_overview_section_copy p {
    max-width: 100%;
    text-align: left;
    overflow-wrap: anywhere;
}

body.is-mobile .summary_program_card_footer .summary_detail_btn,
body.is-mobile .summary_back_btn {
    width: 100%;
    min-width: 0;
}

body.is-mobile .summary_minor_panel_header,
body.is-mobile .summary_detail_section_nav,
body.is-mobile .minor-summary,
body.is-mobile .major-summary {
    max-width: 100%;
    overflow-wrap: anywhere;
}

body.is-mobile .summary_overlay_content .ms-header {
    flex-wrap: wrap;
    align-items: flex-start;
}

body.is-mobile .summary_overlay_content .ms-title,
body.is-mobile .summary_overlay_content .ms-req {
    min-width: 0;
    white-space: normal;
    overflow-wrap: anywhere;
}

body.is-mobile .summary_overlay_content .ms-course {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
    gap: 6px;
}

body.is-mobile .summary_overlay_content .ms-course-left {
    display: flex;
    align-items: flex-start;
    width: 100%;
    min-width: 0;
}

body.is-mobile .summary_overlay_content .ms-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: visible;
    text-overflow: clip;
    white-space: normal;
    overflow-wrap: anywhere;
    line-height: 1.25;
}

body.is-mobile .summary_overlay_content .ms-meta {
    display: flex;
    align-items: center;
    align-content: flex-start;
    flex-wrap: wrap;
    gap: 4px 6px;
    width: 100%;
    min-width: 0;
    padding-left: 16px;
    white-space: normal;
    line-height: 1.35;
    overflow-wrap: anywhere;
}

body.is-mobile .summary_overlay_content .ms-group-top,
body.is-mobile .summary_overlay_content .ms-group-count {
    flex-wrap: wrap;
    white-space: normal;
}

body.is-mobile .summary_overlay_content .ms-group-labels,
body.is-mobile .summary_overlay_content .ms-group-count {
    flex: 1 0 100%;
    width: 100%;
    min-width: 0;
}

/* A detailed course can carry progress state, BS, engineering and SU chips,
   plus an allocation note. On phones those tokens must not compete with the
   course identity for one unbroken row. */
body.is-mobile .m-progress .m-prog-detail .ms-course {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
    gap: 6px;
}

body.is-mobile .m-progress .m-prog-detail .ms-course-left {
    display: flex;
    align-items: flex-start;
    width: 100%;
    min-width: 0;
}

body.is-mobile .m-progress .m-prog-detail .ms-dot {
    margin-top: 0.36em;
}

body.is-mobile .m-progress .m-prog-detail .ms-code {
    flex: 0 0 auto;
}

body.is-mobile .m-progress .m-prog-detail .ms-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: visible;
    text-overflow: clip;
    white-space: normal;
    overflow-wrap: anywhere;
    line-height: 1.25;
}

body.is-mobile .m-progress .m-prog-detail .ms-meta {
    display: flex;
    align-items: center;
    align-content: flex-start;
    flex-wrap: wrap;
    gap: 4px 6px;
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
    padding-left: 16px;
    white-space: normal;
    line-height: 1.35;
    overflow-wrap: anywhere;
}

body.is-mobile .m-progress .m-prog-detail .ms-chip,
body.is-mobile .m-progress .m-prog-detail .ms-state-chip {
    flex: 0 0 auto;
    max-width: 100%;
}

body.is-mobile .m-progress .m-prog-detail .ms-state-chip {
    margin-right: 0;
}

body.is-mobile .m-progress .m-prog-detail .ms-meta-note {
    flex: 1 0 100%;
    min-width: 0;
}

/* Special-requirement labels and their four-part count/status cluster are
   clearer as two wrapping rows on mobile. */
body.is-mobile .m-progress .m-prog-detail .ms-group-top {
    flex-wrap: wrap;
    align-items: flex-start;
    row-gap: 6px;
}

body.is-mobile .m-progress .m-prog-detail .ms-group-labels,
body.is-mobile .m-progress .m-prog-detail .ms-group-count {
    flex: 1 0 100%;
    width: 100%;
    min-width: 0;
}

body.is-mobile .m-progress .m-prog-detail .ms-group-count {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
    white-space: normal;
}

body.is-mobile .m-progress .m-prog-detail .ms-group-badge {
    margin-left: auto;
}

/* On narrow phones, put the requirement summary beneath the section title
   instead of forcing both into the old fixed 100px title grid. */
@media (max-width: 420px) {
    body.is-mobile .m-progress .m-prog-detail .ms-header {
        flex-wrap: wrap;
        align-items: flex-start;
    }

    body.is-mobile .m-progress .m-prog-detail .ms-header .ms-title {
        order: 0;
        flex: 1 1 calc(100% - 24px);
        min-width: 0;
        overflow-wrap: anywhere;
    }

    body.is-mobile .m-progress .m-prog-detail .ms-header::after {
        order: 1;
        margin-left: auto;
    }

    body.is-mobile .m-progress .m-prog-detail .ms-header .ms-req {
        order: 2;
        flex: 1 0 100%;
        min-width: 0;
        line-height: 1.3;
        overflow-wrap: anywhere;
    }
}

/* Keep dynamic custom-course dialogs inside ultra-narrow mobile viewports. */
body.is-mobile .custom_course_overlay {
    box-sizing: border-box;
    padding: 12px;
}

body.is-mobile .custom_course_modal {
    width: 100%;
    min-width: 0;
    max-width: 500px;
    box-sizing: border-box;
}

body.is-mobile .double_major_overlay {
    box-sizing: border-box;
    padding: 12px;
}

body.is-mobile .double_major_modal {
    width: 100%;
    min-width: 0;
    max-width: 400px;
    box-sizing: border-box;
}

body.is-mobile .program-category-help-text {
    width: 100%;
}
