    /* Extra spacing below navbar */
    main {
      padding-top: 32px;
    }

    /* Router cards reuse .smartphone-card wholesale (same grid, same hover,
       same stock/price/warranty rows), so only the router-only bits live here.
       The package table needs nothing at all: it uses the same
       .pricing_section.options_pricing.pricing_demo2 > .blocks_pricing >
       .table_pricing markup as /telefoon, and is styled by main.css. */

    /* No product photography for the routers yet. A card without an `images`
       key in routers.json gets this tile instead of a broken <img>, keeping
       every card the same height. Drop real images in and it disappears. */
    .router-image-placeholder {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 100%;
      height: 100%;
      min-height: 180px;
      background: rgba(255, 255, 255, 0.04);
      border-radius: 12px;
    }

    .router-image-placeholder .material-icons {
      font-size: 72px;
      color: rgba(255, 255, 255, 0.25);
    }

    /* "Onze aanrader" flag on the Flint 2. */
    .router-recommended-badge {
      display: inline-block;
      margin-bottom: 8px;
      padding: 2px 10px;
      border-radius: 12px;
      background: #165df5;
      color: #fff;
      font-size: 0.75em;
      text-transform: uppercase;
      letter-spacing: 0.04em;
    }

    /* Picking a router marks the card, so it stays obvious which one you chose
       once the page has scrolled down to the package table. */
    .router-card.is-selected {
      outline: 2px solid #165df5;
      outline-offset: 2px;
    }

    /* Which router the package attaches to. An OpenWrt package is never sold on
       its own, so this line is the standing explanation of why the buy buttons
       need a choice first, not just an error state. */
    .router-choice-hint {
      margin-top: 12px;
      font-weight: 600;
    }

    .router-choice-hint--empty {
      color: #ffff55;
      font-weight: 400;
    }

    /* Flashed when someone clicks a package with nothing chosen, so the reason
       is still visible once the smooth scroll has landed on the line-up. */
    .router-choice-hint--flash {
      animation: router-choice-flash 0.6s ease-in-out 3;
    }

    @keyframes router-choice-flash {
      50% { opacity: 0.25; }
    }

    @media (prefers-reduced-motion: reduce) {
      .router-choice-hint--flash {
        animation: none;
      }
    }
