/**
 * AI Prompt Cards
 *
 * A plain WordPress component: it owns every value it uses and inherits nothing
 * it has not asked for. Typography is the exception -- it takes the theme's body
 * font, because a shortcode dropped into a post should read as part of the post.
 *
 * Every value routes through a --aip-* custom property. To retheme, override
 * that block on .aip; nothing below it needs touching. A theme with its own
 * design tokens maps them on in a few lines, e.g.
 *
 *     .aip { --aip-accent: var(--wp--preset--color--primary); }
 */

.aip {
	/* ── surfaces ── */
	--aip-radius:        24px;
	--aip-radius-inner:  8px;
	--aip-surface:       #f2f3f7;
	--aip-surface-sunk:  #fff;
	--aip-border:        rgba(0, 0, 0, .12);

	/* ── ink ── */
	--aip-heading:       #000;
	--aip-text:          rgba(0, 0, 0, .75);
	--aip-accent:        #022eee;
	--aip-accent-ink:    var(--aip-accent);   /* accent used AS TEXT or a ring; lifted in dark */

	/* ── type ──
	   The body face comes from the theme. The prompt is monospace on purpose:
	   it is text to be copied verbatim, and a proportional face hides the
	   double spaces and line breaks that are part of it. */
	--aip-font:          inherit;
	--aip-mono:          ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
	                     "Liberation Mono", monospace;
	--aip-prompt-size:   .9375rem;
	--aip-prompt-lh:     1.7;     /* unitless, so the line cap below can use it */
	--aip-prompt-lines:  5;       /* visible lines before the box scrolls */
	--aip-heading-size:  clamp(1.125rem, .95rem + .8vw, 1.5rem);
	--aip-heading-weight: 600;

	/* ── spacing ──
	   A scale that still has room in it at 390px: a viewport-only scale bottoms
	   out near 10px on a phone, which reads as cramped. */
	--aip-pad:           clamp(20px, 3.4vw, 34px);
	--aip-gap:           clamp(18px, 2vw, 24px);
	--aip-prompt-pad:    clamp(16px, 2.2vw, 22px);
	--aip-headroom:      clamp(38px, 4vw, 48px);   /* space the stage grows into */

	/* ── button ── */
	--aip-btn-bg:        #000;
	--aip-btn-fg:        #fff;
	--aip-btn-bg-hover:  var(--aip-accent);
	--aip-btn-fg-hover:  #fff;
	--aip-btn-radius:    999px;

	/* ── motion ── */
	--aip-hold:          3000ms;
	--aip-emerge:        560ms;
	--aip-recede:        440ms;
	--aip-ease:          cubic-bezier(.16, .84, .34, 1);
	--aip-speed:         .22s;

	/* The stage grows upward, so the card reserves room above itself rather than
	   letting the layers ride over whatever paragraph precedes it. */
	margin-block: var(--aip-headroom) clamp(32px, 4vw, 52px);
	font-family: var(--aip-font);
	color: var(--aip-text);
}

/* Light is the base. mode="dark" swaps the surfaces and inverts the button,
   for a card dropped into a dark section. */
.aip[data-aip-mode="dark"] {
	--aip-surface:       #151a22;
	--aip-surface-sunk:  #0b0e14;
	--aip-border:        rgba(255, 255, 255, .2);
	--aip-heading:       #fff;
	--aip-text:          rgba(255, 255, 255, .75);
	--aip-btn-bg:        #fff;
	--aip-btn-fg:        #000;
	/* #022eee reads at 2.2:1 on this surface. The eyebrow is 11px text and the
	   focus ring is a 3:1 component, so the accent-as-ink is lifted here while
	   the accent-as-fill stays the brand blue. */
	--aip-accent-ink:    #7f9cff;
}

/* ════════════════════════════════════════════════════════════
   The stage — the copy confirmation
   Perspective is always on so the layers have somewhere to travel; at
   rest they sit flat behind the card at zero opacity and draw nothing.
   On copy they push back on Z toward a vanishing point above the card,
   which shrinks them and lifts them into view. Only transform, opacity
   and box-shadow animate, so the card never reflows.
   ════════════════════════════════════════════════════════════ */
.aip-stage {
	position: relative;
	z-index: 1;
	/* 700px is the value the Divi hero uses, but that hero is one tall element on
	   its own section. In an article the lift scales with card height, and a tall
	   phone card threw the layers over the paragraph above. A longer focal length
	   keeps the rise inside --aip-headroom at any card height. */
	perspective: 1200px;
	perspective-origin: 50% -50%;
	transform-style: preserve-3d;
	/* The stage paints the shadow and shares the card's box, so without this its
	   square corners show through inside the card's rounded ones -- a white notch
	   at each corner. */
	border-radius: var(--aip-radius);
	box-shadow: 0 0 0 0 transparent;
	transition: box-shadow var(--aip-recede) var(--aip-ease);
}

.aip-stage::before,
.aip-stage::after {
	content: "";
	position: absolute;
	/* Both layers must be pinned. Left to `top: auto` they take their static
	   position, and ::after -- which follows the card in flow -- lands below it
	   rather than behind it. */
	top: 0;
	left: 50%;
	width: 100%;
	height: 100%;
	border: 1px solid var(--aip-accent);
	border-radius: var(--aip-radius);
	background: linear-gradient(110deg, color-mix(in srgb, var(--aip-accent) 25%, transparent) 0, var(--aip-accent) 55%, color-mix(in srgb, var(--aip-accent) 35%, white) 100%);
	opacity: 0;
	pointer-events: none;
	transform: translateX(-50%) translateY(0) translateZ(0);
	transform-style: preserve-3d;
	transition:
		transform var(--aip-recede) var(--aip-ease),
		opacity var(--aip-recede) var(--aip-ease);
}

.aip-stage::before { z-index: -1; }
.aip-stage::after  { z-index: -2; }

/* A shadow sized for a full-bleed hero smears a grey haze across the
   paragraphs either side of an in-article card. This one is bounded and
   tinted with the accent, so it reads as the card lifting rather than as
   dirt on the page. */
.aip.is-copied .aip-stage {
	box-shadow:
		0 18px 40px -18px color-mix(in srgb, var(--aip-accent) 55%, transparent),
		0 4px 14px -6px rgba(0, 0, 0, .18);
	transition-duration: var(--aip-emerge);
}

.aip.is-copied .aip-stage::before,
.aip.is-copied .aip-stage::after {
	transition-duration: var(--aip-emerge);
}

/* The Z-recession lifts each layer in proportion to card height, which is
   slight on a short card, so a fixed rise carries the rest. */
.aip.is-copied .aip-stage::before {
	opacity: .55;
	transform: translateX(-50%) translateY(-5px) translateZ(-35px);
}

.aip.is-copied .aip-stage::after {
	opacity: .28;
	transform: translateX(-50%) translateY(-10px) translateZ(-75px);
}

/* ════════════════════════════════════════════════════════════
   The card
   ════════════════════════════════════════════════════════════ */
.aip-card {
	position: relative;
	z-index: 1;
	/* Holds the card at Z=0 in the stage's 3D space, so the layers recede behind
	   it rather than intersecting it. */
	transform: translateZ(0);
	transform-style: preserve-3d;
	display: flex;
	flex-direction: column;
	gap: var(--aip-gap);
	padding: var(--aip-pad);
	background: var(--aip-surface);
	border: 1px solid var(--aip-border);
	border-radius: var(--aip-radius);
	transition: border-color var(--aip-recede) var(--aip-ease);
}

.aip.is-copied .aip-card {
	border-color: var(--aip-accent);
	transition-duration: var(--aip-emerge);
}

.aip-head {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: var(--aip-gap);
	flex-wrap: wrap;
}

.aip-titles { min-width: 0; flex: 1 1 16rem; }

.aip-eyebrow {
	display: block;
	margin: 0 0 10px;
	font-family: var(--aip-mono);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--aip-accent-ink);
}

/* With no heading under it the eyebrow is the whole head row, so the gap that
   separated the two would otherwise hang off the bottom of it. */
.aip-eyebrow:last-child {
	margin-bottom: 0;
}

/* Same tier as the buttons: themes style `article h3` in chains that outrank
   any plain class selector on margin, size and colour. */
.aip:not(#_) .aip-stage .aip-card .aip-heading {
	margin: 0;
	max-width: none;
	font-size: var(--aip-heading-size);
	font-weight: var(--aip-heading-weight);
	line-height: 1.25;
	color: var(--aip-heading);
	text-wrap: balance;
}

.aip-prompt {
	box-sizing: border-box;
	margin: 0;
	max-width: none;
	padding: var(--aip-prompt-pad);
	background: var(--aip-surface-sunk);
	border: 1px solid var(--aip-border);
	border-radius: var(--aip-radius-inner);
	font-family: var(--aip-mono);
	font-size: var(--aip-prompt-size);
	font-weight: 400;
	line-height: var(--aip-prompt-lh);
	color: var(--aip-text);
	white-space: pre-wrap;
	overflow-wrap: anywhere;
	/* A long prompt scrolls inside its box rather than pushing the CTA off
	   screen. The cap is N lines plus the box's own padding and border. It is
	   measured in the box's real line height -- `lh`, with an em fallback --
	   rather than from the tokens, so it stays exactly N lines even if a theme
	   rule wins on font-size or line-height. The script marks a box that
	   actually overflows as focusable, so it can be scrolled from the keyboard. */
	max-height: calc(
		var(--aip-prompt-lines) * var(--aip-prompt-lh) * 1em
		+ 2 * var(--aip-prompt-pad) + 2px
	);
	max-height: calc(
		var(--aip-prompt-lines) * 1lh
		+ 2 * var(--aip-prompt-pad) + 2px
	);
	overflow-y: auto;
	overscroll-behavior: contain;
	scrollbar-width: thin;
	scrollbar-color: rgba(0, 0, 0, .28) transparent;   /* a quiet thumb, not the default grey block */
}

.aip-prompt:focus-visible {
	outline: 2px solid var(--aip-accent-ink);
	outline-offset: 3px;
}

/* ════════════════════════════════════════════════════════════
   Buttons
   Themes style `a`, `button` and `svg` by element inside the content
   area -- link colour, an underline drawn as a background-image, a
   bold weight, a reset on button borders. Two things keep those out.

   The selectors carry ID-level weight, (1,4,0), from `.aip:not(#_)`:
   a :not() counts the specificity of its argument, and an #id inside
   it adds an ID's worth without any markup. Class counting was an arms
   race that was lost twice. Twenty Twenty-One's `button:not(:hover):
   not(:active):not(.has-text-color)` is (0,3,1) and beat three classes;
   the Elegant Themes blog's `.article-section .article-container
   article a:not(.button):not(.et_social_networks a)` is (0,4,3) and beat
   four. No chain of classes and elements reaches the ID tier. What
   still gets past it: a theme rule with its own #id, or !important.

   And `all: unset` runs first, so every inherited property is cleared
   before ours are set -- including ones never declared here, which
   could never have won on specificity alone.
   ════════════════════════════════════════════════════════════ */
.aip:not(#_) .aip-stage .aip-card .aip-copy,
.aip:not(#_) .aip-stage .aip-card .aip-cta {
	all: unset;
	box-sizing: border-box;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: .5rem;
	margin: 0;
	padding: .875rem 1.35rem;
	font-family: inherit;
	font-size: .9375rem;
	font-weight: 500;
	line-height: 1.2;
	letter-spacing: normal;
	text-transform: none;
	text-decoration: none;
	white-space: nowrap;
	color: var(--aip-btn-fg);
	background-color: var(--aip-btn-bg);
	background-image: none;
	border: 1px solid transparent;
	border-radius: var(--aip-btn-radius);
	box-shadow: none;
	cursor: pointer;
	-webkit-appearance: none;
	appearance: none;
	transition:
		background-color var(--aip-speed) ease,
		color var(--aip-speed) ease,
		box-shadow var(--aip-speed) ease;
}

.aip:not(#_) .aip-stage .aip-card .aip-copy { flex: none; }

.aip:not(#_) .aip-stage .aip-card .aip-copy:hover,
.aip:not(#_) .aip-stage .aip-card .aip-cta:hover {
	background-color: var(--aip-btn-bg-hover);
	color: var(--aip-btn-fg-hover);
}

/* Themes commonly set a global `:focus { outline: … }`. The card owns its
   focus appearance instead: nothing on a pointer press, a clear ring for
   the keyboard. */
.aip:not(#_) .aip-stage .aip-card .aip-copy:focus,
.aip:not(#_) .aip-stage .aip-card .aip-cta:focus {
	outline: none;
}

.aip:not(#_) .aip-stage .aip-card .aip-copy:focus-visible,
.aip:not(#_) .aip-stage .aip-card .aip-cta:focus-visible {
	outline: 2px solid var(--aip-accent-ink);
	outline-offset: 3px;
}

/* The icons are stroke drawings that take the button's text colour. A theme
   `svg { fill: …; color: … }` rule would paint them, so both are pinned. */
.aip:not(#_) .aip-stage .aip-card .aip-ico {
	display: block;
	width: 15px;
	height: 15px;
	flex: none;
	color: inherit;
	fill: none;
	stroke: currentColor;
}

.aip:not(#_) .aip-stage .aip-card .aip-ico-done { display: none; }
.aip:not(#_) .aip-stage .aip-card .aip-cta .aip-ico { width: 14px; height: 14px; }

.aip:not(#_) .aip-stage .aip-card .aip-copy[data-state="copied"] {
	background-color: var(--aip-accent);
	color: #fff;
	box-shadow: 0 0 0 4px color-mix(in srgb, var(--aip-accent) 24%, transparent);
}

.aip:not(#_) .aip-stage .aip-card .aip-copy[data-state="copied"] .aip-ico-copy { display: none; }
.aip:not(#_) .aip-stage .aip-card .aip-copy[data-state="copied"] .aip-ico-done { display: block; }

.aip:not(#_) .aip-stage .aip-card .aip-copy[data-state="error"] {
	background-color: #c0341d;
	color: #fff;
}

.aip-foot {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--aip-gap);
	flex-wrap: wrap;
}

/* On a card with no heading the copy button has nothing to sit beside, so it
   drops to the bottom row: CTA left, copy right, which balances the card
   instead of leaving a button stranded at the top. `auto` rather than
   space-between so it still sits right when there is no CTA to push against. */
.aip:not(#_) .aip-stage .aip-card .aip-foot .aip-copy {
	margin-left: auto;
}

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

/* ════════════════════════════════════════════════════════════
   Narrow columns
   ════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
	/* The copy button wraps onto its own line under the heading and keeps its
	   natural width: stretched full-width it becomes a slab that outweighs the
	   prompt it exists to serve. */
	.aip { --aip-gap: 18px; }

	.aip-titles { flex-basis: 100%; }

	.aip-head { justify-content: flex-start; }

	.aip:not(#_) .aip-stage .aip-card .aip-copy,
	.aip:not(#_) .aip-stage .aip-card .aip-cta {
		padding: .8rem 1.2rem;
	}

	/* Once the bottom row wraps, a right-pushed button reads as a stray
	   element rather than a pair. */
	.aip:not(#_) .aip-stage .aip-card .aip-foot .aip-copy {
		margin-left: 0;
	}
}

/* ════════════════════════════════════════════════════════════
   Reduced motion
   The confirmation still lands -- the button's colour and icon carry it --
   but the 3D emergence is dropped rather than merely shortened.
   ════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
	.aip *,
	.aip *::before,
	.aip *::after {
		transition-duration: .01ms !important;
		animation-duration: .01ms !important;
	}

	/* The stage IS the card's own box: opacity or a transform here hides and
	   displaces the card itself, so it only loses its shadow. */
	.aip.is-copied .aip-stage {
		box-shadow: none;
	}

	/* The layers are what moves, so they simply never appear. */
	.aip.is-copied .aip-stage::before,
	.aip.is-copied .aip-stage::after {
		opacity: 0;
		transform: translateX(-50%) translateZ(0);
	}
}
