package main
import (
"io"
"os"
"sort"
"strconv"
)
const MOD int64 = 1000000007
type FastScanner struct {
data []byte
idx int
n int
}
func NewFastScanner() *FastScanner {
data, _ := io.ReadAll(os.Stdin)
return &FastScanner{data: data, n: len(data)}
}
func (fs *FastScanner) NextInt() int {
for fs.idx < fs.n && (fs.data[fs.idx] < '0' || fs.data[fs.idx] > '9') {
fs.idx++
}
val := 0
for fs.idx < fs.n && fs.data[fs.idx] >= '0' && fs.data[fs.idx] <= '9' {
val = val*10 + int(fs.data[fs.idx]-'0')
fs.idx++
}
return val
}
type Entry struct {
t int
g int
c int
}
type Entries []Entry
func (e Entries) Len() int { return len(e) }
func (e Entries) Less(i, j int) bool {
if e[i].t != e[j].t {
return e[i].t < e[j].t
}
return e[i].g < e[j].g
}
func (e Entries) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
func main() {
fs := NewFastScanner()
n := fs.NextInt()
m := fs.NextInt()
entries := make([]Entry, 0, 500000)
for gym := 1; gym <= n; gym++ {
gi := fs.NextInt()
arr := make([]int, gi)
for i := 0; i < gi; i++ {
arr[i] = fs.NextInt()
}
sort.Ints(arr)
cnt := 1
for i := 1; i <= gi; i++ {
if i < gi && arr[i] == arr[i-1] {
cnt++
} else {
entries = append(entries, Entry{t: arr[i-1], g: gym, c: cnt})
cnt = 1
}
}
}
sort.Sort(Entries(entries))
children := make(map[uint64]int, len(entries)*2+1)
nodeCount := make([]int, 1, len(entries)+1)
usedTypes := 0
for i := 0; i < len(entries); {
t := entries[i].t
node := 0
for i < len(entries) && entries[i].t == t {
key := (uint64(node) << 40) | (uint64(entries[i].g) << 20) | uint64(entries[i].c)
next, ok := children[key]
if !ok {
next = len(nodeCount)
children[key] = next
nodeCount = append(nodeCount, 0)
}
node = next
i++
}
nodeCount[node]++
usedTypes++
}
nodeCount[0] = m - usedTypes
ans := int64(1)
for _, c := range nodeCount {
for i := 2; i <= c; i++ {
ans = (ans * int64(i)) % MOD
}
}
os.Stdout.WriteString(strconv.FormatInt(ans, 10))
}