/* env.css — env-manager's own additions on top of styles.css, which is
   Deployment Manager's stylesheet copied verbatim (one visual family).
   Keep app-specific rules HERE so styles.css can be re-copied from DM. */

.svc-help {
    display: inline-grid; place-items: center;
    width: 16px; height: 16px; margin-left: 6px;
    border: 1px solid var(--border-color); border-radius: 50%;
    color: var(--text-secondary); font-size: 0.75rem; cursor: help;
}

/* Sign-in panel drawing (sp-*). Replaces DM's .si-* topology inside the same
   .signin-map, so its breakpoints still apply. Colours are the panel's own
   --si-* tokens (light and dark). The rules below are the FINISHED frame;
   js/login-panel.js animates into it, so without JS or with reduced motion
   the panel simply stands complete. */
.sp { display: grid; gap: 16px; }
.sp-name { display: flex; font: 600 1.75rem/1.15 var(--font-mono); letter-spacing: -0.02em; color: var(--si-ink); }
.sp-prefix { color: var(--si-ink-dim); }
.sp-slot { position: relative; flex: 1; min-width: 0; height: 1.15em; }
.sp-slot span { position: absolute; left: 0; top: 0; white-space: nowrap; opacity: 0; }
.sp-slot span:last-child { opacity: 1; }
.sp-ns { position: relative; padding: 30px 18px 18px; }
.sp-ns > svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
/* Geometry in CSS, not measured by JS: the outline exists without the script,
   follows the box on resize, and survives a first show while the figure is
   display:none. pathLength=1 lets the draw animate stroke-dashoffset 1 -> 0. */
.sp-ns rect { x: 0.75px; y: 0.75px; width: calc(100% - 1.5px); height: calc(100% - 1.5px);
              fill: none; stroke: var(--si-line); stroke-width: 1.5; stroke-dasharray: 1; stroke-dashoffset: 0; }
.sp-label { position: absolute; top: 10px; left: 18px; font: 400 0.75rem/1 var(--font-mono); color: var(--si-ink-dim); }
.sp-pods { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.sp-pod { display: flex; align-items: center; gap: 10px; min-width: 0; padding: 12px 14px;
          background: var(--si-svc-fill); border: 1px solid var(--si-line); border-radius: var(--radius); }
.sp-pod svg { flex: none; width: 16px; height: 16px; overflow: visible; }
/* A faint track so the turning arc reads against it. */
.sp-track { fill: none; stroke: var(--si-line); stroke-width: 2.5; opacity: 0.45; }
.sp-ring { fill: none; stroke: var(--si-ok); stroke-width: 2.5; stroke-linecap: round;
           stroke-dasharray: 1; stroke-dashoffset: 0; transform: rotate(-90deg); transform-origin: 8px 8px; }
.sp-pod > span { font: 400 0.85rem/1.2 var(--font-mono); color: var(--si-ink-soft);
                 white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sp-pod b { margin-left: 6px; font-weight: 500; color: var(--si-ink); }
.sp-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 18px; }
.sp-url { padding: 8px 12px; font: 400 0.85rem/1 var(--font-mono); color: var(--si-ink);
          background: var(--si-svc-fill); border: 1px solid var(--si-accent); border-radius: var(--radius); }
.sp-status { display: flex; gap: 16px; font: 500 0.85rem/1 var(--font-sans); color: var(--si-ink-soft); }
.sp-status span { display: inline-flex; align-items: center; gap: 6px; }
.sp-status span::before { content: ''; width: 8px; height: 8px; border-radius: 50%; background: var(--si-ok); }

/* ── Environments list (em-*) — approved in docs/env-manager/mockups ── */
.em-title { display: flex; align-items: baseline; margin: 0; font-size: 1.5rem; font-weight: 600; letter-spacing: -0.01em; }
.em-count { margin-left: 8px; font: 500 0.85rem/1 var(--font-sans); color: var(--text-secondary); font-variant-numeric: tabular-nums; }

.em-cap { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px 24px; padding: 14px 16px; margin-bottom: 16px;
    background: var(--surface-sunken); border: 1px solid var(--border-color); border-radius: var(--radius); }
.em-cap:empty { display: none; }
.em-cap-item { display: grid; grid-template-columns: 1fr auto; row-gap: 6px; align-items: center; }
.em-cap-label { font-size: 0.85rem; color: var(--text-secondary); }
.em-cap-val { display: inline-flex; align-items: center; gap: 4px; font-size: 0.85rem; color: var(--text-primary); font-variant-numeric: tabular-nums; }
.em-cap-val small { font-size: inherit; color: var(--text-muted); }
.em-cap-bar { grid-column: 1 / -1; display: flex; height: 4px; border-radius: 999px; background: var(--border-color); overflow: hidden; }
.em-cap-bar > i { display: block; height: 100%; background: var(--accent-primary); opacity: 0.45; }
.em-cap-bar > i.mine { background: var(--accent-text); opacity: 1; }
.em-cap-item.is-high .em-cap-bar > i { background: var(--warning); }
.em-cap-item.is-high .em-cap-bar > i.mine { background: var(--warning-text); }
.em-cap-item.is-high .em-cap-val, .em-cap-item.is-high .em-cap-val small { color: var(--warning-text); font-weight: 600; }
.em-cap-mine { grid-column: 1 / -1; font-size: 0.8rem; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.em-cap-mine b { color: var(--text-primary); font-weight: 600; }
.em-cap-legend { grid-column: 1 / -1; display: flex; gap: 16px; font-size: 0.8rem; color: var(--text-muted); }
.em-cap-legend span { display: inline-flex; align-items: center; gap: 6px; }
.em-cap-legend span::before { content: ''; width: 14px; height: 4px; border-radius: 999px; background: var(--accent-text); }
.em-cap-legend span.team::before { background: var(--accent-primary); opacity: 0.45; }
.em-cap-legend span.em-cap-basis { margin-left: auto; }
.em-cap-legend span.em-cap-basis::before { content: none; }
.em-cap-note { grid-column: 1 / -1; display: flex; align-items: center; gap: 8px; margin: 0; font-size: 0.9rem; color: var(--warning-text); }

.em-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-bottom: 12px; }
.em-search { position: relative; flex: 0 1 320px; }
.em-search svg { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--text-muted); pointer-events: none; }
.em-toolbar input[type="search"] { box-sizing: border-box; width: 100%; height: 40.6px; padding: 10px 14px 10px 36px;
    font: 0.95rem/1.4 var(--font-sans); color: var(--text-primary); background: var(--bg-input, var(--page-chrome));
    border: 1px solid var(--border-color); border-radius: var(--radius); }
.em-toolbar input[type="search"]:hover { border-color: var(--border-strong); }
.em-toolbar input[type="search"]:focus-visible { outline: none; border-color: var(--accent-text); box-shadow: 0 0 0 3px var(--accent-ring); }
.em-toolbar .ui-select { min-width: 170px; }
.em-live-text.is-stale { color: var(--warning-text); font-weight: 600; }

/* .em-table-wrap keeps .table-container's overflow: auto — a narrow screen scrolls the table, not the
   page. The row menu is position: fixed so the scroller cannot clip it (openRowMenuFor). */
.em-name { font: 500 0.9rem/1.35 var(--font-mono); color: var(--accent-text); text-decoration: none; }
.em-name:hover { text-decoration: underline; text-underline-offset: 3px; }
.em-name:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; border-radius: 4px; }
.em-meta { display: block; margin-top: 2px; font-size: 0.8rem; color: var(--text-muted); }
.em-meta code { padding: 0; background: none; font: inherit; font-family: var(--font-mono); color: var(--text-secondary); }
.em-res { font: 0.85rem/1.4 var(--font-mono); white-space: nowrap; font-variant-numeric: tabular-nums; color: var(--text-primary); }
.em-none { color: var(--text-muted); }
.data-table th.em-num, .data-table td.em-num { text-align: center; }
.em-owner { white-space: nowrap; color: var(--text-secondary); }
.em-owner.is-me { color: var(--text-primary); font-weight: 600; }
.em-exp { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; font-variant-numeric: tabular-nums; color: var(--text-primary); }
.em-exp.is-soon { color: var(--warning-text); font-weight: 600; }
.em-exp.is-expired { color: var(--danger-text); font-weight: 600; }
.em-exp.is-never { color: var(--text-muted); }

.em-actions { position: relative; display: flex; justify-content: flex-end; gap: 6px; }
.em-icon-btn { display: inline-grid; place-items: center; width: 32px; height: 32px; padding: 0; cursor: pointer;
    color: var(--text-secondary); background: transparent; border: 1px solid var(--border-control); border-radius: var(--radius);
    transition: background-color 0.15s var(--ease-out), color 0.15s var(--ease-out); }
.em-icon-btn:hover { background: var(--surface-sunken); color: var(--text-primary); }
.em-icon-btn:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; }
.em-icon-btn[aria-expanded="true"] { background: var(--accent-tint); color: var(--accent-text); border-color: var(--accent-text); }

.em-menu { position: absolute; top: 38px; right: 0; z-index: 20; min-width: 200px; padding: 6px;
    background: var(--bg-primary); border: 1px solid var(--border-color); border-radius: var(--radius);
    box-shadow: 0 10px 30px hsl(208 34% 22% / 0.16); }
[data-theme="dark"] .em-menu { box-shadow: 0 10px 30px hsl(0 0% 0% / 0.5); }
.em-menu button { display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px 10px; cursor: pointer; text-align: left;
    font: 0.9rem var(--font-sans); color: var(--text-primary); background: none; border: 0; border-radius: var(--radius-sm); }
.em-menu button svg { flex: none; color: var(--text-muted); }
.em-menu-txt { display: flex; flex-direction: column; gap: 2px; }
.em-menu-txt small { max-width: 220px; font-size: .75rem; line-height: 1.4; color: var(--text-muted); }
.em-menu button:hover .em-menu-txt small, .em-menu button:focus-visible .em-menu-txt small { color: var(--text-secondary); }
.em-menu button:hover, .em-menu button:focus-visible { outline: none; background: var(--accent-tint); color: var(--accent-text); }
.em-menu button:hover svg, .em-menu button:focus-visible svg { color: var(--accent-text); }
.em-menu .is-danger, .em-menu .is-danger svg { color: var(--danger-text); }
.em-menu .is-danger:hover, .em-menu .is-danger:focus-visible { background: var(--danger-bg); color: var(--danger-text); }
.em-menu .is-danger:hover svg, .em-menu .is-danger:focus-visible svg { color: var(--danger-text); }
.em-menu hr { margin: 6px 4px; border: 0; border-top: 1px solid var(--border-color); }

.em-group td { padding-top: 18px; padding-bottom: 6px; font-size: 0.8rem; font-weight: 600; color: var(--text-secondary); }
.data-table tbody tr.em-group:hover > * { background: transparent; }

.em-empty { padding: 56px 24px; text-align: center; border: 1px dashed var(--border-strong); border-radius: var(--radius-lg); }
.em-empty h3 { margin: 0 0 6px; font-size: 1.15rem; font-weight: 600; color: var(--text-primary); }
.em-empty p { max-width: 52ch; margin: 0 auto 20px; color: var(--text-secondary); }
.em-empty-actions { display: inline-flex; gap: 12px; }

@media (max-width: 1100px) { .em-cap { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 768px) {
    .em-cap { grid-template-columns: 1fr; }
    .em-live { margin-left: 0; }
    .em-search { flex-basis: 100%; }
}
@media (prefers-reduced-motion: reduce) { .em-icon-btn { transition: none; } }
.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.em-autorefresh { font-size: 0.85rem; color: var(--text-secondary); cursor: pointer; }
/* Freshness sits at the right end of the toolbar, split from the filters
   by a rule: when the list was loaded + refresh it now (one pair), then
   whether it reloads by itself. */
.em-live { margin-left: auto; display: flex; flex-wrap: wrap; align-items: center; gap: 12px; font-size: 0.85rem; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.em-live-sep { width: 1px; height: 16px; background: var(--border-color); }
/* DM's .switch is laid out for a form column (align-self: flex-start, a
   label bottom margin); here it sits on the line it describes. */
.em-live .switch { align-self: center; margin: 0; line-height: 1; }
.em-live .switch span { line-height: 20px; }
.em-fresh { display: inline-flex; align-items: center; gap: 4px; }
.em-icon-btn.em-icon-btn-sm { width: 28px; height: 28px; border-color: transparent; }
.em-icon-btn.em-icon-btn-sm:hover { border-color: var(--border-control); }

/* ── env details modal (emm-*) ─────────────────────────────────────────
   Copied from docs/env-manager/mockups/env-modal.html's "proposed: emm-*"
   block (the LOOK source of truth). Two deliberate differences, both to
   avoid touching anything outside the modal:
   - `.em-icon-btn-sm` is scoped under `.emm` (the list already ships a
     28px variant at the end of this file; the modal wants 30px).
   - the mockup's frame rules (.mock-bar/.stage/.grid2/.vhead) are not code.
   Reused from DM styles.css as-is: .modal .modal-xl .modal-header
   .modal-body .modal-footer .modal-close .tabs .tab .btn* .data-table
   .badge* .seg .switch .logs-container mark.log-highlight; from the list
   above: .em-icon-btn .em-menu .em-group .em-exp .em-empty .em-actions. */

/* above the tab row, so the Extend / ⋯ menus open over it */
/* OWNER, 2026-10-06: the modal must never change height — Overview, an opened
   "From <parent>", Pods and the loading/empty/error bodies were three different
   heights. One fixed height; header, tabs and footer are fixed rows and the
   ACTIVE panel is the only scroller.
   OWNER follow-up, same day: 880px left a large empty area under a typical
   Overview, so the fixed height is 640px — longer content scrolls in the panel. */
.modal.emm { height: min(640px, calc(100vh - 48px)); max-height: none; display: flex; flex-direction: column; }
.emm .modal-header, .emm .emm-tabs, .emm .modal-footer { flex: none; }
.emm .modal-header { position: relative; z-index: 2; align-items: flex-start; padding: 16px 20px 12px; border-bottom: 0; }
.emm-head { flex: 1; min-width: 0; display: grid; gap: 6px; }
.emm-title { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.emm-title h2 { margin: 0; font: 600 1.2rem/1.3 var(--font-mono); color: var(--text-primary); letter-spacing: -.01em; }
/* Every item hangs its '·' in the 20px column gap to its left. The row is clipped on its left edge
   only, so the dot of whichever item starts a line (first, or after a wrap) falls outside and is cut. */
.emm-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 20px;
  clip-path: inset(-100vh -100vw -100vh 0); font-size: .85rem; color: var(--text-secondary); }
.emm-meta > * { position: relative; white-space: nowrap; }
.emm-meta > *::before { content: '·'; position: absolute; left: -20px; width: 20px; text-align: center; color: var(--text-muted); }
.emm-meta code { font: .85rem var(--font-mono); color: var(--text-primary); background: none; padding: 0; }
.emm-meta .you { color: var(--text-muted); }
.emm-exp-wrap { position: relative; }
.emm-link-btn { padding: 0; margin-left: 8px; border: 0; background: none; cursor: pointer; font: 600 .85rem var(--font-sans);
  color: var(--accent-text); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: color-mix(in srgb, currentColor 40%, transparent); }
.emm-link-btn:hover { text-decoration-color: currentColor; }
.emm-link-btn:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; border-radius: var(--radius-sm); }
.emm-link-btn[disabled] { color: var(--text-muted); cursor: default; text-decoration: none; }
.emm-actions { position: relative; display: flex; align-items: center; gap: 8px; flex: none; }
.emm-actions .btn { display: inline-flex; align-items: center; gap: 6px; }
/* OWNER, 2026-10-06: Sync/Stop read as a third style next to the ⋯ icon button.
   They take the same outline, height and hover as `.em-icon-btn`; only Resume
   on a stopped env stays the one filled primary. */
.emm-actions .btn-secondary.btn-small { height: 32px; padding: 0 10px; color: var(--text-secondary);
  background: transparent; border: 1px solid var(--border-control); }
.emm-actions .btn-secondary.btn-small:hover { background: var(--surface-sunken); color: var(--text-primary); }
.emm-actions .btn-secondary.btn-small svg { color: var(--text-muted); }
.emm-actions .btn-secondary.btn-small:hover svg { color: var(--text-primary); }
.emm-actions .btn-primary.btn-small { height: 32px; }
.emm-actions .emm-sep { width: 1px; height: 16px; margin: 0 2px; background: var(--border-color); }
.emm-actions .modal-close { margin-left: 0; }

/* DM's page-level .tabs is sticky at z-index 20; inside the modal it is a flex item,
   where z-index applies even unpositioned and would cover the header menus. */
.emm-tabs { position: static; z-index: auto; margin: 0 20px; box-shadow: none; }
.emm-tabs .tab { padding: 9px 18px; font-size: .9rem; }
.emm-tabs .tab .n { margin-left: 6px; font-weight: 500; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.emm-tabs .tab.active .n { color: inherit; }
.emm .modal-body { flex: 1 1 auto; min-height: 0; padding: 16px 20px 20px; overflow: auto; }
.emm [role="tabpanel"][hidden], .emm .modal-footer.emm-changes[hidden] { display: none; }

.emm-cols { display: grid; grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr); gap: 28px; align-items: start; }
.emm-sec { display: flex; align-items: baseline; gap: 8px; margin: 0 0 8px; font-size: .8rem; font-weight: 600; color: var(--text-secondary); }
.emm-sec .n { font-weight: 500; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.emm-sec .from { font-weight: 500; color: var(--text-muted); }
.emm-sec code, .emm-from code, .emm-pod-meta code, .emm-dl code, .em-group code, .emm-changes code, .emm-confirm-in code {
  font: inherit; font-family: var(--font-mono); background: none; padding: 0; color: var(--text-secondary); }
.emm-block + .emm-block { margin-top: 22px; }
.emm-muted { margin: 0; font-size: .875rem; color: var(--text-muted); }

.emm-rows { border: 1px solid var(--border-color); border-radius: var(--radius); overflow: hidden; background: var(--bg-secondary); }
.emm-row { display: grid; align-items: center; gap: 12px; min-height: 40px; padding: 4px 6px 4px 12px; }
.emm-row + .emm-row { border-top: 1px solid var(--border-color); }
.emm-row:hover { background: var(--surface-sunken); }
.emm-links .emm-row { grid-template-columns: 170px minmax(0, 1fr) auto; }
/* the parent block's names carry a "parent" word: give them room so they do not wrap */
.emm-links.is-parent .emm-row { grid-template-columns: 236px minmax(0, 1fr) auto; }
/* ...and the env's own block above it takes the same name column, so the URL column runs straight down */
.emm-cols > div:has(.emm-links.is-parent) .emm-links .emm-row { grid-template-columns: 236px minmax(0, 1fr) auto; }
.emm-links a.svc { display: inline-flex; align-items: center; gap: 6px; font-weight: 500; color: var(--accent-text); text-decoration: none; min-width: 0; }
.emm-links a.svc:hover { text-decoration: underline; text-underline-offset: 3px; }
.emm-links a.svc:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; border-radius: var(--radius-sm); }
.emm-links a.svc svg { flex: none; color: var(--text-muted); }
.emm-links .emm-name { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
/* "parent" / "shared": a word in a hairline box — DM bans side stripes, and colour alone is not a label */
.emm-tag { flex: none; display: inline-block; padding: 0 6px; border: 1px solid var(--border-control);
  border-radius: 999px; font: 500 .72rem/1.5 var(--font-sans, inherit); color: var(--text-secondary);
  text-transform: none; letter-spacing: 0; white-space: nowrap; }
.emm-url { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: .8rem var(--font-mono); color: var(--text-secondary); }
.emm-url b { font-weight: 500; color: var(--text-primary); }
/* the whole value must be reachable by mouse, keyboard and touch */
.emm-url:hover, .emm-url:focus-visible { overflow: visible; white-space: normal; overflow-wrap: anywhere; }
.emm-url:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; border-radius: var(--radius-sm); }

/* two copies per URL: Base (connect to) and Swagger / UI (click through) */
.emm-copies { display: grid; grid-template-columns: 60px 80px; gap: 4px; } /* fixed slots: Base lines up in every row */
.emm .em-icon-btn.emm-copy-txt { width: auto; height: 28px; padding: 0 8px; gap: 4px; display: inline-flex;
  justify-content: flex-start; font-size: .75rem; font-weight: 500; color: var(--text-secondary); border-color: transparent; }
.emm .em-icon-btn.emm-copy-txt:hover { border-color: var(--border-control); color: var(--text-primary); }

/* a group label inside the URL list — the same label as .ui-select-group */
.emm-grp { padding: 8px 12px 0; font-size: .72rem; line-height: 1.4; font-weight: 600; text-transform: uppercase;
  letter-spacing: .04em; color: var(--text-muted); }
.emm-grp:not(:first-child) { border-top: 1px solid var(--border-color); }

.emm-ports .emm-row { grid-template-columns: minmax(0, 1fr) auto 72px auto; }
/* Database block: [pick | JDBC User Password], then what they copy */
.emm-db .emm-row { grid-template-columns: minmax(0, 1fr) auto; }
/* the picker's popup hangs below the box: the box must not clip it */
.emm-rows.emm-db { overflow: visible; }
.emm-db .emm-row:hover { background: none; }
.emm-db .ui-select-popup { z-index: 5; }
.emm-db .emm-copies { display: inline-flex; gap: 4px; }
.emm-db .ui-select { min-width: 0; max-width: 200px; }
.emm-db-cred { font: .8rem var(--font-mono); color: var(--text-secondary); white-space: nowrap; }
.emm-db .emm-muted-val { font-family: var(--font-sans, inherit); color: var(--text-muted); }
.emm-ports .name { color: var(--text-primary); }
.emm-ports .ext { font: 500 .9rem var(--font-mono); color: var(--text-primary); font-variant-numeric: tabular-nums; }
.emm-ports .int { font: .8rem var(--font-mono); color: var(--text-muted); }
.emm-ports .int:not(:empty)::before { content: '→ '; }

.emm-dl { display: grid; grid-template-columns: 110px minmax(0, 1fr); gap: 8px 12px; margin: 0; font-size: .875rem; }
.emm-dl dt { color: var(--text-secondary); }
.emm-dl dd { margin: 0; color: var(--text-primary); min-width: 0; overflow-wrap: anywhere; }
.emm-dl dd code { color: var(--text-primary); }
.emm-dl .hint { color: var(--text-muted); }

.emm-copied, .emm-copied:hover { color: var(--success-text) !important; border-color: var(--success-text) !important; }
.emm .em-icon-btn.em-icon-btn-sm { width: 30px; height: 30px; border-color: transparent; }
.emm .em-icon-btn.em-icon-btn-sm:hover { border-color: var(--border-control); }

.emm-note { display: flex; align-items: flex-start; gap: 8px; margin: 0 0 12px; padding: 10px 12px; font-size: .875rem;
  border-radius: var(--radius); border: 1px solid var(--border-color); background: var(--surface-sunken); color: var(--text-secondary); }
.emm-note svg { flex: none; margin-top: 2px; }
.emm-note.warn { color: var(--warning-text); background: var(--warning-bg); border-color: transparent; }
.emm-head .emm-note { margin: 6px 0 0; }

/* pods */
.emm-pod { font: 500 .85rem/1.35 var(--font-mono); color: var(--text-primary); }
.emm-pod-meta { display: block; margin-top: 2px; font-size: .8rem; color: var(--text-muted); }
.emm-pods-sum { margin: 0 0 12px; font-variant-numeric: tabular-nums; }
.emm-restarts.is-warn { display: inline-flex; align-items: center; gap: 4px; color: var(--warning-text); font-weight: 600; }
.emm .data-table td.num, .emm .data-table th.num { text-align: center; font-variant-numeric: tabular-nums; }
.emm-confirm td { background: var(--warning-bg) !important; }
.emm-confirm.is-danger td { background: var(--danger-bg) !important; }
.emm-confirm-in { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.emm-confirm-in p { margin: 0; flex: 1; min-width: 260px; color: var(--text-primary); font-size: .875rem; }
.emm-confirm-in code { color: var(--text-primary); }
.emm-dim .emm-pod { color: var(--text-secondary); }
/* OWNER, 2026-10-06: a row without the ⋯ button used to push Logs right.
   Fixed column, left-aligned, and an empty slot keeps the second position. */
.emm .data-table td.emm-pod-actions, .emm .data-table th.emm-pod-actions { width: 118px; }
.emm-pod-actions .em-actions { justify-content: flex-start; }
.emm-pod-actions .em-slot { display: inline-block; width: 32px; height: 32px; }

/* services */
.emm-svc { font-weight: 500; color: var(--text-primary); }
.emm-img { font: .85rem var(--font-mono); color: var(--text-primary); }
.emm-sha { display: block; font: .75rem var(--font-mono); color: var(--text-muted); }
.emm-from { font-size: .85rem; color: var(--text-muted); }
/* Why a Build button is disabled: one line under it, the Build column is width:1%. */
.svc-build-why { display: block; margin-top: 4px; white-space: nowrap; }
.emm .data-table .ui-select { min-width: 240px; }
.emm .data-table td { vertical-align: middle; }
.emm-changed .emm-svc::after { content: 'changed'; margin-left: 8px; padding: 1px 6px; font: 600 .7rem var(--font-sans);
  color: var(--accent-text); background: var(--accent-tint); border-radius: 999px; }
.emm .modal-footer.emm-changes { display: flex; align-items: center; gap: 12px; justify-content: flex-end; padding: 12px 20px; border-top: 1px solid var(--border-color); }
.emm-changes p { margin: 0 auto 0 0; font-size: .875rem; color: var(--text-secondary); min-width: 0; }
.emm-changes p b { color: var(--text-primary); }
.emm-changes-txt { margin-right: auto; min-width: 0; }
.emm-changes-txt p { margin: 0; }
.emm-changes .emm-apply-how { display: block; margin-top: 2px; font-size: .8rem; color: var(--text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.emm-changes code { color: var(--text-primary); }
.emm-changes p.is-error { display: flex; align-items: flex-start; gap: 8px; color: var(--danger-text); }
.emm-changes p.is-error svg { flex: none; margin-top: 2px; }
.emm-cb { width: 16px; height: 16px; accent-color: var(--accent-primary); cursor: pointer; }

/* logs */
.emm-logbar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 10px; }
.emm-logbar .ui-select { min-width: 150px; }
.emm-logbar .ui-select:has(select.wide) { min-width: 280px; }
.emm-logbar label.chk { display: inline-flex; align-items: center; gap: 6px; font-size: .85rem; color: var(--text-secondary); cursor: pointer; }
.emm-logbar .emm-logright { margin-left: auto; display: flex; flex-wrap: wrap; align-items: center; gap: 10px; font-size: .85rem; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.emm-logbar .switch { align-self: center; margin: 0; line-height: 1; }
.emm-logbar .switch span { line-height: 20px; }
.emm-logbar .emm-logfield { display: inline-flex; align-items: center; gap: 6px; font-size: .85rem; color: var(--text-secondary); }
.emm-logbar .emm-logfield .ui-select { min-width: 0; }
.emm-logfind { display: inline-flex; align-items: center; gap: 4px; flex: 0 1 300px; min-width: 200px; }
.emm-logsearch { position: relative; flex: 1 1 auto; min-width: 0; }
.emm-logsearch svg { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: var(--text-muted); pointer-events: none; }
.emm-logsearch input { box-sizing: border-box; width: 100%; height: 36px; padding: 8px 56px 8px 32px; font: .9rem var(--font-sans);
  color: var(--text-primary); background: var(--bg-input, var(--page-chrome)); border: 1px solid var(--border-color); border-radius: var(--radius); }
.emm-logsearch input:focus-visible { outline: none; border-color: var(--accent-text); box-shadow: 0 0 0 3px var(--accent-ring); }
.emm-logsearch .cnt { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); font-size: .8rem; color: var(--text-muted); font-variant-numeric: tabular-nums; }
/* ID specificity, and scoped to :not([hidden]) so the tabpanel rule still hides it. */
.emm #panel-logs:not([hidden]) { display: flex; flex-direction: column; }
.emm #panel-logs .emm-logbar { flex: none; }
.emm .logs-container { flex: 1 1 auto; min-height: 120px; max-height: none; height: auto; margin: 0; font-size: .8rem; line-height: 1.55; }
/* One row per line: a muted time gutter, then the text with a hanging indent.
   Colours are on the console's fixed dark surface (#16181d) in both themes:
   text 13.2:1, gutter 4.8:1, error 7.0:1, warn 9.1:1, debug 5.8:1. */
.emm-logpane { --log-ts: #7d8590; --log-error: #ff7b72; --log-warn: #e3b341; --log-debug: #8b949e;
  --log-error-tint: rgba(255, 123, 114, .08); --log-warn-tint: rgba(227, 179, 65, .07);
  padding: 8px 0; white-space: normal; word-break: normal; }
.emm-logpane .ll, .emm-logpane summary { display: grid; grid-template-columns: 9ch minmax(0, 1fr); gap: 12px;
  padding: 1px 16px 1px 13px; border-left: 3px solid transparent; }
.emm-logpane .ts { color: var(--log-ts); font-variant-numeric: tabular-nums; user-select: none; }
.emm-logpane.own-stamps .ll, .emm-logpane.own-stamps summary { grid-template-columns: minmax(0, 1fr); }
.emm-logpane.own-stamps .ts { display: none; }
.emm-logpane .at { color: var(--log-ts); }
.emm-logpane .tx { white-space: pre-wrap; overflow-wrap: anywhere; padding-left: 2ch; text-indent: -2ch; }
.emm-logpane .ll-error { border-left-color: var(--log-error); background: var(--log-error-tint); }
.emm-logpane .ll-warn { border-left-color: var(--log-warn); background: var(--log-warn-tint); }
.emm-logpane .ll-error > .tx { color: #ffd7d3; }
.emm-logpane .ll-debug > .tx, .emm-logpane .ll-empty > .tx { color: var(--log-debug); }
/* a folded stack trace: one quiet line under its exception */
.emm-logpane details.ll-frames > summary { cursor: pointer; list-style: none; color: var(--log-debug); }
.emm-logpane details.ll-frames > summary::-webkit-details-marker { display: none; }
.emm-logpane details.ll-frames > summary .tx::before { content: '▸ '; }
.emm-logpane details.ll-frames[open] > summary .tx::before { content: '▾ '; }
.emm-logpane details.ll-frames > summary:hover .tx { color: #d8dee9; text-decoration: underline; text-underline-offset: 3px; }
.emm-logpane details.ll-frames > summary:focus-visible { outline: 2px solid var(--log-warn); outline-offset: -2px; }
.emm-logpane details.ll-frames .ll { color: var(--log-debug); }
.emm-logpane details.ll-error .ll, .emm-logpane details.ll-error > summary { border-left-color: var(--log-error); background: var(--log-error-tint); }
.emm-logpane details.ll-warn .ll, .emm-logpane details.ll-warn > summary { border-left-color: var(--log-warn); background: var(--log-warn-tint); }

.emm-skel { height: 40px; border-radius: var(--radius); background: var(--surface-sunken); margin-bottom: 8px; }
.emm-skel:last-child { width: 70%; }
@media (prefers-reduced-motion: no-preference) {
  .emm-skel { animation: emm-pulse 1.4s var(--ease-in-out) infinite; }
  @keyframes emm-pulse { 50% { opacity: .55; } }
}
@media (max-width: 1000px) { .emm-cols { grid-template-columns: 1fr; } }

/* OWNER, 2026-10-06: a row must never move while a change is pending — the
   service the user just ticked used to jump into another group and "vanish".
   Groups come from the SAVED payload; the pending intent is a pill in place. */
.emm-changed .emm-svc::after, .emm-pill-add .emm-svc::after, .emm-pill-remove .emm-svc::after, .emm-pill-back .emm-svc::after {
  margin-left: 8px; padding: 1px 6px; font: 600 .7rem var(--font-sans); border-radius: 999px; }
.emm-pill-add .emm-svc::after { content: 'will be added'; color: var(--accent-text); background: var(--accent-tint); }
.emm-pill-remove .emm-svc::after { content: 'will be removed'; color: var(--danger-text); background: var(--danger-bg); }
/* Back on the parent's copy is not a removal (services-source-spec.md). */
.emm-pill-back .emm-svc::after { content: 'back to ' attr(data-parent); color: var(--accent-text); background: var(--accent-tint); }
/* A row on its way out dims what it runs now; its Source stays live so the pick can be undone. */
.emm-pill-remove .emm-img, .emm-pill-remove .emm-sha, .emm-pill-back .emm-img, .emm-pill-back .emm-sha { opacity: .5; }

/* One Source per row (services-source-spec.md): a row on a source of its own is
   tinted; the parent's version is read-only data; a blocked first option stays
   visible (it explains the row) but cannot be picked. */
.emm-svc-table tr.svc-own > td { background: var(--accent-tint); }
.svc-why { margin-left: 8px; padding: 1px 8px; border-radius: 999px; font-size: .75rem;
  color: var(--text-secondary); background: var(--surface-sunken); white-space: nowrap; }
.svc-ver { font-size: .8rem; color: var(--text-secondary); }
.svc-muted { font-size: .85rem; color: var(--text-muted); }
.svc-run { display: inline-flex; align-items: center; gap: 8px; font-size: .85rem; font-weight: 400; }
.emm-svc-table .seg input:disabled + label { opacity: .45; cursor: not-allowed; }
.emm-changes p { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The header's inline confirms (delete, stop, resume, set expiry) are not
   table rows, so they carry their own surface instead of `.emm-confirm td`. */
.emm-confirm-danger, .emm-confirm-warn { padding: 12px; border-radius: var(--radius); }
.emm-confirm-danger { background: var(--danger-bg); }
.emm-confirm-warn { background: var(--warning-bg); }

/* OWNER, 2026-10-06: the services table's value columns are centred — header
   AND cell together, so each header stays over its own content. The checkbox
   and Service columns stay left: names of different lengths are read from a
   left edge. Group rows and the muted colspan note stay left too. */
.emm-svc-table th:nth-child(n+2), .emm-svc-table td:nth-child(n+2) { text-align: center; }
.emm-svc-table td:nth-child(n+2) .seg,
.emm-svc-table td:nth-child(n+2) .ui-select { margin-left: auto; margin-right: auto; }
.emm-svc-table tr.em-group td, .emm-svc-table td.emm-span { text-align: left; }
/* The static read-only variant has two columns, so Running now is the second. */
.emm-svc-static th:nth-child(2), .emm-svc-static td:nth-child(2) { text-align: center; }

/* List loading skeleton (owner, 2026-10-06): the capacity band and the table
   keep their real size while the first load runs, so nothing moves when the
   data lands. Sizes match the filled band (113px) and a filled row (62px). */
.em-skel { display: block; height: 12px; border-radius: 999px; background: var(--surface-sunken); }
.em-cap .em-skel { background: var(--border-color); }
.em-skel-val { width: 72px; height: 14px; justify-self: end; }
.em-skel-mine { width: 64px; margin: 3px 0; }
.em-skel-legend { width: 240px; margin: 3px 0; }
.em-skel-name { width: 140px; height: 14px; margin: 3px 0 8px; }
.em-skel-meta { width: 200px; height: 11px; margin-bottom: 3px; }
.em-skel-cell { width: 56px; }
.em-num .em-skel-cell { margin: 0 auto; }
.data-table tbody tr.em-skel-row:hover > * { background: transparent; }
@media (prefers-reduced-motion: no-preference) {
    .em-skel { animation: em-skel-pulse 1.4s var(--ease-in-out) infinite; }
    @keyframes em-skel-pulse { 50% { opacity: .55; } }
}

/* An icon button that also says what it does (owner: the bare terminal glyph
   did not read as "Logs"). Same height, border and hover as .em-icon-btn. */
.em-icon-btn.em-text-btn { width: auto; gap: 6px; padding: 0 10px; font: 500 0.85rem var(--font-sans); display: inline-flex; align-items: center; }

/* the whole row opens the env modal (environments.js) */
#environmentsTableBody tr[data-env] { cursor: pointer; }

/* A checkbox field beside a select: a label row like its neighbours, then a row
   as tall as the control (40.6px, the ui-select trigger) so the box sits on its line. */
.em-field-label { font-size: 0.875rem; font-weight: 500; color: var(--text-secondary); }
.em-check-row { display: flex; min-height: 40.6px; }

/* ---------- New environment (docs/env-manager/create-form-spec.md) ----------
   The form mounts the modal's services table (mode 'create'). Spacing follows
   the card's own steps: 8 / 12 / 16 / 24 / 28px. */
.ec-lead { margin: -16px 0 24px; max-width: 72ch; font-size: .9rem; color: var(--text-secondary); }
.form-section > .ec-lead { margin-top: -8px; margin-bottom: 16px; }
.ec-lead code, .ec-sum code, .ec-fixed code { font-size: .8rem; }
.ec-fixed { display: flex; align-items: center; min-height: 40.6px; margin: 0; font-size: .9rem; color: var(--text-primary); }
/* `.form-group` and `.ec-fixed` set display, which beats the [hidden] the form toggles. */
#create [hidden] { display: none; }
.ec-svc { margin-bottom: 0; border-bottom: 0; }
.ec-svc .ui-select { min-width: 220px; }
#createServicesError { margin-top: 8px; }
/* The build cell's run link (modal and Create): the product's link colour, not the UA blue. */
.emm-svc-table [data-svc-build] a { color: var(--accent-text); }

/* A form is read down a left edge: the modal centres its value columns, Create does not. */
.emm-svc-table.emm-svc-create th:nth-child(n+2), .emm-svc-table.emm-svc-create td:nth-child(n+2) { text-align: left; }
.emm-svc-table.emm-svc-create td:nth-child(n+2) .seg,
.emm-svc-table.emm-svc-create td:nth-child(n+2) .ui-select { margin-left: 0; margin-right: 0; }
.ec-own { margin: 8px 0 0; font-size: .85rem; color: var(--text-secondary); }
.ec-own code { font-size: .8rem; }

/* Focus that lands on a field (a validation error, Tab) must not end up under the
   sticky tabs (52px + offset) or the sticky bar below (63px): WCAG 2.4.11. */
html:has(#create.active) { scroll-padding-top: 80px; scroll-padding-bottom: 80px; }

/* The one primary, pinned to the bottom of the viewport while the form is longer
   than it, with what it will create (TTL included) beside it. */
.ec-bar { position: sticky; bottom: 0; z-index: 5; display: flex; align-items: center; gap: 16px;
  margin: 24px -28px -28px; padding: 12px 28px; background: var(--bg-secondary);
  border-top: 1px solid var(--border-color); border-radius: 0 0 var(--radius-lg) var(--radius-lg); }
.ec-sum { flex: 1; min-width: 0; margin: 0; font-size: .9rem; color: var(--text-secondary); }
.ec-block { display: block; margin-top: 4px; font-size: .85rem; color: var(--danger-text); }

.ec-result #createResultBuilds:empty { display: none; }
.ec-result .ec-builds { margin-top: 8px; }
.ec-result-actions { display: flex; gap: 8px; margin-top: 24px; }

@media (max-width: 760px) { .ec-bar { flex-wrap: wrap; } }
/* styles.css drops the card's padding to 12px here; the bar keeps meeting its edges.
   The table scrolls sideways at this width; its group notes wrap instead of clipping. */
@media (max-width: 480px) {
  .ec-bar { margin: 16px -12px -12px; padding: 12px; }
  .ec-svc tr.em-group td { white-space: normal; }
  .ec-svc .ui-select { min-width: 160px; }
}
