/**
 * chapterwright/code-snippet — front end and editor.
 *
 * Reuses the --hsrtech-code / --hsrtech-code-ink variables defined in
 * assets/css/chapterwright.css so a snippet matches the surrounding
 * chapter's <pre>/<code> look in both light and dark reading mode, when
 * that stylesheet happens to also be loaded (book/chapter pages — see
 * hsrtech_enqueue_public_assets(), public/assets.php). Every var() has a
 * literal fallback, though, so this stylesheet — which, unlike
 * chapterwright.css, auto-loads on *any* page containing the block, via
 * block.json's own "style" registration — never depends on that other
 * stylesheet actually being present. A code block in an ordinary blog post
 * looks the same as one in a chapter for exactly that reason.
 *
 * The --hsrtech-tok-* variables and .hsrtech-tok--* rules below (applied by
 * assets/js/code-highlight.js, to this block and to plain core Code blocks
 * it auto-wraps on book/chapter pages) used to live in chapterwright.css
 * instead — moved here so they're available everywhere this block is,
 * not only where chapterwright.css happens to also be loaded. Token colors
 * are fixed regardless of reading mode (a code block's background is always
 * dark, in both this plugin's light and dark mode), so — unlike
 * --hsrtech-code/--hsrtech-code-ink above — there's no mode-reactive
 * variant of these to keep in sync with chapterwright.css's own.
 *
 * @package Chapterwright
 */

:root {
	--hsrtech-tok-comment: #9099ab;
	--hsrtech-tok-string: #9ece6a;
	--hsrtech-tok-number: #ff9e64;
	--hsrtech-tok-keyword: #c586c0;
	--hsrtech-tok-function: #61afef;
	--hsrtech-tok-variable: #e5c07b;
	--hsrtech-tok-tag: #e06c75;
	--hsrtech-tok-attr-name: #d19a66;
	--hsrtech-tok-attr-value: #98c379;
	--hsrtech-tok-property: #56b6c2;
	--hsrtech-tok-punctuation: rgba(245, 242, 234, 0.55);
}

.hsrtech-tok--comment { color: var(--hsrtech-tok-comment); font-style: italic; }
.hsrtech-tok--string { color: var(--hsrtech-tok-string); }
.hsrtech-tok--attr-value { color: var(--hsrtech-tok-attr-value); }
.hsrtech-tok--number, .hsrtech-tok--boolean { color: var(--hsrtech-tok-number); }
.hsrtech-tok--keyword { color: var(--hsrtech-tok-keyword); }
.hsrtech-tok--function { color: var(--hsrtech-tok-function); }
.hsrtech-tok--variable { color: var(--hsrtech-tok-variable); }
.hsrtech-tok--tag { color: var(--hsrtech-tok-tag); }
.hsrtech-tok--attr-name { color: var(--hsrtech-tok-attr-name); }
.hsrtech-tok--property { color: var(--hsrtech-tok-property); }
.hsrtech-tok--punctuation, .hsrtech-tok--operator { color: var(--hsrtech-tok-punctuation); }

.hsrtech-code {
	margin: 2rem 0;
}

.hsrtech-code__caption {
	color: var(--hsrtech-muted, #716e67);
	font-size: 0.85rem;
	margin: 0 0 0.5rem;
}

.hsrtech-code__frame {
	background: var(--hsrtech-code, #202124);
	border-radius: 0.8rem;
	color: var(--hsrtech-code-ink, #f5f2ea);
	position: relative;
}

.hsrtech-code__lang {
	color: var(--hsrtech-code-ink, #f5f2ea);
	font-family: inherit;
	font-size: 0.68rem;
	font-weight: 700;
	left: 1.5rem;
	letter-spacing: 0.08em;
	opacity: 0.55;
	position: absolute;
	top: 1rem;
}

/* Groups the frame-corner buttons — copy, and the wrap toggle — in one
   positioned flex row instead of each button carrying its own fixed `right`
   offset. That matters now that either one can be turned off per block
   (hideCopyButton / hideWrapToggle, render.php): with a flex row, whichever
   one is still shown just slides over into the gap; with two independently
   `right`-offset absolutely-positioned buttons, hiding one would leave an
   empty gap where it used to sit instead. Order in the markup (wrap toggle,
   then copy) keeps copy closest to the corner when both are present,
   matching its original always-been-there position. wrapPlainBlock()
   (assets/js/code-highlight.js) reuses this same wrapper around its own
   lone copy button for the same reason, even though it never renders a
   wrap toggle at all. */
.hsrtech-code__actions {
	display: flex;
	gap: 0.6rem;
	position: absolute;
	right: 0.9rem;
	top: 0.8rem;
}

.hsrtech-code__wrap-toggle,
.hsrtech-code__copy {
	align-items: center;
	background: rgba(255, 255, 255, 0.08);
	border: 1px solid rgba(255, 255, 255, 0.18);
	border-radius: 999px;
	color: var(--hsrtech-code-ink, #f5f2ea);
	cursor: pointer;
	display: flex;
	flex: none;
	height: 2.1rem;
	justify-content: center;
	padding: 0;
	/* Positions each button's own [data-tooltip] bubble below, relative to
	   itself rather than to .hsrtech-code__actions (the shared positioned
	   ancestor otherwise closest to both buttons) — without this, both
	   tooltips would anchor to the actions row's own top-right corner
	   instead of to whichever button is actually being hovered. */
	position: relative;
	width: 2.1rem;
}

.hsrtech-code__wrap-toggle:hover,
.hsrtech-code__wrap-toggle:focus-visible,
.hsrtech-code__copy:hover,
.hsrtech-code__copy:focus-visible {
	background: rgba(255, 255, 255, 0.18);
}

/* CSS-only tooltip (no JS) for these two icon-only buttons — the browser's
   own title attribute (what these used before) doesn't reliably show a
   tooltip on <button> elements in Safari at all, a long-standing WebKit
   limitation, so this mirrors the same data-tooltip + ::after pattern
   .hsrtech-toc-jump (chapterwright.css) already uses instead, rather than
   relying on title. Positioned BELOW the button rather than above (that
   other button's own convention): these sit near the very top of the code
   frame, where a tooltip opening upward would have far less clearance
   before running into whatever content sits above the block on the page.
   Content comes from data-tooltip so the same translated string also
   lives in aria-label (render.php, and view.js as it changes) for screen
   readers, without duplicating it here. Colors are hardcoded rather than
   any --hsrtech-* custom property, same reasoning as everywhere else in
   this file: this stylesheet never depends on chapterwright.css also
   being loaded, and needs to read clearly against whatever page
   background happens to be behind it, not just this block's own dark
   frame. */
.hsrtech-code__wrap-toggle[data-tooltip]::after,
.hsrtech-code__copy[data-tooltip]::after {
	background: rgba(20, 20, 20, 0.95);
	border-radius: 0.4rem;
	color: #fff;
	content: attr(data-tooltip);
	font-size: 0.72rem;
	font-weight: 600;
	opacity: 0;
	padding: 0.35rem 0.6rem;
	pointer-events: none;
	position: absolute;
	right: 0;
	top: calc(100% + 0.5rem);
	transform: translateY(-0.25rem);
	transition: opacity 0.15s ease, transform 0.15s ease;
	white-space: nowrap;
	z-index: 1;
}

.hsrtech-code__wrap-toggle[data-tooltip]:hover::after,
.hsrtech-code__wrap-toggle[data-tooltip]:focus-visible::after,
.hsrtech-code__copy[data-tooltip]:hover::after,
.hsrtech-code__copy[data-tooltip]:focus-visible::after {
	opacity: 1;
	transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
	.hsrtech-code__wrap-toggle[data-tooltip]::after,
	.hsrtech-code__copy[data-tooltip]::after {
		transition: none;
	}
}

.hsrtech-code__copy.is-copied {
	background: var(--hsrtech-accent, #f45d48);
	border-color: transparent;
	color: #fff;
}

/* A visible "pressed" look while wrap is on — driven by the figure's own
   .hsrtech-code--wrap (view.js toggles that, not any class on this button
   itself), the same class the "Wrap long lines" block option sets, so a
   reader's override and the author's own saved setting look identical
   either way. Deliberately quieter than .is-copied's full accent-color
   flash above: that's a momentary confirmation, this is a standing state. */
.hsrtech-code--wrap .hsrtech-code__wrap-toggle {
	background: rgba(255, 255, 255, 0.18);
	border-color: rgba(255, 255, 255, 0.32);
}

/* Icon-only buttons: swap which of each pair's two icons is visible instead
   of changing any text, so state (copied, or wrapped) reads via aria-label
   (see view.js) for screen readers rather than visible copy. */
.hsrtech-code__copy-icon,
.hsrtech-code__copied-icon,
.hsrtech-code__wrap-icon,
.hsrtech-code__unwrap-icon {
	height: 1.05rem;
	width: 1.05rem;
}

.hsrtech-code__copy-icon { display: block; }
.hsrtech-code__copied-icon { display: none; }

.hsrtech-code__wrap-icon { display: block; }
.hsrtech-code__unwrap-icon { display: none; }

.hsrtech-code--wrap .hsrtech-code__wrap-icon { display: none; }
.hsrtech-code--wrap .hsrtech-code__unwrap-icon { display: block; }

.hsrtech-code__copy.is-copied .hsrtech-code__copy-icon { display: none; }
.hsrtech-code__copy.is-copied .hsrtech-code__copied-icon { display: block; }

/* The flat, no-frills code <pre> — render.php's simplest case, used when
   nothing needs a per-line hook ("Show line numbers" and "Highlight lines"
   both off — see $hsrtech_needs_rows there), and also what
   wrapPlainBlock() (assets/js/code-highlight.js) synthesizes around a bare
   <pre><code> found elsewhere in chapter content, since neither of those
   needs the row structure below either.

   Scoped through both .hsrtech-code and .hsrtech-code__frame (not just one
   of the two) on purpose: a plain "<pre>" is exactly the kind of element
   themes often style generically for their own content areas (e.g. a theme
   rule like ".entry-content pre { background: ...; margin: 1.5rem 0; }").
   A single-class selector like that has the same specificity as a
   single-class selector of ours — one class, one element either way — so on
   a tie, whichever stylesheet the browser happens to cascade later wins,
   and a theme's own background/margin can silently win over ours depending
   on load order (an earlier version of this rule went through
   .hsrtech-code__frame alone for exactly this reason, but that's still only
   one class — it never actually fixed anything). Requiring both ancestor
   classes adds a second class, which reliably outranks a theme's
   single-class content-area selector regardless of order. background: none
   is set explicitly here too, for the same reason — without it, nothing
   here competes for that property at all, so a theme's own
   pre { background: ... } applies completely unopposed and shows through as
   a different shade than .hsrtech-code__frame's own background, right
   behind it. */
.hsrtech-code .hsrtech-code__frame pre {
	background: none;
	font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
	font-size: 0.88rem;
	line-height: 1.65;
	margin: 0;
	max-width: 100%;
	overflow-x: auto;
	padding: 2.75rem 1.5rem 1.5rem;
	tab-size: 4;
	white-space: pre;
}

.hsrtech-code .hsrtech-code__frame pre code {
	background: none;
	color: inherit;
	font-size: inherit;
	padding: 0;
}

/* "Wrap long lines" option: overrides the horizontal-scroll default above
   with normal text wrapping instead. word-break covers a single unbroken
   token (a long URL or hash) that's still wider than the block on its own,
   which white-space: pre-wrap alone wouldn't break.

   .hsrtech-code and .hsrtech-code--wrap with no space between them, not a
   descendant selector — render.php puts both classes on the same <figure>,
   not on two nested elements, so ".hsrtech-code .hsrtech-code--wrap" (with
   a space) would look for one inside the other and never match anything. */
.hsrtech-code.hsrtech-code--wrap pre {
	overflow-x: hidden;
	white-space: pre-wrap;
	word-break: break-word;
}

/* "Show language label" off (render.php adds this class when
   hideLanguageLabel is true) — see the combined .hsrtech-code--no-lang rule
   further down (grouped with its .hsrtech-code__lines counterpart) for the
   full explanation, including how this interacts with hideCopyButton /
   hideWrapToggle via .hsrtech-code--no-actions. */
.hsrtech-code.hsrtech-code--no-lang pre {
	padding-top: 1.75rem;
}

/* Row-based shape: one <div> per source line, a number (if "Show line
   numbers" is on) and that line's code side by side — render.php's markup
   whenever something needs a per-line hook, rebuilt identically client-side
   by buildLineRows() (assets/js/code-highlight.js) once JavaScript runs, so
   a wrapped line's continuation simply has no extra number rather than
   every later one drifting (the two-independent-<pre>-columns approach this
   replaced could only ever stay lined up as long as no line wrapped). A
   plain <div>, not a <pre>, on purpose: unlike the flat case above, it never
   collides with a theme's own generic "pre { ... }" content-area styling at
   all, needing none of that rule's ancestor-class specificity workarounds. */
.hsrtech-code__lines {
	font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
	font-size: 0.88rem;
	line-height: 1.65;
	max-width: 100%;
	overflow-x: auto;
	padding: 2.75rem 1.5rem 1.5rem;
	tab-size: 4;
}

.hsrtech-code__line {
	display: flex;
}

/* "Highlight lines" option: a subtle background tint plus a left accent bar
   for lines an author called out (render.php's $hsrtech_highlight_set, or
   buildLineRows()'s highlightSet once JavaScript rebuilds the row). Sits at
   the row's own edge, not bled out to the frame's full width, since padding
   lives on .hsrtech-code__lines as a whole rather than per row. */
.hsrtech-code__line--highlighted {
	background: rgba(255, 255, 255, 0.07);
	box-shadow: inset 3px 0 0 var(--hsrtech-accent, #f45d48);
}

/* Width driven by --hsrtech-line-digits, a custom property both render.php
   (inline, server-side) and buildLineRows() (JS rebuild) set based on the
   snippet's own line count plus "Start line" offset, so a 3-digit displayed
   number (row 100+, or startLine pushing an early row past 99) gets as much
   room as a 1-digit one, instead of a fixed width sized for the common case
   that would clip or misalign larger ones. */
.hsrtech-code__line-number {
	border-right: 1px solid rgba(255, 255, 255, 0.12);
	color: var(--hsrtech-code-ink, #f5f2ea);
	flex: none;
	margin-right: 0.9rem;
	opacity: 0.4;
	padding-right: 0.9rem;
	text-align: right;
	/* Neither .hsrtech-code__lines nor anything above it sets white-space,
	   so without this a double-digit number wraps onto two stacked rows —
	   "1" then "0" — the moment its width calc (below) comes out even a
	   hair narrower than the digits' actual rendered width, which happens
	   easily since a monospace font's glyphs are rarely an exact 1ch each.
	   nowrap means a too-narrow column just overflows slightly rather than
	   ever breaking the number itself onto a second line. */
	white-space: nowrap;
	user-select: none;
	width: calc(var(--hsrtech-line-digits, 2) * 1ch + 2px);
}

/* The line's own code — min-width: 0 alongside flex: 1 1 auto is required
   for .hsrtech-code__lines' own overflow-x: auto to actually kick in here
   instead of the flex item refusing to shrink below its content's natural
   width (a flex item's default min-width is auto, not 0). white-space: pre
   by default, matching every other code <pre> in this file — the
   .hsrtech-code--wrap override just below is what actually makes wrapping
   (and therefore highlighted-line backgrounds staying full-row-width, and
   line numbers staying correct once a row wraps) work correctly. */
.hsrtech-code__line-code {
	flex: 1 1 auto;
	min-width: 0;
	white-space: pre;
}

.hsrtech-code--wrap .hsrtech-code__line-code {
	overflow-wrap: anywhere;
	white-space: pre-wrap;
	word-break: break-word;
}

.hsrtech-code--no-lang .hsrtech-code__lines {
	padding-top: 1.75rem;
}

/* "Show language label" off (render.php adds this class when
   hideLanguageLabel is true, on either markup shape): the top padding above
   defaults to 2.75rem to clear both the language label (top: 1rem, left)
   and whichever of the copy/wrap-toggle buttons reaches lowest (top: 0.8rem,
   right — about 2.9rem). With the label gone there's only the buttons left
   to clear, so this gives back some — but not all — of that reserved space;
   shrinking all the way down to their own ~2.9rem requirement would give
   back almost nothing, so this accepts them visually overlapping the first
   line or two of short snippets instead, the same trade-off plenty of code
   viewers make for corner-floating buttons. (The rule pairing this with
   .hsrtech-code__frame pre lives further up, right after that rule — kept
   there instead of merged into this selector list since pre's own base
   rule already sits right above it.) */
.hsrtech-code--no-lang .hsrtech-code__lines {
	padding-top: 1.75rem;
}

/* Both hideCopyButton and hideWrapToggle on for this block (render.php adds
   this class only then — see .hsrtech-code__actions above, which handles
   just one of the two being off on its own): nothing left in the top-right
   corner at all, so this can give back the same padding as "no language
   label" alone. Combined with --no-lang, nothing occupies the top of the
   frame at all, so it drops all the way to the block's own side/bottom
   padding, the next rule down. */
.hsrtech-code.hsrtech-code--no-actions pre,
.hsrtech-code--no-actions .hsrtech-code__lines {
	padding-top: 1.75rem;
}

.hsrtech-code.hsrtech-code--no-lang.hsrtech-code--no-actions pre,
.hsrtech-code--no-lang.hsrtech-code--no-actions .hsrtech-code__lines {
	padding-top: 1.5rem;
}

/* The editor's own version of the block — in either its plain editable-field
   mode or its read-only preview mode, see the two override rules just below
   — never shows the copy/wrap-toggle buttons at all; those only ever render
   in render.php's front-end markup. So unlike the front end's own default
   (2.75rem, clearing both the language label and the taller of those two
   buttons), this only ever needs to clear the label — 1.75rem, the same
   amount the front end's own .hsrtech-code--no-actions falls back to for
   the equivalent "nothing in the corner" case. */
.hsrtech-code--editing .hsrtech-code__frame {
	padding: 1.75rem 1.5rem 1.5rem;
}

/* Label also hidden (hideLanguageLabel): nothing left in the frame's top
   edge to clear at all, so this drops all the way down to the same padding
   used on the other three sides. */
.hsrtech-code--no-lang.hsrtech-code--editing .hsrtech-code__frame {
	padding-top: 1.5rem;
}

/* Preview mode (showPreview true in edit.js, including the block Inserter's
   hover preview): the read-only preview's own content — .hsrtech-code__lines
   or a flat <pre>, buildPreviewElement() — carries its own matching top
   padding already, the exact same rules the front end uses (correctly sized
   for "no buttons" via the always-on .hsrtech-code--no-actions class edit.js
   adds — see that file). Without this override, the frame's own padding
   just above would stack on top of that, roughly doubling the gap above the
   code — the frame needs zero padding of its own here, entirely. Same
   specificity as the no-lang rule above (three classes each), so this must
   stay declared after it to still win when both apply at once: preview
   mode's "zero" is correct regardless of the label being shown or hidden,
   since the child underneath already accounts for that on its own. */
.hsrtech-code--editing.hsrtech-code--preview .hsrtech-code__frame {
	padding: 0;
}

/* Editor-only: the block appears while it's being edited, not saved markup. */
.hsrtech-code--editing .hsrtech-code__caption-input input {
	background: transparent;
	border: none;
	color: var(--hsrtech-muted, #716e67);
	font-size: 0.85rem;
	margin: 0 0 0.5rem;
	padding: 0;
}

/* WP core's own TextControl input styles the placeholder with a hardcoded
   gray meant for its usual white input background. This field sits directly
   on the post editor canvas (which several themes, including this site's,
   style dark via editor-styles) with `background: transparent` above — core's
   placeholder gray on a dark canvas reads as all but invisible. Match the
   dimmed light-ink treatment already used for other on-dark-frame labels
   (see .hsrtech-code__lang's opacity: 0.55 just above) instead of relying on
   whatever the surrounding canvas happens to default to. */
.hsrtech-code--editing .hsrtech-code__caption-input input::placeholder {
	color: var(--hsrtech-code-ink, #f5f2ea);
	opacity: 0.5;
}

.hsrtech-code--editing .hsrtech-code__editor {
	background: none;
	border: none;
	color: inherit;
	font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
	font-size: 0.88rem;
	line-height: 1.65;
	min-height: 4em;
	padding: 0;
	resize: vertical;
	tab-size: 4;
	white-space: pre;
	width: 100%;
}

/* Accessibility: the browser's own default text-input focus ring reads
   poorly against this frame's dark background and, worse, tends to hug the
   textarea's actual edges — which sit flush against the frame's own edges
   here (padding lives on .hsrtech-code__frame, not this element, see
   above), so it can look like it's outlining the whole block rather than
   this specific field. Replaced, not just removed, with the same
   accent-color treatment the front end's own :focus-visible rule uses
   (see .hsrtech-page :focus-visible, chapterwright.css) so a keyboard user
   tabbing into this field from elsewhere in the post — where WordPress's
   own block-selection border only indicates the BLOCK is selected, not
   that this particular field currently has keyboard focus for typing —
   still gets a clearly visible indicator of exactly that. */
.hsrtech-code--editing .hsrtech-code__editor:focus {
	border-radius: 0.2rem;
	outline: 2px solid var(--hsrtech-accent, #f45d48);
	outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
	.hsrtech-code * {
		transition: none !important;
	}
}
