#9 darken buildings

#9 darken buildings

@color_physical: #dee0be;
@color_physical_bright: #fff;
@color_water: #99b3cc;
@color_administrative_lowzoom: #000;
@color_administrative_dark: #000;
@color_administrative_bright: #fff;
@color_administrative_medium_low: #000;
@color_administrative_medium_high: #000;
@color_administrative_medium_high2: #000;
@color_transport: #999;
@color_transport_casing: #ddd;
@color_transport_inline: #fff;
@color_transport_tunnel: #ccc;
@color_transport_minor: #ccc;
@color_transport_rail: #aaa; // 35% K
@color_transport_path: #666; // 60% K
@color_building: #b0c0be;
@color_building_outline: darken(@color_building,20);
@color_building_outline_special: #00aeef;
@color_airport_runways: @color_transport;
@color_airport_runways_detail: darken(@color_airport_runways,20);
@color_green_areas: darken(#c0d3b5,20);

Map {
  background-color: @color_physical;
  font-directory: url("fonts/");
}

/**
 * "shore" is a general class for layers with continents, coastlines, lakes,
 * and other kinds of meeting points between water and land.
 */
.shore {
  line-color: @color_physical;
  /* lighten background color, as we decrease landcover opacity */
  [zoom>=12] {
    polygon-fill: lighten(@color_physical,20);
  }
  [zoom>=14] {
    polygon-fill: lighten(@color_physical,40);
  }

  line-cap: round;
  line-join: round;
  line-width: 0;
}

#ne_10m_rivers_lake_centerlines_scale_rank
{
  [zoom=4][scalerank<4] {
    line-color: @color_water;
    line-width: 0.5;
    [strokeweig>1] { line-width: 1; }
    [strokeweig>2] { line-width: 2; }
  }
  [zoom=5][scalerank<5] {
    line-color: @color_water;
    line-width: 0.5;
    [strokeweig>1] { line-width: 1; }
    [strokeweig>2] { line-width: 2; }
  }
  [zoom=6][scalerank<6] {
    line-color: @color_water;
    line-width: 0.5;
    [strokeweig>1] { line-width: 1; }
    [strokeweig>2] { line-width: 2; }
  }
  [zoom=7][scalerank<7] {
    line-color: @color_water;
    line-width: 1;
    [strokeweig>1] { line-width: 1.5; }
    [strokeweig>2] { line-width: 2.5; }
  }
  [zoom>=8] {
    line-width: 1;
    line-color: @color_water;
    [strokeweig>1] { line-width: 2; }
    [strokeweig>2] { line-width: 3; }
  }
}

#water,
#ne_10m_ocean,
#ne_10m_lakes,
#ne_50m_lakes
{
  //line-width: 0.5;
  line-color: @color_water;
  polygon-fill: @color_water;
}

.country-boundary[scalerank<6],
.country-boundary-10m[scalerank<6] {
  line-color: @color_administrative_dark;
  line-opacity: 0.2;
  line-width: 2;
  line-dasharray: 7,3;
  ::glow {
    line-color: @color_administrative_dark;
    line-opacity: 0.08;
    line-width: 4;
    line-dasharray: 7,3;
  }
}

#admin1-lines-10m,
#admin0-map-units-10m {
  [zoom>=4][adm0_a3='CAN'],
  [zoom>=4][adm0_a3='USA'],
  [zoom>=4][adm0_a3='AUS'],
  [zoom>=5][scalerank<=2],
  [zoom>=5][featurecla='Map unit boundary'][adm0_a3='GBR'],
  [zoom>=6][scalerank<=4],
  [zoom>=6][featurecla='Map unit boundary'][adm0_a3='GBR'] {
    line-color: @color_administrative_dark;
    line-opacity: 0.15;
    line-width: 1.5;
    line-dasharray: 7,3;
    ::glow {
      line-color: @color_administrative_dark;
      line-opacity: 0.05;
      line-width: 3;
      line-dasharray: 7,3;
    }
  }

  [zoom>=7][scalerank<=5] {
    line-width: 1;
    line-color: @color_administrative_medium_low;
    line-dasharray: 1,5;
    line-cap: round;
  }

  [zoom>=8][scalerank<=6] {
    line-width: 1.2;
    line-color: @color_administrative_medium_high;
    line-dasharray: 1,5;
    line-cap: round;
  }

  [zoom>=9][scalerank<=8] {
    line-width: 1.2;
    line-color: @color_administrative_medium_high2;
    line-dasharray: 1,5;
    line-cap: round;
  }
}

#lakes-50m[zoom<3][scalerank<1],
#lakes-50m[zoom=3][scalerank<2],
#lakes-50m[zoom=4][scalerank<3],
#lakes-50m[zoom=5][scalerank<5],
#lakes-50m[zoom=6],
#lakes-10m,
{
  line-width: 1;
  polygon-fill: @color_physical;
}

#ne-roads[zoom=7][scalerank<=4],
#ne-roads[zoom>=8][scalerank<=8] {
  ::casing {
    line-color: @color_transport_casing;
    line-opacity: 0.5;
    line-width: 1.5;

    [zoom=8][scalerank<=6] {
      line-width: 3;
    }
  }

  line-color: @color_transport;
  line-width: 0;

  [zoom=8][scalerank<=6] {
    line-width: 1;
  }
}

/**
 * Ocean, lake, and river polygons
 */
#water-bodies-low[zoom=8][area>50000000],
#water-bodies-low[zoom=9][area>10000000],
#water-bodies-low[zoom=10][area>2500000],
#water-bodies-med[zoom=11][area> 800000],
#water-bodies-med[zoom=12][area> 500000],
#water-bodies-med[zoom=13][area>  25000],
#water-bodies-high[zoom=14][area> 10000],
#water-bodies-high[zoom>=15]
{
  polygon-fill: @color_water;
}

/**
 * Water bodies that are parts of rivers
 * should never be filtered
 */
#water-bodies-low[type='riverbank'],
#water-bodies-med[type='riverbank'],
#water-bodies-high[type='riverbank']
{
  polygon-fill: @color_water;
}

#nullisland {
  polygon-fill: @color_physical;
}

#admin1-lines-osm,
{
  line-width: 2.0;
  line-color: @color_administrative_medium_high2;
  line-dasharray: 1,5;
  line-cap: round;
}

/**
 * Zoom 13 buildings.
 * Already filtered by size upon import.
 */
#buildings-med[type!='no'] {
  polygon-fill: @color_building;
  line-width: 0.5;
  line-color: @color_building_outline;
}

/**
 * Zoom 14+ buildings.
 * Includes all buildings.
 */
#buildings-high[type!='no'] {
  [zoom=14] {
    [area>=5000] {
      polygon-fill: @color_building;
      line-width: 0.5;
      line-color: @color_building_outline;
    }
  }

  /**
   * This is for outlines and no stripe. Catches small buildings.
   * Larger buildings will be overridden with stripes below.
   */
  [zoom>=15][area>=2000],
  [zoom>=16] {
    polygon-fill: @color_building;
    line-width: 0.5;
    line-color: @color_building_outline;
  }

  [zoom=15][area>=3000],
  [zoom=16][area>=2000],
  [zoom=17][area>=1000],
  [zoom>=18],
  {
    polygon-fill: @color_building;
    line-width: 0.5;
    line-color: @color_building_outline;
  }

  // Stamen HQ fancy candycane striping
  [zoom>=18] {
    [osm_id=260351411],
    [osm_id=224030635], // Seth's house
    [osm_id=248153467], // Sean's house
    [osm_id=291796473], // Stamen South
    {
      polygon-fill: @color_building;
      line-width: 1.5;
      line-color: @color_building_outline_special;
    }
  }
}

#green-areas-low[zoom=10][area>5000000],
#green-areas-med[zoom=11][area>1000000],
#green-areas-med[zoom=12][area> 500000],
#green-areas-med[zoom=12][area> 200000],
#green-areas-med[zoom=13][area>  75000],
#green-areas-high[zoom=14][area> 10000],
#green-areas-high[zoom>14],
{
  polygon-fill: @color_green_areas;
  polygon-opacity: 0.5;

  [type='nature_reserve'] {
    polygon-fill: @color_green_areas;
    polygon-opacity: 0.3;
  }
}

#aeroways {
  line-color: @color_airport_runways;
  line-cap: square;
  line-join: miter;

  [zoom>=15] {
    line-color: @color_airport_runways_detail;
  }

  [type='runway'] {
    [zoom=12] {
      line-width: 2;
    }

    [zoom=13] {
      line-width: 4;
    }

    [zoom=14] {
      line-width: 8;
    }

    [zoom=15] {
      line-width: 16;
    }

    [zoom=16] {
      line-width: 32;
    }

    [zoom=17] {
      line-width: 64;
    }

    [zoom>=18] {
      line-width: 128;
    }
  }

  [type='taxiway'] {
    [zoom=13] {
      line-width: 1;
    }

    [zoom=14] {
      line-width: 2;
    }

    [zoom=15] {
      line-width: 4;
    }

    [zoom=16] {
      line-width: 8;
    }

    [zoom=17] {
      line-width: 16;
    }

    [zoom>=18] {
      line-width: 32;
    }
  }
}

#tunnels,
#roads,
#roads_med,
#highways_med,
#bridges {
  ::casing,
  ::outline,
  {
    line-cap: butt;
    line-width: 0;
    line-color: @color_transport_casing;
  }

  line-join: round;
  line-cap: round;
  line-width: 1;
  line-color: @color_transport;
}

#tunnels {
  [zoom>=14] {
    ::outline
    {
      line-opacity: 0.7;
      line-color: @color_transport_tunnel;
    }

    line-opacity: 0.5;
    line-width: 4;
  }
}

#tunnels[kind='highway'] {
  [zoom>=15] {
    ::outline {
      line-width: 5.5;
    }

    line-width: 4;
  }

  [zoom>=16] {
    ::outline {
      line-width: 7;
      line-opacity: 0.4;
    }

    line-opacity: 0.7;
    line-color: @color_transport_tunnel;

    [is_link='yes'] {
      ::outline {
        line-color: @color_transport_casing;
      }
    }
  }

  [zoom>=17] {
    ::outline {
      line-width: 18;
    }

    line-width: 12;

    [is_link='yes'] {
      ::outline {
        line-width: 9;
      }
    }
  }

  [zoom>=18] {
    ::outline {
      line-width: 22;
      line-color: @color_transport;
    }

    line-width: 18;
    line-color: @color_transport_inline;
  }

  [zoom>=19] {
    ::outline {
      line-width: 30;
    }

    line-width: 26;

    [is_link='yes'] {
      ::outline {
        line-width: 13;
      }
    }
  }
}

#tunnels[kind='major_road'] {
  [zoom>=15] {
    ::outline {
      line-width: 5;
      line-opacity: 0.7;
      line-color: @color_transport_tunnel;
    }

    line-width: 3;
    line-opacity: 0.5;
  }

  [zoom>=16] {
    ::outline {
      line-width: 7;
      line-opacity: 0.4;
    }

    line-opacity: 0.7;
    line-color: @color_transport_tunnel;

    [is_link='yes'] {
      ::outline {
        line-color: @color_transport_casing;
      }
    }
  }

  [zoom>=17] {
    ::outline {
      line-width: 18;
    }

    line-width: 12;

    [is_link='yes'] {
      ::outline {
        line-width: 9;
      }
    }
  }

  [zoom>=18] {
    ::outline {
      line-width: 22;
    }

    line-width: 18;
  }

  [zoom>=19] {
    ::outline {
      line-width: 30;
    }

    line-width: 26;

    [is_link='yes'] {
      ::outline {
        line-width: 13;
      }
    }
  }
}

#tunnels[kind='minor_road'] {
  [zoom>=15] {
    ::outline {
      line-opacity: 0.7;
      line-color: @color_transport_tunnel;
    }

    line-color: @color_transport_minor;
    line-width: 1.5;
    line-opacity: 0.5;
  }

  [zoom>=16] {
    ::outline {
      line-width: 7;
    }

    line-width: 4;
    line-color: @color_transport;
  }

  [zoom>=17] {
    ::outline {
      line-width: 9;
    }

    line-width: 7;
  }

  [zoom>=18] {
    ::outline {
      line-width: 17;
      line-color: @color_transport;
    }

    line-width: 13;
    line-color: @color_transport_casing;
  }

  [zoom>=19] {
    ::outline {
      line-width: 20;
    }

    line-width: 16;
  }
}

#bridges[kind='highway'] {
  [zoom>=13] {
    ::outline {
      line-width: 8;
    }

    line-width: 4;

    [is_link='yes'] {
      ::outline {
        line-width: 0;
      }

      line-width: 1;
    }
  }

  [zoom>=14] {
    ::outline {
      line-width: 8;
    }

    line-width: 4;

    [is_link='yes'] {
      ::outline {
        line-width: 4;
      }

      line-width: 2.5;
    }
  }

  [zoom>=15] {
    ::outline {
      line-width: 11;
    }

    line-width: 6;

    [is_link='yes'] {
      ::outline {
        line-width: 5.5;
      }

      line-width: 2.5;
    }
  }

  [zoom>=16] {
    ::outline {
      line-width: 14;
    }

    line-width: 9;

    [is_link='yes'] {
      ::outline {
        line-width: 7;
      }

      line-width: 2.5;
    }
  }

  [zoom>=17] {
    ::outline {
      line-width: 20;
    }

    line-width: 15;

    [is_link='yes'] {
      ::outline {
        line-width: 9;
      }

      line-width: 5;
    }
  }

  [zoom>=18] {
    ::outline {
      line-width: 44;
      line-color: @color_transport;
    }

    line-width: 28;
    line-color: @color_transport_inline;

    [is_link='yes'] {
      ::outline {
        line-width: 22;
      }

      line-width: 18;
    }
  }

  [zoom>=19] {
    ::outline {
      line-width: 51;
    }

    line-width: 35;

    [is_link='yes'] {
      ::outline {
        line-width: 21;
      }

      line-width: 16;
    }
  }
}

#bridges[kind='major_road'] {
  line-color: @color_transport;

  [zoom>=14] {
    ::outline {
      line-width: 5;
    }

    line-width: 1.9;
  }

  [zoom>=15] {
    ::outline {
      line-width: 8.5;
    }

    line-width: 5.5;

    [is_link='yes'] {
      ::outline {
        line-width: 5.5;
      }

      line-width: 2.5;
    }
  }

  [zoom>=16] {
    ::outline {
      line-width: 11;
    }

    line-width: 7;

    [is_link='yes'] {
      ::outline {
        line-width: 7;
      }

      line-width: 2.5;
    }
  }

  [zoom>=17] {
    ::outline {
      line-width: 18;
    }

    line-width: 12;

    [is_link='yes'] {
      ::outline {
        line-width: 8;
      }

      line-width: 4;
    }
  }

  [zoom>=18] {
    ::outline {
      line-width: 24;
      line-color: @color_transport;
    }

    line-width: 18;
    line-color: @color_transport_inline;

    [is_link='yes'] {
      ::outline {
        line-width: 14;
      }

      line-width: 9;
    }
  }

  [zoom>=19] {
    ::outline {
      line-width: 32;
    }

    line-width: 26;

    [is_link='yes'] {
      ::outline {
        line-width: 18;
      }

      line-width: 13;
    }
  }
}

#roads,
#roads_med,
#highways_med {
  ::casing,
  ::outline,
  {
    line-cap: butt;
    line-width: 0;
    line-color: @color_transport_casing;
  }

  line-join: round;
  line-cap: round;
  line-width: 0;
  line-color: @color_transport;

  [is_link='yes']
  {
    [zoom>=16]
    {
      ::casing {
        line-width: 8;
      }

      line-width: 4;
    }
  }
}

#roads[kind='highway'],
#highways_med[kind='highway']
{
  [zoom>=9] {
    ::outline {
      line-width: 4.25;
    }

    line-width: 1.5;
  }

  [zoom>=10] {
    ::outline {
      line-width: 5;
    }

    line-width: 2;
  }

  [zoom>=11] {
    ::outline {
      line-width: 6;
    }

    line-width: 2.5;
  }

  [zoom>=12] {
    ::outline {
      line-width: 7;
    }

    line-width: 3;

    [is_link='yes'] {
      ::outline {
        line-width: 0;
      }

      line-width: 0.5;
    }
  }

  [zoom>=13] {
    ::outline {
      line-width: 8;
    }

    [is_link='yes'] {
      ::outline {
        line-width: 0;
      }

      line-width: 1;
    }
  }

  [zoom>=14] {
    ::outline {
      line-width: 9;
    }

    line-width: 4;

    [is_link='yes'] {
      ::outline {
        line-width: 4;
      }

      line-width: 2.5;
    }
  }

  [zoom>=15] {
    ::casing {
      line-width: 11;
    }

    line-width: 6;

    [is_link='yes'] {
      ::casing {
        line-width: 6.5;
      }

      line-width: 2.25;
    }
  }

  [zoom>=16] {
    ::casing {
      line-width: 14;
    }

    line-width: 9;

    [is_link='yes'] {
      ::casing {
        line-width: 7;
      }

      line-width: 2.5;
    }
  }

  [zoom>=17] {
    ::casing {
      line-width: 24;
    }

    line-width: 15;

    [is_link='yes'] {
      ::casing {
        line-width: 9;
      }

      line-width: 5;
    }
  }

  [zoom>=18] {
    line-width: 28;

    [is_link='yes'] {
      ::casing {
        line-width: 14;
      }

      line-width: 10;
    }
  }

  [zoom>=19] {
    ::casing {
      line-width: 49;
    }

    line-width: 35;

    [is_link='yes'] {
      ::casing {
        line-width: 20;
      }

      line-width: 16;
    }
  }
}

#roads[kind='major_road'],
#roads_med[kind='major_road']
{
  [zoom<=12] {
    line-color: @color_transport;
  }

  [zoom>=9] {
    line-width: 0.15;
  }

  [zoom>=10] {
    line-width: 0.5;
  }

  [zoom>=11] {
    ::outline {
      line-width: 1.25;
    }

    line-width: 0.7;
  }

  [zoom>=12] {
    ::outline {
      line-width: 5;
    }

    line-width: 1;

    [is_link='yes'] {
      ::outline {
        line-width: 0;
      }

      line-width: 0.5;
    }
  }

  [zoom>=13] {
    line-width: 1.5;
  }

  [zoom>=14] {
    ::outline {
      line-width: 5;
    }

    line-width: 1.9;

    [is_link='yes'] {
      ::outline {
        line-width: 5;
      }

      line-width: 1.9;
    }
  }

  [zoom>=15] {
    ::casing {
      line-width: 8;
    }

    line-width: 5;

    [is_link='yes'] {
      ::casing {
        line-width: 5.5;
      }

      line-width: 2.25;
    }
  }

  [zoom>=16] {
    ::casing {
      line-width: 11;
    }

    line-width: 7;

    [is_link='yes'] {
      ::casing {
        line-width: 7;
      }

      line-width: 2.5;
    }
  }

  [zoom>=17] {
    line-width: 12;

    [is_link='yes'] {
      line-width: 4;
    }
  }

  [zoom>=18] {
    line-width: 18;

    [is_link='yes'] {
      line-width: 9;
    }
  }

  [zoom>=19] {
    ::casing {
      line-width: 30;
    }

    line-width: 26;

    [is_link='yes'] {
      ::casing {
        line-width: 17;
      }

      line-width: 13;
    }
  }
}

#roads[kind='minor_road'],
#roads_med[kind='minor_road']
{
  line-color: @color_transport_minor;

  [zoom>=10] {
    line-width: 0.2;
  }

  [zoom>=13] {
    line-width: 0.4;
  }

  [zoom>=14] {
    line-width: 0.8;
  }

  [zoom>=15] {
    line-width: 1.5;
  }

  [zoom>=16] {
    line-width: 4;
    line-color: @color_transport;
  }

  [zoom>=17] {
    line-width: 7;
  }

  [zoom>=18] {
    line-width: 13;
  }

  // [zoom>=19] {
  //   ::casing {
  //     line-width: 20;
  //   }

  //   line-width: 16;
  // }
}

#tunnels[kind='rail'],
#roads[kind='rail'],
#bridges[kind='rail']
{
  ::casing,
  ::outline,
  {
    line-color: @color_transport_rail;
  }

  line-color: @color_transport_rail;

  [zoom>=14] {
    ::casing {
      line-width: 3;
      line-dasharray: 1,3;
    }

    line-width: 1;
  }

  [zoom>=16] {
    ::casing {
      line-width: 5;
      line-dasharray: 1,4;
    }
  }

  [zoom>=18] {
    ::casing {
      line-width: 6;
      line-dasharray: 2,6;
    }

    line-width: 2;
  }

  [zoom>=19] {
    line-width: 4;
  }
}

#tunnels[highway='service'],
#roads[highway='service'],
#bridges[highway='service'],
{
  [zoom>=15]
  {
    line-width: 1.5;
  }

  [zoom>=16] {
    ::casing {
      line-width: 4;
    }

    line-width: 2;
  }

  [zoom>=17] {
    line-width: 4;
  }
}

#tunnels[kind='path'],
#roads[kind='path'],
#bridges[kind='path'],
{
  line-color: @color_transport_path;

  [zoom>=15] {
    line-width: 0.5;
    line-cap: butt;
    line-dasharray: 2, 3;
  }

  [zoom>=16] {
    line-width: 0.7;
  }

  [zoom>=17] {
    line-width: 1.2;
    line-dasharray: 4, 6;
  }
}

.landcoverraster {
  raster-opacity:1;
  raster-scaling:gaussian;

  /* blur landcover as it becomes too pixelated */
/*
  [zoom>=10] {
    image-filters: agg-stack-blur(5,5);
  }
  [zoom>=12] {
    image-filters: agg-stack-blur(10,10);
    opacity: 0.8;
  }
  [zoom>=14] {
    image-filters: agg-stack-blur(20,20);
    opacity: 0.6;
  }
*/
}

@color_physical: #dee0be;
@color_physical_bright: #fff;
@color_water: #99b3cc;
@color_administrative_lowzoom: #000;
@color_administrative_dark: #000;
@color_administrative_bright: #fff;
@color_administrative_medium_low: #000;
@color_administrative_medium_high: #000;
@color_administrative_medium_high2: #000;
@color_transport: #999;
@color_transport_casing: #ddd;
@color_transport_inline: #fff;
@color_transport_tunnel: #ccc;
@color_transport_minor: #ccc;
@color_transport_rail: #aaa; // 35% K
@color_transport_path: #666; // 60% K
@color_building: #cdd;
@color_building_outline: darken(@color_building,20);
@color_building_outline_special: #00aeef;
@color_airport_runways: @color_transport;
@color_airport_runways_detail: darken(@color_airport_runways,20);
@color_green_areas: darken(#c0d3b5,20);

Map {
  background-color: @color_physical;
  font-directory: url("fonts/");
}

/**
 * "shore" is a general class for layers with continents, coastlines, lakes,
 * and other kinds of meeting points between water and land.
 */
.shore {
  line-color: @color_physical;
  /* lighten background color, as we decrease landcover opacity */
  [zoom>=12] {
    polygon-fill: lighten(@color_physical,20);
  }
  [zoom>=14] {
    polygon-fill: lighten(@color_physical,40);
  }

  line-cap: round;
  line-join: round;
  line-width: 0;
}

#ne_10m_rivers_lake_centerlines_scale_rank
{
  [zoom=4][scalerank<4] {
    line-color: @color_water;
    line-width: 0.5;
    [strokeweig>1] { line-width: 1; }
    [strokeweig>2] { line-width: 2; }
  }
  [zoom=5][scalerank<5] {
    line-color: @color_water;
    line-width: 0.5;
    [strokeweig>1] { line-width: 1; }
    [strokeweig>2] { line-width: 2; }
  }
  [zoom=6][scalerank<6] {
    line-color: @color_water;
    line-width: 0.5;
    [strokeweig>1] { line-width: 1; }
    [strokeweig>2] { line-width: 2; }
  }
  [zoom=7][scalerank<7] {
    line-color: @color_water;
    line-width: 1;
    [strokeweig>1] { line-width: 1.5; }
    [strokeweig>2] { line-width: 2.5; }
  }
  [zoom>=8] {
    line-width: 1;
    line-color: @color_water;
    [strokeweig>1] { line-width: 2; }
    [strokeweig>2] { line-width: 3; }
  }
}

#water,
#ne_10m_ocean,
#ne_10m_lakes,
#ne_50m_lakes
{
  //line-width: 0.5;
  line-color: @color_water;
  polygon-fill: @color_water;
}

.country-boundary[scalerank<6],
.country-boundary-10m[scalerank<6] {
  line-color: @color_administrative_dark;
  line-opacity: 0.2;
  line-width: 2;
  line-dasharray: 7,3;
  ::glow {
    line-color: @color_administrative_dark;
    line-opacity: 0.08;
    line-width: 4;
    line-dasharray: 7,3;
  }
}

#admin1-lines-10m,
#admin0-map-units-10m {
  [zoom>=4][adm0_a3='CAN'],
  [zoom>=4][adm0_a3='USA'],
  [zoom>=4][adm0_a3='AUS'],
  [zoom>=5][scalerank<=2],
  [zoom>=5][featurecla='Map unit boundary'][adm0_a3='GBR'],
  [zoom>=6][scalerank<=4],
  [zoom>=6][featurecla='Map unit boundary'][adm0_a3='GBR'] {
    line-color: @color_administrative_dark;
    line-opacity: 0.15;
    line-width: 1.5;
    line-dasharray: 7,3;
    ::glow {
      line-color: @color_administrative_dark;
      line-opacity: 0.05;
      line-width: 3;
      line-dasharray: 7,3;
    }
  }

  [zoom>=7][scalerank<=5] {
    line-width: 1;
    line-color: @color_administrative_medium_low;
    line-dasharray: 1,5;
    line-cap: round;
  }

  [zoom>=8][scalerank<=6] {
    line-width: 1.2;
    line-color: @color_administrative_medium_high;
    line-dasharray: 1,5;
    line-cap: round;
  }

  [zoom>=9][scalerank<=8] {
    line-width: 1.2;
    line-color: @color_administrative_medium_high2;
    line-dasharray: 1,5;
    line-cap: round;
  }
}

#lakes-50m[zoom<3][scalerank<1],
#lakes-50m[zoom=3][scalerank<2],
#lakes-50m[zoom=4][scalerank<3],
#lakes-50m[zoom=5][scalerank<5],
#lakes-50m[zoom=6],
#lakes-10m,
{
  line-width: 1;
  polygon-fill: @color_physical;
}

#ne-roads[zoom=7][scalerank<=4],
#ne-roads[zoom>=8][scalerank<=8] {
  ::casing {
    line-color: @color_transport_casing;
    line-opacity: 0.5;
    line-width: 1.5;

    [zoom=8][scalerank<=6] {
      line-width: 3;
    }
  }

  line-color: @color_transport;
  line-width: 0;

  [zoom=8][scalerank<=6] {
    line-width: 1;
  }
}

/**
 * Ocean, lake, and river polygons
 */
#water-bodies-low[zoom=8][area>50000000],
#water-bodies-low[zoom=9][area>10000000],
#water-bodies-low[zoom=10][area>2500000],
#water-bodies-med[zoom=11][area> 800000],
#water-bodies-med[zoom=12][area> 500000],
#water-bodies-med[zoom=13][area>  25000],
#water-bodies-high[zoom=14][area> 10000],
#water-bodies-high[zoom>=15]
{
  polygon-fill: @color_water;
}

/**
 * Water bodies that are parts of rivers
 * should never be filtered
 */
#water-bodies-low[type='riverbank'],
#water-bodies-med[type='riverbank'],
#water-bodies-high[type='riverbank']
{
  polygon-fill: @color_water;
}

#nullisland {
  polygon-fill: @color_physical;
}

#admin1-lines-osm,
{
  line-width: 2.0;
  line-color: @color_administrative_medium_high2;
  line-dasharray: 1,5;
  line-cap: round;
}

/**
 * Zoom 13 buildings.
 * Already filtered by size upon import.
 */
#buildings-med[type!='no'] {
  polygon-fill: @color_building;
  line-width: 0.5;
  line-color: @color_building_outline;
}

/**
 * Zoom 14+ buildings.
 * Includes all buildings.
 */
#buildings-high[type!='no'] {
  [zoom=14] {
    [area>=5000] {
      polygon-fill: @color_building;
      line-width: 0.5;
      line-color: @color_building_outline;
    }
  }

  /**
   * This is for outlines and no stripe. Catches small buildings.
   * Larger buildings will be overridden with stripes below.
   */
  [zoom>=15][area>=2000],
  [zoom>=16] {
    polygon-fill: @color_building;
    line-width: 0.5;
    line-color: @color_building_outline;
  }

  [zoom=15][area>=3000],
  [zoom=16][area>=2000],
  [zoom=17][area>=1000],
  [zoom>=18],
  {
    polygon-fill: @color_building;
    line-width: 0.5;
    line-color: @color_building_outline;
  }

  // Stamen HQ fancy candycane striping
  [zoom>=18] {
    [osm_id=260351411],
    [osm_id=224030635], // Seth's house
    [osm_id=248153467], // Sean's house
    [osm_id=291796473], // Stamen South
    {
      polygon-fill: @color_building;
      line-width: 1.5;
      line-color: @color_building_outline_special;
    }
  }
}

#green-areas-low[zoom=10][area>5000000],
#green-areas-med[zoom=11][area>1000000],
#green-areas-med[zoom=12][area> 500000],
#green-areas-med[zoom=12][area> 200000],
#green-areas-med[zoom=13][area>  75000],
#green-areas-high[zoom=14][area> 10000],
#green-areas-high[zoom>14],
{
  polygon-fill: @color_green_areas;
  polygon-opacity: 0.5;

  [type='nature_reserve'] {
    polygon-fill: @color_green_areas;
    polygon-opacity: 0.3;
  }
}

#aeroways {
  line-color: @color_airport_runways;
  line-cap: square;
  line-join: miter;

  [zoom>=15] {
    line-color: @color_airport_runways_detail;
  }

  [type='runway'] {
    [zoom=12] {
      line-width: 2;
    }

    [zoom=13] {
      line-width: 4;
    }

    [zoom=14] {
      line-width: 8;
    }

    [zoom=15] {
      line-width: 16;
    }

    [zoom=16] {
      line-width: 32;
    }

    [zoom=17] {
      line-width: 64;
    }

    [zoom>=18] {
      line-width: 128;
    }
  }

  [type='taxiway'] {
    [zoom=13] {
      line-width: 1;
    }

    [zoom=14] {
      line-width: 2;
    }

    [zoom=15] {
      line-width: 4;
    }

    [zoom=16] {
      line-width: 8;
    }

    [zoom=17] {
      line-width: 16;
    }

    [zoom>=18] {
      line-width: 32;
    }
  }
}

#tunnels,
#roads,
#roads_med,
#highways_med,
#bridges {
  ::casing,
  ::outline,
  {
    line-cap: butt;
    line-width: 0;
    line-color: @color_transport_casing;
  }

  line-join: round;
  line-cap: round;
  line-width: 1;
  line-color: @color_transport;
}

#tunnels {
  [zoom>=14] {
    ::outline
    {
      line-opacity: 0.7;
      line-color: @color_transport_tunnel;
    }

    line-opacity: 0.5;
    line-width: 4;
  }
}

#tunnels[kind='highway'] {
  [zoom>=15] {
    ::outline {
      line-width: 5.5;
    }

    line-width: 4;
  }

  [zoom>=16] {
    ::outline {
      line-width: 7;
      line-opacity: 0.4;
    }

    line-opacity: 0.7;
    line-color: @color_transport_tunnel;

    [is_link='yes'] {
      ::outline {
        line-color: @color_transport_casing;
      }
    }
  }

  [zoom>=17] {
    ::outline {
      line-width: 18;
    }

    line-width: 12;

    [is_link='yes'] {
      ::outline {
        line-width: 9;
      }
    }
  }

  [zoom>=18] {
    ::outline {
      line-width: 22;
      line-color: @color_transport;
    }

    line-width: 18;
    line-color: @color_transport_inline;
  }

  [zoom>=19] {
    ::outline {
      line-width: 30;
    }

    line-width: 26;

    [is_link='yes'] {
      ::outline {
        line-width: 13;
      }
    }
  }
}

#tunnels[kind='major_road'] {
  [zoom>=15] {
    ::outline {
      line-width: 5;
      line-opacity: 0.7;
      line-color: @color_transport_tunnel;
    }

    line-width: 3;
    line-opacity: 0.5;
  }

  [zoom>=16] {
    ::outline {
      line-width: 7;
      line-opacity: 0.4;
    }

    line-opacity: 0.7;
    line-color: @color_transport_tunnel;

    [is_link='yes'] {
      ::outline {
        line-color: @color_transport_casing;
      }
    }
  }

  [zoom>=17] {
    ::outline {
      line-width: 18;
    }

    line-width: 12;

    [is_link='yes'] {
      ::outline {
        line-width: 9;
      }
    }
  }

  [zoom>=18] {
    ::outline {
      line-width: 22;
    }

    line-width: 18;
  }

  [zoom>=19] {
    ::outline {
      line-width: 30;
    }

    line-width: 26;

    [is_link='yes'] {
      ::outline {
        line-width: 13;
      }
    }
  }
}

#tunnels[kind='minor_road'] {
  [zoom>=15] {
    ::outline {
      line-opacity: 0.7;
      line-color: @color_transport_tunnel;
    }

    line-color: @color_transport_minor;
    line-width: 1.5;
    line-opacity: 0.5;
  }

  [zoom>=16] {
    ::outline {
      line-width: 7;
    }

    line-width: 4;
    line-color: @color_transport;
  }

  [zoom>=17] {
    ::outline {
      line-width: 9;
    }

    line-width: 7;
  }

  [zoom>=18] {
    ::outline {
      line-width: 17;
      line-color: @color_transport;
    }

    line-width: 13;
    line-color: @color_transport_casing;
  }

  [zoom>=19] {
    ::outline {
      line-width: 20;
    }

    line-width: 16;
  }
}

#bridges[kind='highway'] {
  [zoom>=13] {
    ::outline {
      line-width: 8;
    }

    line-width: 4;

    [is_link='yes'] {
      ::outline {
        line-width: 0;
      }

      line-width: 1;
    }
  }

  [zoom>=14] {
    ::outline {
      line-width: 8;
    }

    line-width: 4;

    [is_link='yes'] {
      ::outline {
        line-width: 4;
      }

      line-width: 2.5;
    }
  }

  [zoom>=15] {
    ::outline {
      line-width: 11;
    }

    line-width: 6;

    [is_link='yes'] {
      ::outline {
        line-width: 5.5;
      }

      line-width: 2.5;
    }
  }

  [zoom>=16] {
    ::outline {
      line-width: 14;
    }

    line-width: 9;

    [is_link='yes'] {
      ::outline {
        line-width: 7;
      }

      line-width: 2.5;
    }
  }

  [zoom>=17] {
    ::outline {
      line-width: 20;
    }

    line-width: 15;

    [is_link='yes'] {
      ::outline {
        line-width: 9;
      }

      line-width: 5;
    }
  }

  [zoom>=18] {
    ::outline {
      line-width: 44;
      line-color: @color_transport;
    }

    line-width: 28;
    line-color: @color_transport_inline;

    [is_link='yes'] {
      ::outline {
        line-width: 22;
      }

      line-width: 18;
    }
  }

  [zoom>=19] {
    ::outline {
      line-width: 51;
    }

    line-width: 35;

    [is_link='yes'] {
      ::outline {
        line-width: 21;
      }

      line-width: 16;
    }
  }
}

#bridges[kind='major_road'] {
  line-color: @color_transport;

  [zoom>=14] {
    ::outline {
      line-width: 5;
    }

    line-width: 1.9;
  }

  [zoom>=15] {
    ::outline {
      line-width: 8.5;
    }

    line-width: 5.5;

    [is_link='yes'] {
      ::outline {
        line-width: 5.5;
      }

      line-width: 2.5;
    }
  }

  [zoom>=16] {
    ::outline {
      line-width: 11;
    }

    line-width: 7;

    [is_link='yes'] {
      ::outline {
        line-width: 7;
      }

      line-width: 2.5;
    }
  }

  [zoom>=17] {
    ::outline {
      line-width: 18;
    }

    line-width: 12;

    [is_link='yes'] {
      ::outline {
        line-width: 8;
      }

      line-width: 4;
    }
  }

  [zoom>=18] {
    ::outline {
      line-width: 24;
      line-color: @color_transport;
    }

    line-width: 18;
    line-color: @color_transport_inline;

    [is_link='yes'] {
      ::outline {
        line-width: 14;
      }

      line-width: 9;
    }
  }

  [zoom>=19] {
    ::outline {
      line-width: 32;
    }

    line-width: 26;

    [is_link='yes'] {
      ::outline {
        line-width: 18;
      }

      line-width: 13;
    }
  }
}

#roads,
#roads_med,
#highways_med {
  ::casing,
  ::outline,
  {
    line-cap: butt;
    line-width: 0;
    line-color: @color_transport_casing;
  }

  line-join: round;
  line-cap: round;
  line-width: 0;
  line-color: @color_transport;

  [is_link='yes']
  {
    [zoom>=16]
    {
      ::casing {
        line-width: 8;
      }

      line-width: 4;
    }
  }
}

#roads[kind='highway'],
#highways_med[kind='highway']
{
  [zoom>=9] {
    ::outline {
      line-width: 4.25;
    }

    line-width: 1.5;
  }

  [zoom>=10] {
    ::outline {
      line-width: 5;
    }

    line-width: 2;
  }

  [zoom>=11] {
    ::outline {
      line-width: 6;
    }

    line-width: 2.5;
  }

  [zoom>=12] {
    ::outline {
      line-width: 7;
    }

    line-width: 3;

    [is_link='yes'] {
      ::outline {
        line-width: 0;
      }

      line-width: 0.5;
    }
  }

  [zoom>=13] {
    ::outline {
      line-width: 8;
    }

    [is_link='yes'] {
      ::outline {
        line-width: 0;
      }

      line-width: 1;
    }
  }

  [zoom>=14] {
    ::outline {
      line-width: 9;
    }

    line-width: 4;

    [is_link='yes'] {
      ::outline {
        line-width: 4;
      }

      line-width: 2.5;
    }
  }

  [zoom>=15] {
    ::casing {
      line-width: 11;
    }

    line-width: 6;

    [is_link='yes'] {
      ::casing {
        line-width: 6.5;
      }

      line-width: 2.25;
    }
  }

  [zoom>=16] {
    ::casing {
      line-width: 14;
    }

    line-width: 9;

    [is_link='yes'] {
      ::casing {
        line-width: 7;
      }

      line-width: 2.5;
    }
  }

  [zoom>=17] {
    ::casing {
      line-width: 24;
    }

    line-width: 15;

    [is_link='yes'] {
      ::casing {
        line-width: 9;
      }

      line-width: 5;
    }
  }

  [zoom>=18] {
    line-width: 28;

    [is_link='yes'] {
      ::casing {
        line-width: 14;
      }

      line-width: 10;
    }
  }

  [zoom>=19] {
    ::casing {
      line-width: 49;
    }

    line-width: 35;

    [is_link='yes'] {
      ::casing {
        line-width: 20;
      }

      line-width: 16;
    }
  }
}

#roads[kind='major_road'],
#roads_med[kind='major_road']
{
  [zoom<=12] {
    line-color: @color_transport;
  }

  [zoom>=9] {
    line-width: 0.15;
  }

  [zoom>=10] {
    line-width: 0.5;
  }

  [zoom>=11] {
    ::outline {
      line-width: 1.25;
    }

    line-width: 0.7;
  }

  [zoom>=12] {
    ::outline {
      line-width: 5;
    }

    line-width: 1;

    [is_link='yes'] {
      ::outline {
        line-width: 0;
      }

      line-width: 0.5;
    }
  }

  [zoom>=13] {
    line-width: 1.5;
  }

  [zoom>=14] {
    ::outline {
      line-width: 5;
    }

    line-width: 1.9;

    [is_link='yes'] {
      ::outline {
        line-width: 5;
      }

      line-width: 1.9;
    }
  }

  [zoom>=15] {
    ::casing {
      line-width: 8;
    }

    line-width: 5;

    [is_link='yes'] {
      ::casing {
        line-width: 5.5;
      }

      line-width: 2.25;
    }
  }

  [zoom>=16] {
    ::casing {
      line-width: 11;
    }

    line-width: 7;

    [is_link='yes'] {
      ::casing {
        line-width: 7;
      }

      line-width: 2.5;
    }
  }

  [zoom>=17] {
    line-width: 12;

    [is_link='yes'] {
      line-width: 4;
    }
  }

  [zoom>=18] {
    line-width: 18;

    [is_link='yes'] {
      line-width: 9;
    }
  }

  [zoom>=19] {
    ::casing {
      line-width: 30;
    }

    line-width: 26;

    [is_link='yes'] {
      ::casing {
        line-width: 17;
      }

      line-width: 13;
    }
  }
}

#roads[kind='minor_road'],
#roads_med[kind='minor_road']
{
  line-color: @color_transport_minor;

  [zoom>=10] {
    line-width: 0.2;
  }

  [zoom>=13] {
    line-width: 0.4;
  }

  [zoom>=14] {
    line-width: 0.8;
  }

  [zoom>=15] {
    line-width: 1.5;
  }

  [zoom>=16] {
    line-width: 4;
    line-color: @color_transport;
  }

  [zoom>=17] {
    line-width: 7;
  }

  [zoom>=18] {
    line-width: 13;
  }

  // [zoom>=19] {
  //   ::casing {
  //     line-width: 20;
  //   }

  //   line-width: 16;
  // }
}

#tunnels[kind='rail'],
#roads[kind='rail'],
#bridges[kind='rail']
{
  ::casing,
  ::outline,
  {
    line-color: @color_transport_rail;
  }

  line-color: @color_transport_rail;

  [zoom>=14] {
    ::casing {
      line-width: 3;
      line-dasharray: 1,3;
    }

    line-width: 1;
  }

  [zoom>=16] {
    ::casing {
      line-width: 5;
      line-dasharray: 1,4;
    }
  }

  [zoom>=18] {
    ::casing {
      line-width: 6;
      line-dasharray: 2,6;
    }

    line-width: 2;
  }

  [zoom>=19] {
    line-width: 4;
  }
}

#tunnels[highway='service'],
#roads[highway='service'],
#bridges[highway='service'],
{
  [zoom>=15]
  {
    line-width: 1.5;
  }

  [zoom>=16] {
    ::casing {
      line-width: 4;
    }

    line-width: 2;
  }

  [zoom>=17] {
    line-width: 4;
  }
}

#tunnels[kind='path'],
#roads[kind='path'],
#bridges[kind='path'],
{
  line-color: @color_transport_path;

  [zoom>=15] {
    line-width: 0.5;
    line-cap: butt;
    line-dasharray: 2, 3;
  }

  [zoom>=16] {
    line-width: 0.7;
  }

  [zoom>=17] {
    line-width: 1.2;
    line-dasharray: 4, 6;
  }
}

.landcoverraster {
  raster-opacity:1;
  raster-scaling:gaussian;

  /* blur landcover as it becomes too pixelated */
/*
  [zoom>=10] {
    image-filters: agg-stack-blur(5,5);
  }
  [zoom>=12] {
    image-filters: agg-stack-blur(10,10);
    opacity: 0.8;
  }
  [zoom>=14] {
    image-filters: agg-stack-blur(20,20);
    opacity: 0.6;
  }
*/
}


Update palette.mss

Update palette.mss

/* ****************************************************************** */
/* OSM BRIGHT for Imposm                                              */
/* ****************************************************************** */

/* For basic style customization you can simply edit the colors and
 * fonts defined in this file. For more detailed / advanced
 * adjustments explore the other files.
 *
 * GENERAL NOTES
 *
 * There is a slight performance cost in rendering line-caps.  An
 * effort has been made to restrict line-cap definitions to styles
 * where the results will be visible (lines at least 2 pixels thick).
 */

/* ================================================================== */
/* FONTS
/* ================================================================== */

/* directory to load fonts from in addition to the system directories */
Map { font-directory: url(./fonts); }

/* set up font sets for various weights and styles */
@sans_lt:           "Open Sans Regular","DejaVu Sans Book","unifont Medium";
@sans_lt_italic:    "Open Sans Italic","DejaVu Sans Italic","unifont Medium";
@sans:              "Open Sans Semibold","DejaVu Sans Book","unifont Medium";
@sans_italic:       "Open Sans Semibold Italic","DejaVu Sans Italic","unifont Medium";
@sans_bold:         "Open Sans Bold","DejaVu Sans Bold","unifont Medium";
@sans_bold_italic:  "Open Sans Bold Italic","DejaVu Sans Bold Italic","unifont Medium";

/* Some fonts are larger or smaller than others. Use this variable to
   globally increase or decrease the font sizes. */
/* Note this is only implemented for certain things so far */
@text_adjust: 0;

/* ================================================================== */
/* COLOR PALETTE
/* ================================================================== */

@black: #000000;
@white: #ffffff;

@grey-light: #cccccc;
@grey-medium: #999999;
@grey-strong:  #777777;

@orange: #FF6600;

@blue: #0000ff;

@yellow:  #ffff33;
@yellow-light: #ffff99;

@green: #006600;
@green-light: #D7EFD9;

@purple: #9164CD;
@pink: #FFB4E6;

@path: #D7EFD9;

/* ================================================================== */
/* LANDUSE & LANDCOVER COLORS
/* ================================================================== */

@land:              @green-light;
@water:             @blue;
@grass:             @green;
@beach:             @yellow;
@park:              @green;
@cemetery:          @grey-light;
@wooded:            @green;
@agriculture:      @green-light;

@building:          @grey-strong;
@hospital:          @grey-light;
@school:            @grey-light;
@sports:           @grey-light;

@residential:       @grey-light;
@commercial:       @grey-light;
@industrial:        @grey-light;
@parking:          @grey-light;

/* ================================================================== */
/* ROAD COLORS
/* ================================================================== */

/* For each class of road there are three color variables:
 * - line: for lower zoomlevels when the road is represented by a
 *         single solid line.
 * - case: for higher zoomlevels, this color is for the road's
 *         casing (outline).
 * - fill: for higher zoomlevels, this color is for the road's
 *         inner fill (inline).
 */

@motorway_line:     @white;
@motorway_fill:      @white;
@motorway_case:      @white;

@trunk_line:        @white;
@trunk_fill:         @white;
@trunk_case:         @white;

@primary_line:      @white;
@primary_fill:       @white;
@primary_case:       @white;

@secondary_line:    @white;
@secondary_fill:     @white;
@secondary_case:    @white;

@standard_line:     @white;
@standard_fill:     @white;
@standard_case:      @white;

@pedestrian_line:   @purple;
@pedestrian_fill:  @purple;
@pedestrian_case:  @purple;

@cycle_line:        @purple;
@cycle_fill:        @purple;
@cycle_case:        @purple;

@rail_line:         @black;
@rail_fill:         @black;
@rail_case:         @black;

@aeroway:           @black;

/* ================================================================== */
/* BOUNDARY COLORS
/* ================================================================== */

@admin_2:           @purple;

/* ================================================================== */
/* LABEL COLORS
/* ================================================================== */

/* We set up a default halo color for places so you can edit them all
   at once or override each individually. */
@place_halo:        fadeout(#fff,0%);

@country_text:      @black;
@country_halo:      @place_halo;

@state_text:        @black;
@state_halo:        @place_halo;

@city_text:         @black;
@city_halo:         @place_halo;

@town_text:         @black;
@town_halo:         @place_halo;

@poi_text:          @black;

@road_text:         @black;
@road_halo:         @place_halo;

@other_text:        @black;
@other_halo:        @place_halo;

@locality_text:     @black;
@locality_halo:     @land;

/* Also used for other small places: hamlets, suburbs, localities */
@village_text:      @black;
@village_halo:      @place_halo;

/* ****************************************************************** */

/* ****************************************************************** */
/* OSM BRIGHT for Imposm                                              */
/* ****************************************************************** */

/* For basic style customization you can simply edit the colors and
 * fonts defined in this file. For more detailed / advanced
 * adjustments explore the other files.
 *
 * GENERAL NOTES
 *
 * There is a slight performance cost in rendering line-caps.  An
 * effort has been made to restrict line-cap definitions to styles
 * where the results will be visible (lines at least 2 pixels thick).
 */

/* ================================================================== */
/* FONTS
/* ================================================================== */

/* directory to load fonts from in addition to the system directories */
Map { font-directory: url(./fonts); }

/* set up font sets for various weights and styles */
@sans_lt:           "Open Sans Regular","DejaVu Sans Book","unifont Medium";
@sans_lt_italic:    "Open Sans Italic","DejaVu Sans Italic","unifont Medium";
@sans:              "Open Sans Semibold","DejaVu Sans Book","unifont Medium";
@sans_italic:       "Open Sans Semibold Italic","DejaVu Sans Italic","unifont Medium";
@sans_bold:         "Open Sans Bold","DejaVu Sans Bold","unifont Medium";
@sans_bold_italic:  "Open Sans Bold Italic","DejaVu Sans Bold Italic","unifont Medium";

/* Some fonts are larger or smaller than others. Use this variable to
   globally increase or decrease the font sizes. */
/* Note this is only implemented for certain things so far */
@text_adjust: 0;

/* ================================================================== */
/* COLOR PALETTE
/* ================================================================== */

@black: #000000;
@white: #ffffff;

@grey-light: #cccccc;
@grey-medium: #999999;
@grey-strong:  #777777;

@orange: #FF6600;

@blue: #0000ff;

@yellow:  #ffff33;
@yellow-light: #ffff99;

@green: #006600;
@green-light: #D7EFD9;

@purple: #9164CD;
@pink: #FFB4E6;

@brown: #D7EFD9;

/* ================================================================== */
/* LANDUSE & LANDCOVER COLORS
/* ================================================================== */

@land:              @green-light;
@water:             @blue;
@grass:             @green;
@beach:             @yellow;
@park:              @green;
@cemetery:          @grey-light;
@wooded:            @green;
@agriculture:      @green-light;

@building:          @grey-strong;
@hospital:          @grey-light;
@school:            @grey-light;
@sports:           @grey-light;

@residential:       @grey-light;
@commercial:       @grey-light;
@industrial:        @grey-light;
@parking:          @grey-light;

/* ================================================================== */
/* ROAD COLORS
/* ================================================================== */

/* For each class of road there are three color variables:
 * - line: for lower zoomlevels when the road is represented by a
 *         single solid line.
 * - case: for higher zoomlevels, this color is for the road's
 *         casing (outline).
 * - fill: for higher zoomlevels, this color is for the road's
 *         inner fill (inline).
 */

@motorway_line:     @white;
@motorway_fill:      @white;
@motorway_case:      @white;

@trunk_line:        @white;
@trunk_fill:         @white;
@trunk_case:         @white;

@primary_line:      @white;
@primary_fill:       @white;
@primary_case:       @white;

@secondary_line:    @white;
@secondary_fill:     @white;
@secondary_case:    @white;

@standard_line:     @white;
@standard_fill:     @white;
@standard_case:      @white;

@pedestrian_line:   @purple;
@pedestrian_fill:  @purple;
@pedestrian_case:  @purple;

@cycle_line:        @purple;
@cycle_fill:        @purple;
@cycle_case:        @purple;

@rail_line:         @black;
@rail_fill:         @black;
@rail_case:         @black;

@aeroway:           @black;

/* ================================================================== */
/* BOUNDARY COLORS
/* ================================================================== */

@admin_2:           @purple;

/* ================================================================== */
/* LABEL COLORS
/* ================================================================== */

/* We set up a default halo color for places so you can edit them all
   at once or override each individually. */
@place_halo:        fadeout(#fff,0%);

@country_text:      @black;
@country_halo:      @place_halo;

@state_text:        @black;
@state_halo:        @place_halo;

@city_text:         @black;
@city_halo:         @place_halo;

@town_text:         @black;
@town_halo:         @place_halo;

@poi_text:          @black;

@road_text:         @black;
@road_halo:         @place_halo;

@other_text:        @black;
@other_halo:        @place_halo;

@locality_text:     @black;
@locality_halo:     @land;

/* Also used for other small places: hamlets, suburbs, localities */
@village_text:      @black;
@village_halo:      @place_halo;

/* ****************************************************************** */


large area labels abstracting values

large area labels abstracting values

/*
==Database level==
* join adjacent way segments with same classification and name
  for labels layer and increase text-spacing so labels aren't
  repeated right next to each other

* optimise queries as to select just what is required for rendering

* select way area so can style bay names larger for larger bays

==Style level==
* ShieldSymbolizers for POIs with names at high zooms (eg police station
  icon with name)
*/

/*
  Large labeled areas such as park, golf courses and schools.

  These labels are shown at z15-17, before we see POI features.

  We use the way_area to show labels for larger areas from lower zooms.

  By placing a point-file below all the text-* attributes mapnik will
  render a marker icon if it decides it can't fit the text due to other labels
  in the way.
*/

@school_label_halo_colour: #241600;
@park_label_halo_colour: #0e300e;

@area_label_opacity: 1.0;
@area_label_halo_radius: 2.0;

/**  Parks  **/

/* only show from z15+ where area > 30,000 */
#park-labels[zoom > 14][way_area > 30000] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Regular";
  text-fill: white;
  text-placement: interior;
  text-halo-fill: @park_label_halo_colour;
  text-halo-radius: @area_label_halo_radius;
  text-wrap-width: 20;
  text-opacity: @area_label_opacity;

  [zoom > 21] { text-size: 30; }
  [zoom = 21] { text-size: 25; }
  [zoom = 20] { text-size: 20; }
  [zoom = 19] { text-size: 15; }
  [zoom = 18] { text-size: 13; }
  [zoom = 17] { text-size: 12; }
  [zoom = 16] { text-size: 11; }
  [zoom = 15] { text-size: 11; }
}

/* start showing on z16+ on area > 10,000 */
#park-labels[zoom > 15][way_area >= 10000][way_area < 30000] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Regular";
  text-fill: white;
  text-placement: interior;
  text-halo-fill: @park_label_halo_colour;
  text-halo-radius: @area_label_halo_radius;
  text-wrap-width: 20;
  text-opacity: @area_label_opacity;

  [zoom > 21] { text-size: 30; }
  [zoom = 21] { text-size: 25; }
  [zoom = 20] { text-size: 20; }
  [zoom = 19] { text-size: 15; }
  [zoom = 18] { text-size: 13; }
  [zoom = 17] { text-size: 12; }
  [zoom = 16] { text-size: 11; }
  [zoom = 15] { text-size: 11; }
}

/* show the rest from z17+ */
#park-labels[zoom > 16][way_area < 10000] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Regular";
  text-fill: white;
  text-placement: interior;
  text-halo-fill: @park_label_halo_colour;
  text-halo-radius: @area_label_halo_radius;
  text-wrap-width: 20;
  text-opacity: @area_label_opacity;

  [zoom > 21] { text-size: 30; }
  [zoom = 21] { text-size: 25; }
  [zoom = 20] { text-size: 20; }
  [zoom = 19] { text-size: 15; }
  [zoom = 18] { text-size: 13; }
  [zoom = 17] { text-size: 12; }
  [zoom = 16] { text-size: 11; }
  [zoom = 15] { text-size: 11; }
}

/**  Golf Courses  **/

/* since most are large, just render all labels from zoom 15+ */
#leisure[leisure='golf_course'][zoom > 14] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Regular";
  text-fill: white;
  text-placement: interior;
  text-halo-fill: #021402;
  text-halo-radius: @area_label_halo_radius;
  text-wrap-width: 50;
  text-opacity: @area_label_opacity;

  [zoom > 21] { text-size: 30; }
  [zoom = 21] { text-size: 25; }
  [zoom = 20] { text-size: 20; }
  [zoom = 19] { text-size: 15; }
  [zoom = 18] { text-size: 13; }
  [zoom = 17] { text-size: 12; }
  [zoom = 16] { text-size: 11; }
  [zoom = 15] { text-size: 11; }

  /* if mapnik can't place a label, try an icon instead */
  point-file: url('/usr/share/icons/sjjb/png/sport/golf.glow.000000.12.png');
}

/**  Schools  **/

/* only show from z15+ where area > 30,000 */
#school-labels[zoom > 14][way_area > 30000] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Regular";
  text-fill: white;
  text-placement: interior;
  text-halo-fill: @school_label_halo_colour;
  text-halo-radius: @area_label_halo_radius;
  text-wrap-width: 30;
  text-opacity: @area_label_opacity;

  [zoom > 21] { text-size: 30; }
  [zoom = 21] { text-size: 25; }
  [zoom = 20] { text-size: 20; }
  [zoom = 19] { text-size: 15; }
  [zoom = 18] { text-size: 13; }
  [zoom = 17] { text-size: 12; }
  [zoom = 16] { text-size: 11; }
  [zoom = 15] { text-size: 11; }

  /* if mapnik can't place a label, try an icon instead */
  point-file: url('/usr/share/icons/sjjb/png/education/school.glow.734A08.12.png');
}

/* start showing on z16+ on area > 10,000 */
#school-labels[zoom > 15][way_area >= 10000][way_area < 30000] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Regular";
  text-fill: white;
  text-placement: interior;
  text-halo-fill: @school_label_halo_colour;
  text-halo-radius: @area_label_halo_radius;
  text-wrap-width: 20;
  text-opacity: @area_label_opacity;

  [zoom > 21] { text-size: 30; }
  [zoom = 21] { text-size: 25; }
  [zoom = 20] { text-size: 20; }
  [zoom = 19] { text-size: 15; }
  [zoom = 18] { text-size: 13; }
  [zoom = 17] { text-size: 12; }
  [zoom = 16] { text-size: 11; }
  [zoom = 15] { text-size: 11; }

  point-file: url('/usr/share/icons/sjjb/png/education/school.glow.734A08.16.png');
}

/* show the rest from z17+ */
#school-labels[zoom > 16][way_area < 10000] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Regular";
  text-fill: white;
  text-placement: interior;
  text-halo-fill: @school_label_halo_colour;
  text-halo-radius: @area_label_halo_radius;
  text-wrap-width: 20;
  text-opacity: @area_label_opacity;

  [zoom > 21] { text-size: 30; }
  [zoom = 21] { text-size: 25; }
  [zoom = 20] { text-size: 20; }
  [zoom = 19] { text-size: 15; }
  [zoom = 18] { text-size: 13; }
  [zoom = 17] { text-size: 12; }
  [zoom = 16] { text-size: 11; }
  [zoom = 15] { text-size: 11; }

  point-file: url('/usr/share/icons/sjjb/png/education/school.glow.734A08.20.png');
}

/* building names */
#building-label[zoom > 16] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Regular";
  text-fill: white;
  text-placement: interior;
  text-halo-fill: black;
  text-halo-radius: 2.0;
  text-wrap-width: 20;

  [zoom > 21] { text-size: 17; }
  [zoom = 21] { text-size: 16; }
  [zoom = 20] { text-size: 15; }
  [zoom = 19] { text-size: 14; }
  [zoom = 18] { text-size: 12; }
  [zoom = 17] { text-size: 10; }
}

/*
  Miscellaneous items
  */

/* ferry routes */
#ferry-route[zoom > 6][zoom < 12] {
  line-color: white;
  line-width: 0.7;
  line-opacity: 0.5;
}

#ferry-route[zoom > 11] {
  line-color: #00066f;
  line-dasharray: 6,6;

  [zoom = 12] { line-width: 0.8; }
  [zoom = 13] { line-width: 1.0; }
  [zoom = 14] { line-width: 1.3; }
  [zoom = 15] { line-width: 1.6; }
  [zoom > 15] { line-width: 2.0; }

  ::halo{
    line-color: white;
    line-width: 1.0;
    line-opacity: 0.5;

    [zoom = 13] { line-width: 1.2; }
    [zoom = 14] { line-width: 1.5; }
    [zoom = 15] { line-width: 1.8; }
    [zoom > 15] { line-width: 2.2; }
  }
}

#landuse[landuse='military'][zoom > 10] {
  ::outline {
    line-color: #f55000;
    line-width: 3;
    line-opacity: 0.329;
  }

  polygon-pattern-file: url('/usr/share/icons/osmt/military-pattern.png');
}

/*
==Database level==
* join adjacent way segments with same classification and name
  for labels layer and increase text-spacing so labels aren't
  repeated right next to each other

* optimise queries as to select just what is required for rendering

* select way area so can style bay names larger for larger bays

==Style level==
* ShieldSymbolizers for POIs with names at high zooms (eg police station
  icon with name)
*/

/*
  Large labeled areas such as park, golf courses and schools.

  These labels are shown at z15-17, before we see POI features.

  We use the way_area to show labels for larger areas from lower zooms.

  By placing a point-file below all the text-* attributes mapnik will
  render a marker icon if it decides it can't fit the text due to other labels
  in the way.
*/

@school_label_halo_colour: #342101;
@park_label_halo_colour: #0e300e;

/**  Parks  **/

/* only show from z15+ where area > 30,000 */
#park-labels[zoom > 14][way_area > 30000] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Regular";
  text-fill: white;
  text-placement: interior;
  text-halo-fill: @park_label_halo_colour;
  text-halo-radius: 2.0;
  text-wrap-width: 20;
  text-opacity: 0.75;

  [zoom > 21] { text-size: 30; }
  [zoom = 21] { text-size: 25; }
  [zoom = 20] { text-size: 20; }
  [zoom = 19] { text-size: 15; }
  [zoom = 18] { text-size: 13; }
  [zoom = 17] { text-size: 12; }
  [zoom = 16] { text-size: 11; }
  [zoom = 15] { text-size: 11; }
}

/* start showing on z16+ on area > 10,000 */
#park-labels[zoom > 15][way_area >= 10000][way_area < 30000] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Regular";
  text-fill: white;
  text-placement: interior;
  text-halo-fill: @park_label_halo_colour;
  text-halo-radius: 2.0;
  text-wrap-width: 20;
  text-opacity: 0.75;

  [zoom > 21] { text-size: 30; }
  [zoom = 21] { text-size: 25; }
  [zoom = 20] { text-size: 20; }
  [zoom = 19] { text-size: 15; }
  [zoom = 18] { text-size: 13; }
  [zoom = 17] { text-size: 12; }
  [zoom = 16] { text-size: 11; }
  [zoom = 15] { text-size: 11; }
}

/* show the rest from z17+ */
#park-labels[zoom > 16][way_area < 10000] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Regular";
  text-fill: white;
  text-placement: interior;
  text-halo-fill: @park_label_halo_colour;
  text-halo-radius: 2.0;
  text-wrap-width: 20;
  text-opacity: 0.75;

  [zoom > 21] { text-size: 30; }
  [zoom = 21] { text-size: 25; }
  [zoom = 20] { text-size: 20; }
  [zoom = 19] { text-size: 15; }
  [zoom = 18] { text-size: 13; }
  [zoom = 17] { text-size: 12; }
  [zoom = 16] { text-size: 11; }
  [zoom = 15] { text-size: 11; }
}

/**  Golf Courses  **/

/* since most are large, just render all labels from zoom 15+ */
#leisure[leisure='golf_course'][zoom > 14] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Regular";
  text-fill: white;
  text-placement: interior;
  text-halo-fill: #021402;
  text-halo-radius: 2.0;
  text-wrap-width: 50;
  text-opacity: 0.75;

  [zoom > 21] { text-size: 30; }
  [zoom = 21] { text-size: 25; }
  [zoom = 20] { text-size: 20; }
  [zoom = 19] { text-size: 15; }
  [zoom = 18] { text-size: 13; }
  [zoom = 17] { text-size: 12; }
  [zoom = 16] { text-size: 11; }
  [zoom = 15] { text-size: 11; }

  /* if mapnik can't place a label, try an icon instead */
  point-file: url('/usr/share/icons/sjjb/png/sport/golf.glow.000000.12.png');
}

/**  Schools  **/

/* only show from z15+ where area > 30,000 */
#school-labels[zoom > 14][way_area > 30000] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Regular";
  text-fill: white;
  text-placement: interior;
  text-halo-fill: @school_label_halo_colour;
  text-halo-radius: 2.0;
  text-wrap-width: 20;
  text-opacity: 0.75;

  [zoom > 21] { text-size: 30; }
  [zoom = 21] { text-size: 25; }
  [zoom = 20] { text-size: 20; }
  [zoom = 19] { text-size: 15; }
  [zoom = 18] { text-size: 13; }
  [zoom = 17] { text-size: 12; }
  [zoom = 16] { text-size: 11; }
  [zoom = 15] { text-size: 11; }

  /* if mapnik can't place a label, try an icon instead */
  point-file: url('/usr/share/icons/sjjb/png/education/school.glow.734A08.12.png');
}

/* start showing on z16+ on area > 10,000 */
#school-labels[zoom > 15][way_area >= 10000][way_area < 30000] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Regular";
  text-fill: white;
  text-placement: interior;
  text-halo-fill: @school_label_halo_colour;
  text-halo-radius: 2.0;
  text-wrap-width: 20;
  text-opacity: 0.75;

  [zoom > 21] { text-size: 30; }
  [zoom = 21] { text-size: 25; }
  [zoom = 20] { text-size: 20; }
  [zoom = 19] { text-size: 15; }
  [zoom = 18] { text-size: 13; }
  [zoom = 17] { text-size: 12; }
  [zoom = 16] { text-size: 11; }
  [zoom = 15] { text-size: 11; }

  point-file: url('/usr/share/icons/sjjb/png/education/school.glow.734A08.16.png');
}

/* show the rest from z17+ */
#school-labels[zoom > 16][way_area < 10000] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Regular";
  text-fill: white;
  text-placement: interior;
  text-halo-fill: @school_label_halo_colour;
  text-halo-radius: 2.0;
  text-wrap-width: 20;
  text-opacity: 0.75;

  [zoom > 21] { text-size: 30; }
  [zoom = 21] { text-size: 25; }
  [zoom = 20] { text-size: 20; }
  [zoom = 19] { text-size: 15; }
  [zoom = 18] { text-size: 13; }
  [zoom = 17] { text-size: 12; }
  [zoom = 16] { text-size: 11; }
  [zoom = 15] { text-size: 11; }

  point-file: url('/usr/share/icons/sjjb/png/education/school.glow.734A08.20.png');
}

/* building names */
#building-label[zoom > 16] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Regular";
  text-fill: white;
  text-placement: interior;
  text-halo-fill: black;
  text-halo-radius: 2.0;
  text-wrap-width: 20;

  [zoom > 21] { text-size: 17; }
  [zoom = 21] { text-size: 16; }
  [zoom = 20] { text-size: 15; }
  [zoom = 19] { text-size: 14; }
  [zoom = 18] { text-size: 12; }
  [zoom = 17] { text-size: 10; }
}

/*
  Miscellaneous items
  */

/* ferry routes */
#ferry-route[zoom > 6][zoom < 12] {
  line-color: white;
  line-width: 0.7;
  line-opacity: 0.5;
}

#ferry-route[zoom > 11] {
  line-color: #00066f;
  line-dasharray: 6,6;

  [zoom = 12] { line-width: 0.8; }
  [zoom = 13] { line-width: 1.0; }
  [zoom = 14] { line-width: 1.3; }
  [zoom = 15] { line-width: 1.6; }
  [zoom > 15] { line-width: 2.0; }

  ::halo{
    line-color: white;
    line-width: 1.0;
    line-opacity: 0.5;

    [zoom = 13] { line-width: 1.2; }
    [zoom = 14] { line-width: 1.5; }
    [zoom = 15] { line-width: 1.8; }
    [zoom > 15] { line-width: 2.2; }
  }
}

#landuse[landuse='military'][zoom > 10] {
  ::outline {
    line-color: #f55000;
    line-width: 3;
    line-opacity: 0.329;
  }

  polygon-pattern-file: url('/usr/share/icons/osmt/military-pattern.png');
}


Check for existance needs "!= null" test

function MSplitString (string, delimiter) {
    //$module(Utilities.mss)
    /*
        The default Splitstring method is buggy,
        so I've re-implemented it here.

        Delimiter is optional; if it is false, this will
        split the string into an array of characters.
    */
    ret = CreateSparseArray();
    pos = 0;
    // If there is no delimiter, split the string
    // into an array of characters.
    if (delimiter = false)
    {
        for i = 0 to Length(string)
        {
            ret.Push(Substring(string, i, 1));
        }
        return ret;
    }

    for i = 0 to Length(string) + 1
    {
        if (utils.CharAt(string, i) = delimiter)
        {
            ret.Push(Substring(string, pos, i - pos));
            pos = i + 1;
        }

        if (i = Length(string))
        {
            ret.Push(Substring(string, pos, Length(string) - pos));
        }
    }
    return ret;
}  //$end

function PrevPow2 (val) {
    //$module(Utilities.mss)
    if (val = 0)
    {
        return 0;
    }
    //val = val - 1;
    val = utils.bwOR(val, utils.shr(val, 1));
    val = utils.bwOR(val, utils.shr(val, 2));
    val = utils.bwOR(val, utils.shr(val, 4));
    val = utils.bwOR(val, utils.shr(val, 8));
    val = utils.bwOR(val, utils.shr(val, 16));
    // this might be a hack, but I wrote it in
    // a power outage with no internet.
    // we get the next power of two, and then
    // divide by two to get the previous one.
    val = (val + 1) / 2;
    return val;
}  //$end

function SimpleNoteHash (nobj) {
    //$module(Utilities.mss)
    /*
        Generate a simple note hash. Not guaranteed to be unique given
        any suitably large sample of notes, but should be unique enough for quick
        checks.
    */
    pos = nobj.ParentNoteRest.Position;
    pitch = nobj.Pitch;
    duration = nobj.Duration;
    voice = nobj.VoiceNumber;
    name = nobj.Name;
    parent_bar_number = nobj.ParentNoteRest.ParentBar.BarNumber;
    parent_staff_number = nobj.ParentNoteRest.ParentBar.ParentStaff.StaffNum;
    time = nobj.ParentNoteRest.Time;

    hash = '' & pos & '-' & pitch & '-' & duration & '-' & voice & '-' & name & '-' & parent_bar_number & '-' & parent_staff_number & '-' & time;

    return hash;

}  //$end

function GetNoteObjectAtPosition (bobj) {
    //$module(Utilities.mss)
    // takes a dictionary of {pos:id} mappings for a given
    // voice, and returns the NoteRest object. If one isn't found
    // exactly at `position`, it will first look back (previous)
    // and then look forward, for candidate objects.

    objectPositions = Self._property:ObjectPositions;
    staff_num = bobj.ParentBar.ParentStaff.StaffNum;
    bar_num = bobj.ParentBar.BarNumber;
    voice_num = bobj.VoiceNumber;

    staffObjectPositions = objectPositions[staff_num];
    barObjectPositions = staffObjectPositions[bar_num];
    voiceObjectPositions = barObjectPositions[voice_num];

    if (voiceObjectPositions = null)
    {
        // theres not much we can do here. Bail.
        Log('Bailing due to insufficient voice information');
        return null;
    }

    if (voiceObjectPositions.PropertyExists(bobj.Position))
    {
        obj_id = voiceObjectPositions[bobj.Position];
        obj = libmei.getElementById(obj_id);
        return obj;
    }
    else
    {
        // if we can't find anything at this position,
        // find the previous and subsequent objects, and align the
        // lyrics with them.
        prev_obj = bobj.PreviousItem(voice_num, 'NoteRest');

        if (prev_obj != null)
        {
            // there should be an object registered here
            obj_id = voiceObjectPositions[prev_obj.Position];
            obj = libmei.getElementById(obj_id);
            return obj;
        }
        else
        {
            next_obj = bobj.NextItem(voice_num, 'NoteRest');

            if (next_obj != null)
            {
                obj_id = voiceObjectPositions[next_obj.Position];
                obj = libmei.getElementById(obj_id);
                return obj;
            }
        }
    }

    return null;
}  //$end

function AddBarObjectInfoToElement (bobj, element) {
    //$module(Utilities.mss)
    /*
        adds timing and position info (tstamps, etc.) to an element.
        This info is mostly derived from the base BarObject class.
    */
    voicenum = bobj.VoiceNumber;
    bar = bobj.ParentBar;

    if (voicenum = 0)
    {
        // assign it to the first voice, since we don't have any notes in voice/layer 0.
        voicenum = 1;
        warnings = Self._property:warnings;
        warnings.Push(utils.Format(_ObjectAssignedToAllVoicesWarning, bar.BarNumber, voicenum, 'Bar object'));
    }

    if (bobj.Type = 'Line')
    {
        // lines have durations, but symbols do not.
        if (bobj.Duration > 0)
        {
            libmei.AddAttribute(element, 'dur.ges', bobj.Duration & 'p');
        }
    }

    libmei.AddAttribute(element, 'tstamp', ConvertPositionToTimestamp(bobj.Position, bar));

    switch (bobj.Type)
    {
        case('Line')
        {
            libmei.AddAttribute(element, 'tstamp2', ConvertPositionWithDurationToTimestamp(bobj));
        }
        case('Slur')
        {
            libmei.AddAttribute(element, 'tstamp2', ConvertPositionWithDurationToTimestamp(bobj));
        }
        case('DiminuendoLine')
        {
            libmei.AddAttribute(element, 'tstamp2', ConvertPositionWithDurationToTimestamp(bobj));
        }
        case('CrescendoLine')
        {
            libmei.AddAttribute(element, 'tstamp2', ConvertPositionWithDurationToTimestamp(bobj));
        }
        case('GlissandoLine')
        {
            libmei.AddAttribute(element, 'tstamp2', ConvertPositionWithDurationToTimestamp(bobj));
        }
        case('Trill')
        {
            libmei.AddAttribute(element, 'tstamp2', ConvertPositionWithDurationToTimestamp(bobj));
        }
    }

    libmei.AddAttribute(element, 'staff', bar.ParentStaff.StaffNum);
    libmei.AddAttribute(element, 'layer', voicenum);

    if (bobj.Dx > 0)
    {
        libmei.AddAttribute(element, 'ho', ConvertOffsetsToMillimeters(bobj.Dx));
    }

    if (bobj.Dy > 0)
    {
        libmei.AddAttribute(element, 'vo', ConvertOffsetsToMillimeters(bobj.Dy));
    }

    return element;

}  //$end

function TupletsEqual (t, t2) {
    //$module(Utilities.mss)

    // shamelessly copied from the built-in tuplet plugin.
    tIsBar = (t = null) or (t.Type = 'Bar');
    t2IsBar = (t2 = null) or (t2.Type = 'Bar');

    if( tIsBar and t2IsBar ) { return true; }
    if( tIsBar or t2IsBar ) { return false; }

    b = t.ParentBar;
    b2 = t2.ParentBar;

    if( b.BarNumber != b2.BarNumber ) { return false; }
    if( b.ParentStaff.StaffNum != b2.ParentStaff.StaffNum ) { return 0; }
    if( t.VoiceNumber != t2.VoiceNumber ) { return false; }

    if( t.Position != t2.Position ) { return false; }
    if( t.PlayedDuration != t2.PlayedDuration ) { return false; }

    return true;

}  //$end

function GetTupletStack (bobj) {
    //$module(Utilities.mss)
    tupletStack = CreateSparseArray();
    parentTuplet = bobj.ParentTupletIfAny;
    while (parentTuplet != null)
    {
        tupletStack.Push(parentTuplet);
        parentTuplet = parentTuplet.ParentTupletIfAny;
    }
    tupletStack.Reverse();
    return tupletStack;
}  //$end

function CountTupletsEndingAtNoteRest(noteRest) {
    //$module(Utilities.mss)
    tuplet = noteRest.ParentTupletIfAny;

    if (tuplet = null)
    {
        return 0;
    }

    nextNoteRest = noteRest.NextItem(noteRest.VoiceNumber, 'NoteRest');

    if (nextNoteRest = null or nextNoteRest.ParentTupletIfAny = null)
    {
        tupletStack = GetTupletStack(noteRest);
        return tupletStack.Length;
    }

    if (TupletsEqual(tuplet, nextNoteRest.ParentTupletIfAny))
    {
        return 0;
    }

    tupletStack = GetTupletStack(noteRest);
    nextTupletStack = GetTupletStack(nextNoteRest);

    // We are looking for the highest index where both stacks are identical.
    index = utils.min(tupletStack.Length, nextTupletStack.Length) - 1;

    while (index >= 0 and not(TupletsEqual(tupletStack[index], nextTupletStack[index])))
    {
        index = index - 1;
    }

    return tupletStack.Length - 1 - index;
}  //$end

function GetMeiTupletDepth (layer) {
    //$module(Utilities.mss)
    depth = 0;
    tuplet = layer._property:ActiveMeiTuplet;
    while (tuplet != null)
    {
        depth = depth + 1;
        tuplet = tuplet._property:ParentTuplet;
    }
    return depth;
}  //$end

function lstrip (str) {
    //$module(Utilities.mss)
    if (utils.CharAt(str, 0) = ' ')
    {
        return Substring(str, 1);
    }
    else
    {
        return str;
    }
}  //$end

function rstrip (str) {
    //$module(Utilities.mss)
    if (utils.CharAt(str, Length(str) - 1) = ' ')
    {
        return Substring(str, 0, Length(str) - 1);
    }
    else
    {
        return str;
    }
}  //$end

function Log (message) {
    //$module(Utilities.mss)
    Sibelius.AppendLineToFile(LOGFILE, message, True);
}  //$end

function NormalizedBeamProp (noteRest) {
    //$module(Utilities.mss)
    /*
        Sibelius' Beam properties can't be trusted. We need to look at the context,
        check whether they make sense and if they don't, find out the value we'd expect.
        Problems can e.g. be that Sibelius reports
         * a ContinueBeam at the start of a beam (we'd expect StartBeam)
         * a property other than NoBeam on a quarter or longer un-beamable duration
           (we'd expect NoBeam)
         * ... (almost any combinations imaginable)
    */
    if (noteRest.Beam = NoBeam or noteRest.Duration >= 256)
    {
        return NoBeam;
    }

    // At this point, we're only dealing with ContinueBeam and SingleBeam.
    // We need to look at the preceding note to see whether there's any
    // beam to continue.

    if (noteRest.Beam != StartBeam)
    {
        prev_obj = PrevNormalOrGrace(noteRest, noteRest.GraceNote);

        if (prev_obj != null and prev_obj.Beam != NoBeam and prev_obj.Duration < 256)
        {
            // We actually have a beam we can continue.
            if (noteRest.Beam = SingleBeam and noteRest.Duration < 128 and prev_obj.Duration < 128)
            {
                // SingleBeam only makes sense if we actually have secondary beams between the
                // previous note and the current note.
                return SingleBeam;
            }
            return ContinueBeam;
        }
    }

    // At this point, we know there is no previous beam we can continue because we have a
    // StartBeam or the above test for a previous beam failed.
    // We still need to check whether there is a following note that we can beam to.

    next_obj = NextNormalOrGrace(noteRest, noteRest.GraceNote);
    if (next_obj != null and next_obj.Duration < 256 and (next_obj.Beam = ContinueBeam or next_obj.Beam = SingleBeam))
    {
        return StartBeam;
    }
    else
    {
        return NoBeam;
    }
}  //$end

function NextNormalOrGrace (noteRest, grace) {
    //$module(Utilities.mss)
    /*
        When given a 'normal' NoteRest, this function returns the next 'normal' NoteRest
        in the same voice.
        When given a grace NoteRest, this function returns the immediately adjacent
        following grace NoteRest, if existant.
        This function is basically a duplicate of PrevNormalOrGrace() with
        'Previous' replaced by 'Next'.
    */
    next_obj = noteRest.NextItem(noteRest.VoiceNumber, 'NoteRest');
    if (grace)
    {
        // There mustn't be any intermitting 'normal' notes between grace notes.
        if (next_obj != null and not(next_obj.GraceNote))
        {
            next_obj = null;
        }
    }
    else
    {
        // If noteRest isn't a grace note, we skip all grace notes as their beams
        // can be nested inside normal beams.
        while (next_obj != null and next_obj.GraceNote)
        {
            next_obj = next_obj.NextItem(noteRest.VoiceNumber, 'NoteRest');
        }
    }
    return next_obj;
}  //$end

function PrevNormalOrGrace (noteRest, grace) {
    //$module(Utilities.mss)
    /*
        For a description, see NextNormalOrGrace().
        This function is basically a duplicate of PrevNormalOrGrace() with
        'Next' replaced by 'Previous'.
    */
    prev_obj = noteRest.PreviousItem(noteRest.VoiceNumber, 'NoteRest');
    if (grace)
    {
        // There mustn't be any intermitting 'normal' notes between grace notes.
        if (prev_obj != null and not(prev_obj.GraceNote))
        {
            prev_obj = null;
        }
    }
    else
    {
        // If noteRest isn't a grace note, we skip all grace notes as their beams
        // can be nested inside normal beams.
        while (prev_obj and prev_obj.GraceNote)
        {
            prev_obj = prev_obj.NextItem(noteRest.VoiceNumber, 'NoteRest');
        }
    }
    return prev_obj;
}  //$end

function GetNongraceParentBeam (noteRest, layer) {
    //$module(Utilities.mss)
    /*
       This function is used to find out whether a non-grace beam spans over a grace
       NoteRest that is either unbeamed or at the start of a grace beam.
    */
    if (layer._property:ActiveBeam != null)
    {
        // Only if the active non-grace beam continues to the next normal note, the
        // grace note is truly placed under the non-grace beam.
        nextNongraceNoteRest = NextNormalOrGrace(noteRest, false);
        if (nextNongraceNoteRest != null)
        {
            nextNormalBeamProp = NormalizedBeamProp(nextNongraceNoteRest);
        }
        else
        {
            nextNormalBeamProp = NoBeam;
        }
        if (nextNormalBeamProp = ContinueBeam or nextNormalBeamProp = SingleBeam)
        {
            return layer._property:ActiveBeam;
        }
    }
    return null;
}  //$end

function MSplitString (string, delimiter) {
    //$module(Utilities.mss)
    /*
        The default Splitstring method is buggy,
        so I've re-implemented it here.

        Delimiter is optional; if it is false, this will
        split the string into an array of characters.
    */
    ret = CreateSparseArray();
    pos = 0;
    // If there is no delimiter, split the string
    // into an array of characters.
    if (delimiter = false)
    {
        for i = 0 to Length(string)
        {
            ret.Push(Substring(string, i, 1));
        }
        return ret;
    }

    for i = 0 to Length(string) + 1
    {
        if (utils.CharAt(string, i) = delimiter)
        {
            ret.Push(Substring(string, pos, i - pos));
            pos = i + 1;
        }

        if (i = Length(string))
        {
            ret.Push(Substring(string, pos, Length(string) - pos));
        }
    }
    return ret;
}  //$end

function PrevPow2 (val) {
    //$module(Utilities.mss)
    if (val = 0)
    {
        return 0;
    }
    //val = val - 1;
    val = utils.bwOR(val, utils.shr(val, 1));
    val = utils.bwOR(val, utils.shr(val, 2));
    val = utils.bwOR(val, utils.shr(val, 4));
    val = utils.bwOR(val, utils.shr(val, 8));
    val = utils.bwOR(val, utils.shr(val, 16));
    // this might be a hack, but I wrote it in
    // a power outage with no internet.
    // we get the next power of two, and then
    // divide by two to get the previous one.
    val = (val + 1) / 2;
    return val;
}  //$end

function SimpleNoteHash (nobj) {
    //$module(Utilities.mss)
    /*
        Generate a simple note hash. Not guaranteed to be unique given
        any suitably large sample of notes, but should be unique enough for quick
        checks.
    */
    pos = nobj.ParentNoteRest.Position;
    pitch = nobj.Pitch;
    duration = nobj.Duration;
    voice = nobj.VoiceNumber;
    name = nobj.Name;
    parent_bar_number = nobj.ParentNoteRest.ParentBar.BarNumber;
    parent_staff_number = nobj.ParentNoteRest.ParentBar.ParentStaff.StaffNum;
    time = nobj.ParentNoteRest.Time;

    hash = '' & pos & '-' & pitch & '-' & duration & '-' & voice & '-' & name & '-' & parent_bar_number & '-' & parent_staff_number & '-' & time;

    return hash;

}  //$end

function GetNoteObjectAtPosition (bobj) {
    //$module(Utilities.mss)
    // takes a dictionary of {pos:id} mappings for a given
    // voice, and returns the NoteRest object. If one isn't found
    // exactly at `position`, it will first look back (previous)
    // and then look forward, for candidate objects.

    objectPositions = Self._property:ObjectPositions;
    staff_num = bobj.ParentBar.ParentStaff.StaffNum;
    bar_num = bobj.ParentBar.BarNumber;
    voice_num = bobj.VoiceNumber;

    staffObjectPositions = objectPositions[staff_num];
    barObjectPositions = staffObjectPositions[bar_num];
    voiceObjectPositions = barObjectPositions[voice_num];

    if (voiceObjectPositions = null)
    {
        // theres not much we can do here. Bail.
        Log('Bailing due to insufficient voice information');
        return null;
    }

    if (voiceObjectPositions.PropertyExists(bobj.Position))
    {
        obj_id = voiceObjectPositions[bobj.Position];
        obj = libmei.getElementById(obj_id);
        return obj;
    }
    else
    {
        // if we can't find anything at this position,
        // find the previous and subsequent objects, and align the
        // lyrics with them.
        prev_obj = bobj.PreviousItem(voice_num, 'NoteRest');

        if (prev_obj != null)
        {
            // there should be an object registered here
            obj_id = voiceObjectPositions[prev_obj.Position];
            obj = libmei.getElementById(obj_id);
            return obj;
        }
        else
        {
            next_obj = bobj.NextItem(voice_num, 'NoteRest');

            if (next_obj != null)
            {
                obj_id = voiceObjectPositions[next_obj.Position];
                obj = libmei.getElementById(obj_id);
                return obj;
            }
        }
    }

    return null;
}  //$end

function AddBarObjectInfoToElement (bobj, element) {
    //$module(Utilities.mss)
    /*
        adds timing and position info (tstamps, etc.) to an element.
        This info is mostly derived from the base BarObject class.
    */
    voicenum = bobj.VoiceNumber;
    bar = bobj.ParentBar;

    if (voicenum = 0)
    {
        // assign it to the first voice, since we don't have any notes in voice/layer 0.
        voicenum = 1;
        warnings = Self._property:warnings;
        warnings.Push(utils.Format(_ObjectAssignedToAllVoicesWarning, bar.BarNumber, voicenum, 'Bar object'));
    }

    if (bobj.Type = 'Line')
    {
        // lines have durations, but symbols do not.
        if (bobj.Duration > 0)
        {
            libmei.AddAttribute(element, 'dur.ges', bobj.Duration & 'p');
        }
    }

    libmei.AddAttribute(element, 'tstamp', ConvertPositionToTimestamp(bobj.Position, bar));

    switch (bobj.Type)
    {
        case('Line')
        {
            libmei.AddAttribute(element, 'tstamp2', ConvertPositionWithDurationToTimestamp(bobj));
        }
        case('Slur')
        {
            libmei.AddAttribute(element, 'tstamp2', ConvertPositionWithDurationToTimestamp(bobj));
        }
        case('DiminuendoLine')
        {
            libmei.AddAttribute(element, 'tstamp2', ConvertPositionWithDurationToTimestamp(bobj));
        }
        case('CrescendoLine')
        {
            libmei.AddAttribute(element, 'tstamp2', ConvertPositionWithDurationToTimestamp(bobj));
        }
        case('GlissandoLine')
        {
            libmei.AddAttribute(element, 'tstamp2', ConvertPositionWithDurationToTimestamp(bobj));
        }
        case('Trill')
        {
            libmei.AddAttribute(element, 'tstamp2', ConvertPositionWithDurationToTimestamp(bobj));
        }
    }

    libmei.AddAttribute(element, 'staff', bar.ParentStaff.StaffNum);
    libmei.AddAttribute(element, 'layer', voicenum);

    if (bobj.Dx > 0)
    {
        libmei.AddAttribute(element, 'ho', ConvertOffsetsToMillimeters(bobj.Dx));
    }

    if (bobj.Dy > 0)
    {
        libmei.AddAttribute(element, 'vo', ConvertOffsetsToMillimeters(bobj.Dy));
    }

    return element;

}  //$end

function TupletsEqual (t, t2) {
    //$module(Utilities.mss)

    // shamelessly copied from the built-in tuplet plugin.
    tIsBar = (t = null) or (t.Type = 'Bar');
    t2IsBar = (t2 = null) or (t2.Type = 'Bar');

    if( tIsBar and t2IsBar ) { return true; }
    if( tIsBar or t2IsBar ) { return false; }

    b = t.ParentBar;
    b2 = t2.ParentBar;

    if( b.BarNumber != b2.BarNumber ) { return false; }
    if( b.ParentStaff.StaffNum != b2.ParentStaff.StaffNum ) { return 0; }
    if( t.VoiceNumber != t2.VoiceNumber ) { return false; }

    if( t.Position != t2.Position ) { return false; }
    if( t.PlayedDuration != t2.PlayedDuration ) { return false; }

    return true;

}  //$end

function GetTupletStack (bobj) {
    //$module(Utilities.mss)
    tupletStack = CreateSparseArray();
    parentTuplet = bobj.ParentTupletIfAny;
    while (parentTuplet != null)
    {
        tupletStack.Push(parentTuplet);
        parentTuplet = parentTuplet.ParentTupletIfAny;
    }
    tupletStack.Reverse();
    return tupletStack;
}  //$end

function CountTupletsEndingAtNoteRest(noteRest) {
    //$module(Utilities.mss)
    tuplet = noteRest.ParentTupletIfAny;

    if (tuplet = null)
    {
        return 0;
    }

    nextNoteRest = noteRest.NextItem(noteRest.VoiceNumber, 'NoteRest');

    if (nextNoteRest = null or nextNoteRest.ParentTupletIfAny = null)
    {
        tupletStack = GetTupletStack(noteRest);
        return tupletStack.Length;
    }

    if (TupletsEqual(tuplet, nextNoteRest.ParentTupletIfAny))
    {
        return 0;
    }

    tupletStack = GetTupletStack(noteRest);
    nextTupletStack = GetTupletStack(nextNoteRest);

    // We are looking for the highest index where both stacks are identical.
    index = utils.min(tupletStack.Length, nextTupletStack.Length) - 1;

    while (index >= 0 and not(TupletsEqual(tupletStack[index], nextTupletStack[index])))
    {
        index = index - 1;
    }

    return tupletStack.Length - 1 - index;
}  //$end

function GetMeiTupletDepth (layer) {
    //$module(Utilities.mss)
    depth = 0;
    tuplet = layer._property:ActiveMeiTuplet;
    while (tuplet)
    {
        depth = depth + 1;
        tuplet = tuplet._property:ParentTuplet;
    }
    return depth;
}  //$end

function lstrip (str) {
    //$module(Utilities.mss)
    if (utils.CharAt(str, 0) = ' ')
    {
        return Substring(str, 1);
    }
    else
    {
        return str;
    }
}  //$end

function rstrip (str) {
    //$module(Utilities.mss)
    if (utils.CharAt(str, Length(str) - 1) = ' ')
    {
        return Substring(str, 0, Length(str) - 1);
    }
    else
    {
        return str;
    }
}  //$end

function Log (message) {
    //$module(Utilities.mss)
    Sibelius.AppendLineToFile(LOGFILE, message, True);
}  //$end

function NormalizedBeamProp (noteRest) {
    //$module(Utilities.mss)
    /*
        Sibelius' Beam properties can't be trusted. We need to look at the context,
        check whether they make sense and if they don't, find out the value we'd expect.
        Problems can e.g. be that Sibelius reports
         * a ContinueBeam at the start of a beam (we'd expect StartBeam)
         * a property other than NoBeam on a quarter or longer un-beamable duration
           (we'd expect NoBeam)
         * ... (almost any combinations imaginable)
    */
    if (noteRest.Beam = NoBeam or noteRest.Duration >= 256)
    {
        return NoBeam;
    }

    // At this point, we're only dealing with ContinueBeam and SingleBeam.
    // We need to look at the preceding note to see whether there's any
    // beam to continue.

    if (noteRest.Beam != StartBeam)
    {
        prev_obj = PrevNormalOrGrace(noteRest, noteRest.GraceNote);

        if (prev_obj != null and prev_obj.Beam != NoBeam and prev_obj.Duration < 256)
        {
            // We actually have a beam we can continue.
            if (noteRest.Beam = SingleBeam and noteRest.Duration < 128 and prev_obj.Duration < 128)
            {
                // SingleBeam only makes sense if we actually have secondary beams between the
                // previous note and the current note.
                return SingleBeam;
            }
            return ContinueBeam;
        }
    }

    // At this point, we know there is no previous beam we can continue because we have a
    // StartBeam or the above test for a previous beam failed.
    // We still need to check whether there is a following note that we can beam to.

    next_obj = NextNormalOrGrace(noteRest, noteRest.GraceNote);
    if (next_obj != null and next_obj.Duration < 256 and (next_obj.Beam = ContinueBeam or next_obj.Beam = SingleBeam))
    {
        return StartBeam;
    }
    else
    {
        return NoBeam;
    }
}  //$end

function NextNormalOrGrace (noteRest, grace) {
    //$module(Utilities.mss)
    /*
        When given a 'normal' NoteRest, this function returns the next 'normal' NoteRest
        in the same voice.
        When given a grace NoteRest, this function returns the immediately adjacent
        following grace NoteRest, if existant.
        This function is basically a duplicate of PrevNormalOrGrace() with
        'Previous' replaced by 'Next'.
    */
    next_obj = noteRest.NextItem(noteRest.VoiceNumber, 'NoteRest');
    if (grace)
    {
        // There mustn't be any intermitting 'normal' notes between grace notes.
        if (next_obj != null and not(next_obj.GraceNote))
        {
            next_obj = null;
        }
    }
    else
    {
        // If noteRest isn't a grace note, we skip all grace notes as their beams
        // can be nested inside normal beams.
        while (next_obj != null and next_obj.GraceNote)
        {
            next_obj = next_obj.NextItem(noteRest.VoiceNumber, 'NoteRest');
        }
    }
    return next_obj;
}  //$end

function PrevNormalOrGrace (noteRest, grace) {
    //$module(Utilities.mss)
    /*
        For a description, see NextNormalOrGrace().
        This function is basically a duplicate of PrevNormalOrGrace() with
        'Next' replaced by 'Previous'.
    */
    prev_obj = noteRest.PreviousItem(noteRest.VoiceNumber, 'NoteRest');
    if (grace)
    {
        // There mustn't be any intermitting 'normal' notes between grace notes.
        if (prev_obj != null and not(prev_obj.GraceNote))
        {
            prev_obj = null;
        }
    }
    else
    {
        // If noteRest isn't a grace note, we skip all grace notes as their beams
        // can be nested inside normal beams.
        while (prev_obj and prev_obj.GraceNote)
        {
            prev_obj = prev_obj.NextItem(noteRest.VoiceNumber, 'NoteRest');
        }
    }
    return prev_obj;
}  //$end

function GetNongraceParentBeam (noteRest, layer) {
    //$module(Utilities.mss)
    /*
       This function is used to find out whether a non-grace beam spans over a grace
       NoteRest that is either unbeamed or at the start of a grace beam.
    */
    if (layer._property:ActiveBeam != null)
    {
        // Only if the active non-grace beam continues to the next normal note, the
        // grace note is truly placed under the non-grace beam.
        nextNongraceNoteRest = NextNormalOrGrace(noteRest, false);
        if (nextNongraceNoteRest != null)
        {
            nextNormalBeamProp = NormalizedBeamProp(nextNongraceNoteRest);
        }
        else
        {
            nextNormalBeamProp = NoBeam;
        }
        if (nextNormalBeamProp = ContinueBeam or nextNormalBeamProp = SingleBeam)
        {
            return layer._property:ActiveBeam;
        }
    }
    return null;
}  //$end