Categories
Design Software

From color perception to CSS

Color perception

The way humans perceive colors is not universal. Rather, we are capable of comparing and contrasting colors according to individually understood criteria of similarity, sameness, or distinctness. Moreover, even the choice of specific colors in the spectrum is an individual feature.

It is known that colors have a structure based on three primary colors and their combinations. After all, it is an interesting observation that only the concepts of lightness (white) and darkness (black) are basically universal, and also, if there is one, red color including reds, oranges, as well as yellows, pinks and purples up to filberts. An analysis of color naming in various languages indicates that languages distinguishing six colors have names for the light, dark, red, green, yellow, and blue.

Art perception theory [1] treats shape and color separately. Shape is indicated as a feature that better identifies the object and reveals more numerous qualitative features. Color, on the other hand, depends more on the environment, such as lighting, e.g., strong light makes reds appear brighter, while dim light serves blues and greens.

The basic concepts used in color theory are primary and complementary colors. However, a distinction has to be made between fundamental primary colors, i.e., the pure colors on which the perception of colors is built, and simple generative colors, i.e. the colors needed to gain a wide range of tones in a physical sense.

All color systems assume that a certain small number of tones is enough to obtain a full, or at least a wide color gamut. According to Hering’s color theory [2], humans have sensitivity to the colors black and white, blue and yellow, and green and red. The trichromatic Young-Helmholtz theory [4], on the other hand, assumes the existence of three basic generative colors: red, green, and filbert. Finally, in the 20th century, it was confirmed that pigments on retinal receptors respond to three wavelengths: 447 nm (blue-violet), 540 nm (green), and 577 nm (yellow).

Color theory further indicates that which colors will best form a wide range of colors depends on the method of combination: whether by addition (additive combination) or subtraction (subtractive combination). With additive combining, the eye perceives the sum of the waves (e.g., those emitted by a screen), and with subtractive combining, the impression of color is caused by the remainder left over after light absorption (e.g., stained glass).

To conclude this section, let us recall the concept of complementarity. Generative complementaries are those which, combined, produce monochromatic whites or grays, and fundamental complementaries are which, in perception, desire and complement each other. For example, Helmholz gives as complementary pairs red and blue green, yellow and blue, and green and pink red.

Want to become a part of #espeocrew? Check our current job offers and apply!

from color perception to css

Color models

RYB

Historically, RYB is the first color model based on the discoveries of Isaac Newton. The generative colors in this model are red, yellow, and blue. The model was patented in 1719 by Jacob Christoph Le Blon. The RYB model is a subtractive one and was used for printing on white paper. RYB pigments combined together produce black. The colors that are generated by mixing the base pigments include orange (red with yellow), green (yellow with blue), and purple (blue with red).

RGB

The RGB model creates a gamut from the primary generative colors: red, green, and blue. Zero intensity of each component defines black, while the full intensity of the generative colors gives white. Equal intensity of all the components produces gray. Color ranges are defined in several ways: from 0 to 1, with any fractional value in between, or as unsigned integers ranging from 0 to 255, (8-bit). High-end digital imaging equipment often uses larger ranges, such as 10, 16, or 24 bits. In practice, for the use on monitors, printers, and the World Wide Web, the sRGB standard created by HP and Microsoft in 1996 is used.

CMY (CMYK)

The CMY model uses cyan, magenta, and yellow as the primary generative colors. The colors in the possible palette are obtained by layering the producing colors. When cyan, magenta, and yellow inks are combined, the result (in theory) is black. In practice, however, this combination results in a dark gray or dark brown. Therefore, in practical solutions, the color black is added to this model (CMYK model). It is also possible to achieve the so-called deep black by mixing generative colors and adding black. In this model, the color white is treated as no color (C0 M0 Y0 K0). The colors of the RGB model are obtained by mixing magenta with cyan (blue), magenta with yellow (red), and cyan with yellow (green), respectively.

Furthermore, the generative colors of the CMY model are obtained by combining the corresponding colors of the RGB model: red with green gives yellow, green with blue gives cyan, and blue with red gives magenta.

The RYB, RGB, and CMY models can be graphically described as cubic models: generative colors are placed on the X, Y and Z axes of length 1, and a color is defined as a point with three coordinates. Note that in the above models, it is difficult to define the concepts of color intensity, brightness or saturation. Other models are used for this purpose.

HSL/HSV

The HSL color model was developed in 1938 by Georges Valensi as a method of adding color coding to existing monochrome transmissions containing only the L signal. The model uses the parameters hue from the RGB model, saturation, and lightness. The angular coordinate starts at red (angle 0°), then passes through green (angle 120°) and blue (angle 240°) before returning to red (angle 360°). The distance from the cylinder axis defines the saturation. The vertical axis is achromatic or gray, ranging from white with a brightness of 1 o black with a brightness of 0. Primary and secondary colors red, yellow, green, cyan, blue, and magenta are arranged around the outer edge of the cylinder with the saturation value of 1. However, in this model, lightness is quite meaningless [3]. Colors can have the same lightness value, with wildly different perceptual lightness.

CIE L*a*b*

The CIE LAB model (also Lab) is a color model defined in 1976 by the International Commission on Illumination (CIE). It expresses color by indicating three values: brightness (L) and a* and b* for the four colors recognized by the eye: red, green, blue, and yellow. CIE L*a*b* was designed to be a perceptually uniform space in which the numerical change corresponds to the corresponding perceived color change. It is used to detect small differences in color.

CIE L*a*b* is a device-independent model of the standard observer. Colors refer to the averaged results of color matching experiments under laboratory conditions. The CIE L*a*b* space is three-dimensional and covers the entire range of color perception. It is based on the model of complementary colors. The brightness value (L) defines black at 0 and white at 100. The a* axis refers to the green-red complementary colors, with values negative toward green and positive toward red. The b* axis represents the blue-yellow complements with negative toward blue and positive toward yellow. CIE L*a*b* is calculated with respect to white. Although the a* and b* axes are unbounded, software implementations often limit these values for practical reasons, such as limiting a* and b* to integers in the range of -128 to 127.

LCH

To solve the problem of HSL model lightness, one can use the LCH model. The first argument specifies the CIE Lightness (L), interpreted as Lightness argument of Lab. The second is the chroma, understood as the amount of color, starting a 0 and maximum theoretically unbounded, but practically not exceeding 230. The third argument is the hue angle interpreted similarly to the hue on HSL, with 0° along the positive a* axis (red), 90° pointing along the positive b* axis (yellow), 180° along the negative a* axis (green), and 270° along the negative b* (blue). If the chroma is set to 0%, the hue component can be omitted. If the lightness of an LCH color is 0%, both the hue and chroma components matter.

from color perception to css

Cascading StyleSheet color evolution

Let us now trace the evolution of color support in successive versions of the Cascading Style Sheets (CSS) specifications. The first version of the specification [5] was published in late 1996. Basic CSS support was provided by Internet Explorer 3, but only IE4, which was released in late 1997, correctly supported CSS1. Later implementations, such as in Netscape 4, had numerous bugs, leading it to be thought that CSS itself was flawed. Finally, in 1996, CSS1 was recommended as the standard.

CSS1

Color in CSS1 [5] is either a keyword or an RGB numeric specification. CSS1 supported 16 colors derived from the Windows VGA palette (aqua, black, blue, fuchsia, gray, green, lime, maroon, navy, olive, purple, red, silver, teal, white, and yellow). However, their RGB values are not defined. The RGB color model was used in numeric color specifications. The format for hexadecimal RGB values included the # character followed by three or six hexadecimal characters. The three-digit RGB notation #rgb is converted to the six-digit #rrggbb by duplicating digits rather than by adding zeros, such as #abc converts to #aabbcc. The functional notation rgb() is also specified, which gives a comma-separated list of three numeric values in the range 0-255 or three percentage values in the range 0% to 100%. RGB colors are specified in the sRGB color space.

CSS2

In the next version of the specification [6], the color orange was added to the color list, and numerical values were defined for the colors in the palette:

maroon #800000
red #ff0000
orange #ffA500
yellow #ffff00
olive #808000
purple #800080
fuchsia #ff00ff
white #ffffff
lime #00ff00
green #008000
navy #000080
blue #0000ff
aqua #00ffff
teal #008080
black #000000

In the next version of CSS2.2 released in 2016 [7], the specification remained unchanged.

CSS Color Module 3

Unlike CSS 2, which is a specification that defines a variety of features, CSS3 was broken up into separate documents (modules). The CSS Color Module Level 3 [8], recommended as a valid specification in 2018, has been extracted from the specification.

CSS Color 3 introduces the concept of opacity taking values from 0 (fully transparent) to 1 (fully opaque), and the RGB color model has been extended with an alpha channel to the RGBA model to allow color opacity to be specified. The rgba() function was added to the functional notation to allow the opacity value to be written as the last parameter.

CSS Color 3 extends the color value with the transparent keyword, and allows it to be used in all properties that take a color value. It also extends the color list to the X11COLORS list with the addition of gray variants from SVG 1.0.

CSS Color 3 adds support for the HSL model in addition to numeric RGB colors, and the conversion from HSL to sRGB is purely mathematical. The functional notation hsl() has an equivalent that supports the alpha channel — hsla().

Are you a Front-end Developer looking for new career opportunities? Check out our open job positions and apply!

CSS Color Module Level 4

Subsequent drafts [9] of the CSS Color Module specification extends definitions of color and color space.

Color is understood as a numerical or textual definition of human perception of light or a physical object illuminated by light. The color of an object depends on how much light it reflects at each visible wavelength and the actual color of the light illuminating it, while the color of a light-emitting object such as the colors on a computer screen, depends on the amount of light emitted at each visible wavelength. Color comparisons are made by converting spectra to the CIE XYZ scale — an additive color space with luminance as the Y component.

CSS Color 4 also defines the term color space as the organization of colors with respect to a basic colorimetric model, so that there is a clear, objectively measurable meaning for each color in that color space. It also means that the same color can be expressed in multiple color spaces or transformed from one color space to another and still look the same.

CSS Color 4 also uses the concept of chromaticity as a measure of color in which the brightness component has been subtracted.

CSS Color 4 adds to the already existing color functions rgb(), rgba(), hsl(), hsla() new ones: hwb(), lab(), lch(), oklab(), oklch(), and color(). Of these, hsl(), hsla(), hwb(), lch(), and oklch() are cylindrical polar color representations, specifying color using the hue angle, a central axis representing brightness (black to white), and a radius representing saturation or chromaticity, i.e., how far the color is from neutral gray.

The color() function allows to specify a color in a color space other than sRGB, in which most other functions operate. These include P3, Adobe RGB (1998), ProPhoto RGB, or Rec. 2020.

CSS Color 4 also covers the issue of color interpolation, which occurs in gradients, compositions, filters, transitions, animations, and color mixing and modification functions. It is done by linear interpolation of each component of a calculated color value separately, in a specified color space. In some cases, the result of physically mixing two colored lights is desired. In such a case, the linear CIE XYZ or sRGB color space is appropriate because they are linear in light intensity. However, if the colors must be perceptually uniform (e.g., in a gradient), then it is reasonable to use Lab/OKLab spaces, which are perceptually uniform. To avoid maximizing chromaticity, the use of LCH/OKLCH is recommended, and for compatibility with older web content, the sRGB color space should be chosen.

from color perception to css

CSS Color Module 5

The next draft [10] of the specification adds two new functions: color-mix() and color-contrast().

The first one mixes two colors in the given space in the given proportions. The following algorithm is used: both colors are converted to the required color space, and then the colors are interpolated. If an alpha multiplier was created during percentage normalization, the alpha component of the result is multiplied by the alpha multiplier.

The second function takes as parameters a single color, a list of two or more colors, and, optionally, a target luminance contrast. The single color is separated from the list by the vs keyword, and the target contrast, if any, is separated from the list by the to keyword. The first color that meets or exceeds the target contrast value is then selected from this list. If no target value is specified, the first color with the highest contrast relative to a single color is selected.

Follow us on Instagram for more insights from our experts!

Final remarks

According to MDN [11], CSS Color 3 is rather fully implemented in the modern web browsers. However, the CSS Color 4 and CSS Color 5 recommendations, which are still in development, are implemented partially, e.x., color(), lab(), and lch() functions are available in Safari browser, while color-mix() or color-contrast() are not available at all. 

And while color is a key element of good graphic design, still not all graphic designers’ ideas can be supported in web applications. Despite its rapid development, color in the Web still has a long way to go.

References and further reading

[1] R. Arnheim, Art and Visual Perception. A psychology of the creative eye, California 1974.

[2] E. Hering, Zur Lehre vom Lichtsinn, Vienna 1878.

[3] https://lea.verou.me/2020/04/lch-colors-in-css-what-why-and-how/

[4] T. Young, Bakerian Lecture: On the Theory of Light and Colours. Phil. Trans. R. Soc. Lond. (1802) 92, pp.12–48.

[5] Cascading Style Sheets, level 1, https://www.w3.org/TR/CSS1/

[6] Cascading Style Sheets Level 2 Revision 1, https://www.w3.org/TR/CSS2/

[7] Cascading Style Sheets Level 2 Revision 2, https://www.w3.org/TR/CSS22/

[8] CSS Color Module Level 3, https://www.w3.org/TR/css-color-3/

[9] CSS Color Module Level 4, https://www.w3.org/TR/2022/WD-css-color-4-20220428/

[10] CSS Color Module Level 5, https://www.w3.org/TR/2022/WD-css-color-5-20220428/

[11] https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#browser_compatibility

Categories
Design Software

How to organise a successful digital workshop

Although digital workshops and events have been known in the past, it was the global pandemic that accelerated their popularity among companies and corporations. As more and more people started working from home, organizations had to find ways to make people collaborate effectively despite the distance between them.

Aside from virtual meetings and planning sessions, digital workshops are by far one of the most productive collaboration methods, used both in-house and while working with external clients.

As virtual workshops can bring a significant value to an organization, we want to share our tips on how to run them successfully.

From this article, you will learn about:

Check out also: Identifying the best digital investments: Use Cases

First things first – what is a digital workshop?

The term ‘digital workshop’ refers to an event that takes place virtually with a group of participants discussing specific topics and interacting with each other, the host, and program content. Compared with in-person conferences or trainings, online workshops usually focus on topics in greater depth. As a result, topics can be viewed more objectively, and the host and participants are encouraged to interact more.

Reasons for hosting a workshop online

There are many reasons for hosting digital workshops. Below we share some of them:

  • Online presentations, workshops, and training sessions are increasingly popular in an increasingly globalized world.
  • By arranging a workshop online, you can save a lot of money. The reason for this is that many of the costs (e.g. accommodation, treats, workshop materials) are not necessary.
  • Workshop members from different sites can work efficiently together in a distributed environment.
  • The ability to proceed with workshops or meetings despite difficult circumstances, such as staff illness, travel bans, and environmental concerns.

What obstacles you might encounter while preparing a virtual workshop and how to overcome them?

Before organising a digital workshop, it is important to consider the following:

First of all, a digital workshop should first be designed to engage participants and create a trusting environment.

To achieve this, you may want to establish some rules before the workshop (e.g. that each participant should have a camera on, say something about themselves beforehand etc.). Additionally, everyone should feel safe and comfortable to initiate a conversation. This is why asking short questions that are easy to answer and checking up on the participants is vital.

Secondly, you need to look for tools that fit the needs of the workshop.

Some of the most popular online meeting tools include Zoom, Google Hangouts, and Teams. A good idea is to mix different working methods during the workshop. Consider using sticky notes, dividing participants into smaller groups, ways to answer the potential questions that might arise etc. To facilitate a successful digital workshop, it is recommended that you use tools for:

  • Note-taking
  • Screen sharing
  • File transfers
  • Chatting
  • Voting

Something to highlight is that as a workshop facilitator, you should feel like you have control and understanding of the tools you are using.

Ideation. Gaining advantage with the ideas of the Espeo Consulting team

What about the participants’ attention during digital workshops?

Generally speaking, it is good to prepare a script that identifies each step of the digital workshop (and the tool to utilize a particular step). Then, it is crucial to make sure that everyone is aware of those steps.

Moreover, it is worth testing both the script and the tools before the workshop takes place. Well-chosen tools as well as engaging workshop script should be able to hold people’s focus and attention during the whole virtual workshop. A good idea is to have a plan that consists of short video calls and smaller interventions. By doing so, participants in the workshop will remain more focused.

Lastly, set clear expectations for the digital workshop you are facilitating.

Having clear goals in mind is a must when organising a successful digital workshop. This way, you and the rest of the workshop members are involved in the process and know exactly what you want to accomplish. This step is achievable with a proper structure and preparation.

Successful digital workshop with Laboratorium Marzeń

Recently, we have conducted a successful product design workshop with a Polish foundation called Laboratorium Marzeń. The foundation focuses on helping families with premature infants and children who require special attention.

They had an idea for a mobile app that would help parents with navigation of their kids’ development and day-to-day lives.

We decided to utilize our experience and expertise in UX to help the foundation design the app in a way that focused on the actual needs of potential users and their struggles.

“We started working on our application with a vision of what needs it should respond to but we had no idea how to go about it. The workshop with Mr. Maciej from Espeo Software was an amazing journey that took us from the initial idea of ​​the application to a real prototype, which exceeded our wildest expectations. Professionalism, creativity, commitment and a focus on the needs of potential users at every stage of the cooperation were the characteristics that we valued the most at Espeo.”

Jolanta Uchman, Co-Founder of Laboratorium Marzeń foundation

You can read more about the structure and the course of the workshop here.

Would you like to organize a product design workshop for your business? Use the contact form below and we will come back to you to discuss the details.

Categories
Design Healthcare Software Technology

Caring for premature babies and infants who require special attention: mobile app for a daily development navigation

Laboratorium Marzeń is a non-profit organization based in Poznań, Poland founded by Jolanta Uchman and Jolanta Żółkiewska. Together, they focus on helping families with premature infants and children who require special attention.

So far, Laboratorium Marzeń used e-books and events to promote their organization’s activities. Nevertheless, they had an idea for a mobile app that would help parents with navigation of their kids’ development and day-to-day lives.

With our experience and expertise in UX, we decided to take their idea and turn it into a reality as a pro bono project. For this reason, we helped the foundation with designing the app with a strong focus on the actual needs of the potential users and the struggles that they go through.

From this article you will learn:

Laboratorium Marzeń - Caring for premature babies: mobile app for daily development navigation

Laboratorium Marzeń – taking a step back from the mobile app specification

A long list of specifications and modules were provided by Laboratorium Marzeń. To figure out which features would be the most impactful, we decided to step back and focus on the needs of the possible users. The following steps helped us achieve that:

  1. Firstly, we conducted two interviews with parents and one with a specialist in the field – Jolanta Uchman.
  2. Secondly, we organised a mini Google Design Sprint workshop in which. Jolanta Uchman and Joanna Żółkiewska were the participants.
  3. Thirdly, we created a very interactive prototype of the app.
  4. At the end, we conducted two usability tests of the prototype.

How product design workshop helped us focus our ideas on UX

Because of the current situation, we hosted the UX workshop online. Thanks to the use of proper methodology, we managed to get the most out of the three hours that we had planned for the meeting.

Summary of user interviews10 min
Comparable problem15 min
“How Might We” and affinity mapping10 min
Current Experience Mapping15 min
Break10 min
User Journey Mapping15 min
Importance/Difficulty Matrix15 min
Solution Sketch20-30 min
Sprint methods used during the workshop


To begin the process, we analysed the interviews with parents of a premature child and a child with a Down Syndrome. Then, we focused on current experience mapping. We emphasised the first moment when a user’s need occurs and listed out each step that they go through to try and fill their need currently. We included descriptions for each step and highlighted pain points.

Laboratorium Marzeń - Caring for premature babies: mobile app for daily development navigation

After evaluating comparable problems, each participant created a user journey map which started at a discovery point – where the user does not use the app yet but learns about its existence. Along this process, more “How Might We” cards were created.

Laboratorium Marzeń - Caring for premature babies: mobile app for daily development navigation
Laboratorium Marzeń - Caring for premature babies: mobile app for daily development navigation

The next stages consisted of affinity mapping and creating a difficulty matrix of the “How Might We” sticky notes. Important parts of those stages were categorizing the cards and answering the question of “What if our app doesn’t have it, will it still be useful for users?”. This way, we created a list of the most crucial and urgent features.

Laboratorium Marzeń – UX Affinity mapping

The last step before working on the actual prototype was to draw a mock-up of what the user should see at some points of his journey by each participant of the workshop.

Laboratorium Marzeń - Caring for premature babies: mobile app for daily development navigation
Laboratorium Marzeń - Caring for premature babies: mobile app for daily development navigation
Laboratorium Marzeń - Caring for premature babies: mobile app for daily development navigation

Prototyping the solution and getting the users feedback

Based on the conclusions from the interviews and our findings from the UX workshop, we created an interactive prototype of the app. In addition, we asked the interviewed parents to test it and give us their feedback. The response was astonishing. One user kept repeating how amazing the prototype was.

The reaction of the interviewed parents confirmed that our app for Laboratorium Marzeń will change lives of families with premature babies and children who have special needs. Moreover, thanks to the first-hand insights, we could carry out some minor improvements.

More than a regular app design

The founders of Laboratorium Marzeń didn’t have any previous experience with mobile development. Because of that, the role of our UX Designer wasn’t solely limited to the design part. To provide the best service possible, Maciej used his experience in application planning and prioritization as well as in assessment of implementation difficulties and optimizing the costs of feature maintenance.

As a result of our cooperation, Laboratorium Marzeń has gained a clear image of the most important pain points to address. Therefore, they now have a list of functionalities that the first version of the app should include. The final design of the app itself, which we were in charge of creating, is currently in the final stages of the development process.

“We started working on our application with a vision of what needs it should respond to but we had no idea how to go about it. The workshop with Mr. Maciej from Espeo Software was an amazing journey that took us from the initial idea of ​​the application to a real prototype, which exceeded our wildest expectations. Professionalism, creativity, commitment and a focus on the needs of potential users at every stage of the cooperation were the characteristics that we valued the most at Espeo.”

Jolanta Uchman, co-founder of Laboratorium Marzeń

Do you want us to help you with the UX of your mobile app? Use the contact form below and one of our colleagues will come back to you shortly.

Categories
Design Software Technology

Microinteractions: The Power of Animations in Android Apps

Good design is simple and informative, but apps can also be beautiful and sophisticated. Steve Jobs said details mattered and one opportunity to capture a user’s attention is to communicate with them via the details. Here is where microinteractions comes into play.

Microinteractions are the small details that make interacting with an electronic device more natural and pleasant. One example of such microinteractions are animations and we will focus on them here.

Microinteractions: Animations in Android Apps

We will show you how to improve your app with easy but useful animations in Android apps. Before showing examples, we will discuss what you can gain by adding microinteractions to your app.

Animations improve communication and make it easier to understand what is happening on the device. They make an app more pleasurable to use and give the impression of a well-built app.  This in turn will make your users use your app more often, and be more active and involved with it. Consequently, they will use your app for longer, increasing your retention rate as well making it more likely they will recommend it to their friends and increasing your user numbers.

These are advantages of microinteractions so it’s time to see some examples!

Like Animation

Many apps have likable content. To make “giving likes” more interesting and friendly you can add animation like the one used by Instagram. This is the simplest way to start with microinteractions. See below:

Microinteractions: The Power of Animations in Android Apps

Removing & Inserting Items on a List

Sometimes we want to remove or insert items on a list. The worst thing is having to refresh the entire list even after only one change. It’s much better to animate only the items which have changed. See below:

Microinteractions: The Power of Animations in Android Apps

Transition Animation Framework

A lot of apps have lists containing images as well. To make browsing more pleasant, a very good option is to follow Material Design guidelines and use animation in transition between views.

Microinteractions: The Power of  Animations in Android Apps

Smooth App Bar Layout

If your app has scrollable content with an image at its start, you can use another Material Design solution, which is an app bar with a parallax effect. It can be very useful for things such as a user’s profile.

Microinteractions: The Power of Animations in Android Apps

Loading Button

Many apps use buttons to download content and experience shows that users like to know that something is happening once they have pressed a button. There are various ways this can be done but one of the most effective is the one we use which is to create an animation to show the user the current state of the app.

Microinteractions: The Power of Animations in Android Apps

Summary

Microinteractions are a very important part of building apps. Users expect apps which to resolve problems, provide value or give some kind of entertainment. Users appreciate well-built apps with clear and enjoyable designs. They also often express the pleasure they derive from graphics and animations, and which rarely occur in a mobile app.

The examples shown above are quick and simple to implement and are extremely worthwhile doing. As mentioned above apps with animations have a big advantage over others and provide an easy and proven method of getting users involved with your service and improving your app rates and stats.

Interested in more tips for Android apps? Check out our article Android App Development – Trends for 2018 

You have a mobile idea. We have the needed experience to get you there. Check out our services: Mobile App Development

[contact-form-7 id=”13387″ title=”Contact download_8_reasons”]