```ts
export function admitBytes(perKey: number, total: number, span: number, entries: (string | number)[][]): string[] {
  if (!Number.isInteger(perKey) || perKey <= 0) throw new Error("perKey must be a positive integer");
  if (!Number.isInteger(total) || total <= 0) throw new Error("total must be a positive integer");
  if (!Number.isInteger(span) || span <= 0) throw new Error("span must be a positive integer");

  const result: string[] = [];
  const keyVolumes: { [key: string]: number } = {};
  let currentTotalVolume = 0;
  let lastTime = -1;

  for (const entry of entries) {
    if (entry.length !== 3) throw new Error("Each entry must have exactly three elements");
    const [time, key, size] = entry as [number, string, number];

    if (!Number.isInteger(time) || time < 0) throw new Error("Time must be a non-negative integer");
    if (time < lastTime) throw new Error("Times must not run backwards");
    lastTime = time;

    if (typeof key !== "string" || key.length === 0) throw new Error("Key must be a non-empty string");
    if (!Number.isInteger(size) || size <= 0) throw new Error("Size must be a positive integer");

    // Remove expired entries
    const keysToRemove: string[] = [];
    for (const [k, t] of Object.entries(keyVolumes)) {
      if (time - t > span) {
        keysToRemove.push(k);
      }
    }
    for (const k of keysToRemove) {
      currentTotalVolume -= keyVolumes[k];
      delete keyVolumes[k];
    }

    // Check per-key and total limits
    const newKeyVolume = (keyVolumes[key] || 0) + size;
    if (newKeyVolume <= perKey && currentTotalVolume + size <= total) {
      result.push("pass");
      keyVolumes[key] = time;
      currentTotalVolume += size;
    } else {
      result.push("drop");
    }
  }

  return result;
}
```