{"version":3,"file":"BqStatCard-CQM-b5g9.cjs","names":[],"sources":["../src/components/stat-card/BqStatCard.ts"],"sourcesContent":["/**\r\n * Stat card component - compact metric surface for dashboards and summaries.\r\n * @element bq-stat-card\r\n * @prop {string}  label   - Metric label\r\n * @prop {string}  value   - Primary metric value\r\n * @prop {string}  change  - Secondary delta or comparison value\r\n * @prop {string}  hint    - Supporting description\r\n * @prop {string}  trend   - up | down | neutral\r\n * @prop {string}  size    - sm | md\r\n * @prop {boolean} loading - Displays a loading skeleton while data is pending\r\n * @slot        - Additional supporting content rendered below the hint\r\n * @slot icon   - Optional icon or badge for the metric\r\n */\r\nimport type { ComponentDefinition } from '@bquery/bquery/component';\r\nimport { component, html } from '@bquery/bquery/component';\r\nimport { escapeHtml } from '@bquery/bquery/security';\r\nimport { t } from '../../i18n/index.js';\r\nimport { uniqueId } from '../../utils/dom.js';\r\nimport { getBaseStyles, srOnlyStyles } from '../../utils/styles.js';\r\n\r\ntype BqStatCardProps = {\r\n  label: string;\r\n  value: string;\r\n  change: string;\r\n  hint: string;\r\n  trend: string;\r\n  size: string;\r\n  loading: boolean;\r\n};\r\ntype BqStatCardState = { uid: string };\r\n\r\nfunction getTrend(trend: string): 'up' | 'down' | 'neutral' {\r\n  if (trend === 'up' || trend === 'down') return trend;\r\n  return 'neutral';\r\n}\r\n\r\nfunction getSize(size: string): 'sm' | 'md' {\r\n  return size === 'sm' ? 'sm' : 'md';\r\n}\r\n\r\nconst definition: ComponentDefinition<BqStatCardProps, BqStatCardState> = {\r\n  props: {\r\n    label: { type: String, default: '' },\r\n    value: { type: String, default: '' },\r\n    change: { type: String, default: '' },\r\n    hint: { type: String, default: '' },\r\n    trend: { type: String, default: 'neutral' },\r\n    size: { type: String, default: 'md' },\r\n    loading: { type: Boolean, default: false },\r\n  },\r\n  state: {\r\n    uid: '',\r\n  },\r\n  styles: `\r\n    ${getBaseStyles()}\r\n    ${srOnlyStyles}\r\n    *, *::before, *::after { box-sizing: border-box; }\r\n    :host { display: block; }\r\n    .card {\r\n      display: grid;\r\n      gap: var(--bq-space-4,1rem);\r\n      min-height: 100%;\r\n      padding: var(--bq-space-6,1.5rem);\r\n      border-radius: var(--bq-radius-xl,0.75rem);\r\n      border: 1px solid var(--bq-border-base,#e2e8f0);\r\n      background: var(--bq-bg-base,#fff);\r\n      box-shadow: var(--bq-shadow-sm);\r\n      color: var(--bq-text-base,#0f172a);\r\n      font-family: var(--bq-font-family-sans);\r\n    }\r\n    .card[data-size=\"sm\"] {\r\n      gap: var(--bq-space-3,0.75rem);\r\n      padding: var(--bq-space-4,1rem);\r\n    }\r\n    .header {\r\n      display: flex;\r\n      align-items: flex-start;\r\n      justify-content: space-between;\r\n      gap: var(--bq-space-3,0.75rem);\r\n    }\r\n    .label {\r\n      margin: 0;\r\n      font-size: var(--bq-font-size-sm,0.875rem);\r\n      font-weight: var(--bq-font-weight-medium,500);\r\n      color: var(--bq-text-muted,#475569);\r\n      line-height: 1.4;\r\n    }\r\n    .icon-slot {\r\n      display: inline-flex;\r\n      align-items: center;\r\n      justify-content: center;\r\n      color: var(--bq-color-primary-600,#2563eb);\r\n      min-width: 0;\r\n      flex-shrink: 0;\r\n    }\r\n    .icon-slot slot[name=\"icon\"]::slotted(*) {\r\n      max-width: 100%;\r\n    }\r\n    .value-row {\r\n      display: flex;\r\n      align-items: flex-end;\r\n      justify-content: space-between;\r\n      gap: var(--bq-space-3,0.75rem);\r\n      flex-wrap: wrap;\r\n    }\r\n    .value {\r\n      margin: 0;\r\n      font-size: clamp(1.75rem, 4vw, 2.25rem);\r\n      font-weight: var(--bq-font-weight-bold,700);\r\n      line-height: 1.1;\r\n      letter-spacing: -0.02em;\r\n      color: var(--bq-text-base,#0f172a);\r\n    }\r\n    .card[data-size=\"sm\"] .value {\r\n      font-size: clamp(1.375rem, 3.5vw, 1.875rem);\r\n    }\r\n    .change {\r\n      display: inline-flex;\r\n      align-items: center;\r\n      gap: 0.375rem;\r\n      min-height: 2rem;\r\n      padding: 0.25rem 0.625rem;\r\n      border-radius: var(--bq-radius-full,9999px);\r\n      font-size: var(--bq-font-size-sm,0.875rem);\r\n      font-weight: var(--bq-font-weight-semibold,600);\r\n      white-space: nowrap;\r\n      background: var(--bq-bg-subtle,#f8fafc);\r\n      color: var(--bq-text-muted,#475569);\r\n    }\r\n    .change[data-trend=\"up\"] {\r\n      background: rgba(34, 197, 94, 0.14);\r\n      background: color-mix(in srgb, var(--bq-color-success-500,#22c55e) 14%, transparent);\r\n      color: var(--bq-color-success-700,#15803d);\r\n    }\r\n    .change[data-trend=\"down\"] {\r\n      background: rgba(239, 68, 68, 0.14);\r\n      background: color-mix(in srgb, var(--bq-color-danger-500,#ef4444) 14%, transparent);\r\n      color: var(--bq-color-danger-700,#b91c1c);\r\n    }\r\n    .hint {\r\n      margin: 0;\r\n      font-size: var(--bq-font-size-sm,0.875rem);\r\n      line-height: 1.5;\r\n      color: var(--bq-text-muted,#475569);\r\n    }\r\n    .loading-layout {\r\n      display: grid;\r\n      gap: var(--bq-space-3,0.75rem);\r\n    }\r\n    .skeleton {\r\n      position: relative;\r\n      overflow: hidden;\r\n      display: block;\r\n      border-radius: var(--bq-radius-md,0.375rem);\r\n      background: var(--bq-bg-subtle,#e2e8f0);\r\n    }\r\n    .skeleton::after {\r\n      content: '';\r\n      position: absolute;\r\n      inset: 0;\r\n      transform: translateX(-100%);\r\n      background: linear-gradient(90deg, transparent, rgba(255,255,255,0.45), transparent);\r\n      animation: stat-card-shimmer 1.5s infinite;\r\n    }\r\n    .skeleton-label { width: 40%; height: 0.875rem; }\r\n    .skeleton-value { width: 55%; height: 2.25rem; }\r\n    .skeleton-hint  { width: 75%; height: 0.875rem; }\r\n    @keyframes stat-card-shimmer {\r\n      100% { transform: translateX(100%); }\r\n    }\r\n    @media (prefers-reduced-motion: reduce) {\r\n      .skeleton::after { animation: none; }\r\n    }\r\n  `,\r\n  connected() {\r\n    type BqStatCardElement = HTMLElement & {\r\n      setState(k: 'uid', v: string): void;\r\n      getState<T>(k: string): T;\r\n    };\r\n    const self = this as unknown as BqStatCardElement;\r\n    if (!self.getState<string>('uid'))\r\n      self.setState('uid', uniqueId('bq-stat-card'));\r\n  },\r\n  render({ props, state }) {\r\n    const label = props.label.trim();\r\n    const value = props.value.trim();\r\n    const change = props.change.trim();\r\n    const hint = props.hint.trim();\r\n    const trend = getTrend(props.trend);\r\n    const size = getSize(props.size);\r\n    const uid = state.uid || 'bq-stat-card';\r\n    const labelId = `${uid}-label`;\r\n    const hintId = `${uid}-hint`;\r\n    const statusId = `${uid}-status`;\r\n    const describedByIds = props.loading ? statusId : hint ? hintId : '';\r\n    const describedBy = describedByIds\r\n      ? ` aria-describedby=\"${escapeHtml(describedByIds)}\"`\r\n      : '';\r\n    const labelledBy = label ? ` aria-labelledby=\"${escapeHtml(labelId)}\"` : '';\r\n    const busy = props.loading ? ' aria-busy=\"true\"' : '';\r\n\r\n    const body = props.loading\r\n      ? `\r\n        <div class=\"loading-layout\" part=\"loading\">\r\n          <span class=\"skeleton skeleton-label\" aria-hidden=\"true\"></span>\r\n          <span class=\"skeleton skeleton-value\" aria-hidden=\"true\"></span>\r\n          <span class=\"skeleton skeleton-hint\" aria-hidden=\"true\"></span>\r\n          <span class=\"sr-only\" id=\"${escapeHtml(statusId)}\" role=\"status\" aria-live=\"polite\">${escapeHtml(t('common.loading'))}</span>\r\n        </div>\r\n      `\r\n      : `\r\n        <div class=\"value-row\">\r\n          ${value ? `<p class=\"value\" part=\"value\">${escapeHtml(value)}</p>` : ''}\r\n          ${change ? `<span class=\"change\" part=\"change\" data-trend=\"${trend}\">${escapeHtml(change)}</span>` : ''}\r\n        </div>\r\n        ${hint ? `<p class=\"hint\" id=\"${escapeHtml(hintId)}\" part=\"hint\">${escapeHtml(hint)}</p>` : ''}\r\n        <slot></slot>\r\n      `;\r\n\r\n    return html`\r\n      <article\r\n        part=\"card\"\r\n        class=\"card\"\r\n        data-size=\"${size}\"\r\n        ${labelledBy}${describedBy}${busy}\r\n      >\r\n        <div class=\"header\" part=\"header\">\r\n          ${label\r\n            ? `<p class=\"label\" id=\"${escapeHtml(labelId)}\" part=\"label\">${escapeHtml(label)}</p>`\r\n            : '<span></span>'}\r\n          <div class=\"icon-slot\"><slot name=\"icon\"></slot></div>\r\n        </div>\r\n        ${body}\r\n      </article>\r\n    `;\r\n  },\r\n};\r\n\r\ncomponent<BqStatCardProps, BqStatCardState>('bq-stat-card', definition);\r\n"],"mappings":";;;;;;;AA+BA,SAAS,SAAS,OAA0C;AAC1D,KAAI,UAAU,QAAQ,UAAU,OAAQ,QAAO;AAC/C,QAAO;;AAGT,SAAS,QAAQ,MAA2B;AAC1C,QAAO,SAAS,OAAO,OAAO;;AAyMhC,2BAAA,EAA4C,gBAAgB;CArM1D,OAAO;EACL,OAAO;GAAE,MAAM;GAAQ,SAAS;GAAI;EACpC,OAAO;GAAE,MAAM;GAAQ,SAAS;GAAI;EACpC,QAAQ;GAAE,MAAM;GAAQ,SAAS;GAAI;EACrC,MAAM;GAAE,MAAM;GAAQ,SAAS;GAAI;EACnC,OAAO;GAAE,MAAM;GAAQ,SAAS;GAAW;EAC3C,MAAM;GAAE,MAAM;GAAQ,SAAS;GAAM;EACrC,SAAS;GAAE,MAAM;GAAS,SAAS;GAAO;EAC3C;CACD,OAAO,EACL,KAAK,IACN;CACD,QAAQ;MACJ,eAAA,eAAe,CAAC;MAChB,eAAA,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuHjB,YAAY;EAKV,MAAM,OAAO;AACb,MAAI,CAAC,KAAK,SAAiB,MAAM,CAC/B,MAAK,SAAS,OAAO,YAAA,SAAS,eAAe,CAAC;;CAElD,OAAO,EAAE,OAAO,SAAS;EACvB,MAAM,QAAQ,MAAM,MAAM,MAAM;EAChC,MAAM,QAAQ,MAAM,MAAM,MAAM;EAChC,MAAM,SAAS,MAAM,OAAO,MAAM;EAClC,MAAM,OAAO,MAAM,KAAK,MAAM;EAC9B,MAAM,QAAQ,SAAS,MAAM,MAAM;EACnC,MAAM,OAAO,QAAQ,MAAM,KAAK;EAChC,MAAM,MAAM,MAAM,OAAO;EACzB,MAAM,UAAU,GAAG,IAAI;EACvB,MAAM,SAAS,GAAG,IAAI;EACtB,MAAM,WAAW,GAAG,IAAI;EACxB,MAAM,iBAAiB,MAAM,UAAU,WAAW,OAAO,SAAS;EAClE,MAAM,cAAc,iBAChB,sBAAsB,2BAAA,GAAW,eAAe,CAAC,KACjD;EACJ,MAAM,aAAa,QAAQ,qBAAqB,2BAAA,GAAW,QAAQ,CAAC,KAAK;EACzE,MAAM,OAAO,MAAM,UAAU,wBAAsB;EAEnD,MAAM,OAAO,MAAM,UACf;;;;;sCAK8B,2BAAA,GAAW,SAAS,CAAC,qCAAqC,2BAAA,GAAW,aAAA,EAAE,iBAAiB,CAAC,CAAC;;UAGxH;;YAEI,QAAQ,iCAAiC,2BAAA,GAAW,MAAM,CAAC,QAAQ,GAAG;YACtE,SAAS,kDAAkD,MAAM,IAAI,2BAAA,GAAW,OAAO,CAAC,WAAW,GAAG;;UAExG,OAAO,uBAAuB,2BAAA,GAAW,OAAO,CAAC,gBAAgB,2BAAA,GAAW,KAAK,CAAC,QAAQ,GAAG;;;AAInG,SAAO,2BAAA,CAAI;;;;qBAIM,KAAK;UAChB,aAAa,cAAc,KAAK;;;YAG9B,QACE,wBAAwB,2BAAA,GAAW,QAAQ,CAAC,iBAAiB,2BAAA,GAAW,MAAM,CAAC,QAC/E,gBAAgB;;;UAGpB,KAAK;;;;CAM6C,CAAW"}