Add InitFigbassCharMap()

Add InitFigbassCharMap()

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 InitFigbassCharMap () {
    //$module(Utilities.mss)
    map = CreateDictionary(
        '§', '♮',
        '#', '♯',
        '!', '♭',
        '?', '𝄪',
        '%', '𝄫',
        'a', '(2)',
        'i', '[2]',
        'w', '2♮',
        's', '2♯',
        'x', '2♭',
        'W', '♮2',
        'S', '♯2',
        'X', '♭2',
        'k', '2+',
        'p', '(3)',
        'q', '[3]',
        'e', '3♮',
        'd', '3♯',
        'c', '3♭',
        'E', '♮3',
        'D', '♯3',
        'C', '♭3',
        'z', '3+',
        'A', '(4)',
        'I', '[4]',
        'r', '4♮',
        'f', '4♯',
        'v', '4♭',
        'R', '♮4',
        'F', '♯4',
        'V', '♭4',
        'K', '4+',
        'P', '(5)',
        'Q', '[5]',
        't', '5♮',
        'g', '5♯',
        'b', '5♭',
        'T', '♮5',
        'G', '♯5',
        'B', '♭5',
        'Z', '5+',
        '$', '(6)',
        '¨', '[6]',
        'y', '6♮',
        'h', '6♯',
        'n', '6♭',
        'Y', '♮6',
        'H', '♯6',
        'N', '♭6',
        ',', '6+',
        'Â', '(7)',
        ';', '[7]',
        'u', '7♮',
        'j', '7♯',
        'm', '7♭',
        'U', '♮7',
        'J', '♯7',
        'M', '♭7',
        '<', '7+',
        '>', '+7',
        '=', '(8)',
        'Ö', '[8]',
        'À', '(9)',
        '{', '[9]',
        'o', '9♮',
        'l', '9♯',
        'ë', '9♭',
        'O', '♮9',
        'L', '♯9',
        ':', '♭9',
        '}', '9+',
        'Å', '|',
        'ü', '_',
        '©', CreateSparseArray('2♯', 'U+EA53'), // 2 with slashed foot
        'Ä', CreateSparseArray('4♯', 'U+EA56'), // 4 with slashed horizontal line
        'Ë', CreateSparseArray('5♯', 'U+EA58'), // 5 with straight slash through head
        'Ï', CreateSparseArray('5♯', 'U+EA59'), // 5 with angled slash through head
        'ï', CreateSparseArray('5♯', 'U+EA5A'), // 5 with slashed foot
        '´', CreateSparseArray('6♯', 'U+EA6F'), // 6 with slashed head
        'ä', CreateSparseArray('7♯', 'U+EA5E'), // 7 with slashed head
        '&', CreateSparseArray('7♯', 'U+EA5F'), // 7 with slashed stem
        // (Sibelius/Opus and SMuFL/Bravura don't match 100% for the slashed 9:
        // Opus slashes the stem, Bravura the head)
        'ö', CreateSparseArray('9#', 'U+EA62')  // slashed 9
    );
    literalChars = '0123456789[]_-+.';
    for i = 0 to Length(literalChars)
    {
        char = CharAt(literalChars, i);
        map[char] = char;
    }

    return map;
}  //$end


update marine labels for v6

update marine labels for v6

////////////////////////////////////////////////
// Places //
////////////////////////////////////////////////

// Countries //
#country_label[zoom>=2] {
  text-name: @name;
  text-face-name: @med;
  text-wrap-width: 140;
  text-wrap-before: true;
  text-fill: @country_text;
  text-halo-fill: @country_halo;
  text-halo-radius: 2;
  text-halo-rasterizer: fast;
  text-size: 12;
  [zoom>=3][scalerank=1],
  [zoom>=4][scalerank=2],
  [zoom>=5][scalerank=3],
  [zoom>=6][scalerank>3] {
    text-size: 14;
    text-wrap-width: 160;
  }
  [zoom>=4][scalerank=1],
  [zoom>=5][scalerank=2],
  [zoom>=6][scalerank=3],
  [zoom>=7][scalerank>3] {
    text-size: 16;
    text-wrap-width: 185;
  }
  [zoom>=8] { text-fill: @country_text_high; }
}

// States //
#state_label[zoom>=4][zoom<=10] {
  text-name: [abbr];
  text-face-name: @reg;
  text-transform: uppercase;
  text-character-spacing: 1.5;
  text-placement: point;
  text-fill: @state_text;
  text-halo-fill: @state_halo;
  text-opacity: 1;
  text-halo-radius: 1.5;
  text-halo-rasterizer: fast;
  text-size: 10;
  [zoom>=4][area>100000],
  [zoom>=5][area>50000],
  [zoom>=6][area>10000],
  [zoom>=7][area<=10000] {
    text-name: [abbr];
  }
  [zoom>=5][area>100000],
  [zoom>=6][area>50000],
  [zoom>=7][area>10000],
  [zoom>=8][area<=10000] {
    text-name: @name;
  }
  [zoom>=5][zoom<=6] {
    [area>10000] { text-size: 10; }
    [area>50000] { text-size: 11; }
    text-wrap-width: 40;
  }
  [zoom>=7] {
    text-size: 12;
    [area>50000] { text-size: 13;  }
    [area>100000] { text-size: 14; }
    text-wrap-width: 60;
  }
  [zoom>=8] {
    text-size: 16;
    [area>50000] { text-size: 18;  }
    [area>100000] { text-size: 20; }
    text-wrap-width: 80;
  }
  [zoom>=9][zoom<=10] {
    text-size: 18;
    [area>50000] { text-size: 20; }
    text-wrap-width: 100;
  }
}

// City dots – version with markers as text
#place_label::citydots[type='city'][zoom>=4][zoom<=7][localrank<=1] {
 [ldir='N'],[ldir='S'],[ldir='E'],[ldir='W'],
 [ldir='NE'],[ldir='SE'],[ldir='SW'],[ldir='NW'] {
  // explicitly defining all the `ldir` values wer'e going
  // to use shaves a bit off the final project.xml size
 [ldir='E'] {
      text-name: '∘ ' + [name_en];
      text-horizontal-alignment: right;
      }
    [ldir='W'] {
      text-name: [name_en] + ' ∘';
      text-horizontal-alignment: left;
      }
    [ldir='S'] {
      text-name: '∘\n' + [name_en];
      text-line-spacing: -10;
      text-vertical-alignment: bottom;
      }
     [ldir='N'] {
      text-name: [name_en] + '\n∘';
      text-line-spacing: -10;
      text-vertical-alignment: top;
      }
    [ldir='SE'] {
      text-name: '∘\n  ' + [name_en];
      text-line-spacing: -15;
      text-vertical-alignment: bottom;
      text-horizontal-alignment: right;
      text-align: left;
      }
    [ldir='SW'] {
      text-name: '∘\n' + [name_en] + '  ';
      text-line-spacing: -16;
      text-vertical-alignment: bottom;
      text-horizontal-alignment: left;
      text-align: right;
      }
     [ldir='NE'] {
      text-name: '  ' + [name_en] + '\n∘';
      text-line-spacing: -16;
      text-vertical-alignment: top;
      text-horizontal-alignment: right;
      text-align: left;
      }
    [ldir='NW'] {
      text-name: [name_en] + '  \n∘';
      text-line-spacing: -15;
      text-vertical-alignment: top;
      text-horizontal-alignment: left;
      text-align: right;
      }
    text-name: @name;
    text-size: 16;
    text-face-name: @reg;
    text-placement: point;
    text-fill: @city_text;
    text-halo-fill: @city_halo;
    text-halo-radius: 2;
    text-halo-rasterizer: fast;
    }
}

#place_label {
  [type='city'][zoom>=8][zoom<=15][localrank=1] {
    text-name: @name;
    text-face-name: @reg;
    text-fill: @city_text;
    text-halo-fill: @city_halo;
    text-halo-radius: 2;
    text-halo-rasterizer: fast;
    text-size: 16;
    text-line-spacing: -8;
    text-wrap-width: 160;
    text-wrap-before: true;
    [zoom>=9] {
      text-size: 17;
      text-wrap-width: 170; }
    [zoom>=10] {
      text-size: 18;
      text-wrap-width: 180; }
    [zoom>=12] {
      text-size: 24;
      text-character-spacing: 0;
      text-wrap-width: 220;
      }
    [zoom>=14] {
        text-fill: @city_text_high;
        text-size: 28;
        text-wrap-width: 250;
      }
    }
  }

#place_label {
  [type='town'][zoom>=8][zoom<=17][localrank<=1] {
    text-name: @name;
    text-face-name: @reg;
    text-fill: @town_text;
    text-halo-fill: @town_halo;
    text-halo-radius: 2;
    text-halo-rasterizer: fast;
    text-size: 12;
    text-line-spacing: -8;
    text-wrap-width: 100;
    text-wrap-before: true;
    [zoom>=10] {
      text-size: 14;
      text-wrap-width: 120;
       }
    [zoom>=12] {
      text-size: 20;
      text-wrap-width: 160;
      }
    [zoom>=14] {
      text-fill: @town_text_high;
      text-size: 26;
      text-wrap-width: 200;
      }
    [zoom>=16] {
      text-size: 28;
      text-wrap-width: 180;
    }
  }
  [type='village'][zoom>=10][zoom<=18][localrank<=1],
  [type='hamlet'][zoom>=12][zoom<=18][localrank<=1]  {
    text-name: @name;
    text-face-name: @reg;
    text-fill: @village_text;
    text-halo-fill: @village_halo;
    text-halo-radius: 2;
    text-halo-rasterizer: fast;
    text-size: 12;
    text-wrap-width: 100;
    text-line-spacing: -8;
    text-wrap-before: true;
    [type='village'] {
    [zoom>=12] {
        text-size: 18;
        text-wrap-width: 180;
    }
    [zoom>=14] {
        text-size: 20;
        text-wrap-width: 200;
    }
    [zoom>=16] {
        text-fill: @village_text_high;
        text-size: 24;
        text-wrap-width: 240;
     }
     [zoom>=18] {
        text-size: 26;
        text-wrap-width: 250;
      }
    }
    [type='hamlet'] {
    [zoom>=12] {
        text-size: 16;
        text-wrap-width: 160;
    }
    [zoom>=14] {
        text-size: 18;
        text-wrap-width: 180;
     }
     [zoom>=16] {
        text-fill: @village_text_high;
        text-size: 22;
        text-wrap-width: 220;
      }
      [zoom>=18] {
        text-size: 24;
        text-wrap-width: 240;
       }
    }
 }

  [type='suburb'][zoom>=12][zoom<=17][localrank<=1],
  [type='neighbourhood'][zoom>=13][zoom<=17][localrank<=1] {
    text-name: @name;
    text-face-name: @reg;
    text-fill: @neigh_text;
    text-halo-fill: @neigh_halo;
    text-halo-radius: 2;
    text-halo-rasterizer: fast;
    text-size: 14;
    text-wrap-width: 100;
    text-wrap-before: true;
    text-line-spacing: -8;
    [type='suburb'][zoom>=13],
    [type='neighbourhood'][zoom>=14] {
      text-size: 16;
      text-wrap-width: 160;
    }
    [type='suburb'][zoom>=14],
    [type='neighbourhood'][zoom>=15] {
      text-size: 18;
      text-wrap-width: 180;
    }
    [type='suburb'][zoom>=15],
    [type='neighbourhood'][zoom>=16] {
      text-size: 20;
      text-wrap-width: 200;
      }
     [type='suburb'][zoom>=16],
     [type='neighbourhood'][zoom>=17] {
       text-size: 22;
       text-wrap-width: 220;
     }
     [type='suburb'][zoom>=17] {
       text-size: 24;
       text-wrap-width: 240;
      }
    [zoom>=16] { text-fill:@neigh_text_high; }
  }
}

////////////////////////////////////////////////
// Water Features //
////////////////////////////////////////////////

// Water bodies //
#water_label {
  [zoom<=13],  // automatic area filtering @ low zooms
  [zoom>=14][area>500000],
  [zoom>=16][area>10000],
  [zoom>=17] {
    text-name: @name;
    text-face-name: @it_bd;
    text-fill: darken(@marine_text, 10);
    text-character-spacing: 0.5;
    text-size: 9;
    text-wrap-width: 40;
    text-wrap-before: true;
    text-halo-fill: fadeout(@land, 5);//fadeout(#fff, 25);
    text-halo-radius: 1.5;
    text-halo-rasterizer: fast;
  }
  [zoom>=15][area>500000],
  [zoom>=17][area>10000],
  [zoom>=18]  {
    text-size: 10;
    text-wrap-width: 70;
  }
  [zoom>=16][area>500000],
  [zoom>=18][area>10000],
  [zoom>=19]  {
    text-size: 11;
    text-wrap-width: 80;
  }
  [zoom>=12][area>10000000],
  [zoom>=14][area>5000000]  {
    text-size: 12;
    text-wrap-width: 90;
  }
  [zoom>=10][area>100000000]  {
    text-size: 13;
    text-wrap-width: 90;
  }
}

// Waterways //
#waterway_label {
  [class="river"][zoom>=13],
  [class="canal"][zoom>=15],
  [class="stream"][zoom>=17],
  [class="stream_intermittent"][zoom>=17] {
    text-placement: line;
    text-avoid-edges:true;
    text-min-distance: 400;
    text-name: @name;
    text-face-name: @it_bd;
    text-fill: darken(@marine_text, 25);
    text-size: 9;
    text-character-spacing: 1;
    text-halo-fill: fadeout(#fff, 45);
    text-halo-radius: 1;
    text-halo-rasterizer:fast;
  }
  [class="river"][zoom>=14],
  [class="canal"][zoom>=16],
  [class="stream"][zoom>=18],
  [class="stream_intermittent"][zoom>=18] {
    text-size: 9;
  }
  [class='river'][zoom=15],
  [class='canal'][zoom>=17] {
    text-size: 10;
  }
  [class='river'][zoom>=16],
  [class='canal'][zoom>=18] {
    text-size: 11;
  }
}

// Marine (oceans and seas) //
#marine_label[zoom>=2]["mapnik::geometry_type"=1],
#marine_label[zoom>=2]["mapnik::geometry_type"=2] {
  text-name: @name;
  text-face-name: @it;
  text-fill: @marine_text;
  text-halo-fill: fadeout(#fff, 95);
  text-halo-radius: 2;
  ["mapnik::geometry_type"=1] {
    text-placement: point;
    text-wrap-width: 30;
  }
  ["mapnik::geometry_type"=2] {
    text-placement: line;
  }
  [labelrank=1][zoom>=2],
  [labelrank=2][zoom>=3],
  [labelrank=3][zoom>=4],
  [labelrank=4][zoom>=5],
  [labelrank=5][zoom>=6],
  [labelrank=6][zoom>=7] {
    text-size: 13;
    text-character-spacing: 1;
  }
  [labelrank=1][zoom>=3],
  [labelrank=2][zoom>=4],
  [labelrank=3][zoom>=5],
  [labelrank=4][zoom>=6],
  [labelrank=5][zoom>=7],
  [labelrank=6][zoom>=8] {
    text-size: 16;
    text-character-spacing: 2;
  }
  [labelrank=1][zoom>=4],
  [labelrank=2][zoom>=5],
  [labelrank=3][zoom>=6] {
    text-size: 20;
    text-character-spacing: 4;
  }
  [labelrank=1][zoom>=5],
  [labelrank=2][zoom>=6],
  [labelrank=3][zoom>=7] {
    text-size: 24;
    text-character-spacing: 8;
  }
}

////////////////////////////////////////////////
// Road labels //
////////////////////////////////////////////////

// highway shield
#road_label::shield-pt[class='motorway'][zoom>=7][zoom<=10][localrank=1][reflen<=6],
#road_label::shield-pt[class='motorway'][zoom>=9][zoom<=10][localrank=1][reflen<=6],
#road_label::shield-ln[zoom>=11][reflen<=6] {
  shield-name: "[ref].replace('·', '\n')";
  shield-size: 9;
  shield-line-spacing: -4;
  shield-file: url('img/shield/[shield]-[reflen].svg');
  shield-face-name: @bold;
  shield-fill: #333;
  [zoom>=14] {
    shield-transform: scale(1.25,1.25);
    shield-size: 11;
  }
}
#road_label::shield-pt[class='motorway'][zoom>=7][zoom<=10][localrank=1][reflen<=6],
#road_label::shield-pt[class='motorway'][zoom>=9][zoom<=10][localrank=1][reflen<=6] {
  shield-placement: point;
  shield-avoid-edges: false;
}
#road_label::shield-ln[zoom>=11][reflen<=6] {
  shield-placement: line;
  shield-spacing: 400;
  shield-min-distance: 20;
  shield-avoid-edges: true;
}

// Larger roads //
#road_label['mapnik::geometry_type'=2] {
  // Longer roads get a label earlier as they are likely to be more
  // important. This especially helps label density in rural/remote areas.
  // This z14 filter is *not* redundant to logic in SQL queries. Because z14
  // includes all data for z14+ via overzooming, the streets included in a
  // z14 vector tile include more features than ideal for optimal performance.
  [class='motorway'][zoom>=14],
  [class='main'][zoom<=12][len>5000],
  [class='main'][zoom>=13][len>2000],
  [class='main'][zoom>=14][len>1500],
  [class='main'][zoom>=15][len>750],
  [class='main'][zoom>=16],
  [class='street'][zoom>=15][len>1500],
  [class='street'][zoom>=16],
  [class='street_limited'][zoom>=16] {
    text-avoid-edges: true;
    text-name: [name];
    text-character-spacing: 0.25;
    text-placement: line;
    text-face-name: @reg;
    text-fill: @road_text;
    text-size: 11;
    text-halo-fill: @road_halo;
    text-halo-radius: 1;
    text-halo-rasterizer: fast;
    text-min-distance: 200; // only for labels w/ the same name
    [class='motorway'] { text-halo-fill: @motorway_halo; }
    [zoom>=14] {
      text-size: 11;
      text-fill: @road_text_high;
    }
    [zoom>=16] { text-fill: @road_text_high2; }
    [zoom>=17] { text-size: 12;  }
    [class='motorway'],
    [class='main'] {
      [zoom>=14] {
        text-size: 12;
        text-fill: @road_text_high;
      }
      [zoom>=16] {
        text-size: 13;
        text-fill: @road_text_high2;
      }
      [zoom>=17] { text-size: 14; }
      [zoom>=18] { text-size: 15;  }
    }
  }
}

// Smaller roads //
#road_label['mapnik::geometry_type'=2]
  [class!='motorway']
  [class!='main']
  [class!='street']
  [class!='street_limited'] {
    [len>750][zoom>=16],
    [len>0][zoom>=17] {
      text-avoid-edges: true;
      text-name: [name];
      text-character-spacing: 0.25;
      text-placement: line;
      text-face-name: @reg;
      text-fill: @road_text;
      text-size: 11;
      text-halo-fill: @road_halo;
      text-halo-radius: 1;
      text-halo-rasterizer: fast;
      text-min-distance: 200; // only for labels w/ the same name
      [zoom>=15] { text-fill: @road_text_high; }
    }
 }

////////////////////////////////////////////////
// Places //
////////////////////////////////////////////////

// Countries //
#country_label[zoom>=2] {
  text-name: @name;
  text-face-name: @med;
  text-wrap-width: 140;
  text-wrap-before: true;
  text-fill: @country_text;
  text-halo-fill: @country_halo;
  text-halo-radius: 2;
  text-halo-rasterizer: fast;
  text-size: 12;
  [zoom>=3][scalerank=1],
  [zoom>=4][scalerank=2],
  [zoom>=5][scalerank=3],
  [zoom>=6][scalerank>3] {
    text-size: 14;
    text-wrap-width: 160;
  }
  [zoom>=4][scalerank=1],
  [zoom>=5][scalerank=2],
  [zoom>=6][scalerank=3],
  [zoom>=7][scalerank>3] {
    text-size: 16;
    text-wrap-width: 185;
  }
  [zoom>=8] { text-fill: @country_text_high; }
}

// States //
#state_label[zoom>=4][zoom<=10] {
  text-name: [abbr];
  text-face-name: @reg;
  text-transform: uppercase;
  text-character-spacing: 1.5;
  text-placement: point;
  text-fill: @state_text;
  text-halo-fill: @state_halo;
  text-opacity: 1;
  text-halo-radius: 1.5;
  text-halo-rasterizer: fast;
  text-size: 10;
  [zoom>=4][area>100000],
  [zoom>=5][area>50000],
  [zoom>=6][area>10000],
  [zoom>=7][area<=10000] {
    text-name: [abbr];
  }
  [zoom>=5][area>100000],
  [zoom>=6][area>50000],
  [zoom>=7][area>10000],
  [zoom>=8][area<=10000] {
    text-name: @name;
  }
  [zoom>=5][zoom<=6] {
    [area>10000] { text-size: 10; }
    [area>50000] { text-size: 11; }
    text-wrap-width: 40;
  }
  [zoom>=7] {
    text-size: 12;
    [area>50000] { text-size: 13;  }
    [area>100000] { text-size: 14; }
    text-wrap-width: 60;
  }
  [zoom>=8] {
    text-size: 16;
    [area>50000] { text-size: 18;  }
    [area>100000] { text-size: 20; }
    text-wrap-width: 80;
  }
  [zoom>=9][zoom<=10] {
    text-size: 18;
    [area>50000] { text-size: 20; }
    text-wrap-width: 100;
  }
}

// City dots – version with markers as text
#place_label::citydots[type='city'][zoom>=4][zoom<=7][localrank<=1] {
 [ldir='N'],[ldir='S'],[ldir='E'],[ldir='W'],
 [ldir='NE'],[ldir='SE'],[ldir='SW'],[ldir='NW'] {
  // explicitly defining all the `ldir` values wer'e going
  // to use shaves a bit off the final project.xml size
 [ldir='E'] {
      text-name: '∘ ' + [name_en];
      text-horizontal-alignment: right;
      }
    [ldir='W'] {
      text-name: [name_en] + ' ∘';
      text-horizontal-alignment: left;
      }
    [ldir='S'] {
      text-name: '∘\n' + [name_en];
      text-line-spacing: -10;
      text-vertical-alignment: bottom;
      }
     [ldir='N'] {
      text-name: [name_en] + '\n∘';
      text-line-spacing: -10;
      text-vertical-alignment: top;
      }
    [ldir='SE'] {
      text-name: '∘\n  ' + [name_en];
      text-line-spacing: -15;
      text-vertical-alignment: bottom;
      text-horizontal-alignment: right;
      text-align: left;
      }
    [ldir='SW'] {
      text-name: '∘\n' + [name_en] + '  ';
      text-line-spacing: -16;
      text-vertical-alignment: bottom;
      text-horizontal-alignment: left;
      text-align: right;
      }
     [ldir='NE'] {
      text-name: '  ' + [name_en] + '\n∘';
      text-line-spacing: -16;
      text-vertical-alignment: top;
      text-horizontal-alignment: right;
      text-align: left;
      }
    [ldir='NW'] {
      text-name: [name_en] + '  \n∘';
      text-line-spacing: -15;
      text-vertical-alignment: top;
      text-horizontal-alignment: left;
      text-align: right;
      }
    text-name: @name;
    text-size: 16;
    text-face-name: @reg;
    text-placement: point;
    text-fill: @city_text;
    text-halo-fill: @city_halo;
    text-halo-radius: 2;
    text-halo-rasterizer: fast;
    }
}

#place_label {
  [type='city'][zoom>=8][zoom<=15][localrank=1] {
    text-name: @name;
    text-face-name: @reg;
    text-fill: @city_text;
    text-halo-fill: @city_halo;
    text-halo-radius: 2;
    text-halo-rasterizer: fast;
    text-size: 16;
    text-line-spacing: -8;
    text-wrap-width: 160;
    text-wrap-before: true;
    [zoom>=9] {
      text-size: 17;
      text-wrap-width: 170; }
    [zoom>=10] {
      text-size: 18;
      text-wrap-width: 180; }
    [zoom>=12] {
      text-size: 24;
      text-character-spacing: 0;
      text-wrap-width: 220;
      }
    [zoom>=14] {
        text-fill: @city_text_high;
        text-size: 28;
        text-wrap-width: 250;
      }
    }
  }

#place_label {
  [type='town'][zoom>=8][zoom<=17][localrank<=1] {
    text-name: @name;
    text-face-name: @reg;
    text-fill: @town_text;
    text-halo-fill: @town_halo;
    text-halo-radius: 2;
    text-halo-rasterizer: fast;
    text-size: 12;
    text-line-spacing: -8;
    text-wrap-width: 100;
    text-wrap-before: true;
    [zoom>=10] {
      text-size: 14;
      text-wrap-width: 120;
       }
    [zoom>=12] {
      text-size: 20;
      text-wrap-width: 160;
      }
    [zoom>=14] {
      text-fill: @town_text_high;
      text-size: 26;
      text-wrap-width: 200;
      }
    [zoom>=16] {
      text-size: 28;
      text-wrap-width: 180;
    }
  }
  [type='village'][zoom>=10][zoom<=18][localrank<=1],
  [type='hamlet'][zoom>=12][zoom<=18][localrank<=1]  {
    text-name: @name;
    text-face-name: @reg;
    text-fill: @village_text;
    text-halo-fill: @village_halo;
    text-halo-radius: 2;
    text-halo-rasterizer: fast;
    text-size: 12;
    text-wrap-width: 100;
    text-line-spacing: -8;
    text-wrap-before: true;
    [type='village'] {
    [zoom>=12] {
        text-size: 18;
        text-wrap-width: 180;
    }
    [zoom>=14] {
        text-size: 20;
        text-wrap-width: 200;
    }
    [zoom>=16] {
        text-fill: @village_text_high;
        text-size: 24;
        text-wrap-width: 240;
     }
     [zoom>=18] {
        text-size: 26;
        text-wrap-width: 250;
      }
    }
    [type='hamlet'] {
    [zoom>=12] {
        text-size: 16;
        text-wrap-width: 160;
    }
    [zoom>=14] {
        text-size: 18;
        text-wrap-width: 180;
     }
     [zoom>=16] {
        text-fill: @village_text_high;
        text-size: 22;
        text-wrap-width: 220;
      }
      [zoom>=18] {
        text-size: 24;
        text-wrap-width: 240;
       }
    }
 }

  [type='suburb'][zoom>=12][zoom<=17][localrank<=1],
  [type='neighbourhood'][zoom>=13][zoom<=17][localrank<=1] {
    text-name: @name;
    text-face-name: @reg;
    text-fill: @neigh_text;
    text-halo-fill: @neigh_halo;
    text-halo-radius: 2;
    text-halo-rasterizer: fast;
    text-size: 14;
    text-wrap-width: 100;
    text-wrap-before: true;
    text-line-spacing: -8;
    [type='suburb'][zoom>=13],
    [type='neighbourhood'][zoom>=14] {
      text-size: 16;
      text-wrap-width: 160;
    }
    [type='suburb'][zoom>=14],
    [type='neighbourhood'][zoom>=15] {
      text-size: 18;
      text-wrap-width: 180;
    }
    [type='suburb'][zoom>=15],
    [type='neighbourhood'][zoom>=16] {
      text-size: 20;
      text-wrap-width: 200;
      }
     [type='suburb'][zoom>=16],
     [type='neighbourhood'][zoom>=17] {
       text-size: 22;
       text-wrap-width: 220;
     }
     [type='suburb'][zoom>=17] {
       text-size: 24;
       text-wrap-width: 240;
      }
    [zoom>=16] { text-fill:@neigh_text_high; }
  }
}

////////////////////////////////////////////////
// Water Features //
////////////////////////////////////////////////

// Water bodies //
#water_label {
  [zoom<=13],  // automatic area filtering @ low zooms
  [zoom>=14][area>500000],
  [zoom>=16][area>10000],
  [zoom>=17] {
    text-name: @name;
    text-face-name: @it_bd;
    text-fill: darken(@marine_text, 10);
    text-character-spacing: 0.5;
    text-size: 9;
    text-wrap-width: 40;
    text-wrap-before: true;
    text-halo-fill: fadeout(@land, 5);//fadeout(#fff, 25);
    text-halo-radius: 1.5;
    text-halo-rasterizer: fast;
  }
  [zoom>=15][area>500000],
  [zoom>=17][area>10000],
  [zoom>=18]  {
    text-size: 10;
    text-wrap-width: 70;
  }
  [zoom>=16][area>500000],
  [zoom>=18][area>10000],
  [zoom>=19]  {
    text-size: 11;
    text-wrap-width: 80;
  }
  [zoom>=12][area>10000000],
  [zoom>=14][area>5000000]  {
    text-size: 12;
    text-wrap-width: 90;
  }
  [zoom>=10][area>100000000]  {
    text-size: 13;
    text-wrap-width: 90;
  }
}

// Waterways //
#waterway_label {
  [class="river"][zoom>=13],
  [class="canal"][zoom>=15],
  [class="stream"][zoom>=17],
  [class="stream_intermittent"][zoom>=17] {
    text-placement: line;
    text-avoid-edges:true;
    text-min-distance: 400;
    text-name: @name;
    text-face-name: @it_bd;
    text-fill: darken(@marine_text, 25);
    text-size: 9;
    text-character-spacing: 1;
    text-halo-fill: fadeout(#fff, 45);
    text-halo-radius: 1;
    text-halo-rasterizer:fast;
  }
  [class="river"][zoom>=14],
  [class="canal"][zoom>=16],
  [class="stream"][zoom>=18],
  [class="stream_intermittent"][zoom>=18] {
    text-size: 9;
  }
  [class='river'][zoom=15],
  [class='canal'][zoom>=17] {
    text-size: 10;
  }
  [class='river'][zoom>=16],
  [class='canal'][zoom>=18] {
    text-size: 11;
  }
}

// Marine (oceans and seas) //
#marine_label[zoom>=2]["mapnik::geometry_type"=1],
#marine_label[zoom>=2]["mapnik::geometry_type"=2] {
  text-name: @name;
  text-face-name: @it;
  text-fill: @marine_text;
  text-wrap-width: 70;
  text-wrap-before: true;
  text-halo-fill: fadeout(#fff, 95);
  text-halo-radius: 2;
  ["mapnik::geometry_type"=1] {
    text-placement: point;
    text-wrap-width: 30;
  }
  ["mapnik::geometry_type"=2] {
    text-placement: line;
  }
  [labelrank = 1] {
    text-wrap-width: 400;
    [zoom = 3] {
      text-size: 14;
      text-character-spacing: 4;
      text-line-spacing: 16;
    }
    [zoom = 4] {
      text-size: 16;
      text-character-spacing: 6;
      text-line-spacing: 24;
    }
    [zoom = 5] {
      text-size: 18;
      text-character-spacing: 8;
      text-line-spacing: 32;
    }
  }
  [labelrank = 2] {
    [zoom = 3] {
      text-size: 10;
      text-character-spacing: 2;
      text-line-spacing: 6;
    }
    [zoom = 4] {
      text-size: 11;
      text-character-spacing: 2;
      text-line-spacing: 8;
    }
    [zoom = 5] {
      text-size: 17;
      text-character-spacing: 4;
      text-line-spacing: 8;
    }
    [zoom = 6] {
      text-size: 19;
      text-character-spacing: 5;
      text-line-spacing: 10;
    }
  }
  [labelrank = 3] {
    [zoom = 3] {
      text-size: 9;
      text-character-spacing: 2;
      text-line-spacing: 3;
    }
    [zoom = 4] {
      text-size: 10;
      text-character-spacing: 2;
      text-line-spacing: 8;
    }
    [zoom = 5] {
      text-size: 12;
      text-character-spacing: 4;
      text-line-spacing: 8;
    }
    [zoom = 6] {
      text-size: 15;
      text-character-spacing: 5;
      text-line-spacing: 10;
    }
  }
  [labelrank = 4][zoom = 4],
  [labelrank = 5][zoom = 5],
  [labelrank = 6][zoom = 6] {
    text-size: 9;
    text-character-spacing: 2;
    text-line-spacing: 6;
  }
  [labelrank = 4][zoom = 5],
  [labelrank = 5][zoom = 6],
  [labelrank = 6][zoom = 7] {
    text-size: 11;
    text-character-spacing: 3;
    text-line-spacing: 8;
  }
  [labelrank = 4][zoom = 6],
  [labelrank = 5][zoom = 7] {
    text-size: 16;
    text-character-spacing: 4;
    text-line-spacing: 1;
  }
}

////////////////////////////////////////////////
// Road labels //
////////////////////////////////////////////////

// highway shield
#road_label::shield-pt[class='motorway'][zoom>=7][zoom<=10][localrank=1][reflen<=6],
#road_label::shield-pt[class='motorway'][zoom>=9][zoom<=10][localrank=1][reflen<=6],
#road_label::shield-ln[zoom>=11][reflen<=6] {
  shield-name: "[ref].replace('·', '\n')";
  shield-size: 9;
  shield-line-spacing: -4;
  shield-file: url('img/shield/[shield]-[reflen].svg');
  shield-face-name: @bold;
  shield-fill: #333;
  [zoom>=14] {
    shield-transform: scale(1.25,1.25);
    shield-size: 11;
  }
}
#road_label::shield-pt[class='motorway'][zoom>=7][zoom<=10][localrank=1][reflen<=6],
#road_label::shield-pt[class='motorway'][zoom>=9][zoom<=10][localrank=1][reflen<=6] {
  shield-placement: point;
  shield-avoid-edges: false;
}
#road_label::shield-ln[zoom>=11][reflen<=6] {
  shield-placement: line;
  shield-spacing: 400;
  shield-min-distance: 20;
  shield-avoid-edges: true;
}

// Larger roads //
#road_label['mapnik::geometry_type'=2] {
  // Longer roads get a label earlier as they are likely to be more
  // important. This especially helps label density in rural/remote areas.
  // This z14 filter is *not* redundant to logic in SQL queries. Because z14
  // includes all data for z14+ via overzooming, the streets included in a
  // z14 vector tile include more features than ideal for optimal performance.
  [class='motorway'][zoom>=14],
  [class='main'][zoom<=12][len>5000],
  [class='main'][zoom>=13][len>2000],
  [class='main'][zoom>=14][len>1500],
  [class='main'][zoom>=15][len>750],
  [class='main'][zoom>=16],
  [class='street'][zoom>=15][len>1500],
  [class='street'][zoom>=16],
  [class='street_limited'][zoom>=16] {
    text-avoid-edges: true;
    text-name: [name];
    text-character-spacing: 0.25;
    text-placement: line;
    text-face-name: @reg;
    text-fill: @road_text;
    text-size: 11;
    text-halo-fill: @road_halo;
    text-halo-radius: 1;
    text-halo-rasterizer: fast;
    text-min-distance: 200; // only for labels w/ the same name
    [class='motorway'] { text-halo-fill: @motorway_halo; }
    [zoom>=14] {
      text-size: 11;
      text-fill: @road_text_high;
    }
    [zoom>=16] { text-fill: @road_text_high2; }
    [zoom>=17] { text-size: 12;  }
    [class='motorway'],
    [class='main'] {
      [zoom>=14] {
        text-size: 12;
        text-fill: @road_text_high;
      }
      [zoom>=16] {
        text-size: 13;
        text-fill: @road_text_high2;
      }
      [zoom>=17] { text-size: 14; }
      [zoom>=18] { text-size: 15;  }
    }
  }
}

// Smaller roads //
#road_label['mapnik::geometry_type'=2]
  [class!='motorway']
  [class!='main']
  [class!='street']
  [class!='street_limited'] {
    [len>750][zoom>=16],
    [len>0][zoom>=17] {
      text-avoid-edges: true;
      text-name: [name];
      text-character-spacing: 0.25;
      text-placement: line;
      text-face-name: @reg;
      text-fill: @road_text;
      text-size: 11;
      text-halo-fill: @road_halo;
      text-halo-radius: 1;
      text-halo-rasterizer: fast;
      text-min-distance: 200; // only for labels w/ the same name
      [zoom>=15] { text-fill: @road_text_high; }
    }
 }