/* KIN Python Activities — front-end styles.
 *
 * All colours flow through the --kinpy-* / --kind-* variables defined on
 * the activity containers (light values) and remapped for dark mode at the
 * bottom of this file. The dark block keys on html[data-theme="dark"] (the
 * host theme's toggle) and prefers the theme's --color-* tokens with dark
 * literals as fallbacks — sites without a data-theme attribute never enter
 * it, so the plugin stays light-only when used standalone. */

.kinpy-activity {
	--kinpy-ink: #101826;
	--kinpy-ink-soft: #3c4759;
	--kinpy-line: #dde3ec;
	--kinpy-accent: #27c265;
	--kinpy-accent-strong: #148247;
	--kinpy-accent-soft: #eaf7ef;
	--kinpy-pass-line: #bfe3cd;
	--kinpy-fail: #f72167;
	--kinpy-fail-strong: #d5145a;
	--kinpy-fail-soft: #fef0f5;
	--kinpy-fail-line: #fbc9db;
	--kinpy-hint: #9a6700;
	--kinpy-hint-soft: #fff6e0;
	--kinpy-console-bg: #282a36; /* matches the Dracula editor theme */
	--kinpy-surface: #fff;
	--kinpy-surface-soft: #fafbfd;
	--kinpy-code-chip: #f4f6f9;
	--kinpy-hover-soft: #eef1f6;
	--kinpy-btn-run-bg: #101826;
	--kinpy-btn-run-bg-hover: #1f2a40;
	--kinpy-btn-run-ink: #fff;
	--kinpy-btn-check-hover: #1fa855;
	--kinpy-success-ink: #14532d;
	--kinpy-label: #7c8aa5;
	--kinpy-dot-idle: #b9c2d0;
	--kinpy-focus: #7fb8ff;
	--kinpy-mono: ui-monospace, "SF Mono", "Cascadia Code", Consolas, Menlo, monospace;

	background: var(--kinpy-surface);
	border: 1px solid var(--kinpy-line);
	border-radius: 12px;
	overflow: hidden;
	margin: 1.5em 0;
	color: var(--kinpy-ink);
	font-size: 15px;
	line-height: 1.5;
}

/* Header */
.kinpy-head { padding: 18px 22px 14px; border-bottom: 1px solid var(--kinpy-line); }
.kinpy-badge {
	display: inline-block; font-size: 11px; font-weight: 700; letter-spacing: .08em;
	text-transform: uppercase; color: var(--kinpy-accent-strong, var(--kinpy-accent)); background: var(--kinpy-accent-soft);
	border-radius: 99px; padding: 3px 10px; margin-bottom: 8px;
}
.kinpy-activity h3.kinpy-title { margin: 0 0 6px; font-size: 19px; line-height: 1.3; color: var(--kinpy-ink); }
.kinpy-instructions { color: var(--kinpy-ink-soft); font-size: 14.5px; }
.kinpy-instructions p { margin: 0 0 .6em; }
.kinpy-instructions p:last-child { margin-bottom: 0; }
.kinpy-instructions code {
	font-family: var(--kinpy-mono); font-size: 13px; background: var(--kinpy-code-chip);
	border: 1px solid var(--kinpy-line); border-radius: 4px; padding: 1px 5px;
}

/* Editor */
.kinpy-editor-wrap { position: relative; }
.kinpy-activity .CodeMirror {
	height: auto; font-family: var(--kinpy-mono); font-size: 14px;
	line-height: 1.6; padding: 8px 0;
}
.kinpy-editor-label {
	position: absolute; top: 8px; right: 12px; z-index: 5; font-family: var(--kinpy-mono);
	font-size: 10.5px; letter-spacing: .06em; color: var(--kinpy-label); text-transform: uppercase;
}
/* Plain textarea fallback if CodeMirror failed to load */
.kinpy-activity textarea.kinpy-code {
	display: block; width: 100%; min-height: 220px; border: 0; resize: vertical;
	background: var(--kinpy-console-bg); color: #e6ecf7;
	font-family: var(--kinpy-mono); font-size: 14px; line-height: 1.6; padding: 14px 16px;
	tab-size: 4;
}
.kinpy-activity .CodeMirror + textarea.kinpy-code,
.kinpy-activity .CodeMirror ~ .kinpy-editor-label { /* keep label above editor */ }

/* Toolbar */
/* The body's children are ordered per layout: the stacked flow keeps
   the toolbar under the editor (its pre-1.2.3 position) even though the
   toolbar now lives at the end of the DOM so the horizontal layout can
   span it full width at the card's foot. */
.kinpy-body { display: flex; flex-direction: column; }
.kinpy-body > .kinpy-pane-code { order: 1; }
.kinpy-body > .kinpy-toolbar { order: 2; }
.kinpy-body > .kinpy-pane-results { order: 3; }
.kinpy-body > .kinpy-success { order: 4; }

.kinpy-toolbar {
	display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
	padding: 12px 22px; border-top: 1px solid var(--kinpy-line);
	border-bottom: 1px solid var(--kinpy-line); background: var(--kinpy-surface-soft);
}
.kinpy-btn {
	font-size: 14px; font-weight: 600; border-radius: 8px; padding: 8px 16px;
	cursor: pointer; border: 1px solid transparent; line-height: 1.4;
	transition: background .15s, opacity .15s; box-shadow: none; text-transform: none;
}
.kinpy-btn:focus-visible { outline: 3px solid var(--kinpy-focus); outline-offset: 2px; }
.kinpy-btn:disabled { opacity: .45; cursor: not-allowed; }
/* The host theme (Kadence) paints border-color var(--global-palette2)
   — the site's pink — onto every button on hover/focus/active. These
   buttons follow the activity card's palette instead: the filled ones
   keep no visible border, Reset keeps its own neutral line. */
.kinpy-btn:hover, .kinpy-btn:focus, .kinpy-btn:active { border-color: transparent; }
.kinpy-btn-reset:hover, .kinpy-btn-reset:focus, .kinpy-btn-reset:active { border-color: var(--kinpy-line); }
.kinpy-btn-run { background: var(--kinpy-btn-run-bg); color: var(--kinpy-btn-run-ink); }
.kinpy-btn-run:hover:not(:disabled) { background: var(--kinpy-btn-run-bg-hover); color: var(--kinpy-btn-run-ink); }
.kinpy-btn-check { background: var(--kinpy-accent); color: #fff; }
.kinpy-btn-check:hover:not(:disabled) { background: var(--kinpy-btn-check-hover); color: #fff; }
.kinpy-btn-reset { background: transparent; color: var(--kinpy-ink-soft); border-color: var(--kinpy-line); }
.kinpy-btn-reset:hover:not(:disabled) { background: var(--kinpy-hover-soft); color: var(--kinpy-ink); }

.kinpy-loader { margin-left: auto; font-size: 12.5px; color: var(--kinpy-ink-soft); display: flex; align-items: center; gap: 8px; }
.kinpy-spinner {
	width: 13px; height: 13px; border: 2px solid var(--kinpy-line);
	border-top-color: var(--kinpy-accent); border-radius: 50%;
	animation: kinpy-spin .8s linear infinite;
}
@keyframes kinpy-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .kinpy-spinner { animation: none; } }

/* Console — deliberately dark in both themes, like a real terminal */
.kinpy-console {
	background: var(--kinpy-console-bg); color: #f8f8f2; font-family: var(--kinpy-mono);
	font-size: 13px; padding: 14px 22px; min-height: 64px; white-space: pre-wrap;
	word-break: break-word;
}
.kinpy-console-label {
	color: #5d6a85; font-size: 10.5px; letter-spacing: .06em;
	text-transform: uppercase; display: block; margin-bottom: 6px;
	font-family: inherit;
}
.kinpy-err { color: #ff8a7a; }
.kinpy-muted { color: #5d6a85; font-style: italic; }

/* Checks */
.kinpy-checks { padding: 16px 22px 18px; }
.kinpy-checks h4 {
	margin: 0 0 10px; font-size: 13px; letter-spacing: .06em;
	text-transform: uppercase; color: var(--kinpy-ink-soft);
}
.kinpy-check {
	padding: 10px 12px; border: 1px solid var(--kinpy-line); border-radius: 8px;
	margin-bottom: 8px; font-size: 14px; background: var(--kinpy-surface-soft);
}
.kinpy-check-row { display: flex; gap: 10px; align-items: center; }
.kinpy-dot {
	flex: none; width: 20px; height: 20px; border-radius: 50%;
	display: flex; align-items: center; justify-content: center;
	font-size: 12px; font-weight: 700; color: #fff; background: var(--kinpy-dot-idle);
}
.kinpy-check.kinpy-pass { border-color: var(--kinpy-pass-line); background: var(--kinpy-accent-soft); }
.kinpy-check.kinpy-pass .kinpy-dot { background: var(--kinpy-accent); }
.kinpy-check.kinpy-fail { border-color: var(--kinpy-fail-line); background: var(--kinpy-fail-soft); }
.kinpy-check.kinpy-fail .kinpy-dot { background: var(--kinpy-fail); }
.kinpy-hint {
	display: flex; align-items: flex-start; gap: 7px;
	margin-top: 8px; font-size: 13px; color: var(--kinpy-hint);
	background: var(--kinpy-hint-soft); border-radius: 6px; padding: 6px 10px;
}
.kinpy-hint-icon { flex: none; }
.kinpy-retry {
	margin-left: 6px; padding: 2px 10px; font-size: 12.5px; font-weight: 600;
	border: 1.5px solid var(--kinpy-line); border-radius: 999px;
	background: var(--kinpy-surface); color: var(--kinpy-ink); cursor: pointer;
}
.kinpy-retry:hover { background: var(--kinpy-hover-soft); }

/* Success banner: a full-bleed bar in the brand green that slides up
   from behind the card's bottom edge (the card's overflow:hidden clips
   the start of the rise, selling the "from below" effect). */
.kinpy-success {
	display: none; margin: 0; padding: 12px 22px; border-radius: 0;
	background: var(--kinpy-accent);
	color: #fff; font-size: 15px;
}
.kinpy-success .kina-tick { color: #fff; }
.kinpy-success span { color: rgba(255, 255, 255, .88); }
.kinpy-success.kinpy-show { display: block; transform-origin: bottom center; animation: kina-rise .6s ease-out backwards; }
/* Squash-and-stretch spring: the bar rises from behind the toolbar,
   then — anchored at its bottom edge — its top overshoots tall,
   squashes short and jiggles to rest. The bottom edge never leaves
   the toolbar, so nothing shows beneath it. */
@keyframes kina-rise {
	/* Start at 70% (not 100%): the bar is taller than the toolbar that
	   hides the rise, so a full-height offset pokes out below the card
	   for a frame before the clip catches up. Squashed to .55 the bar is
	   short enough for a 70% drop to sit entirely behind the toolbar.
	   The quick fade guarantees no stray first-frame pixels either. */
	0%   { transform: translateY(70%) scaleY(.55); opacity: 0; }
	18%  { opacity: 1; }
	48%  { transform: translateY(0) scaleY(1.25); }
	69%  { transform: translateY(0) scaleY(.85); }
	85%  { transform: translateY(0) scaleY(1.09); }
	100% { transform: translateY(0) scaleY(1); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) { .kinpy-success.kinpy-show { animation: none; } }
.kinpy-success strong { display: block; margin-bottom: 2px; }

/* ------------------------------------------------------------------
 * Horizontal layout — editor beside output, for slide-style lessons
 * ---------------------------------------------------------------- */
.kinpy-layout-h .kinpy-head { padding: 14px 22px 12px; }
.kinpy-layout-h .kinpy-instructions { font-size: 14px; }

.kinpy-layout-h .kinpy-body {
	display: grid;
	grid-template-columns: minmax(0, 11fr) minmax(0, 9fr);
	/* Panes take all flexible height; the success banner and toolbar
	   rows stay natural height (without this the leftover from the
	   380px minimum stretched them tall). */
	grid-template-rows: minmax(0, 1fr) auto auto;
	align-items: stretch;
	min-height: 380px;
}

.kinpy-layout-h .kinpy-pane-code {
	display: flex;
	flex-direction: column;
	border-right: 1px solid var(--kinpy-line);
	min-width: 0;
}
.kinpy-layout-h .kinpy-editor-wrap { flex: 1; min-height: 0; }
.kinpy-layout-h .CodeMirror { height: 100%; min-height: 280px; }
.kinpy-layout-h textarea.kinpy-code { height: 100%; min-height: 280px; }
.kinpy-layout-h .kinpy-body > .kinpy-pane-code,
.kinpy-layout-h .kinpy-body > .kinpy-pane-results,
.kinpy-layout-h .kinpy-body > .kinpy-toolbar,
.kinpy-layout-h .kinpy-body > .kinpy-success { order: 0; }
.kinpy-layout-h .kinpy-toolbar { grid-column: 1 / -1; border-bottom: 0; }

.kinpy-layout-h .kinpy-pane-results {
	display: flex;
	flex-direction: column;
	min-width: 0;
}
.kinpy-layout-h .kinpy-console {
	flex: 1;
	/* Roomy enough for ~6 lines even when expanded hints press in -
	   the shrink reads "large to comfortable", not "large to crushed"
	   (Dan's call, 19 July 2026). */
	min-height: 160px;
	max-height: 100%;
	overflow: auto;
}
.kinpy-layout-h .kinpy-checks {
	padding: 14px 18px 14px;
	/* When expanded hints outgrow the pane, the checks region scrolls
	   rather than silently clipping. */
	overflow-y: auto;
	min-height: 0;
}
.kinpy-layout-h .kinpy-check { padding: 8px 10px; font-size: 13.5px; }
.kinpy-layout-h .kinpy-success { grid-column: 1 / -1; }

/* Collapse back to stacked on narrow screens */
@media (max-width: 880px) {
	.kinpy-layout-h .kinpy-body { display: flex; min-height: 0; }
	.kinpy-layout-h .kinpy-body > .kinpy-pane-code { order: 1; }
	.kinpy-layout-h .kinpy-body > .kinpy-toolbar { order: 2; }
	.kinpy-layout-h .kinpy-body > .kinpy-pane-results { order: 3; }
	.kinpy-layout-h .kinpy-body > .kinpy-success { order: 4; }
	.kinpy-layout-h .kinpy-pane-code { border-right: 0; }
	.kinpy-layout-h .kinpy-toolbar { border-bottom: 1px solid var(--kinpy-line); }
	.kinpy-layout-h .CodeMirror,
	.kinpy-layout-h textarea.kinpy-code { height: auto; }
	.kinpy-layout-h .CodeMirror { min-height: 0; }
}

/* Admin preview container niceties */
#kina-preview-target .kinpy-activity { margin: 12px 0 0; }

/* ====================================================================
   Web activities (HTML / CSS / JavaScript)

   The card deliberately reuses .kinpy-activity: same shell, same palette
   variables, same head/toolbar/checks/success furniture, same dark-mode
   remap. Only the parts that differ from the Python type — the file tabs
   and the sandboxed preview in place of the console — are new here.
==================================================================== */
.kinw-pane-code { display: flex; flex-direction: column; min-width: 0; }

/* File tabs (only rendered when an activity has more than one file) */
.kinw-tabs {
	display: flex; gap: 2px; overflow-x: auto; padding: 0 8px;
	background: var(--kinpy-surface-soft); border-bottom: 1px solid var(--kinpy-line);
}
.kinw-tab {
	background: transparent; border: 0; box-shadow: none; border-radius: 0;
	padding: 8px 12px; cursor: pointer; white-space: nowrap; line-height: 1.4;
	font-family: var(--kinpy-mono); font-size: 12px; text-transform: none;
	color: var(--kinpy-ink-soft);
}
/* Host-theme defence, as with .kinpy-btn: Kadence paints its own border
   colour onto buttons on hover/focus. The active underline is an inset
   shadow rather than a border so it cannot be overwritten. */
.kinw-tab:hover, .kinw-tab:focus, .kinw-tab:active { border-color: transparent; color: var(--kinpy-ink); }
.kinw-tab:focus-visible { outline: 3px solid var(--kinpy-focus); outline-offset: -3px; }
.kinw-tab-on { color: var(--kinpy-ink); background: var(--kinpy-surface); box-shadow: inset 0 -2px 0 var(--kinpy-accent); }
.kinw-tab-ro {
	margin-left: 6px; font-size: 9.5px; letter-spacing: .05em;
	text-transform: uppercase; color: var(--kinpy-label);
}

.kinw-files { display: flex; flex-direction: column; min-height: 0; }
.kinw-file { position: relative; display: flex; flex-direction: column; min-height: 0; }
.kinw-file[hidden] { display: none; }

/* Plain textarea fallback if CodeMirror failed to load */
.kinw-activity textarea.kinw-code {
	display: block; width: 100%; min-height: 220px; border: 0; resize: vertical;
	background: var(--kinpy-console-bg); color: #e6ecf7;
	font-family: var(--kinpy-mono); font-size: 14px; line-height: 1.6; padding: 14px 16px;
	tab-size: 2;
}

/* Preview — the same sandboxed frame the checks are asserted against, so
   the student is always marked on exactly what they can see. The frame
   fills the pane edge to edge (no label row, no padded inner box - a
   rendered page needs every pixel, Dan, 10 Aug 2026); the label floats
   over the page like the editor's filename label. */
.kinw-pane-results { display: flex; flex-direction: column; min-width: 0; position: relative; }
.kinw-stage {
	position: relative; display: flex; justify-content: center;
	min-height: 280px; background: var(--kinpy-surface-soft);
}
.kinw-preview-label {
	position: absolute; top: 8px; right: 12px; z-index: 5;
	font-family: var(--kinpy-mono); font-size: 10.5px; letter-spacing: .06em;
	text-transform: uppercase; color: var(--kinpy-label);
	background: rgba(255, 255, 255, .82); border-radius: 4px; padding: 1px 6px;
	pointer-events: none;
}
.kinw-frame {
	display: block; width: 100%; max-width: var(--kinw-w, 100%); height: 100%; min-height: 280px;
	border: 0; background: #fff;
}

/* Checks overlay: slides up over the preview when summoned (toolbar
   chip), when a check run finds failures, or never at all on a clean
   solve. Absolute within the results pane, so the preview keeps its
   full size whatever the checks need to say. */
.kinw-checks-panel {
	position: absolute; left: 0; right: 0; bottom: 0; z-index: 10;
	max-height: 88%; display: flex; flex-direction: column;
	background: var(--kinpy-surface);
	border-top: 1px solid var(--kinpy-line);
	box-shadow: 0 -10px 26px rgba(16, 24, 38, .16);
	animation: kinw-panel-rise .22s ease-out;
}
.kinw-checks-panel[hidden] { display: none; }
@keyframes kinw-panel-rise { from { transform: translateY(14px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .kinw-checks-panel { animation: none; } }
.kinw-checks-head {
	display: flex; align-items: center; justify-content: space-between;
	padding: 10px 16px 8px;
}
.kinw-checks-head h4 {
	margin: 0; font-size: 13px; letter-spacing: .06em;
	text-transform: uppercase; color: var(--kinpy-ink-soft);
}
.kinw-checks-score { color: var(--kinpy-label); }
.kinw-checks-close {
	background: transparent; border: 0; box-shadow: none; cursor: pointer;
	font-size: 14px; line-height: 1; padding: 4px 8px; border-radius: 6px;
	color: var(--kinpy-ink-soft);
}
.kinw-checks-close:hover, .kinw-checks-close:focus, .kinw-checks-close:active {
	background: var(--kinpy-hover-soft); color: var(--kinpy-ink); border-color: transparent;
}
.kinw-checks-close:focus-visible { outline: 3px solid var(--kinpy-focus); outline-offset: 1px; }
.kinw-checks-panel .kinpy-check-list { overflow-y: auto; padding: 0 16px 14px; min-height: 0; }

/* Toolbar chip: the always-visible score ("Checks 3/5") that reopens
   the overlay. Styled as a quiet third button. */
.kinw-checks-toggle {
	background: transparent; color: var(--kinpy-ink-soft); border-color: var(--kinpy-line);
}
.kinw-checks-toggle:hover, .kinw-checks-toggle:focus, .kinw-checks-toggle:active {
	background: var(--kinpy-hover-soft); color: var(--kinpy-ink); border-color: var(--kinpy-line);
}
.kinw-checks-toggle[aria-expanded="true"] { background: var(--kinpy-hover-soft); color: var(--kinpy-ink); }
.kinw-score {
	display: inline-block; margin-left: 4px; padding: 0 7px; border-radius: 99px;
	font-size: 12px; font-variant-numeric: tabular-nums;
	background: var(--kinpy-code-chip); border: 1px solid var(--kinpy-line);
}

/* Script errors from the student's own code */
.kinw-error {
	display: flex; gap: 8px; align-items: flex-start; margin: 0;
	padding: 9px 22px; font-size: 13px; font-family: var(--kinpy-mono);
	color: var(--kinpy-fail-strong); background: var(--kinpy-fail-soft);
	border-top: 1px solid var(--kinpy-fail-line); word-break: break-word;
}
.kinw-error[hidden] { display: none; }
.kinw-error-icon { flex: none; }

.kinw-note { margin-left: auto; font-size: 12.5px; color: var(--kinpy-ink-soft); }

/* Horizontal layout: editors fill the left column, preview the right.
   Two deliberate departures from the python card (Dan, 10 Aug 2026):
   the columns split 50-50, because a rendered page needs real room
   where a console output does not; and the preview owns the flexible
   height — it may grow but never shrink below its stage, and the
   checks list scrolls in whatever remains. (Originally the preview was
   shrinkable like the checks; flexbox squashed it below the stage's
   min-height and the stage painted straight over the checks.) */
.kinw-activity.kinpy-layout-h .kinpy-body { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.kinpy-layout-h .kinw-files,
.kinpy-layout-h .kinw-file { flex: 1; min-height: 0; }
.kinpy-layout-h textarea.kinw-code { height: 100%; min-height: 280px; }
.kinpy-layout-h .kinw-stage { flex: 1; min-height: 240px; }
.kinpy-layout-h .kinw-frame { min-height: 0; }

@media (max-width: 880px) {
	.kinpy-layout-h .kinw-stage { min-height: 260px; }
	.kinpy-layout-h .kinw-frame { min-height: 240px; }
	.kinpy-layout-h textarea.kinw-code { height: auto; }
}

#kina-preview-target .kinw-activity { margin: 12px 0 0; }

/* ====================================================================
   Drag-and-drop activity types (categorise / sequence / match / gapfill)
==================================================================== */
.kind-activity {
	--kind-ink: #101826;
	--kind-ink-soft: #3c4759;
	--kind-line: #dde3ec;
	--kind-accent: #27c265;
	--kind-accent-strong: #148247;
	--kind-accent-soft: #eaf7ef;
	--kind-fail: #f72167;
	--kind-fail-strong: #d5145a;
	--kind-fail-soft: #fef0f5;
	--kind-hint: #9a6700;
	--kind-hint-soft: #fff6e0;
	--kind-blue: #398ffc;
	--kind-blue-strong: #1c6fdb; /* chip label text — #398ffc fails contrast on white */
	--kind-blue-soft: #ebf4ff;
	--kind-surface: #fff;
	--kind-surface-soft: #fafbfd;
	--kind-surface-strong: #f0f3f8;
	--kind-hover-soft: #eef1f6;
	--kind-chip-bg: #fff;
	--kind-btn-check-hover: #1fa855;
	--kind-success-ink: #14532d;
	--kind-focus: #7fb8ff;
	--kind-ghost-shadow: rgba(16, 24, 38, .25);

	background: var(--kind-surface);
	border: 1px solid var(--kind-line);
	border-radius: 12px;
	overflow: hidden;
	margin: 1.5em 0;
	color: var(--kind-ink);
	font-size: 15px;
	line-height: 1.5;
}

.kind-head { padding: 18px 22px 14px; border-bottom: 1px solid var(--kind-line); }
.kind-badge {
	display: inline-block; font-size: 11px; font-weight: 700; letter-spacing: .08em;
	text-transform: uppercase; color: var(--kind-accent-strong, var(--kind-accent)); background: var(--kind-accent-soft);
	border-radius: 99px; padding: 3px 10px; margin-bottom: 8px;
}
.kind-activity h3.kind-title { margin: 0 0 6px; font-size: 19px; line-height: 1.3; color: var(--kind-ink); }
.kind-instructions { color: var(--kind-ink-soft); font-size: 14.5px; }
.kind-instructions p { margin: 0 0 .6em; }
.kind-instructions p:last-child { margin-bottom: 0; }

.kind-body { padding: 18px 22px; }

/* Chips */
.kind-chip {
	display: inline-block; background: var(--kind-chip-bg); border: 1.5px solid var(--kind-blue);
	color: var(--kind-blue-strong, var(--kind-blue)); border-radius: 8px; padding: 7px 12px; margin: 4px;
	font-size: 14px; font-weight: 600; cursor: grab; user-select: none;
	-webkit-user-select: none; touch-action: none; line-height: 1.35;
}
.kind-chip.kind-selected { outline: 3px solid var(--kind-focus); outline-offset: 1px; }
/* Keyboard operability: chips and drop targets are focusable (see dragdrop.js). */
.kind-chip:focus-visible, .kind-zone:focus-visible, .kind-tray:focus-visible {
	outline: 3px solid var(--kind-focus); outline-offset: 1px;
}
.kind-chip.kind-ok { border-color: var(--kind-accent); color: var(--kind-accent-strong, var(--kind-accent)); background: var(--kind-accent-soft); }
/* Banked after a failed check: correct chips stay put and stop being
   draggable until Reset or a full solve. */
.kind-chip.kind-locked { cursor: default; }
/* Mid-flight back to the tray: painted above the buckets it crosses. */
.kind-chip.kind-flying { position: relative; z-index: 20; will-change: transform; }
.kind-chip.kind-bad { border-color: var(--kind-fail); color: var(--kind-fail-strong, var(--kind-fail)); background: var(--kind-fail-soft); animation: kind-shake .3s ease; }
/* Colour-independent marking: right/wrong must not rely on green vs red
   alone (colour-blind students), so marked chips also get a tick/cross. */
.kind-chip.kind-ok::before { content: "✓ "; font-weight: 700; }
.kind-chip.kind-bad::before { content: "✕ "; font-weight: 700; }
@keyframes kind-shake { 25% { transform: translateX(-3px); } 75% { transform: translateX(3px); } }
@media (prefers-reduced-motion: reduce) { .kind-chip.kind-bad { animation: none; } }
.kind-ghost {
	position: fixed; z-index: 99999; pointer-events: none; opacity: .92;
	transform: translate(-50%, -50%) rotate(2deg); box-shadow: 0 8px 22px var(--kind-ghost-shadow, rgba(16, 24, 38, .25));
}
.kind-chip.kind-dragging { opacity: .35; }

/* Tray */
.kind-tray {
	border: 1.5px dashed var(--kind-line); border-radius: 10px; background: var(--kind-surface-soft);
	padding: 8px; min-height: 52px; margin-bottom: 14px;
}
.kind-tray-label {
	font-size: 11px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
	color: var(--kind-ink-soft); margin: 2px 4px 4px;
}

/* Categorise buckets */
.kind-buckets { display: grid; grid-template-columns: repeat(var(--kind-buckets, 4), minmax(0, 1fr)); gap: 10px; }
@media (max-width: 760px) { .kind-buckets { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 430px) { .kind-buckets { grid-template-columns: 1fr; } }
/* Buckets are flex columns so the drop zone always stretches to fill
   the box (grid rows equalise bucket heights; without this, shorter
   buckets showed dead space below the zone). */
.kind-bucket { border: 1.5px solid var(--kind-line); border-radius: 10px; overflow: hidden; background: var(--kind-surface); display: flex; flex-direction: column; }
.kind-bucket h4 {
	margin: 0; padding: 8px 12px; font-size: 13.5px; background: var(--kind-surface-strong);
	border-bottom: 1px solid var(--kind-line); color: var(--kind-ink);
}
.kind-zone { min-height: 64px; padding: 6px; }
/* The categorise drop area is always visibly marked and fills the
   whole bucket; dropped chips span its full width. (Scoped to buckets:
   .kind-zone is shared with match rows and inline gapfill gaps.) */
.kind-bucket .kind-zone {
	flex: 1 1 auto; margin: 6px; padding: 4px;
	border: 1.5px dashed var(--kind-line); border-radius: 8px;
}
.kind-bucket .kind-zone .kind-chip { display: block; }
.kind-zone.kind-hover, .kind-tray.kind-hover {
	background: var(--kind-blue-soft); outline: 2px dashed var(--kind-blue);
	outline-offset: -4px; border-radius: 8px;
}

/* Sequence */
.kind-seq { list-style: none; margin: 0; padding: 0; counter-reset: kindstep; }
.kind-seq .kind-chip { display: flex; align-items: center; gap: 10px; margin: 0 0 8px; width: 100%; counter-increment: kindstep; }
.kind-seq .kind-chip::before {
	content: counter(kindstep); flex: none; width: 22px; height: 22px; border-radius: 50%;
	background: var(--kind-surface-strong); color: var(--kind-ink-soft); border: 1px solid var(--kind-line);
	display: flex; align-items: center; justify-content: center; font-size: 12px;
}
.kind-seq.kind-unnumbered .kind-chip::before { display: none; }

/* Match */
.kind-match-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 8px; align-items: stretch; }
@media (max-width: 560px) { .kind-match-row { grid-template-columns: 1fr; gap: 4px; margin-bottom: 14px; } }
.kind-match-left {
	border: 1px solid var(--kind-line); border-radius: 8px; background: var(--kind-surface-strong);
	padding: 8px 12px; font-size: 14px; display: flex; align-items: center;
}
.kind-match-row .kind-zone { min-height: 44px; border: 1.5px dashed var(--kind-line); border-radius: 8px; padding: 2px; }
.kind-match-row .kind-zone .kind-chip { width: 100%; margin: 2px; }

/* Gap fill */
.kind-cloze { font-size: 15.5px; line-height: 2.2; margin: 0; }
.kind-gap {
	display: inline-block; vertical-align: middle; min-width: 120px; min-height: 34px;
	border-bottom: 2px solid var(--kind-blue); background: var(--kind-blue-soft);
	border-radius: 6px 6px 0 0; margin: 0 3px; padding: 0 2px; text-align: center;
}
.kind-gap .kind-chip { margin: 1px; padding: 4px 10px; }

/* Hints, success, toolbar */
.kind-hints { padding: 0 22px; }
/* Breathing room around the hints so the first doesn't touch the body
   edge and the last doesn't sit on the toolbar border (the container is
   empty until a check, so pad only when it has content). */
.kind-hints:not(:empty) { padding-top: 10px; padding-bottom: 8px; }
.kind-hint {
	font-size: 13.5px; color: var(--kind-hint); background: var(--kind-hint-soft);
	border-radius: 6px; padding: 8px 12px; margin: 0 0 8px;
}
/* Success banner: full-bleed brand-green bar that slides up from
   behind the Check/Reset toolbar below it (the toolbar's opaque
   background + z-index hide the start of the rise). */
.kind-success {
	display: none; margin: 0; padding: 12px 22px; border-radius: 0;
	background: var(--kind-accent);
	color: #fff; font-size: 15px;
}
.kind-success .kina-tick { color: #fff; }
.kind-success .kind-success-msg { color: rgba(255, 255, 255, .88); }
.kind-success.kind-show { display: block; transform-origin: bottom center; animation: kina-rise .6s ease-out backwards; }
@media (prefers-reduced-motion: reduce) { .kind-success.kind-show { animation: none; } }
.kind-success strong { display: block; margin-bottom: 2px; }

.kind-toolbar {
	display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
	padding: 12px 22px; border-top: 1px solid var(--kind-line); background: var(--kind-surface-soft);
	/* Stays painted above the success bar while it animates in from
	   behind (the bar's transform gives it a stacking context). */
	position: relative; z-index: 1;
}
.kind-btn {
	font-size: 14px; font-weight: 600; border-radius: 8px; padding: 8px 16px;
	cursor: pointer; border: 1px solid transparent; line-height: 1.4;
	transition: background .15s; box-shadow: none; text-transform: none;
}
.kind-btn:focus-visible { outline: 3px solid var(--kind-focus); outline-offset: 2px; }
/* Host-theme defence — see the kinpy note above. */
.kind-btn:hover, .kind-btn:focus, .kind-btn:active { border-color: transparent; }
.kind-btn-reset:hover, .kind-btn-reset:focus, .kind-btn-reset:active { border-color: var(--kind-line); }
.kind-btn-check { background: var(--kind-accent); color: #fff; }
.kind-btn-check:hover { background: var(--kind-btn-check-hover); color: #fff; }
.kind-btn-reset { background: transparent; color: var(--kind-ink-soft); border-color: var(--kind-line); }
.kind-btn-reset:hover { background: var(--kind-hover-soft); color: var(--kind-ink); }
.kind-result { margin-left: auto; font-size: 14px; font-weight: 600; }
.kind-result.kind-good { color: var(--kind-accent-strong, var(--kind-accent)); }
.kind-result.kind-partial { color: var(--kind-hint); }

#kina-preview-target .kind-activity { margin: 12px 0 0; }

/* ====================================================================
   Success confetti — spawned by KINACT.celebrate() (core.js) when every
   check passes. transform/opacity only, so the browser composites it on
   the GPU with no layout or paint cost; particles self-remove after
   ~1.4s. Users with prefers-reduced-motion never see it (the JS skips).
==================================================================== */
.kina-confetti-holder { position: fixed; inset: 0; z-index: 99998; pointer-events: none; perspective: 600px; }
.kina-confetti {
	position: fixed; border-radius: 2px;
	opacity: 0; will-change: transform, opacity;
	animation-name: kina-confetti-fall;
	animation-timing-function: cubic-bezier(.25, .4, .45, 1);
	animation-fill-mode: forwards;
}
@keyframes kina-confetti-fall {
	0% { opacity: 1; transform: translate3d(0, 0, 0) rotateZ(0deg) rotateX(0deg); }
	75% { opacity: 1; }
	100% { opacity: 0; transform: translate3d(var(--kina-dx, 0), var(--kina-dy, 320px), 0) rotateZ(var(--kina-rz, 360deg)) rotateX(var(--kina-rx, 360deg)); }
}

/* Animated success tick: the ring and check draw themselves on when the
   banner appears (stroke-dashoffset — cheap, no layout). Static when
   prefers-reduced-motion, since the draw animations simply don't run. */
/* "Completed" pill — quiet persistent state in the card header, shown
   when the logged-in student has completed this activity before (and
   revealed live the moment they complete it). Colour comes from the
   engine's own accent tokens, so it adapts to dark mode for free. */
.kind-head .kina-done {
	float: right; margin: 0 0 6px 12px;
	font-size: 12px; font-weight: 700; letter-spacing: .02em;
	color: var(--kind-accent-strong); background: var(--kind-accent-soft);
	border: 1px solid var(--kind-accent);
	border-radius: 99px; padding: 3px 10px;
}
.kinpy-head .kina-done {
	float: right; margin: 0 0 6px 12px;
	font-size: 12px; font-weight: 700; letter-spacing: .02em;
	color: var(--kinpy-accent-strong); background: var(--kinpy-accent-soft);
	border: 1px solid var(--kinpy-accent);
	border-radius: 99px; padding: 3px 10px;
}
.kina-done[hidden] { display: none; }

.kina-tick { display: inline-flex; width: 22px; height: 22px; vertical-align: -5px; margin-right: 7px; }
.kina-tick svg { width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.kina-tick-ring { --kina-dash: 63; stroke-dasharray: 63; }
.kina-tick-mark { --kina-dash: 15; stroke-dasharray: 15; }
@keyframes kina-draw { from { stroke-dashoffset: var(--kina-dash, 63); } to { stroke-dashoffset: 0; } }
.kind-success.kind-show .kina-tick-ring,
.kinpy-success.kinpy-show .kina-tick-ring { animation: kina-draw .4s ease-out .25s backwards; }
.kind-success.kind-show .kina-tick-mark,
.kinpy-success.kinpy-show .kina-tick-mark { animation: kina-draw .25s ease-out .65s backwards; }
@media (prefers-reduced-motion: reduce) {
	.kind-success.kind-show .kina-tick-ring,
	.kind-success.kind-show .kina-tick-mark,
	.kinpy-success.kinpy-show .kina-tick-ring,
	.kinpy-success.kinpy-show .kina-tick-mark { animation: none; }
}

/* ====================================================================
   Dark mode — remaps the palette variables above. Keys on the host
   theme's html[data-theme="dark"] attribute and prefers the theme's
   --color-* tokens (KnowItAll Ninja) with dark literals as fallbacks.
   The console and code editor are already dark and stay as they are.
==================================================================== */
html[data-theme="dark"] .kinpy-activity {
	--kinpy-ink: var(--color-heading, #eef4fb);
	--kinpy-ink-soft: var(--color-text-muted, #95a5b8);
	--kinpy-line: var(--color-border-light, #233146);
	/* Dulled like the quizzes' dark teal — the bright success green
	   reads too hot on dark surfaces (matches the theme's convention). */
	--kinpy-accent: var(--color-success-dark, #25b860);
	--kinpy-accent-strong: var(--color-success-dark, #25b860);
	--kinpy-accent-soft: #10291c;
	--kinpy-pass-line: #1f5d44;
	--kinpy-fail: var(--color-error, #ff4d7d);
	--kinpy-fail-strong: var(--color-error, #ff4d7d);
	--kinpy-fail-soft: #2a151c;
	--kinpy-fail-line: #5d2331;
	--kinpy-hint: var(--color-warning, #ffc933);
	--kinpy-hint-soft: #241d09;
	--kinpy-surface: var(--color-surface, #131d2c);
	--kinpy-surface-soft: var(--color-surface-inset, #0c1320);
	--kinpy-code-chip: var(--color-surface-inset, #0c1320);
	--kinpy-hover-soft: var(--color-surface-alt, #1a2535);
	--kinpy-btn-run-bg: #33455e;
	--kinpy-btn-run-bg-hover: #3f5471;
	--kinpy-btn-run-ink: var(--color-heading, #eef4fb);
	--kinpy-btn-check-hover: #2bbd68;
	--kinpy-success-ink: #a7e8c0;
	--kinpy-label: #6b7a8d;
	--kinpy-dot-idle: #3d5675;
}

html[data-theme="dark"] .kind-activity {
	--kind-ink: var(--color-heading, #eef4fb);
	--kind-ink-soft: var(--color-text-muted, #95a5b8);
	--kind-line: var(--color-border-light, #233146);
	/* Dulled like the quizzes' dark teal (see kinpy note above). */
	--kind-accent: var(--color-success-dark, #25b860);
	--kind-accent-strong: var(--color-success-dark, #25b860);
	--kind-accent-soft: #10291c;
	--kind-fail: var(--color-error, #ff4d7d);
	--kind-fail-strong: var(--color-error, #ff4d7d);
	--kind-fail-soft: #2a151c;
	--kind-hint: var(--color-warning, #ffc933);
	--kind-hint-soft: #241d09;
	--kind-blue: var(--color-primary, #5da9ff);
	--kind-blue-strong: var(--color-primary, #5da9ff);
	--kind-blue-soft: var(--color-primary-soft, #152944);
	--kind-surface: var(--color-surface, #131d2c);
	--kind-surface-soft: var(--color-surface-inset, #0c1320);
	--kind-surface-strong: var(--color-surface-alt, #1a2535);
	--kind-hover-soft: var(--color-surface-alt, #1a2535);
	--kind-chip-bg: var(--color-surface-alt, #1a2535);
	--kind-btn-check-hover: #2bbd68;
	--kind-success-ink: #a7e8c0;
	--kind-ghost-shadow: rgba(0, 0, 0, .55);
}
