/* ===========================================================================
   Responsive layer — applies to BOTH the legacy skin and the opt-in modern
   skin. Loaded unconditionally, LAST, so its media queries win the cascade.

   The legacy layout was built for a fixed 1050px viewport (see the viewport
   meta in sources/layout/wrapper.php) and pins `min-width: 1000px` on html,
   body, .wrapper, .header, .menu and .body in stylesheet.css.

   Page content is laid out with floated percentage columns — `<div class="l
   w_33">` etc. (see modules/clients/manage.php:202). Three w_33 columns each
   hold a form whose label cell is 150-200px and whose field is 330px, so a
   column needs ~500px before it overflows. That is why the columns have to
   start collapsing well above the phone breakpoint: at 1000px, three of them
   are 333px each and the content spills.

   Breakpoint ladder:
     any width  grid columns auto-balance via flex (see below) where supported
     <= 1500px  three-up columns go two-up
     <= 1200px  columns go full width, and data tables become row-as-cards
     <= 1024px  release the fixed min-widths, condense the nav
     <=  768px  stack the layout tables, hamburger nav, stack form rows
     <=  480px  compress spacing, drop non-essential chrome

   The first two numbers come from measurement rather than convention: a
   label cell (150-200px) beside a field (330px) needs ~500px, so three of
   them need ~1500px and two need ~1000px plus chrome. The old 1400/1100 pair
   left a band around 1400-1450 where three columns were still side by side
   but every label wrapped onto three lines.
   =========================================================================== */


/* ---------------------------------------------------------------------------
   Always-on (any width) — size-independent bugs the fixed viewport hid.
   --------------------------------------------------------------------------- */

.header img {
	max-width: 100%;
	height: auto;
}

/* Select2 parks the original <select> in the DOM as a 1px absolutely
   positioned element. Anything that widens it puts a full-width invisible
   box outside the layout, which escapes overflow containers and creates
   phantom horizontal scroll. Pin it so no width rule below can re-inflate
   it. */
.select2-hidden-accessible {
	width: 1px !important;
	min-width: 0 !important;
	max-width: 1px !important;
}

/* The lightbox iframe was hard-coded to 600x400 and overflowed any viewport
   narrower than that. */
#ep_lightbox td #ep_lightbox_container,
#ep_lightbox td #ep_lightbox_container #ep_lightbox_frame {
	max-width: 95vw;
	max-height: 85vh;
}

#ep_lightbox td #ep_lightbox_container #ep_lightbox_frame {
	width: 100%;
	height: 100%;
	display: block;
}

/* Hamburger — hidden until 768px. Lives in the header row so it stays
   visible while #main_menu is collapsed. */
.nav_toggle {
	display: none;
	background: transparent;
	border: 1px solid rgba(255,255,255,.6);
	border-radius: 4px;
	color: #FFF;
	font-size: 18px;
	line-height: 1;
	padding: 8px 11px;
	margin-left: 10px;
	cursor: pointer;
	vertical-align: middle;
	-webkit-appearance: none;
}

.nav_toggle:hover,
.nav_toggle:focus {
	background-color: rgba(255,255,255,.15);
	border-color: #FFF;
	color: #FFF;
}

/* The caret JS appends to nav items that have a dropdown. Only meaningful in
   the stacked mobile menu, so it stays hidden until then — BOTH levels, or
   the second-level carets leak into the desktop flyouts. */
.menu .parent > .nav_caret,
.menu .child > .nav_caret {
	display: none;
}


/* ---------------------------------------------------------------------------
   Density switch — icons only, label on hover.

   The three words cost ~150px in a header already competing with the logo,
   two skin toggles and the user links, and the icons carry the meaning. The
   `title` on each button is what shows the label on hover.

   Visually hidden rather than `display: none`: a display-none span
   contributes nothing to the accessible name, which would leave the button
   named only by its `title` — a weaker, less consistently announced source.
   Clipping it keeps the real text in the accessibility tree while removing
   it visually. Below 768px it comes back (see that block): there is no hover
   on touch, and the stacked menu panel has room for it.
   --------------------------------------------------------------------------- */

.density_opt_text {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}


/* ---------------------------------------------------------------------------
   Grid columns — let content decide how many fit, at every width.

   The panel columns are floats (`<div class="ca"><div class="l w_33">`), and
   floats have two failure modes the percentage breakpoints below cannot fix:

     1. Uneven wrapping. Three 50%-wide floats put two on the first row and
        snag the third against the taller of them, so it lands beside the
        SHORT column with a column-height hole next to it. Measured on the
        client edit page at 1300px: columns at y=225, y=225, y=666.
     2. Cliff-edge reflow. A fixed breakpoint cannot know that this page's
        columns need 500px while another's need 300px, so one number is
        wrong for one of them.

   A wrapping flex row fixes both: `flex-basis` states the width a column
   actually wants, and the browser fits as many per row as the viewport
   allows and stretches them to fill. No holes, no cliff, no magic number.

   Scoped with `:has()` so only rows that really contain grid columns become
   flex — `.ca` is a bare clearfix used in 147 files for everything from
   button bars to inline labels. Browsers without `:has()` (Firefox < 121)
   simply keep the float behaviour and the percentage breakpoints below,
   which is the pre-existing, working layout.
   --------------------------------------------------------------------------- */

.ca:not(.title_box):has(> .l[class*="w_"], > .r[class*="w_"]) {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-start;
	/* row-gap ONLY, deliberately not the `gap` shorthand: the horizontal
	   gutter already exists as `.p_r`'s 15px padding-right INSIDE each
	   column, so a column-gap would double it. Without this a wrapped panel
	   sits flush against the bottom of the row above (measured: 0px), which
	   is what floats used to avoid by accident. Reads --ep-panel-pad so the
	   modern skin's density switch moves it too; the literal is the legacy
	   fallback, matching .p_r. */
	row-gap: var(--ep-panel-pad, 15px);
}

.ca:not(.title_box):has(> .l[class*="w_"], > .r[class*="w_"]) > .l[class*="w_"],
.ca:not(.title_box):has(> .l[class*="w_"], > .r[class*="w_"]) > .r[class*="w_"] {
	float: none;
	width: auto;
	/* 500px is the measured minimum for a label cell (150-200px) beside a
	   field (330px). Below that the pair wraps and the column looks broken,
	   so it is the point at which a column should drop to the next row
	   instead. `min-width: 0` lets a flex item shrink below its content's
	   min-content width, which is what stops a long table inside a column
	   from pushing the whole row wide. */
	flex: 1 1 500px;
	min-width: 0;
}

/* The clearfix is pointless once the row is flex, and as a generated child it
   would otherwise sit in the row as an empty flex item. */
.ca:not(.title_box):has(> .l[class*="w_"], > .r[class*="w_"]):after {
	display: none;
}


/* ---------------------------------------------------------------------------
   <= 1500px — three-up column rows go two-up.

   This is the percentage fallback. Browsers with `:has()` never reach it for
   grid columns: the flex rule above already sized them by content.

   `[class*="w_"]` deliberately matches the whole w_* scale; .w_100 matching
   is harmless because it is already full width.
   --------------------------------------------------------------------------- */

@media (max-width: 1500px) {

	.w_16,
	.w_20,
	.w_25,
	.w_33 {
		width: 50%;
	}

	.w_60,
	.w_66,
	.w_70,
	.w_75,
	.w_80,
	.w_83,
	.w_90 {
		width: 100%;
	}

	/* Fixed-width fields are what actually overflow a narrowed column. Cap
	   them without forcing a width, so genuinely small inputs (percentage
	   boxes, quantity fields) keep their size. `!important` is required
	   because several of these widths are inline `style` attributes. */
	.form input,
	.form select,
	.form textarea,
	.table input,
	.table select,
	.table textarea {
		max-width: 100% !important;
		min-width: 0 !important;
		box-sizing: border-box;
	}

}


/* ---------------------------------------------------------------------------
   <= 1200px — every percentage column goes full width.
   --------------------------------------------------------------------------- */

@media (max-width: 1200px) {

	.w_10, .w_16, .w_20, .w_25, .w_30, .w_33, .w_40,
	.w_50, .w_60, .w_66, .w_70, .w_75, .w_80, .w_83, .w_90 {
		width: 100%;
	}

	/* Only un-float the grid columns. Bare `.l` / `.r` are also used for
	   small inline button groups and header links, which should keep
	   floating. */
	.l[class*="w_"],
	.r[class*="w_"] {
		float: none;
		width: 100%;
	}

	/* Not every column row uses the w_* scale — the dashboard builds its
	   two-up layout from a `.ca` clearfix wrapping a `.l` with a hard-coded
	   inline `width: 400px`. `.ca` marks a row of floated halves, so that is
	   the reliable signal; `!important` is needed to beat the inline width. */
	.ca > .l,
	.ca > .r {
		float: none !important;
		width: auto !important;
		max-width: 100%;
	}

	/* Stack label/field pairs. A 150-200px label cell beside a 330px field
	   needs roughly 500px, so once the percentage columns above have gone
	   full width the pair no longer fits side by side on anything but a
	   wide screen.

	   Target the `.left`/`.right` cells, NOT `.form` wholesale. `table.form`
	   is overloaded in this app: it wraps listing chrome and filter bars as
	   well as real edit forms, so a blanket `display: block` on `.form`
	   flattens whole listing pages into one column (observed on ?a=3).
	   Making just these two cells blocks lets CSS table fixup wrap them in
	   one anonymous cell, which stacks them, while every other row keeps its
	   normal table layout. */
	.form tbody > tr > td.left,
	.form tbody > tr > td.right {
		display: block;
		width: 100% !important;
		box-sizing: border-box;
	}

	.form tbody > tr > td.left {
		text-align: left;
		padding: 10px 12px 2px;
	}

	.form tbody > tr > td.right {
		padding: 0 12px 12px;
	}

	/* Once stacked there is a full row to fill, so the big fields go fluid.
	   Narrow numeric inputs are left alone — they carry an explicit inline
	   width and only need the cap set at the 1500px breakpoint.

	   `:not(.select2-hidden-accessible)` matters: Select2 keeps the original
	   <select> in the DOM as a 1px visually-hidden element, and this rule
	   outranks its `width: 1px !important` and re-inflates it to full width.
	   Being absolutely positioned, it then escapes the body cell's scroll
	   container and drags the whole page sideways. */
	.form tbody > tr > td.right > input[type="text"],
	.form tbody > tr > td.right > input[type="password"],
	.form tbody > tr > td.right > input[type="email"],
	.form tbody > tr > td.right > select:not(.select2-hidden-accessible),
	.form tbody > tr > td.right > textarea {
		width: 100% !important;
	}

	/* `.title_box` appears in TWO forms in this app and both need handling:
	     a) <div class="ca title_box"> with floated `.l` / `.r` halves
	        (modules/clients/manage.php:89)
	     b) <table class="title_box"> with `td.left` / `td.right`
	        (the saved-reports listings, e.g. ?a=33)

	   Both bars separate their buttons with `&nbsp;&nbsp;`. A non-breaking
	   space cannot line-break, so the row stays one long line and the last
	   button hangs off the edge no matter what `white-space` says — form (a)
	   measured 1132px inside an 885px container, form (b) 775px inside 375px.
	   A wrapping flex row puts each button in its own flex item, which wraps
	   regardless. */
	.title_box,
	.title_box > tbody,
	.title_box > tbody > tr {
		display: block;
		width: 100%;
		text-align: left;
		box-sizing: border-box;
		float: none;
	}

	.title_box > .l,
	.title_box > .r,
	.title_box > tbody > tr > td.left,
	.title_box > tbody > tr > td.right {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: 6px;
		width: 100%;
		text-align: left;
		box-sizing: border-box;
		float: none;
	}

	/* `table.body` is a pure layout wrapper (one row, one cell) but it is a
	   real table, so it sizes to its content's min-content width and drags
	   the whole page sideways when something inside is wide. Promote it to a
	   block and let the cell own the horizontal scroll instead.

	   CHILD combinators, not descendant: `.body td` would match every cell
	   of every data table on the page — that bug collapsed listings to one
	   column per line. Only this table's own cell may become a block. */
	.body,
	.body > tbody,
	.body > tbody > tr,
	.body > tbody > tr > td {
		display: block;
		width: 100%;
		box-sizing: border-box;
	}

	.body > tbody > tr > td {
		overflow-x: auto;
		-webkit-overflow-scrolling: touch;
	}

	/* Every module wraps its own content in a second, UNCLASSED layout table
	   — `<table width="100%"><tr><td valign="top">` in each module's own
	   module.php, 96 of them. `width: 100%` does not shrink a table: a
	   table's used width
	   is max(specified, min-content), so this one sizes to the desktop
	   min-content of everything inside it and drags the page sideways no
	   matter what the rules above do to its children. Measured on the client
	   edit page at a 900px viewport: 1162px wide inside an 885px cell, i.e.
	   301px of horizontal scroll, all of it from this one element.
	   Promoting it to a block is what lets the content below actually reflow.

	   `table:not([class])` plus the child-combinator chain from `.body` is
	   what keeps this off real tables: every data table carries `.table` and
	   every form carries `.form`, and nested tables are never a direct child
	   of the body cell. */
	.body > tbody > tr > td > table:not([class]),
	.body > tbody > tr > td > table:not([class]) > tbody,
	.body > tbody > tr > td > table:not([class]) > tbody > tr,
	.body > tbody > tr > td > table:not([class]) > tbody > tr > td {
		display: block;
		width: 100%;
		box-sizing: border-box;
	}

}


/* ---------------------------------------------------------------------------
   <= 1024px — release the fixed minimum widths.
   --------------------------------------------------------------------------- */

@media (max-width: 1024px) {

	html,
	body,
	.wrapper,
	.header,
	.menu,
	.body,
	.table,
	.form {
		min-width: 0;
	}

	/* Nav items were a single non-wrapping row; let them wrap instead of
	   forcing a horizontal scrollbar. */
	.menu > tbody > tr > td {
		padding-left: 8px;
		padding-right: 8px;
	}

	.menu a.level_0 {
		padding: 0 12px;
	}

	.body > tbody > tr > td {
		padding: 12px;
	}

	.tool_box {
		box-sizing: border-box;
		width: auto;
		max-width: 100%;
	}

	/* Button rows wrap instead of running off the edge. */
	.title_box .right,
	.title_box .left {
		white-space: normal;
	}

	input[type="submit"],
	input[type="button"],
	a.btn,
	a.login_btn {
		margin-bottom: 4px;
	}

}


/* ---------------------------------------------------------------------------
   <= 1200px — data tables become row-as-cards.

   Measured, not guessed. On the client edit page the widest listing table
   reports a min-content width of ~1076px, and a table never renders below
   min-content — so no max-width, overflow or column rule can stop it
   side-scrolling on a narrower screen. That is the whole of the 'tables
   overlap on tablet' symptom.

   1200px rather than 1024px because the residual was measured across the
   band: 77px of scroll left at 1100px and 27px at 1150px with the cards set
   to 1024. That band is precisely iPad landscape (1180-1194px), which is the
   case being complained about. Pairing it with the column-collapse tier also
   keeps one number for 'the layout reflows here' instead of two.

   Two things this is NOT: releasing the fixed min-widths made no measurable
   difference here (tested at 1100 and 1150, identical numbers), and neither
   did the percentage column rules. The tables' own min-content was the
   binding constraint all along.
   --------------------------------------------------------------------------- */

@media (max-width: 1200px) {

	/* --- Data tables --------------------------------------------------- */

	/* 12px is the legacy skin's value and stays its fallback. The modern skin
	   substitutes its density size instead — a flat 12px here would override
	   Enlarge on exactly the screens where someone is most likely to want it. */
	.table {
		font-size: var(--ep-font, 12px);
	}

	/* Tables functions.js could not label keep the side-scroll fallback. */
	.table:not(.ews_stackable) > thead > tr > td,
	.table:not(.ews_stackable) > tbody > tr > td {
		white-space: nowrap;
	}

	/* Row-as-card. Each cell prints its column name (stamped as `data-label`
	   by ews_stack_tables) on the left and its value on the right, so a
	   12-column listing reads as a short list per record instead of a
	   horizontal scroll. Colours are derived from `currentColor` and a
	   neutral alpha so this works unchanged in all four skins. */
	/* All four levels, or `thead` / `thead > tr` stay table boxes inside a
	   block table and the browser wraps them in a shrink-to-fit anonymous
	   table — the panel title bar then renders at min-content instead of
	   spanning the card. */
	.ews_stackable,
	.ews_stackable > tbody,
	.ews_stackable > thead,
	.ews_stackable > thead > tr,
	.ews_stackable > thead > tr > td {
		display: block;
		width: 100%;
		box-sizing: border-box;
	}

	/* The column-name row becomes the per-cell labels, so it is redundant. */
	.ews_stackable > tbody > tr.ews_labels {
		display: none;
	}

	.ews_stackable > tbody > tr {
		display: block;
		width: 100%;
		box-sizing: border-box;
		padding: 4px 0;
		border-top: 3px solid rgba(127,127,127,.28);
	}

	/* `:first-of-type` would match the label row, which is hidden — leaving
	   the first VISIBLE card with a border. Target the row after it too. */
	.ews_stackable > tbody > tr:first-of-type,
	.ews_stackable > tbody > tr.ews_labels + tr {
		border-top: 0;
	}

	.ews_stackable > tbody > tr > td {
		display: flex;
		align-items: baseline;
		justify-content: space-between;
		gap: 14px;
		width: 100%;
		box-sizing: border-box;
		/* The fallback in each var() is the legacy value, so the legacy skin
		   — which declares no custom properties — is unchanged, while the
		   modern skin's density switch also re-spaces the cards. */
		padding: var(--ep-cell-pad-y, 7px) var(--ep-cell-pad-x, 12px);
		border-top: 1px solid rgba(127,127,127,.16);
		white-space: normal;
		text-align: right;
		overflow-wrap: anywhere;
	}

	.ews_stackable > tbody > tr > td:first-child {
		border-top: 0;
	}

	.ews_stackable > tbody > tr > td[data-label]:before {
		content: attr(data-label);
		flex: 0 0 38%;
		text-align: left;
		font-weight: 700;
		font-size: 11px;
		letter-spacing: .02em;
		text-transform: uppercase;
		opacity: .65;
		/* Labels must not be dragged into the value's alignment. */
		white-space: normal;
	}

	/* Rows the labeller skipped (colspan separators, section bands) stay
	   full-width rather than pretending to be a field. */
	.ews_stackable > tbody > tr > td:not([data-label]) {
		display: block;
		text-align: left;
	}

	/* A label with no value is noise. Declared AFTER the :not() rule above —
	   the two are the same specificity, and a cell under a blank column
	   header gets .ews_empty but no data-label, so it matches both. */
	.ews_stackable > tbody > tr > td.ews_empty {
		display: none;
	}

	/* Same row-as-card treatment for the standalone pages that bypass
	   wrapper.php — sso-status.php and mcp-tokens.php. Those use a plain
	   `<thead><th>` instead of the listing template's `.category` row, so
	   they get their own opt-in class, stamped by the small inline script
	   in each page. */
	table.ews_cards {
		display: block;
		width: 100%;
	}

	/* These pages put their <th> cells in a plain first <tr> with no
	   <thead>, so the label row is marked by the script instead. Both are
	   handled. */
	table.ews_cards > thead,
	table.ews_cards > tbody > tr.ews_labels {
		display: none;
	}

	table.ews_cards > tbody {
		display: block;
		width: 100%;
	}

	table.ews_cards > tbody > tr {
		display: block;
		width: 100%;
		box-sizing: border-box;
		padding: 4px 0;
		border-top: 3px solid rgba(127,127,127,.28);
	}

	table.ews_cards > tbody > tr:first-of-type {
		border-top: 0;
	}

	table.ews_cards > tbody > tr > td {
		display: flex;
		align-items: baseline;
		justify-content: space-between;
		gap: 14px;
		width: 100%;
		box-sizing: border-box;
		padding: var(--ep-cell-pad-y, 7px) var(--ep-cell-pad-x, 10px);
		border-bottom: 1px solid rgba(127,127,127,.16);
		text-align: right;
		white-space: normal;
		overflow-wrap: anywhere;
	}

	table.ews_cards > tbody > tr > td[data-label]:before {
		content: attr(data-label);
		flex: 0 0 38%;
		text-align: left;
		font-weight: 700;
		font-size: 11px;
		letter-spacing: .02em;
		text-transform: uppercase;
		opacity: .65;
		white-space: normal;
	}

	table.ews_cards > tbody > tr > td.ews_empty {
		display: none;
	}
}


/* ---------------------------------------------------------------------------
   <= 768px — stack the layout tables, collapse the nav behind the hamburger.
   --------------------------------------------------------------------------- */

@media (max-width: 768px) {

	html {
		background-image: none;
		-webkit-text-size-adjust: 100%;
	}

	/* --- Header ------------------------------------------------------- */

	.header,
	.header > tbody {
		display: block;
		width: 100%;
	}

	.header > tbody > tr {
		display: flex;
		align-items: center;
		justify-content: space-between;
	}

	.header > tbody > tr > td {
		display: block;
		height: auto;
		padding: 10px 12px;
	}

	.header > tbody > tr > td[align="right"] {
		display: flex;
		align-items: center;
		justify-content: flex-end;
		text-align: right;
	}

	.header > tbody > tr > td img {
		max-height: 40px;
		width: auto;
	}

	.nav_toggle {
		display: inline-block;
	}

	/* --- Menu --------------------------------------------------------- */

	/* #main_menu is the collapsible panel; .nav_toggle adds/removes `.open`. */
	#main_menu {
		display: none;
	}

	#main_menu.open {
		display: block;
	}

	.menu,
	.menu > tbody,
	.menu > tbody > tr,
	.menu > tbody > tr > td {
		display: block;
		width: 100%;
		box-sizing: border-box;
	}

	.menu > tbody > tr > td,
	.menu > tbody > tr > td[align="right"] {
		padding: 0;
		text-align: left;
	}

	.menu .parent {
		display: block;
		position: relative;
		background-image: none;
		padding-right: 0;
		border-bottom: 1px solid rgba(255,255,255,.12);
	}

	.menu .child {
		position: relative;
		border-bottom: 0;
	}

	/* 44px minimum touch target. */
	.menu a.level_0 {
		line-height: 44px;
		padding: 0 16px;
	}

	/* Dropdowns become inline accordions — `:hover` never fires on touch, so
	   the caret toggles `.open` instead (see functions.js). */
	.menu .parent .dropdown,
	.menu .child .dropdown {
		position: static;
		display: none;
		top: auto;
		left: auto;
		margin: 0;
		box-shadow: none;
		background-color: rgba(0,0,0,.18);
	}

	/* Kill the desktop hover-flyout behaviour, but never for a branch the
	   user has actually opened — hence `:not(.open)` on the dropdown's own
	   parent. Without it these rules are (0,5,0) and the `.child.open`
	   rule below is (0,4,0), so a NESTED submenu snaps shut the moment its
	   ancestor is hovered. Touch browsers apply a sticky :hover to the
	   element you just tapped, which is exactly the tap that opens it. */
	.menu .parent:not(.open) > .dropdown,
	.menu .parent:hover .child:not(.open) > .dropdown {
		display: none;
	}

	.menu .parent.open > .dropdown,
	.menu .parent:hover .child.open > .dropdown,
	.menu .child.open > .dropdown {
		display: block;
	}

	.menu a.level_1,
	.menu a.level_2 {
		line-height: 38px;
		padding: 0 16px 0 32px;
		background-color: transparent;
		color: #FFF;
	}

	.menu a.level_2 {
		padding-left: 48px;
	}

	/* The legacy flyout arrow images are absolutely positioned for the
	   desktop layout; the caret replaces them when stacked. */
	.menu .child img {
		display: none;
	}

	.menu .parent > .nav_caret {
		display: block;
		position: absolute;
		top: 0;
		right: 0;
		width: 44px;
		height: 44px;
		line-height: 44px;
		text-align: center;
		color: #FFF;
		cursor: pointer;
	}

	.menu .child > .nav_caret {
		display: block;
		position: absolute;
		top: 0;
		right: 0;
		width: 38px;
		height: 38px;
		line-height: 38px;
		text-align: center;
		color: #FFF;
		cursor: pointer;
	}

	/* Utility cell (theme toggles + user links) sits under the nav. */
	.menu > tbody > tr > td[align="right"] {
		padding: 12px 16px;
		border-top: 1px solid rgba(255,255,255,.2);
	}

	.dark_mode_toggle,
	.modern_ui_toggle {
		margin-bottom: 8px;
	}

	/* Once the utility cell is a stacked panel there is room for the words
	   again, and a 44px-tall target is easier to hit than an icon.

	   Selector is `body.modern_ui .density_switch`, not the bare class:
	   modern.css sets `margin: 0 10px` at (0,2,0) and a bare `.density_switch`
	   here is only (0,1,0), so it LOSES and the side margins survive. That
	   pushed a width:100% switch 12px past its cell and put 6px of horizontal
	   scroll on the whole page with the mobile menu open. box-sizing matters
	   for the same reason — the 1px border is outside width:100% otherwise. */
	body.modern_ui .density_switch,
	.density_switch {
		display: flex;
		width: 100%;
		box-sizing: border-box;
		margin: 0 0 8px;
	}

	.density_opt {
		flex: 1 1 0;
		justify-content: center;
		min-height: 40px;
		min-width: 0;
		box-sizing: border-box;
	}

	/* Touch has no hover, so the tooltip is unreachable — the words come
	   back. Every clipping property has to be unset, not just `display`. */
	.density_opt_text {
		position: static;
		width: auto;
		height: auto;
		margin: 0;
		overflow: visible;
		clip: auto;
		clip-path: none;
	}

	/* --- Body / content ------------------------------------------------ */

	/* The block + scroll-container treatment is set up at the 1200px
	   breakpoint; here it only needs tighter padding. */
	.body > tbody > tr > td {
		padding: 12px;
	}

	/* --- Forms --------------------------------------------------------- */

	/* Stacking itself is set up at the 1200px breakpoint — a 150px label
	   beside a 330px field needs ~500px, which is already too wide once the
	   columns go full-width. Only the phone-specific bits live here. */

	.form tbody > tr > td.right > textarea {
		min-height: 120px;
	}

	/* iOS zooms the whole page when a focused field is under 16px. */
	input[type="text"],
	input[type="password"],
	input[type="email"],
	input[type="number"],
	input[type="search"],
	input[type="tel"],
	input[type="url"],
	select,
	textarea {
		font-size: 16px;
	}

	input[type="submit"],
	input[type="button"],
	button,
	a.btn {
		min-height: 38px;
	}

	/* --- Page furniture ------------------------------------------------ */

	/* `.page_nav` IS a table. Child combinators again — a data table nested
	   inside a pager cell must keep its own layout. */
	.page_nav,
	.page_nav > tbody,
	.page_nav > tbody > tr,
	.page_nav > tbody > tr > td {
		display: block;
		width: 100%;
		box-sizing: border-box;
	}

	.page_nav > tbody > tr > td.left,
	.page_nav > tbody > tr > td.right {
		text-align: left;
	}

	/* --- Login --------------------------------------------------------- */

	/* `max-width` alone is not enough: a table never shrinks below its
	   min-content width, and `<input size="30">` plus the label column made
	   that ~400px. Stacking the rows is what gets it under 390px. */
	.login,
	.login > tbody,
	.login > tbody > tr,
	.login > tbody > tr > td,
	.login_wrapper,
	.login_wrapper > tbody,
	.login_wrapper > tbody > tr,
	.login_wrapper > tbody > tr > td {
		display: block;
		width: 100%;
		box-sizing: border-box;
	}

	.login {
		max-width: 340px;
		margin: 0 auto;
	}

	.login > tbody > tr > td.left {
		text-align: left;
		padding: 8px 5px 2px;
	}

	.login img {
		max-width: 100%;
		height: auto;
	}

	.login input[type="text"],
	.login input[type="password"] {
		width: 100%;
		box-sizing: border-box;
	}

	.login_wrapper > tbody > tr > td {
		padding: 20px 15px;
	}

}


/* ---------------------------------------------------------------------------
   <= 480px — small phone.
   --------------------------------------------------------------------------- */

@media (max-width: 480px) {

	.header > tbody > tr > td .version {
		display: none;
	}

	.header > tbody > tr > td,
	.body > tbody > tr > td {
		padding: 8px 10px;
	}

	.header > tbody > tr > td img {
		max-height: 34px;
	}

	.table thead td,
	.table tbody td {
		padding: 8px 10px;
	}

	h1 {
		font-size: 18px;
	}

	h3 {
		font-size: 15px;
	}

	#ep_lightbox td #ep_lightbox_container,
	#ep_lightbox td #ep_lightbox_container #ep_lightbox_frame {
		max-width: 100vw;
		max-height: 100vh;
	}

}
