/* shell.css — the app chrome: top bar, left sidebar, and the footer.
 *
 * Loaded by all three layouts. The public site needs only the footer half; the
 * sidebar rules cost it nothing, because nothing on a public page carries the
 * markup they select.
 *
 * These rules used to live in panel/assets/css/admin.css. When the judge portal
 * moved to the same layout (2026-09-13) the choice was copy ~45 lines into
 * site.css or share one file; copies drift, and a sidebar that behaves subtly
 * differently in two places is worse than one that behaves the same everywhere.
 *
 * The `mjp-a-` prefix is HISTORICAL — it stood for "admin" when the panel was
 * the only thing with a sidebar. Renaming it would touch 68 files of markup for
 * no user-visible gain, so it stays and this comment explains it.
 *
 * Colors come from whichever stylesheet loads alongside this one (admin.css or
 * site.css); both define the same custom properties, and App\Core\Theme
 * overrides them per school. Only the two shell measurements live here.
 */
:root { --topbar-h:58px; --sidebar-w:236px; }

/* Topbar */
.mjp-a-topbar{position:fixed;top:0;left:0;right:0;height:var(--topbar-h);background:var(--navy);
  display:flex;align-items:center;gap:.75rem;padding:0 1.1rem;z-index:1030;box-shadow:0 2px 10px rgba(10,31,56,.2)}
.mjp-a-brand{color:#fff;font-weight:700;font-size:1.1rem;text-decoration:none;display:flex;align-items:center;gap:.5rem;
  min-width:0}
/* A school program name is long ("Lakeside HS Speech & Debate") and the bar is a
   fixed 58px — on a phone it wrapped to two lines and spilled out of the bar.
   Truncate instead: the school already knows its own name. */
.mjp-a-brand-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mjp-a-topbar > .ms-auto{flex:none}
@media (max-width:575px){ .mjp-a-brand{font-size:1rem} }
.mjp-a-brand-mark{display:inline-grid;place-items:center;width:30px;height:30px;border-radius:8px;background:var(--gold);color:var(--on-accent)}
.mjp-a-userpill{align-items:center;gap:.4rem;color:rgba(255,255,255,.9);font-size:.9rem}
.mjp-a-rolebadge{background:rgba(255,255,255,.15);color:#fff;border-radius:1rem;padding:.1rem .55rem;font-size:.72rem;text-transform:capitalize}
.mjp-a-iconbtn{color:rgba(255,255,255,.85);font-size:1.15rem;text-decoration:none}
.mjp-a-iconbtn:hover{color:#fff}
.mjp-a-iconbtn.active{color:var(--gold)}
.mjp-a-hamburger{background:none;border:none;width:26px;height:22px;position:relative;padding:0}
.mjp-a-hamburger span{display:block;height:2px;background:#fff;margin:4px 0;border-radius:2px}
/* The brand mark is 34px on the public site and 30px in a 58px top bar. Scoped
   (two classes) rather than a bare override, so it wins regardless of whether
   this file loads before or after site.css / admin.css. */
.mjp-a-topbar .mjp-mark{width:30px;height:30px;border-radius:8px}
.mjp-a-topbar .mjp-mark.mjp-mark-logo{width:auto;max-width:170px;height:34px;border-radius:0}

/* Shell */
.mjp-a-shell{display:flex;padding-top:var(--topbar-h);min-height:100vh}
.mjp-a-sidebar{width:var(--sidebar-w);background:var(--navy-dark);position:fixed;top:var(--topbar-h);bottom:0;left:0;
  padding:1rem .75rem;overflow-y:auto;z-index:1020;transition:transform .25s}
.mjp-a-navlist{list-style:none;padding:0;margin:0 0 .5rem}
.mjp-a-navitem{display:flex;align-items:center;gap:.65rem;color:rgba(255,255,255,.78);text-decoration:none;
  padding:.6rem .8rem;border-radius:.55rem;font-weight:500;font-size:.94rem;margin-bottom:.15rem}
.mjp-a-navitem:hover{background:rgba(255,255,255,.08);color:#fff}
.mjp-a-navitem.active{background:var(--gold);color:var(--on-accent);font-weight:600}
.mjp-a-navlabel{color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.1em;font-size:.7rem;
  padding:.6rem .8rem .3rem}

/* Collapsible sidebar groups (<details>/<summary>). The summary IS the group
   label, so it keeps .mjp-a-navlabel and gains a chevron that rotates on open.
   Native <details> means this still works with JavaScript off, and keyboard and
   screen-reader behaviour comes for free instead of hand-rolled ARIA. */
.mjp-a-navgroup{margin-bottom:.15rem}
.mjp-a-navgroup > summary{display:flex;align-items:center;justify-content:space-between;gap:.5rem;
  cursor:pointer;list-style:none;border-radius:.5rem;user-select:none}
.mjp-a-navgroup > summary::-webkit-details-marker{display:none}   /* Safari's default triangle */
.mjp-a-navgroup > summary:hover{color:rgba(255,255,255,.75);background:rgba(255,255,255,.05)}
.mjp-a-navgroup > summary:focus-visible{outline:2px solid var(--gold);outline-offset:-2px}
.mjp-a-navgroup > summary::after{content:"";width:.5rem;height:.5rem;flex:none;margin-right:.15rem;
  border-right:2px solid currentColor;border-bottom:2px solid currentColor;
  transform:rotate(45deg) translate(-2px,-2px);transition:transform .15s}
.mjp-a-navgroup[open] > summary::after{transform:rotate(225deg) translate(-2px,-2px)}
/* A collapsed group still holding the current page keeps a hint of the accent. */
.mjp-a-navgroup:not([open]) > summary:has(+ ul .mjp-a-navitem.active){color:var(--gold)}

/* min-width:0 is load-bearing, not tidiness. A flex item's default
   min-width:auto refuses to shrink below its content, so ONE wide child — a
   table with min-width:760px, a long unbroken string, a multi-column grid —
   stretches this COLUMN itself past the viewport, which drags the content,
   headings and footer out of alignment with the fixed sidebar. With min-width:0
   the column stays viewport width and only the offending child pokes out.

   So this is half the job, measured 2026-10-20: it protects the layout, not the
   page from scrolling sideways. Containing the child is still the child's own
   job — every table carries .mjp-a-rtable (cards at <=768px) or sits in a
   .table-responsive, and the crossfire grid uses minmax(min(100%,280px),1fr).
   admin_ui_harness.php fails if wide content ships without one of those.

   Shared by the panel AND the portal, so this is the only place it belongs. */
.mjp-a-main{flex:1;min-width:0;margin-left:var(--sidebar-w)}
.mjp-a-content{padding:1.75rem;max-width:1320px}
.mjp-a-overlay{display:none;position:fixed;inset:var(--topbar-h) 0 0 0;background:rgba(10,31,56,.45);z-index:1010}

/* Sticky footer: let the content column grow so the footer sits at the bottom
   even on a short page. */
.mjp-a-main{display:flex;flex-direction:column;min-height:calc(100vh - var(--topbar-h))}
.mjp-a-content{flex:1 0 auto}

/* ── Footer ──────────────────────────────────────────────────────────────────
   One footer for all three layouts (app/Views/partials/footer.php). Two columns
   on a wide screen, one centered stack on a phone.

   Every item is its own flex child with a gap, so a narrow screen wraps BETWEEN
   items. The old markup was one run of inline text with " · " separators typed
   between the links, which broke mid-phrase ("© 2026 MaD / Development, LLC").
   The separators are drawn by ::before now — they belong to the layout, not the
   content, and the first one is suppressed. */
/* margin-top:0 deliberately. Both sticky-footer layouts grow the content column
   to fill the viewport, so a margin here pushes the footer BELOW the fold and
   invents a scrollbar on a short page. The breathing room comes from the content
   area's own bottom padding. */
.mjp-footer{flex-shrink:0;background:var(--navy-dark,#0a1f38);color:rgba(255,255,255,.75);
  padding:1.4rem 1.75rem;margin-top:0}
.mjp-footer-inner{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:flex-start;
  gap:1rem 1.5rem;max-width:1320px;margin:0 auto}
.mjp-footer-brand{display:flex;flex-direction:column;gap:.2rem;min-width:0}
.mjp-footer-name{display:flex;align-items:center;gap:.55rem;color:#fff;font-weight:600;
  font-family:'Sora',sans-serif}
.mjp-poweredby{font-size:.78rem;color:rgba(255,255,255,.6)}
.mjp-poweredby a{color:rgba(255,255,255,.8);text-decoration:none}
.mjp-poweredby a:hover{color:#fff;text-decoration:underline}

.mjp-footer-meta{display:flex;flex-direction:column;gap:.25rem;align-items:flex-end;font-size:.85rem}
.mjp-footer-links{display:flex;flex-wrap:wrap;gap:.15rem .55rem}
.mjp-footer-links a,.mjp-footer-copy a{color:rgba(255,255,255,.85);text-decoration:none;white-space:nowrap}
.mjp-footer-links a:hover,.mjp-footer-copy a:hover{color:#fff;text-decoration:underline}
.mjp-footer-links a + a::before{content:"·";color:rgba(255,255,255,.45);margin-right:.55rem}
.mjp-footer-copy{color:rgba(255,255,255,.6);white-space:nowrap}

/* Phone: one centered stack. Nothing is dropped — it is the same footer, folded. */
@media (max-width:575px){
  .mjp-footer{padding:1.25rem 1rem;text-align:center}
  .mjp-footer-inner{flex-direction:column;align-items:center;gap:.9rem}
  .mjp-footer-brand{align-items:center}
  .mjp-footer-name{justify-content:center;flex-wrap:wrap}
  .mjp-footer-meta{align-items:center}
  .mjp-footer-links{justify-content:center}
}

/* Focus mode — a flow sheet wants every pixel.
   `<body class="mjp-focus">` (set by the ballot views) hides the sidebar on the
   desktop layout too and gives the content the full width. The sidebar is still
   there: the hamburger, which normally only shows below 992px, stays visible and
   slides the same drawer out. Nothing is unreachable, it is just out of the way
   while a judge is flowing a round. */
body.mjp-focus .mjp-a-sidebar{transform:translateX(-100%)}
body.mjp-focus .mjp-a-sidebar.open{transform:translateX(0)}
body.mjp-focus .mjp-a-main{margin-left:0}
body.mjp-focus .mjp-a-content{max-width:none}
body.mjp-focus .mjp-a-hamburger{display:block!important}
body.mjp-focus .mjp-a-overlay.show{display:block}

/* Below 992px the sidebar is a drawer over the page on EVERY page, opened by the
   hamburger and closed by tapping the overlay or any link inside it. */
@media (max-width:991px){
  .mjp-a-sidebar{transform:translateX(-100%)}
  .mjp-a-sidebar.open{transform:translateX(0)}
  .mjp-a-main{margin-left:0}
  .mjp-a-content{padding:1.1rem}
  .mjp-a-overlay.show{display:block}
}
