A subarray of array a from index l to the index r is the array [a_l, a_{l+1}, ..., a_{r}]. The number of occurrences of the array b in the array a is the number of subarrays of a such that they are equal to b.

You are given n arrays A_1, A_2, ..., A_n; the elements of these arrays are integers from 1 to k. You have to build an array a consisting of m integers from 1 to k in such a way that, for every given subarray A_i, the number of occurrences of A_i in the array a is not less than the number of occurrences of each non-empty subarray of A_i in a. Note that if A_i doesn't occur in a, and no subarray of A_i occurs in a, this condition is still met for A_i.

Your task is to calculate the number of different arrays a you can build, and print it modulo 998244353.

Input

The first line contains three integers n, m and k (1 ≤ n, m, k ≤ 3 ⋅ 10^5) — the number of the given arrays, the desired length of the array a, and the upper bound on the values in the arrays.

Then n lines follow. The i-th line represents the array A_i. The first integer in the i-th line is c_i (1 ≤ c_i ≤ m) — the number of elements in A_i; then, c_i integers from 1 to k follow — the elements of the array A_i.

Additional constraint on the input: ∑_{i=1}^n c_i ≤ 3 ⋅ 10^5; i. e., the number of elements in the given arrays in total does not exceed 3 ⋅ 10^5.

Output

Print one integer — the number of different arrays a you can build, taken modulo 998244353.

Examples

Input


2 4 3
2 1 2
1 3


Output


5


Input


2 4 3
2 1 2
3 3 2 1


Output


0


Input


1 42 1337
2 13 31


Output


721234447
#include <bits/stdc++.h>
#pragma GCC optimize("O3")
#pragma GCC target("sse4")
using namespace std;
template <class T>
using pq = priority_queue<T>;
template <class T>
using pqg = priority_queue<T, vector<T>, greater<T>>;
template <class T>
bool ckmin(T& a, const T& b) {
  return b < a ? a = b, 1 : 0;
}
template <class T>
bool ckmax(T& a, const T& b) {
  return a < b ? a = b, 1 : 0;
}
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
void __print(int x) { cerr << x; }
void __print(long x) { cerr << x; }
void __print(long long x) { cerr << x; }
void __print(unsigned x) { cerr << x; }
void __print(unsigned long x) { cerr << x; }
void __print(unsigned long long x) { cerr << x; }
void __print(float x) { cerr << x; }
void __print(double x) { cerr << x; }
void __print(long double x) { cerr << x; }
void __print(char x) { cerr << '\'' << x << '\''; }
void __print(const char* x) { cerr << '\"' << x << '\"'; }
void __print(const string& x) { cerr << '\"' << x << '\"'; }
void __print(bool x) { cerr << (x ? "true" : "false"); }
template <typename T, typename V>
void __print(const pair<T, V>& x) {
  cerr << '{';
  __print(x.first);
  cerr << ", ";
  __print(x.second);
  cerr << '}';
}
template <typename T>
void __print(const T& x) {
  int first = 0;
  cerr << '{';
  for (auto& i : x) cerr << (first++ ? ", " : ""), __print(i);
  cerr << "}";
}
void _print() { cerr << "]\n"; }
template <typename T, typename... V>
void _print(T t, V... v) {
  __print(t);
  if (sizeof...(v)) cerr << ", ";
  _print(v...);
}
const int MOD = 998244353;
const char nl = '\n';
const int MX = 100001;
int M;
struct mi {
  long long v;
  explicit operator long long() const { return v; }
  mi() { v = 0; }
  mi(long long _v) {
    v = (-MOD < _v && _v < MOD) ? _v : _v % MOD;
    if (v < 0) v += MOD;
  }
  friend bool operator==(const mi& a, const mi& b) { return a.v == b.v; }
  friend bool operator!=(const mi& a, const mi& b) { return !(a == b); }
  friend bool operator<(const mi& a, const mi& b) { return a.v < b.v; }
  mi& operator+=(const mi& m) {
    if ((v += m.v) >= MOD) v -= MOD;
    return *this;
  }
  mi& operator-=(const mi& m) {
    if ((v -= m.v) < 0) v += MOD;
    return *this;
  }
  mi& operator*=(const mi& m) {
    v = v * m.v % MOD;
    return *this;
  }
  mi& operator/=(const mi& m) { return (*this) *= inv(m); }
  friend mi pow(mi a, long long p) {
    mi ans = 1;
    assert(p >= 0);
    for (; p; p /= 2, a *= a)
      if (p & 1) ans *= a;
    return ans;
  }
  friend mi inv(const mi& a) {
    assert(a.v != 0);
    return pow(a, MOD - 2);
  }
  mi operator-() const { return mi(-v); }
  mi& operator++() { return *this += 1; }
  mi& operator--() { return *this -= 1; }
  mi operator++(int) {
    mi temp;
    temp.v = v++;
    return temp;
  }
  mi operator--(int) {
    mi temp;
    temp.v = v--;
    return temp;
  }
  friend mi operator+(mi a, const mi& b) { return a += b; }
  friend mi operator-(mi a, const mi& b) { return a -= b; }
  friend mi operator*(mi a, const mi& b) { return a *= b; }
  friend mi operator/(mi a, const mi& b) { return a /= b; }
  friend ostream& operator<<(ostream& os, const mi& m) {
    os << m.v;
    return os;
  }
  friend istream& operator>>(istream& is, mi& m) {
    long long x;
    is >> x;
    m.v = x;
    return is;
  }
};
void __print(mi X) { cout << X.v; }
long long modExp(long long base, long long power) {
  if (power == 0) {
    return 1;
  } else {
    long long cur = modExp(base, power / 2);
    cur = cur * cur;
    cur = cur % MOD;
    if (power % 2 == 1) cur = cur * base;
    cur = cur % MOD;
    return cur;
  }
}
long long inv(long long base) {
  int g = MOD, r = base, x = 0, y = 1;
  while (r != 0) {
    int q = g / r;
    g %= r;
    swap(g, r);
    x -= q * y;
    swap(x, y);
  }
  return x < 0 ? x + MOD : x;
}
long long mul(long long A, long long B) { return (A * B) % MOD; }
long long add(long long A, long long B) { return (A + B) % MOD; }
long long dvd(long long A, long long B) { return mul(A, inv(B)); }
long long sub(long long A, long long B) { return (A - B + MOD) % MOD; }
namespace NTT {
vector<long long> roots = {0, 1};
vector<int> bit_reverse;
int max_size = -1;
long long root;
bool is_power_of_two(int n) { return (n & (n - 1)) == 0; }
int round_up_power_two(int n) {
  while (n & (n - 1)) n = (n | (n - 1)) + 1;
  return max(n, 1);
}
int get_length(int n) {
  assert(is_power_of_two(n));
  return __builtin_ctz(n);
}
void bit_reorder(int n, vector<long long>& values) {
  if ((int)bit_reverse.size() != n) {
    bit_reverse.assign(n, 0);
    int length = get_length(n);
    for (int i = 0; i < n; i++)
      bit_reverse[i] = (bit_reverse[i >> 1] >> 1) + ((i & 1) << (length - 1));
  }
  for (int i = 0; i < n; i++)
    if (i < bit_reverse[i]) swap(values[i], values[bit_reverse[i]]);
}
void find_root() {
  max_size = 1 << __builtin_ctz(MOD - 1);
  root = 2;
  while (!(modExp(root, max_size) == 1 && modExp(root, max_size / 2) != 1))
    root++;
}
void prepare_roots(int n) {
  if (max_size < 0) find_root();
  assert(n <= max_size);
  if ((int)roots.size() >= n) return;
  int length = get_length(roots.size());
  roots.resize(n);
  while (1 << length < n) {
    long long z = modExp(root, max_size >> (length + 1));
    for (int i = 1 << (length - 1); i < 1 << length; i++) {
      roots[2 * i] = roots[i];
      roots[2 * i + 1] = (roots[i] * z) % MOD;
    }
    length++;
  }
}
void fft_iterative(int N, vector<long long>& values) {
  assert(is_power_of_two(N));
  prepare_roots(N);
  bit_reorder(N, values);
  for (int n = 1; n < N; n *= 2)
    for (int start = 0; start < N; start += 2 * n)
      for (int i = 0; i < n; i++) {
        long long even = values[start + i];
        long long odd = values[start + n + i] * roots[n + i];
        odd %= MOD;
        values[start + n + i] = even - odd + MOD;
        values[start + i] = even + odd;
        values[start + n + i] %= MOD;
        values[start + i] %= MOD;
      }
}
const int FFT_CUTOFF = 150;
vector<long long> mod_multiply(vector<long long> left,
                               vector<long long> right) {
  int n = left.size();
  int m = right.size();
  if (min(n, m) < FFT_CUTOFF) {
    const uint64_t ULL_BOUND =
        numeric_limits<uint64_t>::max() - (uint64_t)MOD * MOD;
    vector<uint64_t> result(n + m - 1, 0);
    for (int i = 0; i < n; i++)
      for (int j = 0; j < m; j++) {
        result[i + j] += (uint64_t)((int)left[i]) * ((int)right[j]);
        if (result[i + j] > ULL_BOUND) result[i + j] %= MOD;
      }
    for (uint64_t& x : result)
      if (x >= MOD) x %= MOD;
    return vector<long long>(result.begin(), result.end());
  }
  int N = round_up_power_two(n + m - 1);
  left.resize(N);
  right.resize(N);
  bool equal = left == right;
  fft_iterative(N, left);
  if (equal)
    right = left;
  else
    fft_iterative(N, right);
  long long inv_N = inv(N);
  for (int i = 0; i < N; i++) {
    left[i] *= (right[i] * inv_N) % MOD;
    left[i] %= MOD;
  }
  reverse(left.begin() + 1, left.end());
  fft_iterative(N, left);
  left.resize(n + m - 1);
  return left;
}
vector<long long> mod_power(const vector<long long>& v, int exponent) {
  assert(exponent >= 0);
  vector<long long> result = {1};
  if (exponent == 0) return result;
  for (int k = 31 - __builtin_clz(exponent); k >= 0; k--) {
    result = mod_multiply(result, result);
    while ((int)(result).size() > M + 1) result.pop_back();
    if (exponent >> k & 1) {
      result = mod_multiply(result, v);
      while ((int)(result).size() > M + 1) result.pop_back();
    }
  }
  return result;
}
vector<long long> mod_multiply_all(
    const vector<vector<long long>>& polynomials) {
  if (polynomials.empty()) return {1};
  struct compare_size {
    bool operator()(const vector<long long>& x, const vector<long long>& y) {
      return x.size() > y.size();
    }
  };
  priority_queue<vector<long long>, vector<vector<long long>>, compare_size> pq(
      polynomials.begin(), polynomials.end());
  while (pq.size() > 1) {
    vector<long long> a = pq.top();
    pq.pop();
    vector<long long> b = pq.top();
    pq.pop();
    pq.push(mod_multiply(a, b));
  }
  return pq.top();
}
}  // namespace NTT
void solve() {
  int N, K;
  cin >> N >> M >> K;
  int nxt[K];
  for (int i = 0; i < (K); i++) nxt[i] = -1;
  int lst[K];
  for (int i = 0; i < (K); i++) lst[i] = -1;
  bool bad[K];
  for (int i = 0; i < (K); i++) bad[i] = false;
  vector<vector<int>> gr(K);
  bool gc = false;
  for (int x = 0; x < (N); x++) {
    int L;
    cin >> L;
    if (L == 59971) gc = true;
    vector<int> A(L);
    for (int i = 0; i < (L); i++) cin >> A[i];
    for (int i = 0; i < (L); i++) A[i]--;
    for (int i = 0; i < (L - 1); i++) {
      gr[A[i]].push_back(A[i + 1]);
      gr[A[i + 1]].push_back(A[i]);
      if (nxt[A[i]] == -1) nxt[A[i]] = A[i + 1];
      if (lst[A[i + 1]] == -1) lst[A[i + 1]] = A[i];
      if (nxt[A[i]] != A[i + 1]) {
        bad[A[i]] = true;
      }
      if (lst[A[i + 1]] != A[i]) {
        bad[A[i]] = true;
      }
    }
  }
  queue<int> q;
  for (int i = 0; i < (K); i++)
    if (bad[i]) q.push(i);
  while (!q.empty()) {
    int v = q.front();
    q.pop();
    for (auto& a : gr[v]) {
      if (!bad[a]) {
        bad[a] = true;
        q.push(a);
      }
    }
  }
  vector<long long> ar(K + 1);
  for (int i = 0; i < (K); i++) {
    if (lst[i] != -1 || bad[i]) continue;
    int p = i;
    int cv = 1;
    while (nxt[p] != -1) {
      p = nxt[p];
      cv++;
    }
    ar[cv]++;
  }
  mi dp[M + 1];
  dp[0] = 1;
  vector<pair<int, int>> trans;
  for (int i = 0; i < (K + 1); i++)
    if (ar[i] > 0) trans.push_back({i, ar[i]});
  for (int i = 0; i < (M); i++) {
    for (auto& a : trans) {
      if (i + a.first > M) break;
      dp[i + a.first] += dp[i] * a.second;
    }
  }
  cout << dp[M] << nl;
  if (gc) {
    cout << ar[1] << endl;
  }
}
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  int T = 1;
  while (T--) {
    solve();
  }
  return 0;
}
