--- availability_calendars.install	Fri Jan 21 08:16:11 2011
+++ availability_calendars.install	Wed Feb 09 12:26:18 2011
@@ -45,8 +45,8 @@
       ),
       'status' => array(
         'description' => 'The status.',
-        'type' => 'text',
-        'size' => 'medium',
+        'type' => 'varchar',
+        'length' => 64,  // status = class or (split day) calsplit cal-<am-class>_<pm-class> = 14 + 2 * length of a class
       ),
       'date' => array(
         'description' => 'Datetime representation of availability',
@@ -89,6 +89,33 @@
       )
     )
   );
+
+  $schema['availability_calendars_states'] = array(
+    'description' => 'Store classes and labels for the possible states in availability calendars',
+    'fields' => array(
+      'class' => array(
+        'description' => 'The class used for this state',
+  			'type' => 'varchar',
+        'length' => 24,
+        'not null' => TRUE,
+      ),
+      'label' => array(
+        'description' => 'The label as displayed to users for this state',
+      	'type' => 'varchar',
+        'length' => 64,  // should not be too long: will give display problems
+        'not null' => TRUE,
+      ),
+      'weight' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+        'description' => 'The weight of this state',
+      ),
+    ),
+    'primary key' => array('class'),
+	);
+
   return $schema;
 }
 
@@ -96,8 +123,40 @@
  * Implementation of hook_install().
  */
 function availability_calendars_install() {
+  // Install schema
   drupal_install_schema('availability_calendars');
-  drupal_set_message(t('Availability Calendars module installed successfully.'), 'warning');
+
+  // Fill schema: add a default (starter, example) set of states to the database
+  // @TODO: shorten the classes if no css refers to these classes anymore
+  $states = array(
+    array(
+      'class' => 'calavailable',
+      'label' => 'Available',
+      'weight' => 1,
+    ),
+    array(
+      'class' => 'calnotavailable',
+      'label' => 'Fully booked',
+      'weight' => 2,
+    ),
+    array(
+      'class' => 'calnotavailableprov',
+      'label' => 'Provisionally booked',
+      'weight' => 3,
+    ),
+  );
+  $insert_query = "INSERT INTO {availability_calendars_states} (class,label,weight) VALUES ('%s','%s',%d)";
+  $success = true;
+  foreach ($states as $state) {
+    $success = db_query($insert_query, $state['class'], $state['label'], $state['weight']) !== false && $success;
+  }
+
+  if (!$success) {
+    drupal_set_message(t('Availability Calendars module not installed successfully.'), 'error');
+  }
+  else {
+    drupal_set_message(t('Availability Calendars module installed successfully.'), 'warning');
+  }
 }
 
 /**
@@ -197,7 +256,7 @@
   );
   return $ret;
 }
-
+
 /**
  * Implementation of hook_update_N().
  * Change statuses to now use class strings instead of integers and alter defaultstatus setting if set.
@@ -253,5 +312,68 @@
     'success' => TRUE,
     'query' => 'Fixed variables for ' . $sandbox['max'] . ' availability calendar variable settings.',
   );
+  return $ret;
+}
+
+/**
+ * Implementation of hook_update_N().
+ * Add custom states
+ *
+ * @return array
+ */
+function availability_calendars_update_6104(&$sandbox) {
+  $ret = array();
+
+  // Change type of field status of table availability_calendars_day,
+  // as it (kind of) refers to the class field of the new states table
+  db_change_field($ret, 'availability_calendars_day', 'status', 'status', array('type' => 'varchar', 'length' => 64));
+
+  // Add table to store configurable statuses
+  $tables = availability_calendars_schema();  //DRY: get table def from schema
+  $table_name = 'availability_calendars_states';
+  db_create_table($ret, $table_name, $tables[$table_name]);
+
+  // Add existing (hard-coded) states to the database
+  // Note: We can never shorten in an update situation, unless we update the database *contents* as well.
+  $states = array(
+    array(
+      'class' => 'calavailable',
+      'label' => 'Available',
+      'weight' => 1,
+    ),
+    array(
+      'class' => 'calnotavailable',
+      'label' => 'Fully booked',
+      'weight' => 2,
+    ),
+    array(
+      'class' => 'calnotavailableprov',
+      'label' => 'Provisionally booked',
+      'weight' => 3,
+    ),
+  );
+  $insert_query = "INSERT INTO {availability_calendars_states} (class,label,weight) VALUES ('%s','%s',%d)";
+  $success = true;
+  foreach ($states as $state) {
+    $success = db_query($insert_query, $state['class'], $state['label'], $state['weight']) !== false && $success;
+  }
+  $ret[] = array('success' => $success, 'query' => $insert_query);
+
+  // Update split statuses: the old way of assembling them did not work any more with configurable states and classes
+  $split_state_updates = array(
+    'calsplit cal-available_notavailable' => 'calsplit cal-calavailable_calnotavailable',
+    'calsplit cal-available_notavailableprov' => 'calsplit cal-calavailable_calnotavailableprov',
+    'calsplit cal-notavailable_available' => 'calsplit cal-calnotavailable_calavailable',
+    'calsplit cal-notavailable_notavailableprov' => 'calsplit cal-calnotavailable_calnotavailableprov',
+    'calsplit cal-notavailableprov_available' => 'calsplit cal-calnotavailableprov_calavailable',
+    'calsplit cal-notavailableprov_notavailable' => 'calsplit cal-calnotavailableprov_calnotavailable',
+  );
+  $update_query = "UPDATE {availability_calendars_day} SET status = '%s' WHERE status = '%s'";
+  $success = true;
+  foreach ($split_state_updates as $split_state_update_old => $split_state_update_new) {
+    $success = db_query($update_query, $split_state_update_new, $split_state_update_old) !== false && $success;
+  }
+  $ret[] = array('success' => $success, 'query' => $update_query);
+
   return $ret;
 }
--- availability_calendars.module	Sun Jan 23 05:35:46 2011
+++ availability_calendars.module	Wed Feb 09 12:31:33 2011
@@ -102,8 +102,12 @@
  * @return array
  */
 function availability_calendars_admin_settings() {
-  $form = array();
   $settings = availability_calendar_getsettings();
+
+  $form = array();
+  $form['#validate'][] = 'availability_calendars_admin_settings_validate';
+  $form['#submit'][] = 'availability_calendars_admin_settings_submit';
+
   $form['display'] = array(
     '#type' => 'fieldset',
     '#title' => t('View settings'),
@@ -125,12 +129,6 @@
     '#title' => t('Allow split day statuses.'),
     '#default_value' => $settings->splitday
   );
-  $form['display']['availability_calendars_settings_system_defaultstatus'] = array(
-    '#type' => 'select',
-    '#options' => availability_calendars_options(),
-    '#title' => t("Set the default status in which to set all newly created nodes' statuses."),
-    '#default_value' => $settings->defaultstatus
-  );
   $form['global'] = array(
     '#type' => 'fieldset',
     '#title' => t('Global settings'),
@@ -138,7 +136,7 @@
   );
   $form['global']['availability_calendars_settings_system_hideold'] = array(
     '#type' => 'checkbox',
-    '#title' => t('Set past dates to fully booked.'),
+    '#title' => t('Do not show availability state of dates in the past.'),
     '#default_value' => $settings->hideold,
   );
   $form['global']['availability_calendars_settings_system_showteaser'] = array(
@@ -146,11 +144,166 @@
     '#title' => t('Show availability calendars within teasers.'),
     '#default_value' => $settings->showteaser,
   );
-  //TODO: add status codes and css classes in here
+
+  // Add states
+  $form['states'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('States'),
+    '#tree' => TRUE,
+  	'#description' => t('<p>You can modify the availability states here.</p>
+<ul>
+<li>The label is what users will see in the legend and what editors will see when editing the calendar.</li>
+<li>The class must be unique and will be used for the css.</li>
+<li>Default defines the status to use for days that have no state yet set.</li>
+<li>The weight defines the order in the legend and in the dropdown on the edit form.</li>
+<li>Make a label empty to remove the row.</li>
+<li>If there are no more empty lines to add new states, save the form and you will be able to add another state.</li>
+<li><strong>Changes made to existing classes will not be updated in existing calendars!</strong> So do not change on live sites.</li>
+<li>If you define your own classes, you will also have to provide your own css.</li>
+</ul>'),
+    '#attributes' => array('class' => 'state-list'),
+  );
+
+  $element = &$form['states'];
+  $states = availability_calendars_get_states();
+  $i = 0;
+  foreach ($states as $state) {
+    availability_calendars_admin_settings_add_state($element, $i, $state, $settings);
+    $i++;
+  }
+
+  // Show a minimum of 4 available states with at least one empty state
+  do {
+    availability_calendars_admin_settings_add_state($element, $i, array('class' => '', 'label' => '', 'weight' => 0), $settings);
+    $i++;
+  } while ($i < 4);
+
   return system_settings_form($form);
 }
 
 /**
+ * Helper function to add a state item to a form.
+ * Only the first item gets labels, as the fields will be presented below each other.
+ *
+ * @param array $element the form element to add the state item to
+ * @param int $i the state item count
+ * @param array $state array containing a state record
+ * @param array $settings array containing general (i.e. non per state) settings
+ */
+function availability_calendars_admin_settings_add_state(&$element, $i, $state, $settings) {
+  static $max_weight = 0;
+  $element[$i]['label'] = array(
+    '#type' => 'textfield',
+    '#title' => $i == 0 ? t('Label') : '',
+    '#default_value' => $state['label'],
+    '#size' => 40,
+    '#prefix' => '<div class="state-item">',
+  );
+  $element[$i]['class'] = array(
+    '#type' => 'textfield',
+    '#title' => $i == 0 ? t('Class') : '',
+    '#default_value' => $state['class'],
+    '#size' => 24,
+  );
+  // Bit difficult to add a set of related radio button's that do not appear together
+  $element[$i]['defaultstatus'] = array(
+    '#type' => 'radio',
+    '#tree' => false,
+    // Use our own label format (as with a radio button the label appears after the radio button)
+    // and wrap it in our own div.form-item
+    '#prefix' => $i == 0 ? '<div class="cal-state-label form-item"><label for="edit-defaultstatus">' . t('Default') . ': </label>' : '',
+    '#suffix' => $i == 0 ? '</div>' : '',
+    '#return_value' => $i,
+    '#default_value' => !empty($state['class']) && $state['class'] == $settings->defaultstatus ? $i : 0,
+    // use the name attribute to group the radio buttons scattered over the items/rows
+    '#attributes' => array('name' => 'defaultstatus'),
+  );
+  $element[$i]['weight'] = array(
+    '#type' => 'select',
+    '#title' => $i == 0 ? t('Weight') : '',
+    '#default_value' => $state['weight'] > 0 ? $state['weight'] : ++$max_weight,
+    '#options' => array_combine(range(1, 20, 1), range(1, 20, 1)),
+    '#suffix' => '</div>',
+  );
+  if ($state['weight'] > $max_weight) {
+    $max_weight = $state['weight'];
+  }
+}
+
+/**
+ * Validate callback for the admin_settings form
+ * - at least one label should be filled
+ * - entered classes should be a valid css class
+ */
+function availability_calendars_admin_settings_validate($form, &$form_state) {
+  $op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
+  if ($op == t('Save configuration')) {
+    $element = $form_state['values']['states'];
+    $all_empty = true;
+    foreach ($element as $i => $state_fields){
+      if (!empty($state_fields['label'])) {
+        $all_empty = false;
+      }
+      if (!empty($state_fields['class']) && !availability_calendars_is_safe_id($state_fields['class'])) {
+        form_set_error("states][$i][class", t('Class should be usable as a valid css class.'));
+      }
+    }
+
+    if ($all_empty) {
+      form_set_error('states][0][label', t('At least 1 state should be defined.'));
+    }
+
+    $default = $form_state['values']['defaultstatus'];
+    if (empty($element[$default]['label'])) {
+      form_set_error("states][$default][label", t('The default state may not be empty or deleted.'));
+    }
+  }
+}
+
+/**
+ * Submit callback for the admin_settings form
+ *
+ * Processes the submitted form. the states are non system settings, and are handled here.
+ * Other values are handled by the default system settings form handling.
+ */
+function availability_calendars_admin_settings_submit($form, &$form_state) {
+  $op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
+  if ($op == t('Save configuration')) {
+    $element = $form_state['values']['states'];
+    // Do not process the states by the default submit handler for system settings forms
+    unset($form_state['values']['states']);
+    $states = array();
+    foreach ($element as $i => $state_fields){
+      // Only add non-empty labels
+      if (!empty($state_fields['label'])) {
+        if (empty($state_fields['class'])) {
+          $state_fields['class'] = availability_calendars_string_to_safe_id($state_fields['label']);
+        }
+        $states[$state_fields['class']] = array(
+          'class' => $state_fields['class'],
+          'label' => $state_fields['label'],
+          'weight' => $state_fields['weight'],
+        );
+      }
+    }
+
+    $default = $form_state['values']['defaultstatus'];
+    if (!empty($element[$default]['class'])) {
+      $form_state['values']['availability_calendars_settings_system_defaultstatus'] = $element[$default]['class'];
+    }
+
+    $existing_States = availability_calendars_get_states();
+    if ($states != $existing_States) {
+      // update states: dellete all existing, insert all states on the form
+      db_query("DELETE FROM {availability_calendars_states}");
+      foreach ($states as $state) {
+        db_query("INSERT INTO {availability_calendars_states} (class,label,weight) VALUES ('%s','%s',%d)", $state['class'], $state['label'], $state['weight']);
+      }
+    }
+  }
+}
+
+/**
  * Create tab to show node availability.
  *
  * @return string or FALSE
@@ -251,6 +404,7 @@
     $notes[$note['week']] = $note['note'];
   }
 
+  $day_status = array();
   $status_result = db_query('SELECT day, status FROM {availability_calendars_day} WHERE nid = %d AND year = %d AND month = %d', $nid, $year, $month);
   while ($status = db_fetch_array($status_result)) {
     $day_status[$status['day']] = $status['status'];
@@ -279,7 +433,7 @@
         '#type' => 'select',
         '#title' => date('l d F', strtotime("$year-$month-$day")),
         '#options' => availability_calendars_options(),
-        '#default_value' => ($day_status[$day] === NULL) ? $settings->defaultstatus : $day_status[$day]
+        '#default_value' => !empty($day_status[$day]) ? $day_status[$day] : $settings->defaultstatus
       );
       $day++;
       $daysinweekremaining--;
@@ -385,7 +539,9 @@
  *   Otherwise settings are set within the root of the object.
  */
 function availability_calendar_getsettings($scope = NULL, $arg = NULL) {
-  switch ($scope):
+  $defaultstatus = reset(availability_calendars_get_states());
+  $defaultstatus = $defaultstatus['class'];
+  switch ($scope) {
     case 'nodetype':
       $settings = variable_get('availability_calendars_settings_system-type_' . $arg, 0);
       break;
@@ -395,9 +551,16 @@
         $settings->showkey = variable_get('availability_calendars_settings_node_' . $arg . '_showkey', 1);
         $settings->firstletter = variable_get('availability_calendars_settings_node_' . $arg . '_firstletter', 0);
         $settings->showteaser = variable_get('availability_calendars_settings_node_' . $arg . '_showteaser', 0);
-        $settings->hideold = (variable_get('availability_calendars_settings_system_hideold', 0)) ? 1 : variable_get('availability_calendars_settings_node_' . $arg . '_hideold', 0);
-        $settings->defaultstatus = (variable_get('availability_calendars_settings_node_' . $arg . '_defaultstatus', NULL) === NULL) ? variable_get('availability_calendars_settings_system_defaultstatus', 'calavailable') : variable_get('availability_calendars_settings_node_' . $arg . '_defaultstatus', 'calavailable');
+        $settings->hideold = variable_get('availability_calendars_settings_node_' . $arg . '_hideold', null);
+        if ($settings->hideold === null) {
+          $settings->hideold = variable_get('availability_calendars_settings_system_hideold', 0);
+        }
+        $settings->defaultstatus = variable_get('availability_calendars_settings_node_' . $arg . '_defaultstatus', null);
+        if ($settings->defaultstatus === null) {
+          $settings->defaultstatus = variable_get('availability_calendars_settings_system_defaultstatus', $defaultstatus);
+        }
       }
+      // explicit fall-through
     default:
       $types = node_get_types();
       $system->status = array();
@@ -409,11 +572,11 @@
       $system->showteaser = variable_get('availability_calendars_settings_system_showteaser', 1);
       $system->splitday = variable_get('availability_calendars_settings_system_splitday', 0);
       $system->hideold = variable_get('availability_calendars_settings_system_hideold', 0);
-      $system->defaultstatus = variable_get('availability_calendars_settings_system_defaultstatus', 'calavailable');
+      $system->defaultstatus = variable_get('availability_calendars_settings_system_defaultstatus', $defaultstatus);
       if ($scope == 'node' && $arg) $settings->system = $system;
       else $settings = $system;
       break;
-  endswitch;
+  };
   return $settings;
 }
 
@@ -478,37 +641,21 @@
     t('Color'),
     t('Availability')
   );
-  $rows = array( // keystatus class used to allow better styling of the status column
-    array(
-      array(
-        'data' => '&nbsp;',
-        'class' => 'calavailable'
-      ),
-      array(
-        'data' => t('Available'),
-        'class' => 'keystatus'
-      )
-    ),
-    array(
-      array(
-        'data' => '&nbsp;',
-        'class' => 'calnotavailable'
-      ),
-      array(
-        'data' => t('Fully booked'),
-        'class' => 'keystatus'
-      )
-    ),
-    array(
+  $rows = array();
+  $states = availability_calendars_get_states();
+  foreach ($states as $class => $state) {
+    $rows[] = array(
       array(
         'data' => '&nbsp;',
-        'class' => 'calnotavailableprov'
+        'class' => $class
       ),
       array(
-        'data' => t('Provisionally booked'),
-        'class' => 'keystatus'
+        'data' => check_plain(t($state['label'])),
+        'class' => 'keystatus' // keystatus class used to allow better styling of the status column
       )
-    ),
+    );
+  }
+  $rows += array(
     array(
       array(
         'data' => '&nbsp;',
@@ -611,15 +758,14 @@
   while ($note = db_fetch_array($notes_result)) {
     $notes[$note['week']] = $note['note'];
   }
+  $day_status = array();
   $status_result = db_query('SELECT day, status FROM {availability_calendars_day} WHERE nid = %d AND year = %d AND month = %d', $node->nid, $year, $month);
   while ($status = db_fetch_array($status_result)) {
     $day_status[$status['day']] = $status['status'];
   }
-  $availability_calendars_options = availability_calendars_options();
   $today = mktime(0, 0, 0, date('m'), date('j'), date('Y'));
   $rows = array(); // our container for rows
   $cells = array(); // our container for cells
-  $options = availability_calendars_options();
   foreach ($week as $key => $val) {
     $weeknumber = $key + 1;
     array_push($cells, array('data' => $notes[$weeknumber], 'class' => 'calnote')); // add the note cell to the cells array
@@ -628,16 +774,15 @@
       $daystamp = mktime(0, 0, 0, (int) $month, (int) $day, (int) $year);
       // if there's a date, it's part of this month
       if ($day) {
+        $status = !empty($day_status[$day]) ? $day_status[$day] : $settings->defaultstatus;
         $classes = array();
         if ($today == $daystamp) $classes[] = 'caltoday'; // today
         if ($daystamp < $today) $classes[] = 'calpastdate'; // past date
-        if ($settings->hideold === 1 && $daystamp < $today) $classes[] = 'calnotavailable'; // past dates should be "fully booked"
-        else {
-          if ($day_status[$day] === NULL) $classes[] = ($settings->defaultstatus) ? $settings->defaultstatus : $options[0];
-          else $classes[] = $day_status[$day];
+        if ($settings->hideold !== 1 || $daystamp >= $today) {
+          $classes[] = $status;
         }
         $classes = implode(' ', $classes);
-        $day = (strpos($day_status[$day], 'calsplit ') === 0) ? '&nbsp;<div class="cal-split-date">' . $day . '</div><div class="cal-split-bg"></div>' : $day;
+        $day = strpos($status, 'calsplit ') === 0 ? '&nbsp;<div class="cal-split-date">' . $day . '</div><div class="cal-split-bg"></div>' : $day;
         array_push($cells, array('data' => $day, 'class' => $classes));
       }
       else { // empty, typically row 1 or 5 in a month
@@ -660,27 +805,26 @@
 
 /**
  * availability_calendars status options.
+ * note: we return unescaped labels as they might be used as options in a select where they get escaped again
  *
- * @return array
+ * @return array array with the classes as the keys and the translated but unescaped labels as values
  */
 function availability_calendars_options() {
-  // TODO: make these configurable
-  $settings = availability_calendar_getsettings();
-  $statuses = array(
-    'available' => t('Available'),
-    'notavailable' => t('Fully booked'),
-    'notavailableprov' => t('Provisionally booked'),
-  );
-  $ret = array();
-  foreach ($statuses as $class => $label) {
-    $ret['cal' . $class] = $label;
-  }
-  if ($settings->splitday === 1) {
-    foreach ($statuses as $class => $label) {
-      $sub = $statuses;
-      unset($sub[$class]);
-      foreach ($sub as $subclass => $sublabel) {
-        $ret['calsplit cal-' . $class . '_' . $subclass] = t('@a (am)/@b (pm)', array('@a' => $label, '@b' => $sublabel));
+  static $ret = null;
+  if ($ret === null) {
+    $ret = array();
+    $settings = availability_calendar_getsettings();
+    $statuses = availability_calendars_get_states();
+    foreach ($statuses as $class => $state) {
+      $ret[$class] = $state['label'];
+    }
+    if ($settings->splitday === 1) {
+      foreach ($statuses as $class => $state) {
+        $sub = $statuses;
+        unset($sub[$class]);
+        foreach ($sub as $subclass => $substate) {
+          $ret['calsplit cal-' . $class . '_' . $subclass] = t('!a (am)/!b (pm)', array('!a' => $state['label'], '!b' => $substate['label']));
+        }
       }
     }
   }
@@ -688,6 +832,21 @@
 }
 
 /**
+ * @return array array with records for all states (unescaped strings)
+ */
+function availability_calendars_get_states() {
+  static $states = null;
+  if ($states === null) {
+    $states = array();
+    $result = db_query("SELECT * FROM {availability_calendars_states} ORDER BY weight");
+    while ($row = db_fetch_array($result)) {
+      $states[$row['class']] = $row;
+    }
+  }
+  return $states;
+}
+
+/**
  * Implementation of hook_form_alter().
  * All form alterations needed for the calendars.
  *
@@ -864,4 +1023,27 @@
       }
     return  $block;
   }
+}
+
+/**
+* Converts a string to a valid html id/class attribute.
+*
+* http://www.w3.org/TR/html4/struct/global.html#h-7.5.2 specifies what makes a
+* valid id/class attribute in HTML. This function:
+*
+* - Ensure an ID starts with an alpha character by prefixing with 'cal'.
+* - Replaces any character except a-z, A-Z, numbers, and underscores with dashes.
+* - Converts entire string to lowercase.
+*
+* @param $string The string
+* @return the converted string
+*/
+function availability_calendars_string_to_safe_id($string) {
+  return 'cal' . strtolower(preg_replace('/[^a-zA-Z0-9_-]+/', '-', $string));
+  //D7: return 'cal' . drupal_html_class($string);
+
+}
+
+function availability_calendars_is_safe_id($string) {
+  return preg_match('/^[a-zA-Z][a-zA-Z0-9_-]*$/', $string) > 0;
 }
--- availability_calendars.css	Tue Jan 18 05:10:01 2011
+++ availability_calendars.css	Wed Feb 09 12:21:12 2011
@@ -19,15 +19,21 @@
 td.calnotavailableprov,tr.odd td.calnotavailableprov,tr.even td.calnotavailableprov{color:#ccc;text-align:center;background:#FFFFE0;}
 td.caltoday,tr.odd td.caltoday,tr.even td.caltoday{border:1px solid #A00000;}
 /* split day statuses */
-td.cal-available_notavailable,tr.odd td.cal-available_notavailable,tr.even td.cal-available_notavailable{background:#FFB6C1;}
-td.cal-available_notavailable > .cal-split-bg{border-color:#90EE90 #FFB6C1 #FFB6C1 #90EE90;}
-td.cal-available_notavailableprov,tr.odd td.cal-available_notavailableprov,tr.even td.cal-available_notavailableprov{background:#FFFFE0;}
-td.cal-available_notavailableprov > .cal-split-bg{border-color:#90EE90 #FFFFE0 #FFFFE0 #90EE90;}
-td.cal-notavailable_available,tr.odd td.cal-notavailable_available, tr.even td.cal-notavailable_available{background:#90EE90;}
-td.cal-notavailable_available > .cal-split-bg{border-color:#FFB6C1 #90EE90 #90EE90 #FFB6C1;}
-td.cal-notavailable_notavailableprov,tr.odd td.cal-notavailable_notavailableprov,tr.even td.cal-notavailable_notavailableprov{background:#FFFFE0;}
-td.cal-notavailable_notavailableprov > .cal-split-bg{border-color:#FFB6C1 #FFFFE0 #FFFFE0 #FFB6C1;}
-td.cal-notavailableprov_available,tr.odd td.cal-notavailableprov_available,tr.even td.cal-notavailableprov_available{background:#90EE90;}
-td.cal-notavailableprov_available > .cal-split-bg{border-color:#FFFFE0 #90EE90 #90EE90 #FFFFE0;}
-td.cal-notavailableprov_notavailable,tr.odd td.cal-notavailableprov_notavailable,tr.even td.cal-notavailableprov_notavailable{background:#FFB6C1;}
-td.cal-notavailableprov_notavailable > .cal-split-bg{border-color:#FFFFE0 #FFB6C1 #FFB6C1 #FFFFE0;}
+td.cal-calavailable_calnotavailable,tr.odd td.cal-calavailable_calnotavailable,tr.even td.cal-calavailable_calnotavailable{background:#FFB6C1;}
+td.cal-calavailable_calnotavailable > .cal-split-bg{border-color:#90EE90 #FFB6C1 #FFB6C1 #90EE90;}
+td.cal-calavailable_calnotavailableprov,tr.odd td.cal-calavailable_calnotavailableprov,tr.even td.cal-calavailable_calnotavailableprov{background:#FFFFE0;}
+td.cal-calavailable_calnotavailableprov > .cal-split-bg{border-color:#90EE90 #FFFFE0 #FFFFE0 #90EE90;}
+td.cal-calnotavailable_calavailable,tr.odd td.cal-calnotavailable_calavailable, tr.even td.cal-calnotavailable_calavailable{background:#90EE90;}
+td.cal-calnotavailable_calavailable > .cal-split-bg{border-color:#FFB6C1 #90EE90 #90EE90 #FFB6C1;}
+td.cal-calnotavailable_calnotavailableprov,tr.odd td.cal-calnotavailable_calnotavailableprov,tr.even td.cal-calnotavailable_calnotavailableprov{background:#FFFFE0;}
+td.cal-calnotavailable_calnotavailableprov > .cal-split-bg{border-color:#FFB6C1 #FFFFE0 #FFFFE0 #FFB6C1;}
+td.cal-calnotavailableprov_calavailable,tr.odd td.cal-calnotavailableprov_calavailable,tr.even td.cal-calnotavailableprov_calavailable{background:#90EE90;}
+td.cal-calnotavailableprov_calavailable > .cal-split-bg{border-color:#FFFFE0 #90EE90 #90EE90 #FFFFE0;}
+td.cal-calnotavailableprov_calnotavailable,tr.odd td.cal-calnotavailableprov_calnotavailable,tr.even td.cal-calnotavailableprov_calnotavailable{background:#FFB6C1;}
+td.cal-calnotavailableprov_calnotavailable > .cal-split-bg{border-color:#FFFFE0 #FFB6C1 #FFB6C1 #FFFFE0;}
+
+/* admin settings form */
+fieldset.state-list .state-item { position: relative; width: 100%; overflow: auto; }
+fieldset.state-list .cal-state-label, fieldset.state-list .form-item { float: left; margin-right: 1em; }
+fieldset.state-list .cal-state-label .form-item { margin: 0; float: none; }
+fieldset.state-list input.form-radio { margin-right: 5em; }
