/* =========================================================================
   Sheets (item type 21000) grid styles.

   Layout is a fixed toolbar on top, a single scrollable grid body below,
   and a tab bar on the bottom. Column and row headers are rendered in their
   own flex rails that translate on body scroll so they stay sticky without
   position:sticky (which fights the body scroll container in some browsers).

   Cells are absolutely positioned using cumulative left/top offsets the JS
   maintains, so column/row resize just updates one number and repaints.

   Color palette kept minimal and high-contrast for WCAG AA; dark text on
   light cells, blue accent matches Writing.Com's nav chrome.
   ========================================================================= */

.sh-app {
	font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
	font-size: 13px;
	color: #222;
	background: #fff;
	border: 1px solid #d9dde3;
	border-radius: 6px;
	display: flex;
	flex-direction: column;
	width: 100%;
	max-width: 100%;
	box-sizing: border-box;
	overflow: hidden;
	/* Block native text selection inside the sheet so dragging from a cell
	   doesn't grab paragraphs in the surrounding page. Re-enabled below
	   for surfaces that legitimately need selectable text (status bar,
	   editors, modals). */
	user-select: none;
	-webkit-user-select: none;
}
/* App is tabindex=0 so keyboard handlers receive arrow keys, but the
   browser-default focus ring around the whole sheet reads as a stray
   highlight. Suppress the outline; cell selection already provides a
   clear visual focus indicator. */
.sh-app:focus,
.sh-app:focus-visible { outline: none; }

/* -------------------- Toolbar -------------------- */

.sh-toolbar {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 8px 12px;
	background: #f5f7fa;
	border-bottom: 1px solid #e3e6eb;
	flex-shrink: 0;
	min-height: 40px;
	/* Wrap to a second row when the seven menus + quick actions +
	   presence + save status no longer fit on one line (popout
	   sub-window or narrow main view). Tested fine to ~900px. */
	flex-wrap: wrap;
	row-gap: 6px;
}
.sh-toolbar-btn {
	background: #fff;
	border: 1px solid #cfd4db;
	border-radius: 4px;
	padding: 5px 10px;
	font-size: 12px;
	color: #333;
	cursor: pointer;
	line-height: 1.3;
}
.sh-toolbar-btn:hover { background: #eef2f7; }
.sh-toolbar-btn:focus { outline: 2px solid #4a90d9; outline-offset: 1px; }
.sh-toolbar-btn:disabled { opacity: 0.5; cursor: not-allowed; }
/* Format painter button. The brush glyph is the only content, so font-size
   and line-height are tuned for visual weight rather than reusing the
   .sh-toolbar-btn defaults that target a text label. */
.sh-toolbar-paint-btn {
	font-size: 14px;
	line-height: 1;
	padding: 4px 8px;
	position: relative;   /* anchor for the locked badge below */
}
/* The .sh-icon-btn prefix bumps specificity above the later
   .sh-icon-btn { background: transparent } rule (the paint button is an
   icon-row button). Without it that rule wins on source order and silently
   kills the blue active fill, leaving only the transient focus outline. */
.sh-icon-btn.sh-toolbar-paint-btn--active {
	background: #1a73e8;
	color: #fff;
	border-color: #1a73e8;
}
.sh-icon-btn.sh-toolbar-paint-btn--active:hover { background: #1561c2; border-color: #1561c2; }
/* Locked (sticky) paint: a corner padlock badge, clearly distinct from the
   one-shot blue fill. The fill persists across paints on its own; only the
   focus outline used to vanish on the first paint click, which is why locked
   looked "lost." The badge sits inside the button box so the overflow:hidden
   icon row cannot clip it. */
.sh-toolbar-paint-btn--locked::after {
	content: "";
	position: absolute;
	top: 1px;
	right: 1px;
	width: 13px;
	height: 13px;
	border-radius: 50%;
	background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23202124' d='M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-3 0H9V6c0-1.66 1.34-3 3-3s3 1.34 3 3v2z'/%3E%3C/svg%3E") center / 9px 9px no-repeat;
	box-shadow: 0 0 0 1px rgba(0,0,0,.3);
	pointer-events: none;
}
/* Crosshair on the grid while paint mode is active. Body class is the
   coarsest hook; the highlighted toolbar button is the unambiguous
   on/off indicator. */
body.sh-paint-mode .sh-cells,
body.sh-paint-mode .sh-cell {
	cursor: crosshair;
}
.sh-save-status {
	font-size: 12px;
	color: #888;
	padding: 0 6px;
	min-width: 60px;
	text-align: right;
}
.sh-save-status.saving { color: #b88600; }
.sh-save-status.error  { color: #c0392b; font-weight: 600; }
.sh-save-status.saved  { color: #2e7d32; }

/* Selection status bar under the grid: active-cell address on the left,
   range dims + quick numeric stats on the right. Pure read-out, no
   interactive controls. */
.sh-status-bar {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 6px 10px;
	font-size: 12px;
	color: #556270;
	background: #f4f7fb;
	border-top: 1px solid #d9dde3;
	border-bottom-left-radius: 6px;
	border-bottom-right-radius: 6px;
	user-select: text;
	gap: 16px;
	min-height: 14px;
}
/* display:flex overrides the default [hidden] rule, so we need an explicit
   attr selector to actually hide the bar when the toggle is off. */
.sh-status-bar[hidden] { display: none; }
.sh-status-bar-addr  { font-weight: 600; color: #1a4971; display: flex; align-items: center; flex: 0 0 auto; }

/* Name box: editable cell-address input in the left slot of the status
   bar. Excel-parity navigation: type a cell ref, range, or named range
   and press Enter to jump. View mode looks like the prior plain-text
   address; focus reveals input affordances (border, white background). */
.sh-name-box {
	font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
	font-size: 12px;
	font-weight: 600;
	color: #1a4971;
	background: transparent;
	border: 1px solid transparent;
	border-radius: 3px;
	padding: 1px 6px;
	margin: 0;
	min-width: 80px;
	max-width: 200px;
	height: 22px;
	line-height: 18px;
	-webkit-appearance: none;
	appearance: none;
	outline: none;
	cursor: text;
}
.sh-name-box:hover {
	border-color: #c2d3e4;
}
.sh-name-box:focus {
	background: #ffffff;
	border-color: #4a86c5;
	box-shadow: 0 0 0 2px rgba(74, 134, 197, 0.18);
}
.sh-status-bar-stats {
	color: #556270;
	font-variant-numeric: tabular-nums;
	display: flex;
	gap: 14px;
	align-items: center;
	flex-wrap: wrap;
	justify-content: flex-end;
}
.sh-status-stat { cursor: help; }

/* Formula bar input. Persistent textarea in the status bar that displays
   and edits the active cell's raw value. View mode is readonly + single-
   line (rows=1 + the row-height clamp here); edit mode keeps the same
   single-line look unless the user expands the bar via the resizer (see
   .sh-formula-input--expanded). Long values clip with horizontal scroll
   on focus; nowrap so the bar never grows vertically on its own. */
.sh-formula-input {
	font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
	font-size: 12px;
	line-height: 18px;
	color: #1a4971;
	background: transparent;
	border: 1px solid transparent;
	border-radius: 3px;
	padding: 1px 4px;
	margin: 0;
	flex: 1 1 auto;
	min-width: 0;
	width: 100%;
	height: 22px;
	min-height: 22px;
	max-height: 22px;
	resize: none;
	overflow: hidden;
	white-space: pre;
	cursor: pointer;
	-webkit-appearance: none;
	appearance: none;
	outline: none;
}
.sh-formula-input[readonly] {
	text-overflow: ellipsis;
}
.sh-formula-input:not([readonly]) {
	background: #ffffff;
	border-color: #b4cae0;
	cursor: text;
	overflow: auto;
}
.sh-formula-input:not([readonly]):focus {
	border-color: #4a86c5;
	box-shadow: 0 0 0 2px rgba(74, 134, 197, 0.18);
}
/* Multi-row state: wrap content and allow vertical scroll. JS sets the
   height inline based on the row count; this rule flips wrap and scroll
   behavior so the user actually sees multiple lines. */
.sh-formula-input--multi {
	white-space: pre-wrap;
	overflow-y: auto;
	overflow-x: hidden;
	word-break: break-word;
}

/* Top-edge drag handle for the formula bar. Sits as an absolutely-
   positioned strip above the status bar's content row (the .sh-status-bar
   itself is set position:relative below). Drag up grows the bar, double-
   click toggles. */
.sh-status-bar { position: relative; }
.sh-formula-bar-resize {
	position: absolute;
	top: -3px;
	left: 0;
	right: 0;
	height: 6px;
	cursor: ns-resize;
	background: transparent;
	z-index: 1;
}
.sh-formula-bar-resize:hover,
.sh-formula-bar-resize:focus {
	background: rgba(74, 134, 197, 0.22);
	outline: none;
}
/* While dragging, suppress text selection across the page so the cursor
   ghost doesn't leave a smear. Body class is toggled by the drag handler. */
body.sh-formula-bar-resizing,
body.sh-formula-bar-resizing * {
	cursor: ns-resize !important;
	user-select: none !important;
	-webkit-user-select: none !important;
}
/* Status-bar stats container needs to permit child shrink-to-fit so the
   bar can ellipsis when long. Without min-width:0 the flex item refuses
   to shrink below its content width and overflow never clips. */
.sh-status-bar-stats { min-width: 0; }

/* -------------------- Grid container -------------------- */

.sh-grid-container {
	position: relative;
	flex: 1;
	/* Bound the grid vertically so the body actually overflows. Without a
	   ceiling the container would grow to fit every row and the body
	   would never scroll (only the page would). */
	min-height: 400px;
	height: 70vh;
	max-height: 800px;
	overflow: hidden;
	display: grid;
	/* Extra 12px column / row at the end reserves layout space for the
	   custom scrollbars so they are always visible and never overlap
	   the last cell. */
	grid-template-columns: 44px 1fr 12px;
	grid-template-rows: 24px 1fr 12px;
	background: #fff;
}

/* Tab-switch loading bar. A 3px strip pinned to the very top of the grid
   container, below the tab strip. Hidden by default; init.js's load path
   adds .sh-app--loading to the app element while a tab's cells are
   fetching, which fades the bar in and runs the slide animation so the
   user sees that their click was received. The 150ms show-delay in JS
   keeps fast / cached loads from flashing it. position:absolute over the
   grid (which is overflow:hidden) so it sits above the corner / headers
   without taking layout space. */
.sh-loading-bar {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	height: 3px;
	pointer-events: none;
	z-index: 50;
	overflow: hidden;
	opacity: 0;
	transition: opacity 120ms ease-out;
	background: rgba(33, 150, 243, 0.12);
}
.sh-loading-bar::before {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	width: 30%;
	background: linear-gradient(90deg, transparent, #2196f3 20%, #2196f3 80%, transparent);
	transform: translateX(-100%);
	animation: sh-loading-slide 1.1s ease-in-out infinite;
}
.sh-app--loading .sh-loading-bar { opacity: 1; }
@keyframes sh-loading-slide {
	0%   { transform: translateX(-100%); }
	100% { transform: translateX(400%); }
}

/* -------------------- Popout (Fullscreen window) -------------------- */
/* When the sheet is rendered in /pop/1 mode, the .sh-app--popout class
   on #sheets-app makes the grid fill the entire window. The browser
   chrome is the only frame; toolbar pins to the top, tab bar to the
   bottom (via flex), grid stretches in the middle. Removes the rounded
   border that's appropriate for an in-page widget but looks odd when
   the sheet IS the window. */
.sh-app--popout {
	height: 100vh;
	max-height: 100vh;
	border: none;
	border-radius: 0;
}
.sh-app--popout .sh-grid-container {
	height: auto;
	max-height: none;
	flex: 1 1 auto;
	min-height: 0;
}

.sh-corner {
	grid-column: 1;
	grid-row: 1;
	background: #eef2f7;
	border-right: 1px solid #d9dde3;
	border-bottom: 1px solid #d9dde3;
	z-index: 3;
	cursor: pointer;
}
.sh-corner:hover        { background: #e2e8f0; }
.sh-corner:focus-visible { outline: 2px solid #1a73e8; outline-offset: -2px; }

.sh-col-headers {
	grid-column: 2;
	grid-row: 1;
	overflow: hidden;
	background: #eef2f7;
	border-bottom: 1px solid #d9dde3;
	position: relative;
}
.sh-col-headers-inner {
	position: relative;
	height: 24px;
	will-change: transform;
}
.sh-col-header {
	position: absolute;
	top: 0;
	height: 24px;
	line-height: 24px;
	text-align: center;
	font-size: calc(11px * var(--sh-zoom, 1));
	font-weight: 600;
	color: #555;
	border-right: 1px solid #d9dde3;
	box-sizing: border-box;
	user-select: none;
	cursor: pointer;
}
.sh-col-header:hover  { background: #e2e8f0; color: #1a4971; }
.sh-col-header.active { background: #d6e4f3; color: #1a4971; }

/* Phase 3b: filter chevron embedded in the column header. Sits at the right
   edge so the column letter stays centered. The button is small (16x16) so
   narrow columns still show their label without it overlapping. */
.sh-col-filter-btn {
	position: absolute;
	right: 4px;
	top: 50%;
	transform: translateY(-50%);
	width: 16px;
	height: 16px;
	padding: 0;
	border: 1px solid transparent;
	background: transparent;
	color: #5f6368;
	font-size: 11px;
	line-height: 14px;
	cursor: pointer;
	border-radius: 3px;
}
.sh-col-filter-btn:hover,
.sh-col-filter-btn:focus {
	background: #fff;
	border-color: #b0c4de;
	color: #1a4971;
	outline: none;
}
.sh-col-filter-btn--active {
	background: #1a73e8;
	color: #fff;
	border-color: #1a73e8;
}
.sh-col-filter-btn--active:hover,
.sh-col-filter-btn--active:focus {
	background: #1659b6;
	color: #fff;
	border-color: #1659b6;
}

/* Filter dropdown popup: lifts above the existing menu z-index and gives
   the value checklist its own scroll region. */
.sh-filter-dropdown {
	padding: 0;
	min-width: 220px;
	max-width: 320px;
	display: flex;
	flex-direction: column;
	gap: 0;
}
.sh-filter-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 8px 10px;
	border-bottom: 1px solid #e5e9ef;
}
.sh-filter-title {
	font-weight: 600;
	font-size: 13px;
}
.sh-filter-actions {
	display: inline-flex;
	gap: 6px;
}
.sh-filter-action {
	background: transparent;
	border: none;
	padding: 2px 6px;
	font-size: 12px;
	color: #1a73e8;
	cursor: pointer;
	border-radius: 3px;
}
.sh-filter-action:hover { background: #eef3fa; }
.sh-filter-search {
	margin: 8px 10px 4px 10px;
	padding: 5px 8px;
	border: 1px solid #cfd4db;
	border-radius: 4px;
	font-size: 13px;
}
.sh-filter-list {
	max-height: 220px;
	overflow-y: auto;
	padding: 4px 6px;
	margin-bottom: 4px;
}
.sh-filter-item {
	display: flex;
	align-items: center;
	gap: 6px;
	padding: 4px 4px;
	border-radius: 3px;
	cursor: pointer;
	font-weight: normal;
	font-size: 13px;
	color: #222;
}
.sh-filter-item:hover { background: #eef3fa; }
.sh-filter-item-label {
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.sh-filter-buttons {
	display: flex;
	justify-content: flex-end;
	gap: 6px;
	padding: 8px 10px;
	border-top: 1px solid #e5e9ef;
}
.sh-filter-btn {
	padding: 5px 12px;
	border: 1px solid #cfd4db;
	border-radius: 4px;
	background: #fff;
	font-size: 13px;
	cursor: pointer;
}
.sh-filter-btn:hover { background: #f3f4f6; }
.sh-filter-btn.primary {
	background: #1a73e8;
	border-color: #1a73e8;
	color: #fff;
}
.sh-filter-btn.primary:hover { background: #1659b6; border-color: #1659b6; }

/* -------------------- Phase 4: Rules panel (CF + DV) ----------------- */

.sh-rules-panel {
	max-width: 720px;
	width: calc(100vw - 64px);
	max-height: calc(100vh - 80px);
	overflow-y: auto;
}
.sh-rules-list {
	display: flex;
	flex-direction: column;
	gap: 12px;
	margin-top: 8px;
}
.sh-rules-empty {
	padding: 24px;
	text-align: center;
	color: #6b7280;
	font-size: 13px;
	border: 1px dashed #d0d4d9;
	border-radius: 6px;
}
.sh-rule-card {
	border: 1px solid #d9dde3;
	border-radius: 6px;
	padding: 10px 12px;
	background: #fff;
	display: flex;
	flex-direction: column;
	gap: 8px;
}
.sh-rule-card-head {
	display: flex;
	align-items: center;
	gap: 6px;
}
.sh-rule-reorder,
.sh-rule-remove {
	border: 1px solid #cfd4db;
	background: #fff;
	width: 24px;
	height: 24px;
	border-radius: 4px;
	cursor: pointer;
	font-size: 12px;
	line-height: 1;
	color: #374151;
	padding: 0;
}
.sh-rule-reorder:hover:not(:disabled),
.sh-rule-remove:hover { background: #f3f4f6; border-color: #b0c4de; }
.sh-rule-reorder:disabled { opacity: 0.4; cursor: default; }
.sh-rule-remove { margin-left: auto; color: #b91c1c; }

.sh-rule-range-chip {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	flex: 1 1 auto;
	flex-wrap: wrap;
}
.sh-rule-range-label {
	font-size: 13px;
	color: #5f6368;
	font-weight: 500;
}
.sh-rule-range-input {
	font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
	font-size: 12px;
	padding: 4px 8px;
	border: 1px solid #cfd4db;
	border-radius: 4px;
	min-width: 100px;
	background: #fff;
}
.sh-rule-range-input--bad {
	border-color: #ef4444;
	background: #fee2e2;
}
.sh-rule-range-pick {
	border: 1px solid #cfd4db;
	background: #fff;
	padding: 4px 10px;
	border-radius: 4px;
	font-size: 12px;
	cursor: pointer;
	color: #374151;
}
.sh-rule-range-pick:hover { background: #eef3fa; border-color: #b0c4de; }

.sh-rule-condition,
.sh-rule-enforcement {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 8px;
}
.sh-rule-condition-prefix {
	font-size: 13px;
	color: #5f6368;
	font-weight: 500;
}
.sh-rule-condition-type {
	padding: 5px 8px;
	border: 1px solid #cfd4db;
	border-radius: 4px;
	font-size: 13px;
}
.sh-rule-inputs {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 8px;
}
.sh-rule-input {
	padding: 5px 8px;
	border: 1px solid #cfd4db;
	border-radius: 4px;
	font-size: 13px;
	min-width: 120px;
}
.sh-rule-input--wide {
	flex: 1 1 240px;
	min-width: 200px;
}
.sh-rule-input--mono {
	font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
	font-size: 13px;
}
.sh-rule-note {
	flex: 1 1 100%;
	margin: 6px 0 0 0;
	font-size: 11px;
	color: #5f6368;
	line-height: 1.4;
	background: #f3f4f6;
	border-left: 3px solid #b0c4de;
	padding: 6px 10px;
	border-radius: 0 4px 4px 0;
}
textarea.sh-rule-input {
	font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
	resize: vertical;
}
.sh-rule-input-sep {
	color: #6b7280;
	font-size: 12px;
}
.sh-rule-case,
.sh-rule-checkbox {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	font-size: 13px;
	color: #374151;
	cursor: pointer;
	font-weight: normal;
}

.sh-rule-format-row {
	display: flex;
	align-items: center;
	gap: 10px;
}
.sh-rule-format-label {
	font-size: 13px;
	color: #5f6368;
	font-weight: 500;
}
.sh-rule-format-preview {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 32px;
	height: 22px;
	padding: 0 8px;
	border: 1px solid #cfd4db;
	border-radius: 4px;
	font-size: 12px;
	background: #fff;
}
.sh-rule-format-btn {
	background: transparent;
	border: 1px solid #cfd4db;
	border-radius: 4px;
	padding: 4px 10px;
	font-size: 12px;
	cursor: pointer;
	color: #374151;
}
.sh-rule-format-btn:hover { background: #eef3fa; }

.sh-rule-format-panel {
	display: flex;
	flex-direction: column;
	gap: 8px;
	padding: 8px 10px;
	background: #f9fafb;
	border: 1px solid #e5e9ef;
	border-radius: 4px;
}
.sh-rule-checks-row {
	display: flex;
	flex-wrap: wrap;
	gap: 14px;
}
.sh-rule-swatch-row {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 6px;
}
.sh-rule-swatch-label {
	font-size: 12px;
	color: #5f6368;
	min-width: 40px;
}
.sh-rule-add-btn {
	margin-top: 12px;
	padding: 8px 14px;
	background: #fff;
	border: 1px dashed #b0c4de;
	border-radius: 6px;
	color: #1a73e8;
	font-size: 13px;
	cursor: pointer;
}
.sh-rule-add-btn:hover {
	background: #eef3fa;
	border-color: #1a73e8;
}

/* -------------------- Help panel ------------------------------------- */

/* Double class beats the base .sh-modal rule, which is declared LATER in
   this file and would otherwise win the tie and clamp the panel to its
   640px max-width (and re-apply its 20/24 padding). */
.sh-modal.sh-help-panel {
	width: min(1200px, 94vw);
	max-width: min(1200px, 94vw);
	min-width: 0; /* .sh-modal's 420px floor overflows small viewports */
	height: min(720px, 88vh);
	max-height: min(720px, 88vh);
	padding: 0;
	display: flex;
	flex-direction: column;
}
.sh-help-head {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 14px 18px;
	border-bottom: 1px solid #e5e9ef;
	flex: 0 0 auto;
}
.sh-help-head h3 {
	margin: 0;
	font-size: 18px;
	font-weight: 600;
	color: #1a4971;
}
.sh-help-search {
	flex: 1 1 auto;
	max-width: 320px;
	margin-left: auto;
	padding: 6px 10px;
	border: 1px solid #cfd4db;
	border-radius: 4px;
	font-size: 13px;
}
.sh-help-close {
	width: 28px;
	height: 28px;
	border: 1px solid #cfd4db;
	background: #fff;
	border-radius: 4px;
	cursor: pointer;
	color: #374151;
	font-size: 13px;
	line-height: 1;
}
.sh-help-close:hover { background: #f3f4f6; }
.sh-help-body {
	display: flex;
	flex: 1 1 auto;
	min-height: 0; /* allow children to scroll inside flex */
}
.sh-help-sidebar {
	flex: 0 0 200px;
	border-right: 1px solid #e5e9ef;
	overflow-y: auto;
	padding: 8px 0;
	background: #fafbfc;
}
.sh-help-section-btn {
	display: block;
	width: 100%;
	text-align: left;
	background: transparent;
	border: none;
	padding: 8px 18px;
	font-size: 13px;
	color: #374151;
	cursor: pointer;
	border-left: 3px solid transparent;
}
.sh-help-section-btn:hover { background: #eef3fa; }
.sh-help-section-btn--active {
	background: #fff;
	border-left-color: #1a73e8;
	color: #1a4971;
	font-weight: 600;
}
.sh-help-section-btn--dim {
	opacity: 0.4;
}
.sh-help-content {
	flex: 1 1 auto;
	overflow-y: auto;
	padding: 16px 22px;
	min-width: 0;
}
.sh-help-content-title {
	margin: 0 0 12px 0;
	font-size: 16px;
	font-weight: 600;
	color: #1a4971;
}
.sh-help-prose {
	font-size: 13px;
	line-height: 1.6;
	color: #374151;
}
.sh-help-prose h4 {
	margin: 18px 0 6px 0;
	font-size: 14px;
	color: #1a4971;
}
.sh-help-prose ul {
	padding-left: 20px;
	margin: 6px 0;
}
.sh-help-prose li { margin: 3px 0; }
.sh-help-prose code,
.sh-help-prose kbd {
	font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
	font-size: 12px;
	background: #f3f4f6;
	border: 1px solid #e5e9ef;
	border-radius: 3px;
	padding: 1px 5px;
}
.sh-help-prose kbd {
	background: #fff;
	box-shadow: 0 1px 0 #cfd4db;
}
.sh-help-prose p { margin: 8px 0; }
.sh-help-prose b { color: #1a4971; }
.sh-help-empty {
	color: #6b7280;
	font-style: italic;
	font-size: 13px;
	margin: 8px 0;
}

/* Formula reference grid */
.sh-help-formula-cat {
	margin: 16px 0 6px 0;
	font-size: 13px;
	color: #1a4971;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	font-weight: 600;
}
.sh-help-formula-grid {
	display: grid;
	grid-template-columns: minmax(180px, 1fr) minmax(220px, 2fr) minmax(160px, 1fr);
	gap: 1px;
	background: #e5e9ef;
	border: 1px solid #e5e9ef;
	border-radius: 4px;
	/* auto, not hidden: if the column minimums ever outgrow the panel
	   (odd zoom combos), scroll instead of silently clipping text. */
	overflow-x: auto;
	margin-bottom: 4px;
}
.sh-help-formula-head {
	display: contents;
}
.sh-help-formula-head > span {
	background: #f3f4f6;
	padding: 6px 10px;
	font-size: 11px;
	font-weight: 600;
	color: #5f6368;
	text-transform: uppercase;
	letter-spacing: 0.04em;
}
.sh-help-formula-row {
	display: contents;
}
.sh-help-formula-row > * {
	background: #fff;
	padding: 8px 10px;
	font-size: 12px;
	line-height: 1.5;
}
.sh-help-formula-sig {
	font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
	color: #1a4971;
	white-space: pre-wrap;
}
.sh-help-formula-desc {
	color: #374151;
}
.sh-help-formula-ex {
	font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
	color: #15803d;
	white-space: pre-wrap;
}

/* Shortcuts table */
.sh-help-shortcuts {
	width: 100%;
	border-collapse: collapse;
	font-size: 13px;
	margin-top: 6px;
}
.sh-help-shortcuts th,
.sh-help-shortcuts td {
	padding: 6px 10px;
	border-bottom: 1px solid #e5e9ef;
	text-align: left;
	vertical-align: top;
}
.sh-help-shortcuts th {
	background: #f3f4f6;
	color: #5f6368;
	font-size: 11px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.04em;
}
.sh-help-shortcuts tbody tr:hover { background: #fafbfc; }

/* Narrow effective viewports (small windows, high OS display scaling or
   browser zoom): the three-column formula reference cannot fit next to
   the 200px sidebar and used to clip mid-word at the panel edge (member
   report, 2026-07). Stack each formula (name, description, example)
   vertically and slim the sidebar instead. */
@media (max-width: 900px) {
	.sh-modal.sh-help-panel {
		width: 96vw;
		max-width: 96vw;
	}
	.sh-help-sidebar { flex-basis: 148px; }
	.sh-help-content { padding: 14px 16px; }
	.sh-help-formula-head { display: none; }
	.sh-help-formula-grid { grid-template-columns: 1fr; }
	/* Function name doubles as the row header once columns stack. */
	.sh-help-formula-sig { background: #f3f4f6; }
}

/* DV cell-level affordances ------------------------------------------- */

/* Red triangle in the top-right corner for cells violating a warn-mode
   rule. Pointer-events:none so it doesn't intercept clicks; the cell's
   data-wdc-tooltip carries the reason. */
.sh-cell-dv-chip {
	position: absolute;
	top: 0;
	right: 0;
	width: 0;
	height: 0;
	border-style: solid;
	border-width: 0 8px 8px 0;
	border-color: transparent #d0021b transparent transparent;
	pointer-events: none;
	z-index: 1;
}

/* Dropdown chevron at the right edge of the active cell when it has a
   list-validation rule. Sized to fit inside slim cells without clipping. */
.sh-cell-dv-btn {
	position: absolute;
	top: 50%;
	right: 2px;
	transform: translateY(-50%);
	width: 18px;
	height: 18px;
	padding: 0;
	border: 1px solid #b0c4de;
	background: #fff;
	color: #1a4971;
	font-size: 11px;
	line-height: 14px;
	cursor: pointer;
	border-radius: 3px;
	z-index: 2;
}
.sh-cell-dv-btn:hover {
	background: #1a73e8;
	color: #fff;
	border-color: #1a73e8;
}

/* Cell comments / notes ------------------------------------------------- */

/* Reserve a bit of right padding on commented cells so the text doesn't
   slide under the corner triangle. Right-aligned numbers and short
   headers would clip otherwise. */
.sh-cell.sh-has-comment .sh-cell-content {
	padding-right: 10px;
}

/* Orange triangle in the top-right corner. Larger hit area via the
   ::before pseudo so it remains tappable on touch without making the
   visible triangle obnoxiously big. pointer-events:auto so hover and
   click reach the indicator (cells default to pointer-events normal). */
.sh-cell-comment-indicator {
	position: absolute;
	top: 0;
	right: 0;
	width: 0;
	height: 0;
	border-style: solid;
	border-width: 0 8px 8px 0;
	border-color: transparent #e8a13d transparent transparent;
	pointer-events: auto;
	cursor: pointer;
	z-index: 3;
}
.sh-cell-comment-indicator::before {
	content: "";
	position: absolute;
	top: -2px;
	right: -8px;
	width: 14px;
	height: 14px;
}

/* Hover popover. Singleton appended to document.body so it escapes the
   3-column site stacking context. Max-width keeps long comments from
   running off-screen; pre-wrap preserves user-entered newlines. */
#sh-comment-hover {
	position: fixed;
	z-index: 2147483647;
	background: #fff;
	border: 1px solid #aaa;
	border-radius: 3px;
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
	padding: 6px 8px;
	max-width: 280px;
	font-size: 12px;
	line-height: 1.4;
	color: #222;
	pointer-events: auto;
}
#sh-comment-hover .sh-cmt-hdr {
	font-weight: 600;
	margin-bottom: 4px;
	color: #555;
}
#sh-comment-hover .sh-cmt-body {
	white-space: pre-wrap;
	word-wrap: break-word;
}
#sh-comment-hover .sh-cmt-popover-edit {
	display: block;
	margin-top: 6px;
	padding: 3px 10px;
	background: #1a73e8;
	color: #fff;
	border: 1px solid #1a73e8;
	border-radius: 3px;
	font-size: 12px;
	cursor: pointer;
}
#sh-comment-hover .sh-cmt-popover-edit:hover {
	background: #1558b0;
	border-color: #1558b0;
}

/* Inline editor. Anchored to the cell (via getBoundingClientRect on
   S.cellEls[key]) so it follows the cell across freeze panes. */
.sh-comment-editor {
	position: fixed;
	z-index: 2147483647;
	background: #fff;
	border: 1px solid #888;
	border-radius: 4px;
	box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
	padding: 8px;
	width: 280px;
}
.sh-comment-editor .sh-cmt-edit-hdr {
	font-size: 11px;
	color: #555;
	margin-bottom: 4px;
}
.sh-comment-editor .sh-cmt-edit-ta {
	width: 100%;
	box-sizing: border-box;
	min-height: 60px;
	max-height: 200px;
	resize: vertical;
	font-family: inherit;
	font-size: 13px;
	padding: 4px 6px;
	border: 1px solid #ccc;
	border-radius: 3px;
}
.sh-comment-editor .sh-cmt-btns {
	margin-top: 6px;
	display: flex;
	gap: 6px;
	align-items: center;
}
.sh-comment-editor .sh-cmt-save,
.sh-comment-editor .sh-cmt-cancel,
.sh-comment-editor .sh-cmt-del {
	padding: 4px 12px;
	font-size: 12px;
	border-radius: 3px;
	cursor: pointer;
	border: 1px solid;
}
.sh-comment-editor .sh-cmt-save {
	background: #1a73e8;
	color: #fff;
	border-color: #1a73e8;
}
.sh-comment-editor .sh-cmt-save:hover {
	background: #1558b0;
	border-color: #1558b0;
}
.sh-comment-editor .sh-cmt-cancel {
	background: #fff;
	color: #333;
	border-color: #b0b0b0;
}
.sh-comment-editor .sh-cmt-cancel:hover {
	background: #f3f3f3;
}
.sh-comment-editor .sh-cmt-del {
	margin-left: auto;
	background: #fff;
	color: #b00020;
	border-color: #d0a0a0;
}
.sh-comment-editor .sh-cmt-del:hover {
	background: #fdecea;
	border-color: #b00020;
}

.sh-col-resize {
	position: absolute;
	top: 0;
	width: 6px;
	height: 24px;
	cursor: col-resize;
	z-index: 2;
}
.sh-col-resize:hover,
.sh-col-resize.dragging { background: #4a90d9; }

.sh-row-headers {
	grid-column: 1;
	grid-row: 2;
	overflow: hidden;
	background: #eef2f7;
	border-right: 1px solid #d9dde3;
	position: relative;
}
.sh-row-headers-inner {
	position: relative;
	width: 44px;
	will-change: transform;
}
.sh-row-header {
	position: absolute;
	left: 0;
	width: 44px;
	line-height: 1;
	text-align: center;
	font-size: calc(11px * var(--sh-zoom, 1));
	font-weight: 600;
	color: #555;
	border-bottom: 1px solid #d9dde3;
	box-sizing: border-box;
	user-select: none;
	cursor: pointer;
	padding-top: 4px;
}
.sh-row-header:hover  { background: #e2e8f0; color: #1a4971; }
.sh-row-header.active { background: #d6e4f3; color: #1a4971; }

.sh-row-resize {
	position: absolute;
	left: 0;
	width: 44px;
	height: 6px;
	cursor: row-resize;
	z-index: 2;
}
.sh-row-resize:hover,
.sh-row-resize.dragging { background: #4a90d9; }

/* Phase 9C: frozen headers need an opaque background and a higher stacking
   order than their non-frozen siblings so that, when the main strip
   translates on scroll, non-frozen headers sliding past the freeze
   boundary are visually clipped behind the pinned ones. Hover / active
   states still need to win when the pointer is over a frozen header, so
   give them matching attr selectors to raise their specificity. */
.sh-col-header[data-frozen="1"],
.sh-row-header[data-frozen="1"] {
	background: #eef2f7;
	z-index: 3;
}
.sh-col-header[data-frozen="1"]:hover,
.sh-row-header[data-frozen="1"]:hover { background: #e2e8f0; color: #1a4971; }
.sh-col-header[data-frozen="1"].active,
.sh-row-header[data-frozen="1"].active { background: #d6e4f3; color: #1a4971; }
.sh-col-resize[data-frozen="1"],
.sh-row-resize[data-frozen="1"] { z-index: 3; }

/* Marker on the row/col header right before a hidden index. A 4px solid
   slate edge (passes 3:1 contrast against the default header background)
   tells the user that something is hidden between this and the next
   visible row/col, so they can right-click to "Unhide rows in selection"
   or "Show all hidden rows". Deliberately NOT selection-blue (#1a73e8): a
   blue edge here reads as a stray selection border, so use a neutral slate
   that signals "structural boundary" instead. */
.sh-col-header[data-hidden-after="true"] { border-right:  4px solid #5f6368; }
.sh-row-header[data-hidden-after="true"] { border-bottom: 4px solid #5f6368; }

/* Body: the scrollable viewport. Native scrollbars are hidden entirely
   (Chrome on macOS tends to render overlay even with custom ::-webkit
   styling); the custom scrollbars below live in their own grid cells
   and are always visible. */
.sh-body {
	grid-column: 2;
	grid-row: 2;
	overflow: scroll;
	position: relative;
	background: #fff;
	scrollbar-width: none;       /* Firefox */
	-ms-overflow-style: none;    /* Old Edge/IE */
}
.sh-body::-webkit-scrollbar { width: 0; height: 0; display: none; }

/* ---- Custom scrollbars ---- */
.sh-scrollbar-v, .sh-scrollbar-h {
	position: relative;
	background: #f5f7fa;
	overflow: hidden;
	z-index: 3;
	user-select: none;
}
.sh-scrollbar-v {
	grid-column: 3;
	grid-row: 2;
	border-left: 1px solid #e3e6eb;
}
.sh-scrollbar-h {
	grid-column: 2;
	grid-row: 3;
	border-top: 1px solid #e3e6eb;
}
.sh-scrollbar-corner {
	grid-column: 3;
	grid-row: 3;
	background: #f5f7fa;
	border-top: 1px solid #e3e6eb;
	border-left: 1px solid #e3e6eb;
	z-index: 3;
}
/* Filler squares at (row 1, col 3) and (row 3, col 1) so the strip
   colors read continuously across the grid chrome. */
.sh-corner-tr {
	grid-column: 3;
	grid-row: 1;
	background: #eef2f7;
	border-bottom: 1px solid #d9dde3;
	border-left:   1px solid #d9dde3;
}
.sh-corner-bl {
	grid-column: 1;
	grid-row: 3;
	background: #eef2f7;
	border-top:   1px solid #d9dde3;
	border-right: 1px solid #d9dde3;
}

.sh-scrollbar-thumb {
	position: absolute;
	background: #bfc5cf;
	border-radius: 4px;
	cursor: pointer;
}
.sh-scrollbar-thumb:hover,
.sh-scrollbar-thumb.dragging {
	background: #8f96a1;
}
.sh-scrollbar-v .sh-scrollbar-thumb {
	left: 2px;
	right: 2px;
	min-height: 24px;
}
.sh-scrollbar-h .sh-scrollbar-thumb {
	top: 2px;
	bottom: 2px;
	min-width: 24px;
}
.sh-body-inner {
	position: relative;
	will-change: transform;
}

/* Grid lines layer: one thin div per row + column divider, absolutely
   positioned. Sits behind cells so a rendered cell covers its own borders
   cleanly; shows through where cells are absent. */
.sh-grid-lines { pointer-events: none; }
.sh-grid-line-h,
.sh-grid-line-v {
	position: absolute;
	background: #eceff3;
	pointer-events: none;
}
.sh-grid-line-h { left: 0; height: 1px; }
.sh-grid-line-v { top: 0;  width: 1px; }

.sh-cell {
	position: absolute;
	box-sizing: border-box;
	border-right: 1px solid #eceff3;
	border-bottom: 1px solid #eceff3;
	padding: calc(3px * var(--sh-zoom, 1)) calc(6px * var(--sh-zoom, 1));
	font-size: calc(13px * var(--sh-zoom, 1));
	line-height: calc(18px * var(--sh-zoom, 1));
	color: #222;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
	cursor: cell;
	background: #fff;
}
.sh-cell.empty { color: transparent; }

/* CF empty-cell overlay: fill-only, pointer-inert divs painted for empty
   positions matched by a conditional-formatting rule (renderCFEmptyOverlay,
   render.js). Mirrors .sh-cell's gridline-separator borders so a filled
   empty region keeps per-cell separators instead of rendering as one slab;
   background color is set inline from the matched rule's fill. */
.sh-cf-empty {
	position: absolute;
	box-sizing: border-box;
	border-right: 1px solid #eceff3;
	border-bottom: 1px solid #eceff3;
	pointer-events: none;
}

/* Merged cells: span the merge bbox (width/height set inline by render.js).
   Default .sh-cell already has solid bg + borders that hide gridlines
   underneath, so no z-index lift is needed - lifting it above siblings
   would cover the selection rectangle. Hook left for future styling. */
.sh-cell[data-merged="true"] {
	background: #fff;
}

/* Spill cells (non-origin members of a SORT / UNIQUE / FILTER / SORTBY /
   SEQUENCE result range) get a subtle background tint so users can see
   they're derived. Editing is blocked separately by the JS guard;
   cursor:not-allowed makes the affordance match. */
.sh-cell[data-spill="1"] {
	background: #fafcff;
	cursor: not-allowed;
}
.sh-cell[data-spill="1"]:hover {
	background: #f3f7fd;
}

/* Text wrap: opt-in via style.wrap. Overrides the default nowrap+ellipsis
   so long values break across lines within the cell (or merged cell) width.
   Cell height does not auto-grow; tall content clips at the bottom edge. */
.sh-cell--wrap {
	white-space: normal;
	overflow-wrap: break-word;
	word-break: break-word;
	text-overflow: clip;
	/* Font-relative line-height so wrapped lines scale with the cell's font
	   size. The base .sh-cell pins line-height to a fixed 18px for single-line
	   row rhythm; at large font sizes that fixed value sits far below the
	   glyphs, so multi-line wrapped text overlaps (reported at 36pt). Unitless,
	   so it multiplies the cell's own font-size. 1.35 matches the 18px/13px
	   ratio of the default size, so default-size cells are visually unchanged. */
	line-height: 1.35;
}
/* The inner .sh-cell-content span carries an explicit white-space:nowrap
   so its rule wins over the outer .sh-cell--wrap above (specificity equal,
   but the inner declaration is set on the element where the text lives).
   Mirror the wrap properties onto the inner span when the cell is wrapped,
   and let it span the cell width so the wrap actually happens at the cell
   edge rather than at the content's natural width. */
.sh-cell--wrap .sh-cell-content {
	white-space: normal;
	overflow-wrap: break-word;
	word-break: break-word;
	max-width: 100%;
}

/* Cell content wrapper. Always present (renderCell wraps content in this
   span). Acts as:
   - the rotation target (transform applied here, not on the cell div)
   - the single flex item when the cell is flex-laid-out for vertical
     alignment, so cell align-items lands in one place
   - the host for inline WritingML, which flows naturally inside the span
     regardless of whether the parent cell is flex.
   Rotation pivots around the wrapper's own center; cell text-align
   (default block layout) or justify-content (flex layout) positions the
   wrapper horizontally. */
.sh-cell-content {
	display: inline-block;
	transform-origin: center center;
	white-space: nowrap;
}

/* Vertical (stacked) rotation uses writing-mode rather than transform so
   each character renders upright in a top-to-bottom column. Distinct from
   the 90° / -90° rotations which lay text on its side. */
.sh-cell--rot-vertical .sh-cell-content {
	writing-mode: vertical-lr;
	text-orientation: upright;
	transform: none;
}

/* Slanted cells (textRotation ±45): the cell box becomes a parallelogram
   whose left and right edges are parallel to the rotated text's reading
   axis. Skew matches the text rotation so adjacent cells in the same
   row share their slanted edges (no gap, no overlap) and the row reads
   as one continuous slanted band. transform-origin at bottom-left keeps
   the row's bottom edge on the column boundaries; only the top half of
   the cell shifts horizontally. The content's counter-skew on top of the
   rotation cancels the parent skew exactly so the text appears purely
   rotated, not sheared. Native CSS borders skew with the box, so the
   left/right edges paint as slanted lines automatically.
   z-index lifts the slanted cell (its rotated text included) above the slant
   cutoff triangles (.sh-slant-triangle, z 1). Those triangles are painted from
   a neighbor's fill to blend the band and, being h-by-h, reach back across this
   cell's rotated text; without the lift a filled neighbor's triangle paints
   over the text (reported bug: a green slanted header band clipped its own
   labels down to the first glyph). Stays below the selection rect (z 4 / 10)
   and the cell editor (z 5), so the marquee and inline editing still show. */
.sh-cell--slanted-pos {              /* textRotation = +45 */
	transform: skewX(-45deg);
	transform-origin: 0 100%;
	z-index: 2;
}
.sh-cell--slanted-neg {              /* textRotation = -45 */
	transform: skewX(45deg);
	transform-origin: 0 100%;
	z-index: 2;
}
.sh-cell--slanted-pos .sh-cell-content { transform: skewX(45deg) rotate(-45deg); }
.sh-cell--slanted-neg .sh-cell-content { transform: skewX(-45deg) rotate(45deg); }

/* Slanted + vertical-align: pin the content's transform-origin so the rotated
   line box falls INTO the visible parallelogram instead of swinging across a
   slant edge (overflow clip follows the cell's skew, so the visible region IS
   the parallelogram). Transform origins cannot shear the text: the composed
   linear part stays a pure +/-45 rotation for any origin (origins contribute
   translation only); the origin just chooses WHERE the text lands. The origin
   point is a fixed point of the skew/rotate pair, so flex seats it on a cell
   edge and the cell skew carries it to the parallelogram corner. The pinned
   corner must be on the side FACING the near slant edge (the span's long edges
   run parallel to the slant edges after rotation), which is why bottom-valign
   pins a TOP span corner and vice versa. valign=middle keeps the centered
   default. Without these, a bottom-aligned 45-degree header clipped the start
   of the word off the bottom of the cell.
   The leading translateY is an ALONG-RUN nudge: the corner pin leaves
   (1 - 1/sqrt(2)) ~ 29.29% of the span height as slack between the rotated
   box and the cell's top/bottom edge. The cell's skew maps a vertical offset
   to a pure diagonal slide (zero change in slant-edge distance, both slant
   signs), so the percentage drops bottom-valigned text flush onto the bottom
   edge (and lifts top-valigned text to the top) while auto-scaling with
   font/zoom. These rules MUST come before the editing escape below: they tie
   it on specificity, so the escape's transform:none must win on source order
   while editing. */
.sh-cell--slanted-pos[data-valign="bottom"] .sh-cell-content {
	transform-origin: 0 0;
	transform: translateY(29.29%) skewX(45deg) rotate(-45deg);
}
.sh-cell--slanted-pos[data-valign="top"] .sh-cell-content {
	transform-origin: 100% 100%;
	transform: translateY(-29.29%) skewX(45deg) rotate(-45deg);
}
.sh-cell--slanted-neg[data-valign="bottom"] .sh-cell-content {
	transform-origin: 100% 0;
	transform: translateY(29.29%) skewX(-45deg) rotate(45deg);
}
.sh-cell--slanted-neg[data-valign="top"] .sh-cell-content {
	transform-origin: 0 100%;
	transform: translateY(-29.29%) skewX(-45deg) rotate(45deg);
}
/* Force the horizontal seat to match each pin. LOAD-BEARING GEOMETRY: the
   pin's depth into the slant channel equals its LAYOUT X (the skew turns
   horizontal position into perpendicular slant distance), so a left-corner pin
   is only inside the parallelogram when the span is seated left, and a right
   pin when seated right. A centered seat puts the pin at (W - textWidth)/2,
   which goes NEGATIVE when the label is wider than the column -- the pin lands
   outside the slant edge and the run, being parallel to that edge, shaves the
   top of every glyph (real-world break: narrow columns + Align center).
   !important so the seat beats the inline justify-content render.js writes for
   the user's horizontal align: for slanted+valigned cells the anchor IS the
   geometry; align still applies to valign=middle and unrotated cells. */
.sh-cell--slanted-pos[data-valign="bottom"],
.sh-cell--slanted-neg[data-valign="top"]    { justify-content: flex-start !important; }
.sh-cell--slanted-pos[data-valign="top"],
.sh-cell--slanted-neg[data-valign="bottom"] { justify-content: flex-end !important; }

/* Disable the skew while the cell is being edited so the textarea / v3
   editor renders upright, the cursor lands where the user clicks, and
   typing isn't visually sheared. Restored as soon as editing commits.
   Source order matters: the valign pin rules above tie this on specificity,
   so this block must stay AFTER them for transform:none to win mid-edit. */
.sh-cell--slanted-pos.sh-cell--editing,
.sh-cell--slanted-neg.sh-cell--editing { transform: none; }
.sh-cell--slanted-pos.sh-cell--editing .sh-cell-content,
.sh-cell--slanted-neg.sh-cell--editing .sh-cell-content { transform: none; }

/* 90 / -90 rotation: lay the text on its side with writing-mode rather than a
   transform. writing-mode sizes the layout box to the vertical text (tall and
   narrow), so a flex valign cell anchors the REAL footprint and over-tall text
   clips at the top (reading end) instead of spilling below the cell and
   shearing off the reading start. vertical-rl is universally supported; the
   Firefox-only sideways-* keywords are avoided.
   nowrap + max-width:none override .sh-cell--wrap .sh-cell-content (above) so a
   wrapped+rotated cell stays one tall column instead of breaking into
   side-by-side vertical columns. Source order after that rule lets these win. */
.sh-cell--rot-neg90 .sh-cell-content {   /* "Rotate down": reads top-to-bottom */
	writing-mode: vertical-rl;
	text-orientation: mixed;
	transform: none;
	white-space: nowrap;
	max-width: none;
}
.sh-cell--rot-90 .sh-cell-content {      /* "Rotate up": reads bottom-to-top */
	writing-mode: vertical-rl;
	text-orientation: mixed;
	/* No cross-browser writing-mode keyword reads bottom-to-top (sideways-lr is
	   Firefox-only), so flip the correctly-sized box in place. The transform is
	   paint-time and does not move the flex-anchored footprint, so the start
	   lands at the visible bottom; do NOT add an align-self swap. */
	transform: rotate(180deg);
	white-space: nowrap;
	max-width: none;
}
/* Editing escape: the underlying .sh-cell-content stays in the DOM behind the
   editor textarea (a separate sibling), so reset it to keep rotated text from
   bleeding around the editor. */
.sh-cell--rot-90.sh-cell--editing  .sh-cell-content,
.sh-cell--rot-neg90.sh-cell--editing .sh-cell-content {
	writing-mode: horizontal-tb;
	transform: none;
}

/* Slant cutoff triangle: filled corner painted in the empty triangle a
   slanted cell's parallelogram leaves behind, colored from the adjacent
   cell's fill so a slanted header band visually merges with the next
   filled row (e.g., a Target-Points red row meeting the slanted header).
   Sibling of the slanted cell in the same pane, position/size set inline
   by render.js. pointer-events:none so it never intercepts clicks meant
   for the underlying cell. z-index lifts above default-stacked cells so
   the triangle overlap into the neighbor's column wins over that
   neighbor's left/right border which would otherwise paint on top. */
.sh-slant-triangle {
	position: absolute;
	pointer-events: none;
	z-index: 1;
}

/* Vertical alignment: opt-in via the data-valign attribute. Cells without
   a valign keep block layout so inline WritingML (multi-tag content)
   continues to flow inline rather than each tag becoming its own flex
   item. Cells with a valign become flex containers; the .sh-cell-content
   wrapper is the single flex item that align-items positions. */
.sh-cell[data-valign] {
	display: flex;
	align-items: flex-start;
}
.sh-cell[data-valign="middle"] { align-items: center; }
.sh-cell[data-valign="bottom"] { align-items: flex-end; }

/* Chart overlay layer: sibling of the cell layer in S.bodyInner. Charts
   are absolute-positioned within. Layer itself has pointer-events:none so
   clicks pass through to cells; chart wrappers re-enable pointer-events.
   Z-stack: z-index 1 elevates the chart above cells (which are level-6
   auto z-index, in DOM order). Selection rect (.sh-selection) is also
   z-index 1 but appended LATER in DOM order, so DOM-order tiebreak puts
   selection above charts. Frozen panes are z-index 2/3 and clip the chart
   automatically when the user scrolls behind a frozen band. */
.sh-chart-layer {
	position: absolute;
	top: 0; left: 0;
	pointer-events: none;
	z-index: 1;
}
.sh-chart {
	position: absolute;
	box-sizing: border-box;
	background: #fff;
	border: 1px solid #d0d7de;
	border-radius: 6px;
	box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
	pointer-events: auto;
	overflow: hidden;
	cursor: grab;
}
.sh-chart canvas.sh-chart-canvas {
	display: block;
	width: 100%;
	height: 100%;
}
.sh-chart:focus-visible,
.sh-chart--selected {
	outline: 2px solid #1a73e8;
	outline-offset: 1px;
	border-color: #1a73e8;
}
.sh-chart--dragging {
	cursor: grabbing;
	box-shadow: 0 4px 16px rgba(26, 115, 232, 0.25);
}

/* Corner resize handles. 14px squares anchored to each corner with the
   appropriate cursor. Visible only when the chart is selected or hovered
   so they don't clutter the default state. */
.sh-chart-handle {
	position: absolute;
	width: 14px;
	height: 14px;
	background: #1a73e8;
	border: 2px solid #fff;
	border-radius: 50%;
	box-sizing: border-box;
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.20);
	opacity: 0;
	transition: opacity 0.10s ease;
	pointer-events: none;
}
.sh-chart:hover .sh-chart-handle,
.sh-chart--selected .sh-chart-handle,
.sh-chart--dragging .sh-chart-handle,
.sh-chart:focus-visible .sh-chart-handle {
	opacity: 1;
	pointer-events: auto;
}
.sh-chart-handle--nw { top: -7px;    left: -7px;    cursor: nwse-resize; }
.sh-chart-handle--ne { top: -7px;    right: -7px;   cursor: nesw-resize; }
.sh-chart-handle--se { bottom: -7px; right: -7px;   cursor: nwse-resize; }
.sh-chart-handle--sw { bottom: -7px; left: -7px;    cursor: nesw-resize; }

/* Properties gear button. Sits inside the wrapper at top-right (NOT at the
   corner where the NE handle lives). Same hover-reveal pattern as the
   handles. data-no-drag escape hatch (handled in onChartLayerMouseDown)
   prevents a click on the gear from starting a chart move. */
.sh-chart-gear {
	position: absolute;
	top: 6px; right: 6px;
	width: 24px; height: 24px;
	font-size: 16px;
	line-height: 20px;
	text-align: center;
	color: #555;
	background: rgba(255, 255, 255, 0.92);
	border: 1px solid #cfd4db;
	border-radius: 4px;
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.10);
	opacity: 0;
	transition: opacity 0.10s ease;
	cursor: pointer;
	pointer-events: none;
	padding: 0;
}
.sh-chart:hover .sh-chart-gear,
.sh-chart--selected .sh-chart-gear,
.sh-chart--dragging .sh-chart-gear,
.sh-chart:focus-visible .sh-chart-gear {
	opacity: 1;
	pointer-events: auto;
}
.sh-chart-gear:hover {
	background: #fff;
	color: #1a73e8;
	border-color: #1a73e8;
}
.sh-chart-gear:focus-visible {
	outline: 2px solid #1a73e8;
	outline-offset: 1px;
}

/* Properties modal: scrollable body so title + footer stay pinned, plus
   typography for sections and helper hints. */
.sh-chart-props-modal {
	min-width: 480px;
	max-width: min(640px, 92vw);
}
.sh-chart-props-body {
	overflow-y: auto;
	flex: 1 1 auto;
	margin: 12px 0;
	padding-right: 4px;
}
.sh-chart-props-section {
	font-weight: 600;
	font-size: 12px;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: #1a4971;
	margin: 14px 0 6px 0;
	padding-bottom: 4px;
	border-bottom: 1px solid #e5e9ee;
}
.sh-chart-props-section:first-child { margin-top: 0; }
.sh-chart-props-row-label {
	font-weight: 600;
	font-size: 12px;
	margin-bottom: 4px;
}
.sh-chart-props-input-row {
	display: flex;
	align-items: center;
	gap: 8px;
}
.sh-chart-props-text {
	/* box-sizing: border-box + min-width: 0 + flex-basis: 0 keeps the input
	   inside the flex parent's content box even when the intrinsic size
	   would otherwise let it overflow. appearance:none normalizes the
	   subtle inset border Safari draws around text inputs. */
	box-sizing: border-box;
	flex: 1 1 0;
	min-width: 0;
	width: 100%;
	font-size: 13px;
	padding: 6px 8px;
	border: 1px solid #cfd4db;
	border-radius: 4px;
	appearance: none;
	-webkit-appearance: none;
	background: #fff;
	font-family: inherit;
}
.sh-chart-props-text:focus-visible {
	/* Inset the focus indicator inside the input's border so it does not
	   visually extend the input to the left (or any side) past where the
	   section labels and other unfocused inputs sit. */
	outline: none;
	border-color: #1a73e8;
	box-shadow: inset 0 0 0 1px #1a73e8;
}
.sh-chart-props-counter {
	flex: 0 0 auto;
	font-size: 11px;
	color: #6b7280;
	min-width: 50px;
	text-align: right;
}
.sh-chart-props-select {
	box-sizing: border-box;
	font-size: 13px;
	padding: 6px 8px;
	border: 1px solid #cfd4db;
	border-radius: 4px;
	background: #fff;
	min-width: 200px;
}
.sh-chart-props-select:focus-visible {
	outline: none;
	border-color: #1a73e8;
	box-shadow: inset 0 0 0 1px #1a73e8;
}
.sh-chart-props-checkbox-row {
	margin-bottom: 8px;
}
.sh-chart-props-checkbox-label {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	cursor: pointer;
	font-weight: normal;
}
.sh-chart-props-hint {
	font-size: 12px;
	color: #6b7280;
	font-style: italic;
	margin: 6px 0 10px 0;
	padding: 6px 8px;
	background: #f3f6fa;
	border-radius: 4px;
}

/* Inline conflict banner shown at top of modal on a 409 from update_chart.
   role="alert" announces it to screen readers. */
.sh-chart-props-conflict-host:empty { display: none; }
.sh-chart-props-conflict {
	margin: 8px 0;
	padding: 10px 12px;
	background: #fff8e1;
	border: 1px solid #fde68a;
	border-radius: 4px;
	color: #92400e;
}
.sh-chart-props-conflict-msg {
	font-size: 13px;
	margin-bottom: 8px;
}
.sh-chart-props-conflict-btns {
	display: flex;
	gap: 8px;
}
.sh-chart-props-conflict-btn {
	font-size: 12px;
	padding: 5px 10px;
	border: 1px solid #cfd4db;
	background: #fff;
	border-radius: 4px;
	cursor: pointer;
}
.sh-chart-props-conflict-btn.primary {
	background: #1a73e8;
	color: #fff;
	border-color: #1a73e8;
}
.sh-chart-props-conflict-btn:hover {
	filter: brightness(0.96);
}
.sh-chart[data-non-numeric="1"]::after {
	content: "Some values aren't numbers";
	position: absolute;
	left: 6px; bottom: 6px;
	font-size: 11px;
	line-height: 14px;
	color: #b54708;
	background: #fff8e1;
	border: 1px solid #fde68a;
	border-radius: 3px;
	padding: 2px 6px;
	pointer-events: none;
}
/* Visually-hidden table mirror for screen readers. Reuses the standard
   accessible-hidden pattern. Chart.js draws on a canvas which screen readers
   cannot interpret, so this table provides the same data in semantic HTML. */
.sh-chart-a11y-table {
	position: absolute !important;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* Chart-type picker modal. Reuses .sh-modal / .sh-modal-backdrop chrome. */
.sh-chart-type-picker .sh-chart-type-grid {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 12px;
	margin: 16px 0;
}
.sh-chart-type-tile {
	padding: 24px 16px;
	font-size: 15px;
	font-weight: 500;
	color: #1a4971;
	background: #f3f6fa;
	border: 1px solid #d0d7de;
	border-radius: 8px;
	cursor: pointer;
	transition: background 0.12s, border-color 0.12s;
}
.sh-chart-type-tile:hover {
	background: #e8eef5;
	border-color: #1a73e8;
}
.sh-chart-type-tile:focus-visible {
	outline: 2px solid #1a73e8;
	outline-offset: 1px;
}

/* Phase 9B view-menu toggles. sh-no-gridlines hides both the line-layer
   divs and the per-cell borders. sh-compact tightens padding + line-height
   on cells (row heights get a 0.75x multiplier via rebuildGeometry). */
#sheets-app.sh-no-gridlines .sh-grid-line-h,
#sheets-app.sh-no-gridlines .sh-grid-line-v { display: none; }
#sheets-app.sh-no-gridlines .sh-cell,
#sheets-app.sh-no-gridlines .sh-cf-empty {
	border-right:  1px solid transparent;
	border-bottom: 1px solid transparent;
}
#sheets-app.sh-compact .sh-cell {
	padding: calc(1px * var(--sh-zoom, 1)) calc(4px * var(--sh-zoom, 1));
	line-height: calc(14px * var(--sh-zoom, 1));
}

/* View-menu toggles (cleaner view). sh-no-toolbar hides the formatting icon row
   and its overflow panel (the ID selector outranks the panel's own [hidden] /
   display:flex). sh-no-headers collapses the grid's header tracks to 0 and hides
   the corner + A/B/C + 1/2/3 strips, letting the body reclaim the space; cell
   colX/rowY geometry is unaffected, so no rebuild is needed. */
#sheets-app.sh-no-toolbar .sh-toolbar-icons,
#sheets-app.sh-no-toolbar .sh-toolbar-overflow { display: none; }

#sheets-app.sh-no-headers .sh-grid-container {
	grid-template-columns: 0 1fr 12px;
	grid-template-rows: 0 1fr 12px;
}
#sheets-app.sh-no-headers .sh-corner,
#sheets-app.sh-no-headers .sh-col-headers,
#sheets-app.sh-no-headers .sh-row-headers { display: none; }

/* Read-only pill: compact amber tag in the menu row (replaces the old
   full-width .sh-readonly-banner). Carries the full message in its tooltip. */
.sh-readonly-pill {
	font-size: 11px;
	font-weight: 600;
	color: #6b5300;
	background: #fff3cd;
	border: 1px solid #f3d88b;
	border-radius: 10px;
	padding: 2px 10px;
	white-space: nowrap;
}

/* Menu-row collapse chevron + the collapsed state. The chevron + read-only pill
   live in the tab line (.sh-tab-bar-controls), so collapsing simply hides the
   whole menu row; the chevron stays put in the tab line to restore it. */
.sh-menu-collapse-btn {
	font-size: 11px;
	line-height: 1;
	color: #555;
}
#sheets-app.sh-menus-collapsed #sh-menu-row {
	display: none;
}

/* Formulas (Phase 8): numeric cells right-align; formula errors are flagged
   with italic red text on a soft pink wash so they pop at a glance. The
   friendly-message tooltip is driven by data-wdc-tooltip from renderCell. */
.sh-cell--numeric { text-align: right; }
.sh-cell--error {
	color: #b00020;
	background: #fff0f0;
	font-style: italic;
}

/* WritingML rendering inside a cell. The cell wrapper keeps its overflow
   rules; the inline strong/em/u/span runs inherit the clamp. No block
   layout - a cell is one line of rich text. */
.sh-cell--ml strong { font-weight: 700; }
.sh-cell--ml em     { font-style: italic; }
.sh-cell--ml u      { text-decoration: underline; }
.sh-cell--ml s      { text-decoration: line-through; }
.sh-cell--ml sub,
.sh-cell--ml sup    { font-size: 0.75em; }

/* Dynamic tag substitutions ({user:}, {item:}, ...) arrive via the
   Phase 2 batch endpoint and can carry images, links, and nested DOM.
   Clamp them so a single {item:...} cannot explode the row height or
   wrap past the cell's ellipsis. */
.sh-cell--ml .sh-dyn {
	display: inline;
	white-space: nowrap;
}
.sh-cell--ml .sh-dyn img {
	/* Bound row height for a stray {item:} cover image, but do NOT clamp width
	   (a fixed-px user/award icon is non-square and gets squished by an em
	   max-width) and keep the cap generous so normal ~18px icons render at
	   natural size, matching how {user:} renders elsewhere on the site. The
	   .sh-dyn * rule below still caps width at the cell for huge media. */
	max-height: 1.8em;
	vertical-align: middle;
}
.sh-cell--ml .sh-dyn * {
	max-width: 100%;
	vertical-align: middle;
}

/* Pending placeholder while a dynamic tag is being fetched. Muted text
   meets AA contrast on white (#6b6b6b on #fff = 5.63:1). aria-busy on
   the element cues screen readers. */
.sh-ml-pending {
	color: #6b6b6b;
	font-style: italic;
}

/* Phase 3 autocomplete dropdown. Class names and CSS mirror the editor's
   autocomplete so users get a consistent look/feel across the site.
   Source of truth: htdocs/main/editor/styles/toolbar.css lines 1431-1548.
   Ported verbatim except for position:fixed (editor uses absolute + document
   coords; sheets uses fixed + viewport coords because the sheet body has
   its own scroll container and the dropdown is appended to document.body
   and closed on any grid scroll). Keep in sync when the editor's rules
   change; scheduled to be a shared CSS file in the bundling cleanup. */
.writingml-autocomplete-dropdown {
	position: fixed;
	background: white;
	border: 1px solid #ccc;
	border-radius: 4px;
	box-shadow: 0 4px 16px rgba(0,0,0,0.25), 0 2px 4px rgba(0,0,0,0.12);
	max-height: 240px;
	overflow-y: scroll;
	overflow-x: hidden;
	z-index: 10000;
	min-width: 250px;
	scrollbar-width: thin;
	scrollbar-color: #c1c1c1 #f5f5f5;
}
.writingml-autocomplete-dropdown[hidden] { display: none; }

.writingml-autocomplete-dropdown::-webkit-scrollbar {
	width: 8px;
	background-color: #f5f5f5;
}
.writingml-autocomplete-dropdown::-webkit-scrollbar-track {
	background-color: #f5f5f5;
	border-radius: 4px;
}
.writingml-autocomplete-dropdown::-webkit-scrollbar-thumb {
	background-color: #c1c1c1;
	border-radius: 4px;
}
.writingml-autocomplete-dropdown::-webkit-scrollbar-thumb:hover {
	background-color: #a8a8a8;
}

.writingml-autocomplete-list {
	margin: 0;
	padding: 0;
}

.writingml-autocomplete-item {
	cursor: pointer;
	border-bottom: 1px solid #f5f5f5;
	font-size: 14px;
	display: flex;
	align-items: center;
	line-height: 1.3;
	padding: 6px 10px;
	min-height: 28px;
}
.writingml-autocomplete-item:last-child { border-bottom: none; }
.writingml-autocomplete-item:hover      { background: #f8f8f8; }
.writingml-autocomplete-item.active     { background: #007bff; color: white; }

.writingml-autocomplete-item .autocomplete-id {
	display: inline-block;
	width: 65px;
	text-align: right;
	font-weight: 500;
	color: #999;
	flex-shrink: 0;
	margin-right: 12px;
}
.writingml-autocomplete-item .autocomplete-title {
	flex: 1;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.writingml-autocomplete-item.active .autocomplete-id    { color: rgba(255, 255, 255, 0.9); }
.writingml-autocomplete-item.active .autocomplete-title { color: white; }

.writingml-autocomplete-item.separator {
	cursor: default;
	height: 1px;
	min-height: 1px;
	padding: 0;
	background: #e1e6ee;
}

/* Phase 6 V3 editor overlay. Sheet cells are typically 24-40px tall; the
   ProseMirror editor with its toolbar needs ~80px minimum. Float it as a
   popup below the active cell (Numbers-style), pinned to viewport coords.
   White panel with light shadow, similar to the Phase 3 autocomplete chrome.
   z-index 90: above grid (z-index 5) but below the editor's own dropdowns
   (which use 10000). */
.sh-v3-host {
	position: fixed;
	z-index: 90;
	display: flex;
	flex-direction: column;
	background: #fff;
	border: 1px solid #c7d0dc;
	border-radius: 6px;
	box-shadow: 0 6px 22px rgba(0,0,0,0.18), 0 2px 4px rgba(0,0,0,0.10);
	padding: 0;
	min-width: 360px;
	max-width: calc(100vw - 16px);
	overflow: hidden;
}
/* Tighter toolbar inside the cell-editor overlay. The bar gets its
   background color (#f2f4fa) and the SVG-button transparency reset from
   editor/styles/toolbar.css scoped to .writingml-toolbar-v2 (we add that
   class alongside .editor-toolbar in buildSheetsToolbarTemplate). What's
   sheets-specific lives here: flex layout, padding, divider line. */
.sh-v3-host .editor-toolbar {
	flex: 0 0 auto;
	display: flex;
	flex-wrap: nowrap;
	align-items: center;
	gap: 1px;
	padding: 4px 6px;
	border-bottom: 1px solid #e3e7ee;
	/* Empty regions of the toolbar drag the whole overlay; buttons keep
	   their own pointer. */
	cursor: grab;
	user-select: none;
}
.sh-v3-host.dragging .editor-toolbar { cursor: grabbing; }
.sh-v3-host .editor-toolbar .Editor_Button {
	flex: 0 0 auto;
	cursor: pointer;
}
/* The .writingml-toolbar-v2 .Editor_Button.svg-button img rule in
   editor/styles/toolbar.css:107-113 sets {width: inherit; height: inherit}
   with !important. Equal specificity + both !important + editor CSS loaded
   after sheets.css = editor wins, icons grow to fill the flex container.
   Bump specificity here by matching the same compound selector AND adding
   .sh-v3-host (giving us 0,4,1 vs editor's 0,3,1). Same trick messenger
   uses at messenger-float.css:1128 - it scopes to .messenger-chat-window. */
.sh-v3-host .writingml-toolbar-v2 .Editor_Button.svg-button img,
.sh-v3-host .writingml-toolbar-v2 .Editor_Button.svg-button.active img,
.sh-v3-host .editor-toolbar .Editor_Button.svg-button img,
.sh-v3-host .editor-toolbar .Editor_Button.svg-button.active img {
	width: 24px !important;
	height: 24px !important;
	display: block;
}
.sh-v3-host .writingml-editor-v3-wrapper {
	flex: 0 0 auto;
}
.sh-v3-host .prosemirror-editor-container {
	min-height: 36px;
}
.sh-v3-host .ProseMirror {
	/* Match the cell's padding (sh-cell rule above: 3px 6px) so opening the
	   editor doesn't visually shift the content. The host's outer edges are
	   aligned with the cell by positionV3Overlay; matching the inner padding
	   keeps the text in the same screen position across view <-> edit. */
	padding: 3px 6px;
	min-height: 24px;
	outline: none;
}
/* The editor's settings-plugin async-applies an "editor-show-block-borders"
   class to .ProseMirror when the user has the corresponding setting on,
   bumping padding-left to 17px and showing gutter indicators (editor.css
   :657-745). That's a full-page-editor visual; in a one-line cell editor
   it pointlessly shifts the text right ~150ms after open. Neutralize the
   padding bump and hide the indicators inside the sheets host. */
.sh-v3-host .ProseMirror.editor-show-block-borders {
	padding: 3px 6px;
}
.sh-v3-host .ProseMirror.editor-show-block-borders .wml-gutter-indicator {
	display: none;
}
/* sheets-plugin formula-mode class on the editor's contenteditable.
   Renders =A1+B1 in a monospace, slightly muted style so users see at
   a glance that the cell is computed, not rich text. */
.sh-v3-host .ProseMirror.sheets-formula-mode,
.sh-v3-host [contenteditable="true"].sheets-formula-mode {
	font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
	color: #1a4971;
}

/* Phase 3b floating cell-editor toolbar. Shows above the textarea when
   the user is editing a cell. Visual language is a compact cousin of
   the v3 editor toolbar (similar button sizing, colors, hover). */
.sh-cell-toolbar {
	position: fixed;
	z-index: 20;  /* above editor (z-index 5); below autocomplete (10000) */
	display: flex;
	align-items: center;
	gap: 2px;
	padding: 4px 6px;
	background: #fff;
	border: 1px solid #c7d0dc;
	border-radius: 6px;
	box-shadow: 0 2px 10px rgba(0, 0, 0, 0.14), 0 1px 3px rgba(0, 0, 0, 0.08);
	font-size: 13px;
	user-select: none;
}
.sh-cell-toolbar[hidden] { display: none; }
.sh-tb-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 28px;
	min-height: 28px;
	padding: 0 6px;
	background: none;
	border: 1px solid transparent;
	border-radius: 4px;
	color: #222;
	cursor: pointer;
	font-size: 14px;
	line-height: 1;
}
.sh-tb-btn:hover { background: #f0f4fa; border-color: #c7d0dc; }
.sh-tb-btn:active { background: #e1ebf7; }
.sh-tb-btn:focus-visible { outline: 2px solid #0D47A1; outline-offset: 1px; }
.sh-tb-sep {
	display: inline-block;
	width: 1px;
	height: 18px;
	margin: 0 4px;
	background: #d9dde3;
}
.sh-tb-size { font-size: 12px; }

/* Shared popover for color / highlight / size (one popover, re-populated). */
.sh-tb-popover {
	position: fixed;
	z-index: 21;
	padding: 6px;
	background: #fff;
	border: 1px solid #c7d0dc;
	border-radius: 6px;
	box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18);
}
.sh-tb-popover[hidden] { display: none; }

.sh-tb-swatches {
	display: grid;
	grid-template-columns: repeat(8, 22px);
	gap: 4px;
	max-width: 220px;
}
.sh-tb-swatch {
	width: 22px;
	height: 22px;
	padding: 0;
	border: 1px solid rgba(0, 0, 0, 0.15);
	border-radius: 3px;
	cursor: pointer;
	box-sizing: border-box;
}
.sh-tb-swatch:hover { transform: scale(1.12); transition: transform 0.12s; outline: 1px solid #0D47A1; }

.sh-tb-sizes { display: flex; flex-direction: column; min-width: 140px; }
.sh-tb-size-opt {
	padding: 6px 10px;
	background: none;
	border: none;
	border-radius: 3px;
	cursor: pointer;
	text-align: left;
	font-size: 13px;
}
.sh-tb-size-opt:hover { background: #f0f4fa; }
.sh-tb-size-opt[data-size="1"]   { font-size: 11px; }
.sh-tb-size-opt[data-size="3"]   { font-size: 13px; }
.sh-tb-size-opt[data-size="4"]   { font-size: 15px; }
.sh-tb-size-opt[data-size="4.5"] { font-size: 17px; }
.sh-tb-size-opt[data-size="5"]   { font-size: 19px; }

.sh-tb-empty {
	padding: 6px 10px;
	color: #6b6b6b;
	font-style: italic;
	font-size: 12px;
}

/* Mobile overrides mirrored from editor/styles/mobile-overrides.css:95-117.
   Sheets is view-only on mobile today (canEdit() blocks edit mode) so the
   autocomplete rarely renders on phones, but keep parity for future. */
@media (max-width: 768px) {
	.writingml-autocomplete-dropdown {
		font-size: 14px !important;
		min-width: 280px !important;
		max-width: calc(100vw - 20px) !important;
	}
	.writingml-autocomplete-item {
		font-size: 15px !important;
		padding: 8px 12px !important;
		min-height: 32px !important;
	}
}

/* Selection outline rendered as a separate element so cells don't need to
   repaint when the selection moves. */
/* Phase 9C frozen panes. Each pane owns the cells in its region and stays
   pinned on its axis via transforms applied in syncScroll. Cells inside
   use absolute positioning with the same colX/rowY coords as the main
   grid, so the math doesn't change.

   Tint: frozen cells get a very subtle blue-gray wash so the pinned area
   is visually distinct from the scrollable body without being loud. The
   tint lives on both the pane bg (covers empty areas) and on cells inside
   the pane (match the pane bg). */
/* Sticky 0x0 anchors that pin each pane natively at compositor time.
   The anchor's offsets pick which axes stick: top-only for frozen rows,
   left-only for frozen cols, both for the corner. The pane sits inside
   as an absolute child at (0, 0) and keeps its existing sizing. */
.sh-pane-anchor {
	position: sticky;
	width: 0;
	height: 0;
}
.sh-pane-anchor--top    { top: 0;          z-index: 2; }
.sh-pane-anchor--left   { left: 0;         z-index: 2; }
.sh-pane-anchor--corner { top: 0; left: 0; z-index: 3; }

.sh-pane-top,
.sh-pane-left,
.sh-pane-corner {
	position: absolute;
	top: 0;
	left: 0;
	background: #f4f7fb;
	overflow: hidden;
	box-sizing: border-box;
}
.sh-pane-top    { z-index: 2; }
.sh-pane-left   { z-index: 2; }
.sh-pane-corner { z-index: 3; }

/* Cells inside the panes inherit the tint (otherwise their own white bg
   would show a rectangle of white on top of the tinted pane). */
.sh-pane-top .sh-cell,
.sh-pane-left .sh-cell,
.sh-pane-corner .sh-cell { background: #f4f7fb; }

/* Hairline at the freeze boundary so the pinned region is visually distinct. */
.sh-pane-top    { border-bottom: 1px solid #8aa4c0; }
.sh-pane-left   { border-right:  1px solid #8aa4c0; }
.sh-pane-corner { border-right:  1px solid #8aa4c0; border-bottom: 1px solid #8aa4c0; }

/* Selection rect. Main-area rect sits BELOW the panes (z-index 1) so when
   the selected cell scrolls behind a frozen pane, its outline is hidden
   with it instead of floating on top. Per-pane selection rects live
   inside each pane's stacking context at z-index 4 so they stay above
   pane cells. */
.sh-selection {
	position: absolute;
	border: 2px solid #1a73e8;
	box-sizing: border-box;
	pointer-events: none;
	/* Z 10 lifts the selection (and the fill handle inside it) above same-pane
	   siblings at z 2-3 (grow handles, formula refs) so the bottom-right
	   handle is never visually covered. The chart layer at z 1 was already
	   ordered below via DOM tiebreak; explicit 10 keeps that ordering. */
	z-index: 10;
	background: rgba(26, 115, 232, 0.06);
}
.sh-pane-top .sh-selection,
.sh-pane-left .sh-selection,
.sh-pane-corner .sh-selection { z-index: 4; }
.sh-selection.range { background: rgba(26, 115, 232, 0.10); }
/* Multi-range: the last slot is the active range (S.range alias points
   at S.ranges[length-1]); single-range case has the lone slot active so
   :not(.active) never matches and rendering is identical to today. In
   multi-range, the inactive slots dim their border so the active range
   reads as primary. */
.sh-selection.range:not(.active) {
	border-color: rgba(26, 115, 232, 0.45);
	background: rgba(26, 115, 232, 0.05);
}

/* Drag-fill handle in the bottom-right corner of the active selection.
   Lives as a child of .sh-selection.main so it follows the rect and gets
   clipped to the same pane. Selection itself is pointer-events:none so we
   explicitly re-enable on the handle. Only the main rect carries one;
   pane-clipped copies stay clean. */
.sh-fill-handle {
	position: absolute;
	right: -6px;
	bottom: -6px;
	width: 12px;
	height: 12px;
	background: #1a73e8;
	border: 2px solid #fff;
	box-sizing: border-box;
	cursor: crosshair;
	pointer-events: auto;
	z-index: 20;
	border-radius: 2px;
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
}
.sh-fill-handle:hover { background: #1557b0; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.45); }

/* Dashed preview rect drawn under the cursor while the fill handle is being
   dragged, indicating the target range. Painted into the same pane layout as
   the selection (one rect per visible region). */
.sh-fill-preview {
	position: absolute;
	border: 2px dashed #1a73e8;
	box-sizing: border-box;
	pointer-events: none;
	background: rgba(26, 115, 232, 0.04);
	z-index: 3;
}
.sh-pane-top .sh-fill-preview,
.sh-pane-left .sh-fill-preview,
.sh-pane-corner .sh-fill-preview { z-index: 5; }

/* Formula cell-ref highlights. When the V3 editor is open on a cell whose
   value starts with "=", every A1 / A1:B5 reference in the formula gets
   one of these outlines drawn over the matching cell or range. Distinct
   color from the blue selection rect so the user can tell at a glance
   which cells the formula consumes. Pointer-events:none so they never
   block clicks on the underlying cells. */
.sh-formula-ref {
	position: absolute;
	border: 2px solid #f08c00;
	box-sizing: border-box;
	pointer-events: none;
	z-index: 2;
	background: rgba(240, 140, 0, 0.06);
}
.sh-formula-ref.range { background: rgba(240, 140, 0, 0.10); }

/* Bottom-right corner drag handle on each formula ref. Sized to be easy to
   grab with a mouse (10px) without obscuring small cells. Sits above the
   ref outline (z-index 3 vs ref's 2). pointer-events explicit so the rect
   itself stays click-through but the handle accepts mousedown. */
.sh-formula-ref-handle {
	position: absolute;
	width: 10px;
	height: 10px;
	background: #f08c00;
	border: 1px solid #fff;
	box-sizing: border-box;
	cursor: nwse-resize;
	z-index: 3;
	pointer-events: auto;
	border-radius: 1px;
}
.sh-formula-ref-handle:hover { background: #e07b00; }
.sh-formula-ref-handle--tl { cursor: nwse-resize; }
.sh-formula-ref-handle--br { cursor: nwse-resize; }

/* Numbers-style grow/shrink handles: small pills at the grid boundary. The
   row-pill drags vertically, the col-pill horizontally, the corner both.
   Handles live inside bodyInner so they scroll with the content and sit
   flush against the last row/column. */
.sh-grow-handle {
	position: absolute;
	z-index: 3;
	background: #ffffff;
	border: 1px solid #8aa4c0;
	color: #1a4971;
	display: flex;
	align-items: center;
	justify-content: center;
	user-select: none;
	box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
	transition: background 0.12s ease, border-color 0.12s ease;
}
.sh-grow-handle:hover          { background: #e5ecf5; border-color: #1a73e8; }
.sh-grow-handle.dragging       { background: #1a73e8; border-color: #1a73e8; }
.sh-grow-handle:focus-visible  { outline: 2px solid #1a73e8; outline-offset: 2px; }

.sh-grow-handle--rows {
	width: 36px;
	height: 12px;
	border-radius: 6px;
	cursor: ns-resize;
}
.sh-grow-handle--cols {
	width: 12px;
	height: 36px;
	border-radius: 6px;
	cursor: ew-resize;
}
.sh-grow-handle--corner {
	width: 16px;
	height: 16px;
	border-radius: 8px;
	cursor: nwse-resize;
}

/* Icon lines inside the pills, rendered with pseudo-elements so we avoid
   an icon font. Two short bars for rows (=), two for cols (||), diagonal
   cross-hatch for the corner. */
.sh-grow-icon {
	display: block;
	position: relative;
}
.sh-grow-icon--rows {
	width: 14px;
	height: 6px;
}
.sh-grow-icon--rows::before,
.sh-grow-icon--rows::after {
	content: "";
	position: absolute;
	left: 0;
	width: 14px;
	height: 1px;
	background: #1a4971;
}
.sh-grow-icon--rows::before { top: 1px; }
.sh-grow-icon--rows::after  { top: 4px; }
.sh-grow-handle--rows.dragging .sh-grow-icon--rows::before,
.sh-grow-handle--rows.dragging .sh-grow-icon--rows::after { background: #fff; }

.sh-grow-icon--cols {
	width: 6px;
	height: 14px;
}
.sh-grow-icon--cols::before,
.sh-grow-icon--cols::after {
	content: "";
	position: absolute;
	top: 0;
	width: 1px;
	height: 14px;
	background: #1a4971;
}
.sh-grow-icon--cols::before { left: 1px; }
.sh-grow-icon--cols::after  { left: 4px; }
.sh-grow-handle--cols.dragging .sh-grow-icon--cols::before,
.sh-grow-handle--cols.dragging .sh-grow-icon--cols::after { background: #fff; }

.sh-grow-icon--corner {
	width: 8px;
	height: 8px;
	border-right:  1px solid #1a4971;
	border-bottom: 1px solid #1a4971;
}
.sh-grow-handle--corner.dragging .sh-grow-icon--corner {
	border-right-color: #fff;
	border-bottom-color: #fff;
}

/* Full-grid ghost outline during a resize drag. The row/col delta is
   shown separately by .sh-drag-badge, which follows the cursor. */
.sh-grow-ghost {
	position: absolute;
	z-index: 5;
	border: 2px dashed #1a73e8;
	background: rgba(26, 115, 232, 0.06);
	box-sizing: border-box;
	pointer-events: none;
}
.sh-grow-ghost--shrink { border-color: #b00020; background: rgba(176, 0, 32, 0.06); }

/* Floating "+5 rows (30 total)" badge that follows the cursor during a
   grow/shrink drag. Sits in a fixed position relative to the viewport so
   it stays visible regardless of scroll. */
.sh-drag-badge {
	position: fixed;
	z-index: 2147483647;
	background: #1a73e8;
	color: #fff;
	font-size: 13px;
	font-weight: 600;
	line-height: 1.35;
	padding: 6px 10px;
	border-radius: 4px;
	box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
	pointer-events: none;
	white-space: pre;
	display: none;
}
.sh-drag-badge--shrink { background: #b00020; }

/* While dragging any grow handle, override the cell cursor everywhere so
   the resize cursor stays consistent over the whole grid. */
body.sh-resizing, body.sh-resizing * { cursor: inherit !important; }

/* Cell editor overlay. */
.sh-editor {
	position: absolute;
	box-sizing: border-box;
	z-index: 5;
	border: 2px solid #1a73e8;
	padding: 2px 5px;
	font-size: calc(13px * var(--sh-zoom, 1));
	line-height: calc(18px * var(--sh-zoom, 1));
	font-family: inherit;
	background: #fff;
	color: #222;
	outline: none;
	border-radius: 0;
	resize: none;
	user-select: text;
	-webkit-user-select: text;
}

/* Re-enable text selection inside the V3 editor and modal text areas; the
   .sh-app user-select:none rule cascades to descendants otherwise. */
.sh-v3-host .ProseMirror,
.sh-v3-host [contenteditable="true"],
.sh-modal textarea,
.sh-modal input[type="text"] {
	user-select: text;
	-webkit-user-select: text;
}

/* -------------------- Tab bar -------------------- */

/* Tab line: scrollable tabs (.sh-tabs) + a pinned controls cluster
   (.sh-tab-bar-controls) holding the read-only pill + the menu collapse chevron.
   The wrapper owns the row chrome so the pinned cluster shares the same surface
   and the tabs can scroll independently beneath it. */
.sh-tab-bar {
	display: flex;
	align-items: stretch;
	background: #f5f7fa;
	border-bottom: 1px solid #e3e6eb;
	flex-shrink: 0;
}
.sh-tabs {
	display: flex;
	align-items: stretch;
	gap: 2px;
	padding: 6px 10px 0 10px;
	flex: 1 1 auto;
	min-width: 0;       /* let the flex item shrink so overflow-x actually scrolls */
	overflow-x: auto;
	position: relative; /* containing block for the drag drop indicator */
}
/* Drag-to-reorder visuals (state machine in ui.js). The indicator is
   positioned in .sh-tabs content coordinates so it scrolls with the strip. */
.sh-tab.sh-drag-src { opacity: 0.4; }
/* Floating copy of the dragged tab that slides along the tab row under the
   pointer (built in ui.js from a cloneNode of the tab, so active state and
   the tab-color strip carry over). Lives on document.body. */
.sh-tab.sh-tab-drag-ghost {
	position: fixed;
	z-index: 2147483647;
	margin: 0;
	opacity: 0.92;
	border-radius: 4px;
	/* Width/style only: the color cascades from the .sh-tab / .active
	   border-color, so a dragged active tab keeps its blue edge. */
	border-bottom-width: 1px;
	border-bottom-style: solid;
	box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
	pointer-events: none;
}
.sh-tab-drop-indicator {
	position: absolute;
	top: 6px;
	bottom: 0;
	width: 3px;
	border-radius: 2px;
	background: #1a73e8;
	pointer-events: none;
	z-index: 3;
}
#sheets-app.sh-tab-dragging,
#sheets-app.sh-tab-dragging .sh-tab { cursor: grabbing; }
.sh-tab-bar-controls {
	display: flex;
	align-items: center;
	gap: 8px;
	flex-shrink: 0;
	padding: 6px 10px 0 8px;
}
.sh-tab {
	display: flex;
	align-items: center;
	padding: 6px 10px 6px 14px;
	background: #fff;
	border: 1px solid #d9dde3;
	border-bottom: 0;
	border-radius: 4px 4px 0 0;
	font-size: 12px;
	color: #555;
	cursor: pointer;
	white-space: nowrap;
	user-select: none;
	position: relative;
	line-height: 1.3;
	margin-bottom: -1px;
}
.sh-tab:hover { background: #eef2f7; }
.sh-tab.active {
	background: #1a73e8;
	color: #fff;
	border-color: #1a73e8;
	font-weight: 600;
}
/* Per-tab accent color, painted as a bottom strip via a CSS variable
   set by renderTabs. Layers above the tab background so active and
   inactive states both display it.
   Specificity note: this is .sh-tab[data-tab-color]::after (0,2,1). If a
   future change adds a generic .sh-tab::after rule (eg a modified
   indicator), bump that selectors specificity or order so it doesnt
   silently shadow the tab-color strip. */
.sh-tab[data-tab-color]::after {
	content: '';
	position: absolute;
	left: 0; right: 0; bottom: 0;
	height: 5px;
	background: var(--tab-color);
	pointer-events: none;
}
/* 1px inner white edge keeps the strip readable when the user picks the
   active-tab blue (#1a73e8) as their tab color. */
.sh-tab.active[data-tab-color]::after {
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7);
}
.sh-tab-label {
	max-width: 180px;
	overflow: hidden;
	text-overflow: ellipsis;
}
.sh-tab-add,
.sh-tab-all {
	padding: 4px 12px;
	background: #fff;
	border: 1px dashed #cfd4db;
	border-radius: 4px;
	font-size: 14px;
	color: #666;
	cursor: pointer;
	line-height: 1;
}
.sh-tab-add:hover,
.sh-tab-all:hover { background: #eef2f7; color: #333; }
.sh-tab-all { border-style: solid; }   /* hamburger isn't a placeholder action */

/* -------------------- Empty / read-only states -------------------- */

.sh-empty {
	padding: 40px 20px;
	text-align: center;
	color: #666;
	font-size: 14px;
	line-height: 1.5;
}
.sh-empty p { margin: 0 0 12px 0; }

/* -------------------- Presence (other users) -------------------- */

.sh-presence {
	display: flex;
	align-items: center;
	gap: 4px;
	margin-left: auto;  /* push presence + save status to the right edge */
	margin-right: 10px;
}
.sh-avatar {
	width: 24px;
	height: 24px;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 11px;
	font-weight: 600;
	color: #fff;
	background: #888;
	cursor: default;
	user-select: none;
	text-transform: uppercase;
	border: 2px solid #fff;
	box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
	line-height: 1;
}

/* Same-tab notice: soft, dismissible heads-up shown when the user has this
   sheet open in another browser tab. Amber, non-blocking; both tabs stay live.
   Lives in normal flow below the toolbar (not a modal), so no z-index needed. */
.sh-own-tab-notice {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: calc(8px * var(--sh-zoom, 1));
	padding: calc(7px * var(--sh-zoom, 1)) calc(12px * var(--sh-zoom, 1));
	background: #fff4d6;
	border-bottom: 1px solid #e0b94d;
	color: #5a4300;
	font-size: calc(13px * var(--sh-zoom, 1));
	line-height: 1.4;
}
/* [hidden] must beat the display:flex above (same specificity otherwise). */
.sh-own-tab-notice[hidden] { display: none; }
.sh-own-tab-notice-icon {
	flex: 0 0 auto;
	width: calc(18px * var(--sh-zoom, 1));
	height: calc(18px * var(--sh-zoom, 1));
	border-radius: 50%;
	background: #9c5c00;
	color: #fff;
	font-weight: 700;
	font-size: calc(13px * var(--sh-zoom, 1));
	display: flex;
	align-items: center;
	justify-content: center;
	line-height: 1;
}
.sh-own-tab-notice-text {
	flex: 1 1 auto;
	min-width: calc(180px * var(--sh-zoom, 1));
}
.sh-own-tab-notice-dismiss {
	flex: 0 0 auto;
	background: #fff;
	border: 1px solid #c9a23f;
	color: #5a4300;
	border-radius: 4px;
	padding: calc(3px * var(--sh-zoom, 1)) calc(10px * var(--sh-zoom, 1));
	font-size: calc(12px * var(--sh-zoom, 1));
	cursor: pointer;
}
.sh-own-tab-notice-dismiss:hover { background: #f5e7bf; }
.sh-own-tab-notice-dismiss:focus-visible {
	outline: 2px solid #8a6d00;
	outline-offset: 1px;
}

/* Outline drawn over the cell/range another user is focused on. Thin dashed
   border keeps it distinguishable from your own selection. */
.sh-peer-focus {
	position: absolute;
	box-sizing: border-box;
	border: 2px dashed;
	pointer-events: none;
	z-index: 3;
	background: transparent;
}
.sh-peer-focus.range { background: rgba(0, 0, 0, 0.04); }
.sh-peer-focus-label {
	position: absolute;
	top: -18px;
	left: -2px;
	padding: 1px 6px;
	font-size: 10px;
	font-weight: 600;
	color: #fff;
	border-radius: 3px 3px 3px 0;
	white-space: nowrap;
	line-height: 1.3;
	pointer-events: none;
}

/* -------------------- Conflict chip -------------------- */

.sh-conflict-chip {
	position: absolute;
	z-index: 6;
	min-width: 220px;
	max-width: 300px;
	padding: 10px 12px;
	background: #fff;
	border: 1px solid #c0392b;
	border-radius: 6px;
	box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
	font-size: 12px;
	line-height: 1.45;
	color: #333;
}
.sh-conflict-chip-title {
	font-weight: 600;
	color: #c0392b;
	margin-bottom: 4px;
}
.sh-conflict-chip-row {
	margin: 2px 0;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.sh-conflict-chip-label {
	color: #666;
	margin-right: 4px;
}
.sh-conflict-chip-val {
	font-family: Menlo, Monaco, Consolas, monospace;
	font-size: 11px;
	background: #f5f7fa;
	padding: 1px 5px;
	border-radius: 3px;
}
.sh-conflict-chip-buttons {
	display: flex;
	gap: 6px;
	margin-top: 8px;
}
.sh-conflict-chip-buttons button {
	flex: 1;
	padding: 4px 8px;
	font-size: 11px;
	border: 1px solid #cfd4db;
	background: #fff;
	border-radius: 4px;
	cursor: pointer;
}
.sh-conflict-chip-buttons button.primary {
	background: #1a73e8;
	color: #fff;
	border-color: #1a73e8;
}
.sh-conflict-chip-buttons button:hover { filter: brightness(0.95); }

/* -------------------- Toast -------------------- */

.sh-toast {
	position: fixed;
	left: 50%;
	bottom: 24px;
	transform: translateX(-50%) translateY(10px);
	padding: 10px 16px;
	background: #333;
	color: #fff;
	border-radius: 6px;
	font-size: 13px;
	box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
	opacity: 0;
	transition: opacity 0.2s ease, transform 0.2s ease;
	z-index: 10000;
	pointer-events: none;
	max-width: 90vw;
}
.sh-toast.visible {
	opacity: 1;
	transform: translateX(-50%) translateY(0);
}

/* -------------------- Import / export modal -------------------- */

/* Modal lives at document.body and uses the site-mandated top z-indexes so
   it stacks above the 3-column layout. */

/* Named-ranges side panel: docked to the right edge, NON-modal so the user
   can click the sheet beneath it. The panel does not dim the page; it just
   floats above. Singleton: opening it again closes the existing instance. */
.sh-nr-panel {
	position: fixed;
	top: 0;
	right: 0;
	bottom: 0;
	width: 360px;
	max-width: 90vw;
	background: #fff;
	border-left: 1px solid #d0d4da;
	box-shadow: -4px 0 16px rgba(0, 0, 0, 0.08);
	z-index: 2147483645;  /* below modal backdrop, above page chrome */
	display: flex;
	flex-direction: column;
	font-size: 13px;
	color: #222;
}
.sh-nr-panel-hdr {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 10px 12px;
	border-bottom: 1px solid #e6e8ec;
	background: #f7f8fa;
}
.sh-nr-panel-hdr h3 {
	flex: 1;
	margin: 0;
	font-size: 15px;
	font-weight: 600;
}
.sh-nr-panel-hdrbtns { display: flex; gap: 6px; align-items: center; }
.sh-nr-panel-define {
	background: #2d6cdf;
	color: #fff;
	border: 1px solid #2459b8;
	border-radius: 3px;
	padding: 4px 10px;
	font-size: 12px;
	cursor: pointer;
}
.sh-nr-panel-define:hover  { background: #245bbf; }
.sh-nr-panel-define:focus  { outline: 2px solid #6aa3ff; outline-offset: 1px; }
.sh-nr-panel-close {
	background: transparent;
	border: 1px solid transparent;
	color: #555;
	font-size: 20px;
	line-height: 1;
	width: 28px;
	height: 28px;
	border-radius: 3px;
	cursor: pointer;
}
.sh-nr-panel-close:hover { background: #e6e8ec; color: #222; }
.sh-nr-panel-close:focus { outline: 2px solid #6aa3ff; outline-offset: 1px; }

.sh-nr-panel-bar {
	display: flex;
	gap: 6px;
	padding: 8px 12px;
	border-bottom: 1px solid #e6e8ec;
}
.sh-nr-panel-search {
	flex: 1;
	padding: 5px 8px;
	border: 1px solid #c7cbd1;
	border-radius: 3px;
	font-size: 13px;
	min-width: 0;
}
.sh-nr-panel-search:focus { outline: 2px solid #6aa3ff; border-color: #6aa3ff; }
.sh-nr-panel-sort {
	padding: 4px 6px;
	border: 1px solid #c7cbd1;
	border-radius: 3px;
	font-size: 12px;
	background: #fff;
}

.sh-nr-panel-list {
	flex: 1;
	overflow-y: auto;
	padding: 4px 0;
}
.sh-nr-panel-empty {
	padding: 24px 16px;
	color: #555;
	text-align: center;
}
.sh-nr-panel-emptyhint {
	margin-top: 8px;
	color: #777;
	font-size: 12px;
}

.sh-nr-panel-row {
	display: flex;
	align-items: stretch;
	gap: 4px;
	padding: 0;
	border-bottom: 1px solid #f0f1f4;
}
.sh-nr-panel-row:hover                { background: #f5f7fa; }
.sh-nr-panel-row:hover .sh-nr-panel-actions { opacity: 1; }
.sh-nr-panel-row--stale .sh-nr-panel-name   { color: #888; text-decoration: line-through; }
.sh-nr-panel-row--stale .sh-nr-panel-addr   { color: #c0392b; font-style: italic; }

.sh-nr-panel-go {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 2px;
	padding: 8px 10px;
	background: transparent;
	border: 0;
	border-radius: 3px;
	cursor: pointer;
	text-align: left;
	color: inherit;
	font-size: 13px;
}
.sh-nr-panel-go:hover  { background: rgba(45, 108, 223, 0.06); }
.sh-nr-panel-go:focus  { outline: 2px solid #6aa3ff; outline-offset: -2px; }
.sh-nr-panel-go[disabled] { cursor: not-allowed; opacity: 0.6; }
.sh-nr-panel-name { font-weight: 600; word-break: break-word; }
.sh-nr-panel-addr {
	font-family: "Courier New", monospace;
	font-size: 12px;
	color: #555;
	word-break: break-all;
}
.sh-nr-panel-usage {
	font-size: 11px;
	color: #777;
}

.sh-nr-panel-actions {
	display: flex;
	gap: 2px;
	padding: 6px 8px 6px 0;
	align-items: center;
	opacity: 0.4;
	transition: opacity 0.12s;
}
.sh-nr-panel-actions:focus-within { opacity: 1; }
.sh-nr-panel-actions button {
	background: #fff;
	border: 1px solid #c7cbd1;
	color: #333;
	border-radius: 3px;
	padding: 3px 8px;
	font-size: 11px;
	cursor: pointer;
}
.sh-nr-panel-actions button:hover  { background: #e6e8ec; }
.sh-nr-panel-actions button:focus  { outline: 2px solid #6aa3ff; outline-offset: 1px; }
.sh-nr-panel-actions .sh-nr-panel-delete {
	border-color: #d2a8a8;
	color: #a13d3d;
}
.sh-nr-panel-actions .sh-nr-panel-delete:hover {
	background: #f5e0e0;
	border-color: #a13d3d;
}

.sh-nr-panel-foot {
	padding: 8px 12px;
	border-top: 1px solid #e6e8ec;
	background: #f7f8fa;
	font-size: 11px;
	color: #666;
}

/* Activity log side panel: docked to the right edge, NON-modal. Same
   visual language as .sh-nr-panel so the two read as a family. Paged
   list of entries; filter dropdowns + paginator below. */
.sh-act-panel {
	position: fixed;
	top: 0;
	right: 0;
	bottom: 0;
	width: 380px;
	max-width: 90vw;
	background: #fff;
	border-left: 1px solid #d0d4da;
	box-shadow: -4px 0 16px rgba(0, 0, 0, 0.08);
	z-index: 2147483645;
	display: flex;
	flex-direction: column;
	font-size: 13px;
	color: #222;
}
.sh-act-panel-hdr {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 10px 12px;
	border-bottom: 1px solid #e6e8ec;
	background: #f7f8fa;
}
.sh-act-panel-hdr h3 {
	flex: 1;
	margin: 0;
	font-size: 15px;
	font-weight: 600;
}
.sh-act-panel-close {
	background: transparent;
	border: 1px solid transparent;
	color: #555;
	font-size: 20px;
	line-height: 1;
	width: 28px;
	height: 28px;
	border-radius: 3px;
	cursor: pointer;
}
.sh-act-panel-close:hover { background: #e6e8ec; color: #222; }
.sh-act-panel-close:focus { outline: 2px solid #6aa3ff; outline-offset: 1px; }

/* "Clear filter" button shown in the activity-log panel header when a
   cell scope is active (right-click cell -> View cell history). Hidden
   for the regular all-tabs view via the `hidden` attribute. */
.sh-act-clear-cell-filter {
	padding: 3px 10px;
	background: #fff;
	border: 1px solid #b0b0b0;
	border-radius: 3px;
	font-size: 11px;
	cursor: pointer;
	color: #333;
}
.sh-act-clear-cell-filter:hover { background: #f3f3f3; }
.sh-act-clear-cell-filter:focus {
	outline: 2px solid #6aa3ff;
	outline-offset: 1px;
}

/* Disabled state for the Tab dropdown while cell-scoped (the tab is
   locked to the cell's tab; user must Clear filter first to change it). */
.sh-act-panel-bar select:disabled {
	opacity: 0.55;
	cursor: not-allowed;
}

/* "Older history truncated" note prepended to the entry list when the
   server hit its 5000-row pre-filter cap. */
.sh-act-panel-truncated {
	margin: 0;
	padding: 8px 14px;
	color: #777;
	font-size: 11px;
	font-style: italic;
	text-align: center;
	border-bottom: 1px solid #eee;
	background: #fafbfc;
}

.sh-act-panel-bar {
	display: flex;
	gap: 6px;
	padding: 8px 12px;
	border-bottom: 1px solid #e6e8ec;
	flex-wrap: wrap;
}
.sh-act-panel-bar select {
	flex: 1 1 auto;
	min-width: 100px;
	padding: 4px 6px;
	border: 1px solid #c7cbd1;
	border-radius: 3px;
	font-size: 12px;
	background: #fff;
}
.sh-act-panel-bar select:focus {
	outline: 2px solid #6aa3ff;
	border-color: #6aa3ff;
}
.sh-act-panel-list {
	flex: 1 1 auto;
	overflow: auto;
	padding: 4px 0;
}
.sh-act-panel-empty,
.sh-act-panel-loading {
	padding: 16px 14px;
	margin: 0;
	color: #666;
	font-size: 13px;
}
.sh-act-entry {
	padding: 8px 12px;
	border-bottom: 1px solid #f0f2f5;
	font-size: 13px;
	line-height: 1.35;
}
.sh-act-entry:hover { background: #f5f7fa; }
.sh-act-meta {
	display: flex;
	gap: 8px;
	align-items: baseline;
	font-size: 11px;
	color: #777;
	margin-bottom: 2px;
}
.sh-act-time { flex: 0 0 auto; }
.sh-act-user {
	flex: 1 1 auto;
	color: #2459b8;
	font-weight: 600;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.sh-act-line {
	color: #222;
	overflow: hidden;
	text-overflow: ellipsis;
}
.sh-act-target { color: #555; }
.sh-act-detail {
	margin: 3px 0 0 0;
	font-size: 12px;
	color: #555;
	overflow: hidden;
	text-overflow: ellipsis;
}
.sh-act-panel-foot {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 8px 12px;
	border-top: 1px solid #e6e8ec;
	background: #f7f8fa;
	font-size: 11px;
	color: #666;
}
.sh-act-panel-pageinfo { flex: 1 1 auto; }
.sh-act-panel-pagebtns { flex: 0 0 auto; display: flex; gap: 4px; }
.sh-act-panel-pagebtns button {
	background: #fff;
	border: 1px solid #c7cbd1;
	color: #333;
	padding: 3px 8px;
	font-size: 11px;
	border-radius: 3px;
	cursor: pointer;
}
.sh-act-panel-pagebtns button:hover:not(:disabled)  { background: #eef2f7; }
.sh-act-panel-pagebtns button:focus:not(:disabled)  { outline: 2px solid #6aa3ff; outline-offset: 1px; }
.sh-act-panel-pagebtns button:disabled {
	opacity: 0.45;
	cursor: not-allowed;
}

/* Status-bar "last change" chip: appended to .sh-status-bar's right
   cluster. Compact two-line read: who, when. Wraps on narrow widths so
   the address readout stays visible. */
.sh-status-lastchange {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	padding: 1px 6px;
	margin-left: 8px;
	font-size: 11px;
	color: #555;
	border-left: 1px solid #d0d4d8;
}
.sh-status-lastchange .sh-status-lc-user {
	color: #2459b8;
	font-weight: 600;
}
.sh-status-lastchange .sh-status-lc-action { color: #555; }
.sh-status-lastchange .sh-status-lc-time   { color: #888; }

/* Transient pulse overlay drawn over a range after a "Go to" click in the
   named-ranges panel. Two pulses across 1.4s, then animationend removes the
   element. Pointer-events disabled so clicks fall through to the cells. */
@keyframes sh-range-flash-pulse {
	0%   { box-shadow: 0 0 0 0   rgba(255, 196, 0, 0.85);
	       background: rgba(255, 196, 0, 0.32); }
	25%  { box-shadow: 0 0 0 12px rgba(255, 196, 0, 0);
	       background: rgba(255, 196, 0, 0.0); }
	50%  { box-shadow: 0 0 0 0   rgba(255, 196, 0, 0.85);
	       background: rgba(255, 196, 0, 0.32); }
	75%  { box-shadow: 0 0 0 12px rgba(255, 196, 0, 0);
	       background: rgba(255, 196, 0, 0.0); }
	100% { box-shadow: 0 0 0 0   rgba(255, 196, 0, 0);
	       background: rgba(255, 196, 0, 0); }
}
@keyframes sh-range-flash-static {
	0%   { background: rgba(255, 196, 0, 0.30); border-color: rgba(255, 140, 0, 0.85); }
	100% { background: rgba(255, 196, 0, 0.00); border-color: rgba(255, 140, 0, 0.00); }
}
.sh-range-flash {
	position: absolute;
	z-index: 5;
	pointer-events: none;
	border: 2px solid rgba(255, 140, 0, 0.85);
	border-radius: 2px;
	box-sizing: border-box;
	animation: sh-range-flash-pulse 1.4s ease-out;
}
@media (prefers-reduced-motion: reduce) {
	.sh-range-flash {
		animation: sh-range-flash-static 1.4s ease-out;
		box-shadow: none;
	}
}

/* Edit-range modal: tab dropdown + text-input range. Stack the two
   label/control pairs; the generic .sh-modal input/select rules handle
   the field chrome itself. */
.sh-nr-edit-modal .sh-modal-field {
	display: flex;
	flex-direction: column;
	gap: 6px;
	margin-bottom: 10px;
}
.sh-nr-edit-modal .sh-modal-field label {
	margin-top: 4px;
}

/* Rename modal: radio group for update-vs-leave + diff list. */
.sh-nr-ren-choice {
	display: flex;
	flex-direction: column;
	gap: 8px;
	margin: 8px 0 12px;
	padding: 8px 10px;
	background: #f7f8fa;
	border: 1px solid #e6e8ec;
	border-radius: 3px;
}
.sh-nr-ren-radio {
	display: flex;
	align-items: flex-start;
	gap: 8px;
	cursor: pointer;
	font-size: 13px;
}
.sh-nr-ren-radio input { margin-top: 3px; }
.sh-nr-ren-radiodesc {
	display: block;
	color: #555;
	font-size: 12px;
	margin-top: 2px;
}
.sh-nr-ren-listlbl { margin: 4px 0; }
.sh-nr-ren-list {
	list-style: none;
	margin: 0 0 12px;
	padding: 0;
	max-height: 240px;
	overflow-y: auto;
	border: 1px solid #e6e8ec;
	border-radius: 3px;
	background: #fff;
}
.sh-nr-ren-list li {
	display: grid;
	grid-template-columns: 1fr 14px 1fr;
	grid-template-rows: auto auto;
	gap: 2px 8px;
	padding: 6px 8px;
	border-bottom: 1px solid #f0f1f4;
	font-size: 12px;
}
.sh-nr-ren-list li:last-child { border-bottom: none; }
.sh-nr-ren-addr {
	grid-column: 1 / 4;
	color: #2d6cdf;
	font-family: "Courier New", monospace;
	font-weight: 600;
}
.sh-nr-ren-old {
	grid-column: 1;
	font-family: "Courier New", monospace;
	color: #a13d3d;
	word-break: break-all;
}
.sh-nr-ren-arrow {
	grid-column: 2;
	color: #888;
	text-align: center;
}
.sh-nr-ren-new {
	grid-column: 3;
	font-family: "Courier New", monospace;
	color: #1f7a3a;
	word-break: break-all;
}

.sh-modal-backdrop {
	position: fixed;
	top: 0; left: 0; right: 0; bottom: 0;
	background: rgba(0, 0, 0, 0.45);
	z-index: 2147483646;
}
.sh-modal {
	position: fixed;
	top: 50%; left: 50%;
	transform: translate(-50%, -50%);
	min-width: 420px;
	max-width: min(640px, 92vw);
	max-height: 88vh;
	padding: 20px 24px;
	background: #fff;
	border-radius: 10px;
	box-shadow: 0 20px 60px rgba(0, 0, 0, 0.30);
	z-index: 2147483647;
	display: flex;
	flex-direction: column;
	font-size: 13px;
	color: #222;
}
.sh-modal h3 {
	margin: 0 0 4px 0;
	font-size: 18px;
	color: #1a4971;
}
.sh-modal-hint {
	margin: 0 0 12px 0;
	color: #555;
	font-size: 13px;
	line-height: 1.5;
	white-space: pre-line;
}
.sh-modal-field {
	margin-bottom: 10px;
}
.sh-modal-field label {
	display: block;
	margin-bottom: 4px;
	font-size: 12px;
	font-weight: 600;
	color: #555;
}
.sh-modal textarea {
	width: 100%;
	box-sizing: border-box;
	min-height: 180px;
	font-family: Menlo, Monaco, Consolas, monospace;
	font-size: 12px;
	padding: 8px 10px;
	border: 1px solid #cfd4db;
	border-radius: 4px;
	resize: vertical;
}
.sh-modal textarea:focus { outline: 2px solid #4a90d9; outline-offset: 1px; }
.sh-modal input[type="text"],
.sh-modal input[type="search"],
.sh-modal select {
	width: 100%;
	box-sizing: border-box;
	padding: 7px 10px;
	font-size: 14px;
	border: 1px solid #cfd4db;
	border-radius: 4px;
	background: #fff;
}
.sh-modal input[type="text"]:focus,
.sh-modal input[type="search"]:focus,
.sh-modal select:focus { outline: 2px solid #4a90d9; outline-offset: 1px; border-color: #4a90d9; }
.sh-modal input[type=file] {
	font-size: 12px;
}
.sh-modal-radios { display: flex; gap: 16px; }
.sh-modal-radios label {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	font-weight: normal;
	cursor: pointer;
}
.sh-modal-buttons {
	display: flex;
	gap: 8px;
	justify-content: flex-end;
	margin-top: 14px;
}
.sh-modal-buttons button {
	padding: 7px 14px;
	font-size: 13px;
	border: 1px solid #cfd4db;
	background: #fff;
	color: #333;
	border-radius: 4px;
	cursor: pointer;
}
.sh-modal-buttons button.primary {
	background: #1a73e8;
	color: #fff;
	border-color: #1a73e8;
}
.sh-modal-buttons button.danger {
	background: #c0392b;
	color: #fff;
	border-color: #c0392b;
}
.sh-modal-buttons button:hover { filter: brightness(0.95); }
.sh-modal-buttons button:focus-visible {
	outline: 2px solid #4a90d9;
	outline-offset: 2px;
}
.sh-modal-buttons button.danger:focus-visible {
	outline-color: #c0392b;
}
.sh-modal-buttons button:disabled { opacity: 0.5; cursor: not-allowed; }

/* Confirm modal: tighter than the bigger import / find-replace panels.
   Message text is sized up from .sh-modal-hint defaults so the question
   the user is being asked is fully readable (WCAG: avoid small low-
   contrast text for decision-critical content). */
.sh-confirm {
	min-width: 360px;
	max-width: min(480px, 92vw);
}
.sh-confirm .sh-confirm-msg {
	color: #222;
	font-size: 14px;
	line-height: 1.5;
	margin-bottom: 4px;
	white-space: pre-wrap;
}

/* -------------------- Accessibility helpers -------------------- */

/* Visually-hidden live region for screen-reader announcements. Kept
   in the DOM so assistive tech can read it; positioned offscreen
   via the clip technique so sighted users never see it. */
.sh-sr-live {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* -------------------- Tab context menu (keyboard-accessible reorder) -------------------- */

.sh-tab-menu-btn {
	margin-left: 6px;
	padding: 0 4px;
	font-size: 14px;
	line-height: 1;
	color: inherit;
	opacity: 0.6;
	background: transparent;
	border: 0;
	cursor: pointer;
	border-radius: 3px;
}
.sh-tab-menu-btn:hover,
.sh-tab-menu-btn:focus {
	opacity: 1;
	outline: 2px solid rgba(255, 255, 255, 0.6);
}
.sh-tab-menu-btn:focus { outline-color: #4a90d9; }
.sh-tab.active .sh-tab-menu-btn:focus { outline-color: rgba(255, 255, 255, 0.9); }

/* Generic dropdown menu used by the tab "..." popover and the toolbars
   Data/View/etc. menus. Fixed-position so viewport coordinates from
   getBoundingClientRect() match regardless of page scroll. */
.sh-menu {
	position: fixed;
	background: #fff;
	border: 1px solid #cfd4db;
	border-radius: 6px;
	box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
	padding: 4px 0;
	min-width: 160px;
	z-index: 2147483647;
	font-size: 13px;
	color: #222;
}
.sh-menu button {
	display: flex;
	align-items: center;
	width: 100%;
	text-align: left;
	padding: 6px 14px 6px 8px;
	border: 0;
	background: transparent;
	cursor: pointer;
	font-size: 13px;
	color: #222;
}
.sh-menu button:hover:not(:disabled) { background: #eef2f7; }
/* Visible focus indicator. WCAG 1.4.11 / 2.4.7 require >=3:1 against the
   surrounding background; the bg tint alone (#eef2f7 vs white = 1.10:1)
   was failing. outline survives Windows High Contrast Mode where
   box-shadow does not. */
.sh-menu button:focus-visible {
	outline: 2px solid #1a73e8;
	outline-offset: -2px;
	background: #eef2f7;
}
.sh-menu button:disabled,
.sh-menu button[aria-disabled="true"] {
	color: #767676;     /* 4.54:1 on white; opacity 0.4 fell to 2.6:1 */
	cursor: not-allowed;
}
.sh-menu-check {
	display: inline-block;
	width: 18px;
	text-align: center;
	color: #1a73e8;
	font-weight: 700;
	flex: 0 0 auto;
}
.sh-menu-label { flex: 1 1 auto; }
.sh-menu-shortcut {
	margin-left: auto;
	padding-left: 24px;
	color: #595959;     /* 7.0:1 on white */
	font-size: 11px;
	font-family: -apple-system-monospaced, "SF Mono", Menlo, Consolas, monospace;
	flex: 0 0 auto;
}
.sh-menu-item--checked { color: #0d47a1; }

/* Cell-level font family picker. Each row's label is rendered in its
   own font-family (set inline by openFontFamilyPicker) so the preview
   matches what will apply to the cell. */
.sh-font-picker {
	min-width: 200px;
	max-height: 360px;
	overflow-y: auto;
}
.sh-font-picker-row {
	display: flex;
	align-items: center;
	gap: 8px;
	width: 100%;
	padding: 4px 8px;
	border: 0;
	background: transparent;
	cursor: pointer;
	text-align: left;
	font-size: 14px;
	color: #1f2630;
}
.sh-font-picker-row:hover,
.sh-font-picker-row:focus {
	background: #eef3ff;
	outline: none;
}
.sh-font-picker-row .sh-menu-label {
	flex: 1 1 auto;
}

/* Cell-level font size picker. Most rows reuse the standard sh-menu-item
   chrome; the trailing custom-numeric-input row gets its own row layout. */
.sh-font-size-picker { min-width: 120px; }
.sh-font-size-custom-row {
	display: flex;
	align-items: center;
	gap: 6px;
	padding: 6px 10px;
	border-top: 1px solid #e5e9ef;
	margin-top: 4px;
	font-size: 12px;
	color: #595959;
}
.sh-font-size-custom-input {
	flex: 1 1 auto;
	width: 0;
	padding: 3px 6px;
	border: 1px solid #c2c7cd;
	border-radius: 3px;
	font-size: 12px;
	color: #1f2630;
}
.sh-font-size-custom-input:focus {
	outline: none;
	border-color: #4a86d9;
	box-shadow: 0 0 0 2px rgba(74, 134, 217, 0.25);
}

.sh-menu-separator {
	height: 1px;
	background: #e5e9ef;
	margin: 4px 6px;
}

/* Chevron on toolbar menu buttons. */
.sh-toolbar-menu-btn::after {
	content: " \25BE"; /* down triangle */
	font-size: 10px;
	opacity: 0.7;
	margin-left: 2px;
}

/* -------------------- Color picker (Phase 2a Format menu) ------------- */

.sh-color-picker {
	padding: 8px;
}
.sh-color-grid {
	display: grid;
	grid-template-columns: repeat(6, 24px);
	gap: 4px;
}
/* Recent-colors MRU strip at the top of the fill and tab color pickers.
   Label stacks above the row (column flex) so the strips width matches
   the main grid below, regardless of swatch count. Without this the
   menu stretches sideways every time a new recent gets added.
   No horizontal padding because the parent .sh-color-picker already
   has padding: 8px; doubling would indent past the swatch grid. */
.sh-color-recent {
	display: flex;
	flex-direction: column;
	gap: 4px;
	padding: 0 0 6px 0;
	border-bottom: 1px solid #e5e7eb;
	margin-bottom: 6px;
}
.sh-color-recent-label {
	font-size: 11px;
	color: #6b7280;
}
/* Grid (not flex) so the swatches stay 24x24. The flex parent .sh-menu
   has a 'button { width: 100% }' rule that outranks .sh-color-swatch on
   specificity; grid columns sized to 24px override that. Matches the
   main .sh-color-grid layout below for visual consistency. */
.sh-color-recent-row {
	display: grid;
	grid-template-columns: repeat(6, 24px);
	gap: 4px;
}
/* Custom color row at the bottom of the picker: native OS color popup
   + hex text field + Apply button. Stays on one line; the hex field
   flexes to absorb leftover width inside the menus content area. */
.sh-color-custom {
	display: flex;
	align-items: center;
	gap: 6px;
	padding-top: 6px;
	border-top: 1px solid #e5e7eb;
	margin-top: 6px;
}
.sh-color-custom-native {
	width: 24px;
	height: 24px;
	padding: 0;
	border: 1px solid #d0d4d9;
	border-radius: 4px;
	background: #fff;
	cursor: pointer;
	flex: 0 0 auto;
	box-sizing: border-box;
}
.sh-color-custom-native::-webkit-color-swatch-wrapper { padding: 0; }
.sh-color-custom-native::-webkit-color-swatch { border: 0; border-radius: 3px; }
.sh-color-custom-native::-moz-color-swatch    { border: 0; border-radius: 3px; }
.sh-color-custom-hex {
	flex: 0 0 auto;
	width: 84px;
	min-width: 0;
	height: 24px;
	padding: 0 6px;
	border: 1px solid #d0d4d9;
	border-radius: 4px;
	background: #fff;
	font: 12px/1 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
	box-sizing: border-box;
}
.sh-color-custom-hex:focus { outline: 2px solid #1a73e8; outline-offset: -1px; border-color: #1a73e8; }
.sh-color-custom-hex--invalid { border-color: #d0021b; }
/* Scoped to .sh-color-custom so specificity beats .sh-menu button
   (0,2,0 vs 0,1,1), which otherwise forces width: 100% and breaks the
   flex layout. Same lesson as the swatch grid trap above. */
.sh-color-custom .sh-color-custom-apply {
	flex: 0 0 auto;
	width: auto;
	height: 24px;
	padding: 0 10px;
	border: 1px solid #1a73e8;
	border-radius: 4px;
	background: #1a73e8;
	color: #fff;
	font-size: 12px;
	cursor: pointer;
	display: inline-flex;
	align-items: center;
	text-align: center;
}
.sh-color-custom .sh-color-custom-apply:hover { background: #1561c2; border-color: #1561c2; }
.sh-color-custom .sh-color-custom-apply:focus-visible { outline: 2px solid #1a73e8; outline-offset: 2px; }
.sh-color-swatch {
	width: 24px;
	height: 24px;
	border: 1px solid #d0d4d9;
	border-radius: 4px;
	padding: 0;
	cursor: pointer;
	background: #fff;
	box-sizing: border-box;
}
.sh-color-swatch:hover,
.sh-color-swatch:focus {
	outline: 2px solid #1a73e8;
	outline-offset: 1px;
}
.sh-color-swatch--clear {
	background:
		linear-gradient(45deg, transparent calc(50% - 1px), #d0021b calc(50% - 1px),
		                       #d0021b calc(50% + 1px), transparent calc(50% + 1px)),
		#fff;
}
.sh-color-swatch--selected {
	outline: 2px solid #1a73e8;
	outline-offset: 1px;
}

/* -------------------- Border picker (Google parity) ------------------
   Compact 2-column layout: a 2x5 pictogram grid on the left, two sub-
   triggers (color pencil + line-style) stacked on the right. The color
   picker opens as a sub-popover anchored off the pencil; line-style is
   a tiny inline radio-list menu rooted off its own trigger. Both share
   the openSubMenuEl + closeSubDropdown plumbing. */

.sh-border-picker {
	display: flex;
	gap: 6px;
	padding: 8px;
	align-items: flex-start;
}
.sh-border-pictogram-col {
	display: grid;
	grid-template-columns: repeat(5, 40px);
	grid-auto-rows: 40px;
	gap: 3px;
}
/* Specificity: .sh-menu button (0,1,1) sets width:100%, asymmetric padding,
   and display:flex with text-align:left, which would clobber our 40x40
   centered icons. Prefix with .sh-menu (-> 0,2,0) to outrank. Same for
   the sub-trigger and line-style-opt rules below. */
.sh-menu .sh-border-preset {
	box-sizing: border-box;
	width: 40px;
	height: 40px;
	padding: 0;
	margin: 0;
	background: transparent;
	border: 1px solid transparent;
	border-radius: 4px;
	cursor: pointer;
	display: grid;
	place-items: center;
	color: #222;
	line-height: 0;
	text-align: center;
}
.sh-menu .sh-border-preset:hover,
.sh-menu .sh-border-preset:focus {
	background: #eef3fa;
	border-color: #c5d3e7;
	outline: none;
}
.sh-menu .sh-border-preset svg { display: block; }

/* Sub-trigger column (pencil + line-style). The pencil's underline bar
   shows the currently-selected stroke color; the line-style trigger's
   preview line shows the chosen line style. */
.sh-border-sub-col {
	display: flex;
	flex-direction: column;
	gap: 4px;
	padding-left: 6px;
	margin-left: 2px;
	border-left: 1px solid #e3e6eb;
}
.sh-menu .sh-border-sub-trigger {
	box-sizing: border-box;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 4px;
	padding: 4px 6px;
	min-width: 70px;
	width: auto;
	height: 40px;
	background: transparent;
	border: 1px solid #d0d4da;
	border-radius: 4px;
	cursor: pointer;
	font-size: 13px;
	color: #222;
	text-align: center;
}
.sh-menu .sh-border-sub-trigger:hover,
.sh-menu .sh-border-sub-trigger:focus {
	background: #eef3fa;
	border-color: #c5d3e7;
	outline: none;
}
.sh-border-sub-icon {
	font-size: 14px;
	line-height: 1;
}
.sh-border-sub-bar {
	display: inline-block;
	width: 18px;
	height: 4px;
	border-radius: 1px;
	background: #000;
	border: 1px solid #c2c7cd;
}
.sh-border-sub-line {
	display: inline-block;
	width: 26px;
	height: 0;
	border-top: 1.5px solid #444;
}
.sh-border-sub-line--thin    { border-top: 1px   solid  #444; }
.sh-border-sub-line--medium  { border-top: 2px   solid  #444; }
.sh-border-sub-line--thick   { border-top: 3px   solid  #444; }
.sh-border-sub-line--dashed  { border-top: 1.5px dashed #444; }
.sh-border-sub-line--dotted  { border-top: 1.5px dotted #444; }
.sh-border-sub-line--double  { border-top: 3px   double #444; }
.sh-border-sub-caret {
	font-size: 10px;
	color: #5f6368;
}

/* Line-style sub-menu (small radio-list popover anchored off the line-
   style trigger). Each option pairs a label with a preview of the
   actual line style so the choice is visually self-evident. */
.sh-border-line-style-sub {
	padding: 4px;
	min-width: 140px;
}
.sh-menu .sh-border-line-style-opt {
	display: flex;
	align-items: center;
	gap: 8px;
	width: 100%;
	padding: 6px 8px;
	background: transparent;
	border: 1px solid transparent;
	border-radius: 4px;
	cursor: pointer;
	font-size: 13px;
	color: #222;
	text-align: left;
}
.sh-menu .sh-border-line-style-opt:hover,
.sh-menu .sh-border-line-style-opt:focus {
	background: #eef3fa;
	border-color: #c5d3e7;
	outline: none;
}
.sh-menu .sh-border-line-style-opt--checked {
	background: #d2e3fc;
}
.sh-border-line-style-preview {
	flex: 0 0 36px;
}

/* -------------------- Bottom sheet (phone editor) -------------------- */

@media (max-width: 768px) {
	.sh-grid-container {
		min-height: 300px;
	}
	/* Kill the browser double-tap-to-zoom (and the 300ms click delay) inside
	   the grid so a double-tap reliably opens the cell editor. Pan/scroll and
	   pinch-zoom still work. */
	.sh-body { touch-action: manipulation; }
}

.sh-bottom-sheet-backdrop {
	position: fixed;
	top: 0; left: 0; right: 0; bottom: 0;
	background: rgba(0, 0, 0, 0.35);
	z-index: 2147483646;
	opacity: 0;
	transition: opacity 0.2s ease;
}
.sh-bottom-sheet-backdrop.visible { opacity: 1; }

.sh-bottom-sheet {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	background: #fff;
	border-top: 1px solid #d9dde3;
	border-radius: 12px 12px 0 0;
	padding: 16px 18px 24px;
	max-height: 60vh;
	overflow-y: auto;
	z-index: 2147483647;
	box-shadow: 0 -6px 20px rgba(0, 0, 0, 0.18);
	transform: translateY(100%);
	transition: transform 0.2s ease;
}
.sh-bottom-sheet.visible { transform: translateY(0); }
.sh-bottom-sheet-header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin-bottom: 10px;
}
.sh-bottom-sheet-address {
	font-size: 15px;
	font-weight: 600;
	color: #1a4971;
}
.sh-bottom-sheet-close {
	padding: 6px 12px;
	font-size: 13px;
	border: 1px solid #cfd4db;
	background: #fff;
	border-radius: 4px;
	cursor: pointer;
	color: #333;
}
.sh-bottom-sheet-value {
	white-space: pre-wrap;
	word-break: break-word;
	font-size: 14px;
	line-height: 1.5;
	color: #222;
	background: #f5f7fa;
	border: 1px solid #e3e6eb;
	border-radius: 6px;
	padding: 10px 12px;
	min-height: 40px;
	margin: 0;
	font-family: inherit;
}
.sh-bottom-sheet-empty {
	color: #888;
	font-style: italic;
}
.sh-bottom-sheet-value--tappable { cursor: pointer; }

/* Read tier: a slim horizontal select-bar (A1 + value + Edit + close) that
   overrides the base sheet's tall padded box, so a tap shows a light strip
   (not a modal) and the grid above stays live. */
.sh-bottom-sheet--read {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 8px 12px;
	max-height: none;
	overflow: visible;
	border-radius: 0;
}
.sh-bottom-sheet--read .sh-bottom-sheet-address {
	flex: 0 0 auto;
	padding: 4px 8px;
	background: #eef3f8;
	border-radius: 4px;
}
.sh-bottom-sheet-barvalue {
	flex: 1 1 auto;
	min-width: 0;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	font-size: 15px;
	color: #222;
}
.sh-bottom-sheet--read .sh-bottom-sheet-close {
	flex: 0 0 auto;
	min-width: 44px;
	min-height: 44px;
	padding: 0;
	font-size: 22px;
	line-height: 1;
}

/* Buttons. 44px min keeps every control a comfortable touch target for the
   site's older / reduced-vision members. */
.sh-bottom-sheet-edit,
.sh-bottom-sheet-btn {
	min-height: 44px;
	padding: 0 18px;
	font-size: 15px;
	font-weight: 600;
	border-radius: 6px;
	cursor: pointer;
}
.sh-bottom-sheet-edit {
	flex: 0 0 auto;
	border: 1px solid #1a4971;
	background: #1a4971;
	color: #fff;
}

/* Edit tier: header (A1 + Cancel/Save) above a full-width textarea. */
.sh-bottom-sheet-actions {
	display: flex;
	gap: 8px;
}
.sh-bottom-sheet-cancel {
	border: 1px solid #cfd4db;
	background: #fff;
	color: #333;
}
.sh-bottom-sheet-save {
	border: 1px solid #1a4971;
	background: #1a4971;
	color: #fff;
}
.sh-bottom-sheet-input {
	display: block;
	width: 100%;
	box-sizing: border-box;
	margin-top: 8px;
	min-height: 96px;
	max-height: 32vh;
	padding: 12px;
	/* >=16px keeps iOS Safari from auto-zooming the page on focus. */
	font-size: 16px;
	line-height: 1.5;
	color: #111;
	border: 1px solid #b8c0cc;
	border-radius: 6px;
	font-family: inherit;
	resize: none;
}
.sh-bottom-sheet-input:focus {
	outline: 2px solid #1a6fb5;
	outline-offset: 1px;
	border-color: #1a6fb5;
}

/* -------------------- Function autocomplete + signature hint -------- */
/* Dropdown of function-name matches during cell editing. */
.sh-fnac-list {
	position: fixed;
	background: #fff;
	border: 1px solid #cfd4db;
	border-radius: 4px;
	box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
	z-index: 2147483647;
	min-width: 200px;
	max-width: 320px;
	padding: 4px 0;
	font-size: 13px;
	overflow: hidden;
}
.sh-fnac-row {
	display: flex;
	align-items: baseline;
	gap: 8px;
	padding: 4px 10px;
	cursor: pointer;
	white-space: nowrap;
	user-select: none;
}
.sh-fnac-row--selected { background: #1a73e8; color: #fff; }
.sh-fnac-row-name { font-weight: 600; }
.sh-fnac-row-sig  { color: #6b7280; font-size: 11px; }
.sh-fnac-row--selected .sh-fnac-row-sig { color: rgba(255, 255, 255, 0.85); }

/* Signature hint tooltip once cursor is inside a function call. */
.sh-fnhint {
	position: fixed;
	background: #222;
	color: #fff;
	border-radius: 4px;
	box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
	z-index: 2147483647;
	padding: 6px 10px;
	font-size: 12px;
	max-width: 360px;
	line-height: 1.4;
	pointer-events: none;
}
.sh-fnhint-name { font-weight: 600; }
.sh-fnhint-args b { font-weight: 700; color: #ffe28a; }
.sh-fnhint-desc { color: #b8b8b8; font-size: 11px; margin-top: 4px; }

/* -------------------- In-formula range picker ---------------------- */
/* Marching-ants box drawn over the cells being picked. A pulse on
   border-color reads as "active pending pick" without the cross-browser
   pain of an animated dashed-stroke gradient. */
.sh-fpick-ants {
	position: absolute;
	border: 2px dashed #1a73e8;
	background: rgba(26, 115, 232, 0.08);
	pointer-events: none;
	box-sizing: border-box;
	animation: sh-fpick-pulse 0.8s ease-in-out infinite alternate;
	z-index: 5;
}
@keyframes sh-fpick-pulse {
	from { border-color: #1a73e8; }
	to   { border-color: #4a90d9; }
}

/* Print view --------------------------------------------------------- */

/* Hidden by default; revealed only during our window.print() flow via
   the body.sh-printing class + @media print rules below. The grid is
   absolute-positioned and prints as a huge unreadable single page
   unless we swap it out for the flat table. */
#sh-print-root {
	display: none;
}

@media print {
	body.sh-printing > *:not(#sh-print-root) {
		display: none !important;
	}
	body.sh-printing #sh-print-root {
		display: block;
	}

	@page { margin: 0.5in; }

	/* Chrome strips background colors and inverts dark fills on print
	   by default. exact preserves cell fills + font colors. */
	#sh-print-root,
	#sh-print-root * {
		-webkit-print-color-adjust: exact;
		print-color-adjust: exact;
	}
}

.sh-print-title {
	margin: 0 0 8px;
	font-size: 14pt;
	font-weight: 600;
	color: #000;
}
.sh-print-table {
	border-collapse: collapse;
	width: 100%;
	font-size: 9pt;
	color: #000;
	table-layout: fixed;
}
/* Resolved entity tags ({user:}/{item:}/...) can carry an icon or nested DOM;
   clamp them so one cannot blow up a print row (the print <td> does not carry
   the .sh-cell--ml class the live grid uses for the same clamp above). */
#sh-print-root .sh-dyn { display: inline; white-space: nowrap; }
#sh-print-root .sh-dyn img { max-height: 1.8em; vertical-align: middle; }
#sh-print-root .sh-dyn * { max-width: 100%; vertical-align: middle; }
.sh-print-table th,
.sh-print-table td {
	border: 0.5pt solid #888;
	padding: 2px 4px;
	vertical-align: top;
	overflow-wrap: break-word;
	word-wrap: break-word;
}
.sh-print-table thead th {
	background: #f0f0f0;
	text-align: center;
	font-weight: 600;
}
.sh-print-table .sh-print-rownum {
	background: #f0f0f0;
	text-align: right;
	font-weight: 600;
	min-width: 28px;
}
.sh-print-table tr {
	page-break-inside: avoid;
}

/* About Sheets modal --------------------------------------------------- */

/* Tight feature-bullet list. Inherits .sh-modal-hint color from siblings. */
.sh-about .sh-about-features {
	margin: 4px 0 12px 0;
	padding-left: 20px;
	color: #444;
	font-size: 13px;
	line-height: 1.6;
}
.sh-about .sh-about-features li {
	margin: 2px 0;
}
.sh-about .sh-about-foot {
	margin-top: 4px;
	color: #777;
	font-style: italic;
	font-size: 12px;
}

/* Icon toolbar (Sheets-style quick-access row) --------------------------- */

/* Second toolbar row directly below the menu row. Same surface tone, tighter
   padding. Single line (flex-nowrap): groups that don't fit are moved into the
   secondary .sh-toolbar-overflow row behind the "⋮" kebab by _reflowToolbar
   (ui.js). overflow:hidden clips the lone kept group at extreme narrowness. */
.sh-toolbar-icons {
	display: flex;
	align-items: center;
	gap: 2px;
	padding: 4px 12px;
	background: #f5f7fa;
	border-bottom: 1px solid #e3e6eb;
	flex-shrink: 0;
	flex-wrap: nowrap;
	overflow: hidden;
}

/* Each divider-delimited cluster of buttons is wrapped in a group so the
   overflow reflow can move it as a unit. The visual divider between groups is
   the left-border below (replaces the old .sh-toolbar-divider span); the
   leading group in either row gets no border via the sibling selector. */
.sh-icon-group {
	display: inline-flex;
	align-items: center;
	gap: 2px;
	flex: 0 0 auto;
}
.sh-icon-group + .sh-icon-group {
	margin-left: 4px;
	padding-left: 6px;
	border-left: 1px solid #d0d4da;
}

/* Secondary "more" row: holds the groups pushed out of the icon row, revealed
   when the "⋮" kebab is toggled open. Same surface tone as the icon row; wraps
   internally so every overflowed group stays reachable on very narrow widths.
   The [hidden] override is required because display:flex out-specifies the bare
   UA [hidden] rule (cf. .sh-status-bar[hidden]). */
.sh-toolbar-overflow {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 2px;
	row-gap: 4px;
	padding: 4px 12px;
	background: #f5f7fa;
	border-bottom: 1px solid #e3e6eb;
	flex-shrink: 0;
}
.sh-toolbar-overflow[hidden] {
	display: none;
}

.sh-icon-btn {
	background: transparent;
	border: 1px solid transparent;
	border-radius: 4px;
	padding: 4px 7px;
	font-size: 15px;
	line-height: 1;
	color: #333;
	cursor: pointer;
	min-width: 32px;
	height: 32px;
}
.sh-icon-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.sh-icon-btn:hover    { background: #e6ebf2; }
.sh-icon-btn:focus    { outline: 2px solid #4a90d9; outline-offset: 1px; }
.sh-icon-btn:active   { background: #d4dce6; }

/* Buttons whose glyph IS the text label ($, %, .0, .00, 123 ▾,
   100% ▾, V ▾, Merge, Filter ▾): smaller font + horizontal padding so
   the text reads cleanly without crowding the borders. */
.sh-icon-btn--text {
	font-size: 12px;
	padding: 4px 8px;
}

/* Image-icon toolbar buttons (Bold / Italic / Underline / Strikethrough /
   Text-color / Horizontal-align) reuse the v3 editor's SVG art set so the
   Sheets toolbar matches the cell editor. addIconImg renders a 20x20
   <img>; the 3-state src swap (inactive / hover / active) is wired in
   render.js, mirroring editor/toolbar.js. */
.sh-icon-btn--img {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 1px;
}
.sh-icon-btn--img img {
	width: 20px;
	height: 20px;
	display: block;
}
/* Dropdown chevron appended to menu-opening image buttons (align). */
.sh-icon-caret {
	font-size: 10px;
	line-height: 1;
	color: #555;
}

/* Text color icon: the colored underline bar sits below the glyph and
   shows the color that will be applied. Uses a CSS custom property set
   by _syncFontIconsToSelection so the bar reflects the current selection. */
.sh-icon-btn--text-color {
	position: relative;
	padding-bottom: 8px;
}
.sh-icon-btn--text-color::after {
	content: "";
	position: absolute;
	left: 7px;
	right: 7px;
	bottom: 5px;
	height: 3px;
	background: var(--sh-text-color, transparent);
	border-radius: 1px;
}

/* "Checked" state: this selection has the corresponding mark applied
   uniformly. Slightly stronger than :hover so the user can see "this is on"
   even when the cursor is hovering somewhere else. Mirrored visual to the
   v3 cell editor's active-toolbar-button state. */
.sh-icon-btn--checked {
	background: #d2e3fc;
	border-color: #c0d6f7;
}
.sh-icon-btn--checked:hover { background: #c0d6f7; }

/* Overflow "⋮" kebab: revealed by _reflowToolbar when groups don't fit.
   margin-left:auto pins it to the right edge when the row has slack (the move
   loop can stop before the row is packed tight); under true overflow the auto
   margin resolves to 0, so it does not perturb the scrollWidth measurement.
   No [hidden] override needed: .sh-icon-btn sets no display, so the bare UA
   [hidden]{display:none} already wins. */
.sh-icon-btn--overflow {
	font-size: 18px;
	margin-left: auto;
}

/* Paint-button active/locked styling lives near the top of this file with the
   other .sh-toolbar-paint-btn rules (the --active fill needs an .sh-icon-btn
   specificity bump to beat the base transparent background). */
