#include <bits/stdc++.h>
using namespace std;
const int inf = (1 << 30) - 1;
const long long linf = (1ll << 62) - 1;
const int N = 1e6 + 100;
const int M = 1e9 + 7;
int m, n;
vector<int> cl[N], sign[N];
vector<int> g[N];
bool used[N];
int dp[2], ndp[2], cdp[2];
int rt;
int val;
map<tuple<int, int, int>, int> current;
int self[N], signSelf[N];
inline int f(int v, int pe, int mustValue, int vValue) {
  used[v] = true;
  if (v == rt && pe != -1) {
    return mustValue == 0 && vValue == val;
  }
  if (current.count(make_tuple(v, mustValue, vValue))) {
    return current[make_tuple(v, mustValue, vValue)];
  }
  int& result = current[make_tuple(v, mustValue, vValue)] = 0;
  if (self[v] != -1) {
    mustValue ^= signSelf[v] ? !vValue : vValue;
  }
  int cnt = 0;
  for (int e : g[v]) {
    int to = cl[e][0] ^ cl[e][1] ^ v;
    if (e == pe) {
      continue;
    }
    cnt++;
    for (int vTo = 0; vTo < 2; vTo++) {
      int cur = (sign[e][cl[e][0] == v ? 0 : 1] ? !vValue : vValue) ||
                (sign[e][cl[e][0] == to ? 0 : 1] ? !vTo : vTo);
      result += f(to, e, mustValue ^ cur, vTo);
      if (result >= M) {
        result -= M;
      }
    }
    if (cnt) {
      break;
    }
  }
  if (cnt == 0) {
    return result = (mustValue == 0);
  }
  return result;
}
void calcDP(int v) {
  rt = v;
  cdp[0] = cdp[1] = 0;
  current.clear();
  val = 0;
  cdp[0] += f(rt, -1, 0, 0);
  current.clear();
  val = 1;
  cdp[0] += f(rt, -1, 0, 1);
  current.clear();
  val = 0;
  cdp[1] += f(rt, -1, 1, 0);
  current.clear();
  val = 1;
  cdp[1] += f(rt, -1, 1, 1);
  while (cdp[0] >= M) {
    cdp[0] -= M;
  }
  while (cdp[1] >= M) {
    cdp[1] -= M;
  }
}
int mustHave = 1;
int main() {
  cin >> m >> n;
  for (int i = 0; i < m; i++) {
    int k;
    scanf("%d", &k);
    cl[i].resize(k);
    sign[i].resize(k);
    for (int j = 0; j < k; j++) {
      scanf("%d", &cl[i][j]);
      sign[i][j] = cl[i][j] < 0;
      cl[i][j] = abs(cl[i][j]) - 1;
    }
    if (k == 2 && cl[i][0] == cl[i][1] && sign[i][0] == sign[i][1]) {
      cl[i].pop_back();
    }
    if (((int)(cl[i]).size()) == 2 && cl[i][0] == cl[i][1] &&
        sign[i][0] != sign[i][1]) {
      i--;
      m--;
      mustHave ^= 1;
    }
  }
  fill_n(self, n, -1);
  for (int i = 0; i < m; i++) {
    if (((int)(cl[i]).size()) > 1) {
      g[cl[i][1]].push_back(i);
      g[cl[i][0]].push_back(i);
    } else {
      self[cl[i].back()] = i;
      signSelf[cl[i].back()] = sign[i].back();
    }
  }
  static int list[N];
  for (int i = 0; i < n; i++) {
    list[i] = i;
  }
  sort(list, list + n, [&](int a, int b) {
    return ((int)(g[a]).size()) < ((int)(g[b]).size());
  });
  dp[0] = 1;
  dp[1] = 0;
  for (int t = 0; t < n; t++) {
    int i = list[t];
    if (!used[i]) {
      cdp[0] = cdp[1] = 0;
      calcDP(i);
      ndp[0] = (1ll * dp[0] * cdp[0] + 1ll * dp[1] * cdp[1]) % M;
      ndp[1] = (1ll * dp[0] * cdp[1] + 1ll * dp[1] * cdp[0]) % M;
      dp[0] = ndp[0];
      dp[1] = ndp[1];
    }
  }
  printf("%d\n", dp[mustHave]);
  return 0;
}
