/* ============================================================
   NetStudy Portals — app shell + type scale
   Bootstrap 5.3.8 + AdminLTE 4 + NetStudy Design System
   ------------------------------------------------------------
   The chrome every NetStudy staff/client portal draws: the type
   scale, the form/button/table defaults, the navy sidebar rail,
   the white top bar, breadcrumbs, content well and footer.

   Loaded by BOTH the admin and instructor modules, after
   css/ds/* and css/ns/ns-portal.css and before the module's own
   main.css. Anything only one module renders stays in that
   module's sheet; anything both draw belongs here.

   This file was lifted out of css/admin/main.css when the
   instructor module adopted the same AdminLTE 4 shell — it had
   been the only copy of the shell, so the instructor portal had
   no way to share it. Its --adm-* aliases were re-authored onto
   design-system semantics on the way across: the instructor
   layout never loads css/admin/main.css, where those aliases are
   declared, so every one of them would have resolved to nothing.

   Webfonts come from css/ds/tokens/fonts.css (Jost, Merriweather,
   Open Sans). Do not @import a face here.

   RULES: no literal hex/font/radius/shadow/duration — every value
   is a token. Warm neutrals only. Never `transition: all`. Focus
   rings are never removed.
   ============================================================ */

/* Text on the navy chrome. Not a design-system token: the DS has
   no "on dark rail" pair, and the rail is ours. Named --portal-*
   because the DS owns the whole --ns-* namespace.

   The dim step was 0.65, which put a resting sidebar link at
   #A6B4C7 on the navy — 6.7:1, AA but visibly washed out, and it
   dragged the icon (which dims again on top of this) down to
   4.4:1. At 0.80 the label reads 9.4:1 and the icon 7.9:1, still
   clearly quieter than the .95 hover and the pure-white active
   item, which keep their own fill and left border anyway. */
:root {
    --portal-on-nav:     rgba(255, 255, 255, 0.95);
    --portal-on-nav-dim: rgba(255, 255, 255, 0.80);
}

/* ── The rail ladder ─────────────────────────────────────────
   Four steps in one direction — base, hover, active, and the 3px
   edge on the active item — plus the deeper well the treeview
   submenu sits in. The sidebar rules below read ONLY these; the
   hue is not written into a single one of them.

   That is the seam a portal recolours through. Admin keeps the
   blue ladder declared here; the instructor portal redefines the
   five variables in css/instructor/main.css so the two rails are
   telling apart at a glance across browser tabs. Add a rule that
   hardcodes --blue-800 in the rail and you have quietly reattached
   admin's hue to both portals.
   ------------------------------------------------------------ */
:root {
    --portal-rail:        var(--surface-brand-deep);   /* blue-800 */
    --portal-rail-deep:   var(--blue-900);             /* treeview well */
    --portal-rail-hover:  var(--blue-700);
    --portal-rail-active: var(--blue-600);
    --portal-rail-edge:   var(--surface-brand);        /* blue-500 */
}

/* ============================================================
   TYPOGRAPHY
   ============================================================ */

body {
    font-family: var(--font-body);
    font-size: var(--text-base);   /* 15px — data-dense without feeling cramped */
    font-weight: var(--weight-regular);
    line-height: 1.6;
    color: var(--text-heading);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* Headings — the display face (Jost) gives structural weight to section titles.
   Near-black, NOT navy. Blue in this portal means one thing: this is clickable.
   Painting every heading navy gave the page a second blue that was not a
   link, so neither the headings nor the links read as a signal. Weight, size and
   face carry the hierarchy instead. */
h1, h2, h3,
.h1, .h2, .h3 {
    font-family: var(--font-display);
    font-weight: var(--weight-bold);
    line-height: 1.25;
    letter-spacing: var(--tracking-tight);
    color: var(--text-heading);
}

h4, h5, h6,
.h4, .h5, .h6 {
    font-family: var(--font-body);
    font-weight: var(--weight-semibold);
    line-height: 1.3;
    color: var(--text-heading);
}

h1, .h1 { font-size: var(--text-2xl); }
h2, .h2 { font-size: var(--text-xl); }
h3, .h3 { font-size: var(--text-lg); }
h4, .h4 { font-size: var(--text-base); }
h5, .h5 { font-size: var(--text-sm); }
h6, .h6 { font-size: var(--text-sm); }

/* Labels and form text — slightly tighter */
label,
.form-label,
.col-form-label {
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    color: var(--text-body);
    letter-spacing: var(--tracking-wide);
}

/* Form controls */
.form-control,
.form-select {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    border-color: var(--border-strong);
}

.form-check-input {
    border-color: var(--border-strong);
}

.form-control[readonly] {
    background-color: var(--surface-sunken);
    border-color: var(--border-default);
    color: var(--text-heading);
    cursor: default;
    box-shadow: none;
}

.form-control[readonly]:focus {
    background-color: var(--surface-sunken);
    border-color: var(--border-default);
    box-shadow: none;
}

/* Password reveal toggle */
.password-wrapper {
    position: relative;
}

.password-wrapper input {
    padding-right: 45px;
}

.password-toggler {
    background: none;
    border: none;
    padding: 0;
    position: absolute;
    top: 50%;
    right: 12px;
    transform: translateY(-50%);
    font-size: var(--text-md);
    color: var(--text-muted);
    cursor: pointer;
    line-height: 1;
}

.password-toggler:hover {
    color: var(--surface-brand);
}

/* Buttons */
.btn {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    letter-spacing: var(--tracking-wide);
}

/* btn-primary — matches the brand blue used by the dashboard search button */
.btn-primary {
    background-color: var(--surface-brand);
    border-color: var(--surface-brand);
    color: var(--text-on-brand);
    transition: background-color var(--duration-fast) var(--ease-standard), border-color var(--duration-fast) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard), transform var(--duration-instant) var(--ease-standard);
    box-shadow: var(--shadow-md);
}

.btn-primary:hover,
.btn-primary:focus {
    background-color: var(--blue-600);
    border-color: var(--blue-600);
    color: var(--text-on-brand);
    transform: translateY(-1px);
    box-shadow: var(--shadow-lg);
}

.btn-primary:active {
    background-color: var(--blue-600);
    border-color: var(--blue-600);
    color: var(--text-on-brand);
    transform: translateY(0);
    box-shadow: var(--shadow-sm);
}

.btn-primary:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

/* Disabled follows the design system: "45–50% opacity, not-allowed cursor,
   nothing else" — the shared .btn:disabled rule supplies it. This used to repaint
   the button a solid --blue-200 with opacity:1, which cancelled that rule and
   produced a pale-but-solid button that read as enabled-and-faint rather than
   disabled (white label on #BDD0E1 is 1.58:1). Only the lift is suppressed here. */
.btn-primary:disabled,
.btn-primary.disabled {
    box-shadow: none;
    transform: none;
}

/* btn-secondary / btn-outline-secondary / btn-ghost / btn-outline-danger are
   owned by ns-portal.css, which defines the four action ranks for both portals.
   This module used to paint .btn-secondary solid navy and flood
   .btn-outline-secondary with brand blue on hover; both put a second filled
   brand button next to the primary, so rank came from hue instead of weight.
   Navy is sidebar and header chrome — it is not a button fill. Only the shared
   transition and focus ring stay here, because the module's .btn-primary sets a
   lift that these ranks deliberately do not get. */
.btn-secondary,
.btn-outline-secondary,
.btn-ghost,
.btn-outline-danger {
    transition: color var(--duration-fast) var(--ease-standard), background-color var(--duration-fast) var(--ease-standard), border-color var(--duration-fast) var(--ease-standard);
}

.btn-secondary:focus-visible,
.btn-outline-secondary:focus-visible,
.btn-ghost:focus-visible,
.btn-outline-danger:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

/* btn-danger / btn-outline-danger — shift padding: more top, less bottom */
.btn-danger,
.btn-outline-danger {
    padding-top: 0.4375rem;
    padding-bottom: 0.3125rem;
}

.btn-sm.btn-danger,
.btn-sm.btn-outline-danger {
    padding-top: 0.3125rem;
    padding-bottom: 0.1875rem;
}

/* Tables — slightly smaller for data density, tabular nums for amounts */
.table,
table {
    font-size: var(--text-sm);
}

.table td,
.table th {
    font-variant-numeric: tabular-nums;
}

/* Small text, badges, meta */
small, .small {
    font-size: var(--text-xs);
    font-weight: var(--weight-regular);
}

/* Sidebar nav — the UI face (Open Sans) at small optical size */
.sidebar-menu .nav-item > a p {
    font-family: var(--font-body);
}

/* ============================================================
   SIDEBAR
   ============================================================ */

.app-sidebar {
    background-color: var(--portal-rail) !important;
    border-right: none;
    --lte-sidebar-submenu-bg: var(--portal-rail-deep);
    --lte-sidebar-submenu-active-bg: transparent;
    --lte-sidebar-submenu-active-color: var(--portal-on-nav-dim);
    --lte-sidebar-submenu-hover-color: var(--portal-on-nav-dim);
}

/* Brand area (top of sidebar) — dark, NetStudy logo */
.sidebar-brand {
    background-color: var(--portal-rail) !important;
    border-bottom: 1px solid rgba(255, 255, 255, 0.15);
    min-height: 57px;
}

.brand-link {
    display: flex !important;
    align-items: center;
    justify-content: center;
    padding: 0.85rem 1rem !important;
    text-decoration: none !important;
}

.sidebar-ns-logo {
    height: 28px;
    width: auto;
    display: block;
    opacity: 0.9;
}

/* Sidebar scrollable area */
.sidebar-wrapper {
    background-color: var(--portal-rail) !important;
    display: flex !important;
    flex-direction: column;
}

.sidebar-wrapper nav {
    flex: 1;
}

/* ── Sidebar Nav (Yii CMenu output) ── */
.sidebar-menu {
    list-style: none;
    padding: 0.4rem 0;
    margin: 0;
}

.sidebar-menu .nav-item > a {
    display: flex !important;
    align-items: center;
    padding: 0.55rem 1rem;
    color: var(--portal-on-nav-dim);
    text-decoration: none !important;
    transition: var(--transition-control);
    line-height: 1.5;
    border-left: 3px solid transparent;
}

.sidebar-menu .nav-item > a:hover {
    background-color: var(--portal-rail-hover);
    color: var(--portal-on-nav);
    border-left-color: rgba(255, 255, 255, 0.25);
}

.sidebar-menu .nav-item.active > a,
.sidebar-menu .nav-item.menu-open.active > a {
    background-color: var(--portal-rail-active);
    color: var(--text-on-brand);
    border-left-color: var(--portal-rail-edge);
}

/* Icon */
.sidebar-menu .nav-icon {
    width: 1.2rem;
    font-size: var(--text-base);
    margin-right: 0.7rem;
    text-align: center;
    flex-shrink: 0;
    /* This multiplies the already-translucent --portal-on-nav-dim rather than
       replacing it, so it is the SECOND dimming applied to the same pixels. At
       0.75 the two compounded to 0.49 effective alpha and the icons read as the
       faintest thing in the chrome. Kept only as a slight step below the label. */
    opacity: 0.9;
    transition: opacity var(--duration-fast) var(--ease-standard);
}

.sidebar-menu > .nav-item > a:hover .nav-icon,
.sidebar-menu > .nav-item.active > a .nav-icon {
    opacity: 1;
}

/* Label text wrapped in <p> per AdminLTE convention */
.sidebar-menu .nav-item > a p {
    margin: 0;
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    letter-spacing: var(--tracking-wide);
    flex: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ── CMenu treeview submenu (nested under active main nav item) ── */

.nav-treeview {
    list-style: none;
    padding: 0.25rem 0;
    margin: 0;
    background-color: var(--portal-rail-deep) !important;
    border-top: 1px solid rgba(255, 255, 255, 0.06);
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

.nav-treeview > li > a {
    display: flex;
    align-items: center;
    padding: 0.42rem 1rem 0.42rem 1.5rem;
    color: var(--portal-on-nav-dim);
    text-decoration: none !important;
    font-size: var(--text-sm);
    border-left: 3px solid transparent;
    transition: var(--transition-control);
}

.nav-treeview .nav-icon {
    font-size: 0.38rem;
    min-width: 1.4rem;
    text-align: center;
    opacity: 0.5 !important;
    transition: opacity var(--duration-fast) var(--ease-standard);
}

.nav-treeview > li > a:hover .nav-icon {
    opacity: 1 !important;
}

.nav-treeview > li > a,
.nav-treeview > li.active > a,
.nav-treeview > li.active > a:focus {
    background-color: transparent !important;
    /* Was a hardcoded rgba(255,255,255,.65) — the one submenu rule that did not
       read the shared dim token, so it stayed faded when that token was raised. */
    color: var(--portal-on-nav-dim) !important;
    border-left-color: transparent !important;
    font-weight: var(--weight-regular) !important;
}

.nav-treeview > li > a:hover,
.nav-treeview > li.active > a:hover {
    background-color: transparent !important;
    color: var(--portal-on-nav) !important;
    border-left-color: transparent !important;
}

/* ============================================================
   TOP HEADER
   ============================================================ */

.app-header {
    background-color: var(--surface-card) !important;
    border-bottom: 1px solid var(--border-subtle);
    box-shadow: var(--shadow-sm);
    min-height: 57px;
}


/* Each portal names itself here, so a user who holds accounts in more than one can
   tell at a glance which one they are signed into. Truncates rather than pushing the
   account menu off the bar on a narrow viewport. */
.app-header-title {
    font-family: var(--font-display);
    font-weight: var(--weight-bold);
    font-size: var(--text-lg);
    letter-spacing: var(--tracking-tight);
    color: var(--text-heading);
    margin-left: var(--space-2);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.app-header .nav-link {
    color: var(--text-body);
    padding: 0.45rem 0.7rem;
    border-radius: var(--radius-control);
    transition: var(--transition-control);
}

.app-header .nav-link:hover {
    color: var(--surface-brand-deep);
    background-color: var(--surface-hover);
}

.app-header .dropdown-menu {
    border: 1px solid var(--border-subtle);
    box-shadow: var(--shadow-lg);
    border-radius: var(--radius-card);
    padding: 0.4rem;
    min-width: 200px;
}

.app-header .dropdown-item {
    border-radius: var(--radius-control);
    font-size: var(--text-sm);
    padding: 0.45rem 0.75rem;
    color: var(--surface-brand-deep);
    transition: var(--transition-control);
}

.app-header .dropdown-item:hover {
    background-color: var(--surface-hover);
    color: var(--surface-brand-deep);
}

.app-header .dropdown-divider {
    border-color: var(--border-subtle);
    margin: 0.3rem 0;
}

/* ============================================================
   BREADCRUMBS
   ============================================================ */

.app-content-header {
    background-color: var(--surface-card);
    border-bottom: 1px solid var(--border-subtle);
    padding: 0;
}

.app-content-header .container-fluid {
    padding-top: 0.3rem;
    padding-bottom: 0.3rem;
}

/* CBreadcrumbs widget output */
.app-content-header .breadcrumbs {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.25rem;
    font-size: var(--text-sm);
    color: var(--text-muted);
    margin: 0;
    padding: 0;
}

.app-content-header .breadcrumbs a {
    color: var(--text-body);
    text-decoration: none;
}

.app-content-header .breadcrumbs a:hover {
    color: var(--surface-brand-deep);
    text-decoration: underline;
}

/* ============================================================
   MAIN CONTENT
   ============================================================ */

.app-content {
    padding: 1.5rem 0;
    flex: 1;
}

/* ── Links ── */
a {
    color: var(--surface-brand);
}

a:hover {
    color: var(--blue-600);
}

p a {
    text-decoration: underline;
}

@media (min-width: 768px) {
    .content-body {
        padding-inline: 2rem;
    }
}

.main h1,
.content-body h1 {
    font-size: 1.75em;
    margin-top: 0;
    margin-bottom: 1.25rem;
}

/* ── Footer ── */
.app-footer {
    background-color: transparent;
    color: var(--text-muted);
    font-size: var(--text-sm);
    text-align: center;
    padding: 0.75rem 1rem;
}

/* ── Sticky footer: push footer to bottom when content is short ── */
.app-main {
    display: flex !important;
    flex-direction: column !important;
}


/* ============================================================
   UTILITY HELPERS
   Legacy float/align helpers, still used by both portals' older
   markup. Both module sheets carried their own copy until the
   shell moved here.
   ============================================================ */

.center { text-align: center; }
.right  { float: right; }
.left   { float: left; }
.clear  { clear: both; }
.error  { color: var(--status-danger); }
