/*
 * Akshara "Hall & Shift" — layout, shell and components.
 * Tokens live in app.css; load this AFTER it. Spec: ai/design.md
 *
 * Swiss-editorial: square corners, hairline rules, no shadows. Structure is
 * drawn with 1px lines; layouts are built from hairline-divided cells.
 *
 * Section map:
 *   1 App shell        5 THE SHIFT BAND (signature)   9 Auth
 *   2 Header           6 Tables & DataTables         10 Billing / plans
 *   3 Rail + launcher  7 Tabs, forms                 11 Library setup
 *   4 Page header      8 Permission matrix           12 Motion
 */

/* ============================================================================
   1. App shell
   ============================================================================ */
/* App-shell scroll model: the page itself never scrolls. The header and the Day
   Bar are fixed rows, the rail is a fixed column, and .app-content is the ONLY
   scrolling region — so the header and nav stay put while a 90-row roster
   scrolls past them. 100dvh (not 100vh) so a mobile browser's collapsing
   address bar doesn't leave a dead strip at the bottom. */
.app-body {
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  background: var(--ak-ground);
}

.app-shell {
  flex: 1 1 auto;
  min-height: 0;              /* lets the flex child shrink so its child can scroll */
  display: flex;
  align-items: stretch;
  overflow: hidden;
}
/* min-width:0 is load-bearing: without it a wide server-side DataTable forces
   the flex row to overflow and the page scrolls sideways (forbidden). */
.app-shell > .app-content {
  flex: 1 1 auto;
  min-width: 0;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

.app-content { padding: 1.15rem; }
@media (min-width: 992px) { .app-content { padding: 1.7rem 2rem; } }

/* ============================================================================
   2. Header
   ============================================================================ */
/* A fixed row of the shell flex column — it no longer needs sticky, because
   the page behind it never scrolls. */
.app-header {
  flex: 0 0 auto; z-index: 1030;
  min-height: var(--app-header-h);
  background: var(--ak-panel);
  border-bottom: 1px solid var(--ak-ink);
}
.app-header__bar { display: flex; align-items: center; gap: .6rem; padding: .45rem .75rem; }
@media (min-width: 576px) { .app-header__bar { gap: .85rem; padding: .45rem 1rem; } }

.app-logo {
  width: 28px; height: 28px; object-fit: contain; flex: 0 0 auto;
  background: var(--ak-panel); border: 1px solid var(--ak-line); padding: 2px;
}
.app-avatar {
  width: 28px; height: 28px; flex: 0 0 auto;
  background: var(--ak-ink); color: var(--ak-panel);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--ak-font-mono); font-size: .64rem; font-weight: 500;
}

.app-icon-button {
  width: 2.3rem; height: 2.3rem; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--ak-line); background: transparent; color: var(--ak-ink);
}
.app-icon-button:hover { border-color: var(--ak-ink); background: var(--ak-ground); }
.app-icon-square {
  width: 1.9rem; height: 1.9rem; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
}

.library-switcher__btn {
  display: inline-flex; align-items: center; gap: .4rem; max-width: 210px;
  border: 1px solid var(--ak-line); padding: .3rem .6rem;
  color: var(--ak-ink); background: transparent;
  font-size: .82rem; font-weight: 600; line-height: 1.35; cursor: pointer;
}
.library-switcher__btn:hover { border-color: var(--ak-ink); }
.library-switcher__btn .bi-chevron-down { font-size: .6rem; color: var(--ak-ink-muted); }
.library-switcher .dropdown-item.active { background: var(--ak-accent); color: var(--ak-accent-ink); }

/* ============================================================================
   3. Module rail + launcher — one nav list, two surfaces.
   Active = solid accent block. The accent is the only thing that fills.
   ============================================================================ */
/* The rail is pinned and fills the viewport, so its surface and border run the
   full height of the page at every scroll position. Without the min-height it
   collapses to the height of its nav items and leaves a bare gap down the left
   of long pages. max-height keeps a long nav scrollable inside it. */
/* A fixed column of the shell. It fills the shell's full height and scrolls
   internally only if the nav itself is taller than the viewport — the content
   column's scrolling never moves it. */
.app-submodule-rail {
  min-width: 224px; max-width: 224px; flex: 0 0 224px;
  height: 100%;
  overflow-y: auto; overscroll-behavior: contain;
  background: var(--ak-panel);
  border-right: 1px solid var(--ak-line);
  padding-bottom: 1rem;
}

.app-nav-group { padding: 0 .5rem; }
.app-nav-group > .app-eyebrow {
  border-top: 1px solid var(--ak-line);
  padding: .85rem .5rem .4rem;
  margin: 0;
}
.app-nav-group:first-child > .app-eyebrow { border-top: 0; }

.module-link, .submodule-link, .app-nav-link {
  display: flex; align-items: center; gap: .55rem;
  padding: .45rem .5rem;
  color: var(--ak-ink); text-decoration: none;
  font-size: .89rem; font-weight: 500; line-height: 1.3;
  min-height: 2.15rem;
}
.module-link .bi, .submodule-link .bi, .app-nav-link .bi {
  font-size: .95rem; flex: 0 0 auto; color: var(--ak-ink-muted);
}
.module-link:hover, .submodule-link:hover, .app-nav-link:hover {
  background: var(--ak-ground); text-decoration: none;
}
.module-link.active, .submodule-link.active, .app-nav-link.active {
  background: var(--ak-accent); color: var(--ak-accent-ink); font-weight: 600;
}
.module-link.active .bi, .app-nav-link.active .bi { color: var(--ak-accent-ink); }
.module-link.disabled { opacity: .4; pointer-events: none; }

/* Launcher offcanvas — full ink. The one place depth is intentional. */
.module-launcher.offcanvas {
  background: var(--ak-ink); color: var(--ak-panel); width: min(19rem, 86vw);
}
.module-launcher .offcanvas-header { border-bottom: 1px solid rgba(255, 255, 255, .16); }
.module-launcher .offcanvas-title { color: var(--ak-panel); }
.module-launcher .app-eyebrow { color: var(--ak-accent); }
[data-bs-theme="light"] .module-launcher .app-eyebrow { color: #9E95FF; }
.module-launcher .app-nav-group > .app-eyebrow { border-top-color: rgba(255, 255, 255, .16); }
.module-launcher .module-link { color: rgba(255, 255, 255, .85); }
.module-launcher .module-link .bi { color: rgba(255, 255, 255, .55); }
.module-launcher .module-link:hover { color: #fff; background: rgba(255, 255, 255, .09); }
.module-launcher .module-link.active { background: var(--ak-accent); color: var(--ak-accent-ink); }
.module-launcher .module-link.active .bi { color: var(--ak-accent-ink); }
.module-launcher .btn-close { filter: invert(1) grayscale(1) brightness(2); }

/* ============================================================================
   4. Page header
   ============================================================================ */
.app-page-header {
  display: flex; flex-wrap: wrap; justify-content: space-between;
  align-items: flex-end; gap: .85rem;
}
.app-page-header__actions { display: flex; flex-wrap: wrap; gap: .45rem; }
/* On a phone the action row becomes a compact horizontal strip: secondary
   actions shrink to icon+label at small size and the primary action keeps its
   full width. Wrapping four full-size buttons onto three rows pushed the actual
   content below the fold. */
@media (max-width: 575.98px) {
  .app-page-header__actions {
    width: 100%; flex-wrap: nowrap; overflow-x: auto;
    scrollbar-width: none; padding-bottom: .15rem;
  }
  .app-page-header__actions::-webkit-scrollbar { display: none; }
  .app-page-header__actions > .btn {
    flex: 0 0 auto; white-space: nowrap;
    --bs-btn-padding-y: .38rem; --bs-btn-padding-x: .6rem; font-size: .8rem;
  }
}

/* ============================================================================
   5. THE SHIFT BAND — the signature (ai/design.md §2, ADR-0047 D2)
   One primitive at four scales. State is carried by FILL SHAPE as well as
   colour, so it survives greyscale, colour-blindness and print. Occupancy is
   INK: a mid-luminance accent measures ~1:1 against its own empty track.
   ============================================================================ */

/* 5.1 The segment — shared by every scale. */
.ak-seg {
  flex: 1 1 0; min-width: 4px;
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--ak-track);
}
.ak-seg--booked { background: var(--ak-ink); box-shadow: none; }
.ak-seg--free { background: transparent; box-shadow: inset 0 0 0 1px var(--ak-track); }
.ak-seg--unpaid {
  background: repeating-linear-gradient(45deg, var(--ak-overdue) 0 2px, transparent 2px 4px);
  box-shadow: inset 0 0 0 1px var(--ak-overdue);
}
.ak-seg--live { background: var(--ak-accent); box-shadow: none; }

/* 5.2 Row Band — tables and profiles. */
.ak-rowband { display: inline-flex; gap: 2px; vertical-align: middle; }
.ak-rowband .ak-seg { width: 9px; height: 15px; flex: 0 0 auto; }

/* 5.3 Day Bar — pinned under the header on LIBRARY-tier screens only.
   Absent on account screens: no seat context there, so it would be decoration. */
/* A fixed row of the shell column, directly below the header — it stays put
   while content scrolls, which is the whole point of it. */
.ak-daybar {
  flex: 0 0 auto; z-index: 1020;
  display: flex; align-items: stretch;
  background: var(--ak-panel);
  border-bottom: 1px solid var(--ak-line);
  overflow-x: auto; scrollbar-width: none;
}
.ak-daybar::-webkit-scrollbar { display: none; }
.ak-daybar__shift {
  flex: 1 1 0; min-width: 8.5rem;
  padding: .4rem .85rem .45rem;
  border-right: 1px solid var(--ak-line);
  position: relative;
}
.ak-daybar__shift:last-child { border-right: 0; }
.ak-daybar__shift--live::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px; background: var(--ak-accent);
}
.ak-daybar__name { font-size: .84rem; font-weight: 650; line-height: 1.25; }
.ak-daybar__meta {
  font-family: var(--ak-font-mono); font-size: .62rem;
  color: var(--ak-ink-muted); line-height: 1.35; display: block;
}
.ak-daybar__meter { height: 4px; background: var(--ak-track); margin-top: .28rem; overflow: hidden; }
.ak-daybar__meter > span { display: block; height: 100%; background: var(--ak-ink); }
.ak-daybar__meter--full > span { background: var(--ak-overdue); }
@media (max-width: 991.98px) {
  .ak-daybar__shift { min-width: 7rem; }
  .ak-daybar--compact .ak-daybar__shift:not(.ak-daybar__shift--live) { display: none; }
}

/* 5.4 Hall Map — the room itself. Hairline-divided cells, exactly the
   structural device the whole system is built from. */
.ak-hallmap {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(2.5rem, 1fr));
  gap: 0;
  border-top: 1px solid var(--ak-line);
  border-left: 1px solid var(--ak-line);
}
.ak-seat {
  border-right: 1px solid var(--ak-line);
  border-bottom: 1px solid var(--ak-line);
  background: var(--ak-panel);
  padding: .28rem .2rem .3rem;
  text-align: center; text-decoration: none; color: inherit; display: block;
}
.ak-seat--free { background: var(--ak-ground); }
.ak-seat__no {
  font-family: var(--ak-font-mono); font-size: .58rem;
  color: var(--ak-ink-muted); display: block; line-height: 1; margin-bottom: .28rem;
}
.ak-seat__band { display: flex; gap: 1.5px; height: 13px; }
a.ak-seat:hover, button.ak-seat:hover { background: var(--ak-ground); text-decoration: none; }
.ak-seat[aria-pressed="true"] { box-shadow: inset 0 0 0 2px var(--ak-accent); }

.ak-legend { display: flex; flex-wrap: wrap; gap: .9rem; align-items: center; margin-top: .65rem; }
.ak-legend > span {
  display: inline-flex; align-items: center; gap: .35rem;
  font-family: var(--ak-font-mono); font-size: .6rem;
  text-transform: uppercase; letter-spacing: .1em; color: var(--ak-ink-muted);
}
.ak-legend .ak-seg { width: 11px; height: 11px; flex: 0 0 auto; }

/* 5.5 Code cell — OTP input. Same character-cell rhythm as a seat. */
.ak-codecell { display: flex; gap: .4rem; flex-wrap: wrap; }
.ak-codecell input {
  width: 2.7rem; height: 3.2rem; text-align: center;
  font-family: var(--ak-font-mono); font-size: 1.2rem;
  border: 1px solid var(--ak-line-strong); background: var(--ak-panel); color: var(--ak-ink);
}
.ak-codecell input:focus { outline: 2px solid var(--ak-accent); outline-offset: -1px; border-color: var(--ak-accent); }

/* KPI chip */
.ak-chip {
  width: 2rem; height: 2rem; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--ak-line); color: var(--ak-accent); background: transparent;
}
.ak-chip-sm { width: 1.75rem; height: 1.75rem; font-size: .8rem; }

/* ============================================================================
   6. Tables & DataTables — hairline grid, mono headers.
   ============================================================================ */
.table { --bs-table-bg: transparent; color: var(--ak-ink); margin-bottom: 0; }
.table > thead > tr > th {
  font-family: var(--ak-font-mono); font-weight: 500;
  font-size: .6rem; letter-spacing: .11em; text-transform: uppercase;
  color: var(--ak-ink-muted);
  border-bottom: 1px solid var(--ak-ink);
  padding: .3rem .6rem .5rem; white-space: nowrap;
}
.table > tbody > tr > td {
  border-top: 1px solid var(--ak-line); border-bottom: 0;
  padding: .55rem .6rem; vertical-align: middle; font-size: .88rem;
}
.table > tbody > tr:hover > td { background: var(--ak-ground); }

@media (min-width: 768px) { .app-table-fixed { table-layout: fixed; min-width: 62rem; } }

.dt-container .dt-layout-row { align-items: center; row-gap: .6rem; }
.dt-container .dt-layout-cell { display: flex; align-items: center; gap: .65rem; }
.dt-container .dt-layout-cell.dt-layout-end { justify-content: flex-end; }
.dt-container .dt-length, .dt-container .dt-info {
  font-family: var(--ak-font-mono); font-size: .64rem;
  letter-spacing: .06em; text-transform: uppercase;
  color: var(--ak-ink-muted); white-space: nowrap; padding: 0;
}
.dt-container .dt-length { display: flex; align-items: center; gap: .4rem; }
.dt-container .dt-length select { width: auto; min-width: 4rem; padding-block: .2rem; }
.dt-container .pagination { margin-bottom: 0; }
.pagination {
  --bs-pagination-color: var(--ak-ink);
  --bs-pagination-bg: transparent;
  --bs-pagination-border-color: var(--ak-line);
  --bs-pagination-border-radius: 0;
  --bs-pagination-hover-color: var(--ak-ink);
  --bs-pagination-hover-bg: var(--ak-ground);
  --bs-pagination-hover-border-color: var(--ak-line);
  --bs-pagination-focus-bg: transparent;
  --bs-pagination-active-color: var(--ak-accent-ink);
  --bs-pagination-active-bg: var(--ak-accent);
  --bs-pagination-active-border-color: var(--ak-accent);
  --bs-pagination-disabled-color: var(--ak-ink-muted);
  --bs-pagination-disabled-bg: transparent;
  --bs-pagination-disabled-border-color: var(--ak-line);
}

.table-action-button { position: relative; }
.table-action-button::after {
  content: attr(data-action-tooltip); position: absolute; bottom: calc(100% + 5px);
  left: 50%; transform: translateX(-50%);
  background: var(--ak-ink); color: var(--ak-panel);
  font-family: var(--ak-font-mono); font-size: .58rem;
  letter-spacing: .06em; text-transform: uppercase;
  white-space: nowrap; padding: .2rem .4rem;
  opacity: 0; pointer-events: none; transition: opacity .12s; z-index: 5;
}
.table-action-button:hover::after, .table-action-button:focus-visible::after { opacity: 1; }

/* 6.1 Two-line rows below md (ai/design.md §11.1).
   NOT a seven-row label/value stack — a 90-student roster must stay scannable. */
@media (max-width: 767.98px) {
  table.app-table thead { display: none; }
  table.app-table, table.app-table tbody, table.app-table tr, table.app-table td { display: block; }
  table.app-table tr {
    position: relative; border: 1px solid var(--ak-line);
    background: var(--ak-panel); padding: .6rem .7rem; margin-bottom: -1px;
  }
  table.app-table tr.row-overdue { box-shadow: inset 3px 0 var(--ak-overdue); }
  table.app-table tr.row-overdue > td:first-child { box-shadow: none; }
  /* Matches .table > tbody > tr > td's specificity — a bare `table.app-table td`
     loses to it and every cell keeps a stray top border. */
  table.app-table > tbody > tr > td { border: 0; padding: 0; }

  /* Two lines, not seven. The row becomes a wrapping flex box: identity claims
     line 1, every meta cell flows inline on line 2, actions sit on their own
     line under a hairline. A 90-student roster stays scannable on a phone. */
  table.app-table tr {
    display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .55rem;
  }
  table.app-table td[data-cell="identity"] { flex: 1 1 100%; min-width: 0; }
  /* `0 1 auto`, not `0 0 auto`: a meta cell must be able to SHRINK. Fixed-basis
     cells ("Evening · Fixed · C30  05:00 PM–10:00 PM") pushed straight through
     the card's right edge on a narrow phone. */
  table.app-table td[data-cell="meta"] {
    flex: 0 1 auto; min-width: 0; max-width: 100%;
    font-size: .82rem; color: var(--ak-ink-muted);
    display: inline-flex; align-items: center; flex-wrap: wrap; gap: .35rem;
    overflow-wrap: anywhere;
  }
  table.app-table td[data-cell="meta"]:empty { display: none; }
  table.app-table td[data-cell="actions"] {
    flex: 1 1 100%; display: flex; gap: .3rem;
    margin-top: .2rem; padding-top: .5rem; border-top: 1px solid var(--ak-line);
  }
  table.app-table td[data-cell="hide"] { display: none; }
  /* Fallback for tables not yet migrated to data-cell. */
  table.app-table td:not([data-cell]) {
    display: flex; justify-content: space-between; gap: 1rem;
    padding: .3rem 0; border-bottom: 1px solid var(--ak-line);
  }
  table.app-table td:not([data-cell])::before {
    content: attr(data-label);
    font-family: var(--ak-font-mono); text-transform: uppercase;
    letter-spacing: .1em; font-size: .58rem; color: var(--ak-ink-muted);
  }
  table.app-table tr td:not([data-cell]):last-child { border-bottom: 0; }
  .app-table-fixed { min-width: 0; }
}

/* ============================================================================
   7. Tabs, dropdowns, forms
   ============================================================================ */
.nav-tabs { border-bottom: 1px solid var(--ak-ink); gap: 0; }
.nav-tabs .nav-link {
  border: 0; border-bottom: 3px solid transparent; border-radius: 0;
  color: var(--ak-ink-muted);
  font-family: var(--ak-font-mono); font-size: .64rem;
  letter-spacing: .11em; text-transform: uppercase;
  padding: .55rem .9rem; margin-bottom: -1px;
}
.nav-tabs .nav-link:hover { color: var(--ak-ink); background: var(--ak-ground); }
.nav-tabs .nav-link.active {
  color: var(--ak-accent); background: transparent; border-bottom-color: var(--ak-accent);
}

.accordion {
  --bs-accordion-bg: var(--ak-panel);
  --bs-accordion-color: var(--ak-ink);
  --bs-accordion-border-color: var(--ak-line);
  --bs-accordion-border-radius: 0;
  --bs-accordion-inner-border-radius: 0;
  --bs-accordion-btn-color: var(--ak-ink);
  --bs-accordion-active-color: var(--ak-ink);
  --bs-accordion-active-bg: var(--ak-ground);
  --bs-accordion-btn-focus-box-shadow: none;
}
.dropdown-menu {
  --bs-dropdown-bg: var(--ak-panel);
  --bs-dropdown-border-color: var(--ak-ink);
  --bs-dropdown-border-radius: 0;
  --bs-dropdown-link-color: var(--ak-ink);
  --bs-dropdown-link-hover-bg: var(--ak-ground);
  --bs-dropdown-link-active-bg: var(--ak-accent);
  --bs-dropdown-link-active-color: var(--ak-accent-ink);
  box-shadow: none;
}
.modal-content, .offcanvas {
  background: var(--ak-panel); color: var(--ak-ink);
  border-color: var(--ak-ink); border-radius: 0;
}

/* Sticky within .app-content (the scroll container), so the offset is measured
   from the top of that box — not from the page. */
.app-form-bar {
  position: sticky; top: 0; z-index: 1015;
  background: var(--ak-panel); border: 1px solid var(--ak-ink);
  padding: .55rem .8rem;
}
.app-form-bar .app-form-title {
  font-family: var(--ak-font-display); font-weight: 700;
  letter-spacing: -.02em; font-size: 1.05rem; margin: 0;
}
@media (max-width: 575.98px) {
  .app-form-bar { position: static; }
  .app-form-bar .app-form-actions { width: 100%; }
  .app-form-bar .app-form-actions .btn { flex: 1 1 0; }
}

/* Form spine — section nav beside a long form */
.ak-spine { position: sticky; top: 0; }
.ak-spine a {
  display: block; padding: .4rem .6rem;
  border-left: 2px solid var(--ak-line);
  color: var(--ak-ink-muted); text-decoration: none;
  font-family: var(--ak-font-mono); font-size: .62rem;
  letter-spacing: .1em; text-transform: uppercase;
}
.ak-spine a.active { border-left-color: var(--ak-accent); color: var(--ak-accent); }
@media (max-width: 991.98px) {
  .ak-spine { position: static; display: flex; gap: 0; overflow-x: auto; padding-bottom: .5rem; }
  .ak-spine a { border-left: 0; border-bottom: 2px solid var(--ak-line); white-space: nowrap; }
  .ak-spine a.active { border-bottom-color: var(--ak-accent); }
}

.req { color: var(--ak-overdue); margin-left: .1rem; }

/* ============================================================================
   8. Permission matrix — modules down, actions across.
   Sticky header row + first column; degrades to the accordion below md.
   ============================================================================ */
/* A CSS Grid, not a table: the module and child wrappers use `display: contents`
   so the DOM keeps its nesting (a child module stays a <fieldset> inside its
   parent's <div>) while every cell still lands in one flat grid. */
.ak-matrix-wrap {
  overflow: auto; max-height: 72vh;
  border: 1px solid var(--ak-ink); background: var(--ak-panel);
  overscroll-behavior: contain;
}
.ak-matrix {
  display: grid;
  grid-template-columns: minmax(11rem, 1.6fr) repeat(4, minmax(3.4rem, auto)) minmax(0, 2fr);
  align-items: stretch;
  min-width: 34rem;                  /* below this the wrap scrolls sideways, not the page */
}
.ak-matrix__head, .ak-matrix__module, .ak-matrix__child { display: contents; }

.ak-matrix__corner, .ak-matrix__col {
  position: sticky; top: 0; z-index: 3;
  background: var(--ak-panel);
  border-bottom: 1px solid var(--ak-ink);
  padding: .5rem .6rem;
  font-family: var(--ak-font-mono); font-weight: 500; font-size: .58rem;
  letter-spacing: .11em; text-transform: uppercase; color: var(--ak-ink);
  text-align: center; white-space: nowrap;
}
.ak-matrix__corner { left: 0; z-index: 4; text-align: left; color: var(--ak-ink-muted); }
.ak-matrix__col--more { text-align: left; color: var(--ak-ink-muted); }
button.ak-matrix__col { border: 0; cursor: pointer; }
button.ak-matrix__col:hover { background: var(--ak-ground); color: var(--ak-accent); }

.ak-matrix__label {
  position: sticky; left: 0; z-index: 2;
  background: var(--ak-panel);
  border-bottom: 1px solid var(--ak-line);
  border-right: 1px solid var(--ak-line);
  padding: .45rem .6rem;
  display: flex; align-items: center; gap: .45rem; flex-wrap: wrap;
  font-size: .86rem;
}
.ak-matrix__label--child { padding-left: 1.7rem; float: none; width: auto; }
.ak-matrix__label--child .ak-matrix__bulk { color: var(--ak-ink-muted); font-weight: 400; }

.ak-matrix__cell {
  border-bottom: 1px solid var(--ak-line);
  padding: .45rem .6rem;
  display: flex; align-items: center; justify-content: center;
}
.ak-matrix__cell--more {
  justify-content: flex-start; flex-wrap: wrap; gap: .3rem;
  border-left: 1px solid var(--ak-line);
}

.ak-matrix__bulk {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; font-weight: 560; color: var(--ak-ink);
  display: inline-flex; align-items: center; gap: .4rem; text-align: left;
}
.ak-matrix__bulk:hover { color: var(--ak-accent); text-decoration: underline; text-underline-offset: .18em; }
.ak-matrix__bulk .bi { color: var(--ak-ink-muted); }

.ak-matrix .form-check-input { margin: 0; width: 1.05rem; height: 1.05rem; cursor: pointer; }
.ak-matrix .form-check-input:disabled { opacity: .35; }

/* A module-specific action with no canonical column. */
.ak-chip-check { display: inline-flex; align-items: center; gap: .3rem; max-width: 100%;
  border: 1px solid var(--ak-line); padding: .12rem .4rem .12rem .3rem; }
/* Some registry labels are full sentences ("Split a seat into shares or merge it
   back — changes how many students you can seat…"). Clamp the chip to one line so a
   row stays one row; the full text is still in the DOM for screen readers and in
   the title attribute on hover. */
.ak-chip-check label {
  font-size: .74rem; color: var(--ak-ink-muted); cursor: pointer; margin: 0;
  max-width: 15rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ak-chip-check:has(input:checked) { border-color: var(--ak-accent); }
.ak-chip-check:has(input:checked) label { color: var(--ak-ink); }

/* A cascade lit this switch rather than the user — flash it so the change is seen. */
.perm-autolit { outline: 2px solid var(--ak-accent); outline-offset: 2px; }

/* ============================================================================
   9. Auth
   ============================================================================ */
.auth-shell {
  min-height: 100vh; min-height: 100dvh;
  display: flex; align-items: center;
  background: var(--ak-ground); padding: 1.15rem 0;
}
.auth-shell .container { max-width: 62rem; }
/* One bordered block split down the middle — collapsed borders, no gap, so the
   two halves read as a single object rather than two floating cards. */
.auth-split { border: 1px solid var(--ak-ink); background: var(--ak-panel); }
.auth-brand { padding: 2rem; border-right: 1px solid var(--ak-line); background: var(--ak-ground); }
.auth-card { padding: 2rem; background: var(--ak-panel); }
@media (min-width: 1200px) { .auth-brand, .auth-card { padding: 2.75rem; } }
@media (max-width: 575.98px) { .auth-card { padding: 1.5rem 1.15rem; } }

.auth-brand__headline {
  font-family: var(--ak-font-display); font-weight: 700;
  font-size: clamp(1.5rem, 1rem + 1.6vw, 2.1rem);
  letter-spacing: -.03em; line-height: 1.05; margin: 0 0 .7rem;
}
/* The signature, as the first thing anyone sees. Decorative here, so aria-hidden.
   Kept sparse and low-contrast: at full ink weight a dense grid reads as a
   barcode and fights the headline it is meant to support. */
.auth-brand__map {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 0;
  border-top: 1px solid var(--ak-line); border-left: 1px solid var(--ak-line);
  max-width: 17rem;
}
.auth-brand__map .ak-seat { padding: .3rem .25rem; background: var(--ak-panel); }
.auth-brand__map .ak-seat__band { height: 10px; }
.auth-brand__map .ak-seg--booked { background: var(--ak-ink-muted); opacity: .55; }

.auth-feature { background: var(--ak-panel); border: 1px solid var(--ak-line); }

/* ============================================================================
   9b. Error pages — a normal scrolling page, not the app shell (a 419 can render
   before any nav context exists).
   ============================================================================ */
.ak-error-body { min-height: 100vh; background: var(--ak-ground); color: var(--ak-ink); }
.ak-error {
  min-height: 100vh; display: flex; align-items: center;
  padding: 2rem 1.15rem;
}
.ak-error__inner { width: 100%; max-width: 34rem; margin-inline: auto; }
.ak-error__title {
  font-family: var(--ak-font-display); font-weight: 700;
  font-size: clamp(1.7rem, 1.1rem + 2.6vw, 2.6rem);
  letter-spacing: -.03em; line-height: 1.05; margin: 0 0 .6rem;
}
.ak-error__body { color: var(--ak-ink-muted); font-size: 1rem; margin: 0; max-width: 30rem; }

/* The Shift Band motif used literally: a row of desks with one that isn't there. */
.ak-error__seats { display: flex; gap: 0; margin-bottom: 1.75rem; }
.ak-error__seat {
  width: 1.6rem; height: 2rem;
  border: 1px solid var(--ak-line); margin-right: -1px;
  background: var(--ak-panel);
}
.ak-error__seat--missing {
  background: transparent; border-style: dashed; border-color: var(--ak-accent);
  position: relative; z-index: 1;
}
@media (min-width: 576px) { .ak-error { padding: 3rem 2rem; } }

/* ============================================================================
   10. Billing / plans / checkout
   ============================================================================ */
.plan-card { transition: border-color .12s; }
.plan-card:hover { border-color: var(--ak-ink); }
.plan-card.is-recommended { border-color: var(--ak-accent); box-shadow: inset 0 0 0 1px var(--ak-accent); }
.plan-ribbon {
  font-family: var(--ak-font-mono); font-size: .58rem;
  letter-spacing: .11em; text-transform: uppercase;
  background: var(--ak-accent); color: var(--ak-accent-ink); padding: .2rem .5rem;
}
.plan-offer, .billing-badge {
  font-family: var(--ak-font-mono); font-size: .56rem;
  letter-spacing: .11em; text-transform: uppercase;
  background: transparent; color: var(--ak-accent);
  box-shadow: inset 0 0 0 1px var(--ak-accent); padding: .18rem .45rem;
}
.plan-ribbon--corner { position: absolute; top: 0; right: 0; z-index: 2; }
.plan-price {
  font-family: var(--ak-font-display); font-weight: 700; font-size: 2.3rem;
  line-height: 1; letter-spacing: -.03em; font-variant-numeric: tabular-nums;
}
.plan-mrp { text-decoration: line-through; color: var(--ak-ink-muted); font-size: .9rem; }
.plan-excl-tax, .pay-method__desc, .billing-option__meta { font-size: .8rem; color: var(--ak-ink-muted); }
.plan-feature { display: flex; gap: .5rem; align-items: baseline; padding: .22rem 0; }
.plan-feature .bi { color: var(--ak-accent); }
.plan-pay-icons {
  display: flex; align-items: center; justify-content: center; gap: .5rem;
  margin-top: .8rem; color: var(--ak-ink-muted); font-size: .75rem;
}

.checkout-summary { background: var(--ak-ground); }
.summary-line { display: flex; justify-content: space-between; gap: 1rem; padding: .3rem 0; font-size: .9rem; }
.summary-total {
  font-family: var(--ak-font-display); font-weight: 700;
  letter-spacing: -.025em; font-size: 1.25rem; padding-top: .45rem;
}
.pay-label {
  font-family: var(--ak-font-mono); font-size: .6rem;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--ak-ink-muted); margin-bottom: .5rem;
}
.pay-method, .billing-option {
  display: flex; gap: .7rem; align-items: flex-start; cursor: pointer;
  border: 1px solid var(--ak-line); padding: .75rem .9rem; margin-bottom: -1px;
  transition: border-color .12s, background .12s;
}
.pay-method:hover, .billing-option:hover { background: var(--ak-ground); }
.pay-method input, .billing-option input { margin-top: .2rem; accent-color: var(--ak-accent); flex: 0 0 auto; }
.pay-method:has(input:checked), .billing-option:has(input:checked) {
  border-color: var(--ak-accent); box-shadow: inset 0 0 0 1px var(--ak-accent); position: relative; z-index: 1;
}
.pay-method__body, .billing-option__body { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.pay-method__title, .billing-option__org { font-weight: 600; }
.pay-method__title .bi { color: var(--ak-accent); margin-right: .4rem; }
.billing-list { display: flex; flex-direction: column; }
.billing-option__head { display: flex; align-items: center; gap: .45rem; }
.billing-option .billing-edit { flex: 0 0 auto; padding: 0; color: var(--ak-accent); }
.cash-code-field, .autopay-field { margin-top: .3rem; padding: .75rem .9rem; background: var(--ak-ground); }
.autopay-field { border: 1px solid var(--ak-line-strong); }
.autopay-field .form-check-input { accent-color: var(--ak-accent); }

/* ============================================================================
   11. Library setup — seat chips
   ============================================================================ */
.setup-seats { display: flex; flex-wrap: wrap; gap: -1px; }
.setup-seat {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.9rem; padding: .12rem .35rem; margin: 0 -1px -1px 0;
  border: 1px solid var(--ak-line);
  font-family: var(--ak-font-mono); font-size: .66rem;
  color: var(--ak-ink); background: var(--ak-panel);
}
.setup-seat--fixed { box-shadow: inset 0 0 0 2px var(--ak-accent); position: relative; z-index: 1; }

/* Select2: the bootstrap-5 theme flex-grows containers inside an .input-group,
   overriding the compact width Select2 resolved. Pin the country-code picker. */
.input-group > .select2-container { flex: 0 0 auto !important; width: 100px !important; }

/* Chart.js runs maintainAspectRatio:false, so the canvas MUST live in a
   fixed-height relative box or its height feeds back into an auto-height
   parent and the page grows without bound. */
.report-chart { position: relative; width: 100%; height: 280px; }
.report-chart > canvas { width: 100% !important; height: 100% !important; }
.report-chart.report-chart-sm { height: 200px; }

/* Theme segmented switcher (account menu) */
.theme-switch { display: grid; grid-template-columns: repeat(3, 1fr); }
.theme-switch-btn {
  display: flex; flex-direction: column; align-items: center; gap: .3rem;
  padding: .5rem .25rem; margin-right: -1px;
  border: 1px solid var(--ak-line); background: var(--ak-panel);
  color: var(--ak-ink-muted); cursor: pointer;
  font-family: var(--ak-font-mono); font-size: .56rem;
  letter-spacing: .08em; text-transform: uppercase; line-height: 1;
}
.theme-switch-btn i { font-size: 1rem; }
.theme-switch-btn:hover { background: var(--ak-ground); color: var(--ak-ink); }
.theme-switch-btn.active {
  color: var(--ak-accent); box-shadow: inset 0 0 0 1px var(--ak-accent);
  position: relative; z-index: 1;
}

/* ============================================================================
   RESPONSIVE FLOOR — the phone is the primary device for library staff.
   Verified at 320 / 390 / 768 / 1024 / 1440.
   ============================================================================ */
/* Nothing may scroll the page sideways (ai/standards.md). The app shell already
   pins .app-body to the viewport; this covers the auth/public layouts, which
   scroll normally. */
html { max-width: 100%; overflow-x: hidden; }

/* Micro-labels are wide-tracked by design, which makes them wrap badly in a
   narrow KPI card. Tighten the tracking as the viewport shrinks rather than
   letting "COLLECTED THIS MONTH" break across three lines. */
@media (max-width: 575.98px) {
  .app-eyebrow { letter-spacing: .07em; font-size: .58rem; }
  .app-content { padding: .85rem; }
  .app-header__bar { gap: .4rem; padding: .4rem .5rem; }
  .app-icon-button { width: 2.15rem; height: 2.15rem; }
  .library-switcher__btn { max-width: 9.5rem; padding: .28rem .45rem; font-size: .78rem; }
  /* A KPI tile stacks its icon above the figure instead of squeezing beside it —
     a six-figure rupee amount needs the tile's whole width. */
  .ak-kpi { display: block !important; }
  .ak-kpi .ak-chip { margin-bottom: .45rem; }
  .app-page-header { padding-bottom: .75rem; margin-bottom: 1rem; }
  .modal-dialog { margin: .5rem; }
}

/* Tablet: the rail is gone (lg-), so content gets the full width. */
@media (min-width: 576px) and (max-width: 991.98px) {
  .app-content { padding: 1.25rem; }
}

/* Long, unbreakable strings (emails, slugs, IDs) must not push the layout wide. */
.app-content { overflow-wrap: anywhere; }
.app-content .table { overflow-wrap: normal; }

/* Any table wider than its column scrolls inside its own box, never the page. */
.table-responsive { -webkit-overflow-scrolling: touch; }

/* ============================================================================
   12. Motion — one quiet entrance; zeroed by prefers-reduced-motion (app.css)
   ============================================================================ */
@media (prefers-reduced-motion: no-preference) {
  .app-content > * { animation: ak-rise .26s cubic-bezier(.2, .7, .2, 1) both; }
  @keyframes ak-rise { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
}

.cursor-pointer { cursor: pointer; }
.min-w-0 { min-width: 0; }
.tracking-widest { letter-spacing: .3em; }
