#include <bits/stdc++.h>
struct Node {
  std::map<long, long> g;
  std::vector<long> type;
  long count;
  Node() : count(0) {}
};
int main() {
  std::ios_base::sync_with_stdio(false);
  long n, m;
  std::cin >> n >> m;
  std::vector<std::vector<long> > type(m + 1);
  for (long i = 0; i != n; ++i) {
    long g;
    std::cin >> g;
    for (long j = 0; j != g; ++j) {
      long t;
      std::cin >> t;
      type[t].push_back(i);
    }
  }
  std::vector<Node> trie(1);
  for (long i = 1; i != m + 1; ++i) {
    if (type[i].empty()) {
      ++trie[0].count;
      trie[0].type.push_back(i);
      continue;
    }
    long prev = 0;
    for (long j = 0; j != (long)type[i].size(); ++j) {
      std::map<long, long>::iterator it = trie[prev].g.find(type[i][j]);
      if (it != trie[prev].g.end()) {
        prev = it->second;
        continue;
      }
      trie[prev].g[type[i][j]] = trie.size();
      prev = (long)trie.size();
      trie.push_back(Node());
    }
    ++trie[prev].count;
    trie[prev].type.push_back(i);
  }
  const unsigned long long M = 1000000007ull;
  unsigned long long ans = 1;
  for (std::size_t i = 0; i != trie.size(); ++i) {
    if (!trie[i].count) continue;
    for (long j = 2; j <= trie[i].count; ++j) ans = (ans * j) % M;
  }
  std::cout << ans << "\n";
  return 0;
}
