/* ============================================================================
 * jfx-list — the Listings table (views/properties/index.php)
 *
 * Purpose-built and self-contained ON PURPOSE.
 *
 * This table previously used Bitrix's genuine main.ui.grid.css together with
 * its real .main-grid-* markup. That stylesheet is written for the
 * main.ui.grid PHP/JS component, which an external marketplace app cannot run.
 * Everything that component does at runtime — assigning every column an
 * explicit width, positioning the "ear" scroll buttons, the sticky header —
 * has to be re-supplied by hand, and each of those gaps caused its own round
 * of visible breakage (rows ballooning to 234px, thumbnails at full size,
 * columns shearing; see the plan file's history). Rather than keep patching a
 * stylesheet whose runtime assumptions we can't satisfy, this file owns the
 * list outright and depends on no JS to lay itself out.
 *
 * The LOOK is still Bitrix's, taken from its real specs/design tokens:
 * head cells 14px weight-400 #535c69 (NOT uppercase) on #fff with an #edeef0
 * underline; body 14px #535c69 with #eef2f4 row separators; hover #f6f8f9;
 * Helvetica Neue via --ui-font-family-primary.
 *
 * LAYOUT: `table-layout: fixed` + an explicit <colgroup> is the same technique
 * main.ui.grid's JS applies at runtime, just declared up front. Note that
 * `table-layout: fixed` WITHOUT declared widths is the exact trap that
 * previously split the container evenly across 13 columns; the <colgroup> in
 * the markup is therefore load-bearing, not decoration. `min-width` keeps the
 * columns legible and lets the box scroll sideways instead of crushing them.
 * ========================================================================= */

/* The scroll box. Height is capped by sizeGridBox() in views/footer.php so the
   horizontal scrollbar stays on screen: this app's iframe renders at full
   content height inside Bitrix's slider, so an uncapped list puts its own
   scrollbar hundreds of px below the fold where it can never be reached.
   The max-height here is only a pre-JS fallback. */
.jfx-list-box {
	background: #fff;
	border: 1px solid #e6e8ea;
	border-radius: var(--ui-border-radius-2xs, 4px);
	overflow: auto;
	max-height: 60vh;
	/* Do NOT add `scroll-behavior: smooth` here. It turns even a plain
	   `scrollLeft = x` assignment into an animation, and animations are a
	   silent no-op wherever the page isn't being painted — which makes the ear
	   buttons do nothing at all. Measured: with it, 0px moved; without it, the
	   full amount. An instant jump that always works beats a glide that
	   sometimes doesn't. */
}

.jfx-list {
	table-layout: fixed;
	width: 100%;
	/* Sum of the fixed columns (1208px) + a still-usable Details column. Below
	   this the box scrolls sideways rather than squeezing the columns. Keep it
	   UNDER a real slider's inner width (~1495px at a 1600px slider) or the
	   table overruns by a few px and draws a horizontal scrollbar for nothing;
	   above that width `width:100%` takes over and Details absorbs the slack. */
	min-width: 1440px;
	/* separate (not collapse) so the sticky header keeps its bottom border —
	   collapsed borders belong to the table, not the cell, and detach on scroll. */
	border-collapse: separate;
	border-spacing: 0;
	font-family: var(--ui-font-family-primary, "Helvetica Neue", Arial, sans-serif);
	font-size: 14px;
	color: #535c69;
	background: #fff;
}

/* ---- column widths (see LAYOUT note above) — fixed total: 1208px ----
   Type and Portals are 116px because their content MEASURED 89px + 24px cell
   padding. Don't shrink them on looks alone: at 84/96px the bathroom count and
   the 4th portal icon were silently clipped (the cell still reported its full
   width — only scrollWidth vs clientWidth reveals it). */
.jfx-c-check   { width: 40px; }
.jfx-c-act     { width: 44px; }
/* Widened 2026-08-17 after reading the real table on a real window: at 96px a
   reference set as "DEMO-R-..." and a status as "Archi…", while four columns
   nobody scans took the room. Those four are hidden by default now (see
   views/properties/index.php DEFAULT_HIDDEN), so the space exists to spend. */
.jfx-c-ref     { width: 132px; }
.jfx-c-details { /* no width: absorbs whatever is left over */ }
.jfx-c-type    { width: 116px; }
.jfx-c-size    { width: 96px; }
.jfx-c-price   { width: 140px; }
.jfx-c-status  { width: 118px; }
.jfx-c-loc     { width: 186px; }
.jfx-c-agent   { width: 116px; }
.jfx-c-owner   { width: 116px; }
.jfx-c-portals { width: 132px; }
.jfx-c-leads   { width: 74px; }
.jfx-c-created { width: 96px; }

/* ---- header ---- */
.jfx-list thead th {
	position: sticky;
	top: 0;
	z-index: 2;
	height: 44px;
	padding: 0 12px;
	background: #fff;
	border-bottom: 1px solid #edeef0;
	font-size: 14px;
	font-weight: 400;
	color: #535c69;
	/* start, not left: this is a column header and it has to sit over its
	   own data. Under dir=rtl `left` put it at the far edge of the cell. */
	text-align: start;
	white-space: nowrap;
	vertical-align: middle;
}

.jfx-list th.jfx-sortable {
	cursor: pointer;
	user-select: none;
}

.jfx-list th.jfx-sortable:hover,
.jfx-list th.jfx-sort-active {
	color: var(--ui-color-primary, #2fc6f6);
}

/* The direction caret only shows on the sorted column (or on hover as an
   affordance), so the header row doesn't read as a row of arrows. */
.jfx-sort-icon {
	margin-inline-start: 4px;
	font-size: 9px;
	opacity: 0;
}

.jfx-list th.jfx-sortable:hover .jfx-sort-icon { opacity: .45; }
.jfx-list th.jfx-sort-active .jfx-sort-icon    { opacity: 1; }

/* ---- resize grip + reorder feedback ---- */
/* The header cells are already `position: sticky`, which is a positioned
   ancestor, so the grip anchors to the th without needing position:relative. */
.jfx-resizer {
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	width: 7px;
	cursor: col-resize;
	user-select: none;
}

.jfx-resizer:hover { background: var(--ui-color-primary, #2fc6f6); opacity: .5; }

/* While dragging, the pointer leaves the 7px grip constantly — force the
   cursor and kill text selection document-wide for the duration. */
body.jfx-resizing { cursor: col-resize !important; user-select: none; }

.jfx-list th.jfx-dragging { opacity: .4; }

.jfx-list th.jfx-drop-target {
	box-shadow: inset 2px 0 0 var(--ui-color-primary, #2fc6f6);
}

/* Only the reorderable headers advertise the grab cursor; the frozen
   checkbox/actions columns aren't draggable. */
.jfx-list thead th[draggable="true"] { cursor: grab; }
.jfx-list thead th[draggable="true"]:active { cursor: grabbing; }

/* ---- body ---- */
.jfx-list tbody td {
	padding: 8px 12px;
	border-bottom: 1px solid #eef2f4;
	vertical-align: middle;
	/* NO `overflow: hidden` here. It looks like the natural way to enforce the
	   column width, but it isn't needed — table-layout:fixed + the <colgroup>
	   already fix every width, and the text is clipped by .jfx-t on the inner
	   element. What it DID do was clip the row's action menu (a Bootstrap
	   dropdown rendered as a child of this 44px cell) out of existence: the menu
	   opened, had a size, and painted nowhere. */
}

.jfx-list tbody tr:hover td { background: #f6f8f9; }

/* ---- frozen checkbox + Actions columns ----
 * Without this, scrolling right to reach Location/Agent/Created takes the row's
 * ⋮ menu off screen with it, so the actions are unreachable exactly when the
 * table is wide enough to need scrolling.
 *
 * These need an opaque background or the scrolled cells slide visibly under
 * them. `left` on the second column must equal the first column's width (40px).
 * The row-hover rule above still wins over these backgrounds on specificity
 * (0,2,3 vs 0,2,1), so frozen cells keep highlighting with their row.
 */
.jfx-list th:nth-child(1),
.jfx-list td:nth-child(1) {
	position: sticky;
	left: 0;
	z-index: 1;
	background: #fff;
}

.jfx-list th:nth-child(2),
.jfx-list td:nth-child(2) {
	position: sticky;
	left: 40px;
	z-index: 1;
	background: #fff;
}

/* The header's frozen cells stick on BOTH axes, so they must outrank both the
   sticky header (z-index 2) and the frozen body cells (1). */
.jfx-list thead th:nth-child(1),
.jfx-list thead th:nth-child(2) {
	z-index: 3;
}

/* While a row's action menu is open, lift THAT CELL above the header.
 *
 * This is not cosmetic. Freezing the Actions column makes the cell
 * `position: sticky` WITH a z-index, which makes it a stacking context — so the
 * menu's own `z-index: 1000` is scoped inside the cell and is measured against
 * the header as if it were the cell's z-index of 1. The header (2) therefore
 * paints straight over any menu that flips upward. Raising the cell is what
 * actually raises the menu; setting a bigger z-index on the menu cannot work.
 * Toggled by initRowMenus() on Bootstrap's show/hide.bs.dropdown.
 */
.jfx-list tbody td.jfx-menu-open { z-index: 10; }

/* Marks where the frozen pair ends — only once the table is actually scrolled,
   which is why it's on the cell rather than a container. */
.jfx-list th:nth-child(2)::after,
.jfx-list td:nth-child(2)::after {
	content: "";
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	width: 1px;
	background: #edeef0;
}

/* Single-line + ellipsis. Every text cell uses this: an untruncated 60-char
   description is what dictated column widths and wrapped rows to 110px+. */
.jfx-t {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* Two-line cell rhythm: a primary value and a muted secondary under it.
   Kept tight (13px + 11px) so a row stays ~56px with a 40px thumbnail. */
.jfx-v  { font-size: 13px; color: #535c69; line-height: 1.35; }
.jfx-vs { font-size: 11px; color: #a8adb4; line-height: 1.35; margin-top: 1px; }

/* ---- the Details cell (thumbnail + title + description) ---- */
.jfx-media {
	display: flex;
	align-items: center;
	gap: 10px;
	min-width: 0; /* required, or the flex child refuses to shrink and ellipsis never kicks in */
}

.jfx-thumb {
	flex: 0 0 40px;
	width: 40px;
	height: 40px;
	border-radius: var(--ui-border-radius-2xs, 4px);
	object-fit: cover;
	background: #f1f3f5;
}

.jfx-media-text { min-width: 0; flex: 1 1 auto; }

.jfx-title {
	display: block;
	font-size: 13px;
	font-weight: 600;
	color: var(--ui-color-primary, #2fc6f6);
	text-decoration: none;
}

.jfx-title:hover {
	color: var(--ui-color-primary, #2fc6f6);
	text-decoration: underline;
}

/* ---- small pieces ---- */
.jfx-facts {
	display: flex;
	align-items: center;
	gap: 10px;
	font-size: 13px;
	white-space: nowrap;
}

.jfx-facts i { margin-inline-end: 3px; color: var(--ui-color-accent-light-blue, #559be6); }

.jfx-portal-icons { display: flex; align-items: center; gap: 4px; }

.jfx-portal-icons img {
	width: 20px;
	height: 20px;
	border-radius: 50%;
	object-fit: cover;
}

/* ---- portals as switches ----
 * The cell used to draw only the portals a listing WAS on, which made "not on
 * Bayut" and "this app has never heard of Bayut" look identical. All four are
 * always drawn now; the ones that are off are greyed and faded rather than
 * hidden, so the cell reads as a row of four switches with some flipped.
 *
 * grayscale + opacity rather than a separate off-state icon: it works for any
 * logo, including the tenant's own, which is what the fourth switch shows. */
.jfx-portal-icons--switch { gap: 2px; }

.jfx-portal-sw {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 26px;
	height: 26px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: transparent;
	cursor: pointer;
	transition: filter .12s, opacity .12s, background .12s;
	/* Off. Legible as "this exists and is not on", not as a broken image. */
	filter: grayscale(1);
	opacity: .38;
}

.jfx-portal-sw.--on {
	filter: none;
	opacity: 1;
}

.jfx-portal-sw:hover:not([disabled]) {
	background: #f0f2f5;
	opacity: 1;
}

/* Read-only for anyone without publish rights: still shows the state, offers
 * no affordance to change it. */
.jfx-portal-sw[disabled] { cursor: default; }
.jfx-portal-sw[disabled]:hover { background: transparent; }

.jfx-portal-sw img {
	width: 20px;
	height: 20px;
	border-radius: 50%;
	object-fit: cover;
}

/* ---- leads ---- */
/* The count of enquiries against a listing. The second number is the ones not
 * yet turned into a CRM record — the ones still needing somebody. */
.jfx-leads-new {
	display: inline-block;
	min-width: 18px;
	padding: 0 5px;
	border-radius: 9px;
	background: #2fc26b;
	color: #fff;
	font-size: 11px;
	font-weight: 600;
	line-height: 18px;
	text-align: center;
}

.jfx-muted { color: #a8adb4; }

/* ---- grid "ears" (Bitrix's edge scroll buttons) ----
 * Sizes/opacity from Bitrix's own .main-grid-ear (50x160, opacity .6, .8 on
 * hover). Bitrix's rule carries NO `top` because its grid JS positions these;
 * this list owns its box, so they're simply centred here. `display:none` until
 * .show, so they never sit over the data when there's nothing to scroll.
 */
.jfx-list-shell { position: relative; }

.jfx-ear {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	z-index: 4;
	display: none;
	align-items: center;
	justify-content: center;
	width: 34px;
	height: 90px;
	padding: 0;
	border: 1px solid #dfe0e3;
	border-radius: 4px;
	background: #fff;
	color: #535c69;
	cursor: pointer;
	opacity: .6;
	transition: opacity 200ms ease;
}

.jfx-ear.show { display: flex; }
.jfx-ear:hover { opacity: .95; }

.jfx-ear-left  { left: 4px; }
.jfx-ear-right { right: 4px; }

/* ---- action panel ----
 * Bitrix's .main-grid-panel-wrap is `border-top: 2px solid #eef2f4`; its
 * counter is padding-inline-start 19px / min-width 120px.
 */
.jfx-panel {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 8px 0;
	border-top: 2px solid #eef2f4;
	font-size: 13px;
	color: #535c69;
}

.jfx-panel-forall {
	display: flex;
	align-items: center;
	gap: 6px;
	margin: 0 0 0 4px;
	cursor: pointer;
	user-select: none;
}

.jfx-panel-counter {
	margin-inline-start: auto;
	padding-inline-start: 19px;
	min-width: 120px;
	text-align: end;
	white-space: nowrap;
}

/* ---- Bulk Actions flyout submenus ----
 * The flat menu ran ~15 items deep and overflowed the slider. Grouping it into
 * flyouts keeps the top level short. Bootstrap 5 has no submenu support, so
 * the mechanics live here + in index-buttons.php.
 */
.jfx-has-sub { position: relative; }

.jfx-has-sub > .jfx-sub-toggle {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	width: 100%;
}

.jfx-sub-caret {
	font-size: 10px;
	opacity: .55;
}

.jfx-has-sub.show > .jfx-sub-toggle { background: #f5f5f6; color: #3b434f; }

.jfx-submenu {
	display: none;
	position: absolute;
	top: 0;
	left: 100%;
	margin: 0;
	/* Beat the parent menu so the flyout can overlap it when flipped left. */
	z-index: 1;
}

.jfx-has-sub.show > .jfx-submenu { display: block; }

/* Flipped when there's no room on the right (the Bulk Actions button lives at
   the right edge of the toolbar, so this is the normal case, not the edge case). */
.jfx-has-sub.jfx-sub-left > .jfx-submenu {
	left: auto;
	right: 100%;
}

/* Column-chooser rows: a whole-row click target for each checkbox. */
.jfx-col-opt {
	display: flex;
	align-items: center;
	gap: 8px;
	margin: 0;
	cursor: pointer;
}

.jfx-empty {
	padding: 40px 12px;
	text-align: center;
	color: #a8adb4;
}

/* An empty list should look finished rather than half-loaded. The icon is what
   does that: a bare grey sentence in the middle of a white page reads as
   something that failed to render, which is how Activity looked with no records
   yet. */
.jfx-empty-icon {
	display: block;
	font-size: 26px;
	margin-bottom: 10px;
	color: #cdd3d9;
}

/* The row action button — a quiet ⋮ that only gains weight on hover, matching
   how Bitrix's own row menus sit in the grid. */
.jfx-act-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 28px;
	height: 28px;
	padding: 0;
	border: 0;
	border-radius: var(--ui-border-radius-2xs, 4px);
	background: transparent;
	color: #828b95;
	cursor: pointer;
}

.jfx-act-btn:hover { background: #e8eafb; color: #535c69; }

/* ============================================================================
 * .jfx-list--plain — the simple lists (agents, developers, bayut/pf-locations)
 *
 * Same Bitrix look, none of the 13-column machinery. Everything above is tuned
 * for Listings, and two of its rules are actively wrong on a 3-6 column table:
 *
 *   - `min-width: 1440px` is the sum of Listings' fixed columns. On Developers
 *     (3 columns) it would force ~1150px of empty table and a horizontal
 *     scrollbar over nothing.
 *   - the frozen pair is addressed by :nth-child(1)/(2) because on Listings
 *     those ARE the checkbox and the action menu. On Developers they're ID and
 *     Name — freezing them is meaningless, and there's nothing to scroll anyway.
 *
 * These overrides rely on SOURCE ORDER, not specificity: each pairs with an
 * identically-specific rule above ((0,1,0) and (0,2,1)), so this block must
 * stay at the END of the file. Scoping the originals to a Listings-only class
 * instead would mean editing the working Listings markup — which is how this
 * grid has shipped broken before.
 * ========================================================================= */
.jfx-list--plain { min-width: 0; }

/* Un-freeze the body's first two cells outright. */
.jfx-list--plain tbody td:nth-child(1),
.jfx-list--plain tbody td:nth-child(2) {
	position: static;
	background: transparent;
}

/* The HEADER keeps position:sticky — it still sticks to the top of the scroll
   box. Only the horizontal component is dropped, via `left: auto`. Do NOT set
   `position: static` here: at (0,2,1) it would out-specify `.jfx-list thead th`
   (0,1,2) and silently kill the sticky header for these two columns only. */
.jfx-list--plain thead th:nth-child(1),
.jfx-list--plain thead th:nth-child(2) {
	left: auto;
	z-index: 2; /* back in line with the rest of the header */
}

/* The divider marking where the frozen pair ends has nothing to mark. */
.jfx-list--plain th:nth-child(2)::after,
.jfx-list--plain td:nth-child(2)::after { content: none; }

/* Right-aligned trailing action column (Delete), which these lists use instead
   of Listings' frozen burger menu. */
.jfx-list--plain .jfx-cell-end { text-align: end; }

/* ---- column widths for the plain lists ----
   Same contract as Listings' .jfx-c-*: `table-layout: fixed` needs a declared
   width or the column collapses, so every <col> gets one EXCEPT the single
   column meant to absorb the slack (the name/location). */
/* Six columns on a 1340px table means the one with no width takes everything
   left over — about 600px of it — so the agent's name sat alone in the middle
   of the row with its email pinned to the far right. Widened on 2026-08-17
   against the real table: the data columns take their share and the name keeps
   the slack rather than hoarding it. The action column shrinks because DELETE
   is an icon now, not a word. */
.jfx-c-id      { width: 80px; }
.jfx-c-rowact  { width: 76px; }
.jfx-c-email   { width: 300px; }
.jfx-c-mobile  { width: 170px; }
.jfx-c-licence { width: 170px; }

/* The agent name cell: a round photo next to the name, so it reads as the same
   component as Listings' .jfx-media thumbnail row rather than a second idiom. */
.jfx-avatar {
	flex: 0 0 32px;
	width: 32px;
	height: 32px;
	border-radius: 50%;
	object-fit: cover;
	background: #f1f3f5;
}

/* --------------------------------------------------------------------------
 * Scrollbars, made quiet.
 *
 * The list box needs a HORIZONTAL scrollbar — thirteen columns do not fit any
 * screen, and the ear buttons alone are not a discoverable affordance. What it
 * does not need is the platform's default chunky grey bar sitting under every
 * table, which is what made the page look unfinished.
 *
 * The VERTICAL one is gone for a different reason: five rows per page never
 * reach the box's height cap, so it is simply absent rather than styled away.
 * Nested scrollbars — the list's inside the page's — were the real complaint.
 * ------------------------------------------------------------------------ */
.jfx-list-box {
	scrollbar-width: thin;                    /* Firefox */
	scrollbar-color: #c9ced3 transparent;
}

.jfx-list-box::-webkit-scrollbar {
	height: 8px;
	width: 8px;
}

.jfx-list-box::-webkit-scrollbar-track {
	background: transparent;
}

.jfx-list-box::-webkit-scrollbar-thumb {
	background: #d5dade;
	border-radius: 4px;
}

/* Only on hover does it assert itself — the bar is there when a hand is
   already on the list, and near-invisible when the page is being read. */
.jfx-list-box:hover::-webkit-scrollbar-thumb {
	background: #b6bdc4;
}

.jfx-list-box::-webkit-scrollbar-thumb:hover {
	background: #97a0a8;
}

/* A scrollbar for an axis that does not overflow is chrome for nothing. */
.jfx-list-box::-webkit-scrollbar-corner {
	background: transparent;
}

/* ============================================================================
 * MIN-WIDTH FLOORS for the multi-column plain lists
 *
 * `.jfx-list--plain` sets `min-width: 0`, which is right for a 3-column
 * reference list and wrong for a 7-column one. With no floor, a panel narrower
 * than the sum of the declared columns does not scroll — `table-layout: fixed`
 * takes the shortfall out of the ONE column with no declared width (the tenant
 * name) until it is zero px wide, and the name then wraps a word per line and
 * paints straight over the Unit column. That was the broken screenshot; the
 * floor is the fix — below it the box scrolls sideways instead of collapsing.
 *
 * Each floor is `declared columns + the slack column's guaranteed minimum`.
 * Must stay AFTER the .jfx-list--plain block: source order is what decides
 * between two equally-specific rules, exactly as noted at the top of that block.
 * ========================================================================= */
.jfx-list.tn-contract-list { min-width: 982px; }   /* 788 declared + 194 tenant   */
.jfx-list.tn-building-list { min-width: 760px; }   /* 558 declared + 202 name     */
.jfx-list.agr-issued-list  { min-width: 700px; }   /* 404 declared + 296 document */

/* ============================================================================
 * The renewals board
 *
 * Columns rather than rows because the question is "how soon", and the shape of
 * the answer — three cards here, twelve there — is the whole point. A sorted
 * list cannot show that at a glance.
 *
 * The columns SCROLL SIDEWAYS below their combined minimum rather than
 * squeezing: four 260px columns need 1100px, and a Bitrix24 slider is often
 * narrower than that. Letting them compress instead would wrap every tenant
 * name onto three lines, which is the same failure the contract table's
 * min-width floor exists to prevent.
 * ========================================================================= */
.tn-board {
	display: flex;
	gap: 12px;
	align-items: flex-start;
	overflow-x: auto;
	padding-bottom: 8px;
}

.tn-board-col {
	flex: 1 1 0;
	min-width: 240px;
	background: #f6f8f9;
	border-radius: 6px;
	padding: 8px;
}

.tn-board-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	/* The bucket's own colour, as a rule across the top: it is the same colour
	   the list's pills use, so the two screens agree at a glance. */
	border-top: 3px solid #7d8389;
	border-radius: 3px 3px 0 0;
	padding: 8px 4px;
	margin-bottom: 6px;
}

.tn-board-title { font-size: 13px; font-weight: 600; color: #3b434f; }

.tn-board-count {
	font-size: 12px;
	color: #535c69;
	background: #fff;
	border-radius: 10px;
	padding: 1px 8px;
	min-width: 24px;
	text-align: center;
}

.tn-board-body { display: flex; flex-direction: column; gap: 6px; }

.tn-board-empty {
	font-size: 12px;
	color: #a8adb4;
	padding: 12px 4px;
	margin: 0;
}

.tn-card {
	background: #fff;
	border: 1px solid #e3e6e9;
	border-radius: 6px;
	padding: 10px;
}

.tn-card-top {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 6px;
}

/* Every line truncates. A card that grows with its content makes the columns
   ragged, and the ragged edge is what the eye tracks instead of the counts. */
.tn-card-tenant,
.tn-card-unit,
.tn-card-meta,
.tn-card-rent,
.tn-card-note {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.tn-card-tenant { font-size: 13px; font-weight: 600; color: #3b434f; min-width: 0; }
.tn-card-unit   { font-size: 12px; color: #535c69; margin-top: 2px; }
.tn-card-meta   { font-size: 11px; color: #a8adb4; margin-top: 4px; }
.tn-card-rent   { font-size: 12px; color: #535c69; margin-top: 2px; }
.tn-card-note   { font-size: 11px; color: #1eb96f; margin-top: 4px; }

.tn-card-acts { margin-top: 6px; }

/* Already renewed: still readable, visibly not a task. Shown only when asked
   for — the board hides them by default, or it would never empty. */
.tn-card.--renewed { opacity: .62; }

/* One rhythm for every row regardless of whether it carries an expiry badge.
   Mismatched heights were half of what read as "broken" — the eye tracks the
   ragged left edge of the action column, not the content. */
.tn-contract-list tbody tr,
.tn-building-list tbody tr,
.agr-issued-list tbody tr { height: 56px; }

/* Truncate, never wrap. A list is scanned, and one cell that wraps costs every
   other row its alignment. The full value stays reachable via title=.
   Deliberately NOT scoped to one table — three lists use these now, and a
   scoped copy per table is how three lists drift apart. */
.jfx-cell-main,
.jfx-cell-sub {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.jfx-cell-main   { font-size: 13px; font-weight: 600; color: #3b434f; line-height: 1.35; }
.jfx-cell-sub { font-size: 11px; color: #a8adb4; line-height: 1.35; margin-top: 1px; }

/* A unit number or a city is a fact, not a heading — same truncation, normal weight. */
.jfx-cell-main.jfx-cell-plain { font-weight: 400; color: #535c69; }

.jfx-nowrap { white-space: nowrap; }

/* `white-space: nowrap` on its own only promises one line — it says nothing
   about where that line stops. In a `table-layout: fixed` cell the text simply
   carries on past the column and paints over its neighbour, which is how a term
   date's closing year came to sit on top of the rent figure. Clipping is what
   was actually wanted, and it belongs with the class rather than with each
   caller.

   Applied to `.jfx-nowrap` only, never to the cell generally: an action cell
   holds a dropdown that has to escape its column, and `overflow: hidden` on a
   td is precisely what erased the row menus once before. No action cell carries
   this class, so no menu can be clipped by this rule. */
.jfx-list td.jfx-nowrap,
.jfx-list td > .jfx-nowrap {
	overflow: hidden;
	text-overflow: ellipsis;
}

.jfx-badge-row { margin-top: 3px; }

/* Pills sized in px, not with the utility classes: `py-0.5` on an inline span
   gives no reliable height, so two pills in adjacent columns sat at different
   heights on the same row. */
.jfx-pill {
	display: inline-flex;
	align-items: center;
	max-width: 100%;
	height: 20px;
	padding: 0 8px;
	border-radius: 10px;
	font-size: 11px;
	font-weight: 500;
	line-height: 1;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* Row actions are icons (see the row template), so the column is sized for
   icons: two 28px buttons + the cell's 12px padding either side = 68px inside
   a 92px column. Laid out with flex so they can only ever sit side by side —
   inline-block buttons wrapped the moment the column was a few px short. */
.jfx-rowacts {
	display: flex;
	align-items: center;
	justify-content: flex-end;
	gap: 2px;
	flex-wrap: nowrap;
}

/* Tone modifiers for the icon buttons.
 *
 * Stripping the labels off Submit/Approve/Reject would otherwise strip their
 * meaning with them — the old buttons carried it in ui-btn-primary / -success /
 * -link, and a green tick beside a red cross is the only thing that still tells
 * approve from reject at a glance once the words are gone. The colour is on the
 * GLYPH, not a filled background: five solid chips in one cell is exactly the
 * noise the labelled buttons were.
 */
.jfx-act-btn.--primary { color: var(--ui-color-primary, #2fc6f6); }
.jfx-act-btn.--success { color: #1eb96f; }
.jfx-act-btn.--danger  { color: #e85340; }

.jfx-act-btn.--primary:hover { background: #e8f4fd; color: var(--ui-color-primary, #2fc6f6); }
.jfx-act-btn.--success:hover { background: #e6f6ee; color: #1eb96f; }
.jfx-act-btn.--danger:hover  { background: #fdeceb; color: #e85340; }
