/* ============================================================================
   mm-polish.css — shared finish layer for every Cultivate screen.

   Loaded by all *.dc.html. Everything here is deliberately LOW SPECIFICITY
   (element and pseudo-element selectors only, no !important except the
   reduced-motion guard) so the inline styles the screens are written in always
   win. This fills gaps; it never overrides a screen's own design decisions.

   Audited before writing: font-smoothing was set on 0/40 screens, a
   reduced-motion guard on 7/40, a focus-visible ring on 20/40, and tabular
   numerals on 4/40. Those are the gaps this closes.
   ============================================================================ */

/* ── 1. Type rendering ─────────────────────────────────────────────────────
   Light text on dark backgrounds renders heavy with subpixel antialiasing.
   Greyscale AA is what makes the UI read crisp rather than slightly bloomed —
   the single biggest perceptual change in this file. */
html {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* Kerning/ligatures for the display face; never for mono (it breaks alignment). */
body {
  font-kerning: normal;
  font-feature-settings: "kern" 1;
}

/* ── 2. Numerals ───────────────────────────────────────────────────────────
   Every number in this app is set in JetBrains Mono. Tabular figures stop
   counters, KPI tiles and table columns from shifting width as digits change —
   the count-up animations were visibly jittering without this. */
[style*="--mono"],
[style*="JetBrains"],
code, kbd, samp, pre {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* ── 3. Keyboard focus ─────────────────────────────────────────────────────
   A visible ring on every interactive element, using the screen's own accent
   so it inherits per-screen theming. :focus-visible (not :focus) so it appears
   for keyboard users without ringing on mouse clicks. */
:focus-visible {
  outline: 2px solid var(--accent, #a394f5);
  outline-offset: 2px;
}
/* Screens that draw their own ring keep it — this only removes the UA default. */
:focus:not(:focus-visible) { outline: none; }

/* ── 4. Interactive feel ───────────────────────────────────────────────────
   One consistent easing for hover/active across buttons, links and inputs.
   Transitioning specific properties (not `all`) keeps layout off the
   compositor's critical path. */
button, a, input, select, textarea, summary, [role="button"], [role="tab"] {
  transition:
    background-color .16s cubic-bezier(.2, .7, .2, 1),
    border-color     .16s cubic-bezier(.2, .7, .2, 1),
    color            .16s cubic-bezier(.2, .7, .2, 1),
    box-shadow       .16s cubic-bezier(.2, .7, .2, 1),
    filter           .16s cubic-bezier(.2, .7, .2, 1),
    opacity          .16s cubic-bezier(.2, .7, .2, 1),
    transform        .16s cubic-bezier(.2, .7, .2, 1);
}
button:active, [role="button"]:active { transform: translateY(.5px); }

/* Kill the grey flash on tap and the iOS long-press callout. */
button, a, [role="button"] {
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}
button:disabled, [aria-disabled="true"] { cursor: not-allowed; opacity: .45; }

/* ── 5. Selection ──────────────────────────────────────────────────────────*/
::selection      { background: rgba(163, 148, 245, .35); color: #f2f5ff; }
::-moz-selection { background: rgba(163, 148, 245, .35); color: #f2f5ff; }

/* ── 6. Scrollbars ─────────────────────────────────────────────────────────
   Thin dark scrollbars everywhere; the default light ones were breaking the
   dark surface on the screens that hadn't styled them. */
* { scrollbar-width: thin; scrollbar-color: #2e3c5e transparent; }
::-webkit-scrollbar            { width: 8px; height: 8px; }
::-webkit-scrollbar-track      { background: transparent; }
::-webkit-scrollbar-thumb      { background: #2e3c5e; border-radius: 100px; border: 2px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-thumb:hover{ background: #3e4f78; border: 2px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-corner     { background: transparent; }

/* ── 7. Scroll containment ─────────────────────────────────────────────────
   Screens render inside an iframe in the shell. Without this, scrolling past
   the end of an inner panel chains to the parent frame and drags the whole
   app — the "page jumps while I'm scrolling a list" behaviour. */
body { overscroll-behavior: contain; }

/* ── 8. Text layout ────────────────────────────────────────────────────────
   `pretty` prevents single-word orphans on headings and copy. Applied only to
   text elements so it can't affect flex/grid chrome. */
h1, h2, h3, h4, h5, h6 { text-wrap: balance; }
p, li, figcaption       { text-wrap: pretty; }

/* Long URLs and venue names shouldn't blow out a fixed-width panel. */
a[href] { overflow-wrap: break-word; }

/* ── 9. Media defaults ─────────────────────────────────────────────────────*/
img, svg, video, canvas { max-width: 100%; }
img { image-rendering: auto; }

/* ── 10. Reduced motion ────────────────────────────────────────────────────
   The app is animation-heavy (boot sequences, count-ups, staggered entrances).
   Only 7/40 screens honoured this. Animations are reduced to a single frame
   rather than removed, so `animation-fill-mode: both` still applies the end
   state and nothing renders invisible. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── 11. Forced-colors / high-contrast ─────────────────────────────────────*/
@media (forced-colors: active) {
  :focus-visible { outline: 2px solid CanvasText; }
}

/* ── 12. AI thinking indicator ────────────────────────────────────────────
   One shared "Claude is working on this" animation, used everywhere a
   screen is actually waiting on an AI call: Tour Planner's architect,
   Ask the Data, Competition Grid's night explain, and anywhere else that
   calls IArchitectService. A solid wireframe cube genuinely tumbling in 3D
   (real perspective/rotateX/rotateY on the badge itself, not a 2D illusion)
   with a glowing rune suspended at its center, read as "processing," not
   "loading a page" -- picked over an earlier orbiting-rings design (see git
   history) for reading cleanly at every size instead of turning into fine
   crossed lines at the smallest one. The label shimmers instead of just
   sitting there so a slow model call still feels alive.

   Markup (unchanged in element count from the earlier ring/dot version --
   this is a pure CSS redesign, every existing call site upgrades with no
   template edits beyond the one-time swap from ring+3 dots to 6 faces):
   <span class="ai-thinking">
     <span class="ai-thinking-badge">
       <span class="ai-thinking-face"></span><span class="ai-thinking-face"></span><span class="ai-thinking-face"></span>
       <span class="ai-thinking-face"></span><span class="ai-thinking-face"></span><span class="ai-thinking-face"></span>
       <span class="ai-thinking-core">✦</span>
     </span>
     <span class="ai-thinking-label">Your label here…</span>
   </span>
   The 6 .ai-thinking-face spans are a real cube's faces: each gets a fixed
   STATIC transform (translateZ to its side, or rotateY/rotateX + translateZ
   for the other 5) positioning it relative to the cube's own center: no
   per-face keyframe needed, because the actual spin lives on their shared
   parent (.ai-thinking-badge, which also holds perspective) and 3D children
   inherit a rotating parent's coordinate space for free under
   transform-style:preserve-3d. --cube-half (half the cube's side, so a face
   sits flush against it) is the one size-dependent number, overridden per
   variant below; the spin keyframe itself never changes.

   Respects each page's own --accent/--text-2/--mono if set; falls back
   otherwise, so it drops into any screen without extra wiring. Reduced
   motion is covered globally by section 10, not repeated here. */
@keyframes aiThinkCubeSpin { from { transform: rotateX(0deg) rotateY(0deg); } to { transform: rotateX(360deg) rotateY(360deg); } }
@keyframes aiThinkCubeCore { 0%, 100% { opacity: .75; transform: translate(-50%,-50%) scale(1); } 50% { opacity: 1; transform: translate(-50%,-50%) scale(1.25); } }
@keyframes aiThinkShimmer { to { background-position: -200% 0; } }

.ai-thinking { display: inline-flex; align-items: center; gap: 10px; }
.ai-thinking-badge {
  position: relative; width: 24px; height: 24px; flex-shrink: 0;
  perspective: 60px; transform-style: preserve-3d; --cube-half: 12px;
  animation: aiThinkCubeSpin 4.2s linear infinite;
}
.ai-thinking-face {
  position: absolute; inset: 0; margin: 0;
  border: 1.5px solid var(--accent, #a394f5);
  background: rgba(163, 148, 245, .09);
  box-shadow: 0 0 10px rgba(163, 148, 245, .22) inset;
}
.ai-thinking-face:nth-child(1) { transform: translateZ(var(--cube-half)); }
.ai-thinking-face:nth-child(2) { transform: rotateY(180deg) translateZ(var(--cube-half)); }
.ai-thinking-face:nth-child(3) { transform: rotateY(90deg) translateZ(var(--cube-half)); }
.ai-thinking-face:nth-child(4) { transform: rotateY(-90deg) translateZ(var(--cube-half)); }
.ai-thinking-face:nth-child(5) { transform: rotateX(90deg) translateZ(var(--cube-half)); }
.ai-thinking-face:nth-child(6) { transform: rotateX(-90deg) translateZ(var(--cube-half)); }
.ai-thinking-core {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%);
  font-size: 11px; line-height: 1; color: var(--accent, #a394f5);
  text-shadow: 0 0 8px currentColor;
  animation: aiThinkCubeCore 2.1s ease-in-out infinite;
}
.ai-thinking-label {
  font-family: var(--mono, 'JetBrains Mono', monospace); font-size: 10.5px; letter-spacing: .4px;
  background: linear-gradient(90deg, var(--text-2, #8792ad) 0%, var(--text-2, #8792ad) 40%, #fff 50%, var(--text-2, #8792ad) 60%, var(--text-2, #8792ad) 100%);
  background-size: 250% 100%; -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: aiThinkShimmer 1.6s linear infinite;
}

/* Larger variant -- add class="ai-thinking ai-thinking-lg" for a standalone/centered loading
   moment with real room around it (Ask the Data, Competition Grid's no-day-selected panel,
   one-sheet/outreach drafting). Leave the default size wherever the badge sits inline next to
   other dense content (e.g. Competition Grid's per-night "why" note, squeezed into a bordered
   card beside the day title). The spin keyframe is identical at every size -- only --cube-half
   and the border/glyph geometry scale. */
.ai-thinking-lg { gap: 14px; }
.ai-thinking-lg .ai-thinking-badge { width: 44px; height: 44px; perspective: 110px; --cube-half: 22px; }
.ai-thinking-lg .ai-thinking-face { border-width: 2.5px; }
.ai-thinking-lg .ai-thinking-core { font-size: 19px; }
.ai-thinking-lg .ai-thinking-label { font-size: 13px; }

/* Hero variant -- add class="ai-thinking ai-thinking-xl" (stacked: text under the badge, not
   beside it) for a loading moment that owns most of its panel with nothing else competing for
   attention, e.g. Tour Planner's architect results pane while it has no plan yet. About 2.7x
   the already-large .ai-thinking-lg badge. */
.ai-thinking-xl { flex-direction: column; gap: 12px; text-align: center; }
.ai-thinking-xl .ai-thinking-badge { width: 80px; height: 80px; perspective: 200px; --cube-half: 40px; }
.ai-thinking-xl .ai-thinking-face { border-width: 2.5px; }
.ai-thinking-xl .ai-thinking-core { font-size: 33px; }
.ai-thinking-xl .ai-thinking-label { font-size: 13px; max-width: 34ch; }

/* ---------------------------------------------------------------------------------------------
   Loading veil (2026-09-22). A screen sets data-mm-loading="1" on a container while it fetches
   (Console: <main>, driven by its `busy` state); every standard panel under it gets a skeleton
   over its BODY -- the header stays readable, so you can see what is loading -- and every KPI
   tile gets one over its number. Keyed on the panels' shared inline styles, so no per-panel
   markup changes (the Charts and Electronic panels, 2026-10-11, are the classed .ch-panel / .el-panel
   instead). Each selector lists the style twice: as written in the .dc.html template, and
   as the browser re-serializes it after the DC runtime renders (spaces after ':' and ';', hex ->
   rgb(), a default 180deg gradient angle dropped) -- the rendered form is what actually matches.
   --------------------------------------------------------------------------------------------- */
[data-mm-loading="1"] :is(div[style*="border: 1px solid var(--border-lit); background: var(--surface)"], div[style*="border:1px solid var(--border-lit);background:var(--surface)"], .ch-panel, .el-panel), [data-mm-loading="1"] :is(div[style*="background: linear-gradient(rgb(16, 22, 44), rgb(11, 16, 32))"], div[style*="background:linear-gradient(180deg,#10162c,#0b1020)"]) { position: relative; }
[data-mm-loading="1"] :is(div[style*="border: 1px solid var(--border-lit); background: var(--surface)"], div[style*="border:1px solid var(--border-lit);background:var(--surface)"], .ch-panel, .el-panel) { min-height: 150px; }
/* ::before = opaque veil + label; ::after = skeleton rows with a moving sheen. */
[data-mm-loading="1"] :is(div[style*="border: 1px solid var(--border-lit); background: var(--surface)"], div[style*="border:1px solid var(--border-lit);background:var(--surface)"], .ch-panel, .el-panel)::before, [data-mm-loading="1"] :is(div[style*="background: linear-gradient(rgb(16, 22, 44), rgb(11, 16, 32))"], div[style*="background:linear-gradient(180deg,#10162c,#0b1020)"])::before {
  content: "LOADING";
  position: absolute; left: 0; right: 0; top: 46px; bottom: 0; z-index: 6;
  background: var(--surface, #0d1428);
  padding: 12px 16px;
  font-family: var(--mono, 'JetBrains Mono', monospace); font-size: 9px; letter-spacing: 2px;
  color: var(--accent, #a394f5);
  animation: mmVeilPulse 1.4s ease-in-out infinite;
}
[data-mm-loading="1"] :is(div[style*="border: 1px solid var(--border-lit); background: var(--surface)"], div[style*="border:1px solid var(--border-lit);background:var(--surface)"], .ch-panel, .el-panel)::after, [data-mm-loading="1"] :is(div[style*="background: linear-gradient(rgb(16, 22, 44), rgb(11, 16, 32))"], div[style*="background:linear-gradient(180deg,#10162c,#0b1020)"])::after {
  content: "";
  position: absolute; left: 16px; right: 16px; top: 76px; bottom: 16px; z-index: 7;
  background-image:
    linear-gradient(100deg, transparent 30%, rgba(163, 148, 245, .16) 50%, transparent 70%),
    repeating-linear-gradient(180deg, rgba(135, 146, 173, .13) 0 10px, transparent 10px 26px);
  background-size: 220% 100%, 100% 100%;
  animation: mmVeilSheen 1.3s linear infinite;
  border-radius: 2px;
  pointer-events: none;
}
/* KPI tiles are short: veil below the label, one skeleton bar for the number. */
[data-mm-loading="1"] :is(div[style*="background: linear-gradient(rgb(16, 22, 44), rgb(11, 16, 32))"], div[style*="background:linear-gradient(180deg,#10162c,#0b1020)"])::before { top: 26px; padding: 0; background: linear-gradient(180deg, #10162c, #0b1020); content: ""; }
[data-mm-loading="1"] :is(div[style*="background: linear-gradient(rgb(16, 22, 44), rgb(11, 16, 32))"], div[style*="background:linear-gradient(180deg,#10162c,#0b1020)"])::after {
  top: 32px; bottom: auto; right: 45%; height: 26px;
  background-image:
    linear-gradient(100deg, transparent 30%, rgba(163, 148, 245, .2) 50%, transparent 70%),
    linear-gradient(rgba(135, 146, 173, .16), rgba(135, 146, 173, .16));
}
@keyframes mmVeilSheen { from { background-position: 120% 0, 0 0; } to { background-position: -120% 0, 0 0; } }
@keyframes mmVeilPulse { 0%, 100% { color: var(--accent, #a394f5); } 50% { color: rgba(163, 148, 245, .35); } }   /* label only -- the veil stays opaque */
@media (prefers-reduced-motion: reduce) {
  [data-mm-loading="1"] div::before, [data-mm-loading="1"] div::after { animation: none !important; }
}


/* ---------------------------------------------------------------------------------------------
   Detail-modal skeleton (2026-09-29). The venue/artist modal opens instantly with only the row
   it was clicked from, then fills in when its own reads land. While they are in flight the page
   sets data-mm-skel="1" on the modal's columns (data-mm-sk = side | main | sheet) and each one
   is covered below its header with skeleton rows and a moving sheen, so the identity (avatar,
   name, tabs) stays readable and nothing half-loaded shows through.
   --------------------------------------------------------------------------------------------- */
[data-mm-sk="side"]  { --sk-top: 108px; --sk-bg: #0b1122; --sk-pad: 20px; }
[data-mm-sk="main"]  { --sk-top: 84px;  --sk-bg: var(--surface, #10162c); --sk-pad: clamp(20px, 4vw, 40px); }
[data-mm-sk="sheet"] { --sk-top: 0px;   --sk-bg: var(--surface, #10162c); --sk-pad: 20px; }
.mb-modal-b[data-mm-sk="sheet"] { --sk-bg: var(--mb-bg, #0b1020); --sk-pad: 16px; }
[data-mm-skel="1"] { position: relative; overflow: hidden !important; }
/* ::before = the opaque cover with the skeleton shapes drawn on it; ::after = the moving sheen. */
[data-mm-skel="1"]::before {
  content: "LOADING"; position: absolute; z-index: 30; left: 0; right: 0; top: var(--sk-top); bottom: 0; box-sizing: border-box;
  padding: 14px var(--sk-pad) 24px;
  font-family: var(--mono, 'JetBrains Mono', monospace); font-size: 9px; letter-spacing: 2px;
  color: var(--accent, #a394f5); animation: mmVeilPulse 1.4s ease-in-out infinite;
  background-color: var(--sk-bg); background-origin: content-box; background-repeat: no-repeat;
  background-image:
    linear-gradient(rgba(135, 146, 173, .14), rgba(135, 146, 173, .14)),
    linear-gradient(rgba(135, 146, 173, .10), rgba(135, 146, 173, .10)),
    repeating-linear-gradient(180deg, rgba(135, 146, 173, .11) 0 12px, transparent 12px 30px);
  background-size: 62% 20px, 100% 84px, 100% calc(100% - 200px);
  background-position: 0 38px, 0 74px, 0 182px;
}
[data-mm-sk="side"][data-mm-skel="1"]::before {
  background-image:
    linear-gradient(rgba(135, 146, 173, .13), rgba(135, 146, 173, .13)),
    linear-gradient(rgba(135, 146, 173, .13), rgba(135, 146, 173, .13)),
    linear-gradient(rgba(135, 146, 173, .13), rgba(135, 146, 173, .13)),
    linear-gradient(rgba(135, 146, 173, .13), rgba(135, 146, 173, .13)),
    repeating-linear-gradient(180deg, rgba(135, 146, 173, .11) 0 10px, transparent 10px 28px);
  background-size: 48% 58px, 48% 58px, 48% 58px, 48% 58px, 100% calc(100% - 200px);
  background-position: 0 38px, 100% 38px, 0 104px, 100% 104px, 0 186px;
}
[data-mm-skel="1"]::after {
  content: ""; position: absolute; z-index: 31; pointer-events: none;
  left: 0; right: 0; top: calc(var(--sk-top) + 36px); bottom: 0;
  background-image: linear-gradient(100deg, transparent 30%, rgba(163, 148, 245, .14) 50%, transparent 70%);
  background-size: 220% 100%; background-repeat: no-repeat;
  animation: mmVeilSheen 1.3s linear infinite;
}
@media (prefers-reduced-motion: reduce) { [data-mm-skel="1"]::before, [data-mm-skel="1"]::after { animation: none !important; } }

/* ---------------------------------------------------------------------------------------------
   Number skeleton (2026-09-30). A KPI tile whose value is still being fetched (an artist
   modal's show totals arrive after the modal opens) carries data-mm-num="1" on the number
   element: the text is hidden and a shimmering bar sits where the number will be, so the tile
   never reads as blank or as a false zero. Flip the attribute to "0" when the value lands.
   --------------------------------------------------------------------------------------------- */
[data-mm-num="1"] { position: relative; color: transparent !important; text-shadow: none !important; }
[data-mm-num="1"] * { visibility: hidden !important; }
[data-mm-num="1"]::before {
  content: ""; position: absolute; left: 22%; right: 22%; top: 10%; bottom: 10%; border-radius: 4px;
  background: linear-gradient(90deg, rgba(135, 146, 173, .12) 0%, rgba(135, 146, 173, .32) 50%, rgba(135, 146, 173, .12) 100%);
  background-size: 200% 100%; animation: mmNumSk 1.2s linear infinite;
}
@keyframes mmNumSk { from { background-position: 200% 0; } to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { [data-mm-num="1"]::before { animation: none; } }

/* ---- Phones (under 760px) get a few desktop screens as they are (Dashboard, Contacts, Saved, Alerts,
   Account, Pipeline, Reports; 2026-10-06). A type floor for their inline-styled text: nothing under 9px.
   The purpose-built *Mobile.dc.html screens never go below 9px, so this does not touch them. */
@media (max-width: 760px) {
  [style*="font-size:6px"], [style*="font-size:6.5px"], [style*="font-size:7px"], [style*="font-size:7.5px"],
  [style*="font-size:8px"], [style*="font-size:8.5px"],
  [style*="font-size: 6px"], [style*="font-size: 6.5px"], [style*="font-size: 7px"], [style*="font-size: 7.5px"],
  [style*="font-size: 8px"], [style*="font-size: 8.5px"] { font-size: 9px !important; }   /* the runtime writes "font-size: 7.5px;" */
}

/* ── 13. The AI mark ──────────────────────────────────────────────────────
   One small animated mark for anything AI, wherever it appears: the AI tab on a window, a tool
   card, a button. The same cube as .ai-thinking, turning slowly (it is a mark, not a wait), with
   the rune glowing at its centre. [data-on="1"] (the tab is open) turns it faster and brighter.
   Markup: <span class="ai-mark"><i></i><i></i><i></i><i></i><i></i><i></i><b>✦</b></span> */
@keyframes aiMarkSpin { from { transform: rotateX(-18deg) rotateY(0deg); } to { transform: rotateX(-18deg) rotateY(360deg); } }
@keyframes aiMarkGlow { 0%, 100% { opacity: .8; text-shadow: 0 0 6px currentColor; } 50% { opacity: 1; text-shadow: 0 0 14px currentColor, 0 0 26px currentColor; } }
.ai-mark { position: relative; display: inline-block; width: 18px; height: 18px; flex-shrink: 0; vertical-align: -3px;
  perspective: 50px; transform-style: preserve-3d; --cube-half: 9px; animation: aiMarkSpin 9s linear infinite; }
.ai-mark > i { position: absolute; inset: 0; border: 1.2px solid var(--accent, #a394f5); background: rgba(163, 148, 245, .07); box-shadow: 0 0 8px rgba(163, 148, 245, .18) inset; }
.ai-mark > i:nth-child(1) { transform: translateZ(var(--cube-half)); }
.ai-mark > i:nth-child(2) { transform: rotateY(180deg) translateZ(var(--cube-half)); }
.ai-mark > i:nth-child(3) { transform: rotateY(90deg) translateZ(var(--cube-half)); }
.ai-mark > i:nth-child(4) { transform: rotateY(-90deg) translateZ(var(--cube-half)); }
.ai-mark > i:nth-child(5) { transform: rotateX(90deg) translateZ(var(--cube-half)); }
.ai-mark > i:nth-child(6) { transform: rotateX(-90deg) translateZ(var(--cube-half)); }
.ai-mark > b { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 9px; line-height: 1; font-weight: 400;
  color: var(--accent, #a394f5); animation: aiMarkGlow 2.6s ease-in-out infinite; }
[data-on="1"] > .ai-mark, .ai-mark[data-on="1"] { animation-duration: 3.2s; }
[data-on="1"] > .ai-mark > b, .ai-mark[data-on="1"] > b { animation-duration: 1.2s; }
.ai-mark-lg { width: 26px; height: 26px; perspective: 70px; --cube-half: 13px; vertical-align: -6px; }
.ai-mark-lg > b { font-size: 13px; }

/* ── 14. The act window (2026-10-06) ──────────────────────────────────────
   A detail window with no sidebar: a header band (art, the name across the width, a kicker line,
   the actions), a strip of five stat tiles, a tab rail, then the open tab. Overview is two columns
   on a wide window (the read on the left, facts and links on the right) and one on a narrow one.
   Every piece enters in order: the back fades, the panel lands, the art pops, the title slides in
   from the left as it sharpens, the kicker and actions follow, the tiles rise one after another,
   the tab rail drops in and the first cards rise. --d on each piece is its cue. Reduced motion is
   handled globally (section 10). */
@keyframes awBackIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes awBackOut { from { opacity: 1; } to { opacity: 0; } }
@keyframes awPanelIn { 0% { opacity: 0; transform: translateY(26px) scale(.965); } 100% { opacity: 1; transform: none; } }
@keyframes awPanelOut { 0% { opacity: 1; transform: none; } 100% { opacity: 0; transform: translateY(14px) scale(.975); } }
@keyframes awArt { 0% { opacity: 0; transform: scale(.55) rotate(-9deg); filter: blur(6px); } 60% { filter: blur(0); } 100% { opacity: 1; transform: none; } }
@keyframes awTitle { 0% { opacity: 0; transform: translateX(-22px); filter: blur(7px); letter-spacing: 2px; } 100% { opacity: 1; transform: none; filter: blur(0); letter-spacing: -.4px; } }
@keyframes awRise { 0% { opacity: 0; transform: translateY(14px); } 100% { opacity: 1; transform: none; } }
@keyframes awDrop { 0% { opacity: 0; transform: translateY(-10px); } 100% { opacity: 1; transform: none; } }
@keyframes awLine { 0% { transform: scaleX(0); } 100% { transform: scaleX(1); } }
@keyframes awGlow { 0% { box-shadow: 0 0 0 0 rgba(163,148,245,0); } 40% { box-shadow: 0 0 0 10px rgba(163,148,245,.12); } 100% { box-shadow: 0 0 0 0 rgba(163,148,245,0); } }

.aw-back { position: fixed; inset: 0; z-index: 50; display: flex; align-items: center; justify-content: center; padding: 28px;
  background: rgba(4, 7, 16, .74); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
.aw { position: relative; width: 100%; max-width: 1180px; height: 100%; max-height: 860px; display: flex; flex-direction: column;
  border-radius: 20px; background: var(--surface, #10162c); border: 1px solid var(--border-lit, #2e3c5e); overflow: hidden;
  box-shadow: 0 30px 80px -20px rgba(0, 0, 0, .6), 0 0 0 1px rgba(163, 148, 245, .05); color: var(--text, #d6def0); }
.aw > * { animation-fill-mode: both; }
.aw-x { position: absolute; top: 16px; right: 18px; z-index: 8; width: 32px; height: 32px; border-radius: 100px; border: 1px solid var(--border-lit, #2e3c5e);
  background: rgba(11, 17, 34, .9); color: var(--text-2, #8792ad); font-size: 13px; cursor: pointer; animation: awRise .35s ease both var(--d, .9s); }
.aw-x:hover { color: var(--text, #d6def0); border-color: var(--accent, #a394f5); }

/* the header band */
.aw-head { position: relative; flex-shrink: 0; display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 18px 22px; align-items: center;
  padding: 26px clamp(22px, 3.6vw, 44px) 18px; background: linear-gradient(180deg, rgba(11, 17, 34, .92), rgba(16, 22, 44, 0)); }
.aw-head::before { content: ''; position: absolute; inset: 0 0 auto 0; height: 180px; pointer-events: none;
  background: radial-gradient(60% 120% at 12% 0%, var(--aw-tint, rgba(163, 148, 245, .22)), transparent 70%); opacity: .9; }
.aw-head > * { position: relative; }
.aw-art { width: 74px; height: 74px; border-radius: 16px; flex-shrink: 0; position: relative; overflow: hidden; display: flex; align-items: center; justify-content: center;
  font-family: var(--tech, 'Archivo', sans-serif); font-size: 24px; font-weight: 800; color: #0a0e1a; animation: awArt .7s cubic-bezier(.2, .9, .2, 1.1) both var(--d, .42s), awGlow 1.6s ease both calc(var(--d, .42s) + .5s); }
.aw-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.aw-id { min-width: 0; }
.aw-kicker { display: flex; flex-wrap: wrap; align-items: center; gap: 7px 10px; font-family: var(--mono, 'JetBrains Mono', monospace); font-size: 9.5px; letter-spacing: .9px; color: var(--text-3, #566079); text-transform: uppercase;
  animation: awRise .45s cubic-bezier(.2, .8, .2, 1) both var(--d, .6s); }
.aw-kicker .aw-chip { display: inline-block; padding: 3px 9px; border-radius: 3px; font-weight: 700; letter-spacing: .6px; }
.aw-kicker .aw-dot { color: var(--border-lit, #2e3c5e); }
.aw-kicker .aw-status { font-weight: 700; }
.aw-title { margin: 6px 0 0; font-family: var(--tech, 'Archivo', sans-serif); font-weight: 800; font-size: clamp(26px, 3.2vw, 38px); line-height: 1.02; letter-spacing: -.4px; color: #f2f5ff;
  text-wrap: balance; text-shadow: 0 2px 30px rgba(163, 148, 245, .25); animation: awTitle .75s cubic-bezier(.2, .8, .2, 1) both var(--d, .5s); }
.aw-sub { margin-top: 7px; font-family: var(--sans, 'Inter', sans-serif); font-size: 12.5px; color: var(--text-2, #8792ad); animation: awRise .45s ease both var(--d, .68s); }
.aw-actions { display: flex; flex-direction: column; align-items: stretch; gap: 8px; animation: awRise .45s cubic-bezier(.2, .8, .2, 1) both var(--d, .64s); padding-right: 36px; }
.aw-actions > div { display: flex; gap: 8px; }
.aw-rule { position: relative; height: 1px; margin: 0 clamp(22px, 3.6vw, 44px); background: linear-gradient(90deg, var(--accent, #a394f5), var(--border-lit, #2e3c5e) 55%, transparent); transform-origin: left; animation: awLine .7s cubic-bezier(.2, .8, .2, 1) both var(--d, .72s); }

/* the stat strip */
.aw-stats { flex-shrink: 0; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 10px; padding: 16px clamp(22px, 3.6vw, 44px) 4px; }
.aw-stat { border: 1px solid var(--border, #1e2742); border-radius: 10px; background: #0b1122; padding: 12px 14px 11px; text-align: left; animation: awRise .5s cubic-bezier(.2, .8, .2, 1) both var(--d, .8s); position: relative; overflow: hidden; }
.aw-stat::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--c, var(--accent, #a394f5)); opacity: .55; }
.aw-stat > b { display: block; font-family: var(--tech, 'Archivo', sans-serif); font-weight: 800; font-size: 22px; line-height: 1; color: var(--c, var(--text, #d6def0)); letter-spacing: -.5px; font-variant-numeric: tabular-nums; }
.aw-stat > span { display: block; font-family: var(--mono, 'JetBrains Mono', monospace); font-size: 8.5px; letter-spacing: 1px; color: var(--text-3, #566079); margin-top: 6px; text-transform: uppercase; }

/* the tab rail */
.aw-tabs { flex-shrink: 0; display: flex; align-items: center; gap: 4px; padding: 14px clamp(22px, 3.6vw, 44px) 0; border-bottom: 1px solid var(--border, #1e2742); margin: 0; animation: awDrop .45s cubic-bezier(.2, .8, .2, 1) both var(--d, 1s); }
.aw-tab { position: relative; display: inline-flex; align-items: center; gap: 7px; padding: 10px 14px 12px; border: 0; background: transparent; color: var(--text-2, #8792ad);
  font-family: var(--tech, 'Archivo', sans-serif); font-size: 12.5px; font-weight: 700; letter-spacing: .4px; cursor: pointer; border-radius: 8px 8px 0 0; }
.aw-tab:hover { color: var(--text, #d6def0); background: rgba(255, 255, 255, .03); }
.aw-tab::after { content: ''; position: absolute; left: 10px; right: 10px; bottom: -1px; height: 2px; border-radius: 2px; background: var(--accent, #a394f5); transform: scaleX(0); transition: transform .25s cubic-bezier(.2, .8, .2, 1); }
.aw-tab[data-on="1"] { color: #f2f5ff; }
.aw-tab[data-on="1"]::after { transform: scaleX(1); }
.aw-tab .aw-badge { font-family: var(--mono, 'JetBrains Mono', monospace); font-size: 9px; font-weight: 400; padding: 1px 7px; border-radius: 100px; background: var(--cyan-dim, #201a40); color: var(--accent, #a394f5); }
.aw-tab-ai { margin-left: 6px; padding-left: 12px; padding-right: 14px; border: 1px solid rgba(163, 148, 245, .35); border-bottom: 0; background: linear-gradient(180deg, rgba(163, 148, 245, .10), rgba(163, 148, 245, 0)); color: var(--accent, #a394f5); }
.aw-tab-ai:hover, .aw-tab-ai[data-on="1"] { color: #eaf0ff; background: linear-gradient(180deg, rgba(163, 148, 245, .22), rgba(163, 148, 245, .04)); }
@keyframes awAiBreathe { 0%, 100% { box-shadow: 0 0 0 0 rgba(163,148,245,0); } 50% { box-shadow: 0 -6px 18px -8px rgba(163,148,245,.55); } }
.aw-tab-ai { animation: awAiBreathe 3.4s ease-in-out infinite; }
.aw-tab-ai .aw-ai-word { font-family: var(--mono, 'JetBrains Mono', monospace); font-size: 10px; letter-spacing: 1.6px; }

/* the body */
.aw-body { flex: 1; min-height: 0; overflow-y: auto; padding: 20px clamp(22px, 3.6vw, 44px) 48px; }
.aw-body--legacy { padding-left: 0; padding-right: 0; padding-top: 10px; }
.aw-reach { animation: awRise .5s cubic-bezier(.2, .8, .2, 1) both var(--d, .08s); }
.aw-reach .mmax.mmax-top { margin: 0; }
.aw-grid { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 22px; align-items: start; }
.aw-main, .aw-rail { min-width: 0; display: grid; gap: 14px; align-content: start; }
.aw-main > *, .aw-rail > * { animation: awRise .5s cubic-bezier(.2, .8, .2, 1) both var(--d, 1.1s); }
.aw-main .mmax.mmax-top, .aw-main .mmax { margin: 0; }
.aw-card { border: 1px solid var(--border, #1e2742); border-radius: 10px; background: #0b1122; padding: 15px 18px; }
.aw-card.aw-bio { border-left: 2px solid var(--aw-c, var(--accent, #a394f5)); }
.aw-k { font-family: var(--mono, 'JetBrains Mono', monospace); font-size: 9px; letter-spacing: 1.5px; color: var(--text-3, #566079); margin-bottom: 8px; text-transform: uppercase; }
.aw-p { font-family: var(--sans, 'Inter', sans-serif); font-size: 14.5px; color: var(--text, #d6def0); line-height: 1.7; text-wrap: pretty; }
.aw-p.aw-dim { font-size: 13px; color: var(--text-2, #8792ad); line-height: 1.6; }
.aw-facts { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 14px; }
.aw-fact > span { display: block; font-family: var(--mono, 'JetBrains Mono', monospace); font-size: 8.5px; letter-spacing: 1px; color: var(--text-3, #566079); margin-bottom: 3px; text-transform: uppercase; }
.aw-fact > b { display: block; font-family: var(--tech, 'Archivo', sans-serif); font-weight: 700; font-size: 13px; color: var(--text, #d6def0); }
.aw-links { display: flex; flex-wrap: wrap; gap: 7px; }
.aw-link { padding: 8px 12px; border-radius: 4px; border: 1px solid; font-family: var(--tech, 'Archivo', sans-serif); font-size: 9.5px; font-weight: 700; letter-spacing: .6px; text-decoration: none; transition: transform .15s, filter .15s; }
.aw-link:hover { transform: translateY(-1px); filter: brightness(1.15); }
.aw-source { font-family: var(--mono, 'JetBrains Mono', monospace); font-size: 9px; color: var(--text-3, #566079); line-height: 1.7; }
.aw-contact { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 18px; align-items: start; }
.aw-contact > * { animation: awRise .5s cubic-bezier(.2, .8, .2, 1) both var(--d, .2s); }
.aw-booking { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border: 1px solid var(--accent, #a394f5); border-radius: 8px; background: var(--cyan-dim, #201a40); text-decoration: none; }
.aw-booking i { width: 30px; height: 30px; flex-shrink: 0; border-radius: 6px; background: var(--accent, #a394f5); color: #100c22; display: flex; align-items: center; justify-content: center; font-family: var(--tech, 'Archivo', sans-serif); font-size: 13px; font-weight: 700; font-style: normal; }
.aw-booking > span { display: block; min-width: 0; }
.aw-booking small { display: block; font-family: var(--mono, 'JetBrains Mono', monospace); font-size: 8.5px; letter-spacing: 1px; color: var(--text-3, #566079); }
.aw-booking strong { display: block; font-family: var(--tech, 'Archivo', sans-serif); font-size: 13.5px; font-weight: 600; color: var(--text, #d6def0); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.aw-empty { text-align: center; padding: 60px 12px; }
.aw-empty > b { display: block; font-family: var(--tech, 'Archivo', sans-serif); font-size: 16px; font-weight: 700; color: var(--text-2, #8792ad); margin-bottom: 8px; }
.aw-empty > span { font-family: var(--mono, 'JetBrains Mono', monospace); font-size: 10px; color: var(--text-3, #566079); line-height: 1.7; }
/* the Shows tab: pills, then cards in a responsive grid; a card lifts on hover */
.aw-pills { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 14px; animation: awRise .4s ease both var(--d, .1s); }
.aw-pill { padding: 7px 14px; border-radius: 100px; border: 1px solid; font-family: var(--tech, 'Archivo', sans-serif); font-size: 11px; font-weight: 700; letter-spacing: .5px; cursor: pointer; }
.aw-shows { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 10px; margin-bottom: 20px; }
.aw-show { border: 1px solid var(--border, #1e2742); border-radius: 10px; background: #0b1122; padding: 13px 14px; animation: awRise .4s ease both; transition: transform .18s, border-color .18s; }
.aw-show:hover { transform: translateY(-2px); border-color: var(--border-lit, #2e3c5e); }
.aw-show .d { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 8px; }
.aw-show .d b { font-family: var(--tech, 'Archivo', sans-serif); font-weight: 700; font-size: 15px; }
.aw-show .d i { font-style: normal; font-family: var(--mono, 'JetBrains Mono', monospace); font-size: 9px; letter-spacing: .5px; }
.aw-show .v { font-family: var(--tech, 'Archivo', sans-serif); font-weight: 600; font-size: 13.5px; color: var(--text, #d6def0); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.aw-show .c { font-family: var(--mono, 'JetBrains Mono', monospace); font-size: 9.5px; color: var(--text-2, #8792ad); margin-top: 2px; }
.aw-show .t { display: inline-block; margin-top: 8px; margin-right: 5px; font-family: var(--mono, 'JetBrains Mono', monospace); font-size: 8.5px; letter-spacing: .5px; padding: 2px 6px; border-radius: 2px; }
.aw-show.past .v { color: var(--text-2, #8792ad); }
.aw-foot { font-family: var(--mono, 'JetBrains Mono', monospace); font-size: 9px; color: var(--text-3, #566079); margin-top: 10px; }
@media (max-width: 960px) { .aw-grid { grid-template-columns: 1fr; } .aw-stats { grid-template-columns: repeat(3, minmax(0, 1fr)); } .aw-contact { grid-template-columns: 1fr; } }
@media (max-width: 760px) { .aw-back { padding: 0; } .aw { max-height: none; border-radius: 0; } .aw-head { grid-template-columns: auto minmax(0, 1fr); } .aw-actions { grid-column: 1 / -1; flex-direction: row; flex-wrap: wrap; padding-right: 0; } .aw-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } .aw-tabs { overflow-x: auto; } .aw-tab-ai { margin-left: 0; } }

/* ---- 15. list view on the search screens (2026-10-08): one row per result beside the card grid.
   The row grid differs per screen (.ven / .act / .evt); the cells are shared. ---- */
.cv-list{display:flex;flex-direction:column;border:1px solid var(--border-lit);border-radius:8px;overflow:hidden;background:var(--surface);min-width:0;max-width:100%;}
.cv-list-head,.cv-row{display:grid;align-items:center;gap:12px;padding:0 14px;}
.cv-list-head{height:30px;background:#0b1122;border-bottom:1px solid var(--border);font-family:var(--mono);font-size:7.5px;letter-spacing:1.2px;color:var(--text-3);text-transform:uppercase;}
.cv-list-head > span:last-child,.cv-row > .num{text-align:right;}
.cv-row{min-height:52px;padding-top:8px;padding-bottom:8px;border-bottom:1px solid var(--border);border-left:3px solid var(--rc,transparent);cursor:pointer;transition:background .12s;animation:fadeIn .3s ease both;}
.cv-row:last-child{border-bottom:none;} .cv-row:hover{background:var(--surface2);}
/* Child selectors throughout: every {{ value }} renders in its own span, which a bare descendant rule would restyle. */
.cv-row .nm{min-width:0;} .cv-row .nm > b{display:block;font-family:var(--tech);font-weight:700;font-size:13.5px;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.cv-row .nm > span{display:block;font-family:var(--mono);font-size:9px;color:var(--text-3);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.cv-row .nm > b span,.cv-row .nm > span span{display:inline;font:inherit;color:inherit;margin:0;}
.cv-row .mono{font-family:var(--mono);font-size:10px;color:var(--text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;}
.cv-row .num{font-family:var(--tech);font-weight:800;font-size:13px;color:var(--text);white-space:nowrap;font-variant-numeric:tabular-nums;}
.cv-row .num > small{display:block;font-family:var(--mono);font-size:6.5px;letter-spacing:.6px;color:var(--text-3);font-weight:400;}
.cv-row .tags{display:flex;gap:5px;flex-wrap:wrap;min-width:0;}
.cv-row .tag{display:inline-block;font-family:var(--mono);font-size:8.5px;letter-spacing:.5px;padding:2px 7px;border-radius:3px;font-weight:700;white-space:nowrap;}
.cv-row .av{width:34px;height:34px;border-radius:7px;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-family:var(--tech);font-size:12px;font-weight:800;color:#0a0e1a;overflow:hidden;position:relative;}
.cv-row .av img{width:100%;height:100%;object-fit:cover;}
.cv-row .date{display:flex;flex-direction:column;align-items:center;line-height:1;} .cv-row .date i{font-family:var(--mono);font-style:normal;font-size:8px;letter-spacing:1.5px;font-weight:700;} .cv-row .date b{font-family:var(--tech);font-weight:800;font-size:20px;color:var(--text);margin-top:2px;}
.cv-row .cv-fav.lbl{position:static;width:auto;min-width:78px;height:30px;padding:0 10px;border-radius:6px;border:1px solid var(--border-lit);background:rgba(10,14,26,.6);color:var(--text-2);font-family:var(--mono);font-size:9px;letter-spacing:.8px;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;gap:5px;justify-self:end;white-space:nowrap;}
.cv-row .cv-fav.lbl[data-on="1"]{border-color:rgba(231,138,118,.5);}
/* Column heads are sort controls. */
.cv-list-head{padding-top:0;padding-bottom:0;}
.cv-th{all:unset;display:flex;align-items:center;gap:4px;height:30px;cursor:pointer;font-family:var(--mono);font-size:7.5px;letter-spacing:1.2px;color:var(--text-3);text-transform:uppercase;white-space:nowrap;min-width:0;overflow:hidden;}
.cv-th:hover{color:var(--text-2);} .cv-th.on{color:var(--accent,#a394f5);} .cv-th.n{justify-content:flex-end;}
.cv-th i{font-style:normal;font-size:7px;}
.cv-list .ven{grid-template-columns:34px minmax(0,2fr) minmax(0,1.3fr) 120px 80px 84px 92px;}
.cv-list .act{grid-template-columns:34px minmax(0,2fr) minmax(0,1.2fr) 120px 70px 84px 52px 92px;}
.cv-list .evt{grid-template-columns:48px minmax(0,2fr) minmax(0,1.6fr) 150px 80px 70px 92px;}
@media (max-width:900px){ .cv-list-head{display:none;} .cv-list .ven,.cv-list .act{grid-template-columns:34px 1fr auto 92px;} .cv-list .evt{grid-template-columns:48px 1fr auto 92px;} .cv-row .sm-hide{display:none;} }

/* ── 14b. The Artist Search act window's rich header (2026-10-10, data-aw-rich): the stat strip grows to seven tiles
   once the audience read lands (monthly listeners, Reach), and the kicker carries the career stage and momentum. ── */
.aw[data-aw-rich="1"] .aw-stats { grid-template-columns: repeat(auto-fit, minmax(118px, 1fr)); }
.aw[data-aw-rich="1"] .aw-stat > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.aw-stat > em.aw-stat-sub { position: absolute; top: 10px; right: 10px; font-style: normal; font-family: var(--mono, 'JetBrains Mono', monospace); font-size: 8px; letter-spacing: .6px; font-weight: 700; }
.aw-kicker .aw-career { display: inline-flex; align-items: center; gap: 6px; padding: 2px 8px; border-radius: 100px; border: 1px solid var(--border-lit, #2e3c5e); color: var(--text, #d6def0); font-weight: 700; letter-spacing: .7px; }
.aw-kicker .aw-career i { font-style: normal; }
.aw-kicker .aw-career small { font-size: inherit; font-weight: 400; color: var(--text-3, #566079); padding-left: 6px; border-left: 1px solid var(--border-lit, #2e3c5e); }
