'use strict';

var react = require('react');
var react$1 = require('@emotion/react');
var jsxRuntime = require('@emotion/react/jsx-runtime');
var reactDom = require('react-dom');

var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
// src/PdfViewer/PdfViewer.tsx
function withAlpha(color, alpha) {
  const a = Math.max(0, Math.min(1, alpha));
  const c = color.trim();
  const rgbMatch = c.match(
    /^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)(?:[\s,/]+[\d.%]+)?\s*\)$/i
  );
  if (rgbMatch) {
    const [, r, g, b] = rgbMatch;
    return `rgba(${r}, ${g}, ${b}, ${a})`;
  }
  const hexMatch = c.match(/^#([0-9a-f]{3,8})$/i);
  if (hexMatch && hexMatch[1]) {
    let h = hexMatch[1];
    if (h.length === 3) {
      h = h.split("").map((ch) => ch + ch).join("");
    }
    if (h.length === 6 || h.length === 8) {
      const r = parseInt(h.slice(0, 2), 16);
      const g = parseInt(h.slice(2, 4), 16);
      const b = parseInt(h.slice(4, 6), 16);
      return `rgba(${r}, ${g}, ${b}, ${a})`;
    }
  }
  return c;
}
function resolveVariantColor(variant, color) {
  const newVariants = [
    "solid",
    "bordered",
    "light",
    "flat",
    "faded",
    "shadow",
    "ghost"
  ];
  if (variant && newVariants.includes(variant)) {
    return { variant, color: color ?? "default" };
  }
  switch (variant) {
    case "primary":
      return { variant: "solid", color: color ?? "primary" };
    case "secondary":
      return { variant: "solid", color: color ?? "secondary" };
    case "outline":
      return { variant: "bordered", color: color ?? "primary" };
    case "danger":
      return { variant: "solid", color: color ?? "danger" };
    case "ghost":
      return color ? { variant: "ghost", color } : { variant: "light", color: "default" };
    default:
      return { variant: "solid", color: color ?? "default" };
  }
}
var Spinner = ({ size = 14 }) => /* @__PURE__ */ jsxRuntime.jsx(
  "span",
  {
    "aria-hidden": true,
    css: react$1.css`
      width: ${size}px;
      height: ${size}px;
      border: 2px solid currentColor;
      border-right-color: transparent;
      border-radius: 50%;
      display: inline-block;
      flex-shrink: 0;
      animation: timeui-spin 0.7s linear infinite;
      @media (prefers-reduced-motion: reduce) {
        animation: none;
      }
      @keyframes timeui-spin {
        to {
          transform: rotate(360deg);
        }
      }
    `
  }
);
var spinnerSize = {
  xs: 12,
  sm: 14,
  md: 16,
  lg: 18,
  xl: 20
};
var Button = react.forwardRef(function Button2({
  as,
  variant,
  color,
  size = "md",
  radius: radiusProp,
  isLoading = false,
  isDisabled = false,
  isFullWidth = false,
  isIconOnly = false,
  startIcon,
  endIcon,
  children,
  type,
  title: titleProp,
  "aria-label": ariaLabel,
  ...rest
}, ref) {
  const tooltipTitle = titleProp ?? (isIconOnly ? ariaLabel : void 0);
  const theme = react$1.useTheme();
  const Comp = as || "button";
  const isButton = Comp === "button";
  const { variant: v, color: c } = resolveVariantColor(variant, color);
  const scale = theme.colors[c];
  const neutral = theme.colors.default;
  const focusColor = theme.colors.focus;
  const borderThin = theme.borders.width.thin;
  const sizeTokens = theme.components.button[size];
  const sizeRadiusMap = {
    xs: "sm",
    sm: "sm",
    md: "md",
    lg: "lg",
    xl: "lg"
  };
  const radiusKey = radiusProp ?? sizeRadiusMap[size];
  const borderRadius = theme.componentRadius[radiusKey];
  let bg = "transparent";
  let fg = scale.DEFAULT;
  let border = "0 solid transparent";
  let boxShadow = "none";
  let hoverBg = null;
  let hoverFg = null;
  switch (v) {
    case "solid":
      bg = scale.DEFAULT;
      fg = scale.foreground;
      hoverBg = withAlpha(scale.DEFAULT, 0.9);
      break;
    case "bordered":
      bg = "transparent";
      fg = scale[600];
      border = `${borderThin} solid ${scale.DEFAULT}`;
      hoverBg = withAlpha(scale.DEFAULT, 0.12);
      break;
    case "light":
      bg = "transparent";
      fg = scale[600];
      hoverBg = withAlpha(scale.DEFAULT, 0.2);
      break;
    case "flat":
      bg = withAlpha(scale.DEFAULT, 0.2);
      fg = scale[600];
      hoverBg = withAlpha(scale.DEFAULT, 0.3);
      break;
    case "faded":
      bg = neutral[100];
      fg = scale[600];
      border = `${borderThin} solid ${neutral[200]}`;
      break;
    case "shadow":
      bg = scale.DEFAULT;
      fg = scale.foreground;
      boxShadow = `${withAlpha(scale.DEFAULT, 0.4)} 0 10px 15px -3px, ${withAlpha(
        scale.DEFAULT,
        0.4
      )} 0 4px 6px -4px`;
      hoverBg = withAlpha(scale.DEFAULT, 0.9);
      break;
    case "ghost":
      bg = "transparent";
      fg = scale[600];
      border = `${borderThin} solid ${scale.DEFAULT}`;
      hoverBg = scale.DEFAULT;
      hoverFg = scale.foreground;
      break;
  }
  const duration = theme.motion.duration.normal ?? "250ms";
  return /* @__PURE__ */ jsxRuntime.jsxs(
    Comp,
    {
      ref,
      type: isButton ? type ?? "button" : type,
      disabled: isButton ? isDisabled || isLoading : void 0,
      "aria-label": ariaLabel,
      "aria-disabled": isDisabled || isLoading || void 0,
      "aria-busy": isLoading || void 0,
      title: tooltipTitle,
      "data-variant": v,
      "data-color": c,
      "data-size": size,
      "data-loading": isLoading || void 0,
      "data-icon-only": isIconOnly || void 0,
      css: react$1.css`
        position: relative;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: ${isIconOnly ? "0" : sizeTokens.gap};
        box-sizing: border-box;
        height: ${sizeTokens.height};
        min-width: ${isIconOnly ? sizeTokens.height : sizeTokens.minWidth};
        ${isIconOnly ? `width: ${sizeTokens.height};` : ""}
        padding: ${isIconOnly ? "0" : `0 ${sizeTokens.paddingX}`};
        font-family: inherit;
        font-size: ${sizeTokens.fontSize};
        line-height: ${sizeTokens.lineHeight};
        font-weight: 400;
        letter-spacing: normal;
        white-space: nowrap;
        overflow: hidden;
        cursor: pointer;
        user-select: none;
        width: ${isFullWidth ? "100%" : "auto"};
        background-color: ${bg};
        color: ${fg};
        border: ${border};
        border-radius: ${borderRadius};
        box-shadow: ${boxShadow};
        outline: 1.5px solid transparent;
        -webkit-font-smoothing: antialiased;
        transition:
          background-color ${duration},
          color ${duration},
          border-color ${duration},
          transform ${duration},
          opacity ${duration},
          box-shadow ${duration};

        &:hover:not(:disabled):not([aria-disabled='true']) {
          ${hoverBg !== null ? `background-color: ${hoverBg};` : ""}
          ${hoverFg !== null ? `color: ${hoverFg};` : ""}
        }

        &:active:not(:disabled):not([aria-disabled='true']),
        &[data-pressed='true'] {
          transform: scale(0.97);
        }

        &:focus-visible {
          outline: none;
          box-shadow: ${boxShadow === "none" ? "" : `${boxShadow},`} inset 0 0 0 2px ${focusColor};
          z-index: 1;
        }

        &:disabled,
        &[aria-disabled='true'],
        &[data-loading='true'] {
          opacity: 0.5;
          pointer-events: none;
        }

        @media (prefers-reduced-motion: reduce) {
          transition: none;
          &:active:not(:disabled):not([aria-disabled='true']),
          &[data-pressed='true'] {
            transform: none;
          }
        }
      `,
      ...rest,
      children: [
        isLoading ? /* @__PURE__ */ jsxRuntime.jsx(Spinner, { size: spinnerSize[size] }) : startIcon,
        children,
        !isLoading && endIcon
      ]
    }
  );
});
Button.displayName = "Button";

// src/utils/env.ts
var isDev = typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production";

// src/utils/refs.ts
function mergeRefs(...refs) {
  return (node) => {
    for (const ref of refs) {
      if (!ref) continue;
      if (typeof ref === "function") {
        ref(node);
      } else {
        ref.current = node;
      }
    }
  };
}
function useControllableState(opts) {
  const { value, defaultValue, onChange, name } = opts;
  const [internal, setInternal] = react.useState(defaultValue);
  const isControlled = value !== void 0;
  const current = isControlled ? value : internal;
  const onChangeRef = react.useRef(onChange);
  const isControlledRef = react.useRef(isControlled);
  react.useEffect(() => {
    onChangeRef.current = onChange;
  }, [onChange]);
  react.useEffect(() => {
    isControlledRef.current = isControlled;
  }, [isControlled]);
  const warnedBothRef = react.useRef(false);
  react.useEffect(() => {
    if (!isDev) return;
    if (warnedBothRef.current) return;
    if (value !== void 0 && defaultValue !== void 0) {
      warnedBothRef.current = true;
      console.warn(
        `[TimeUI] ${name ?? "useControllableState"}: received both \`value\` and \`defaultValue\`. Components must be either controlled or uncontrolled \u2014 \`defaultValue\` will be ignored.`
      );
    }
  }, []);
  const firstControlledRef = react.useRef(isControlled);
  const warnedFlipRef = react.useRef(false);
  react.useEffect(() => {
    if (!isDev) return;
    if (warnedFlipRef.current) return;
    if (firstControlledRef.current !== isControlled) {
      warnedFlipRef.current = true;
      console.warn(
        `[TimeUI] ${name ?? "useControllableState"}: a component is changing from ${firstControlledRef.current ? "controlled" : "uncontrolled"} to ${isControlled ? "controlled" : "uncontrolled"}. Decide between using a controlled or uncontrolled component for the lifetime of the component.`
      );
    }
  }, [isControlled, name]);
  const setState = react.useCallback((next) => {
    if (isControlledRef.current) {
      onChangeRef.current?.(next);
      return;
    }
    setInternal(next);
    onChangeRef.current?.(next);
  }, []);
  return [current, setState];
}
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
var parseOffsetToken = (raw, fallback) => {
  if (raw === void 0) return fallback;
  if (typeof raw === "number") return raw;
  const n = parseFloat(raw);
  return Number.isFinite(n) ? n : fallback;
};
var splitPlacement = (placement) => {
  const [side, alignSuffix] = placement.split("-");
  return { side, align: alignSuffix ?? "center" };
};
var OPPOSITE_SIDE = {
  top: "bottom",
  bottom: "top",
  left: "right",
  right: "left"
};
var sideHasRoom = (side, anchorRect, popoverSize, offset, viewport, padding) => {
  if (side === "top") return anchorRect.top - offset - padding >= popoverSize.height;
  if (side === "bottom")
    return viewport.height - (anchorRect.top + anchorRect.height) - offset - padding >= popoverSize.height;
  if (side === "left") return anchorRect.left - offset - padding >= popoverSize.width;
  return viewport.width - (anchorRect.left + anchorRect.width) - offset - padding >= popoverSize.width;
};
var computePopoverPosition = (anchorRect, popoverSize, placement, offset, viewport, padding = 8) => {
  let { side, align } = splitPlacement(placement);
  if (viewport) {
    const fits = sideHasRoom(side, anchorRect, popoverSize, offset, viewport, padding);
    const opposite = OPPOSITE_SIDE[side];
    const oppositeFits = sideHasRoom(opposite, anchorRect, popoverSize, offset, viewport, padding);
    if (!fits && oppositeFits) {
      side = opposite;
    }
  }
  let top = 0;
  let left = 0;
  if (side === "top") {
    top = anchorRect.top - popoverSize.height - offset;
  } else if (side === "bottom") {
    top = anchorRect.top + anchorRect.height + offset;
  } else if (side === "left") {
    left = anchorRect.left - popoverSize.width - offset;
  } else {
    left = anchorRect.left + anchorRect.width + offset;
  }
  if (side === "top" || side === "bottom") {
    if (align === "start") {
      left = anchorRect.left;
    } else if (align === "end") {
      left = anchorRect.left + anchorRect.width - popoverSize.width;
    } else {
      left = anchorRect.left + anchorRect.width / 2 - popoverSize.width / 2;
    }
  } else {
    if (align === "start") {
      top = anchorRect.top;
    } else if (align === "end") {
      top = anchorRect.top + anchorRect.height - popoverSize.height;
    } else {
      top = anchorRect.top + anchorRect.height / 2 - popoverSize.height / 2;
    }
  }
  if (viewport) {
    if (side === "top" || side === "bottom") {
      const minLeft = padding;
      const maxLeft = viewport.width - popoverSize.width - padding;
      if (maxLeft >= minLeft) {
        left = Math.min(Math.max(left, minLeft), maxLeft);
      }
    } else {
      const minTop = padding;
      const maxTop = viewport.height - popoverSize.height - padding;
      if (maxTop >= minTop) {
        top = Math.min(Math.max(top, minTop), maxTop);
      }
    }
  }
  return { top, left, side, align };
};
var enterTransformStart = (side, distance) => {
  if (side === "top") return `translateY(${distance})`;
  if (side === "bottom") return `translateY(-${distance})`;
  if (side === "left") return `translateX(${distance})`;
  return `translateX(-${distance})`;
};
var Popover = react.forwardRef(
  function Popover2(props, forwardedRef) {
    const {
      anchor,
      children,
      isOpen,
      defaultOpen = false,
      onOpenChange,
      trigger = "click",
      placement = "bottom",
      offset,
      hasArrow = true,
      closeOnBlur = true,
      closeOnEsc = true,
      header,
      footer,
      openDelay = 0,
      closeDelay = 100,
      className,
      style,
      id,
      "aria-label": ariaLabel
    } = props;
    const theme = react$1.useTheme();
    const popoverTokens = theme.components.popover;
    const autoId = react.useId();
    const safeAutoId = autoId.replace(/:/g, "");
    const baseId = id ?? `timeui-popover-${safeAutoId}`;
    const headerId = header ? `${baseId}-header` : void 0;
    const [open, setOpen] = useControllableState({
      value: isOpen,
      defaultValue: isOpen !== void 0 ? void 0 : defaultOpen,
      onChange: onOpenChange,
      name: "Popover"
    });
    const isManual = trigger === "manual";
    const anchorRef = react.useRef(null);
    const panelRef = react.useRef(null);
    const hoverTimerRef = react.useRef(null);
    const clearHoverTimer = react.useCallback(() => {
      if (hoverTimerRef.current) {
        clearTimeout(hoverTimerRef.current);
        hoverTimerRef.current = null;
      }
    }, []);
    react.useEffect(
      () => () => {
        clearHoverTimer();
      },
      [clearHoverTimer]
    );
    const [position, setPosition] = react.useState(null);
    const [isMounted, setIsMounted] = react.useState(false);
    react.useEffect(() => {
      setIsMounted(true);
    }, []);
    const offsetPx = react.useMemo(
      () => parseOffsetToken(offset, parseOffsetToken(popoverTokens.offset, 8)),
      [offset, popoverTokens.offset]
    );
    const { side: placementSide, align: placementAlign } = react.useMemo(
      () => splitPlacement(placement),
      [placement]
    );
    const updatePosition = react.useCallback(() => {
      const anchorEl = anchorRef.current;
      const panelEl = panelRef.current;
      if (!anchorEl || !panelEl) return;
      const aRect = anchorEl.getBoundingClientRect();
      const pRect = panelEl.getBoundingClientRect();
      const next = computePopoverPosition(
        { top: aRect.top, left: aRect.left, width: aRect.width, height: aRect.height },
        { width: pRect.width, height: pRect.height },
        placement,
        offsetPx,
        { width: window.innerWidth, height: window.innerHeight }
      );
      setPosition((prev) => {
        if (prev && prev.top === next.top && prev.left === next.left && prev.side === next.side && prev.align === next.align) {
          return prev;
        }
        return next;
      });
    }, [placement, offsetPx]);
    useIsomorphicLayoutEffect(() => {
      if (!open || !isMounted) {
        setPosition(null);
        return;
      }
      updatePosition();
      const onScrollResize = () => updatePosition();
      window.addEventListener("scroll", onScrollResize, { passive: true, capture: true });
      window.addEventListener("resize", onScrollResize, { passive: true });
      return () => {
        window.removeEventListener("scroll", onScrollResize, true);
        window.removeEventListener("resize", onScrollResize);
      };
    }, [open, isMounted, updatePosition]);
    react.useEffect(() => {
      if (!open || !closeOnEsc || isManual) return;
      const onKey = (e) => {
        if (e.key === "Escape") {
          e.stopPropagation();
          setOpen(false);
        }
      };
      window.addEventListener("keydown", onKey);
      return () => window.removeEventListener("keydown", onKey);
    }, [open, closeOnEsc, isManual, setOpen]);
    react.useEffect(() => {
      if (!open || !closeOnBlur || isManual) return;
      const onMouseDown = (e) => {
        const target = e.target;
        if (!target) return;
        if (anchorRef.current?.contains(target)) return;
        if (panelRef.current?.contains(target)) return;
        setOpen(false);
      };
      document.addEventListener("mousedown", onMouseDown);
      return () => document.removeEventListener("mousedown", onMouseDown);
    }, [open, closeOnBlur, isManual, setOpen]);
    const handleAnchorClick = react.useCallback(
      (e) => {
        if (isManual || trigger !== "click") return;
        e.preventDefault();
        setOpen(!open);
      },
      [isManual, trigger, open, setOpen]
    );
    const openWithDelay = react.useCallback(
      (delay) => {
        clearHoverTimer();
        if (delay <= 0) {
          setOpen(true);
          return;
        }
        hoverTimerRef.current = setTimeout(() => setOpen(true), delay);
      },
      [clearHoverTimer, setOpen]
    );
    const closeWithDelay = react.useCallback(
      (delay) => {
        clearHoverTimer();
        if (delay <= 0) {
          setOpen(false);
          return;
        }
        hoverTimerRef.current = setTimeout(() => setOpen(false), delay);
      },
      [clearHoverTimer, setOpen]
    );
    const handleAnchorMouseEnter = react.useCallback(() => {
      if (isManual || trigger !== "hover") return;
      openWithDelay(openDelay);
    }, [isManual, trigger, openDelay, openWithDelay]);
    const handleAnchorMouseLeave = react.useCallback(() => {
      if (isManual || trigger !== "hover") return;
      closeWithDelay(closeDelay);
    }, [isManual, trigger, closeDelay, closeWithDelay]);
    const handleAnchorFocus = react.useCallback(() => {
      if (isManual || trigger !== "focus") return;
      setOpen(true);
    }, [isManual, trigger, setOpen]);
    const handleAnchorBlur = react.useCallback(() => {
      if (isManual || trigger !== "focus") return;
      setOpen(false);
    }, [isManual, trigger, setOpen]);
    const handlePanelMouseEnter = react.useCallback(() => {
      if (isManual || trigger !== "hover") return;
      clearHoverTimer();
    }, [isManual, trigger, clearHoverTimer]);
    const handlePanelMouseLeave = react.useCallback(() => {
      if (isManual || trigger !== "hover") return;
      closeWithDelay(closeDelay);
    }, [isManual, trigger, closeDelay, closeWithDelay]);
    const anchorEventProps = {
      onClick: handleAnchorClick,
      onMouseEnter: handleAnchorMouseEnter,
      onMouseLeave: handleAnchorMouseLeave,
      onFocus: handleAnchorFocus,
      onBlur: handleAnchorBlur,
      "aria-expanded": trigger === "click" ? open : void 0,
      "aria-haspopup": trigger === "click" ? "dialog" : void 0,
      "aria-controls": open ? baseId : void 0
    };
    const renderAnchor = () => {
      if (typeof anchor === "function") {
        return anchor({ isOpen: open, ref: anchorRef });
      }
      if (!react.isValidElement(anchor)) return null;
      const element = anchor;
      const existingProps = element.props ?? {};
      const majorReactVersion = Number.parseInt(react.version.split(".")[0] ?? "18", 10);
      const existingRef = majorReactVersion >= 19 ? element.props.ref : element.ref;
      const composed = {
        onClick: (e) => {
          existingProps.onClick?.(e);
          if (!e.defaultPrevented) anchorEventProps.onClick(e);
        },
        onMouseEnter: () => {
          existingProps.onMouseEnter?.();
          anchorEventProps.onMouseEnter();
        },
        onMouseLeave: () => {
          existingProps.onMouseLeave?.();
          anchorEventProps.onMouseLeave();
        },
        onFocus: (e) => {
          existingProps.onFocus?.(e);
          anchorEventProps.onFocus();
        },
        onBlur: (e) => {
          existingProps.onBlur?.(e);
          anchorEventProps.onBlur();
        },
        "aria-expanded": anchorEventProps["aria-expanded"],
        "aria-haspopup": anchorEventProps["aria-haspopup"],
        "aria-controls": anchorEventProps["aria-controls"],
        // React 19 puts ref on props; React 18 warns if props.ref is read.
        ref: mergeRefs(anchorRef, existingRef)
      };
      return react.cloneElement(element, composed);
    };
    const handlePanelKeyDown = react.useCallback(
      (e) => {
        if (e.key === "Escape" && closeOnEsc && !isManual) {
          e.stopPropagation();
          setOpen(false);
        }
      },
      [closeOnEsc, isManual, setOpen]
    );
    const surfaceBg = theme.colors.bg.surface ?? theme.colors.bg.canvas;
    const hairline = theme.colors.border.subtle;
    const textPrimary = theme.colors.text.primary;
    const textSecondary = theme.colors.text.secondary;
    const motionEasing = theme.motion.easing;
    const easing = motionEasing.emphasized ?? motionEasing.standard ?? motionEasing.easeInOut;
    const enterTransform = enterTransformStart(
      position?.side ?? placementSide,
      popoverTokens.enterTranslate
    );
    const panelCss = react$1.css`
      position: fixed;
      z-index: ${theme.zIndex.popover};
      min-width: ${popoverTokens.minWidth};
      max-width: ${popoverTokens.maxWidth};
      background: ${surfaceBg};
      color: ${textPrimary};
      border-radius: ${popoverTokens.radius};
      box-shadow:
        0 8px 24px rgba(0, 0, 0, 0.12),
        0 0 0 1px ${hairline};
      font-family: inherit;
      font-size: ${popoverTokens.bodyFontSize};
      line-height: ${popoverTokens.bodyLineHeight};
      box-sizing: border-box;
      outline: none;
      animation: timeui-popover-in ${popoverTokens.enterDuration} ${easing};
      @keyframes timeui-popover-in {
        from {
          opacity: 0;
          transform: ${enterTransform};
        }
        to {
          opacity: 1;
          transform: translate(0, 0);
        }
      }
      @media (prefers-reduced-motion: reduce) {
        animation: none;
        transition: none;
        transform: none !important;
      }
    `;
    const headerCss = react$1.css`
      padding: ${popoverTokens.headerPaddingY} ${popoverTokens.paddingX};
      font-size: ${popoverTokens.headerFontSize};
      font-weight: ${popoverTokens.headerFontWeight};
      color: ${textPrimary};
      border-bottom: 1px solid ${hairline};
    `;
    const bodyCss = react$1.css`
      padding: ${popoverTokens.paddingY} ${popoverTokens.paddingX};
      color: ${textPrimary};
    `;
    const footerCss = react$1.css`
      padding: ${popoverTokens.footerPaddingY} ${popoverTokens.paddingX};
      border-top: 1px solid ${hairline};
      color: ${textSecondary};
    `;
    const arrowSize = popoverTokens.arrowSize;
    const arrowInset = popoverTokens.arrowInset;
    const arrowSidePos = react.useMemo(() => {
      const side = position?.side ?? placementSide;
      const align = position?.align ?? placementAlign;
      const baseStyle = {
        position: "absolute",
        width: arrowSize,
        height: arrowSize,
        background: surfaceBg,
        transform: "rotate(45deg)",
        boxShadow: `1px 1px 0 0 ${hairline}`,
        pointerEvents: "none"
      };
      const centerOffset = `calc(${arrowSize} / -2)`;
      if (side === "top") {
        baseStyle.bottom = centerOffset;
        baseStyle.boxShadow = `1px 1px 0 0 ${hairline}`;
      } else if (side === "bottom") {
        baseStyle.top = centerOffset;
        baseStyle.boxShadow = `-1px -1px 0 0 ${hairline}`;
      } else if (side === "left") {
        baseStyle.right = centerOffset;
        baseStyle.boxShadow = `1px -1px 0 0 ${hairline}`;
      } else {
        baseStyle.left = centerOffset;
        baseStyle.boxShadow = `-1px 1px 0 0 ${hairline}`;
      }
      if (side === "top" || side === "bottom") {
        if (align === "start") {
          baseStyle.left = arrowInset;
        } else if (align === "end") {
          baseStyle.right = arrowInset;
        } else {
          baseStyle.left = `calc(50% - ${arrowSize} / 2)`;
        }
      } else {
        if (align === "start") {
          baseStyle.top = arrowInset;
        } else if (align === "end") {
          baseStyle.bottom = arrowInset;
        } else {
          baseStyle.top = `calc(50% - ${arrowSize} / 2)`;
        }
      }
      return baseStyle;
    }, [position, placementSide, placementAlign, arrowSize, arrowInset, surfaceBg, hairline]);
    const positionStyle = position ? { top: position.top, left: position.left } : { top: -9999, left: -9999, visibility: "hidden" };
    const mergedStyle = { ...positionStyle, ...style };
    const role = trigger === "hover" ? "tooltip" : "dialog";
    const ariaModal = role === "dialog" ? false : void 0;
    const renderPanel = () => /* @__PURE__ */ jsxRuntime.jsxs(
      "div",
      {
        ref: mergeRefs(panelRef, forwardedRef),
        id: baseId,
        role,
        "aria-modal": ariaModal,
        "aria-label": ariaLabel,
        "aria-labelledby": !ariaLabel && headerId ? headerId : void 0,
        "data-placement": placement,
        "data-side": position?.side ?? placementSide,
        "data-align": position?.align ?? placementAlign,
        tabIndex: -1,
        className,
        style: mergedStyle,
        css: panelCss,
        onKeyDown: handlePanelKeyDown,
        onMouseEnter: handlePanelMouseEnter,
        onMouseLeave: handlePanelMouseLeave,
        children: [
          header ? /* @__PURE__ */ jsxRuntime.jsx("div", { id: headerId, css: headerCss, children: header }) : null,
          /* @__PURE__ */ jsxRuntime.jsx("div", { css: bodyCss, children }),
          footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { css: footerCss, children: footer }) : null,
          hasArrow ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, "data-popover-arrow": "", style: arrowSidePos }) : null
        ]
      }
    );
    return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
      renderAnchor(),
      open && isMounted && typeof document !== "undefined" ? reactDom.createPortal(renderPanel(), document.body) : null
    ] });
  }
);
Popover.displayName = "TimeUI.Popover";
var lastClosedAt = 0;
var parseToken = (raw, fallback) => {
  if (raw === void 0) return fallback;
  if (typeof raw === "number") return raw;
  const n = parseFloat(raw);
  return Number.isFinite(n) ? n : fallback;
};
var splitPlacement2 = (placement) => {
  const [side, alignSuffix] = placement.split("-");
  return { side, align: alignSuffix ?? "center" };
};
var enterTransformStart2 = (side, distance) => {
  if (side === "top") return `translateY(${distance})`;
  if (side === "bottom") return `translateY(-${distance})`;
  if (side === "left") return `translateX(${distance})`;
  return `translateX(-${distance})`;
};
var Tooltip = react.forwardRef(
  function Tooltip2(props, forwardedRef) {
    const {
      content,
      children,
      placement = "top",
      offset,
      hasArrow = true,
      isDisabled = false,
      openDelay,
      closeDelay,
      isOpen,
      defaultOpen = false,
      onOpenChange,
      className,
      style,
      id
    } = props;
    const theme = react$1.useTheme();
    const tooltipTokens = theme.components.tooltip;
    const isDark = theme.mode === "dark";
    const [open, setOpen] = useControllableState({
      value: isOpen,
      defaultValue: isOpen !== void 0 ? void 0 : defaultOpen,
      onChange: onOpenChange,
      name: "Tooltip"
    });
    const isControlled = isOpen !== void 0;
    const autoId = react.useId();
    const safeAutoId = autoId.replace(/:/g, "");
    const baseId = id ?? `timeui-tooltip-${safeAutoId}`;
    const anchorRef = react.useRef(null);
    const panelRef = react.useRef(null);
    const enterTimerRef = react.useRef(null);
    const exitTimerRef = react.useRef(null);
    const clearEnterTimer = react.useCallback(() => {
      if (enterTimerRef.current) {
        clearTimeout(enterTimerRef.current);
        enterTimerRef.current = null;
      }
    }, []);
    const clearExitTimer = react.useCallback(() => {
      if (exitTimerRef.current) {
        clearTimeout(exitTimerRef.current);
        exitTimerRef.current = null;
      }
    }, []);
    react.useEffect(
      () => () => {
        clearEnterTimer();
        clearExitTimer();
      },
      [clearEnterTimer, clearExitTimer]
    );
    const offsetPx = react.useMemo(
      () => parseToken(offset, parseToken(tooltipTokens.offset, 6)),
      [offset, tooltipTokens.offset]
    );
    const openDelayMs = react.useMemo(
      () => parseToken(openDelay, parseToken(tooltipTokens.enterDelay, 120)),
      [openDelay, tooltipTokens.enterDelay]
    );
    const closeDelayMs = react.useMemo(
      () => parseToken(closeDelay, parseToken(tooltipTokens.exitDelay, 80)),
      [closeDelay, tooltipTokens.exitDelay]
    );
    const warmThresholdMs = react.useMemo(
      () => parseToken(void 0, parseToken(tooltipTokens.warmThreshold, 500)),
      [tooltipTokens.warmThreshold]
    );
    const { side: placementSide, align: placementAlign } = react.useMemo(
      () => splitPlacement2(placement),
      [placement]
    );
    const [position, setPosition] = react.useState(null);
    const [isMounted, setIsMounted] = react.useState(false);
    react.useEffect(() => {
      setIsMounted(true);
    }, []);
    const updatePosition = react.useCallback(() => {
      const anchorEl = anchorRef.current;
      const panelEl = panelRef.current;
      if (!anchorEl || !panelEl) return;
      const aRect = anchorEl.getBoundingClientRect();
      const pRect = panelEl.getBoundingClientRect();
      const next = computePopoverPosition(
        { top: aRect.top, left: aRect.left, width: aRect.width, height: aRect.height },
        { width: pRect.width, height: pRect.height },
        placement,
        offsetPx,
        { width: window.innerWidth, height: window.innerHeight }
      );
      setPosition((prev) => {
        if (prev && prev.top === next.top && prev.left === next.left && prev.side === next.side && prev.align === next.align) {
          return prev;
        }
        return next;
      });
    }, [placement, offsetPx]);
    useIsomorphicLayoutEffect(() => {
      if (!open || !isMounted || isDisabled) {
        setPosition(null);
        return;
      }
      updatePosition();
      const onScrollResize = () => updatePosition();
      window.addEventListener("scroll", onScrollResize, { passive: true, capture: true });
      window.addEventListener("resize", onScrollResize, { passive: true });
      return () => {
        window.removeEventListener("scroll", onScrollResize, true);
        window.removeEventListener("resize", onScrollResize);
      };
    }, [open, isMounted, isDisabled, updatePosition]);
    const computeEffectiveEnterDelay = react.useCallback(() => {
      const now = Date.now();
      if (lastClosedAt > 0 && now - lastClosedAt < warmThresholdMs) {
        return 0;
      }
      return openDelayMs;
    }, [openDelayMs, warmThresholdMs]);
    const scheduleOpen = react.useCallback(() => {
      if (isControlled || isDisabled) return;
      clearExitTimer();
      clearEnterTimer();
      const delay = computeEffectiveEnterDelay();
      if (delay <= 0) {
        setOpen(true);
        return;
      }
      enterTimerRef.current = setTimeout(() => {
        enterTimerRef.current = null;
        setOpen(true);
      }, delay);
    }, [
      isControlled,
      isDisabled,
      clearExitTimer,
      clearEnterTimer,
      computeEffectiveEnterDelay,
      setOpen
    ]);
    const scheduleClose = react.useCallback(() => {
      if (isControlled || isDisabled) return;
      clearEnterTimer();
      clearExitTimer();
      const doClose = () => {
        lastClosedAt = Date.now();
        setOpen(false);
      };
      if (closeDelayMs <= 0) {
        doClose();
        return;
      }
      exitTimerRef.current = setTimeout(() => {
        exitTimerRef.current = null;
        doClose();
      }, closeDelayMs);
    }, [isControlled, isDisabled, clearEnterTimer, clearExitTimer, closeDelayMs, setOpen]);
    const renderAnchor = () => {
      if (!react.isValidElement(children)) return null;
      const element = children;
      const existingProps = element.props ?? {};
      const composedDescribedBy = [existingProps["aria-describedby"], baseId].filter(Boolean).join(" ");
      const composed = {
        onMouseEnter: (e) => {
          existingProps.onMouseEnter?.(e);
          scheduleOpen();
        },
        onMouseLeave: (e) => {
          existingProps.onMouseLeave?.(e);
          scheduleClose();
        },
        onFocus: (e) => {
          existingProps.onFocus?.(e);
          scheduleOpen();
        },
        onBlur: (e) => {
          existingProps.onBlur?.(e);
          scheduleClose();
        },
        "aria-describedby": composedDescribedBy,
        // React 19 把 ref 放进 props；React 18 仍挂在 element.ref 上。
        // 优先读 props.ref 以消除 R19 的 deprecation 警告，fallback 保持 R18 兼容。
        ref: mergeRefs(
          anchorRef,
          element.props.ref ?? element.ref
        )
      };
      return react.cloneElement(element, composed);
    };
    const bg = isDark ? tooltipTokens.bgDark : tooltipTokens.bgLight;
    const fg = isDark ? tooltipTokens.fgDark : tooltipTokens.fgLight;
    const motionEasing = theme.motion.easing;
    const easing = motionEasing.standard ?? motionEasing.easeInOut;
    const enterTransform = enterTransformStart2(
      position?.side ?? placementSide,
      tooltipTokens.enterTranslate
    );
    const panelCss = react$1.css`
      position: fixed;
      z-index: ${theme.zIndex.tooltip};
      max-width: ${tooltipTokens.maxWidth};
      padding: ${tooltipTokens.paddingY} ${tooltipTokens.paddingX};
      background: ${bg};
      color: ${fg};
      border-radius: ${tooltipTokens.radius};
      box-shadow: ${tooltipTokens.shadow};
      font-family: inherit;
      font-size: ${tooltipTokens.fontSize};
      line-height: ${tooltipTokens.lineHeight};
      font-weight: ${tooltipTokens.fontWeight};
      box-sizing: border-box;
      /* tooltip 不应该捕获鼠标 —— 鼠标移到 tooltip 上不会使其保持开启，
       移开 anchor 后立刻进入 exit 流程，符合 tooltip 的 UX 预期。 */
      pointer-events: none;
      /* 触摸屏上 tooltip 不应被显示（无 hover）；用 hover 媒体特性兜底。 */
      @media (hover: none) {
        display: none;
      }
      animation: timeui-tooltip-in ${tooltipTokens.enterDuration} ${easing};
      @keyframes timeui-tooltip-in {
        from {
          opacity: 0;
          transform: ${enterTransform};
        }
        to {
          opacity: 1;
          transform: translate(0, 0);
        }
      }
      @media (prefers-reduced-motion: reduce) {
        animation: none;
        transition: none;
        transform: none !important;
      }
    `;
    const arrowSize = tooltipTokens.arrowSize;
    const arrowStyle = react.useMemo(() => {
      const side = position?.side ?? placementSide;
      const align = position?.align ?? placementAlign;
      const baseStyle = {
        position: "absolute",
        width: arrowSize,
        height: arrowSize,
        background: bg,
        transform: "rotate(45deg)",
        pointerEvents: "none"
      };
      const centerOffset = `calc(${arrowSize} / -2)`;
      if (side === "top") {
        baseStyle.bottom = centerOffset;
      } else if (side === "bottom") {
        baseStyle.top = centerOffset;
      } else if (side === "left") {
        baseStyle.right = centerOffset;
      } else {
        baseStyle.left = centerOffset;
      }
      if (side === "top" || side === "bottom") {
        if (align === "start") {
          baseStyle.left = "8px";
        } else if (align === "end") {
          baseStyle.right = "8px";
        } else {
          baseStyle.left = `calc(50% - ${arrowSize} / 2)`;
        }
      } else {
        if (align === "start") {
          baseStyle.top = "8px";
        } else if (align === "end") {
          baseStyle.bottom = "8px";
        } else {
          baseStyle.top = `calc(50% - ${arrowSize} / 2)`;
        }
      }
      return baseStyle;
    }, [position, placementSide, placementAlign, arrowSize, bg]);
    const positionStyle = position ? { top: position.top, left: position.left } : { top: -9999, left: -9999, visibility: "hidden" };
    const mergedStyle = { ...positionStyle, ...style };
    const renderPanel = () => /* @__PURE__ */ jsxRuntime.jsxs(
      "div",
      {
        ref: mergeRefs(panelRef, forwardedRef),
        id: baseId,
        role: "tooltip",
        "data-placement": placement,
        "data-side": position?.side ?? placementSide,
        "data-align": position?.align ?? placementAlign,
        className,
        style: mergedStyle,
        css: panelCss,
        children: [
          content,
          hasArrow ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, "data-tooltip-arrow": "", style: arrowStyle }) : null
        ]
      }
    );
    const shouldRenderPortal = !isDisabled && open && isMounted && typeof document !== "undefined";
    return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
      renderAnchor(),
      shouldRenderPortal ? reactDom.createPortal(renderPanel(), document.body) : null
    ] });
  }
);
Tooltip.displayName = "TimeUI.Tooltip";
var PDF_FALLBACK_LABELS = {
  toolbarLabel: "PDF viewer toolbar",
  prevPage: "Previous page",
  nextPage: "Next page",
  zoomIn: "Zoom in",
  zoomOut: "Zoom out",
  fitWidth: "Fit width",
  fitPage: "Fit page",
  download: "Download",
  print: "Print",
  pageOf: (current, total) => `Page ${current} of ${total}`
};
function Icon({ size = 16, children }) {
  return /* @__PURE__ */ jsxRuntime.jsx(
    "svg",
    {
      width: size,
      height: size,
      viewBox: "0 0 24 24",
      fill: "none",
      stroke: "currentColor",
      strokeWidth: 1.8,
      strokeLinecap: "round",
      strokeLinejoin: "round",
      "aria-hidden": true,
      focusable: false,
      children
    }
  );
}
var ChevronLeftIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsx(Icon, { size, children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "15 18 9 12 15 6" }) });
var ChevronRightIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsx(Icon, { size, children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "9 18 15 12 9 6" }) });
var ZoomInIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "11", cy: "11", r: "7" }),
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" }),
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "11", y1: "8", x2: "11", y2: "14" }),
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "8", y1: "11", x2: "14", y2: "11" })
] });
var ZoomOutIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "11", cy: "11", r: "7" }),
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" }),
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "8", y1: "11", x2: "14", y2: "11" })
] });
var FitWidthIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 12h18" }),
  /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "7 8 3 12 7 16" }),
  /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "17 8 21 12 17 16" })
] });
var DownloadIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
  /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "7 10 12 15 17 10" }),
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "15", x2: "12", y2: "3" })
] });
var PrintIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "6 9 6 2 18 2 18 9" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2" }),
  /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "6", y: "14", width: "12", height: "8" })
] });
function PdfViewerToolbar({
  currentPage,
  numPages,
  zoom,
  minZoom,
  maxZoom,
  onPrev,
  onNext,
  onGoToPage,
  onZoomIn,
  onZoomOut,
  onFitWidth,
  onDownload,
  onPrint,
  config,
  labelOverrides,
  isLoading,
  "aria-label": ariaLabelProp
}) {
  const theme = react$1.useTheme();
  const labels = { ...PDF_FALLBACK_LABELS, ...labelOverrides };
  const resolvedAriaLabel = ariaLabelProp ?? labels.toolbarLabel;
  const showDownload = config.download === true && !!onDownload;
  const showPrint = config.print === true && !!onPrint;
  const showPageInput = config.pageInput !== false;
  const [inputValue, setInputValue] = react.useState(String(currentPage));
  react.useEffect(() => {
    setInputValue(String(currentPage));
  }, [currentPage]);
  const commitPage = react.useCallback(() => {
    const parsed = parseInt(inputValue, 10);
    if (Number.isFinite(parsed) && parsed >= 1 && parsed <= Math.max(1, numPages)) {
      onGoToPage(parsed);
    } else {
      setInputValue(String(currentPage));
    }
  }, [inputValue, numPages, currentPage, onGoToPage]);
  const handleInputChange = react.useCallback((e) => {
    setInputValue(e.target.value);
  }, []);
  const containerCss = react$1.css`
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    padding: 6px 10px;
    border-bottom: ${theme.borders.width.thin} solid ${theme.colors.border.subtle};
    color: ${theme.colors.text.primary};
    background-color: ${theme.colors.bg.muted};
    border-radius: ${theme.componentRadius.md} ${theme.componentRadius.md} 0 0;
  `;
  const separatorCss = react$1.css`
    width: ${theme.borders.width.thin};
    align-self: stretch;
    min-height: 16px;
    margin: 2px 4px;
    background: ${theme.colors.border.subtle};
  `;
  const pageInfoCss = react$1.css`
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: ${theme.typography.fontSize.xs};
    color: ${theme.colors.text.secondary};
    user-select: none;
    white-space: nowrap;
  `;
  const pageInputCss = react$1.css`
    appearance: none;
    -webkit-appearance: none;
    background-color: transparent;
    border: 1px solid ${theme.colors.border.subtle};
    border-radius: ${theme.componentRadius.sm};
    color: ${theme.colors.text.primary};
    font-family: ${theme.typography.fontFamily.sans};
    font-size: ${theme.typography.fontSize.xs};
    height: 24px;
    width: 48px;
    padding: 0 6px;
    text-align: center;
    outline: none;

    &:hover {
      border-color: ${theme.colors.border.default};
    }
    &:focus {
      border-color: ${theme.colors.primary[500]};
      box-shadow: 0 0 0 2px ${theme.colors.primary[100]};
    }

    /* hide spin buttons */
    &::-webkit-outer-spin-button,
    &::-webkit-inner-spin-button {
      -webkit-appearance: none;
      margin: 0;
    }
    -moz-appearance: textfield;
  `;
  const zoomLabelCss = react$1.css`
    min-width: 44px;
    text-align: center;
    font-variant-numeric: tabular-nums;
    font-size: ${theme.typography.fontSize.xs};
    color: ${theme.colors.text.secondary};
    user-select: none;
  `;
  const spacerCss = react$1.css`
    flex: 1;
  `;
  const zoomPercent = Math.round(zoom * 100);
  const navDisabled = isLoading || numPages <= 0;
  const prevDisabled = navDisabled || currentPage <= 1;
  const nextDisabled = navDisabled || currentPage >= numPages;
  const zoomOutDisabled = zoom <= minZoom + 1e-6;
  const zoomInDisabled = zoom >= maxZoom - 1e-6;
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "toolbar", "aria-label": resolvedAriaLabel, css: containerCss, children: [
    /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: labels.prevPage, placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(
      Button,
      {
        type: "button",
        variant: "light",
        color: "default",
        size: "sm",
        isIconOnly: true,
        "aria-label": labels.prevPage,
        isDisabled: prevDisabled,
        onClick: onPrev,
        children: /* @__PURE__ */ jsxRuntime.jsx(ChevronLeftIcon, { size: 15 })
      }
    ) }),
    /* @__PURE__ */ jsxRuntime.jsxs("span", { css: pageInfoCss, children: [
      showPageInput ? /* @__PURE__ */ jsxRuntime.jsx(
        "input",
        {
          type: "number",
          min: 1,
          max: Math.max(1, numPages),
          step: 1,
          value: inputValue,
          disabled: navDisabled,
          onChange: handleInputChange,
          onBlur: commitPage,
          onKeyDown: (e) => {
            if (e.key === "Enter") {
              e.preventDefault();
              commitPage();
            }
          },
          "aria-label": "Current page",
          css: pageInputCss
        }
      ) : /* @__PURE__ */ jsxRuntime.jsx("span", { children: currentPage }),
      /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "/" }),
      /* @__PURE__ */ jsxRuntime.jsx("span", { "data-testid": "pdf-num-pages", children: numPages || 0 })
    ] }),
    /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: labels.nextPage, placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(
      Button,
      {
        type: "button",
        variant: "light",
        color: "default",
        size: "sm",
        isIconOnly: true,
        "aria-label": labels.nextPage,
        isDisabled: nextDisabled,
        onClick: onNext,
        children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRightIcon, { size: 15 })
      }
    ) }),
    /* @__PURE__ */ jsxRuntime.jsx("span", { css: separatorCss, "aria-hidden": true }),
    /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: labels.zoomOut, placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(
      Button,
      {
        type: "button",
        variant: "light",
        color: "default",
        size: "sm",
        isIconOnly: true,
        "aria-label": labels.zoomOut,
        isDisabled: zoomOutDisabled,
        onClick: onZoomOut,
        children: /* @__PURE__ */ jsxRuntime.jsx(ZoomOutIcon, { size: 15 })
      }
    ) }),
    /* @__PURE__ */ jsxRuntime.jsxs("span", { css: zoomLabelCss, "aria-live": "polite", "aria-atomic": "true", children: [
      zoomPercent,
      "%"
    ] }),
    /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: labels.zoomIn, placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(
      Button,
      {
        type: "button",
        variant: "light",
        color: "default",
        size: "sm",
        isIconOnly: true,
        "aria-label": labels.zoomIn,
        isDisabled: zoomInDisabled,
        onClick: onZoomIn,
        children: /* @__PURE__ */ jsxRuntime.jsx(ZoomInIcon, { size: 15 })
      }
    ) }),
    /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: labels.fitWidth, placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(
      Button,
      {
        type: "button",
        variant: "light",
        color: "default",
        size: "sm",
        isIconOnly: true,
        "aria-label": labels.fitWidth,
        onClick: onFitWidth,
        children: /* @__PURE__ */ jsxRuntime.jsx(FitWidthIcon, { size: 15 })
      }
    ) }),
    /* @__PURE__ */ jsxRuntime.jsx("span", { css: spacerCss }),
    showDownload && /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: labels.download, placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(
      Button,
      {
        type: "button",
        variant: "light",
        color: "default",
        size: "sm",
        isIconOnly: true,
        "aria-label": labels.download,
        onClick: onDownload,
        children: /* @__PURE__ */ jsxRuntime.jsx(DownloadIcon, { size: 15 })
      }
    ) }),
    showPrint && /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: labels.print, placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(
      Button,
      {
        type: "button",
        variant: "light",
        color: "default",
        size: "sm",
        isIconOnly: true,
        "aria-label": labels.print,
        onClick: onPrint,
        children: /* @__PURE__ */ jsxRuntime.jsx(PrintIcon, { size: 15 })
      }
    ) })
  ] });
}
function toCssLength(value) {
  if (value === null || value === void 0) return null;
  return typeof value === "number" ? `${value}px` : value;
}
function buildContainerCss(theme, opts) {
  const widthCss = toCssLength(opts.width) ?? "100%";
  const heightCss = toCssLength(opts.height) ?? "600px";
  return react$1.css`
    display: flex;
    flex-direction: column;
    box-sizing: border-box;
    width: ${widthCss};
    height: ${heightCss};
    min-width: 0;
    background-color: ${theme.colors.bg.surface};
    border: ${theme.borders.width.thin} solid ${theme.colors.border.default};
    border-radius: ${theme.componentRadius.md};
    overflow: hidden;
    color: ${theme.colors.text.primary};
    font-family: ${theme.typography.fontFamily.sans};

    @media (prefers-reduced-motion: reduce) {
      *,
      *::before,
      *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
      }
    }
  `;
}
function buildScrollAreaCss(theme) {
  return react$1.css`
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    background-color: ${theme.colors.bg.muted};
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 16px;
    outline: none;

    &:focus-visible {
      box-shadow: inset 0 0 0 2px ${theme.colors.primary[500]};
    }
  `;
}
function buildCanvasCss(theme) {
  return react$1.css`
    display: block;
    background-color: ${theme.colors.bg.canvas};
    box-shadow: ${theme.shadows.sm};
    max-width: none;
  `;
}
function buildStatusOverlayCss(theme) {
  return react$1.css`
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    text-align: center;
    color: ${theme.colors.text.secondary};
    font-size: ${theme.typography.fontSize.sm};
  `;
}
function buildPageAnnouncerCss() {
  return react$1.css`
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  `;
}
async function sourceToBuffer(source) {
  if (typeof source === "string") {
    const res = await fetch(source);
    if (!res.ok) {
      throw new Error(`Failed to fetch PDF (${res.status} ${res.statusText})`);
    }
    return await res.arrayBuffer();
  }
  if (source instanceof URL) {
    const res = await fetch(source.toString());
    if (!res.ok) {
      throw new Error(`Failed to fetch PDF (${res.status} ${res.statusText})`);
    }
    return await res.arrayBuffer();
  }
  if (source instanceof ArrayBuffer) {
    return source.slice(0);
  }
  if (source instanceof Uint8Array) {
    const copy = new Uint8Array(source.byteLength);
    copy.set(source);
    return copy;
  }
  if (typeof Blob !== "undefined" && source instanceof Blob) {
    return await source.arrayBuffer();
  }
  throw new Error("Unsupported PDF source type");
}
function clamp(n, min, max) {
  return Math.max(min, Math.min(max, n));
}
function resolveDefaultZoomMode(defaultZoom) {
  if (defaultZoom === "page-fit") return "fit";
  if (defaultZoom === "page-width") return "width";
  return "custom";
}
function resolveDefaultZoomValue(defaultZoom) {
  if (typeof defaultZoom === "number") return defaultZoom;
  return 1;
}
function resolveDefaultWorkerSrc() {
  try {
    return new URL("pdfjs-dist/build/pdf.worker.mjs", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('pdf-viewer.cjs', document.baseURI).href))).toString();
  } catch {
    return null;
  }
}
var PdfViewer = react.forwardRef(function PdfViewer2(props, ref) {
  const {
    source,
    defaultPage = 1,
    page: pageProp,
    onPageChange,
    zoom: zoomProp,
    onZoomChange,
    defaultZoom = "page-width",
    minZoom = 0.25,
    maxZoom = 4,
    showToolbar = true,
    toolbar,
    onLoad,
    onError,
    loadingFallback,
    errorFallback,
    workerSrc,
    width,
    height,
    className,
    style,
    id,
    "aria-label": ariaLabel = "PDF document",
    ...rest
  } = props;
  const theme = react$1.useTheme();
  const [numPages, setNumPages] = react.useState(0);
  const [internalPage, setInternalPage] = react.useState(Math.max(1, defaultPage));
  const currentPage = pageProp ?? internalPage;
  const [zoomMode, setZoomMode] = react.useState(
    () => resolveDefaultZoomMode(defaultZoom)
  );
  const [internalZoom, setInternalZoom] = react.useState(
    () => resolveDefaultZoomValue(defaultZoom)
  );
  const effectiveZoom = zoomProp ?? internalZoom;
  const [isLoading, setIsLoading] = react.useState(true);
  const [error, setError] = react.useState(null);
  const containerRef = react.useRef(null);
  const scrollAreaRef = react.useRef(null);
  const canvasRef = react.useRef(null);
  const pdfDocRef = react.useRef(null);
  const renderTaskRef = react.useRef(null);
  const pdfjsRef = react.useRef(null);
  const onLoadRef = react.useRef(onLoad);
  const onErrorRef = react.useRef(onError);
  const onPageChangeRef = react.useRef(onPageChange);
  const onZoomChangeRef = react.useRef(onZoomChange);
  react.useEffect(() => {
    onLoadRef.current = onLoad;
  }, [onLoad]);
  react.useEffect(() => {
    onErrorRef.current = onError;
  }, [onError]);
  react.useEffect(() => {
    onPageChangeRef.current = onPageChange;
  }, [onPageChange]);
  react.useEffect(() => {
    onZoomChangeRef.current = onZoomChange;
  }, [onZoomChange]);
  const toolbarConfig = react.useMemo(() => toolbar ?? {}, [toolbar]);
  react.useEffect(() => {
    if (typeof window === "undefined") return;
    if (source === void 0 || source === null || source === "") {
      setError(new Error("PDF source is empty"));
      setIsLoading(false);
      onErrorRef.current?.(new Error("PDF source is empty"));
      return;
    }
    let cancelled = false;
    setIsLoading(true);
    setError(null);
    (async () => {
      try {
        const mod = await import(
          /* @vite-ignore */
          'pdfjs-dist'
        );
        if (cancelled) return;
        pdfjsRef.current = mod;
        const resolvedWorker = workerSrc ?? resolveDefaultWorkerSrc();
        if (resolvedWorker && (workerSrc || !mod.GlobalWorkerOptions.workerSrc)) {
          mod.GlobalWorkerOptions.workerSrc = resolvedWorker;
        }
        const data = await sourceToBuffer(source);
        if (cancelled) return;
        const loadingTask = mod.getDocument({ data });
        const doc = await loadingTask.promise;
        if (cancelled) {
          void doc.destroy();
          return;
        }
        const prev = pdfDocRef.current;
        pdfDocRef.current = doc;
        if (prev) {
          try {
            void prev.destroy();
          } catch {
          }
        }
        setNumPages(doc.numPages);
        setIsLoading(false);
        onLoadRef.current?.({ numPages: doc.numPages });
      } catch (err) {
        if (cancelled) return;
        const e = err instanceof Error ? err : new Error(String(err));
        setError(e);
        setIsLoading(false);
        onErrorRef.current?.(e);
      }
    })();
    return () => {
      cancelled = true;
      const task = renderTaskRef.current;
      if (task) {
        try {
          task.cancel();
        } catch {
        }
        renderTaskRef.current = null;
      }
      const doc = pdfDocRef.current;
      if (doc) {
        try {
          void doc.destroy();
        } catch {
        }
        pdfDocRef.current = null;
      }
    };
  }, [source, workerSrc]);
  react.useEffect(() => {
    if (typeof window === "undefined") return;
    const doc = pdfDocRef.current;
    const canvas = canvasRef.current;
    if (!doc || !canvas) return;
    if (numPages <= 0) return;
    const safePage = clamp(currentPage, 1, numPages);
    let cancelled = false;
    const prevTask = renderTaskRef.current;
    if (prevTask) {
      try {
        prevTask.cancel();
      } catch {
      }
      renderTaskRef.current = null;
    }
    const isStale = () => cancelled || pdfDocRef.current !== doc;
    (async () => {
      try {
        const pageObj = await doc.getPage(safePage);
        if (isStale()) return;
        let scale = effectiveZoom;
        if (zoomMode === "width" && scrollAreaRef.current) {
          const baseViewport = pageObj.getViewport({ scale: 1 });
          const containerW = scrollAreaRef.current.clientWidth - 32;
          if (containerW > 0 && baseViewport.width > 0) {
            scale = clamp(containerW / baseViewport.width, minZoom, maxZoom);
          }
        } else if (zoomMode === "fit" && scrollAreaRef.current) {
          const baseViewport = pageObj.getViewport({ scale: 1 });
          const containerW = scrollAreaRef.current.clientWidth - 32;
          const containerH = scrollAreaRef.current.clientHeight - 32;
          if (containerW > 0 && containerH > 0 && baseViewport.width > 0 && baseViewport.height > 0) {
            scale = clamp(
              Math.min(containerW / baseViewport.width, containerH / baseViewport.height),
              minZoom,
              maxZoom
            );
          }
        }
        const viewport = pageObj.getViewport({ scale });
        canvas.width = Math.max(1, Math.floor(viewport.width));
        canvas.height = Math.max(1, Math.floor(viewport.height));
        canvas.style.width = `${Math.floor(viewport.width)}px`;
        canvas.style.height = `${Math.floor(viewport.height)}px`;
        const ctx = canvas.getContext("2d");
        if (!ctx) return;
        if (isStale()) return;
        const task = pageObj.render({ canvasContext: ctx, viewport });
        renderTaskRef.current = task;
        await task.promise;
        if (isStale()) return;
        renderTaskRef.current = null;
      } catch (err) {
        if (isStale()) return;
        const name = err?.name;
        if (name === "RenderingCancelledException") return;
        const e = err instanceof Error ? err : new Error(String(err));
        setError(e);
        onErrorRef.current?.(e);
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [currentPage, effectiveZoom, zoomMode, numPages, minZoom, maxZoom]);
  react.useEffect(() => {
    if (zoomProp !== void 0) {
      setZoomMode("custom");
    }
  }, [zoomProp]);
  const goToPage = react.useCallback(
    (next) => {
      const safe = clamp(next, 1, Math.max(1, numPages));
      if (pageProp === void 0) {
        setInternalPage(safe);
      }
      onPageChangeRef.current?.(safe);
    },
    [numPages, pageProp]
  );
  const setZoomValue = react.useCallback(
    (next) => {
      const safe = clamp(next, minZoom, maxZoom);
      setZoomMode("custom");
      if (zoomProp === void 0) {
        setInternalZoom(safe);
      }
      onZoomChangeRef.current?.(safe);
    },
    [minZoom, maxZoom, zoomProp]
  );
  const handlePrev = react.useCallback(() => goToPage(currentPage - 1), [goToPage, currentPage]);
  const handleNext = react.useCallback(() => goToPage(currentPage + 1), [goToPage, currentPage]);
  const handleZoomIn = react.useCallback(() => {
    setZoomValue(Math.min(maxZoom, effectiveZoom + 0.1));
  }, [effectiveZoom, maxZoom, setZoomValue]);
  const handleZoomOut = react.useCallback(() => {
    setZoomValue(Math.max(minZoom, effectiveZoom - 0.1));
  }, [effectiveZoom, minZoom, setZoomValue]);
  const handleFitWidth = react.useCallback(() => {
    setZoomMode("width");
  }, []);
  const handleDownload = react.useCallback(() => {
    if (typeof window === "undefined" || typeof source !== "string") return;
    try {
      const a = document.createElement("a");
      a.href = source;
      a.download = "";
      a.target = "_blank";
      a.rel = "noopener noreferrer";
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
    } catch {
    }
  }, [source]);
  const handlePrint = react.useCallback(() => {
    if (typeof window === "undefined") return;
    try {
      window.print();
    } catch {
    }
  }, []);
  const handleKeyDown = react.useCallback(
    (e) => {
      if (e.defaultPrevented) return;
      switch (e.key) {
        case "ArrowLeft":
        case "PageUp":
          e.preventDefault();
          handlePrev();
          break;
        case "ArrowRight":
        case "PageDown":
          e.preventDefault();
          handleNext();
          break;
        case "+":
        case "=":
          e.preventDefault();
          handleZoomIn();
          break;
        case "-":
        case "_":
          e.preventDefault();
          handleZoomOut();
          break;
        case "0":
          e.preventDefault();
          handleFitWidth();
          break;
      }
    },
    [handlePrev, handleNext, handleZoomIn, handleZoomOut, handleFitWidth]
  );
  const containerCss = buildContainerCss(theme, { width, height });
  const scrollAreaCss = buildScrollAreaCss(theme);
  const canvasCss = buildCanvasCss(theme);
  const overlayCss = buildStatusOverlayCss(theme);
  const announcerCss = buildPageAnnouncerCss();
  const showError = error !== null;
  const showLoading = !showError && isLoading;
  const showCanvas = !showError;
  const errorContent = showError ? typeof errorFallback === "function" ? errorFallback(error) : errorFallback ?? /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
    "Failed to load PDF: ",
    error.message
  ] }) : null;
  const loadingContent = showLoading ? loadingFallback ?? /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Loading PDF\u2026" }) : null;
  const setContainerRef = (el) => {
    containerRef.current = el;
    if (typeof ref === "function") {
      ref(el);
    } else if (ref) {
      ref.current = el;
    }
  };
  return /* @__PURE__ */ jsxRuntime.jsxs(
    "div",
    {
      ref: setContainerRef,
      role: "region",
      "aria-label": ariaLabel,
      id,
      className,
      style,
      css: containerCss,
      "data-loading": showLoading || void 0,
      "data-error": showError || void 0,
      ...rest,
      children: [
        showToolbar && /* @__PURE__ */ jsxRuntime.jsx(
          PdfViewerToolbar,
          {
            currentPage,
            numPages,
            zoom: effectiveZoom,
            minZoom,
            maxZoom,
            onPrev: handlePrev,
            onNext: handleNext,
            onGoToPage: goToPage,
            onZoomIn: handleZoomIn,
            onZoomOut: handleZoomOut,
            onFitWidth: handleFitWidth,
            onDownload: typeof source === "string" ? handleDownload : void 0,
            onPrint: handlePrint,
            config: toolbarConfig,
            isLoading
          }
        ),
        showError ? /* @__PURE__ */ jsxRuntime.jsx("div", { role: "alert", css: overlayCss, children: errorContent }) : /* @__PURE__ */ jsxRuntime.jsxs(
          "div",
          {
            ref: scrollAreaRef,
            tabIndex: 0,
            role: "group",
            "aria-label": "PDF page area",
            onKeyDown: handleKeyDown,
            css: scrollAreaCss,
            "data-slot": "pdf-viewer-mount",
            children: [
              showCanvas && /* @__PURE__ */ jsxRuntime.jsx(
                "canvas",
                {
                  ref: canvasRef,
                  css: canvasCss,
                  role: "img",
                  "aria-label": "PDF page content",
                  "data-testid": "pdf-canvas"
                }
              ),
              showLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { css: overlayCss, "data-slot": "pdf-viewer-loading", children: loadingContent })
            ]
          }
        ),
        /* @__PURE__ */ jsxRuntime.jsx("span", { css: announcerCss, "aria-live": "polite", "data-slot": "pdf-viewer-announcer", children: numPages > 0 ? `Page ${currentPage} of ${numPages}` : "" })
      ]
    }
  );
});
PdfViewer.displayName = "PdfViewer";

exports.PdfViewer = PdfViewer;
//# sourceMappingURL=pdf-viewer.cjs.map
//# sourceMappingURL=pdf-viewer.cjs.map