/* ============================================================
 * Platform icon-button — single source of truth for shape.
 *
 * Loaded by every app in the monorepo (sift, shed, app/next).
 * Shape (size, radius, shrink behavior, glyph size) is declared ONCE here
 * and never redeclared by consumers. Themes tune colors via CSS vars only.
 *
 * Consumers may use `.sift-icon-btn` directly, or any of the legacy class
 * aliases below (kept so existing HTML keeps working without churn):
 *   .ui-topbar__btn   (shed, app/next topbar)
 *   .view-menu-btn    (sift main-app toolbar, density menu, filter bar)
 *   .notif-btn        (sift notification bell)
 *   .date-btn         (sift date picker)
 *   .acct-btn         (sift account dropdown, legacy)
 *   .flt-btn          (sift filter dropdown)
 *   .toolbar-icon-btn (sift filter history, etc.)
 *
 * All of these share ONE rule block — no drift is possible.
 * If you need a different shape for some reason, it's not an icon-button;
 * use a different class with a clearly different name.
 *
 * TRK-394 Phase 3 layer assignment:
 *   @layer platform → shape, glyph sizing, inter-icon spacing, layout slots
 *   @layer module   → state rules (hover/active/selected/disabled/has-notifs)
 *   @layer theme    → dark-mode :root token defaults
 * Layer order declared in 00-reset.css. Module > theme > platform; state
 * rules win over any theme catch-all without needing !important or
 * specificity gymnastics.
 * ============================================================ */

@layer platform {
  .sift-icon-btn,
  .ui-topbar__btn,
  .view-menu-btn,
  .notif-btn,
  .date-btn,
  .acct-btn,
  .flt-btn,
  .toolbar-icon-btn,
  .ra-btn,
  .bulk-dismiss,
  .family-reaction-picker__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    position: relative;
    width: var(--icon-btn-size, 24px);
    height: var(--icon-btn-size, 24px);
    flex-shrink: 0;
    padding: 0;
    /* Spec §components.icon_btn.spacing — default horizontal breathing
       room is 1/4 of the icon-card SIZE on each side, so two adjacent
       icons sit one HALF of the icon-card-size apart (1/4 + 1/4).
       Rhythm scales to the hit-target the user clicks, not glyph
       weight, and matches the perceived "card" of each toolbar button.
       Icon islands retired (2026-04-21), no opt-out contexts. */
    margin-inline: var(--icon-btn-inline-gap, calc(var(--icon-btn-size, 24px) / 4));
    margin-block: 0;
    border: 1px solid transparent;
    background: transparent;
    border-radius: 50%;
    color: var(--icon-btn-fg, #DCDCDC);
    cursor: pointer;
    font: inherit;
    -webkit-app-region: no-drag;
    transition: background 120ms, border-color 120ms, color 120ms;
  }

  /* Glyph — inherits color from the button so state-changes tint uniformly. */
  .sift-icon-btn > svg, .sift-icon-btn > i,
  .ui-topbar__btn > svg, .ui-topbar__btn > i,
  .view-menu-btn > svg, .view-menu-btn > i,
  .notif-btn > svg, .notif-btn > i,
  .date-btn > svg, .date-btn > i,
  .acct-btn > svg, .acct-btn > i,
  .flt-btn > svg, .flt-btn > i,
  .toolbar-icon-btn > svg, .toolbar-icon-btn > i,
  .ra-btn > svg, .ra-btn > i,
  .bulk-dismiss > svg, .bulk-dismiss > i,
  .family-reaction-picker__btn > svg, .family-reaction-picker__btn > i {
    width: var(--icon-btn-glyph, 16px);
    height: var(--icon-btn-glyph, 16px);
    stroke-width: 1.8;
    flex-shrink: 0;
    color: currentColor;
  }
}

@layer module {
  /* ------------------------------------------------------------
   * State rules — hover / active / selected / disabled.
   *
   * The platform button set is declared ONCE via an `:is(…)` prefix;
   * signal unions are declared ONCE via an `:is(…)` suffix. Adding a
   * new alias = append to the prefix list (never a new rule block).
   * Adding a new signal form (e.g. [aria-checked="true"]) = append to
   * the suffix list (never a new rule block per button).
   *
   * Specificity invariant: `:is(.a, .b)` takes the highest specificity
   * of its arguments. Both prefix and suffix resolve to 0.1.0, so the
   * combined state selector is 0.2.0 — identical to the prior per-class
   * comma-group enumeration, no cascade drift.
   *
   * Layer invariant: state lives in @layer module which beats @layer
   * theme. Theme catch-alls on the base button can never override these
   * state rules regardless of source order or specificity.
   *
   * Signal contracts per specs/ui-platform.yaml §components.icon_btn:
   *   active_signals   = class (.is-active | .active | .open)
   *                      OR [aria-expanded="true"]
   *                      OR [aria-pressed="true"]
   *   selected_signals = .is-selected OR [aria-selected="true"]
   *   disabled_signals = :disabled OR [disabled] OR .disabled
   *
   * Per TRK-381 every interactive state paints the 1px border ring
   * only; background stays transparent across all themes.
   * ------------------------------------------------------------ */

  /* Hover */
  :is(.sift-icon-btn, .ui-topbar__btn, .view-menu-btn, .notif-btn,
      .date-btn, .acct-btn, .flt-btn, .toolbar-icon-btn, .ra-btn,
      .bulk-dismiss):hover:not(:is([disabled], .disabled)) {
    border-color: var(--icon-btn-border, rgba(0, 0, 0, 0.20));
    color: var(--icon-btn-hover-fg, #3F3F3F);
  }

  /* Pressed / open / expanded — per §components.icon_btn.active_signals. */
  :is(.sift-icon-btn, .ui-topbar__btn, .view-menu-btn, .notif-btn,
      .date-btn, .acct-btn, .flt-btn, .toolbar-icon-btn, .ra-btn,
      .bulk-dismiss):is(
    .is-active, .active, .open,
    [aria-expanded="true"],
    [aria-pressed="true"]
  ) {
    border-color: var(--icon-btn-border, rgba(0, 0, 0, 0.20));
    color: var(--icon-btn-active-fg, #3F3F3F);
  }

  /* Selected — per §components.icon_btn.selected_signals. */
  :is(.sift-icon-btn, .ui-topbar__btn, .view-menu-btn, .notif-btn,
      .date-btn, .acct-btn, .flt-btn, .toolbar-icon-btn, .ra-btn,
      .bulk-dismiss):is(.is-selected, [aria-selected="true"]) {
    border-color: var(--icon-btn-border, rgba(0, 0, 0, 0.20));
    color: var(--icon-btn-active-fg, #3F3F3F);
  }

  /* Disabled — property / attribute / class forms. */
  :is(.sift-icon-btn, .ui-topbar__btn, .view-menu-btn, .notif-btn,
      .date-btn, .acct-btn, .flt-btn, .toolbar-icon-btn, .ra-btn,
      .bulk-dismiss):is(:disabled, [disabled], .disabled),
  .nav-hist-btn[disabled] {
    opacity: 0.35;
    cursor: default;
    pointer-events: none;
  }

  /* Special state: "has-notifs" — amber alert ring on the bell. */
  .notif-btn.has-notifs { border-color: var(--icon-btn-alert, #d97706); }
}

@layer platform {
  /* ============================================================
   * Inter-icon spacing — platform default (TRK-406, retires C5;
   * value updated TRK-410: glyph/3 → size/2; updated again 2026-04-27:
   * size/2 → size/4 per side, so neighbors sit at size/2 instead of
   * one full card-size).
   *
   * Spec §components.icon_btn.spacing: each icon-btn carries
   * `margin-inline: calc(var(--icon-btn-size) / 4)` on itself, so
   * two adjacent icon-btn siblings already sit `--icon-btn-size / 2`
   * apart (half a card-size of breathing room between cards).
   * ANY ancestor container that adds `gap: <N>` on flex/grid
   * compounds with the per-icon margin and doubles spacing.
   *
   * This rule defaults `gap: 0` on every flex/grid container of
   * adjacent icon-btn siblings, automatically — new views inherit
   * the correct spacing without each one having to declare it.
   *
   * `:where()` zeros the specificity (0, 0, 0), so an explicit
   * consumer override (e.g. a vertical overflow panel that wants
   * `gap: 2px` between icon rows) still wins. The default is the
   * safety net for the common case (horizontal icon clusters), not
   * a hard rule.
   * ============================================================ */
  :where(:has(> :is(.sift-icon-btn, .ui-topbar__btn, .view-menu-btn, .notif-btn,
                    .date-btn, .acct-btn, .flt-btn, .toolbar-icon-btn,
                    .ra-btn, .bulk-dismiss)
              + :is(.sift-icon-btn, .ui-topbar__btn, .view-menu-btn, .notif-btn,
                    .date-btn, .acct-btn, .flt-btn, .toolbar-icon-btn,
                    .ra-btn, .bulk-dismiss))) {
    gap: 0;
    column-gap: 0;
    row-gap: 0;
  }

  /* ============================================================
   * Back/forward nav cluster — chrome retired per spec
   * §tokens.lf.icon_islands_retired (2026-04-21). The two chevrons
   * are plain icon_btn siblings; they cast their own LF shadows and
   * carry their own inline spacing per §components.icon_btn.spacing.
   * The classes remain as layout slots (transparent, no chrome, no
   * flex gap) so existing HTML keeps working.
   * ============================================================ */
  .sift-icon-pill,
  .nav-hist-island,
  .ui-topbar__island[data-island-id="nav-hist"] {
    display: inline-flex;
    align-items: center;
    flex-shrink: 0;
    background: transparent;
    box-shadow: none;
    border: 0;
    padding: 0;
    -webkit-app-region: no-drag;
  }

  /* Navigation chevrons (topbar back/forward, pager prev/next) inherit
     the default {icon_size.glyph} from .sift-icon-btn > svg above. The
     narrow-and-tall 10×18 override was retired in TRK-421 so every
     round icon-button reads at the same glyph weight. */
}

@layer theme {
  /* Dark-mode defaults (any app whose <body> or :root matches dark mode). */
  @media (prefers-color-scheme: dark) {
    :root {
      --icon-btn-border: rgba(255, 255, 255, 0.25);
      --icon-pill-bg: #2C2C2E;
      --icon-pill-border: rgba(255, 255, 255, 0.12);
      --icon-pill-shadow-near: rgba(0, 0, 0, 0.30);
      --icon-pill-shadow-far:  rgba(0, 0, 0, 0.25);
    }
  }
}
