/*
	EIC Project Dashboard

	Renders inside a Hamilton SiteManager page, within <div class="typography">.
	Everything is namespaced under .eic-app; nothing resets or restyles site chrome.

	Two things about the host page drive most of the rules below.

	1. FONTS. site.css sets `body { font-family: "miller-text", serif }`. Inherited
	   into a data grid that gives you a book serif with OLD-STYLE (lowercase)
	   figures, which is unreadable in columns of dates and day counts. Hamilton's
	   own sans is Mallory Compact (Book/Medium/Bold), already loaded on every page
	   by /assets/fonts/fonts.css, so the app uses that plus lining tabular figures.

	   Mallory Book/Medium/Bold are three separate FAMILIES, each registered at
	   weight 400 - so weight is changed by switching family, and font-weight stays
	   400 to stop the browser synthesizing fake bold on an already-bold face.

	2. SPECIFICITY. `.typography a` is (0,1,1) and underlines every link. A bare
	   `.eic-app a` is also (0,1,1) and would only win on source order, so link
	   rules here are (0,2,1) to win outright.

	Sizing is deliberately generous rather than dense: the page gets read on a
	laptop during a committee meeting, by people who are mostly not in EIS.
*/

.eic-app {
	/* Hamilton's sans, with a real fallback stack. */
	--eic-sans:      "Mallory Compact Book", "Segoe UI", system-ui, -apple-system, Arial, sans-serif;
	--eic-sans-med:  "Mallory Compact Medium", "Segoe UI", system-ui, -apple-system, Arial, sans-serif;
	--eic-sans-bold: "Mallory Compact Bold", "Segoe UI", system-ui, -apple-system, Arial, sans-serif;

	/* Hamilton palette, so the app reads as part of the site. */
	--eic-navy:    #0a2355;
	--eic-blue:    #002f86;
	--eic-ink:     #26292e;
	--eic-muted:   #5c6470;
	--eic-faint:   #a7aeb8;
	--eic-line:    #dfe3e8;
	--eic-line-soft: #edf0f3;
	--eic-bg-soft: #f5f7fa;

	/* Status: a saturated line color and a pale fill for each, so the same
	   status reads the same way whether it is a dot, a pill or a timeline bar. */
	--eic-on-track: #1f7a3d;
	--eic-at-risk:  #9a5b00;
	--eic-off-track:#b32020;
	--eic-on-hold:  #626b78;
	--eic-complete: #1d4ed8;

	--eic-on-track-bg: #e4f3e9;
	--eic-at-risk-bg:  #fdf0d9;
	--eic-off-track-bg:#fce7e7;
	--eic-on-hold-bg:  #ebedf1;
	--eic-complete-bg: #e4ecfb;

	/*
		EIC status (the committee's decision) - pills, timeline row bands, tiles.

		A color means ONE thing across both statuses. EIC status and project
		status share a color only where they share a meaning:
		  Completed (EIC) = Complete (project)  blue, the --eic-complete values
		  Hold      (EIC) = On hold  (project)  gray, the --eic-on-hold values
		Everything else is kept out of the project-status hues: Approved is
		violet, not blue (blue is "complete"); Under Review is pale violet with a
		dotted edge, not amber (amber is "at risk"); Denied is an outlined
		neutral, not red (red is "off track", and a decision is not an alarm).

		Before this, the two sets were drawn from unrelated palettes and every hue
		meant two things - most visibly, Completed was green in the list and blue
		on the timeline.
	*/
	--eic-x-approved:     #6d28d9;  --eic-x-approved-bg: #efe8fc;  --eic-x-approved-ink: #4c1d95;
	--eic-x-review:       #8b6fc9;  --eic-x-review-bg:   #f8f5fe;  --eic-x-review-ink:   #5b3a91;
	--eic-x-hold-ink:     #444b55;
	--eic-x-denied:       #a7aeb8;  --eic-x-denied-bg:   #fafafb;  --eic-x-denied-ink:   #5c6470;
	--eic-x-completed-ink:#1e3a8a;

	/* Lifecycle stage tints, deliberately paler than the status fills so a
	   category pill never competes with a status color. */
	--eic-stage-pipeline-bg: #fdf6e6;  --eic-stage-pipeline-ink: #7a5b12;
	--eic-stage-hold-bg:     #f2f0f4;  --eic-stage-hold-ink:     #574d63;
	--eic-stage-planned-bg:  #eaf1fc;  --eic-stage-planned-ink:  #1c4a8a;
	--eic-stage-active-bg:   #e2edfa;  --eic-stage-active-ink:   #002f86;
	--eic-stage-done-bg:     #e9f1ec;  --eic-stage-done-ink:     #1f5c33;
	--eic-stage-closed-bg:   #f0f1f3;  --eic-stage-closed-ink:   #5c6470;
	--eic-stage-other-bg:    #f2f3f5;  --eic-stage-other-ink:    #5c6470;

	font-family: var(--eic-sans);
	/* Lining, fixed-width figures. Without this the grid inherits old-style
	   numerals from miller-text and dates do not line up column to column. */
	font-variant-numeric: lining-nums tabular-nums;
	font-feature-settings: "lnum" 1, "tnum" 1;
	color: var(--eic-ink);
	font-size: 1rem;
	line-height: 1.5;
}

.eic-app *,
.eic-app *::before,
.eic-app *::after { box-sizing: border-box; }

/* Inherit the app's font into every control, overriding the serif body. */
.eic-app input,
.eic-app select,
.eic-app button,
.eic-app dl,
.eic-app ul,
.eic-app p { font-family: inherit; font-variant-numeric: inherit; }

/* Beat `.typography a` (0,1,1) outright rather than relying on source order. */
.eic-app a.eic-projlink,
.eic-app .eic-nodates-list a,
.eic-app a.eic-btn {
	text-decoration: none;
	color: var(--eic-blue);
}

.eic-app a.eic-projlink:hover,
.eic-app .eic-nodates-list a:hover { text-decoration: underline; }

/* ------------------------------------------------------------------ header */

/* The page title comes from the SiteManager template, so this header holds only
   the refresh line. No bottom rule - the stat tiles below provide the edge. */
.eic-head { margin: 0 0 .85rem; }

.eic-app .eic-title {
	margin: 0 0 .2rem;
	font-family: var(--eic-sans-med);
	font-weight: 400;
	color: var(--eic-navy);
}

.eic-app .eic-refreshed {
	margin: 0;
	font-size: .9rem;
	color: var(--eic-muted);
}

.eic-app .eic-refreshed strong { font-family: var(--eic-sans-bold); font-weight: 400; }

.eic-muted { color: var(--eic-muted); }

/* ----------------------------------------------------------------- banners */

.eic-app .eic-banner {
	margin: 0 0 1.25rem;
	padding: .8rem 1rem;
	border: 1px solid;
	border-left-width: 4px;
	border-radius: 3px;
	font-size: .92rem;
	line-height: 1.45;
}

.eic-app .eic-banner strong { font-family: var(--eic-sans-bold); font-weight: 400; }

.eic-app .eic-banner-warn {
	background: #fdf8ea;
	border-color: #ead9ae;
	border-left-color: var(--eic-at-risk);
	color: #4a3a12;
}

.eic-app .eic-banner-error {
	background: #fdeeee;
	border-color: #eec4c4;
	border-left-color: var(--eic-off-track);
	color: #5c1a1a;
}

/* ------------------------------------------------------- summary stat tiles */

.eic-app .eic-summary {
	display: flex;
	flex-wrap: wrap;
	gap: 0;
	margin: 0 0 1.5rem;
	padding: 0;
	list-style: none;
	border: 1px solid var(--eic-line);
	border-radius: 4px;
	background: #fff;
	overflow: hidden;
}

.eic-app .eic-summary li {
	flex: 1 1 8rem;
	margin: 0;
	padding: .8rem 1.1rem;
	border-left: 1px solid var(--eic-line-soft);
	font-size: .82rem;
	line-height: 1.3;
	color: var(--eic-muted);
	/* number over label reads far better than a run-on sentence of figures */
	display: flex;
	flex-direction: column;
	gap: .15rem;
}

.eic-app .eic-summary li:first-child { border-left: 0; }

/*
	Tile tint carries meaning: the first two are facts, the last three are gaps
	the committee may need to act on. A colored top edge rather than a filled
	tile, so five tiles in a row do not turn into a paintbox.
*/
.eic-app .eic-summary li { border-top: 3px solid transparent; }
.eic-app .eic-summary li.eic-stat-neutral  { border-top-color: var(--eic-navy); }
/* The two EIC-status tiles use the EIC-status colors, the same as the pills
   and row bands they count. */
.eic-app .eic-summary li.eic-stat-approved { border-top-color: var(--eic-x-approved); background: var(--eic-x-approved-bg); }
.eic-app .eic-summary li.eic-stat-review   { border-top: 3px dotted var(--eic-x-review); background: var(--eic-x-review-bg); }
/* Amber, not red. These are "someone should look at this", not failures - and
   red is already spoken for by off_track status, which should not have to
   compete with a headline tile. */
.eic-app .eic-summary li.eic-stat-warn     { border-top-color: var(--eic-at-risk); background: var(--eic-at-risk-bg); }

.eic-app .eic-summary li.eic-stat-approved .eic-num { color: var(--eic-x-approved-ink); }
.eic-app .eic-summary li.eic-stat-review   .eic-num { color: var(--eic-x-review-ink); }
.eic-app .eic-summary li.eic-stat-warn     .eic-num { color: #7d4a00; }

/* Completed: the shared "complete" blue, on white - an archive figure. */
.eic-app .eic-summary li.eic-stat-done {
	border-top-color: var(--eic-complete);
	background: #fff;
}
.eic-app .eic-summary li.eic-stat-done .eic-num { color: var(--eic-x-completed-ink); }

/* A gap of zero is good news, so it should not be alarming. */
.eic-app .eic-summary li.eic-stat-warn.is-zero,
.eic-app .eic-summary li.eic-stat-review.is-zero { background: #fff; border-top-color: var(--eic-line); }
.eic-app .eic-summary li.eic-stat-warn.is-zero .eic-num,
.eic-app .eic-summary li.eic-stat-review.is-zero .eic-num { color: var(--eic-muted); }

/* ------------------------------------------------------- lifecycle pills */

.eic-pill {
	display: inline-block;
	padding: .1rem .5rem;
	border-radius: 11px;
	font-family: var(--eic-sans-med);
	font-size: .8rem;
	line-height: 1.5;
	white-space: nowrap;
	/* Transparent so outlined pills (Under Review, Denied) are the same size. */
	border: 1px solid transparent;
	background: var(--eic-stage-other-bg);
	color: var(--eic-stage-other-ink);
}

/*
	EIC status pills. Same five buckets as the timeline's left axis, same colors
	as its row bands, so a project reads identically in either view. See the
	palette note at the top and eic-tgroup-* further down.
*/
.eic-pill.eic-cat-approved  { background: var(--eic-x-approved-bg); color: var(--eic-x-approved-ink); }
.eic-pill.eic-cat-review    { background: var(--eic-x-review-bg);   color: var(--eic-x-review-ink); border: 1px dotted var(--eic-x-review); }
.eic-pill.eic-cat-hold      { background: var(--eic-on-hold-bg);    color: var(--eic-x-hold-ink); }
.eic-pill.eic-cat-denied    { background: var(--eic-x-denied-bg);   color: var(--eic-x-denied-ink); border-color: var(--eic-x-denied); }
.eic-pill.eic-cat-completed { background: var(--eic-complete-bg);   color: var(--eic-x-completed-ink); }

.eic-app .eic-num {
	display: block;
	font-family: var(--eic-sans-bold);
	font-weight: 400;
	font-size: 1.7rem;
	line-height: 1.05;
	color: var(--eic-navy);
}

/* -------------------------------------------------------------------- tabs */

/*
	Segmented buttons, not underlined text. As text links the inactive tab read as
	a caption and people missed that "Project list" was clickable at all - so these
	now have a border, a hover state and a filled active state.
*/
.eic-app .eic-views {
	display: flex;
	align-items: center;
	gap: .4rem;
	margin: 0 0 1.1rem;
}

.eic-views-lead {
	margin-right: .35rem;
	font-family: var(--eic-sans-med);
	font-size: .72rem;
	text-transform: uppercase;
	letter-spacing: .04em;
	color: var(--eic-muted);
}

.eic-app .eic-tab {
	padding: .5rem 1.15rem;
	border: 1px solid #c7cdd5;
	border-radius: 4px;
	background: #fff;
	font-family: var(--eic-sans-med);
	font-size: .95rem;
	font-weight: 400;
	color: var(--eic-blue);
	cursor: pointer;
}

.eic-app .eic-tab:hover {
	border-color: var(--eic-blue);
	background: #eef3fb;
}

.eic-app .eic-tab.is-active {
	font-family: var(--eic-sans-bold);
	background: var(--eic-navy);
	border-color: var(--eic-navy);
	color: #fff;
}

.eic-app .eic-tab:focus-visible { outline: 2px solid var(--eic-blue); outline-offset: 2px; }

/* ----------------------------------------------------------------- filters */

/*
	Grid, not flex. With flex the last row stretched two selects to half the page
	each, and a label that wrapped to two lines ("LITS Workflow Category") pushed
	its own select out of line with its neighbours.
*/
.eic-app .eic-filters {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
	gap: .55rem .65rem;
	align-items: end;
	margin: 0 0 .7rem;
	/* Tight and pale: the filters are a tool, not the subject of the page. */
	padding: .6rem .75rem;
	background: #fafbfc;
	border: 1px solid #e8ecf0;
	border-radius: 4px;
}

/*
	At full width, explicit columns rather than auto-fit. Each is sized so its
	label fits on ONE line - "LITS WORKFLOW CATEGORY" is the widest at roughly
	154px - which is what keeps the whole bar to a single row. Auto-fit gave
	every control the same width, so the bar was as tall as its longest label.
*/
/*
	The breakpoint is on the VIEWPORT but the constraint is the SiteManager content
	column, which is ~200px narrower. With four controls the minimums plus gaps plus
	the button need only ~780px of inner width, so ~1000px of viewport is enough;
	1080 leaves headroom. (It was 1280 when there were six controls.)

	Below this the auto-fit rule above takes over and the bar wraps cleanly.
*/
@media (min-width: 1080px) {
	.eic-app .eic-filters {
		/*
			minmax, not fixed widths: the minimum is what keeps each label on one
			line, and the fr share lets the controls absorb the slack evenly. A
			plain `auto` last track made the Clear filters button swallow all the
			leftover width and turned it into the biggest thing in the bar.
		*/
		grid-template-columns:
			minmax(10rem, 1.2fr)     /* Search              */
			minmax(8rem, 0.9fr)      /* Project Size        */
			minmax(8.5rem, 1fr)      /* IT Category         */
			minmax(10.5rem, 1.15fr)  /* Resource Constraint */
			max-content;             /* Clear filters       */
	}
}

.eic-filter {
	display: flex;
	flex-direction: column;
	gap: .15rem;
	min-width: 0;
}

.eic-app .eic-filter label {
	/* One line, never wrapping - the column widths above are set to guarantee
	   it. A wrapping label was what made the bar two rows tall. */
	display: block;
	margin: 0;
	white-space: nowrap;
	font-family: var(--eic-sans-med);
	font-size: .68rem;
	font-weight: 400;
	line-height: 1.4;
	text-transform: uppercase;
	letter-spacing: .03em;
	color: var(--eic-muted);
}

.eic-app .eic-filter select,
.eic-app .eic-filter input[type="search"] {
	width: 100%;
	max-width: 100%;
	height: 2.1rem;
	padding: .25rem .45rem;
	border: 1px solid #c7cdd5;
	border-radius: 3px;
	background: #fff;
	font-family: var(--eic-sans);
	font-size: .88rem;
	color: var(--eic-ink);
}

.eic-app .eic-filter select:focus,
.eic-app .eic-filter input[type="search"]:focus {
	outline: 2px solid var(--eic-blue);
	outline-offset: 1px;
}

.eic-filter-reset { justify-content: flex-end; }

.eic-app .eic-btn {
	height: 2.1rem;
	padding: 0 1rem;
	border: 1px solid var(--eic-blue);
	border-radius: 3px;
	background: #fff;
	font-family: var(--eic-sans-med);
	font-size: .88rem;
	font-weight: 400;
	color: var(--eic-blue);
	cursor: pointer;
	white-space: nowrap;
}

.eic-app .eic-btn:hover { background: var(--eic-blue); color: #fff; }

.eic-app .eic-btn-small { height: auto; padding: .2rem .6rem; font-size: .82rem; }

.eic-app .eic-resultcount {
	margin: 0 0 .6rem;
	font-size: .88rem;
	color: var(--eic-muted);
}

.eic-app .eic-note {
	margin: .7rem 0 0;
	font-size: .87rem;
	line-height: 1.5;
	color: var(--eic-muted);
}

/* -------------------------------------------------------------------- grid */

.eic-grid { margin: 0; }

.eic-app .tabulator {
	border: 1px solid var(--eic-line);
	border-radius: 4px;
	background: #fff;
	font-family: var(--eic-sans);
	font-variant-numeric: lining-nums tabular-nums;
	font-size: .92rem;
}

/* Header: two tiers deep because of the date column groups, so it needs to be
   compact and clearly separated from the body. */
.eic-app .tabulator .tabulator-header {
	background: var(--eic-bg-soft);
	border-bottom: 2px solid #c3cad4;
	color: var(--eic-navy);
	font-family: var(--eic-sans-med);
	font-weight: 400;
	font-size: .78rem;
}

.eic-app .tabulator .tabulator-col {
	background: var(--eic-bg-soft);
	border-right: 1px solid #e3e7ec;
}

/*
	Uppercase the GROUP title only. A descendant selector here also caught the
	group's own child columns, which turned "Completion" into "COMPLE..." and
	"Start" into "STA..." - the letter-spacing pushed them past their width. The
	direct-child chain stops at the group's own title cell.
*/
.eic-app .tabulator .tabulator-col-group > .tabulator-col-content .tabulator-col-title {
	text-transform: uppercase;
	letter-spacing: .05em;
	font-family: var(--eic-sans-bold);
	color: var(--eic-navy);
}

.eic-app .tabulator .tabulator-col-title {
	font-weight: 400;
	white-space: normal;
	line-height: 1.25;
}

.eic-app .tabulator .tabulator-row { border-bottom: 1px solid var(--eic-line-soft); }
.eic-app .tabulator .tabulator-row.tabulator-row-even { background: #fbfcfd; }
.eic-app .tabulator .tabulator-row:hover { background: #eef3fa; }
.eic-app .tabulator .tabulator-row.tabulator-selected { background: #e3ecf8; }

.eic-app .tabulator .tabulator-cell {
	padding: .55rem .65rem;
	border-right: 1px solid var(--eic-line-soft);
}

/*
	Tabulator sets `white-space: nowrap` + ellipsis on every cell, which truncated
	the two columns that must stay readable: the project name
	("BI-EndowCustodyBank: Endowment Custody B...") and the status age
	("On hold 2.4 years ..."). These columns opt into wrapping and pair it with
	variableHeight so the row grows instead.
*/
.eic-app .tabulator .tabulator-cell.eic-cell-wrap {
	white-space: normal;
	text-overflow: clip;
	line-height: 1.35;
}

/* Frozen first column needs a hard edge so it reads as pinned while the rest
   of the grid scrolls horizontally under it. */
.eic-app .tabulator .tabulator-frozen {
	border-right: 1px solid #c3cad4;
	background: inherit;
}

.eic-app .tabulator .tabulator-row .tabulator-cell.tabulator-frozen { background: #fff; }
.eic-app .tabulator .tabulator-row.tabulator-row-even .tabulator-cell.tabulator-frozen { background: #fbfcfd; }
.eic-app .tabulator .tabulator-row:hover .tabulator-cell.tabulator-frozen { background: #eef3fa; }

.eic-app a.eic-projlink {
	font-family: var(--eic-sans-med);
	font-weight: 400;
}

.eic-code {
	display: block;
	font-size: .78rem;
	color: var(--eic-muted);
	letter-spacing: .01em;
}

.eic-flag { cursor: help; color: var(--eic-at-risk); }

/* The empty-today columns are mostly em-dashes. Keep them present, per the
   spec, but let them recede instead of dominating the grid. */
.eic-app .tabulator .eic-muted { color: var(--eic-faint); }

/* ------------------------------------------------------------------ status */

.eic-status {
	display: inline-flex;
	align-items: center;
	gap: .38rem;
	white-space: nowrap;
	font-family: var(--eic-sans-med);
	font-weight: 400;
}

.eic-dot {
	width: .6rem;
	height: .6rem;
	border-radius: 50%;
	background: currentColor;
	flex: 0 0 auto;
}

.eic-status-on_track  { color: var(--eic-on-track); }
.eic-status-at_risk   { color: var(--eic-at-risk); }
.eic-status-off_track { color: var(--eic-off-track); }
.eic-status-on_hold   { color: var(--eic-on-hold); }
.eic-status-complete  { color: var(--eic-complete); }

/* "No update" is a governance signal for this committee, so it is a deliberate
   neutral outline rather than blank. */
.eic-status-none,
.eic-status- {
	color: var(--eic-muted);
	font-family: var(--eic-sans);
}

.eic-status-none .eic-dot,
.eic-status- .eic-dot {
	background: transparent;
	border: 2px solid var(--eic-faint);
}

/* Own line under the status label - see statusFormatter(). */
.eic-age {
	display: block;
	font-family: var(--eic-sans);
	font-size: .8rem;
	line-height: 1.3;
	color: var(--eic-muted);
}

/* ---------------------------------------------------------------- variance */

.eic-var-late,
.eic-var-early { font-family: var(--eic-sans-bold); font-weight: 400; }
.eic-var-late  { color: var(--eic-off-track); }
.eic-var-early { color: var(--eic-on-track); }
.eic-var-same  { color: var(--eic-muted); }

/* ---------------------------------------------------------------- timeline */

.eic-app .eic-tlcontrols {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: .45rem .9rem;
	margin: 0 0 .7rem;
	font-size: .87rem;
	color: var(--eic-muted);
}

.eic-app .eic-legend {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: .45rem .9rem;
	margin: 0 0 .7rem;
	font-size: .87rem;
	color: var(--eic-muted);
}

.eic-key {
	display: inline-block;
	width: 1.6rem;
	height: .8rem;
	border-radius: 2px;
	vertical-align: middle;
	margin-right: -.35rem;
}

.eic-legend-lead {
	font-family: var(--eic-sans-med);
	color: var(--eic-ink);
}

/* Status swatches, matching the timeline fills exactly. */
.eic-key-on_track  { background: var(--eic-on-track-bg);  border: 1px solid var(--eic-on-track);  border-left: 4px solid var(--eic-on-track); }
.eic-key-at_risk   { background: var(--eic-at-risk-bg);   border: 1px solid var(--eic-at-risk);   border-left: 4px solid var(--eic-at-risk); }
.eic-key-off_track { background: var(--eic-off-track-bg); border: 1px solid var(--eic-off-track); border-left: 4px solid var(--eic-off-track); }
.eic-key-on_hold   { background: var(--eic-on-hold-bg);   border: 1px solid var(--eic-on-hold);   border-left: 4px solid var(--eic-on-hold); }
.eic-key-complete  { background: var(--eic-complete-bg);  border: 1px solid var(--eic-complete);  border-left: 4px solid var(--eic-complete); }
.eic-key-noupdate  { background: #fbfbfc; border: 1px dashed var(--eic-faint); border-left: 4px dotted var(--eic-faint); }

.eic-timeline {
	border: 1px solid var(--eic-line);
	border-radius: 4px;
	background: #fff;
}

.eic-app .vis-timeline {
	border: 0;
	font-family: var(--eic-sans);
	font-variant-numeric: lining-nums tabular-nums;
	font-size: .85rem;
}

.eic-app .vis-labelset .vis-label {
	padding: .3rem .6rem;
	font-family: var(--eic-sans-med);
	font-weight: 400;
	color: var(--eic-navy);
}

/*
	The EIC status rows down the left. Same colors as the grid's EIC status pills.
	Committed work reads as solid and present, the review queue as tentative
	(dotted, like its bars), finished work in the shared "complete" blue.
*/
.eic-app .vis-labelset .vis-label.eic-tgroup-approved {
	background: var(--eic-x-approved-bg);
	color: var(--eic-x-approved-ink);
	border-left: 4px solid var(--eic-x-approved);
}

.eic-app .vis-labelset .vis-label.eic-tgroup-review {
	background: var(--eic-x-review-bg);
	color: var(--eic-x-review-ink);
	border-left: 4px dotted var(--eic-x-review);
}

.eic-app .vis-labelset .vis-label.eic-tgroup-hold {
	background: var(--eic-on-hold-bg);
	color: var(--eic-x-hold-ink);
	border-left: 4px solid var(--eic-on-hold);
}

.eic-app .vis-labelset .vis-label.eic-tgroup-denied {
	background: var(--eic-x-denied-bg);
	color: var(--eic-x-denied-ink);
	border-left: 4px solid var(--eic-x-denied);
}

.eic-app .vis-labelset .vis-label.eic-tgroup-completed {
	background: var(--eic-complete-bg);
	color: var(--eic-x-completed-ink);
	border-left: 4px solid var(--eic-complete);
}

/* Legend swatches for the EIC status rows. */
.eic-xkey-approved  { background: var(--eic-x-approved-bg); border: 1px solid var(--eic-x-approved); border-left: 4px solid var(--eic-x-approved); }
.eic-xkey-review    { background: var(--eic-x-review-bg);   border: 1px dotted var(--eic-x-review); border-left: 4px dotted var(--eic-x-review); }
.eic-xkey-hold      { background: var(--eic-on-hold-bg);    border: 1px solid var(--eic-on-hold);   border-left: 4px solid var(--eic-on-hold); }
.eic-xkey-denied    { background: var(--eic-x-denied-bg);   border: 1px solid var(--eic-x-denied);  border-left: 4px solid var(--eic-x-denied); }
.eic-xkey-completed { background: var(--eic-complete-bg);   border: 1px solid var(--eic-complete);  border-left: 4px solid var(--eic-complete); }

/* -------------------------------------------------------- timeline nav */

.eic-nav {
	display: inline-flex;
	gap: .3rem;
	margin-left: .25rem;
}

.eic-app .eic-nav .eic-btn { min-width: 4.5rem; }

.eic-app .vis-item {
	border-radius: 3px;
	border-width: 1px;
}

/*
	Approved bars are filled by STATUS, not one uniform blue.

	Status was previously only a 5px stripe on the left edge, which made the one
	thing this page exists to surface the least visible thing on it - a screen of
	identical blue bars. The whole bar now carries the status fill, with the
	saturated color on the border and a heavier left edge still anchoring it.
	Status is never color alone: the grid shows a labeled dot, and every bar's
	tooltip names the status in words.
*/
.eic-app .vis-item.eic-bar-approved {
	background-color: #dfe7f2;
	border-color: #8fa6c4;
	color: var(--eic-ink);
}

.eic-app .vis-item.eic-bar-approved.eic-status-on_track  { background-color: var(--eic-on-track-bg);  border-color: var(--eic-on-track); }
.eic-app .vis-item.eic-bar-approved.eic-status-at_risk   { background-color: var(--eic-at-risk-bg);   border-color: var(--eic-at-risk); }
.eic-app .vis-item.eic-bar-approved.eic-status-off_track { background-color: var(--eic-off-track-bg); border-color: var(--eic-off-track); }
.eic-app .vis-item.eic-bar-approved.eic-status-on_hold   { background-color: var(--eic-on-hold-bg);   border-color: var(--eic-on-hold); }
.eic-app .vis-item.eic-bar-approved.eic-status-complete  { background-color: var(--eic-complete-bg);  border-color: var(--eic-complete); }

/* Status color also anchors the bar's left edge. */
.eic-app .vis-item.eic-status-on_track  { border-left: 5px solid var(--eic-on-track); }
.eic-app .vis-item.eic-status-at_risk   { border-left: 5px solid var(--eic-at-risk); }
.eic-app .vis-item.eic-status-off_track { border-left: 5px solid var(--eic-off-track); }
.eic-app .vis-item.eic-status-on_hold   { border-left: 5px solid var(--eic-on-hold); }
.eic-app .vis-item.eic-status-complete  { border-left: 5px solid var(--eic-complete); }

/* No update stays deliberately pale and dashed - it is an absence, and it should
   look like one next to the projects that do report. */
.eic-app .vis-item.eic-bar-approved.eic-status-none {
	background-color: #fbfbfc;
	border: 1px dashed var(--eic-faint);
	border-left: 5px dotted var(--eic-faint);
	color: var(--eic-muted);
}

/*
	Requested but not scheduled. Muted and hatched so it can never be mistaken
	for work the committee has committed to.
*/
.eic-app .vis-item.eic-bar-proposed {
	background-color: transparent;
	background-image: repeating-linear-gradient(
		45deg, transparent, transparent 3px, #d6dae0 3px, #d6dae0 6px
	);
	border: 1px dashed var(--eic-muted);
	color: var(--eic-muted);
}

.eic-bar-tag {
	margin-left: .4rem;
	padding: 0 .3rem;
	border: 1px solid var(--eic-muted);
	border-radius: 2px;
	font-size: .72rem;
	text-transform: uppercase;
	letter-spacing: .03em;
	white-space: nowrap;
}

.eic-app .vis-item.eic-bar-partial.vis-point .vis-dot {
	border-color: var(--eic-at-risk);
	border-width: 6px;
}

/*
	Single-day approved projects are drawn as points rather than a sub-pixel bar
	(see buildTimelineItem). The status color moves from the bar's left edge to
	the dot so the color coding still reads.
*/
.eic-app .vis-item.eic-bar-approved.vis-point .vis-dot {
	border-color: var(--eic-blue);
	border-width: 6px;
}

.eic-app .vis-item.eic-bar-approved.vis-point.eic-status-on_track  .vis-dot { border-color: var(--eic-on-track); }
.eic-app .vis-item.eic-bar-approved.vis-point.eic-status-at_risk   .vis-dot { border-color: var(--eic-at-risk); }
.eic-app .vis-item.eic-bar-approved.vis-point.eic-status-off_track .vis-dot { border-color: var(--eic-off-track); }
.eic-app .vis-item.eic-bar-approved.vis-point.eic-status-on_hold   .vis-dot { border-color: var(--eic-on-hold); }
.eic-app .vis-item.eic-bar-approved.vis-point.eic-status-complete  .vis-dot { border-color: var(--eic-complete); }
.eic-app .vis-item.eic-bar-approved.vis-point.eic-status-none      .vis-dot { border-color: var(--eic-faint); }

/*
	Under Review = the dates are not settled, whichever dates they are. A dotted
	outline says "tentative" while the status fill and the solid left edge still
	carry the status, so the bar loses none of its meaning.

	Dotted, not dashed: dashed is already taken by "no status update", and the two
	need to stay tellable apart.
*/
.eic-app .vis-item.eic-tentative {
	border-top-style: dotted;
	border-right-style: dotted;
	border-bottom-style: dotted;
	border-top-width: 2px;
	border-right-width: 2px;
	border-bottom-width: 2px;
}

/* A point item's own border must not double as a bar outline. */
.eic-app .vis-item.vis-point { background: none; border: 0; }
.eic-app .vis-item.vis-point .vis-item-content { padding-left: .2rem; }

/* --------------------------------------------------------------- no dates */

.eic-app .eic-nodates {
	margin: 1.5rem 0 0;
	padding: 1rem 1.1rem;
	background: var(--eic-bg-soft);
	border: 1px solid var(--eic-line);
	border-radius: 4px;
}

.eic-app .eic-nodates h3 {
	margin: 0 0 .2rem;
	font-family: var(--eic-sans-bold);
	font-weight: 400;
	font-size: 1.05rem;
	color: var(--eic-navy);
}

.eic-app .eic-nodates-list {
	margin: .8rem 0 0;
	padding: 0;
	list-style: none;
}

.eic-app .eic-nodates-list li {
	margin: 0;
	padding: .4rem 0;
	border-top: 1px solid var(--eic-line);
	font-size: .93rem;
}

.eic-tag {
	display: inline-block;
	margin: 0 .4rem;
	padding: .05rem .5rem;
	background: #fff;
	border: 1px solid var(--eic-line);
	border-radius: 10px;
	font-size: .78rem;
	color: var(--eic-muted);
}

/* ------------------------------------------------------------ detail panel */

/*
	A centered modal. `position: fixed` with an explicit transform is set for BOTH
	paths on purpose: showModal() would centre it anyway in the top layer, and the
	fallback (a plain `open` attribute, where the dialog would otherwise sit in
	normal flow) needs it. One rule covers both.
*/
.eic-app dialog.eic-detail {
	position: fixed;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	z-index: 900;
	width: min(46rem, calc(100vw - 2rem));
	max-height: min(80vh, 44rem);
	margin: 0;
	padding: 1.35rem 2.8rem 1.35rem 1.35rem;
	overflow-y: auto;
	background: #fff;
	color: var(--eic-ink);
	border: 1px solid var(--eic-line);
	border-top: 3px solid var(--eic-blue);
	border-radius: 5px;
	box-shadow: 0 18px 50px rgba(10, 35, 85, .28);
}

.eic-app dialog.eic-detail::backdrop { background: rgba(10, 35, 85, .45); }

.eic-app dialog.eic-detail:not([open]) { display: none; }

.eic-app .eic-detail h3 {
	margin: 0 0 .6rem;
	font-family: var(--eic-sans-med);
	font-weight: 400;
	font-size: 1.15rem;
	color: var(--eic-navy);
}

.eic-app .eic-detail h4 {
	margin: 1.3rem 0 .4rem;
	font-family: var(--eic-sans-bold);
	font-weight: 400;
	font-size: .95rem;
	text-transform: uppercase;
	letter-spacing: .04em;
	color: var(--eic-muted);
}

.eic-app .eic-detail-close {
	position: absolute;
	top: .6rem;
	right: .6rem;
	width: 1.9rem;
	height: 1.9rem;
	border: 1px solid var(--eic-line);
	border-radius: 3px;
	background: #fff;
	font-size: 1.2rem;
	line-height: 1;
	color: var(--eic-muted);
	cursor: pointer;
}

.eic-app .eic-detail-close:hover { color: var(--eic-ink); border-color: var(--eic-muted); }

.eic-app .eic-dl {
	display: grid;
	grid-template-columns: minmax(10rem, 15rem) 1fr;
	gap: 0;
	margin: 0;
	font-size: .93rem;
}

.eic-app .eic-dl dt,
.eic-app .eic-dl dd {
	margin: 0;
	padding: .4rem .6rem .4rem 0;
	border-top: 1px solid var(--eic-line-soft);
}

.eic-app .eic-dl dt {
	font-family: var(--eic-sans-med);
	font-weight: 400;
	color: var(--eic-muted);
}

/* --------------------------------------------------------------- page foot */

.eic-app .eic-foot {
	margin: 1.75rem 0 0;
	padding-top: .8rem;
	border-top: 1px solid var(--eic-line);
	font-size: .83rem;
	color: var(--eic-muted);
}

/* ------------------------------------------------------------------ narrow */

@media (max-width: 700px) {
	.eic-app .eic-dl { grid-template-columns: 1fr; }
	.eic-app .eic-dl dt { padding-bottom: 0; border-top: 1px solid var(--eic-line); }
	.eic-app .eic-dl dd { border-top: 0; padding-top: .1rem; }
	.eic-app .eic-summary li { flex: 1 1 45%; }
}
