/* MedEikon Portal - Accordion Component
   ================================================================
   Stylesheet for the merged site > trailer > detail accordion.
   Pairs with medeikon-accordion.js and medeikon-icons.js.

   Load order in the page:
     1. <link rel="stylesheet" href="medeikon-accordion.css">
     2. <script src="medeikon-icons.js"></script>
     3. <script src="medeikon-accordion.js"></script>

   No build step, no external dependencies - plain CSS custom
   properties for theming (light/dark switch toggles a
   [data-theme] attribute on <html>).
   ================================================================ */


/* ---------------------------------------------------------
   Tokens - every colour comes from here
   --------------------------------------------------------- */
:root {
  color-scheme: light;
  --page-bg: #ffffff;
  --panel-bg: #ffffff;
  --stripe: #f4f6f3;
  --ink: #17211d;
  --accent: #538234;
  --accent-hover: #3f6527;
  --on-accent: #ffffff;
  --heading: #3f6527;
  --line: rgba(83, 130, 52, 0.28);
  --rule: rgba(23, 33, 29, 0.12);
  --focus: #538234;
  --ok: #2e7d32;
  --fail: #c62828;
  --radius: 0.65rem;
  --control-height: 2.4rem;

  /* One spacing value for every gap: between tiers, between a tier
     and its contents, and between the panels. Change it here and the
     whole page stays evenly spaced. */
  --gap: 0.75rem;
  --toggle-size: 2.3rem;
  --panel-col: 20rem;
  --indent: clamp(0.6rem, 2.5vw, 2rem);
}

[data-theme="dark"] {
  color-scheme: dark;
  --page-bg: #121711;
  --panel-bg: #1a201a;
  --stripe: #202719;
  --ink: #e6ece3;
  --accent: #4c7a30;
  --accent-hover: #5f9740;
  --on-accent: #ffffff;
  --heading: #9ec97a;
  --line: rgba(158, 201, 122, 0.26);
  --rule: rgba(230, 236, 227, 0.14);
  --focus: #9ec97a;
  --ok: #7fc784;
  --fail: #ef7b7b;
}

* { box-sizing: border-box; }

/* Always reserve room for the scrollbar. Without this, a layout that
   grows the page taller makes the scrollbar appear, which narrows the
   window, which can undo the layout, which removes the scrollbar again -
   the page ends up flickering between two states at certain widths. */
html { scrollbar-gutter: stable; }

body {
  margin: 0;
  background: var(--page-bg);
  color: var(--ink);
  font-family: "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  transition: background-color 220ms ease, color 220ms ease;
}

button, input, select { font: inherit; }

button:focus-visible,
select:focus-visible,
input:focus-visible + .radio-indicator,
[role="button"]:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

svg { display: block; }

/* Stroked icons, drawn in the current text colour */
.icon-glyph {
  width: 100%; height: 100%;
  fill: none; stroke: currentColor;
  stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round;
}

/* Brand-green form checkboxes: take the accent instead of the browser
   default blue (matches the table-options menu ticks). Token-driven, so it
   follows the accent in both light and dark. */
input[type="checkbox"] { accent-color: var(--accent); }

/* MedEikon icons. The green tile has been stripped out of the artwork,
   so these now take their colour from whatever contains them - except
   the signal strengths and feedback faces, which keep their own colours
   because the colour carries the meaning. */
.mei-icon { width: 1.5rem; height: 1.5rem; flex: 0 0 auto; }

/* ---------------------------------------------------------
   Shell
   --------------------------------------------------------- */
.app-shell { display: flex; flex-direction: column; min-height: 100vh; }
.app-body { flex: 1 0 auto; padding: clamp(0.75rem, 2vw, 1.5rem); }

/* Briefly holds the page's scrollable height while a region collapses, so
   the browser never force-scrolls the content upward. Height is set from
   the script and is zero at rest. */
.collapse-spacer { height: 0; }

/* ---------------------------------------------------------
   Header
   --------------------------------------------------------- */
.app-header {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: 0.75rem 1rem;
  padding: 0.9rem clamp(0.75rem, 2vw, 1.5rem);
  border-bottom: 1px solid var(--line);
}

.brand { display: flex; align-items: center; gap: 1rem; min-width: 0; }

/* Account, edge, user and broker status, as the portal shows them */
.account-block {
  min-width: 0;
  font-size: 0.78rem;
  line-height: 1.45;
  opacity: 0.85;
}
.account-block > div { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#acct-name { font-weight: 700; opacity: 1; }

.brand-button {
  display: flex; align-items: center;
  border: 0; padding: 0; background: transparent;
  cursor: pointer; border-radius: 0.35rem;
}

.brand-logo { display: block; width: auto; height: 4.5rem; }
.brand-logo-dark { display: none; }
[data-theme="dark"] .brand-logo-light { display: none; }
[data-theme="dark"] .brand-logo-dark { display: block; }

.header-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }

/* Pill buttons. All header controls share one height so they can
   never drift apart when padding or font size changes. */
.header-button {
  display: inline-flex; align-items: center; gap: 0.55rem;
  height: var(--control-height);
  padding: 0 1.05rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  cursor: pointer;
  color: var(--ink); background: transparent;
  font-size: 0.88rem; font-weight: 600;
  transition: border-color 170ms ease, color 170ms ease;
}

.header-button:hover { border-color: var(--accent); color: var(--accent); }
.header-button .icon-glyph { width: 1.15rem; height: 1.15rem; stroke-width: 2; }

/* Both labels sit in the same grid cell, so the button is always as wide
   as the longer of the two and never resizes when the theme flips. Which
   one shows is decided by CSS from the theme attribute, so there is no
   JavaScript involved and no width change to chase. */
.theme-label { display: grid; }
.theme-label > span { grid-area: 1 / 1; text-align: left; }
.theme-label-light { visibility: hidden; }

[data-theme="dark"] .theme-label-dark { visibility: hidden; }
[data-theme="dark"] .theme-label-light { visibility: visible; }

.feedback-group {
  display: inline-flex; align-items: center; gap: 0.15rem;
  height: var(--control-height);
  padding: 0 0.45rem 0 0.85rem;
  border: 1px solid var(--line);
  border-radius: 999px;
}

/* "Thanks" replaces the word "Feedback" rather than sitting after it, so
   it adds no width at all - no empty gap while it is absent, and nothing
   moves when it appears. Both words share one grid cell, so the slot is
   always as wide as the longer of the two. */
.feedback-label {
  display: grid;
  margin-right: 0.4rem;
  font-size: 0.82rem;
  font-weight: 600;
  opacity: 0.85;
}

.feedback-label > span { grid-area: 1 / 1; white-space: nowrap; text-align: left; }
.feedback-label-thanks { visibility: hidden; color: var(--heading); }

.feedback-group.is-answered .feedback-label-default { visibility: hidden; }
.feedback-group.is-answered .feedback-label-thanks { visibility: visible; }

/* Unchosen faces are dimmed rather than nearly erased, and each sits on a
   faint disc so the paler ones have something to read against instead of
   bare white. */
.feedback-button {
  display: inline-grid; place-items: center;
  width: 1.85rem; height: 1.85rem;
  border: 0; border-radius: 50%; padding: 0;
  cursor: pointer;
  background: rgba(23, 33, 29, 0.07);
  opacity: 0.72;
  transition: opacity 150ms ease, transform 150ms ease, background-color 150ms ease;
}

[data-theme="dark"] .feedback-button { background: rgba(255, 255, 255, 0.08); }

.feedback-button:hover { opacity: 1; transform: translateY(-1px); }
.feedback-button[aria-pressed="true"] { opacity: 1; background: rgba(83,130,52,0.18); }
[data-theme="dark"] .feedback-button[aria-pressed="true"] { background: rgba(158,201,122,0.2); }
.feedback-button .mei-icon { width: 1.45rem; height: 1.45rem; }

/* The faces carry their own colours, which are pitched for a dark
   background. On the light theme the amber in particular disappears
   against white, so they are deepened rather than recoloured - the
   traffic-light meaning stays intact. */
:root:not([data-theme="dark"]) .feedback-button .mei-icon {
  filter: saturate(1.25) brightness(0.82);
}

/* The amber needs deepening further than the other two - at the shared
   setting it still only reached about 2.5:1 against white, under the 3:1
   usually asked of a graphic element. */
:root:not([data-theme="dark"]) .feedback-button[data-feedback="neutral"] .mei-icon {
  filter: saturate(1.5) brightness(0.7);
}

/* ---------------------------------------------------------
   Nav - scrolls sideways on small screens rather than stacking
   into a tall wall of buttons
   --------------------------------------------------------- */
.app-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  padding: 0.8rem clamp(0.75rem, 2vw, 1.5rem) 0;
}

.nav-button {
  flex: 0 0 auto;
  text-align: center;
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  padding: 0.42rem 0.95rem;
  cursor: pointer;
  color: var(--on-accent); background: var(--accent);
  font-size: 0.86rem; font-weight: 600;
  transition: background-color 160ms ease;
}

.nav-button:hover { background: var(--accent-hover); }
.nav-button[aria-current="page"] { background: var(--accent-hover); box-shadow: inset 0 0 0 2px rgba(255,255,255,0.55); }

/* ---------------------------------------------------------
   Collapse to a dropdown

   A row of items that would otherwise wrap or scroll when the window
   narrows. The script measures the row once, and when it no longer
   fits it moves the very same buttons into a dropdown panel - they are
   moved, not duplicated, so there is only ever one of each.
   --------------------------------------------------------- */
.collapsible {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 0.3rem;
  min-width: 0;
}

/* Allowed to wrap now - the script decides when there are too many lines
   and only then swaps the row for the menu. */
.collapsible-row { display: flex; flex-wrap: wrap; gap: 0.3rem; min-width: 0; }
.collapsible.is-compact > .collapsible-row { display: none; }

.menu-trigger {
  display: none;
  align-self: flex-start;
  align-items: center;
  gap: 0.4rem;
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  padding: 0.42rem 0.8rem;
  cursor: pointer;
  color: var(--on-accent);
  background: var(--accent);
  font-size: 0.86rem;
  font-weight: 600;
  white-space: nowrap;
}

.collapsible.is-compact > .menu-trigger { display: inline-flex; }
.menu-trigger .icon-glyph { width: 0.95rem; height: 0.95rem; transition: transform 200ms ease; }

/* The navigation collapses to a single large hamburger, centred, rather
   than a worded button. Nothing about it changes when a section is chosen,
   so it cannot resize or shift anything around it. */
.menu-trigger-icon {
  align-self: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  padding: 0;
  border-radius: var(--radius);
}

.menu-trigger-icon .icon-glyph {
  width: 1.7rem;
  height: 1.7rem;
  stroke-width: 2.4;
  transition: none;
}

/* The label text changes - "13 of 13 fields" becomes "9 of 13 fields",
   a section name becomes a longer one. A hidden copy of the widest text
   sits in the same grid cell so the button is always that wide and never
   resizes, which would shove whatever sits beside it. */
.menu-trigger-text { display: grid; }
.menu-trigger-text > span { grid-area: 1 / 1; text-align: left; white-space: nowrap; }
.menu-trigger-ghost { visibility: hidden; }
.menu-trigger[aria-expanded="true"] .icon-glyph { transform: rotate(90deg); }

/* The menu opens in the flow and pushes the page down, using the same
   grid-row animation as the accordions rather than floating over the
   content. Padding sits on the inner element, never on the one being
   animated, so a closed menu collapses to nothing. */
/* Sits on its own full-width row beneath the control, so the chips can
   use the whole box rather than only the column under the trigger. */
.menu-panel {
  flex: 1 1 100%;
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 260ms cubic-bezier(.2, .8, .2, 1);
}

.menu-panel.is-open { grid-template-rows: 1fr; }
.menu-panel > div { min-height: 0; overflow: hidden; }

/* Items wrap rather than stacking one per line - thirteen fields in a
   single column pushed half the page off the bottom. */
.menu-items {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  padding: 0.15rem 0 0.25rem;
}

/* ---------------------------------------------------------
   Nav dropdown groups   (new-nav.php)

   A top-level .nav-button that reveals a panel of sub-buttons, plus a
   three-bar button that collapses the whole bar into a stacked menu on
   narrow screens. Deliberately separate from the width-measured
   .collapsible / .menu-* collapse above, so the two never clash. The
   open/close behaviour is in new-javascript.js?2026082801 (section 4b).

   Who sees which button is decided in the PHP (the same if ($isadmin) /
   if ($issuperadmin) / isset($account) / isset($edge) guards the old nav
   files use) - a button the user may not have is simply not rendered.
   There are no role/scope classes here on purpose: one source per fact.
   --------------------------------------------------------- */
.nav-groups {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 0.4rem; flex: 1 1 auto; min-width: 0;
}

.nav-group { position: relative; display: inline-flex; }

/* the trigger is an ordinary .nav-button carrying a caret */
.nav-group > .nav-button { display: inline-flex; align-items: center; gap: 0.4rem; }

.nav-caret {
  width: 0.72rem; height: 0.72rem; flex: 0 0 auto;
  fill: none; stroke: currentColor; stroke-width: 2.4;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform 200ms ease;
}
.nav-group.is-open > .nav-button { background: var(--accent-hover); }
.nav-group.is-open > .nav-button .nav-caret { transform: rotate(90deg); }

/* the panel - a bordered surface, not a block of solid green. The literal
   rgba() shadow matches the login-card and popup shadows already here. */
.nav-submenu {
  position: absolute; top: calc(100% + 0.35rem); left: 0; z-index: 50;
  display: none; flex-direction: column; gap: 0.25rem; min-width: 100%;
  padding: 0.4rem;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--panel-bg);
  box-shadow: 0 6px 20px rgba(23, 33, 29, 0.18);
}
.nav-group.is-open > .nav-submenu { display: flex; }

/* Desktop: open the dropdown on hover (the click handler still works, so touch
   devices and the stacked narrow menu are unaffected). A transparent bridge
   fills the 0.35rem gap between trigger and panel so the hover never drops. */
@media (min-width: 761px) {
  .nav-group:hover > .nav-submenu { display: flex; }
  .nav-group:hover > .nav-button { background: var(--accent-hover); }
  .nav-group:hover > .nav-button .nav-caret { transform: rotate(90deg); }
  .nav-group > .nav-submenu::before {
    content: ""; position: absolute; left: 0; right: 0; top: -0.35rem; height: 0.35rem;
  }
}

.nav-subitem {
  text-align: left; white-space: nowrap;
  border: 1px solid transparent; border-radius: calc(var(--radius) - 0.25rem);
  padding: 0.42rem 0.7rem; cursor: pointer;
  color: var(--ink); background: transparent;
  font-size: 0.86rem; font-weight: 600;
  transition: background-color 150ms ease, color 150ms ease;
}
.nav-subitem:hover { background: var(--accent); color: var(--on-accent); }
.nav-subitem[aria-current="page"] { background: var(--accent-hover); color: var(--on-accent); }

/* Divider between submenu sections (e.g. the superadmin split in the Account menu).
   The dropdown stacks vertically, so the separator is a thin horizontal rule across
   the menu width. Insert one from PHP with mei_nav_divider() in new-nav.php. */
.nav-submenu .nav-subdivider { height: 1px; margin: 0.3rem 0.35rem; background: var(--line); }

/* the parent trigger reflects an active child: the PHP adds .has-current
   to the .nav-group whose sub-item is the current page. */
.nav-group.has-current > .nav-button {
  background: var(--accent-hover);
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.55);
}

/* new-window marker - e.g. Explorer and VNA open in their own window */
.nav-ext { font-size: 0.85em; opacity: 0.85; margin-left: 0.1rem; }

/* the three-bar trigger: hidden until the nav collapses (narrow screens) */
.nav-hamburger {
  display: none; align-items: center; justify-content: center;
  flex: 0 0 auto; width: 3rem; height: 3rem; padding: 0;
  border: 1px solid var(--accent); border-radius: var(--radius);
  cursor: pointer; color: var(--on-accent); background: var(--accent);
}
.nav-hamburger .icon-glyph { width: 1.5rem; height: 1.5rem; stroke-width: 2.4; }

/* Narrow: the three-bar trigger shows, the inline row hides, and opening
   it stacks the top-level buttons; each still opens its own sub-buttons in
   the flow - a three-tier menu (bars > groups > items). */
@media (max-width: 760px) {
  .nav-hamburger { display: inline-flex; }

  .app-nav .nav-groups { display: none; }
  .app-nav.is-menu-open .nav-groups {
    display: flex; flex-direction: column; align-items: stretch;
    width: 100%; gap: 0.3rem;
  }
  .app-nav.is-menu-open .nav-group { width: 100%; flex-direction: column; align-items: stretch; }
  .app-nav.is-menu-open .nav-group > .nav-button { width: 100%; justify-content: space-between; }
  .app-nav.is-menu-open .nav-groups > .nav-button { width: 100%; text-align: left; }
  .app-nav.is-menu-open .nav-submenu {
    position: static; min-width: 0; border: 0; box-shadow: none;
    padding: 0.15rem 0 0.35rem 0.9rem;
  }
}

/* ---------------------------------------------------------
   Accordion
   --------------------------------------------------------- */
/* Every level uses the same flex-column-with-gap pattern, so the space
   between two tiers and the space between a tier and its contents are
   always identical. */
.accordion-stack,
.tier-2-shell,
.tier-3-shell {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
}

.accordion-region {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows 300ms cubic-bezier(.2,.8,.2,1);
}
.accordion-region.is-open { grid-template-rows: 1fr; }
.accordion-region > .region-inner { min-height: 0; overflow: hidden; }

/* Padding lives inside the clipped wrapper, never on it, so a closed
   panel collapses to exactly nothing and every gap on the page is the
   same --gap value. */

.accordion-row {
  display: flex; align-items: center; gap: 0.6rem;
  border-radius: var(--radius);
  background: var(--accent); color: var(--on-accent);
  transition: background-color 180ms ease;
}
.accordion-row:hover { background: var(--accent-hover); }

.tier-1-row { min-height: 3.3rem; padding: 0.4rem 0.7rem; }
.tier-2-shell { padding: var(--gap) 0 0 var(--indent); }
.tier-2-row { min-height: 3rem; padding: 0.35rem 0.65rem; }

/* The trailer bar carries the trailer name and its action buttons. */

.bar-actions {
  display: inline-flex;
  flex: 0 0 auto;
  gap: 0.15rem;
}

.bar-action {
  display: inline-grid;
  place-items: center;
  width: 1.9rem;
  height: 1.9rem;
  border: 0;
  border-radius: 0.35rem;
  padding: 0;
  cursor: pointer;
  color: var(--on-accent);
  background: rgba(255, 255, 255, 0.14);
  transition: background-color 150ms ease;
}

.bar-action:hover { background: rgba(255, 255, 255, 0.3); }
.bar-action .mei-icon,
.bar-action .icon-glyph { width: 1.05rem; height: 1.05rem; }

.tier-3-shell { padding: var(--gap) 0 0 var(--indent); }
.tier-3-row { min-height: 2.8rem; padding: 0.3rem 0.6rem; }
.panel-inner { padding-top: var(--gap); }

.toggle-button {
  display: inline-grid; flex: 0 0 auto; place-items: center;
  width: var(--toggle-size); height: var(--toggle-size);
  border: 0; border-radius: 50%; cursor: pointer;
  color: var(--on-accent); background: transparent;
  transition: background-color 170ms ease;
}
.toggle-button:hover { background: rgba(255,255,255,0.18); }
.toggle-button svg { width: 1.4rem; height: 1.4rem; transition: transform 240ms ease; }
.toggle-button[aria-expanded="true"] svg { transform: rotate(90deg); }

.row-label { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.tier-1-label { font-size: 1.1rem; font-weight: 700; }
.tier-2-label { font-size: 1rem; font-weight: 600; }
.tier-3-label { font-size: 0.94rem; font-weight: 700; }

.row-meta {
  flex: 0 0 auto; margin-left: auto;
  font-size: 0.8rem; font-weight: 600; opacity: 0.9;
  white-space: nowrap;
}

/* ---------------------------------------------------------
   Status panels
   Auto-fitting grid: as many columns as fit, one on a phone.
   --------------------------------------------------------- */
/* Columns rather than a grid. In a grid every row is as tall as its
   tallest panel, so a short panel leaves a block of dead space beneath it
   before the next row starts. Columns let each one sit directly under the
   one above, whatever their heights. */
.panel-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--panel-col), 1fr));
  gap: var(--gap);
  align-items: start;
}

.panel-grid > .panel {
  min-width: 0;
}

.panel {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel-bg);
  overflow: hidden;
}

/* Three columns with equal sides, so the title is centred in the panel
   rather than centred in whatever space the buttons leave over. Without
   it, panels with more buttons push their heading further left and the
   headings no longer line up with each other. */
.panel-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 0.4rem;
  padding: 0.15rem 0.45rem;
  background: var(--accent);
  color: var(--on-accent);
}

.panel-head > .panel-toggle { justify-self: start; }
.panel-head > .panel-actions { justify-self: end; }

/* Action buttons in a panel header sit on the accent bar, so their icons are
   white like the toggle and title. (The same .row-action on a light table row
   keeps the default dark colour - this is scoped to .panel-head only.) */
.panel-head .row-action { color: var(--on-accent); }

/* A fourth tier in effect, so it behaves and animates like the others -
   same chevron, same grid-row transition, padding inside the clipped
   wrapper so a closed panel collapses to nothing. */
.panel-toggle {
  display: inline-grid;
  flex: 0 0 auto;
  place-items: center;
  width: 1.55rem;
  height: 1.55rem;
  border: 0;
  border-radius: 50%;
  padding: 0;
  cursor: pointer;
  color: var(--on-accent);
  background: transparent;
  transition: background-color 170ms ease;
}

.panel-toggle:hover { background: rgba(255, 255, 255, 0.2); }

.panel-toggle .icon-glyph {
  width: 1rem;
  height: 1rem;
  transition: transform 240ms ease;
}

.panel-toggle[aria-expanded="true"] .icon-glyph { transform: rotate(90deg); }

.panel-region {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 260ms cubic-bezier(.2, .8, .2, 1);
}

.panel-region.is-open { grid-template-rows: 1fr; }
.panel-region > .region-inner { min-height: 0; overflow: hidden; }

.panel-title {
  min-width: 0;
  text-align: center;
  font-size: 0.9rem; font-weight: 700;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.panel-actions {
  display: inline-flex; flex: 0 0 auto; gap: 0.1rem;
  padding-left: 0.5rem;
  border-left: 1px solid rgba(255,255,255,0.35);
}

.panel-action {
  display: inline-grid; place-items: center;
  width: 1.8rem; height: 1.8rem;
  border: 0; border-radius: 50%; padding: 0;
  cursor: pointer; color: var(--on-accent); background: transparent;
  transition: background-color 150ms ease;
}
.panel-action:hover { background: rgba(255,255,255,0.2); }
.panel-action .icon-glyph { width: 1rem; height: 1rem; }

.panel-body { padding: 0.3rem 0.6rem 0.6rem; }

/* Panel detail forms: pin the selects to the same width as the text inputs
   so the two line up (identity / dest-edit tables). Tune the one width here. */
.panel-body td input[type="text"],
.panel-body td input[type="password"],
.panel-body td select {
  width: 12rem;
  max-width: 100%;
  box-sizing: border-box;
}

/* panelwide - a panel two standard columns wide (double a normal panel).
   Spans two .panel-grid tracks on wide viewports only (min-width:761px, the
   breakpoint reused from the nav-hover block above); the gate matters because
   a spanning grid item forces a second track to exist, which on a narrow grid
   would push content off-screen. Below the breakpoint the panel sits in one
   track and its content keeps its natural width, scrolling sideways inside
   the panel body - the page itself never scrolls horizontally. */
@media (min-width: 761px) {
  .panel-grid > .panel.panelwide { grid-column: span 2; }
}
.panel.panelwide .panel-body { overflow-x: auto; }
.panel.panelwide .matrix     { min-width: max-content; }

/* Action buttons belong to the row they act on, in a column of their own
   at the end of that row - the same place the portal puts them. Keeping
   them in the flow is what stops them spilling over the row below. */
.pair-actions {
  display: inline-flex;
  flex: 0 0 auto;
  gap: 0.2rem;
  margin-left: auto;
}

.body-action {
  display: inline-grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  border: 1px solid var(--line);
  border-radius: 0.35rem;
  padding: 0;
  cursor: pointer;
  color: var(--accent);
  background: transparent;
  transition: background-color 150ms ease, color 150ms ease, border-color 150ms ease;
}

.body-action:hover { border-color: var(--accent); background: rgba(83,130,52,0.1); }
[data-theme="dark"] .body-action:hover { background: rgba(158,201,122,0.14); }
.body-action .mei-icon { width: 1.1rem; height: 1.1rem; }

/* Locked is a real state, so it is shown as one rather than only
   swapping the icon. */
.body-action[aria-pressed="true"] {
  color: var(--on-accent);
  background: var(--accent);
  border-color: var(--accent);
}



/* Label / value rows. Wraps to two lines rather than truncating,
   so nothing is ever unreadable on a narrow screen. */
.pair-row {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 0.25rem 0.75rem;
  padding: 0.32rem 0;
  border-bottom: 1px solid var(--rule);
  font-size: 0.87rem;
}
.pair-row:last-child { border-bottom: 0; }
.pair-label { flex: 1 1 8rem; font-weight: 600; }
.pair-value { flex: 1 1 8rem; overflow-wrap: anywhere; }
.pair-extra { flex: 1 1 9rem; font-size: 0.82rem; opacity: 0.75; overflow-wrap: anywhere; }

.status-ok { color: var(--ok); font-weight: 700; }
.status-fail { color: var(--fail); font-weight: 700; }
.status-none { opacity: 0.45; }

/* The negative left margin cancels the control's own border and padding,
   so the text inside the dropdown lines up with the plain text in the
   rows above and below it, rather than the box lining up. */
.site-select {
  width: 100%;
  max-width: 16rem;
  margin-left: calc(-0.45rem - 1px);
  padding: 0.1rem 1.4rem 0.1rem 0.45rem;
  border: 1px solid var(--line);
  border-radius: 0.35rem;
  color: var(--ink);
  background: var(--page-bg);
  font-size: 0.87rem;
  line-height: inherit;
}

.site-select:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  background: var(--stripe);
}

/* Connections matrix - its own mini table */
.matrix { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.matrix th {
  padding: 0.3rem 0.35rem;
  border-bottom: 2px solid var(--accent);
  color: var(--heading);
  font-size: 0.7rem; letter-spacing: 0.05em; text-transform: uppercase;
  text-align: center;
}
.matrix th:first-child { text-align: left; }
.matrix td {
  padding: 0.28rem 0.35rem;
  border-bottom: 1px solid var(--rule);
  text-align: center;
}
.matrix td:first-child { text-align: left; font-weight: 400; }
.matrix tr:last-child td { border-bottom: 0; }

/* ---------------------------------------------------------
   Data tables
   --------------------------------------------------------- */
.data-table { border-bottom: 4px solid var(--accent); }

.table-title-bar {
  display: flex; align-items: center; gap: 0.75rem;
  padding: 0.35rem 0.55rem;
  border-radius: var(--radius) var(--radius) 0 0;
  background: var(--accent); color: var(--on-accent);
}

.table-title {
  flex: 1 1 auto; min-width: 0; text-align: center;
  font-size: 0.92rem; font-weight: 700;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.table-title-actions {
  display: inline-flex; flex: 0 0 auto; gap: 0.1rem;
  padding-left: 0.5rem; border-left: 1px solid rgba(255,255,255,0.35);
}

.title-action {
  display: inline-grid; place-items: center;
  width: 1.8rem; height: 1.8rem;
  border: 0; border-radius: 50%; padding: 0;
  cursor: pointer; color: var(--on-accent); background: transparent;
  transition: background-color 150ms ease;
}
.title-action:hover { background: rgba(255,255,255,0.2); }
.title-action .icon-glyph { width: 1rem; height: 1rem; }

/* --- Table options menu (the 3-dot / kebab): column show/hide + sort. Injected
   into every table's title bar by MeiInitDataTable; supersedes the old
   narrow-screen sort control (.table-sort, hidden below). --- */
.table-title-bar { position: relative; }
.table-sort { display: none !important; }
.table-menu { position: relative; display: inline-flex; margin-left: 0.4rem; }
.table-menu-trigger {   /* matches the .title-action (+) button: transparent green-bar circle, white glyph */
	display: inline-grid; place-items: center;
	width: 1.8rem; height: 1.8rem; padding: 0;
	border: 0; border-radius: 50%;
	background: transparent; color: var(--on-accent);
	font-size: 1.15rem; line-height: 1; cursor: pointer;
	transition: background-color 150ms ease;
}
.table-menu-trigger:hover { background: rgba(255,255,255,0.2); }
.table-menu-panel {
	position: absolute; top: calc(100% + 0.35rem); right: 0; z-index: 60;
	min-width: 16rem; max-height: 70vh; overflow: auto;
	padding: 0.55rem 0.65rem;
	border: 1px solid var(--line); border-radius: var(--radius);
	background: var(--panel-bg); color: var(--ink); box-shadow: 0 6px 20px rgba(23,33,29,0.18);
}
.table-menu-panel h4 { margin: 0.55rem 0 0.3rem; font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink); opacity: 0.55; }
.table-menu-panel h4:first-child { margin-top: 0; }
.table-menu-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 0.1rem 0.6rem; }
.table-menu-panel label { display: flex; align-items: center; gap: 0.45rem; padding: 0.22rem 0.3rem; font-size: 0.82rem; font-weight: 600; border-radius: calc(var(--radius) - 0.25rem); cursor: pointer; white-space: nowrap; }
.table-menu-panel label:hover { background: rgba(83,130,52,0.08); }
:root[data-theme="dark"] .table-menu-panel label:hover { background: rgba(158,201,122,0.12); }
.table-menu-panel input[type="checkbox"] { flex: 0 0 auto; accent-color: var(--accent); }
.table-menu-sort { display: flex; gap: 0.4rem; align-items: center; }
.table-menu-sort select { flex: 1; font: inherit; font-size: 0.82rem; padding: 0.25rem 0.35rem; border: 1px solid var(--line); border-radius: calc(var(--radius) - 0.25rem); background: var(--panel-bg); color: var(--ink); }
.table-menu-dir { width: 2rem; height: 1.85rem; flex: 0 0 auto; border: 1px solid var(--line); border-radius: calc(var(--radius) - 0.25rem); background: var(--panel-bg); color: var(--ink); cursor: pointer; font-size: 0.9rem; }
.table-menu-dir:hover { border-color: var(--accent); }
.table-menu-foot { display: flex; justify-content: space-between; margin-top: 0.55rem; gap: 0.5rem; }
.table-menu-foot button { font: inherit; font-size: 0.78rem; font-weight: 600; background: none; border: 0; color: var(--accent); cursor: pointer; padding: 0.15rem 0.1rem; }
.table-menu-foot button:hover { text-decoration: underline; }

/* Narrow-screen sort control (built by MeiInitDataTable, lives in the title
   bar). Hidden on wide screens where the column headings do the sorting;
   revealed at <=760px, where the headings are hidden. */
.table-sort { display: none; align-items: center; gap: 0.35rem; flex: 0 0 auto; }
.table-sort-label {
  font-size: 0.7rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.04em; opacity: 0.9;
}
.table-sort-select {
  height: 1.8rem; max-width: 9rem;
  border: 1px solid rgba(255,255,255,0.55); border-radius: 0.35rem;
  background: var(--panel-bg); color: var(--ink);
  font-size: 0.8rem; padding: 0 0.35rem; cursor: pointer;
}
.table-sort-dir {
  width: 1.8rem; height: 1.8rem; flex: 0 0 auto;
  display: inline-grid; place-items: center;
  border: 1px solid rgba(255,255,255,0.55); border-radius: 0.35rem;
  background: transparent; color: var(--on-accent);
  cursor: pointer; font-size: 0.95rem; line-height: 1;
}
.table-sort-dir:hover { background: rgba(255,255,255,0.2); }

.table-scroll { overflow-x: auto; border-top: 1px solid var(--line); }

.table-head, .table-row {
  display: grid;
  grid-template-columns: var(--table-columns);
  gap: 0.6rem;
  min-width: var(--table-min-width, 0);
  padding: 0.5rem 0.45rem;
}

.table-head {
  align-items: end;
  border-top: 3px solid var(--accent);
  border-bottom: 3px solid var(--accent);
  color: var(--heading);
  font-size: 0.72rem; font-weight: 700;
  letter-spacing: 0.05em; text-transform: uppercase;
}

.table-row { align-items: center; min-height: 1.8rem; font-size: 0.85rem; border-bottom: 1px solid var(--rule); padding: 0.3rem 0.45rem; }
.table-row:nth-child(even) { background: var(--stripe); }
/* Rollover highlight (after the stripe rule so it wins on even rows too). Matches the
   subtle accent tint used by .body-action / .act-btn hovers, light and dark. */
.table-row:hover { background: rgba(83,130,52,0.12); }
:root[data-theme="dark"] .table-row:hover { background: rgba(158,201,122,0.16); }

.table-head > *, .table-row > * { min-width: 0; }

/* Column headings wrap onto a second line instead of being cut off.
   Body cells still truncate with an ellipsis, with the full value on
   hover, because row data varies far more in length. */
.table-head-cell {
  display: flex; align-items: flex-end; gap: 0.3rem;
  cursor: pointer;
}
.table-head-cell .cell-label {
  min-width: 0;
  overflow-wrap: anywhere;
}

.cell-text {
  min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Fixed-size arrow slot so the heading never shifts when sorting
   changes. Every column keeps an arrow; the active one is solid. */
.table-head-cell::after {
  display: inline-grid; place-items: center;
  width: 1.1em; height: 1em; flex: 0 0 auto;
  content: "\2191";
  color: var(--accent); font-size: 1em; font-weight: 800; line-height: 1;
  opacity: 0.4;
}
[data-theme="dark"] .table-head-cell::after { color: var(--heading); }
.table-head-cell[data-active="true"]::after { opacity: 1; }
.table-head-cell[data-sort-direction="desc"]::after { content: "\2193"; }

.actions-head { justify-self: end; }
.row-actions { display: inline-flex; justify-self: end; gap: 0.25rem; }

.row-action {
  display: inline-grid; place-items: center;
  border: 0; border-radius: 0.3rem; padding: 0;
  cursor: pointer; background: transparent;
  transition: transform 150ms ease, opacity 150ms ease;
}
.row-action:hover { transform: translateY(-1px); opacity: 0.8; }
.row-action .mei-icon { width: 1.3rem; height: 1.3rem; }

.table-empty { padding: 0.9rem 0.5rem; font-size: 0.85rem; opacity: 0.7; }

/* ---------------------------------------------------------
   Filters
   --------------------------------------------------------- */
.filter-stack { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: var(--gap); }

.filter-panel {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.15rem;
  padding: 0.28rem 0.45rem 0.28rem 0.8rem;
  border-radius: var(--radius);
  background: var(--accent);
}

.filter-label {
  margin-right: 0.4rem; color: var(--on-accent);
  font-size: 0.86rem; font-weight: 700; white-space: nowrap;
}

.radio-options { display: flex; flex-wrap: wrap; gap: 0.25rem; }
.radio-option { position: relative; display: inline-flex; align-items: center; cursor: pointer; }
.radio-option input { position: absolute; width: 1px; height: 1px; opacity: 0; }

.radio-indicator {
  display: inline-flex; align-items: center; gap: 0.45rem;
  padding: 0.24rem 0.7rem;
  border-radius: calc(var(--radius) - 0.25rem);
  color: var(--on-accent); font-size: 0.85rem; font-weight: 600;
  white-space: nowrap;
}
.radio-indicator::before {
  content: ""; flex: 0 0 auto;
  width: 0.68rem; height: 0.68rem;
  border: 1.5px solid var(--on-accent); border-radius: 50%;
  transition: background-color 160ms ease;
}
.radio-option input:checked + .radio-indicator { background: rgba(255,255,255,0.16); }
.radio-option input:checked + .radio-indicator::before {
  background: radial-gradient(circle, var(--on-accent) 0 38%, transparent 42%);
}

/* ---------------------------------------------------------
   Footer
   --------------------------------------------------------- */
.app-footer {
  display: flex; flex: 0 0 auto; flex-wrap: wrap;
  align-items: center; justify-content: center;
  gap: 0.35rem 2.5rem;
  padding: 0.7rem 1rem;
  background: var(--accent); color: var(--on-accent);
  font-size: 0.88rem;
}
.app-footer a { color: var(--on-accent); text-decoration: none; }
.app-footer a:hover { text-decoration: underline; }
.footer-item { display: inline-flex; gap: 0.4rem; white-space: nowrap; }
.footer-key { font-weight: 700; }

/* =========================================================
   NARROW SCREENS

   Below 760px each table row becomes its own labelled card.
   The grid and its column headings are dropped entirely, so
   nothing is squeezed, truncated or scrolled off the side -
   every value is shown with its column name beside it.
   ========================================================= */
@media (max-width: 760px) {
  .table-scroll { overflow-x: visible; }
  .table-head { display: none; }

  .table-row {
    display: block;
    min-width: 0;
    margin: 0 0 0.55rem;
    padding: 0.45rem 0.65rem;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--panel-bg);
  }
  .table-row:nth-child(even) { background: var(--stripe); }

  .table-row .cell-text {
    display: flex; justify-content: space-between; gap: 1rem;
    padding: 0.22rem 0;
    white-space: normal;
    overflow: visible;
    border-bottom: 1px solid var(--rule);
  }
  .table-row .cell-text:last-of-type { border-bottom: 0; }

  /* The column name for each value, taken from the header */
  .table-row .cell-text::before {
    content: attr(data-label);
    flex: 0 0 auto;
    color: var(--heading);
    font-size: 0.7rem; font-weight: 700;
    letter-spacing: 0.04em; text-transform: uppercase;
  }

  .table-row .cell-text.is-empty::after { content: "-"; opacity: 0.4; }

  .row-actions { justify-self: start; margin-top: 0.45rem; }

  .table-title { text-align: left; }

  /* The column headings are hidden here, so reveal the title-bar sort control. */
  .table-sort { display: inline-flex; }
}


@media (max-width: 520px) {
  :root { --toggle-size: 2rem; }
  .app-header { justify-content: center; }
  .header-actions { width: 100%; justify-content: center; }
  .brand-logo { height: 3.4rem; }
  .account-block { display: none; }
  .feedback-label { display: none; }

  /* Collapse the header controls to icons only. Their text labels wrapped the
     action bar onto several rows here, pushing the header to ~half the screen;
     as icon buttons they stay one compact row. Each button keeps its name via
     its title / aria-label, so nothing is lost to assistive tech. */
  .header-button { width: var(--control-height); padding: 0; gap: 0; justify-content: center; }
  .header-button > span { display: none; }

  .pair-label, .pair-value, .pair-extra { flex: 1 1 100%; }
  .pair-actions { margin-left: 0; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

/* ================================================================
   Login pages
  
   Sits on top of medeikon-accordion.css and reuses its design
   tokens (colours, radius, control height, spacing), so the login
   screens share the portal's look. Only the login-specific pieces
   live here: the header, the centred card, the fields, the button
   and the error line.

   login.html and login-otp.html need no JavaScript. They are
   ordinary forms that post to the server, and the server outputs
   the red error line when the details are wrong.
   ================================================================ */

/* ---- header: logo + title, no portal controls (not signed in yet) ---- */
.login-header { justify-content: flex-start; }
.brand { display: flex; align-items: center; gap: 1rem; }
.brand-title {
  display: flex; flex-direction: column; line-height: 1.25;
  color: var(--ink); font-size: 1rem;
}
.brand-title .brand-name { font-weight: 700; }
.brand-user { font-size: 0.85rem; color: var(--heading); margin-top: 0.15rem; }

/* ---- the card ---- */
.login-main {
  flex: 1 0 auto;
  display: flex; align-items: flex-start; justify-content: center;
  padding: clamp(1.5rem, 6vh, 4rem) 1rem;
  background: var(--stripe);
}
.login-card {
  display: flex; flex-direction: column;
  width: 100%; max-width: 25rem;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--panel-bg); overflow: hidden;
  box-shadow: 0 1px 3px rgba(23, 33, 29, 0.08);
}
.login-card-title {
  background: var(--accent); color: var(--on-accent);
  padding: 0.7rem 1rem; font-weight: 700; text-align: center;
}
.login-card-body {
  display: flex; flex-direction: column; gap: 1rem;
  padding: 1.25rem;
}

/* ---- error line: the server outputs this when details are wrong ---- */
.login-error {
  margin: 0; color: var(--fail); font-weight: 600; font-size: 0.92rem;
}

/* ---- fields ---- */
.login-field { display: flex; flex-direction: column; gap: 0.35rem; }
.login-field label { font-weight: 600; font-size: 0.9rem; }
.login-field input {
  height: var(--control-height);
  padding: 0 0.7rem;
  border: 1px solid var(--line); border-radius: 0.4rem;
  background: var(--page-bg); color: var(--ink);
  font: inherit;
}
.login-field input:focus-visible {
  outline: 2px solid var(--focus); outline-offset: 1px;
  border-color: var(--focus);
}

/* ---- submit button: solid green, matches the portal ---- */
.login-button {
  align-self: flex-start;
  height: var(--control-height);
  padding: 0 1.4rem;
  border: none; border-radius: var(--radius);
  background: var(--accent); color: var(--on-accent);
  font: inherit; font-weight: 600; cursor: pointer;
  transition: background-color 160ms ease;
}
.login-button:hover { background: var(--accent-hover); }
.login-button:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* ================================================================
   Popups

   Shared modal shell for any new-popup-*.php (feedback, and future
   popups). Sits on top of the tokens at the top of this file, so it
   themes light/dark automatically - every colour is a var(); only the
   translucent scrim and drop-shadow are literal rgba(), the same way
   the header overlays and the login-card shadow already are.

   Markup shape (see new-popup-feedback.php):
     .popup-overlay#xPopup            role="dialog" aria-modal="true"
       .popup (.popup-sm for a narrow one)
         .popup-title  > span + .popup-close
         .popup-body   > .popup-intro, .popup-field(s), .popup-submit
   Open by adding .is-open to the overlay; close by removing it.
   ================================================================ */
.popup-overlay {
  position: fixed; inset: 0; z-index: 1000; display: none;
  align-items: flex-start; justify-content: center;
  padding: 3rem 1rem; overflow: auto;
  background: rgba(23, 33, 29, 0.45);          /* --ink at low alpha, as a scrim */
}
.popup-overlay.is-open { display: flex; }

.popup {
  width: 100%; max-width: 60rem;
  border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden;
  background: var(--panel-bg); color: var(--ink);
  box-shadow: 0 10px 40px rgba(23, 33, 29, 0.3);
}
.popup-sm { max-width: 34rem; }

.popup-title {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.75rem;
  padding: 0.6rem 1rem;
  background: var(--accent); color: var(--on-accent);
  font-weight: 700;
}

.popup-close {
  border: 0; background: transparent; color: var(--on-accent);
  font-size: 1.4rem; line-height: 1; cursor: pointer; padding: 0 0.3rem;
}
.popup-close:hover { opacity: 0.85; }

.popup-body { padding: 1.25rem; }

/* Explanatory line above the fields */
.popup-intro { margin: 0 0 0.9rem; font-size: 0.9rem; line-height: 1.5; }

/* Label stacked above a full-width control. (The throwaway consumables
   demo used a 12rem/1fr grid inline; this stacked form is the shared
   default and suits a full-width comment box.) */
.popup-field { display: flex; flex-direction: column; gap: 0.35rem; margin-bottom: 0.9rem; }
.popup-field > label { font-weight: 600; font-size: 0.9rem; }
.popup-field input,
.popup-field select,
.popup-field textarea {
  width: 100%;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--line); border-radius: 0.4rem;
  background: var(--page-bg); color: var(--ink);
  font: inherit;
}
.popup-field input, .popup-field select { height: var(--control-height); }
.popup-field textarea { min-height: 6rem; resize: vertical; }
.popup-field input:focus-visible,
.popup-field select:focus-visible,
.popup-field textarea:focus-visible {
  outline: 2px solid var(--focus); outline-offset: 1px;
  border-color: var(--focus);
}

.popup-submit {
  height: var(--control-height); padding: 0 1.3rem;
  border: 0; border-radius: var(--radius);
  background: var(--accent); color: var(--on-accent);
  font: inherit; font-weight: 600; cursor: pointer;
  transition: background-color 160ms ease;
}
.popup-submit:hover { background: var(--accent-hover); }
.popup-submit:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* Actions row: buttons aligned to the right of a popup body (a primary
   .popup-submit plus a secondary .popup-cancel). Promoted from
   new-popup-downloads.php so any popup can reuse it. */
.popup-actions { display: flex; justify-content: flex-end; gap: 0.6rem; margin-top: 0.4rem; }

/* Secondary / cancel button - the muted counterpart to .popup-submit. */
.popup-cancel {
  height: var(--control-height); padding: 0 1.1rem;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--panel-bg); color: var(--ink);
  font: inherit; font-weight: 600; cursor: pointer;
  transition: background-color 160ms ease;
}
.popup-cancel:hover { background: var(--page-bg); }
.popup-cancel:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* Inline status / validation line (e.g. "Uploading…" or an error). */
.popup-msg { margin: 0 0 0.9rem; font-size: 0.9rem; line-height: 1.4; }
.popup-msg.is-error { color: var(--fail); }

/* Upload / task progress bar. Hidden until in use (toggle the [hidden] attr). */
.popup-progress { height: 0.5rem; margin: 0 0 0.9rem; border-radius: 999px; background: var(--line); overflow: hidden; }
.popup-progress-bar { height: 100%; width: 0; background: var(--accent); transition: width 120ms linear; }

@media (max-width: 520px) {
  .popup-overlay { padding: 1.5rem 0.75rem; }
}
