No Time Dad

A blog about web development written by a busy dad

Responsive Blog Starter Template with CSS

I’ve been having an internal struggle with using Tailwindcss. There are many things that make Tailwind appealing to me. But there are also some things that make me want to write vanilla css. I can’t make up my mind about using Tailwind long-term and if it’s right for me.

Recently, I wrote a couple blog posts on building a responsive blog starter template with Tailwind. It wasn’t hard. Tailwind made it quite enjoyable, in fact. There’s no denying that using Tailwind’s utility classes is faster than writing out all of the css by hand. But, I still somehow felt like I wanted to write the css myself.

So, I thought it would be fun to re-create the blog starter template I previously created with Tailwind in vanilla css. I was curious if it would give me an answer on which version I liked creating more. Spoiler: it did not. But, I still enjoyed creating it anyways, and it was nice to get into writing css again.

Part one of the tailwind responsive blog starter template can be found here, and part two can be found here. The full demo from those parts can be found here.

The final code and demo of this vanilla css version of the responsive blog starter template can be viewed here.

Getting started

Similar to some other examples I’ve done recently, I wrote this responsive blog starter template with React. I like to break up large pages into smaller components because I think it’s easier to explain each section in a blog post, and the smaller components often make more sense to me if I read over the code again in a few months time. With that being said, I don’t use any state, click handlers, or any other React features in this example, so it can be easily translated to vanilla html or another web framework.

I’m not going to dive too deep into each section since much of the code is just unwrapping Tailwind’s utility classes, but there are some interesting differences in some of that components that I think are worth pointing out.

Container component

Similar to the Tailwind version of the template, all of the components sit inside of a parent container component. One difference here is that I used this container as an opportunity to define some css custom properties that I used in a few places throughout the template. Defining custom properties is easy in plain css, but a little more cumbersome in Tailwind since I’d need to modify tailwind.config.js. But to be fair, I’ve only needed customer properties a handlful of times when using Tailwind. It’s packed with features.

// BlogTemplateComponent.jsx
import React from 'react';
import * as styles from './index.module.css';
import cyclist from './cyclist.jpg';

const Index = () => (
  <div className={styles.Container}>
    <HeaderSection />
    <HeroSection />
    <BlogPostsSection />
    <FooterSection />
  </div>
);
/* index.module.css */
.Container {
  --shared-text-color: #2a2e2e;
  --shared-link-opacity: 0.8;
  --shared-light-background: #f3f3f3;
}
...

Compared to the Tailwind version:

const Index = () => (
  <>
    <HeaderSection />
    <HeroSection />
    <BlogPostsSection />
    <FooterSection />
  </>
);
Header section

Structurally, the HeaderSection markup in the Tailwind version and the vanilla css version is the same. In fact, this is pretty much the case for most of the sections. I tried to match the colors the best I could but I didn’t use Tailwind’s exact color palette, so they’re slightly off. Not a huge deal.

One of the things I changed in the HeaderSection in the vanilla css version is the spacing between the nav elements, particularly for small screens when the nav links are stacked in a column. In the Tailwind version I used the space-y-2 utility class, but that wasn’t an option for this version. Sure, I could’ve just copied the css but that somehow felt like cheating.

What I ended up doing instead was initializing a single column grid and using gap to add space between the elements. At first, I was skeptical about this approach but it seems to work well.

// BlogTemplateComponent.jsx
...
const HeaderSection = () => (
  <div className={styles.Header}>
    <a href="#home" className={styles.Header__Title}>Cycle Blog</a>
    <nav className={styles.Header__Nav}>
      <a className={styles.Nav__Link} href="#home">Home</a>
      <a className={styles.Nav__Link} href="#about">About</a>
      <a className={styles.Nav__Link} href="#contact">Contact</a>
      <a className={styles.Nav__Link} href="#projects">Projects</a>
    </nav>
  </div>
);
/* index.module.css */
...
.Header {
  padding: 1rem;
}

.Header__Title {
  font-size: x-large;
  font-weight: 800;
  color: var(--shared-text-color);
  text-decoration: none;
}

.Header__Title:hover {
  opacity: var(--shared-link-opacity);
}

.Header__Nav {
  display: grid;
  gap: 8px;
  padding-top: 1rem;
}

.Header__Nav > a {
  text-decoration: none;
  color: var(--shared-text-color);
  font-weight: 600;
}

.Header__Nav > a:hover {
  opacity: var(--shared-link-opacity);
}

Compared to the Tailwind version:

const HeaderSection = () => (
  <div className="flex flex-col p-4 md:flex-row md:items-center md:justify-between md:px-16">
    <a href="#home" className="text-2xl font-bold no-underline text-gray-800 hover:text-gray-600">Cycle Blog</a>
    <nav className="flex flex-col pt-4 space-y-2 md:flex-row md:space-y-0 md:space-x-3 md:pt-0">
      <a className="no-underline text-gray-800 hover:text-gray-600 font-semibold" href="#home">Home</a>
      <a className="no-underline text-gray-800 hover:text-gray-600 font-semibold" href="#about">About</a>
      <a className="no-underline text-gray-800 hover:text-gray-600 font-semibold" href="#contact">Contact</a>
      <a className="no-underline text-gray-800 hover:text-gray-600 font-semibold" href="#projects">Projects</a>
    </nav>
  </div>
);
Hero section

The hero section added some new challenges. I noticed immediately that the line spacing Tailwind uses was much tighter than what I had. I don’t think I’ve actually used the line-height property until this point, so it was fun to try it out. Admittedly, I added the property and tinkered with the values to get it working instead of researching on MDN like a good developer.

I also employed the same display: grid and gap: 10px trick from the HeaderSection. I’m sure this technique has it’s drawbacks that will probably bite me when I least expect it, but it works for now.

// BlogTemplateComponent.jsx
...
const HeroSection = () => (
  <div className={styles.Hero}>
    <div>
      <div className={styles.Hero__Header_Text}>A blog about cycling</div>
      <div className={styles.Hero__Header_Sub_Text}>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
      </div>
    </div>
    <img className={styles.Hero__Image} src={cyclist} alt="cyclist" />
  </div>
);
...
/* index.module.css */
...
.Hero {
  display: grid;
  gap: 10px;
  background-color: var(--shared-light-background);
  padding: 1rem;
}

.Hero__Header_Text {
  font-size: 36px;
  font-weight: 900;
  line-height: 1.1;
  padding-bottom: 1rem;
}

.Hero__Header_Sub_Text {
  opacity: var(--shared-link-opacity);
}

.Hero__Image {
  border-radius: 0.5rem;
}
...

Compared to the Tailwind version:

const HeroSection = () => (
  <div className="bg-gray-100 p-4 space-y-3 md:grid md:grid-cols-2 md:gap-2 md:py-10 md:px-16">
    <div className="space-y-2">
      <div className="text-4xl font-extrabold">A blog about cycling</div>
      <div className="opacity-70">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
    </div>
    <img className="max-w-full h-auto rounded-md" src={cyclist} alt="cyclist" />
  </div>
);
Blog posts section

The most difficult part of this section for me was the More and Next buttons at the bottom. I really don’t like making buttons. It always takes me a few tries to get the sizing right, and making the focus state look nice is a headache for me. I really appreciate Tailwind making this easy for me. I spent more time than I’d like to admit on the buttons.

I know I said I wasn’t going to just copy the Tailwind css, but I couldn’t resist for box-shadow. I think the look of theirs is great. It just has the right amount of shadow to make a card stand out but not draw the eye in too much.

// BlogTemplateComponent.jsx
...
const BlogPostsSection = () => (
  <div className={styles.Blog_Posts}>
    <div className={styles.Blog_Posts__Header}>Posts</div>
    <div className={styles.Blog_Posts__Content}>
      {[...Array(10)].map((_, i) => <BlogPostCard key={i} />)}
    </div>
    <div className={styles.Blog_Posts__Pagination}>
      <BackButton />  
      <MoreButton />
    </div>
  </div>
);

const MoreButton = () => (
  <button className={styles.Button}>
    More
    <ArrowSmRightSvg />
  </button>
);

const BackButton = () => (
  <button className={styles.Button}>
    <ArrowSmLeftSvg />
    Back
  </button>
);

const BlogPostCard = () => (
  <div className={styles.Blog_Post}>
    <div className={styles.Blog_Post__Header}></div>
    <div className={styles.Blog_Post__Content}>
      <a href="#post" className={styles.Blog_Post__Title}>Lorem ipsum</a>
      <div className={styles.Blog_Post__Date}>Jan 21, 2021</div>
      <div>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor...
      </div>
    </div>
  </div>
);

const ArrowSmRightSvg = () => <svg xmlns="http://www.w3.org/2000/svg" className={styles.Button__Icon} viewBox="0 0 20 20" fill="currentColor">
  <path fillRule="evenodd" d="M10.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L12.586 11H5a1 1 0 110-2h7.586l-2.293-2.293a1 1 0 010-1.414z" clipRule="evenodd" />
</svg>

const ArrowSmLeftSvg = () => <svg xmlns="http://www.w3.org/2000/svg" className={styles.Button__Icon} viewBox="0 0 20 20" fill="currentColor">
  <path fillRule="evenodd" d="M9.707 14.707a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 1.414L7.414 9H15a1 1 0 110 2H7.414l2.293 2.293a1 1 0 010 1.414z" clipRule="evenodd" />
</svg>
...
/* index.module.css */
...
.Blog_Posts {
  display: grid;
  gap: 21px;
  padding: 1rem;
  padding-bottom: 3rem;
}

.Blog_Posts__Header {
  font-size: 24px;
  font-weight: 600;
  padding-bottom: 1rem;
  padding-top: 1rem;
}

.Blog_Posts__Pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
}


/* Blog Post Card */
.Blog_Post {
  box-shadow: 0 0 #0000, 0 0 #0000, 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  border-radius: 0.5rem;
}

.Blog_Post:hover {
  transform: translateY(-5px);
}

.Blog_Post__Header {
  width: 100%;
  height: 9rem;
  background-color: var(--shared-light-background);
  border-top-left-radius: 0.5rem;
  border-top-right-radius: 0.5rem;
}

.Blog_Post__Content {
  display: grid;
  gap: 5px;
  padding: 0.5rem;
}

.Blog_Post__Title {
  font-weight: 600;
  font-size: 20px;
  text-decoration: none;
  color: var(--shared-text-color);
}

.Blog_Post__Title:hover {
  opacity: var(--shared-link-opacity);
}

.Blog_Post__Date {
  opacity: var(--shared-link-opacity);
}

.Button {
  display: flex;
  align-items: center;
  background-color: #fff;
  border-color: #dbdbdb;
  border-width: 1px;
  color: #363636;
  border-radius: 0.5rem;
  padding: 1rem 1.5rem;
}

.Button:hover {
  border-color: #b5b5b5;
  color: #363636;
}

.Button:focus {
  outline: none;
  border-color: #485fc7;
  color: #363636;
  box-shadow: 0 0 0 0.125em rgba(72, 95, 199, 0.25);
}

.Button__Icon {
  width: 18px;
  height: 18px;
}
...

Compared to the Tailwind version:

const BlogPostsSection = () => (
  <div className="p-4 md:px-16">
    <div className="text-2xl font-bold py-4">Posts</div>
    <div className="space-y-6 md:space-y-0 md:grid md:grid-cols-2 lg:grid-cols-3 md:gap-4">
      {[...Array(10)].map((_, i) => <Post key={i} />)}
    </div>
    <div className="flex justify-between pt-6">
      <PreviousButton />
      <NextButton />
    </div>
  </div>
);

const Post = () => (
  <div className="shadow-md rounded-br-md rounded-bl-md hover:shadow-lg">
    <a href="#blog-post" className="no-underline">
      <div className="max-w-full h-36 bg-gray-200 rounded-tr-md rounded-tl-md"></div>
    </a>
    <div className="p-2 space-y-1">
      <a href="#blog-post" className="text-xl font-bold no-underline text-gray-800 hover:text-gray-600">Lorem ipsum</a>
      <div className="opacity-70">Jan 21, 2021</div>
      <div className="opacity-85">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor...</div>
    </div>
  </div>
);

const NextButton = () => (
  <button type="button" className="flex-shrink-0 border border-gray-500 text-base font-semibold py-2 px-4 rounded-lg shadow-md hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 focus:ring-offset-gray-200">
    <div className="flex items-center">
      More
      <ArrowSmRightSvg />
    </div>
  </button>
);

const PreviousButton = () => (
  <button type="button" className="flex-shrink-0 border border-gray-500 text-base font-semibold py-2 px-4 rounded-lg shadow-md hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 focus:ring-offset-gray-200">
    <div className="flex items-center">
      <ArrowSmLeftSvg />
      Back
    </div>
  </button>
);

const ArrowSmRightSvg = () => <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 ml-2" viewBox="0 0 20 20" fill="currentColor">
  <path fillRule="evenodd" d="M10.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L12.586 11H5a1 1 0 110-2h7.586l-2.293-2.293a1 1 0 010-1.414z" clipRule="evenodd" />
</svg>

const ArrowSmLeftSvg = () => <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
  <path fillRule="evenodd" d="M9.707 14.707a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 1.414L7.414 9H15a1 1 0 110 2H7.414l2.293 2.293a1 1 0 010 1.414z" clipRule="evenodd" />
</svg>
Footer section

The footer section was the easiest section to make in both versions of the responsive blog starter template. I applied the grid and gap trick again here to handle the spacing, but otherwise the two versions are mostly the same.

// BlogTemplateComponent.jsx
...
const FooterSection = () => (
  <div className={styles.Footer}>
    <a href="#home" className={styles.Footer__Header}>Cycle Blog</a>
    <div className={styles.Footer__Sub_Text}>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
    <div className={styles.Footer__Icons}>
      <a href="#email" aria-label="email"><EmailSvg /></a>
      <a href="#message" aria-label="chat"><ChatSvg /></a>
      <a href="#call" aria-label="phone"><PhoneSvg /></a>
    </div>
  </div>
);

const EmailSvg = () => <svg xmlns="http://www.w3.org/2000/svg" className={styles.Footer__Icon} viewBox="0 0 20 20" fill="currentColor">
  <path fillRule="evenodd" d="M14.243 5.757a6 6 0 10-.986 9.284 1 1 0 111.087 1.678A8 8 0 1118 10a3 3 0 01-4.8 2.401A4 4 0 1114 10a1 1 0 102 0c0-1.537-.586-3.07-1.757-4.243zM12 10a2 2 0 10-4 0 2 2 0 004 0z" clipRule="evenodd" />
</svg>

const ChatSvg = () => <svg xmlns="http://www.w3.org/2000/svg" className={styles.Footer__Icon} fill="none" viewBox="0 0 24 24" stroke="currentColor">
  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M17 8h2a2 2 0 012 2v6a2 2 0 01-2 2h-2v4l-4-4H9a1.994 1.994 0 01-1.414-.586m0 0L11 14h4a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2v4l.586-.586z" />
</svg>

const PhoneSvg = () => <svg xmlns="http://www.w3.org/2000/svg" className={styles.Footer__Icon} fill="none" viewBox="0 0 24 24" stroke="currentColor">
  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>
...
/* index.module.css */
...
.Footer {
  display: grid;
  gap: 10px;
  padding: 1rem;
  background-color: var(--shared-light-background);
}

.Footer__Header {
  text-decoration: none;
  color: var(--shared-text-color);
  font-size: 36px;
  font-weight: 800;
}

.Footer__Header:hover {
  opacity: var(--shared-link-opacity);
}

.Footer__Sub_Text {
  opacity: var(--shared-link-opacity);
}

.Footer__Icons {
  display: flex;
}

.Footer__Icon {
  width: 24px;
  height: 24px;
  color: var(--shared-text-color);
  margin-right: 0.5rem;
}

.Footer__Icon:hover {
  opacity: var(--shared-link-opacity);
}
...

Compared to the Tailwind version:

const FooterSection = () => (
  <div className="bg-gray-100 p-4 space-y-3 md:px-16 md:py-10">
    <a href="#home" className="text-4xl font-extrabold no-underline text-gray-800 hover:text-gray-600">Cycle Blog</a>
    <div className="opacity-70">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
    <div className="flex items-center space-x-2">
      <a href="#email" aria-label="email"><EmailSvg /></a>
      <a href="#chat" aria-label="chat"><ChatSvg /></a>
      <a href="#phone" aria-label="call"><PhoneSvg /></a>
    </div>
  </div>
);

const EmailSvg = () => <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6 text-gray-600 hover:text-gray-800" viewBox="0 0 20 20" fill="currentColor">
  <path fillRule="evenodd" d="M14.243 5.757a6 6 0 10-.986 9.284 1 1 0 111.087 1.678A8 8 0 1118 10a3 3 0 01-4.8 2.401A4 4 0 1114 10a1 1 0 102 0c0-1.537-.586-3.07-1.757-4.243zM12 10a2 2 0 10-4 0 2 2 0 004 0z" clipRule="evenodd" />
</svg>

const ChatSvg = () => <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6 text-gray-600 hover:text-gray-800" fill="none" viewBox="0 0 24 24" stroke="currentColor">
  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M17 8h2a2 2 0 012 2v6a2 2 0 01-2 2h-2v4l-4-4H9a1.994 1.994 0 01-1.414-.586m0 0L11 14h4a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2v4l.586-.586z" />
</svg>

const PhoneSvg = () => <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6 text-gray-600 hover:text-gray-800" fill="none" viewBox="0 0 24 24" stroke="currentColor">
  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>

Conclusion

So, is using Tailwind over writing css better? Unfortunately, I don’t have the answer yet. It’s obviously faster and less code to use Tailwind’s utility classes, but I can’t decide if that makes it better. There have been more than a few times recently where I had to modify tailwind.config.js to add custom selectors, but it wasn’t difficult, just slightly annoying.

I know one of Tailwind’s big claims is that “you never have to leave your html file”, and I guess it never really occurred to me that this was actually a problem. Maybe that’s just personal preference, though. I typically switch between files using a keyboard shortcuts, which is quick. I’ve just always done it this way because I know it saves a lot of time.

I think what I might need to do is to take an existing template or element written using Tailwind and make changes to it. Add a new feature to it or modify an existing feature on the page. That way I can see how difficult it is to maintain and extend Tailwind’s utility class system. Stay tuned for that, I guess.

Final code & demo

The full demo of this version of the respsonsive blog starter template can be viewed here. Try resizing the browser window to see how it responds.

// package.json
...
"react": "^17.0.2",
...
// BlogTemplateComponent.jsx
import React from 'react';
import * as styles from './index.module.css';
import cyclist from './cyclist.jpg';

const Index = () => (
  <div className={styles.Container}>
    <HeaderSection />
    <HeroSection />
    <BlogPostsSection />
    <FooterSection />
  </div>
);

const HeaderSection = () => (
  <div className={styles.Header}>
    <a href="#home" className={styles.Header__Title}>Cycle Blog</a>
    <nav className={styles.Header__Nav}>
      <a className={styles.Nav__Link} href="#home">Home</a>
      <a className={styles.Nav__Link} href="#about">About</a>
      <a className={styles.Nav__Link} href="#contact">Contact</a>
      <a className={styles.Nav__Link} href="#projects">Projects</a>
    </nav>
  </div>
);

const HeroSection = () => (
  <div className={styles.Hero}>
    <div>
      <div className={styles.Hero__Header_Text}>A blog about cycling</div>
      <div className={styles.Hero__Header_Sub_Text}>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
      </div>
    </div>
    <img className={styles.Hero__Image} src={cyclist} alt="cyclist" />
  </div>
);

const BlogPostsSection = () => (
  <div className={styles.Blog_Posts}>
    <div className={styles.Blog_Posts__Header}>Posts</div>
    <div className={styles.Blog_Posts__Content}>
      {[...Array(10)].map((_, i) => <BlogPostCard key={i} />)}
    </div>
    <div className={styles.Blog_Posts__Pagination}>
      <BackButton />  
      <MoreButton />
    </div>
  </div>
);

const MoreButton = () => (
  <button className={styles.Button}>
    More
    <ArrowSmRightSvg />
  </button>
);

const BackButton = () => (
  <button className={styles.Button}>
    <ArrowSmLeftSvg />
    Back
  </button>
);

const BlogPostCard = () => (
  <div className={styles.Blog_Post}>
    <div className={styles.Blog_Post__Header}></div>
    <div className={styles.Blog_Post__Content}>
      <a href="#post" className={styles.Blog_Post__Title}>Lorem ipsum</a>
      <div className={styles.Blog_Post__Date}>Jan 21, 2021</div>
      <div>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor...
      </div>
    </div>
  </div>
);

const FooterSection = () => (
  <div className={styles.Footer}>
    <a href="#home" className={styles.Footer__Header}>Cycle Blog</a>
    <div className={styles.Footer__Sub_Text}>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
    <div className={styles.Footer__Icons}>
      <a href="#email" aria-label="email"><EmailSvg /></a>
      <a href="#message" aria-label="chat"><ChatSvg /></a>
      <a href="#call" aria-label="phone"><PhoneSvg /></a>
    </div>
  </div>
);

const EmailSvg = () => <svg xmlns="http://www.w3.org/2000/svg" className={styles.Footer__Icon} viewBox="0 0 20 20" fill="currentColor">
  <path fillRule="evenodd" d="M14.243 5.757a6 6 0 10-.986 9.284 1 1 0 111.087 1.678A8 8 0 1118 10a3 3 0 01-4.8 2.401A4 4 0 1114 10a1 1 0 102 0c0-1.537-.586-3.07-1.757-4.243zM12 10a2 2 0 10-4 0 2 2 0 004 0z" clipRule="evenodd" />
</svg>

const ChatSvg = () => <svg xmlns="http://www.w3.org/2000/svg" className={styles.Footer__Icon} fill="none" viewBox="0 0 24 24" stroke="currentColor">
  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M17 8h2a2 2 0 012 2v6a2 2 0 01-2 2h-2v4l-4-4H9a1.994 1.994 0 01-1.414-.586m0 0L11 14h4a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2v4l.586-.586z" />
</svg>

const PhoneSvg = () => <svg xmlns="http://www.w3.org/2000/svg" className={styles.Footer__Icon} fill="none" viewBox="0 0 24 24" stroke="currentColor">
  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>

const ArrowSmRightSvg = () => <svg xmlns="http://www.w3.org/2000/svg" className={styles.Button__Icon} viewBox="0 0 20 20" fill="currentColor">
  <path fillRule="evenodd" d="M10.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L12.586 11H5a1 1 0 110-2h7.586l-2.293-2.293a1 1 0 010-1.414z" clipRule="evenodd" />
</svg>

const ArrowSmLeftSvg = () => <svg xmlns="http://www.w3.org/2000/svg" className={styles.Button__Icon} viewBox="0 0 20 20" fill="currentColor">
  <path fillRule="evenodd" d="M9.707 14.707a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 1.414L7.414 9H15a1 1 0 110 2H7.414l2.293 2.293a1 1 0 010 1.414z" clipRule="evenodd" />
</svg>

export default Index;
/* index.module.css */
.Container {
  --shared-text-color: #2a2e2e;
  --shared-link-opacity: 0.8;
  --shared-light-background: #f3f3f3;
}

/* Header */
.Header {
  padding: 1rem;
}

.Header__Title {
  font-size: x-large;
  font-weight: 800;
  color: var(--shared-text-color);
  text-decoration: none;
}

.Header__Title:hover {
  opacity: var(--shared-link-opacity);
}

.Header__Nav {
  display: grid;
  gap: 8px;
  padding-top: 1rem;
}

.Header__Nav > a {
  text-decoration: none;
  color: var(--shared-text-color);
  font-weight: 600;
}

.Header__Nav > a:hover {
  opacity: var(--shared-link-opacity);
}

/* Hero */
.Hero {
  display: grid;
  gap: 10px;
  background-color: var(--shared-light-background);
  padding: 1rem;
}

.Hero__Header_Text {
  font-size: 36px;
  font-weight: 900;
  line-height: 1.1;
  padding-bottom: 1rem;
}

.Hero__Header_Sub_Text {
  opacity: var(--shared-link-opacity);
}

.Hero__Image {
  border-radius: 0.5rem;
}


/* Blog posts */
.Blog_Posts {
  display: grid;
  gap: 21px;
  padding: 1rem;
  padding-bottom: 3rem;
}

.Blog_Posts__Header {
  font-size: 24px;
  font-weight: 600;
  padding-bottom: 1rem;
  padding-top: 1rem;
}

.Blog_Posts__Pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
}


/* Blog Post Card */
.Blog_Post {
  box-shadow: 0 0 #0000, 0 0 #0000, 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  border-radius: 0.5rem;
}

.Blog_Post:hover {
  transform: translateY(-5px);
}

.Blog_Post__Header {
  width: 100%;
  height: 9rem;
  background-color: var(--shared-light-background);
  border-top-left-radius: 0.5rem;
  border-top-right-radius: 0.5rem;
}

.Blog_Post__Content {
  display: grid;
  gap: 5px;
  padding: 0.5rem;
}

.Blog_Post__Title {
  font-weight: 600;
  font-size: 20px;
  text-decoration: none;
  color: var(--shared-text-color);
}

.Blog_Post__Title:hover {
  opacity: var(--shared-link-opacity);
}

.Blog_Post__Date {
  opacity: var(--shared-link-opacity);
}


/* Footer section */
.Footer {
  display: grid;
  gap: 10px;
  padding: 1rem;
  background-color: var(--shared-light-background);
}

.Footer__Header {
  text-decoration: none;
  color: var(--shared-text-color);
  font-size: 36px;
  font-weight: 800;
}

.Footer__Header:hover {
  opacity: var(--shared-link-opacity);
}

.Footer__Sub_Text {
  opacity: var(--shared-link-opacity);
}

.Footer__Icons {
  display: flex;
}

.Footer__Icon {
  width: 24px;
  height: 24px;
  color: var(--shared-text-color);
  margin-right: 0.5rem;
}

.Footer__Icon:hover {
  opacity: var(--shared-link-opacity);
}


/* Button */
.Button {
  display: flex;
  align-items: center;
  background-color: #fff;
  border-color: #dbdbdb;
  border-width: 1px;
  color: #363636;
  border-radius: 0.5rem;
  padding: 1rem 1.5rem;
}

.Button:hover {
  border-color: #b5b5b5;
  color: #363636;
}

.Button:focus {
  outline: none;
  border-color: #485fc7;
  color: #363636;
  box-shadow: 0 0 0 0.125em rgba(72, 95, 199, 0.25);
}

.Button__Icon {
  width: 18px;
  height: 18px;
}


/* Media queries */
@media (min-width: 768px) {
  .Header {
    padding-left: 4rem;
    padding-right: 4rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
  }

  .Header__Nav {
    display: flex;
    padding-top: 0;
  }

  .Nav__Link:not(:last-child) {
    margin-right: 16px;
  }

  .Hero {
    padding: 4rem;
    grid-template-columns: 1fr 1fr;
  }

  .Blog_Posts {
    padding-left: 4rem;
    padding-right: 4rem;
  }

  .Blog_Posts__Content {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 18px;
  }

  .Footer {
    padding-left: 4rem;
    padding-right: 4rem;
  }
}

@media (min-width: 1024px) { 
  .Blog_Posts__Content {
    grid-template-columns: 1fr 1fr 1fr;
  }
}