public void LinesShouldBeCorrectlyCalculated()
        {
            //string content = "// ===================================================================================================================================================\r\n// The philosophy and measurements come from the section \"A proposed overhaul\" in FogBugz 9788, further details may be found in the four comments\r\n// following it: \"iPhone 3 and low-dpi tablets\", \"Desktop\", \"Modern Mobile\" and \"Mid-or-hi-dpi Tablet\"\r\n// - There is no overlap between targets such as \"desktop\" and \"phoneHiDpi\" so it should always be clear which target any given device in any\r\n//   given configuration (eg. landscape orientation) will have applied. The same approach is applied to the basic pixel break points; no\r\n//   overlaps.\r\n// ===================================================================================================================================================\r\n// Configurable values\r\n// ===============================================================================================\r\n// Breakpoint measurements in pixels\r\n@breakPoint320InPixels: 320;\r\n@breakPoint480InPixels: 480;\r\n@breakPoint560InPixels: 560;\r\n@breakPoint760InPixels: 768;\r\n@breakPoint880InPixels: 920;\r\n@breakPoint980InPixels: 994;\r\n@breakPointWideInPixels: 1450;\r\n\r\n// Measurements to differentiate between hardware devices\r\n// - To differentiate between a desktop device and a low-dpi tablet we look at the min/max-device-height when in landscape and min/max-device-width\r\n//   when portrait (the logic being that a 10\" tablet may be 211mm high when in landscape but 338mm high when in portrait, which is higher than\r\n//   most monitors, so we can't differentiate on device-height only). Using min/max-device-width/height means that desktops are not categorised\r\n//   as tablets if the browser window is made too small vertically (which using min/max-width would).\r\n// - 2013-12-17 DWR: We now need different landscape and portrait desktop min device heights since we've had to sacrifice the low-dpi tablet 10\"\r\n//   landscape breakpoint since there was no way to differentiate between it and a small laptop screen (10\" tablet was 211mm high in landscape\r\n//   but a laptop used for comparison was 203mm). In order to keep the low-dpi 10\" tablet displaying as a tablet in portrait, \r\n//   - 2014-03-12 DG: The reference to tenInchTabletMinLandscapeWidthInMM has been changed from 290 to 270 to incorporate the Ipad Air, as this was not picking up\r\n//   elements such as the Mega Nav at Landscape Level\r\n@tabletMinLandscapeWidthInMM: 210;\r\n@tabletMinPortraitWidthInMM: 159;\r\n@tenInchTabletMinLandscapeWidthInMM: 270;\r\n@desktopMonitorMinLandscapeDeviceHeightInMM: 200;\r\n@desktopMonitorMinPortraitDeviceHeightInMM: 220;\r\n\r\n// ===============================================================================================\r\n// These are all calculated and shouldn't have to be changed (unless new breakpoints are added)\r\n// ===============================================================================================\r\n// - General breakpoint cutoffs\r\n@breakPoint320AfterInPixels: @breakPoint320InPixels + 1;\r\n@breakPoint480AfterInPixels: @breakPoint480InPixels + 1;\r\n@breakPoint560AfterInPixels: @breakPoint560InPixels + 1;\r\n@breakPoint760AfterInPixels: @breakPoint760InPixels + 1;\r\n@breakPoint880AfterInPixels: @breakPoint880InPixels + 1;\r\n@breakPoint980AfterInPixels: @breakPoint980InPixels + 1;\r\n@breakPoint320: ~\"@{breakPoint320InPixels}px\";\r\n@breakPoint480: ~\"@{breakPoint480InPixels}px\";\r\n@breakPoint560: ~\"@{breakPoint560InPixels}px\";\r\n@breakPoint760: ~\"@{breakPoint760InPixels}px\";\r\n@breakPoint880: ~\"@{breakPoint880InPixels}px\";\r\n@breakPoint980: ~\"@{breakPoint980InPixels}px\";\r\n@breakPointWide: ~\"@{breakPointWideInPixels}px\";\r\n@breakPoint320After: ~\"@{breakPoint320AfterInPixels}px\";\r\n@breakPoint480After: ~\"@{breakPoint480AfterInPixels}px\";\r\n@breakPoint560After: ~\"@{breakPoint560AfterInPixels}px\";\r\n@breakPoint760After: ~\"@{breakPoint760AfterInPixels}px\";\r\n@breakPoint880After: ~\"@{breakPoint880AfterInPixels}px\";\r\n@breakPoint980After: ~\"@{breakPoint980AfterInPixels}px\";\r\n\r\n// - Tablet physical size start point (to differentiate between phones and tablets, required for hi-dpi devices only)\r\n@tabletMinLandscapeWidth: ~\"@{tabletMinLandscapeWidthInMM}mm\";\r\n@tabletMinLandscapeWidthBeforeInMM: @tabletMinLandscapeWidthInMM - 1;\r\n@tabletMinLandscapeWidthBefore: ~\"@{tabletMinLandscapeWidthBeforeInMM}mm\";\r\n@tabletMinPortraitWidth: ~\"@{tabletMinPortraitWidthInMM}mm\";\r\n@tabletMinPortraitWidthBeforeInMM: @tabletMinPortraitWidthInMM - 1;\r\n@tabletMinPortraitWidthBefore: ~\"@{tabletMinPortraitWidthBeforeInMM}mm\";\r\n\r\n// - Tablet physical size differentiations (between 7\" and 10\")\r\n@tenInchTabletMinLandscapeWidth: ~\"@{tenInchTabletMinLandscapeWidthInMM}mm\";\r\n@tenInchTabletMinLandscapeWidthBeforeInMM: @tenInchTabletMinLandscapeWidthInMM - 1;\r\n@tenInchTabletMinLandscapeWidthBefore: ~\"@{tenInchTabletMinLandscapeWidthBeforeInMM}mm\";\r\n\r\n// - Desktop physical size differentiations (between tablets and desktops, required for low-dpi devices only)\r\n@desktopMonitorMinLandscapeDeviceHeight: ~\"@{desktopMonitorMinLandscapeDeviceHeightInMM}mm\";\r\n@desktopMonitorMinLandscapeDeviceHeightBeforeInMM: @desktopMonitorMinLandscapeDeviceHeightInMM - 1;\r\n@desktopMonitorMinLandscapeDeviceHeightBefore: ~\"@{desktopMonitorMinLandscapeDeviceHeightBeforeInMM}mm\";\r\n@desktopMonitorMinPortraitDeviceHeight: ~\"@{desktopMonitorMinPortraitDeviceHeightInMM}mm\";\r\n@desktopMonitorMinPortraitDeviceHeightBeforeInMM: @desktopMonitorMinPortraitDeviceHeightInMM - 1;\r\n@desktopMonitorMinPortraitDeviceHeightBefore: ~\"@{desktopMonitorMinPortraitDeviceHeightBeforeInMM}mm\";\r\n\r\n// ===============================================================================================\r\n// Breakpoint categories\r\n// ===============================================================================================\r\n@desktopStandardsLandscape: ~\"all and (max-resolution: 229dpi)                       and (orientation: landscape) and (min-device-height: @{desktopMonitorMinLandscapeDeviceHeight})\";\r\n@desktopStandardsPortrait: ~\"all and (max-resolution: 229dpi)                        and (orientation: portrait)  and (min-device-width:  @{desktopMonitorMinPortraitDeviceHeight})\";\r\n@desktopWebKitLandscape: ~\"all and (-webkit-max-device-pixel-ratio: 23.395)           and (orientation: landscape) and (min-device-height: @{desktopMonitorMinLandscapeDeviceHeight})\";\r\n@desktopWebKitPortrait: ~\"all and (-webkit-max-device-pixel-ratio: 23.395)            and (orientation: portrait)  and (min-device-width:  @{desktopMonitorMinPortraitDeviceHeight})\";\r\n\r\n@phoneTabletLowDpiStandardsLandscape: ~\"all and (max-resolution: 229dpi)             and (orientation: landscape) and (max-device-height: @{desktopMonitorMinLandscapeDeviceHeightBefore})\";\r\n@phoneTabletLowDpiStandardsPortrait: ~\"all and (max-resolution: 229dpi)              and (orientation: portrait)  and (max-device-width:  @{desktopMonitorMinPortraitDeviceHeightBefore})\";\r\n@phoneTabletLowDpiWebKitLandscape: ~\"all and (-webkit-max-device-pixel-ratio: 23.395) and (orientation: landscape) and (max-device-height: @{desktopMonitorMinLandscapeDeviceHeightBefore})\";\r\n@phoneTabletLowDpiWebKitPortrait: ~\"all and (-webkit-max-device-pixel-ratio: 23.395)  and (orientation: portrait)  and (max-device-width:  @{desktopMonitorMinPortraitDeviceHeightBefore})\";\r\n\r\n@phoneHiDpiStandardsLandscape: ~\"all and (min-resolution: 230dpi)                    and (orientation: landscape) and (max-width: @{tabletMinLandscapeWidthBefore})\";\r\n@phoneHiDpiStandardsPortrait: ~\"all and (min-resolution: 230dpi)                     and (orientation: portrait)  and (max-width: @{tabletMinPortraitWidthBefore})\";\r\n@phoneHiDpiWebKitLandscape: ~\"all and (-webkit-min-device-pixel-ratio: 23.396)         and (orientation: landscape) and (max-width: @{tabletMinLandscapeWidthBefore})\";\r\n@phoneHiDpiWebKitPortrait: ~\"all and (-webkit-min-device-pixel-ratio: 23.396)          and (orientation: portrait)  and (max-width: @{tabletMinPortraitWidthBefore})\";\r\n\r\n@tabletHiDpiStandardsLandscape: ~\"all and (min-resolution: 230dpi)                   and (orientation: landscape) and (min-width: @{tabletMinLandscapeWidth})\";\r\n@tabletHiDpiStandardsPortrait: ~\"all and (min-resolution: 230dpi)                    and (orientation: portrait)  and (min-width: @{tabletMinPortraitWidth})\";\r\n@tabletHiDpiWebKitLandscape: ~\"all and (-webkit-min-device-pixel-ratio: 23.396)        and (orientation: landscape) and (min-width: @{tabletMinLandscapeWidth})\";\r\n@tabletHiDpiWebKitPortrait: ~\"all and (-webkit-min-device-pixel-ratio: 23.396)         and (orientation: portrait)  and (min-width: @{tabletMinPortraitWidth})\";\r\n\r\n// ===============================================================================================\r\n// Base media query bands\r\n// - There should be no overlap between bands for any device / orientation\r\n// - If any changes are made here, ensure that they are propogated through the \"Extended/ranged\r\n//   media query bands\" content further down\r\n// ===============================================================================================\r\n// \"Narrow Mobile\"\r\n// Only expect this to hit vary narrow desktop browsers (for demonstration purposes) and mobiles which report very low widths (eg iPhone 3G's\r\n// genuine width and iPhone 4s reported width)\r\n@ResponsiveTo320:\r\n    ~\"@{desktopStandardsLandscape}           and (max-width: @{breakPoint320}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (max-width: @{breakPoint320}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (max-width: @{breakPoint320}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (max-width: @{breakPoint320}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (max-width: @{breakPoint320}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait}  and (max-width: @{breakPoint320}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (max-width: @{breakPoint320}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait}     and (max-width: @{breakPoint320}),\"\r\n    ~\"@{phoneHiDpiStandardsLandscape}        and (max-width: @{breakPoint320}),\"\r\n    ~\"@{phoneHiDpiStandardsPortrait}         and (max-width: @{breakPoint320}),\"\r\n    ~\"@{phoneHiDpiWebKitLandscape}           and (max-width: @{breakPoint320}),\"\r\n    ~\"@{phoneHiDpiWebKitPortrait}            and (max-width: @{breakPoint320})\";\r\n\r\n// \"Mobile\"\r\n// Note that HiDpi phones are capped at this breakpoint (there is no max-width for them here)\r\n@Responsive320To480:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint480}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint480}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint480}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait}  and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait}     and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneHiDpiStandardsLandscape}        and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiStandardsPortrait}         and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiWebKitLandscape}           and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiWebKitPortrait}            and (min-width: @{breakPoint320After})\";\r\n\r\n// \"Desktop mid-way convenience point only\"\r\n// Note: This is a mid-way breakpoint that is only really intended for desktop devices. As such, we only consider the desktop devices here.\r\n@Responsive480To560:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint480After}) and (max-width: @{breakPoint560}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint480After}) and (max-width: @{breakPoint560}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint480After}) and (max-width: @{breakPoint560}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint480After}) and (max-width: @{breakPoint560})\";\r\n\r\n// \"Tablet Portrait\"\r\n// Note that HiDpi tablets are only introduced here since they may only be in this breakpoint (if portrait, regardless of size) or \"Small\r\n// Tablet Landscape\" (if less than 10\" landscape) or \"Big Tablet Landscape (if 10\" or greater landscape). The table portrait restriction\r\n// means that tablets in portrait are capped here (no max-width). Also note that the min-width values for the tablets and phones are 480\r\n// and not 560, this is because the 560 breakpoint above is not applied to tablets or phones and so, to them, it is as if the 560\r\n// breakpoint does not exist.\r\n@Responsive560To760:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint560After}) and (max-width: @{breakPoint760}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint560After}) and (max-width: @{breakPoint760}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint560After}) and (max-width: @{breakPoint760}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint560After}) and (max-width: @{breakPoint760}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint480After}) and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait}  and (min-width: @{breakPoint480After}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (min-width: @{breakPoint480After}) and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait}     and (min-width: @{breakPoint480After}),\"\r\n    ~\"@{tabletHiDpiStandardsPortrait},\"\r\n    ~\"@{tabletHiDpiWebKitPortrait}\";\r\n\r\n// \"Small Tablet Landscape / Desktop FatButton NonMegaNav\"\r\n// Historically, this was only ever used as a mid-way breakpoint for desktops (like \"Responsive480To560\") but recently (as of 2014-03-12) it\r\n// has been decided to use the full MegaNav for large tablets in landscape but the menu button for smaller tablets in landscape, so now this\r\n// breakpoint is used to make that distinction.\r\n@Responsive760To880:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint760After}) and (max-width: @{breakPoint880}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint760After}) and (max-width: @{breakPoint880}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint760After}) and (max-width: @{breakPoint880}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint760After}) and (max-width: @{breakPoint880}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint760After}) and (max-width: @{breakPoint880}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (min-width: @{breakPoint760After}) and (max-width: @{breakPoint880}),\"\r\n    ~\"@{tabletHiDpiStandardsLandscape}       and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{tabletHiDpiWebKitLandscape}          and (max-width: @{tenInchTabletMinLandscapeWidthBefore})\";\r\n\r\n// \"Big Tablet Landscape / Desktop FatButton\"\r\n// Note that tablets are capped at this breakpoint (there is no max-width for them here) and portrait tablet are not here at all as they\r\n// will never hit this breakpoint in portrait.\r\n@Responsive880To980:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint880After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint880After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint880After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint880After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint880After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (min-width: @{breakPoint880After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{tabletHiDpiStandardsLandscape}       and (min-width: @{tenInchTabletMinLandscapeWidth}),\"\r\n    ~\"@{tabletHiDpiWebKitLandscape}          and (min-width: @{tenInchTabletMinLandscapeWidth})\";\r\n\r\n// 2014-01-23 DWR: There is no mention of the \"wide\" breakpoint here, that exists only as a \"ResponsiveWide\" value. The logic being that\r\n// we are introducing a guideline that the \"default site appearance\" should never be targetted by media queries so that legacy browsers\r\n// (IE7 and 8) which do not support media queries always see the default site. If there were ranges such as \"ResponsiveToWide\" or\r\n// \"Responsive480ToWide\" then there would be media queries affecting the default site layout, which is not allowed.\r\n\r\n// ===============================================================================================\r\n// Extended/ranged media query bands\r\n// - These are combinations of the above criteria (eg. instead of ResponsiveTo320 and\r\n//   Responsive320To480, it may be useful to target ResponsiveTo480)\r\n// - These should be taken by combining criteria from above, ensure that any changes made there\r\n//   are always reflected here\r\n// ===============================================================================================\r\n// Extended/ranged media query bands: From 0px\r\n// ===============================================================================================\r\n// Note that these ranged brackets (that effectively start from 0px and go up to at least 480px) will always contain HiDpi phones, regardless\r\n// of resolution or orientation since they may only ever go into the 320 or 480 breakpoints and these brackets covers both of thoses\r\n@ResponsiveTo480:\r\n    ~\"@{desktopStandardsLandscape}           and (max-width: @{breakPoint480}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (max-width: @{breakPoint480}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (max-width: @{breakPoint480}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait}  and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait}     and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneHiDpiStandardsLandscape},\"\r\n    ~\"@{phoneHiDpiStandardsPortrait},\"\r\n    ~\"@{phoneHiDpiWebKitLandscape},\"\r\n    ~\"@{phoneHiDpiWebKitPortrait}\";\r\n\r\n// The 560 breakpoint only applies to desktop targets, so the LowDpi phone/tablet targets only go up to @breakPoint480 here\r\n@ResponsiveTo560:\r\n    ~\"@{desktopStandardsLandscape}           and (max-width: @{breakPoint560}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (max-width: @{breakPoint560}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (max-width: @{breakPoint560}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (max-width: @{breakPoint560}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait}  and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait}     and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneHiDpiStandardsLandscape},\"\r\n    ~\"@{phoneHiDpiStandardsPortrait},\"\r\n    ~\"@{phoneHiDpiWebKitLandscape},\"\r\n    ~\"@{phoneHiDpiWebKitPortrait}\";\r\n\r\n@ResponsiveTo760:\r\n    ~\"@{desktopStandardsLandscape}           and (max-width: @{breakPoint760}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (max-width: @{breakPoint760}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (max-width: @{breakPoint760}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (max-width: @{breakPoint760}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait},\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait},\"\r\n    ~\"@{tabletHiDpiStandardsPortrait},\"\r\n    ~\"@{tabletHiDpiWebKitPortrait},\"\r\n    ~\"@{phoneHiDpiStandardsLandscape},\"\r\n    ~\"@{phoneHiDpiStandardsPortrait},\"\r\n    ~\"@{phoneHiDpiWebKitLandscape},\"\r\n    ~\"@{phoneHiDpiWebKitPortrait}\";\r\n\r\n@ResponsiveTo880:\r\n    ~\"@{desktopStandardsLandscape}           and (max-width: @{breakPoint880}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (max-width: @{breakPoint880}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (max-width: @{breakPoint880}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (max-width: @{breakPoint880}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait},\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait},\"\r\n    ~\"@{tabletHiDpiStandardsLandscape}       and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{tabletHiDpiWebKitLandscape}          and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{tabletHiDpiStandardsPortrait},\"\r\n    ~\"@{tabletHiDpiWebKitPortrait},\"\r\n    ~\"@{phoneHiDpiStandardsLandscape},\"\r\n    ~\"@{phoneHiDpiStandardsPortrait},\"\r\n    ~\"@{phoneHiDpiWebKitLandscape},\"\r\n    ~\"@{phoneHiDpiWebKitPortrait}\";\r\n\r\n// The only device that needs a width cap is the desktop; all others (phones and tablets - regardless of resolution, orientation or\r\n// dpi) will be within this range that goes all the way from 0px (effectively) to 980px\r\n@ResponsiveTo980:\r\n    ~\"@{desktopStandardsLandscape}           and (max-width: @{breakPoint980}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (max-width: @{breakPoint980}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (max-width: @{breakPoint980}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (max-width: @{breakPoint980}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape},\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait},\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape},\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait},\"\r\n    ~\"@{tabletHiDpiStandardsLandscape},\"\r\n    ~\"@{tabletHiDpiStandardsPortrait},\"\r\n    ~\"@{tabletHiDpiWebKitLandscape},\"\r\n    ~\"@{tabletHiDpiWebKitPortrait},\"\r\n    ~\"@{phoneHiDpiStandardsLandscape},\"\r\n    ~\"@{phoneHiDpiStandardsPortrait},\"\r\n    ~\"@{phoneHiDpiWebKitLandscape},\"\r\n    ~\"@{phoneHiDpiWebKitPortrait}\";\r\n\r\n// ===============================================================================================\r\n// Extended/ranged media query bands: From 320px\r\n// ===============================================================================================\r\n@Responsive320To560:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint560}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint560}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint560}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint560}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait}  and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait}     and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneHiDpiStandardsLandscape}        and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiStandardsPortrait}         and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiWebKitLandscape}           and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiWebKitPortrait}            and (min-width: @{breakPoint320After})\";\r\n\r\n@Responsive320To760:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint760}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint760}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint760}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint760}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait}  and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait}     and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiStandardsPortrait}         and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiWebKitLandscape}           and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiWebKitPortrait}            and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{tabletHiDpiStandardsPortrait},\"\r\n    ~\"@{tabletHiDpiWebKitPortrait}\";\r\n\r\n@Responsive320To880:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint880}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint880}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint880}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint880}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait}  and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (min-width: @{breakPoint320After}) and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait}     and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiStandardsLandscape}        and (min-width: @{breakPoint320After}) and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{phoneHiDpiStandardsPortrait}         and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiWebKitLandscape}           and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiWebKitPortrait}            and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{tabletHiDpiStandardsLandscape}                                              and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{tabletHiDpiWebKitLandscape}                                                 and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{tabletHiDpiStandardsPortrait},\"\r\n    ~\"@{tabletHiDpiWebKitPortrait}\";\r\n\r\n@Responsive320To980:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait}  and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait}     and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiStandardsLandscape}        and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiStandardsPortrait}         and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiWebKitLandscape}           and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiWebKitPortrait}            and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{tabletHiDpiStandardsLandscape},\"\r\n    ~\"@{tabletHiDpiStandardsPortrait},\"\r\n    ~\"@{tabletHiDpiWebKitLandscape},\"\r\n    ~\"@{tabletHiDpiWebKitPortrait}\";\r\n\r\n// ===============================================================================================\r\n// Extended/ranged media query bands: From 480px\r\n// ===============================================================================================\r\n@Responsive480To760:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint480After}) and (max-width: @{breakPoint760}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint480After}) and (max-width: @{breakPoint760}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint480After}) and (max-width: @{breakPoint760}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint480After}) and (max-width: @{breakPoint760}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint480After}) and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait}  and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (min-width: @{breakPoint320After}) and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait}     and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiStandardsLandscape}        and (min-width: @{breakPoint320After}) and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{phoneHiDpiStandardsPortrait}         and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiWebKitLandscape}           and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiWebKitPortrait}            and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{tabletHiDpiStandardsPortrait},\"\r\n    ~\"@{tabletHiDpiWebKitPortrait}\";\r\n\r\n@Responsive480To880:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint480After}) and (max-width: @{breakPoint880}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint480After}) and (max-width: @{breakPoint880}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint480After}) and (max-width: @{breakPoint880}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint480After}) and (max-width: @{breakPoint880}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait}  and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (min-width: @{breakPoint320After}) and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait}     and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiStandardsLandscape}        and (min-width: @{breakPoint320After}) and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{phoneHiDpiStandardsPortrait}         and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiWebKitLandscape}           and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiWebKitPortrait}            and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{tabletHiDpiStandardsLandscape}                                              and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{tabletHiDpiWebKitLandscape}                                                 and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{tabletHiDpiStandardsPortrait},\"\r\n    ~\"@{tabletHiDpiWebKitPortrait}\";\r\n\r\n@Responsive480To980:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint480After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint480After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint480After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint480After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint320After}) and (max-width: @{breakPoint480}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait}  and (min-width: @{breakPoint480After}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (min-width: @{breakPoint480After}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait}     and (min-width: @{breakPoint480After}),\"\r\n    ~\"@{phoneHiDpiStandardsLandscape}        and (min-width: @{breakPoint480After}),\"\r\n    ~\"@{phoneHiDpiStandardsPortrait}         and (min-width: @{breakPoint480After}),\"\r\n    ~\"@{phoneHiDpiWebKitLandscape}           and (min-width: @{breakPoint480After}),\"\r\n    ~\"@{phoneHiDpiWebKitPortrait}            and (min-width: @{breakPoint480After}),\"\r\n    ~\"@{tabletHiDpiStandardsLandscape},\"\r\n    ~\"@{tabletHiDpiStandardsPortrait},\"\r\n    ~\"@{tabletHiDpiWebKitLandscape},\"\r\n    ~\"@{tabletHiDpiWebKitPortrait}\";\r\n\r\n// ===============================================================================================\r\n// Extended/ranged media query bands: From 560px\r\n// ===============================================================================================\r\n@Responsive560To880:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint560After}) and (max-width: @{breakPoint880}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint560After}) and (max-width: @{breakPoint880}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint560After}) and (max-width: @{breakPoint880}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint560After}) and (max-width: @{breakPoint880}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint560After}) and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait}  and (min-width: @{breakPoint560After}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (min-width: @{breakPoint560After}) and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait}     and (min-width: @{breakPoint560After}),\"\r\n    ~\"@{tabletHiDpiStandardsLandscape}                                              and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{tabletHiDpiWebKitLandscape}                                                 and (max-width: @{tenInchTabletMinLandscapeWidthBefore}),\"\r\n    ~\"@{tabletHiDpiStandardsPortrait},\"\r\n    ~\"@{tabletHiDpiWebKitPortrait}\";\r\n\r\n@Responsive560To980:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint560After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint560After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint560After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint560After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint560After}) and (min-width: @{tenInchTabletMinLandscapeWidth}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait}  and (min-width: @{breakPoint560After}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (min-width: @{breakPoint560After}) and (min-width: @{tenInchTabletMinLandscapeWidth}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait}     and (min-width: @{breakPoint560After}),\"\r\n    ~\"@{tabletHiDpiStandardsLandscape},\"\r\n    ~\"@{tabletHiDpiStandardsPortrait},\"\r\n    ~\"@{tabletHiDpiWebKitLandscape},\"\r\n    ~\"@{tabletHiDpiWebKitPortrait}\";\r\n\r\n// ===============================================================================================\r\n// Extended/ranged media query bands: From 760px\r\n// ===============================================================================================\r\n@Responsive760To980:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint760After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint760After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint760After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint760After}) and (max-width: @{breakPoint980}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint760After}) and (min-width: @{tenInchTabletMinLandscapeWidth}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (min-width: @{breakPoint760After}) and (min-width: @{tenInchTabletMinLandscapeWidth}),\"\r\n    ~\"@{tabletHiDpiStandardsLandscape},\"\r\n    ~\"@{tabletHiDpiWebKitLandscape}\";\r\n\r\n// ===============================================================================================\r\n// Extended/ranged media query bands: Above\r\n// IMPORTANT: The \"wide\" breakpoint does NOT apply to most of these \"Above\" ranges since that\r\n// would mean that a media query overlaps the \"default\" view, which is a no-no (since styles\r\n// might be applied in it which the default view then relies upon, which will cause problems\r\n// in IE7 and 8 as they don't support media queries)\r\n// ===============================================================================================\r\n// This covers a lot; I started with @Responsive320To980 and then removed any upper limits on width.\r\n// Includes: Mobile, DesktopMidPoint480To560, TabletPortrait, SmallTabletLandscape, LargeTabletLandscape\r\n@ResponsiveAbove320:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait}  and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait}     and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiStandardsLandscape}        and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiStandardsPortrait}         and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiWebKitLandscape}           and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{phoneHiDpiWebKitPortrait}            and (min-width: @{breakPoint320After}),\"\r\n    ~\"@{tabletHiDpiStandardsLandscape},\"\r\n    ~\"@{tabletHiDpiStandardsPortrait},\"\r\n    ~\"@{tabletHiDpiWebKitLandscape},\"\r\n    ~\"@{tabletHiDpiWebKitPortrait}\";\r\n\r\n// Above 480 counts out HiDpi phones entirely (it also counts out LowDpi phones but they're grouped into the same category as LowDpi tablets).\r\n// I started with @ResponsiveAbove320, bumped up the min-width values and removed the devices that wouldn't be affected.\r\n// Includes: DesktopMidPoint480To560, TabletPortrait, SmallTabletLandscape, LargeTabletLandscape\r\n@ResponsiveAbove480:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint480After}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint480After}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint480After}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint480After}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint480After}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsPortrait}  and (min-width: @{breakPoint480After}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (min-width: @{breakPoint480After}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitPortrait}     and (min-width: @{breakPoint480After}),\"\r\n    ~\"@{tabletHiDpiStandardsLandscape},\"\r\n    ~\"@{tabletHiDpiStandardsPortrait},\"\r\n    ~\"@{tabletHiDpiWebKitLandscape},\"\r\n    ~\"@{tabletHiDpiWebKitPortrait}\";\r\n\r\n// Includes: TabletPortrait, SmallTabletLandscape, LargeTabletLandscape\r\n@ResponsiveAbove560:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint560After}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint560After}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint560After}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint560After}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint760After}) and (min-width: @{tenInchTabletMinLandscapeWidth}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (min-width: @{breakPoint760After}) and (min-width: @{tenInchTabletMinLandscapeWidth}),\"\r\n    ~\"@{tabletHiDpiStandardsLandscape},\"\r\n    ~\"@{tabletHiDpiStandardsPortrait},\"\r\n    ~\"@{tabletHiDpiWebKitLandscape},\"\r\n    ~\"@{tabletHiDpiWebKitPortrait}\";\r\n\r\n// Includes: SmallTabletLandscape, LargeTabletLandscape\r\n@ResponsiveAbove760:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint760}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint760}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint760}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint760}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint760After}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (min-width: @{breakPoint760After}),\"\r\n    ~\"@{tabletHiDpiStandardsLandscape},\"\r\n    ~\"@{tabletHiDpiWebKitLandscape}\";\r\n\r\n// Includes: LargeTabletLandscape\r\n@ResponsiveAbove880:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint880}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint880}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint880}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint880}),\"\r\n    ~\"@{phoneTabletLowDpiStandardsLandscape} and (min-width: @{breakPoint760After}) and (min-width: @{tenInchTabletMinLandscapeWidth}),\"\r\n    ~\"@{phoneTabletLowDpiWebKitLandscape}    and (min-width: @{breakPoint760After}) and (min-width: @{tenInchTabletMinLandscapeWidth}),\"\r\n    ~\"@{tabletHiDpiStandardsLandscape}                                              and (min-width: @{tenInchTabletMinLandscapeWidth}),\"\r\n    ~\"@{tabletHiDpiWebKitLandscape}                                                 and (min-width: @{tenInchTabletMinLandscapeWidth})\";\r\n\r\n@ResponsiveAbove980:\r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPoint980}),\"\r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPoint980}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPoint980}),\"\r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPoint980})\";\r\n\r\n// 2014-01-23 DWR: This is the only place that the \"wide\" breakpoint exists since any other media query range would go against the \"no\r\n// media query should affect the default site appearance\" guideline. This is another easy range since it only applies to desktop devices.\r\n@ResponsiveWidestBreak: \r\n    ~\"@{desktopStandardsLandscape}           and (min-width: @{breakPointWide}),\" \r\n    ~\"@{desktopStandardsPortrait}            and (min-width: @{breakPointWide}),\"\r\n    ~\"@{desktopWebKitLandscape}              and (min-width: @{breakPointWide}),\" \r\n    ~\"@{desktopWebKitPortrait}               and (min-width: @{breakPointWide})\";";
            string content = "a:hover { color: blue; }\r\n //silly comment \r\n //in multiple lines\r\n.RoundedCorners (@radius: 4px) { border-radius: @radius; } ";

            var individualContentFragments = LessCssHierarchicalParser.ParseIntoStructuredData(
                Parser.ParseLESS(content)
                );

            Assert.Equal(2, individualContentFragments.Count());
            Assert.Equal(3, individualContentFragments.ElementAt(1).SourceLineIndex);
        }
Esempio n. 2
0
        /// <summary>
        /// Apply a CSS string to a control.
        /// </summary>
        /// <param name="parent">The control to apply to.</param>
        /// <param name="cssString">The CSS content.</param>
        private static void ApplyInternal(object parent, string cssString)
        {
            var result = LessCssHierarchicalParser.ParseIntoStructuredData(Parser.ParseLESS(cssString));

            foreach (Selector fragment in result)
            {
                foreach (ContainerFragment.WhiteSpaceNormalisedString selector in fragment.Selectors)
                {
                    foreach (var item in fragment.ChildFragments)
                    {
                        var controls = GetControlsBySelector(parent, selector.Value);
                        foreach (object control in controls)
                        {
                            if (control != null && item is StylePropertyValue styleProp)
                            {
                                SetProp(control, styleProp.Property.Value, styleProp.ValueSegments.Aggregate((x, y) => x + " " + y));
                            }
                        }
                    }
                }

                void SetProp(object target, string property, string valueString)
                {
                    if (valueString == "")
                    {
                        return;
                    }
                    valueString = valueString.Trim();
                    var    prop = target.GetType().GetProperty(property, BindingFlags.Public | BindingFlags.Instance);
                    object value;

                    if (prop == null)
                    {
                        return;
                    }
                    var eval = new Interpreter();

                    eval.Reference(prop.PropertyType);
                    value = eval.Eval(valueString);
                    prop.SetValue(target, value);
                }
            }
        }
        /// <summary>
        /// This will throw a BrokenRuleEncounteredInFileException if any of the specified rules are broken
        /// </summary>
        public TextFileContents Load(string relativePath)
        {
            if (string.IsNullOrWhiteSpace(relativePath))
            {
                throw new ArgumentException("Null/blank relativePath specified");
            }

            // Several passes may be required for apply all of the rules - the first pass is to deal with rules that apply to individual files,
            // this is dealt with by wrapping the specified contentLoader in a CallbackMakingTextFileLoader and applying the rules as each file
            // is loaded. The callback from each Load call is also used to build up a representation of the combined content across all of the
            // files (before any processing or compilation work has been applied to the content). Subsequent passes (further down) will process
            // rules that apply to combined or compiled content.
            var loadedContentBuilder    = new StringBuilder();
            var rulesForIndividualFiles = _rules.Where(r =>
                                                       r.DoesThisRuleApplyTo(StyleSheetTypeOptions.Reset) ||
                                                       r.DoesThisRuleApplyTo(StyleSheetTypeOptions.Themes) ||
                                                       r.DoesThisRuleApplyTo(StyleSheetTypeOptions.Other)
                                                       );
            var individualFileValidatingAndTrackingContentLoader = new CallbackMakingTextFileLoader(
                _baseContentLoader,
                content =>
            {
                if (content == null)
                {
                    throw new ArgumentNullException("content");
                }

                // Apply the rules for individual files (if any)
                if (rulesForIndividualFiles.Any())
                {
                    var individualContentFragments = LessCssHierarchicalParser.ParseIntoStructuredData(
                        Parser.ParseLESS(content.Content)
                        );
                    var styleSheetType = _styleSheetTypeDeterminer(content.RelativePath);
                    foreach (var ruleForIndividualFiles in rulesForIndividualFiles)
                    {
                        if (ruleForIndividualFiles.DoesThisRuleApplyTo(styleSheetType))
                        {
                            // If there's no callback then we're in the "throw as soon as validation rule broken" mode. If there IS a
                            // callback then we want to gather ALL validation rule breaks and pass them to the caller
                            if (_optionalBrokenFileCallback == null)
                            {
                                try
                                {
                                    ruleForIndividualFiles.EnsureRulesAreMet(individualContentFragments);
                                }
                                catch (BrokenRuleEncounteredException e)
                                {
                                    throw new BrokenRuleEncounteredInFileException(e, styleSheetType, content.RelativePath);
                                }
                            }
                            else
                            {
                                foreach (var brokenRule in ruleForIndividualFiles.GetAnyBrokenRules(individualContentFragments))
                                {
                                    _optionalBrokenFileCallback(
                                        new BrokenRuleEncounteredInFileException(brokenRule, styleSheetType, content.RelativePath)
                                        );
                                }
                            }
                        }
                    }
                }

                // Build up the combined content (I don't expect that parallel requests will be going on but considering the amount of
                // processing that will be going on with the rules validation, a tiny overhead from locking here for safety will have
                // no significant negative impact)
                lock (loadedContentBuilder)
                {
                    // Using AppendLine rather than Append means that if any files have a single-line comment (eg. "// Comment") on
                    // their last line then the content will be correctly interpreted as a comment when the combined content is
                    // parsed (otherwise the first line of the next file will end up on the same line as the comment and some
                    // of it may be incorrectly identified as comment content)
                    loadedContentBuilder.AppendLine(content.Content);
                }
            }
                );

            // Process the content by retrieving an ITextFileLoader through the provided compilerGenerator, using the content loader above
            // that will deal with individual-file rules and generate combined content for use below
            var compiler = _compilerGenerator(individualFileValidatingAndTrackingContentLoader);

            if (compiler == null)
            {
                throw new Exception("The provided compiledGenerator returned null - this is not valid");
            }
            var compiledContent = compiler.Load(relativePath);

            // The source content has all been processed in terms of import flattening, LESS compilation (and the various other actions)
            // but rules that apply to Combined and Compiled content haven't been yet.
            // - If there are any rules that apply to Compiled content then the compiled content is parsed and the data passed through
            //   each applicable rule
            var rulesForCompiledContent = _rules.Where(r => r.DoesThisRuleApplyTo(StyleSheetTypeOptions.Compiled));

            if (rulesForCompiledContent.Any())
            {
                var compiledContentFragments = LessCssHierarchicalParser.ParseIntoStructuredData(
                    Parser.ParseLESS(compiledContent.Content)
                    );
                foreach (var ruleForCompiledContent in rulesForCompiledContent)
                {
                    // If there's no callback then we're in the "throw as soon as validation rule broken" mode. If there IS a
                    // callback then we want to gather ALL validation rule breaks and pass them to the caller
                    if (_optionalBrokenFileCallback == null)
                    {
                        try
                        {
                            ruleForCompiledContent.EnsureRulesAreMet(compiledContentFragments);
                        }
                        catch (BrokenRuleEncounteredException e)
                        {
                            throw new BrokenRuleEncounteredInFileException(e, StyleSheetTypeOptions.Combined, relativePath);
                        }
                    }
                    else
                    {
                        foreach (var brokenRule in ruleForCompiledContent.GetAnyBrokenRules(compiledContentFragments))
                        {
                            _optionalBrokenFileCallback(
                                new BrokenRuleEncounteredInFileException(brokenRule, StyleSheetTypeOptions.Combined, relativePath)
                                );
                        }
                    }
                }
            }

            // Similarly rules for Combined content are processed (the combined content is retrieved from the ContentRecordingTextFileLoader)
            var rulesForCombinedContent = _rules.Where(r => r.DoesThisRuleApplyTo(StyleSheetTypeOptions.Combined));

            if (rulesForCombinedContent.Any())
            {
                string combinedContent;
                lock (loadedContentBuilder)
                {
                    combinedContent = loadedContentBuilder.ToString();
                }
                if (combinedContent != "")
                {
                    var combinedContentFragments = LessCssHierarchicalParser.ParseIntoStructuredData(
                        Parser.ParseLESS(combinedContent)
                        );
                    foreach (var ruleForCombinedContent in rulesForCombinedContent)
                    {
                        // If there's no callback then we're in the "throw as soon as validation rule broken" mode. If there IS a
                        // callback then we want to gather ALL validation rule breaks and pass them to the caller
                        if (_optionalBrokenFileCallback == null)
                        {
                            try
                            {
                                ruleForCombinedContent.EnsureRulesAreMet(combinedContentFragments);
                            }
                            catch (BrokenRuleEncounteredException e)
                            {
                                throw new BrokenRuleEncounteredInFileException(e, StyleSheetTypeOptions.Combined, relativePath);
                            }
                        }
                        else
                        {
                            foreach (var brokenRule in ruleForCombinedContent.GetAnyBrokenRules(combinedContentFragments))
                            {
                                _optionalBrokenFileCallback(
                                    new BrokenRuleEncounteredInFileException(brokenRule, StyleSheetTypeOptions.Combined, relativePath)
                                    );
                            }
                        }
                    }
                }
            }

            // Now that the rules validation process is complete, the compiled content can be returned
            return(compiledContent);
        }