Pure CSSMIT licensed

Promotional Mega Menu with Offer Panel

Commerce navigation with a promotional block beside the links. The design constraint is the interesting part: the promo has to stay subordinate to the navigation, because a panel that is mostly marketing stops doing the job the user opened it for. One offer, one third of the panel, and the categories keep their weight.

Live Demo
Plain CSSTailwind v4
Try it

Nucleo: 44,000+ SVG icons in five families · All Icons Bundle $149

Nucleo · Affiliate link

Get the Nucleo bundle

The code

<section class="mm-20" aria-labelledby="mm-20-title">
  <h2 class="mm-20__sr" id="mm-20-title">Orbit Supply Co.</h2>

  <div class="mm-20__theme">
    <input class="mm-20__theme-input" type="checkbox" id="mm-20-theme">
    <label class="mm-20__theme-label" for="mm-20-theme">
      <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor"/></svg>
      <span class="mm-20__sr">Toggle dark theme</span>
    </label>
  </div>

  <header class="mm-20__header">
    <div class="mm-20__bar">
      <a class="mm-20__brand" href="#mm-20-title">ORBIT<span>supply co.</span></a>

      <nav class="mm-20__nav" aria-label="Primary">
        <ul class="mm-20__list">
          <li class="mm-20__item">
            <button class="mm-20__trigger" type="button" id="mm-20-trigger-shop" aria-expanded="false" aria-controls="mm-20-panel-shop">Shop</button>
            <div class="mm-20__panel" id="mm-20-panel-shop" aria-labelledby="mm-20-trigger-shop">
              <div class="mm-20__cols">
                <section class="mm-20__col" aria-labelledby="mm-20-h-desk">
                  <h3 class="mm-20__col-head" id="mm-20-h-desk">Desk</h3>
                  <ul class="mm-20__links"><li><a href="#mm-20-title">Notebooks</a></li><li><a href="#mm-20-title">Pens and refills</a></li><li><a href="#mm-20-title">Desk mats</a></li><li><a href="#mm-20-title">Organisers</a></li></ul>
                </section>
                <section class="mm-20__col" aria-labelledby="mm-20-h-carry">
                  <h3 class="mm-20__col-head" id="mm-20-h-carry">Carry</h3>
                  <ul class="mm-20__links"><li><a href="#mm-20-title">Backpacks</a></li><li><a href="#mm-20-title">Sleeves</a></li><li><a href="#mm-20-title">Pouches</a></li><li><a href="#mm-20-title">Travel sets</a></li></ul>
                </section>
                <section class="mm-20__col" aria-labelledby="mm-20-h-gift">
                  <h3 class="mm-20__col-head" id="mm-20-h-gift">Gifting</h3>
                  <ul class="mm-20__links"><li><a href="#mm-20-title">Under &pound;40</a></li><li><a href="#mm-20-title">Bundles</a></li><li><a href="#mm-20-title">Gift cards</a></li></ul>
                </section>
              </div>

              <aside class="mm-20__offer" aria-label="Autumn offer">
                <p class="mm-20__offer-tag">Autumn offer</p>
                <p class="mm-20__offer-head">Second notebook half price</p>
                <p class="mm-20__offer-body">On every A5 dot-grid in the Meridian range. Ends Sunday, no code needed.</p>
                <a class="mm-20__offer-cta" href="#mm-20-title">Shop the range</a>
              </aside>
            </div>
          </li>

          <li class="mm-20__item">
            <button class="mm-20__trigger" type="button" id="mm-20-trigger-new" aria-expanded="false" aria-controls="mm-20-panel-new">New in</button>
            <div class="mm-20__panel" id="mm-20-panel-new" aria-labelledby="mm-20-trigger-new">
              <div class="mm-20__cols">
                <section class="mm-20__col" aria-labelledby="mm-20-h-season">
                  <h3 class="mm-20__col-head" id="mm-20-h-season">This season</h3>
                  <ul class="mm-20__links"><li><a href="#mm-20-title">Winter linen range</a></li><li><a href="#mm-20-title">Brass edition pens</a></li><li><a href="#mm-20-title">Archive reprints</a></li></ul>
                </section>
                <section class="mm-20__col" aria-labelledby="mm-20-h-collab">
                  <h3 class="mm-20__col-head" id="mm-20-h-collab">Collaborations</h3>
                  <ul class="mm-20__links"><li><a href="#mm-20-title">Fern Studio</a></li><li><a href="#mm-20-title">Quill Press</a></li></ul>
                </section>
                <section class="mm-20__col" aria-labelledby="mm-20-h-back">
                  <h3 class="mm-20__col-head" id="mm-20-h-back">Back in stock</h3>
                  <ul class="mm-20__links"><li><a href="#mm-20-title">A5 dot grid</a></li><li><a href="#mm-20-title">Card wallet</a></li></ul>
                </section>
              </div>
              <aside class="mm-20__offer" aria-label="Members offer">
                <p class="mm-20__offer-tag">Members</p>
                <p class="mm-20__offer-head">Early access from Thursday</p>
                <p class="mm-20__offer-body">Sign in to shop the winter range 48 hours before general release.</p>
                <a class="mm-20__offer-cta" href="#mm-20-title">Sign in</a>
              </aside>
            </div>
          </li>

          <li class="mm-20__item"><a class="mm-20__plain" href="#mm-20-title">Journal</a></li>
          <li class="mm-20__item"><a class="mm-20__plain" href="#mm-20-title">Stores</a></li>
        </ul>
      </nav>

      <a class="mm-20__cart" href="#mm-20-title">
        <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M6 7h12l-1.2 11H7.2Z" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/><path d="M9.5 7a2.5 2.5 0 0 1 5 0" fill="none" stroke="currentColor" stroke-width="1.8"/></svg>
        Bag <span>2</span>
      </a>
    </div>
  </header>

  <main class="mm-20__page">
    <div class="mm-20__hero">
      <p class="mm-20__kicker">Made in Britain since 2009</p>
      <h1 class="mm-20__h1">Paper worth writing on.</h1>
      <p class="mm-20__sub">120gsm, fountain-pen friendly, bound to lie flat.</p>
      <a class="mm-20__hero-cta" href="#mm-20-title">Shop notebooks</a>
    </div>
  </main>
</section>
.mm-20 {
  --mm-20-bg: #eef2f8;
  --mm-20-surf: #ffffff;
  --mm-20-deep: #10213f;
  --mm-20-line: #10213f;
  --mm-20-soft: #d6dfec;
  --mm-20-ink: #10213f;
  --mm-20-mut: #56668a;
  --mm-20-acc: #f0a202;
  --mm-20-acc: oklch(78% 0.16 78);
  --mm-20-offset: 5px;
  --mm-20-font-display: "Futura", "Century Gothic", "Avenir Next", ui-sans-serif, system-ui, sans-serif;
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  display: block;
  position: relative;
  box-sizing: border-box;
  background: var(--mm-20-bg);
  color: var(--mm-20-ink);
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  line-height: 1.55;
}

.mm-20 *,
.mm-20 *::before,
.mm-20 *::after {
  box-sizing: border-box;
}

.mm-20 :focus-visible {
  outline: 2px solid var(--mm-20-deep);
  outline-offset: 3px;
}

.mm-20__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.mm-20:has(.mm-20__theme-input:checked) {
  --mm-20-bg: #060b16;
  --mm-20-surf: #0d1626;
  --mm-20-deep: #f2f6fc;
  --mm-20-line: #22314c;
  --mm-20-soft: #1a2740;
  --mm-20-ink: #eaf0f9;
  --mm-20-mut: #93a5c2;
  --mm-20-acc: #fbbf24;
  --mm-20-acc: oklch(83% 0.15 80);
}

@media (prefers-color-scheme: dark) {
  .mm-20 {
    --mm-20-bg: #060b16;
    --mm-20-surf: #0d1626;
    --mm-20-deep: #f2f6fc;
    --mm-20-line: #22314c;
    --mm-20-soft: #1a2740;
    --mm-20-ink: #eaf0f9;
    --mm-20-mut: #93a5c2;
    --mm-20-acc: #fbbf24;
    --mm-20-acc: oklch(83% 0.15 80);
  }

  .mm-20:has(.mm-20__theme-input:checked) {
    --mm-20-bg: #eef2f8;
    --mm-20-surf: #ffffff;
    --mm-20-deep: #10213f;
    --mm-20-line: #10213f;
    --mm-20-soft: #d6dfec;
    --mm-20-ink: #10213f;
    --mm-20-mut: #56668a;
    --mm-20-acc: #f0a202;
    --mm-20-acc: oklch(78% 0.16 78);
  }
}

@media (prefers-color-scheme: light) {
  .mm-20:has(.mm-20__theme-input:checked) {
    --mm-20-bg: #060b16;
    --mm-20-surf: #0d1626;
    --mm-20-deep: #f2f6fc;
    --mm-20-line: #22314c;
    --mm-20-soft: #1a2740;
    --mm-20-ink: #eaf0f9;
    --mm-20-mut: #93a5c2;
    --mm-20-acc: #fbbf24;
    --mm-20-acc: oklch(83% 0.15 80);
  }
}

.mm-20__theme {
  position: absolute;
  inset-block-start: clamp(1.5rem, 4vw, 2.2rem);
  inset-inline-end: clamp(0.75rem, 3vw, 1.5rem);
  z-index: 60;
}

.mm-20__theme-input {
  position: absolute;
  opacity: 0;
  inline-size: 100%;
  block-size: 100%;
  margin: 0;
  cursor: pointer;
}

.mm-20__theme-label {
  display: grid;
  place-items: center;
  inline-size: 44px;
  block-size: 44px;
  border: 2px solid var(--mm-20-line);
  background: var(--mm-20-surf);
  color: var(--mm-20-ink);
  cursor: pointer;
  box-shadow: var(--mm-20-offset) var(--mm-20-offset) 0 var(--mm-20-line);
}

.mm-20__theme-label svg {
  inline-size: 20px;
  block-size: 20px;
}

.mm-20__theme-input:focus-visible + .mm-20__theme-label {
  outline: 2px solid var(--mm-20-acc);
  outline-offset: 3px;
}

.mm-20__header {
  position: relative;
  z-index: 10;
  inline-size: min(70rem, calc(100% - 2rem));
  margin: clamp(1rem, 3vw, 1.75rem) auto 0;
}

.mm-20__bar {
  display: flex;
  align-items: center;
  gap: clamp(0.5rem, 2vw, 1.75rem);
  flex-wrap: wrap;
  min-block-size: 68px;
  padding-inline: clamp(0.85rem, 2vw, 1.25rem) 64px;
  border: 2px solid var(--mm-20-line);
  background: var(--mm-20-surf);
}

.mm-20__brand {
  color: var(--mm-20-ink);
  text-decoration: none;
  font: 700 1rem/1 var(--mm-20-font-display);
  letter-spacing: 0.14em;
}

.mm-20__brand span {
  display: block;
  font: 400 0.6rem/1.3 system-ui, sans-serif;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--mm-20-mut);
}

.mm-20__nav {
  min-inline-size: 0;
}

.mm-20__list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem;
  list-style: none;
  margin: 0;
  padding: 0;
  min-inline-size: 0;
}

.mm-20__item {
  position: static;
}

.mm-20__trigger,
.mm-20__plain {
  display: inline-flex;
  align-items: center;
  min-block-size: 44px;
  padding-inline: 0.9rem;
  border: 0;
  background: transparent;
  color: var(--mm-20-ink);
  font: 600 0.88rem/1 var(--mm-20-font-display);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
}

.mm-20__item--open > .mm-20__trigger,
.mm-20__item:hover > .mm-20__trigger,
.mm-20__item:focus-within > .mm-20__trigger {
  background: var(--mm-20-acc);
  color: #10213f;
}

.mm-20__plain:hover,
.mm-20__trigger:hover {
  color: var(--mm-20-mut);
}

.mm-20__cart {
  margin-inline-start: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-block-size: 44px;
  padding-inline: 0.75rem;
  color: var(--mm-20-ink);
  text-decoration: none;
  font: 600 0.8rem/1 var(--mm-20-font-display);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.mm-20__cart svg {
  inline-size: 20px;
  block-size: 20px;
}

.mm-20__cart span {
  display: grid;
  place-items: center;
  inline-size: 20px;
  block-size: 20px;
  border-radius: 999px;
  background: var(--mm-20-acc);
  color: #10213f;
  font-size: 0.7rem;
}

.mm-20__panel {
  position: absolute;
  inset-inline: -2px;
  inset-block-start: 100%;
  z-index: 30;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  border: 2px solid var(--mm-20-line);
  background: var(--mm-20-surf);
  box-shadow: var(--mm-20-offset) var(--mm-20-offset) 0 var(--mm-20-line);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 160ms ease, visibility 0s linear 160ms;
}

@media (min-width: 58rem) {
  .mm-20__panel {
    grid-template-columns: 2fr 1fr;
  }
}

.mm-20__item--open > .mm-20__panel,
.mm-20__item:focus-within > .mm-20__panel {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition-delay: 0s;
}

@media (hover: hover) {
  .mm-20__item:hover > .mm-20__panel {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition-delay: 0s;
  }
}

.mm-20__cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
  gap: clamp(0.75rem, 2.4vw, 1.75rem);
  padding: clamp(1rem, 2.8vw, 1.6rem);
  min-inline-size: 0;
}

.mm-20__col {
  min-inline-size: 0;
}

.mm-20__col-head {
  margin: 0 0 0.4rem;
  padding-block-end: 0.35rem;
  border-block-end: 2px solid var(--mm-20-line);
  font: 700 0.85rem/1.2 var(--mm-20-font-display);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.mm-20__links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1px;
}

.mm-20__links a {
  display: flex;
  align-items: center;
  min-block-size: 44px;
  color: var(--mm-20-ink);
  text-decoration: none;
  font-size: 0.9rem;
  min-inline-size: 0;
}

.mm-20__links a:hover {
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 2px;
}

.mm-20__offer {
  min-inline-size: 0;
  display: grid;
  align-content: start;
  gap: 0.35rem;
  padding: clamp(1rem, 2.8vw, 1.6rem);
  background: var(--mm-20-acc);
  color: #10213f;
}

.mm-20__offer-tag {
  margin: 0;
  font: 700 0.66rem/1 var(--mm-20-font-display);
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

.mm-20__offer-head {
  margin: 0;
  font: 700 clamp(1.1rem, 3vw, 1.35rem)/1.15 var(--mm-20-font-display);
  text-wrap: balance;
}

.mm-20__offer-body {
  margin: 0;
  font-size: 0.86rem;
  text-wrap: pretty;
}

.mm-20__offer-cta {
  justify-self: start;
  margin-block-start: 0.4rem;
  display: inline-flex;
  align-items: center;
  min-block-size: 44px;
  padding-inline: 1rem;
  background: #10213f;
  color: #ffffff;
  text-decoration: none;
  font: 700 0.78rem/1 var(--mm-20-font-display);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.mm-20__offer-cta:hover {
  background: #000000;
}

.mm-20__page {
  inline-size: min(70rem, calc(100% - 2rem));
  margin-inline: auto;
  padding-block: clamp(3rem, 9vw, 5.5rem);
}

.mm-20__hero {
  max-inline-size: 34rem;
  display: grid;
  gap: 0.55rem;
}

.mm-20__kicker {
  margin: 0;
  font: 700 0.68rem/1 var(--mm-20-font-display);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--mm-20-mut);
}

.mm-20__h1 {
  margin: 0;
  font: 700 clamp(2.2rem, 7vw, 3.8rem)/1.02 var(--mm-20-font-display);
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.mm-20__sub {
  margin: 0;
  color: var(--mm-20-mut);
  font-size: clamp(0.95rem, 2.3vw, 1.1rem);
}

.mm-20__hero-cta {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  min-block-size: 48px;
  margin-block-start: 0.4rem;
  padding-inline: 1.4rem;
  border: 2px solid var(--mm-20-line);
  background: var(--mm-20-acc);
  color: #10213f;
  text-decoration: none;
  font: 700 0.82rem/1 var(--mm-20-font-display);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  box-shadow: var(--mm-20-offset) var(--mm-20-offset) 0 var(--mm-20-line);
}

@media (max-width: 54rem) {
  .mm-20__bar {
    flex-direction: column;
    align-items: stretch;
    padding-block: 0.6rem;
  }

  .mm-20__list {
    flex-direction: column;
  }

  .mm-20__cart {
    margin-inline-start: 0;
  }

  .mm-20__panel {
    position: static;
    inset-inline: auto;
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    box-shadow: none;
    display: none;
    margin-block-start: 0.5rem;
  }

  .mm-20__item--open > .mm-20__panel,
    .mm-20__item:focus-within > .mm-20__panel {
    display: grid;
  }
}

@media (prefers-reduced-motion: reduce) {
  .mm-20__panel {
    transition-duration: 1ms;
  }
}

@media (hover: hover) and (pointer: fine) {
  .mm-20__trigger {
    position: relative;
  }

  .mm-20__item:hover > .mm-20__trigger::after,
    .mm-20__item:focus-within > .mm-20__trigger::after {
    content: "";
    position: absolute;
    inset-inline: 0;
    inset-block-start: 100%;
    block-size: 16px;
  }
}
/* Entry signature — fast overshoot pop, alternating columns offset for a ripple across the panel */

.mm-20__links li,
.mm-20__sub li {
  opacity: 0;
  scale: 0.86;
  transform-origin: 0 50%;
  transition: opacity 140ms ease, scale 400ms cubic-bezier(0.34, 1.6, 0.64, 1);
}

.mm-20__item:hover > .mm-20__panel .mm-20__links li,
.mm-20__item:focus-within > .mm-20__panel .mm-20__links li,
.mm-20__item--open > .mm-20__panel .mm-20__links li {
  opacity: 1;
  scale: 1;
}

.mm-20__item:hover > .mm-20__panel .mm-20__sub li,
.mm-20__item:focus-within > .mm-20__panel .mm-20__sub li,
.mm-20__item--open > .mm-20__panel .mm-20__sub li {
  opacity: 1;
  scale: 1;
}

.mm-20__links li:nth-child(1) {
  transition-delay: 20ms;
}

.mm-20__links li:nth-child(2) {
  transition-delay: 52ms;
}

.mm-20__links li:nth-child(3) {
  transition-delay: 84ms;
}

.mm-20__links li:nth-child(4) {
  transition-delay: 116ms;
}

.mm-20__links li:nth-child(5) {
  transition-delay: 148ms;
}

.mm-20__links li:nth-child(6) {
  transition-delay: 180ms;
}

.mm-20__links li:nth-child(n+7) {
  transition-delay: 180ms;
}

.mm-20__col:nth-child(even) .mm-20__links li {
  transition-delay: 80ms;
}

@media (prefers-reduced-motion: reduce) {
  .mm-20__links li,
    .mm-20__sub li {
    transition-duration: 1ms;
    transition-delay: 0s;
    animation: none;
  }

  .mm-20__links li,
    .mm-20__sub li {
    opacity: 1;
    scale: 1;
  }
}
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Mega Menu from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Promotional Mega Menu with Offer Panel
Source: https://codefronts.com/navigation/css-mega-menus/flash-sale-command-center/

Commerce navigation with a promotional block beside the links. The design constraint is the interesting part: the promo has to stay subordinate to the navigation, because a panel that is mostly marketing stops doing the job the user opened it for. One offer, one third of the panel, and the categories keep their weight.
## HTML
```html
<section class="mm-20" aria-labelledby="mm-20-title">
  <h2 class="mm-20__sr" id="mm-20-title">Orbit Supply Co.</h2>

  <div class="mm-20__theme">
    <input class="mm-20__theme-input" type="checkbox" id="mm-20-theme">
    <label class="mm-20__theme-label" for="mm-20-theme">
      <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor"/></svg>
      <span class="mm-20__sr">Toggle dark theme</span>
    </label>
  </div>

  <header class="mm-20__header">
    <div class="mm-20__bar">
      <a class="mm-20__brand" href="#mm-20-title">ORBIT<span>supply co.</span></a>

      <nav class="mm-20__nav" aria-label="Primary">
        <ul class="mm-20__list">
          <li class="mm-20__item">
            <button class="mm-20__trigger" type="button" id="mm-20-trigger-shop" aria-expanded="false" aria-controls="mm-20-panel-shop">Shop</button>
            <div class="mm-20__panel" id="mm-20-panel-shop" aria-labelledby="mm-20-trigger-shop">
              <div class="mm-20__cols">
                <section class="mm-20__col" aria-labelledby="mm-20-h-desk">
                  <h3 class="mm-20__col-head" id="mm-20-h-desk">Desk</h3>
                  <ul class="mm-20__links"><li><a href="#mm-20-title">Notebooks</a></li><li><a href="#mm-20-title">Pens and refills</a></li><li><a href="#mm-20-title">Desk mats</a></li><li><a href="#mm-20-title">Organisers</a></li></ul>
                </section>
                <section class="mm-20__col" aria-labelledby="mm-20-h-carry">
                  <h3 class="mm-20__col-head" id="mm-20-h-carry">Carry</h3>
                  <ul class="mm-20__links"><li><a href="#mm-20-title">Backpacks</a></li><li><a href="#mm-20-title">Sleeves</a></li><li><a href="#mm-20-title">Pouches</a></li><li><a href="#mm-20-title">Travel sets</a></li></ul>
                </section>
                <section class="mm-20__col" aria-labelledby="mm-20-h-gift">
                  <h3 class="mm-20__col-head" id="mm-20-h-gift">Gifting</h3>
                  <ul class="mm-20__links"><li><a href="#mm-20-title">Under &pound;40</a></li><li><a href="#mm-20-title">Bundles</a></li><li><a href="#mm-20-title">Gift cards</a></li></ul>
                </section>
              </div>

              <aside class="mm-20__offer" aria-label="Autumn offer">
                <p class="mm-20__offer-tag">Autumn offer</p>
                <p class="mm-20__offer-head">Second notebook half price</p>
                <p class="mm-20__offer-body">On every A5 dot-grid in the Meridian range. Ends Sunday, no code needed.</p>
                <a class="mm-20__offer-cta" href="#mm-20-title">Shop the range</a>
              </aside>
            </div>
          </li>

          <li class="mm-20__item">
            <button class="mm-20__trigger" type="button" id="mm-20-trigger-new" aria-expanded="false" aria-controls="mm-20-panel-new">New in</button>
            <div class="mm-20__panel" id="mm-20-panel-new" aria-labelledby="mm-20-trigger-new">
              <div class="mm-20__cols">
                <section class="mm-20__col" aria-labelledby="mm-20-h-season">
                  <h3 class="mm-20__col-head" id="mm-20-h-season">This season</h3>
                  <ul class="mm-20__links"><li><a href="#mm-20-title">Winter linen range</a></li><li><a href="#mm-20-title">Brass edition pens</a></li><li><a href="#mm-20-title">Archive reprints</a></li></ul>
                </section>
                <section class="mm-20__col" aria-labelledby="mm-20-h-collab">
                  <h3 class="mm-20__col-head" id="mm-20-h-collab">Collaborations</h3>
                  <ul class="mm-20__links"><li><a href="#mm-20-title">Fern Studio</a></li><li><a href="#mm-20-title">Quill Press</a></li></ul>
                </section>
                <section class="mm-20__col" aria-labelledby="mm-20-h-back">
                  <h3 class="mm-20__col-head" id="mm-20-h-back">Back in stock</h3>
                  <ul class="mm-20__links"><li><a href="#mm-20-title">A5 dot grid</a></li><li><a href="#mm-20-title">Card wallet</a></li></ul>
                </section>
              </div>
              <aside class="mm-20__offer" aria-label="Members offer">
                <p class="mm-20__offer-tag">Members</p>
                <p class="mm-20__offer-head">Early access from Thursday</p>
                <p class="mm-20__offer-body">Sign in to shop the winter range 48 hours before general release.</p>
                <a class="mm-20__offer-cta" href="#mm-20-title">Sign in</a>
              </aside>
            </div>
          </li>

          <li class="mm-20__item"><a class="mm-20__plain" href="#mm-20-title">Journal</a></li>
          <li class="mm-20__item"><a class="mm-20__plain" href="#mm-20-title">Stores</a></li>
        </ul>
      </nav>

      <a class="mm-20__cart" href="#mm-20-title">
        <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M6 7h12l-1.2 11H7.2Z" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/><path d="M9.5 7a2.5 2.5 0 0 1 5 0" fill="none" stroke="currentColor" stroke-width="1.8"/></svg>
        Bag <span>2</span>
      </a>
    </div>
  </header>

  <main class="mm-20__page">
    <div class="mm-20__hero">
      <p class="mm-20__kicker">Made in Britain since 2009</p>
      <h1 class="mm-20__h1">Paper worth writing on.</h1>
      <p class="mm-20__sub">120gsm, fountain-pen friendly, bound to lie flat.</p>
      <a class="mm-20__hero-cta" href="#mm-20-title">Shop notebooks</a>
    </div>
  </main>
</section>
```
## CSS
```css
.mm-20 {
  --mm-20-bg: #eef2f8;
  --mm-20-surf: #ffffff;
  --mm-20-deep: #10213f;
  --mm-20-line: #10213f;
  --mm-20-soft: #d6dfec;
  --mm-20-ink: #10213f;
  --mm-20-mut: #56668a;
  --mm-20-acc: #f0a202;
  --mm-20-acc: oklch(78% 0.16 78);
  --mm-20-offset: 5px;
  --mm-20-font-display: "Futura", "Century Gothic", "Avenir Next", ui-sans-serif, system-ui, sans-serif;
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  display: block;
  position: relative;
  box-sizing: border-box;
  background: var(--mm-20-bg);
  color: var(--mm-20-ink);
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  line-height: 1.55;
}

.mm-20 *,
.mm-20 *::before,
.mm-20 *::after {
  box-sizing: border-box;
}

.mm-20 :focus-visible {
  outline: 2px solid var(--mm-20-deep);
  outline-offset: 3px;
}

.mm-20__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.mm-20:has(.mm-20__theme-input:checked) {
  --mm-20-bg: #060b16;
  --mm-20-surf: #0d1626;
  --mm-20-deep: #f2f6fc;
  --mm-20-line: #22314c;
  --mm-20-soft: #1a2740;
  --mm-20-ink: #eaf0f9;
  --mm-20-mut: #93a5c2;
  --mm-20-acc: #fbbf24;
  --mm-20-acc: oklch(83% 0.15 80);
}

@media (prefers-color-scheme: dark) {
  .mm-20 {
    --mm-20-bg: #060b16;
    --mm-20-surf: #0d1626;
    --mm-20-deep: #f2f6fc;
    --mm-20-line: #22314c;
    --mm-20-soft: #1a2740;
    --mm-20-ink: #eaf0f9;
    --mm-20-mut: #93a5c2;
    --mm-20-acc: #fbbf24;
    --mm-20-acc: oklch(83% 0.15 80);
  }

  .mm-20:has(.mm-20__theme-input:checked) {
    --mm-20-bg: #eef2f8;
    --mm-20-surf: #ffffff;
    --mm-20-deep: #10213f;
    --mm-20-line: #10213f;
    --mm-20-soft: #d6dfec;
    --mm-20-ink: #10213f;
    --mm-20-mut: #56668a;
    --mm-20-acc: #f0a202;
    --mm-20-acc: oklch(78% 0.16 78);
  }
}

@media (prefers-color-scheme: light) {
  .mm-20:has(.mm-20__theme-input:checked) {
    --mm-20-bg: #060b16;
    --mm-20-surf: #0d1626;
    --mm-20-deep: #f2f6fc;
    --mm-20-line: #22314c;
    --mm-20-soft: #1a2740;
    --mm-20-ink: #eaf0f9;
    --mm-20-mut: #93a5c2;
    --mm-20-acc: #fbbf24;
    --mm-20-acc: oklch(83% 0.15 80);
  }
}

.mm-20__theme {
  position: absolute;
  inset-block-start: clamp(1.5rem, 4vw, 2.2rem);
  inset-inline-end: clamp(0.75rem, 3vw, 1.5rem);
  z-index: 60;
}

.mm-20__theme-input {
  position: absolute;
  opacity: 0;
  inline-size: 100%;
  block-size: 100%;
  margin: 0;
  cursor: pointer;
}

.mm-20__theme-label {
  display: grid;
  place-items: center;
  inline-size: 44px;
  block-size: 44px;
  border: 2px solid var(--mm-20-line);
  background: var(--mm-20-surf);
  color: var(--mm-20-ink);
  cursor: pointer;
  box-shadow: var(--mm-20-offset) var(--mm-20-offset) 0 var(--mm-20-line);
}

.mm-20__theme-label svg {
  inline-size: 20px;
  block-size: 20px;
}

.mm-20__theme-input:focus-visible + .mm-20__theme-label {
  outline: 2px solid var(--mm-20-acc);
  outline-offset: 3px;
}

.mm-20__header {
  position: relative;
  z-index: 10;
  inline-size: min(70rem, calc(100% - 2rem));
  margin: clamp(1rem, 3vw, 1.75rem) auto 0;
}

.mm-20__bar {
  display: flex;
  align-items: center;
  gap: clamp(0.5rem, 2vw, 1.75rem);
  flex-wrap: wrap;
  min-block-size: 68px;
  padding-inline: clamp(0.85rem, 2vw, 1.25rem) 64px;
  border: 2px solid var(--mm-20-line);
  background: var(--mm-20-surf);
}

.mm-20__brand {
  color: var(--mm-20-ink);
  text-decoration: none;
  font: 700 1rem/1 var(--mm-20-font-display);
  letter-spacing: 0.14em;
}

.mm-20__brand span {
  display: block;
  font: 400 0.6rem/1.3 system-ui, sans-serif;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--mm-20-mut);
}

.mm-20__nav {
  min-inline-size: 0;
}

.mm-20__list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem;
  list-style: none;
  margin: 0;
  padding: 0;
  min-inline-size: 0;
}

.mm-20__item {
  position: static;
}

.mm-20__trigger,
.mm-20__plain {
  display: inline-flex;
  align-items: center;
  min-block-size: 44px;
  padding-inline: 0.9rem;
  border: 0;
  background: transparent;
  color: var(--mm-20-ink);
  font: 600 0.88rem/1 var(--mm-20-font-display);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
}

.mm-20__item--open > .mm-20__trigger,
.mm-20__item:hover > .mm-20__trigger,
.mm-20__item:focus-within > .mm-20__trigger {
  background: var(--mm-20-acc);
  color: #10213f;
}

.mm-20__plain:hover,
.mm-20__trigger:hover {
  color: var(--mm-20-mut);
}

.mm-20__cart {
  margin-inline-start: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-block-size: 44px;
  padding-inline: 0.75rem;
  color: var(--mm-20-ink);
  text-decoration: none;
  font: 600 0.8rem/1 var(--mm-20-font-display);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.mm-20__cart svg {
  inline-size: 20px;
  block-size: 20px;
}

.mm-20__cart span {
  display: grid;
  place-items: center;
  inline-size: 20px;
  block-size: 20px;
  border-radius: 999px;
  background: var(--mm-20-acc);
  color: #10213f;
  font-size: 0.7rem;
}

.mm-20__panel {
  position: absolute;
  inset-inline: -2px;
  inset-block-start: 100%;
  z-index: 30;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  border: 2px solid var(--mm-20-line);
  background: var(--mm-20-surf);
  box-shadow: var(--mm-20-offset) var(--mm-20-offset) 0 var(--mm-20-line);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 160ms ease, visibility 0s linear 160ms;
}

@media (min-width: 58rem) {
  .mm-20__panel {
    grid-template-columns: 2fr 1fr;
  }
}

.mm-20__item--open > .mm-20__panel,
.mm-20__item:focus-within > .mm-20__panel {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition-delay: 0s;
}

@media (hover: hover) {
  .mm-20__item:hover > .mm-20__panel {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition-delay: 0s;
  }
}

.mm-20__cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
  gap: clamp(0.75rem, 2.4vw, 1.75rem);
  padding: clamp(1rem, 2.8vw, 1.6rem);
  min-inline-size: 0;
}

.mm-20__col {
  min-inline-size: 0;
}

.mm-20__col-head {
  margin: 0 0 0.4rem;
  padding-block-end: 0.35rem;
  border-block-end: 2px solid var(--mm-20-line);
  font: 700 0.85rem/1.2 var(--mm-20-font-display);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.mm-20__links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1px;
}

.mm-20__links a {
  display: flex;
  align-items: center;
  min-block-size: 44px;
  color: var(--mm-20-ink);
  text-decoration: none;
  font-size: 0.9rem;
  min-inline-size: 0;
}

.mm-20__links a:hover {
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 2px;
}

.mm-20__offer {
  min-inline-size: 0;
  display: grid;
  align-content: start;
  gap: 0.35rem;
  padding: clamp(1rem, 2.8vw, 1.6rem);
  background: var(--mm-20-acc);
  color: #10213f;
}

.mm-20__offer-tag {
  margin: 0;
  font: 700 0.66rem/1 var(--mm-20-font-display);
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

.mm-20__offer-head {
  margin: 0;
  font: 700 clamp(1.1rem, 3vw, 1.35rem)/1.15 var(--mm-20-font-display);
  text-wrap: balance;
}

.mm-20__offer-body {
  margin: 0;
  font-size: 0.86rem;
  text-wrap: pretty;
}

.mm-20__offer-cta {
  justify-self: start;
  margin-block-start: 0.4rem;
  display: inline-flex;
  align-items: center;
  min-block-size: 44px;
  padding-inline: 1rem;
  background: #10213f;
  color: #ffffff;
  text-decoration: none;
  font: 700 0.78rem/1 var(--mm-20-font-display);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.mm-20__offer-cta:hover {
  background: #000000;
}

.mm-20__page {
  inline-size: min(70rem, calc(100% - 2rem));
  margin-inline: auto;
  padding-block: clamp(3rem, 9vw, 5.5rem);
}

.mm-20__hero {
  max-inline-size: 34rem;
  display: grid;
  gap: 0.55rem;
}

.mm-20__kicker {
  margin: 0;
  font: 700 0.68rem/1 var(--mm-20-font-display);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--mm-20-mut);
}

.mm-20__h1 {
  margin: 0;
  font: 700 clamp(2.2rem, 7vw, 3.8rem)/1.02 var(--mm-20-font-display);
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.mm-20__sub {
  margin: 0;
  color: var(--mm-20-mut);
  font-size: clamp(0.95rem, 2.3vw, 1.1rem);
}

.mm-20__hero-cta {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  min-block-size: 48px;
  margin-block-start: 0.4rem;
  padding-inline: 1.4rem;
  border: 2px solid var(--mm-20-line);
  background: var(--mm-20-acc);
  color: #10213f;
  text-decoration: none;
  font: 700 0.82rem/1 var(--mm-20-font-display);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  box-shadow: var(--mm-20-offset) var(--mm-20-offset) 0 var(--mm-20-line);
}

@media (max-width: 54rem) {
  .mm-20__bar {
    flex-direction: column;
    align-items: stretch;
    padding-block: 0.6rem;
  }

  .mm-20__list {
    flex-direction: column;
  }

  .mm-20__cart {
    margin-inline-start: 0;
  }

  .mm-20__panel {
    position: static;
    inset-inline: auto;
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    box-shadow: none;
    display: none;
    margin-block-start: 0.5rem;
  }

  .mm-20__item--open > .mm-20__panel,
    .mm-20__item:focus-within > .mm-20__panel {
    display: grid;
  }
}

@media (prefers-reduced-motion: reduce) {
  .mm-20__panel {
    transition-duration: 1ms;
  }
}

@media (hover: hover) and (pointer: fine) {
  .mm-20__trigger {
    position: relative;
  }

  .mm-20__item:hover > .mm-20__trigger::after,
    .mm-20__item:focus-within > .mm-20__trigger::after {
    content: "";
    position: absolute;
    inset-inline: 0;
    inset-block-start: 100%;
    block-size: 16px;
  }
}
/* Entry signature — fast overshoot pop, alternating columns offset for a ripple across the panel */

.mm-20__links li,
.mm-20__sub li {
  opacity: 0;
  scale: 0.86;
  transform-origin: 0 50%;
  transition: opacity 140ms ease, scale 400ms cubic-bezier(0.34, 1.6, 0.64, 1);
}

.mm-20__item:hover > .mm-20__panel .mm-20__links li,
.mm-20__item:focus-within > .mm-20__panel .mm-20__links li,
.mm-20__item--open > .mm-20__panel .mm-20__links li {
  opacity: 1;
  scale: 1;
}

.mm-20__item:hover > .mm-20__panel .mm-20__sub li,
.mm-20__item:focus-within > .mm-20__panel .mm-20__sub li,
.mm-20__item--open > .mm-20__panel .mm-20__sub li {
  opacity: 1;
  scale: 1;
}

.mm-20__links li:nth-child(1) {
  transition-delay: 20ms;
}

.mm-20__links li:nth-child(2) {
  transition-delay: 52ms;
}

.mm-20__links li:nth-child(3) {
  transition-delay: 84ms;
}

.mm-20__links li:nth-child(4) {
  transition-delay: 116ms;
}

.mm-20__links li:nth-child(5) {
  transition-delay: 148ms;
}

.mm-20__links li:nth-child(6) {
  transition-delay: 180ms;
}

.mm-20__links li:nth-child(n+7) {
  transition-delay: 180ms;
}

.mm-20__col:nth-child(even) .mm-20__links li {
  transition-delay: 80ms;
}

@media (prefers-reduced-motion: reduce) {
  .mm-20__links li,
    .mm-20__sub li {
    transition-duration: 1ms;
    transition-delay: 0s;
    animation: none;
  }

  .mm-20__links li,
    .mm-20__sub li {
    opacity: 1;
    scale: 1;
  }
}
```

How this works

A mega panel opens because someone wants to go somewhere. Every pixel spent on a promotion is a pixel not spent on that. The split here is deliberate and structural: 2fr to categories, 1fr to the offer. Because it is a grid ratio rather than a fixed width, the promotion cannot creep — adding copy makes the text wrap, not the block grow.

The promotion may use colour; it may not use weight. The offer card carries the accent, so it is clearly the loudest thing in the panel visually. But the category headings are the largest type and the links have the highest contrast, so the reading order still starts with navigation. That separation — colour for attention, weight for hierarchy — is what keeps the panel usable while still selling something.

Name it honestly for assistive technology. The offer sits in its own region with an aria-label that says what it is. A screen reader user hearing "Autumn offer, region" can skip it in one command; the same content dropped unlabelled into the link columns has to be tabbed through.

One offer. Not three, and not a carousel. A rotating promotion inside a hover-opened panel is content that changes while the user is reading it, which fails WCAG SC 2.2.2 unless it can be paused, and nobody builds the pause control. A single offer with one destination is also measurably more effective — and if the marketing team needs more than that, the answer is a landing page, not a bigger nav panel.

Make it yours

  • Change the 2fr 1fr ratio to 3fr 1fr if the promotion should be quieter still; do not go the other way.
  • Swap the offer card's accent by editing the two --mm-20-acc declarations, hex first then oklch.
  • Set --mm-20-offset to 0 to remove the hard shadow for a flatter treatment.
  • Replace the deadline line with a plain standfirst if your offer has no end date; a fake deadline is worse than none.
  • Add a fourth category column by copying a <section>; the promotion keeps its third regardless.
  • Remove the offer entirely for a clean commerce panel — nothing else depends on it.

Gotchas — read before shipping

  • A panel that is half promotion trains users to stop opening it, which costs more traffic than the promotion earns.
  • A rotating carousel inside a hover-opened panel changes content while it is being read and needs a pause control to meet SC 2.2.2. One static offer avoids the whole problem.
  • Giving the offer the largest type in the panel inverts the reading order, so users scan the marketing before the navigation they came for.
  • An unlabelled promotional block sits in the tab order between the link columns with no way to skip it. Put it in its own labelled region and last in source order.
  • A countdown implemented client-side that resets on every page load is a dark pattern and, on a nav panel, an obvious one.

Browser support

ChromeSafariFirefoxEdge
114+17.5+121+114+

Floor set by :has(), oklch(), text-wrap as this demo is written. The core technique itself goes back further — Chrome 111+.

oklch() and the :has() theme toggle set the floor; the layout is grid and absolute positioning, Baseline since 2017, and text-wrap: balance on the offer headline is progressive enhancement only (Chrome 114, Safari 17.5, Firefox 121). Below the oklch() floor the sRGB hex declared first applies and the panel is unchanged apart from slightly less even headline wrapping.

Techniques used in this demo

Search CodeFronts

Loading…