/* ==========================================================================
   Air Market - v5, the action-first hero (V5-SPEC.md).

   v5 is v4's page with ONE change: the hero's action surface. Where v4 (and
   v3) render a small `.buy-row` with a 24px "Get" chip, v5 rebuilds the hero
   into two columns - an identity column (icon, title, creator, value prop,
   benefit chips) and an ACTION column carrying a large "Open in Claude" split
   button, a helper line, and Save / Share as demoted secondaries. The chevron
   half of the split button opens an anchored options menu (Desktop / Web /
   Code / Copy prompt / Copy CLI / Learn how it works).

   Scope contract, held strictly so v0-v4 stay byte-identical:
   - Everything v5 SHARES with v4 (the value-prop lede, the benefit chips, the
     block reorder, all shell chrome) is styled by store-v4.css / store-v3-*.css
     whose selectors were widened to :is([data-ui="v4"],[data-ui="v5"]) etc. in
     the A5 sweep. This file does NOT restate those.
   - Everything BELOW is v5-only and scoped under :root[data-ui="v5"], so it can
     never reach v0-v4. The one exception is the reusable menu/toast primitives,
     which live in components.css (they are design-agnostic, not v5-only).

   Group C (V5-SPEC.md §16 C3). All rules scoped under :root[data-ui="v5"].
   ========================================================================== */

/* ---- Hero: two columns ------------------------------------------------------
   The base .detail-head is already a flex row (icon + flex:1 identity column).
   v5 adds a third child, .cta-col, and pins it right and vertically centred, so
   the action balances the 116px icon on the far left. */
:root[data-ui="v5"] .detail-head { gap: var(--space-32); align-items: flex-start; }
/* Let the identity column shrink instead of shoving the action off-screen. */
:root[data-ui="v5"] .detail-head > div[style*="flex"] { min-width: 0; }
:root[data-ui="v5"] .cta-col { flex: none; width: 360px; margin-left: auto; align-self: center; }
:root[data-ui="v5"] .cta-block { display: grid; gap: var(--space-12); }

/* ---- Anthropic / Claude brand values ----------------------------------------
   THIRD-PARTY BRAND VALUES. Not Air_DS, not ours. Every Anthropic-derived value
   in this codebase is in this one block: grep "--claude-" to find them all, and
   revert the whole branded-CTA treatment by deleting this block and restoring
   the six property references in the split-button rules below.

   Do NOT move these into tokens/air-ds.tokens.json or assets/css/tokens.css.
   Both are GENERATED (style-dictionary, and a Figma round-trip via /sync-figma),
   so a rebuild would either drop these values or push a third party's palette
   into Air_DS's own. Declared on :root[data-ui="v5"] rather than bare :root on
   purpose: in v0-v4 these properties do not exist at all, so a stray reference
   from a non-v5 rule resolves to nothing instead of quietly painting an older
   design orange.

   Provenance: the clay hex is the fill of Claude's own favicon
   (https://claude.ai/favicon.svg) and independently appears in the CSS shipped
   by https://www.anthropic.com/, so two Anthropic-controlled sources agree on
   it. Usage is nominative - it identifies the destination the button opens, the
   same basis on which app.js already ships GitHub's mark - and the context is an
   unpublished internal mock, not marketing.

   Contrast, computed from the WCAG relative-luminance formula rather than judged
   by eye, with alpha values composited over their backdrop first (label = the
   17px/600 CTA text; boundary = the fill against the white page):

   - The label is WHITE, on purpose, to match claude.ai's own product buttons -
     even though white on the clay fill measures only 3.12:1 and fails SC 1.4.3's
     4.5:1 floor for text this size (slate would clear it at 5.90:1). This is a
     knowing accessibility trade for brand-visual match, not an oversight: if
     that floor becomes a hard requirement later, revert --claude-label to
     --claude-slate below and the mark/chevron/label all move together again via
     currentColor.
   - --claude-slate itself is kept for the focus ring and the loading-spinner
     arc, NOT the label - those are dark-on-fill regardless of label colour, and
     the focus ring's own contrast math (see the :focus-visible rule below)
     depends on it staying slate.
   - Hover and active both DARKEN. That direction was chosen when the label was
     slate, to protect the button's boundary contrast against the page (2.77:1
     on lighten vs 3.51/3.97:1 on darken) while the label had contrast to spare.
     With a white label the boundary and label track together, so darkening
     still helps the edge without a label trade-off to weigh.
   - The divider needs far more weight than a like-for-like alpha would suggest.
     On this fill a light alpha is nearly invisible at low opacity; 0.65 is
     shipped for margin against antialiasing on a 1px line. It stays an rgba
     rather than a composited hex because the two halves hover independently, so
     the colour behind it is not constant. */
:root[data-ui="v5"] {
  --claude-orange:        #D97757;
  --claude-orange-hover:  #D56A46;
  --claude-orange-active: #D15C36;
  --claude-slate:         #141413;              /* focus ring + spinner arc only */
  --claude-label:         #FFFFFF;              /* label, mark, chevron - 3.12:1, accepted */
  --claude-ivory:         #FAF9F5;              /* focus-ring separator band only */
  --claude-divider:       rgba(255, 255, 255, 0.65); /* light rule on the fill */
}

/* ---- The split button -------------------------------------------------------
   One rounded rectangle, two hit targets divided by a 1px rule.

   PARTNER-BRAND EXCEPTION. This control is filled with Claude orange and labelled
   in white, matching claude.ai's own product buttons, not the ink/white pair
   the rest of the product uses. V5-SPEC.md §5.4 rejected a PER-LISTING accent -
   one hue per app across 49 listings - and that rejection still stands. This is
   a different case its own escape clause did not anticipate: a single fixed
   partner colour identifying the one destination the button opens. The white
   label is a deliberate SC 1.4.3 trade (3.12:1, below the 4.5:1 floor) made for
   brand-visual match; see the --claude-* block above for the full rationale and
   every measured ratio, and revert --claude-label to --claude-slate there if
   that floor must be met later.

   The rule this establishes, which the v5.1 block at the bottom of this file
   depends on: partner brand colour is reserved for the action that opens the
   partner's product. Every store-owned action stays on --color-action-primary. */
:root[data-ui="v5"] .cta-split {
  display: flex; align-items: stretch;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  transition: box-shadow 120ms ease, transform 120ms ease;
}
:root[data-ui="v5"] .cta-split:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); }
:root[data-ui="v5"] .cta-primary,
:root[data-ui="v5"] .cta-more {
  /* The mark and the chevron take the label colour through currentColor -
     neither declares its own colour, so both track the label if it ever
     changes. */
  border: 0; background: var(--claude-orange); color: var(--claude-label);
  cursor: pointer; transition: background-color 120ms ease;
}
:root[data-ui="v5"] .cta-primary {
  flex: 1 1 auto; min-width: 0;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  height: 56px; padding: 0 var(--space-24);
  font-family: var(--font); font-size: 17px; font-weight: 600; white-space: nowrap;
}
:root[data-ui="v5"] .cta-more {
  flex: none; width: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  /* 0.65 white ships for margin against antialiasing on a 1px line. It stays an
     rgba rather than a composited hex because the two halves hover
     independently, so the colour behind it moves. */
  border-left: 1px solid var(--claude-divider);
}
/* Explicit shades, not filter: brightness(). Multiplicative brightness on a
   saturated hue shifts perceived saturation rather than lightness, and the
   colour it paints appears nowhere in the source, so no state's contrast can be
   recorded. These two are derived from the resting fill by HSL lightness offset
   at fixed hue 14.8 and saturation 63.1%, so they are demonstrably descended
   from the official hex rather than picked by eye.

   BOTH STATES DARKEN. With a white label, label contrast and boundary contrast
   are the same measurement (white against the fill, fill against the white
   page - symmetric by the contrast formula), so there is no trade-off to weigh
   between them: lightening would drop both together, darkening lifts both
   together. Resting is 3.12:1, already below the 4.5:1 text floor by design
   (see the --claude-* block above); darkening improves it as it goes - 3.51:1
   hovered, 3.97:1 pressed - without a lightening path back toward AA to give up.

   The ladder stops at L-8%; it was chosen for the boundary/label ratio's steady
   climb, not against a text floor it was never going to clear.

   Colour is not the only cue: .cta-split:hover above still adds --shadow-md and
   a 1px lift, and that geometry carries the hover signal alongside the shade. */
:root[data-ui="v5"] .cta-primary:hover,
:root[data-ui="v5"] .cta-more:hover { background: var(--claude-orange-hover); }
:root[data-ui="v5"] .cta-primary:active,
:root[data-ui="v5"] .cta-more:active { background: var(--claude-orange-active); }
/* Focus ring: slate ring, ivory separator band, same 2px/4px inset geometry.
   The insets are load-bearing - .cta-split sets overflow: hidden above, which
   would clip an outline or an outward box-shadow, so the indicator has to be
   painted inside the control.

   box-shadow paints first-listed on top, so the old rule was really a 2px white
   ring over an ink band that was invisible because it equalled the fill - the
   second shadow did no work. Translating it literally would have reproduced that
   dead band in orange, and the white ring would now sit against a white page and
   vanish outright (1.00:1). Substituting ivory for the inner band costs nothing
   and turns dead geometry into a working separator.

   Conformance rests on the slate ring, not on the ivory: 18.43:1 outward against
   the page and 17.50:1 inward against the band, so both of the indicator's edges
   clear SC 1.4.11, and a continuous 2px perimeter satisfies SC 2.4.11. The
   ivory's own 2.96:1 against the fill is not a target - it is a separator inside
   the indicator, not the indicator boundary. */
:root[data-ui="v5"] .cta-split :focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--claude-slate), inset 0 0 0 4px var(--claude-ivory); }
/* 16px, DOWN from the sparkle's 18px. FR-10 expected the opposite - that the
   official mark's arms would be too thin and the box would need to grow - but
   the geometry says otherwise: the sunburst fills 95.0% of its viewBox height
   where the sparkle filled 78.8%, and carries 3.25x the ink. At 18px it would
   render 17.1px tall next to a 17px label, matching the type it is meant to
   lead. At 16px it renders 15.2px, about 1.25x the label's ~12px cap height,
   which is the ordinary band for a mark in a mark-plus-text lockup, and still
   ~7% taller than the decoration it replaces. The path itself is never
   simplified to fit a size (NFR-8). If 16px reads timid in situ, the agreed
   fallback is 17px here and 14px in the compact rule below - change only these
   two numbers.

   The mark's bounding box is vertically centred but sits 3.6% right of centre
   horizontally, which is 0.6px at this size. Accepted as-is; do not add an
   optical nudge next to a brand asset. */
:root[data-ui="v5"] .cta-brand svg { width: 16px; height: 16px; display: block; }
:root[data-ui="v5"] .cta-more svg { width: 20px; height: 20px; transition: transform 160ms ease; }
:root[data-ui="v5"] .cta-more[aria-expanded="true"] svg { transform: rotate(180deg); }

/* Loading: the primary region shows a spinner and "Opening Claude..."; the
   chevron stays live. */
:root[data-ui="v5"] .cta-primary.is-loading { pointer-events: none; }
:root[data-ui="v5"] .cta-primary.is-loading .cta-brand { display: none; }
:root[data-ui="v5"] .cta-primary.is-loading::before {
  /* Same structure as before - low-alpha track, full-strength head - inverted
     for a light fill. The old white borders were tuned for ink: on this fill the
     #fff head scrapes 3.12:1 with no headroom and the 0.35 white track drops to
     1.53:1, so the ring you read the arc against all but disappears. Ivory was
     rejected too, at 2.96:1. The arc carries the meaning and takes slate at
     5.90:1; the track is decorative and stays deliberately quiet at 1.70:1.
     Colours only - the geometry and the animation are untouched, so the
     reduced-motion rule below and setCtaLoading() both keep working unedited. */
  content: ""; width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid rgba(20, 20, 19, 0.30); border-top-color: var(--claude-slate);
  animation: cta-spin 0.8s linear infinite;
}
@keyframes cta-spin { to { transform: rotate(360deg); } }

/* ---- Helper line + secondary actions --------------------------------------- */
:root[data-ui="v5"] .cta-helper {
  margin: 0; text-align: center;
  font-size: 13px; line-height: 1.4; color: var(--text-2);
}
:root[data-ui="v5"] .cta-secondary { display: flex; gap: var(--space-8); justify-content: center; margin-top: var(--space-4); }
/* Save + Share are demoted to matched ghost buttons so the hero has exactly one
   filled control. This overrides the base .save-btn treatment under v5 only. */
:root[data-ui="v5"] .cta-secondary .save-btn,
:root[data-ui="v5"] .cta-ghost {
  display: inline-flex; align-items: center; gap: 6px;
  height: 40px; padding: 0 var(--space-16);
  border: 1px solid var(--color-border-default); border-radius: var(--radius-md);
  background: transparent; color: var(--color-text-primary);
  font-family: var(--font); font-size: 14px; font-weight: 500; cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease;
}
:root[data-ui="v5"] .cta-secondary .save-btn:hover,
:root[data-ui="v5"] .cta-ghost:hover { background: var(--color-action-secondary); border-color: var(--color-border-strong); }
:root[data-ui="v5"] .cta-secondary .save-btn .ic,
:root[data-ui="v5"] .cta-secondary .save-btn .sv-glyph svg,
:root[data-ui="v5"] .cta-ghost svg { width: 16px; height: 16px; }
/* The hero column centres its rows; the sync strip rides along. */
:root[data-ui="v5"] .cta-block .save-sync { margin: var(--space-8) auto 0; }
:root[data-ui="v5"] .cta-secondary .save-btn.is-saved { color: var(--color-brand-700); border-color: var(--color-brand-200); background: var(--color-brand-50); }
:root[data-ui="v5"] .cta-ghost:focus-visible,
:root[data-ui="v5"] .cta-secondary .save-btn:focus-visible { outline: none; border-color: var(--color-border-focus); }

/* ---- Sticky chrome bar: the compact split button --------------------------- */
/* Hidden on load so it never competes with the hero CTA; wire()'s scroll handler
   adds .revealed once the hero CTA scrolls under the chrome bar. */
:root[data-ui="v5"] .chrome-bar .cta-split.compact,
:root[data-ui="v5"] .chrome-bar .save-btn {
  opacity: 0; transform: translateY(-6px); pointer-events: none;
  /* visibility:hidden also pulls the hidden control out of the tab order and the
     accessibility tree, so keyboard/SR users never land on an invisible CTA.
     It transitions discretely (flips at the end of the fade-out). */
  visibility: hidden;
  transition: opacity 200ms ease, transform 200ms ease, visibility 0s linear 200ms;
}
:root[data-ui="v5"] .chrome-bar .cta-split.compact.revealed,
:root[data-ui="v5"] .chrome-bar .save-btn.revealed {
  opacity: 1; transform: translateY(0); pointer-events: auto;
  visibility: visible;
  transition: opacity 200ms ease, transform 200ms ease, visibility 0s;
}
:root[data-ui="v5"] .cta-split.compact { border-radius: var(--radius-md); box-shadow: none; }
:root[data-ui="v5"] .cta-split.compact:hover { transform: none; box-shadow: var(--shadow-sm); }
:root[data-ui="v5"] .cta-split.compact .cta-primary { height: 34px; padding: 0 var(--space-16); font-size: 13px; gap: 7px; }
/* 13px, down from 15px, on the same reasoning as the hero rule: renders 12.4px
   beside the 13px compact label. Legibility at this size is not a gamble - this
   exact path is Claude's browser-tab favicon, rasterised at 16px routinely and
   smaller on pinned tabs - but confirm it in the chrome bar during the visual
   pass. Fallback if it reads timid: 14px. */
:root[data-ui="v5"] .cta-split.compact .cta-primary .cta-brand svg { width: 13px; height: 13px; }
:root[data-ui="v5"] .cta-split.compact .cta-more { width: 34px; }
:root[data-ui="v5"] .cta-split.compact .cta-more svg { width: 18px; height: 18px; }

/* ---- v5.1 convergence: one primary-action family across the product ---------
   The listing CTA taught users that "the primary action" is a confident ink
   control with the radius-lg language. The home hero's primary button was still
   the small 8px/13px/~24px chip from v2 - so the landing page (a new user's
   first screen) had a WEAKER primary action than a detail page, in a different
   radius. This aligns it to the same family: ink, radius-lg, confident size,
   with the listing CTA's hover-lift and focus ring. Scoped to v5 only, so the
   legacy v2/v3/v4 toggles stay byte-identical. Not a resize for its own sake -
   it serves "what is this / start here" on the highest-traffic page.

   THIS BUTTON STAYS INK ON PURPOSE. The listing CTA above is now Claude orange,
   and the two sitting side by side in one release could easily read as a
   half-finished migration. It is not. The rule:

     Partner brand colour is reserved for the one action that opens the
     partner's product. Every store-owned action stays on
     --color-action-primary.

   This button navigates within the store - it does not open Claude - so wearing
   Anthropic's colour would misstate where the click lands, and would put a third
   party's brand on a store-owned control. Colour now encodes DESTINATION rather
   than rank; the v5.1 convergence remains a GEOMETRY family (radius, height,
   shadow, hover lift, focus ring), and that unification is untouched here.

   If the catalog ever lists a non-Claude destination: give that listing's CTA
   that partner's colour with contrast measured, not eyeballed, and weigh the
   same AA trade the Claude CTA makes explicitly rather than skipping it (see
   the --claude-* block at the top of this file), and leave every store-owned
   control ink. Do NOT generalise one partner's colour into the store's action
   colour. */
:root[data-ui="v5"] .v2-hero-cta .get-btn.primary {
  height: 44px;
  padding: 0 var(--space-24);
  border-radius: var(--radius-lg);
  font-size: 15px;
  font-weight: 600;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 120ms ease, transform 120ms ease, background-color 120ms ease;
}
:root[data-ui="v5"] .v2-hero-cta .get-btn.primary:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
}
:root[data-ui="v5"] .v2-hero-cta .get-btn.primary:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--color-text-inverse), inset 0 0 0 4px var(--color-action-primary);
}
@media (prefers-reduced-motion: reduce) {
  :root[data-ui="v5"] .v2-hero-cta .get-btn.primary,
  :root[data-ui="v5"] .v2-hero-cta .get-btn.primary:hover { transition: none; transform: none; }
}

/* ---- Responsive (V5-SPEC.md §12) ------------------------------------------- */
@media (max-width: 1023px) {
  :root[data-ui="v5"] .cta-col { width: 300px; }
  :root[data-ui="v5"] .cta-primary { height: 52px; font-size: 16px; }
}
@media (max-width: 720px) {
  /* Single column: the action drops below the identity and goes full width. */
  :root[data-ui="v5"] .detail-head { flex-wrap: wrap; }
  :root[data-ui="v5"] .cta-col { width: 100%; margin-left: 0; align-self: stretch; }
  :root[data-ui="v5"] .cta-helper { text-align: left; }
  :root[data-ui="v5"] .cta-secondary { justify-content: flex-start; }
}

/* ---- Motion (V5-SPEC.md §13) ----------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  :root[data-ui="v5"] .cta-split,
  :root[data-ui="v5"] .cta-split:hover,
  :root[data-ui="v5"] .cta-more svg { transition: none; transform: none; }
  :root[data-ui="v5"] .cta-primary.is-loading::before { animation: none; }
  /* Sticky CTA still appears/disappears, just without the slide or fade. */
  :root[data-ui="v5"] .chrome-bar .cta-split.compact,
  :root[data-ui="v5"] .chrome-bar .save-btn { transition: visibility 0s; transform: none; }
  :root[data-ui="v5"] .chrome-bar .cta-split.compact.revealed,
  :root[data-ui="v5"] .chrome-bar .save-btn.revealed { transition: visibility 0s; transform: none; }
}
