/**
 * ACE IOOT — brand layer
 * ======================
 *
 * Loaded by PrestaShop as `theme-custom` at priority 1000, i.e. after
 * Hummingbird's own theme.css. That ordering is why this file can restyle the
 * parent without forking it: nothing here replaces Hummingbird, it lands on top.
 *
 * Do not add an assets/css/theme.css to this child theme — the stylesheet
 * manager resolves that name against the child first and would silently drop
 * Hummingbird's entire stylesheet.
 *
 * Tokens follow primitive -> semantic -> component. Components must never
 * reference a primitive directly; go through the semantic layer so the palette
 * can be retuned in one place.
 *
 * Colour values are sampled from the client mockups
 * (design/mockups/pasted-movie-70.png and 66.png).
 */

/* ==========================================================================
   0. FONTS — self-hosted
   ==========================================================================

   Served from this theme rather than a font CDN. A CDN request would disclose
   every EU visitor's IP address to a third party, which is a GDPR question the
   shop does not need to answer.

   Outfit ships as a variable font, so one file covers the whole 400–700
   range; declaring separate 600 and 700 faces would download the identical
   file twice. Latin-ext is split out so it is only fetched when a page
   actually needs the accented glyphs — which Italian copy will.

   font-display: swap renders body text immediately in the fallback rather than
   leaving the page blank while the face loads.
   ========================================================================== */

/* Outfit carries the headings. The client's two hero clips are lettered in a
   geometric sans - single-storey a, circular bowls, high x-height, tight fit -
   and the serif that used to sit here read as a different brand entirely. Of
   the open-licence geometrics, Outfit matches the clips closest: Poppins runs
   noticeably wider, Jost too loosely tracked. */
@font-face {
  font-family: "Outfit";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/fonts/outfit-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Outfit";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/fonts/outfit-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Lato";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/lato-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Lato";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/lato-400-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Lato";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/fonts/lato-700-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Lato";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/fonts/lato-700-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ==========================================================================
   1. PRIMITIVES — raw brand values. Never referenced by components.
   ========================================================================== */

:root {
  /* Navy — headings and body copy */
  --ai-navy-900: #14253a;
  --ai-navy-700: #23384f;
  --ai-navy-500: #3d5570;

  /* Indigo — the brand's primary accent: prices, links, eyebrows, selection */
  --ai-indigo-700: #3d55d4;
  --ai-indigo-600: #516aed;
  --ai-indigo-500: #6b81f1;
  /* For indigo text on the navy contact band. indigo-500 measures only 3.74:1
     there, which fails AA for anything but large text; this clears 4.5:1
     against both the band and its lightened cards. */
  --ai-indigo-300: #7f92f2;
  --ai-indigo-200: #d9e0fb;
  --ai-indigo-100: #e9edfd;

  /* Azure - sampled from the client's own artwork, not chosen. 800 is the blue
     the SIM retail pack is printed in; 600 is the landmass of the coverage map
     in the hero clip. White text measures 9.9:1 and 5.1:1 on them, so unlike
     the indigo pair they carry body-sized type as well as display. */
  --ai-azure-800: #00408f;
  --ai-azure-600: #0073b9;

  /* Orange — reserved for commitment actions only (see --color-action).
     The mockup's #EE804E is kept exactly; only the text on it changed. See the
     note on --color-action-fg. */
  --ai-orange-700: #cc4d14; /* dark enough to serve as a border/outline (3:1) */
  --ai-orange-600: #e8703a;
  --ai-orange-500: #ee804e; /* brand orange, straight from the mockup */
  --ai-orange-300: #f09468; /* hover: lighter, so dark text gains contrast */
  --ai-orange-100: #fdeee6;

  /* Neutral greys are cool-tinted; grey-600 is set one notch darker than a
     typical slate-500 so it still clears 4.5:1 on the pale surface, not only on
     pure white. */

  /* Neutrals — cool-tinted to sit with the indigo rather than fight it */
  --ai-white: #ffffff;
  --ai-grey-50: #f6f8fe;
  --ai-grey-100: #e9f1fc;
  --ai-grey-200: #e4ecf3;
  --ai-grey-400: #94a3b8;
  --ai-grey-600: #63738a;

  /* Status — only these three carry meaning in the SIM dashboard */
  --ai-green-600: #1b7f3b;
  --ai-green-100: #e7f6ec;
  --ai-red-600: #d92d20;
  --ai-amber-700: #a35b00;
  --ai-amber-100: #fff4e5;

  /* Type scale — 1.25 major third, 1rem base */
  --ai-size-xs: 0.75rem;
  --ai-size-sm: 0.875rem;
  --ai-size-base: 1rem;
  --ai-size-lg: 1.25rem;
  --ai-size-xl: 1.5rem;
  --ai-size-2xl: 1.953rem;
  --ai-size-3xl: 2.441rem;
  --ai-size-4xl: 3.052rem;

  /* Spacing — 4px base */
  --ai-space-1: 0.25rem;
  --ai-space-2: 0.5rem;
  --ai-space-3: 0.75rem;
  --ai-space-4: 1rem;
  --ai-space-5: 1.5rem;
  --ai-space-6: 2rem;
  --ai-space-7: 3rem;
  --ai-space-8: 4rem;

  --ai-radius-sm: 6px;
  --ai-radius-md: 10px;
  --ai-radius-lg: 16px;
  --ai-radius-pill: 999px;

  --ai-shadow-sm: 0 1px 2px rgba(20, 37, 58, 0.06);
  --ai-shadow-md: 0 4px 16px rgba(20, 37, 58, 0.08);
  --ai-shadow-lg: 0 12px 32px rgba(20, 37, 58, 0.12);
}

/* ==========================================================================
   2. SEMANTIC — what a colour is *for*. This is the layer to retune.
   ========================================================================== */

:root {
  --color-page: var(--ai-white);
  --color-surface: var(--ai-grey-50);
  --color-surface-tint: var(--ai-grey-100);
  --color-border: var(--ai-grey-200);
  --color-border-strong: var(--ai-indigo-600);

  --color-heading: var(--ai-navy-900);
  --color-body: var(--ai-navy-700);
  --color-muted: var(--ai-grey-600);
  --color-on-dark: var(--ai-white);

  /* Primary = navigation, prices, links, selected state. */
  --color-primary: var(--ai-indigo-600);
  --color-primary-hover: var(--ai-indigo-700);
  --color-primary-soft: var(--ai-indigo-100);
  /* One step down from soft. For a tinted surface that has to hold its own
     shape against a white card, where indigo-100 reads as a printing fault. */
  --color-primary-tint: var(--ai-indigo-200);
  /* Use on navy/dark surfaces, never on white - it is too light there. */
  --color-primary-on-dark: var(--ai-indigo-300);
  /* Indigo text sitting on the pale surface rather than pure white.
     indigo-600 measures 4.53:1 on white but only 4.27:1 on #F6F8FE, so links
     inside cards step one shade darker to stay above 4.5:1. */
  --color-primary-on-surface: var(--ai-indigo-700);

  /* Action = orange. Deliberately scarce: in the mockups it appears only on
     Continue and Check-Out, i.e. the step that commits the customer. Using it
     for ordinary buttons would flatten that signal.

     ACCESSIBILITY DEVIATION FROM THE MOCKUP: the mockup sets white text on this
     orange, which measures 2.68:1 — below the 4.5:1 WCAG AA minimum, and below
     even the 3:1 large-text floor. Rather than darken the brand colour, the
     text is navy, which measures 5.78:1 against the identical background. The
     brand orange is therefore preserved exactly.

     Hover goes LIGHTER, not darker: with dark text on the button, a darker
     background would reduce contrast rather than increase it. */
  --color-action: var(--ai-orange-500);
  --color-action-hover: var(--ai-orange-300);
  --color-action-fg: var(--ai-navy-900);
  --color-action-border: var(--ai-orange-700);
  --color-action-soft: var(--ai-orange-100);

  /* The artwork blues. The client asked for the trust cards to be "blue, like
     the SIM colour", and these two are that colour: the pack and the map. Used
     as a gradient pair and as text on white; never as a link or a price, which
     stay indigo so the primary keeps meaning "you can click this". */
  --color-artwork-deep: var(--ai-azure-800);
  --color-artwork-blue: var(--ai-azure-600);

  --color-success: var(--ai-green-600);
  --color-success-soft: var(--ai-green-100);
  --color-danger: var(--ai-red-600);
  --color-warning: var(--ai-amber-700);
  --color-warning-soft: var(--ai-amber-100);
  --color-inactive: var(--ai-grey-400);

  /* Typography.
     Headings take Outfit, the geometric sans that matches the lettering in the
     client's own hero animations - the brand's actual voice. It replaced a
     high-contrast serif, which read as a different company beside the clips.
     Body copy stays on Lato: a humanist sans holds up better than a geometric
     one at paragraph sizes, and the pairing gives the headings something to
     contrast against. Both are self-hosted above. Fallbacks are listed so text
     stays readable if a font fails to load, and are metrically similar enough
     not to reflow noticeably. */
  --font-display: "Outfit", "Avenir Next", "Century Gothic", system-ui,
    -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-body: "Lato", system-ui, -apple-system, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --leading-tight: 1.15;
  --leading-normal: 1.55;
  --tracking-eyebrow: 0.12em;
}

/* ==========================================================================
   3. COMPONENTS
   ========================================================================== */

:root {
  --btn-action-bg: var(--color-action);
  --btn-action-bg-hover: var(--color-action-hover);
  --btn-action-fg: var(--color-action-fg);
  --btn-action-radius: var(--ai-radius-pill);

  --btn-primary-bg: var(--color-primary);
  --btn-primary-bg-hover: var(--color-primary-hover);
  --btn-primary-fg: var(--color-on-dark);

  --card-bg: var(--color-surface);
  --card-border: var(--color-border);
  --card-radius: var(--ai-radius-lg);
  --card-padding: var(--ai-space-5);
  --card-selected-border: var(--color-action-border);

  --badge-radius: var(--ai-radius-pill);
  --badge-font-size: var(--ai-size-xs);
}

/* --------------------------------------------------------------------------
   Base typography
   -------------------------------------------------------------------------- */

body {
  background: var(--color-page);
  color: var(--color-body);
  font-family: var(--font-body);
  line-height: var(--leading-normal);
}

/* The negative tracking is part of matching the animations: geometric sans set
   at heading sizes fits tighter than a serif did, and the clips are lettered
   tight. Without it the headings read loose and undersized. */
h1, h2, h3, h4, h5,
.h1, .h2, .h3, .h4, .h5 {
  color: var(--color-heading);
  font-family: var(--font-display);
  line-height: var(--leading-tight);
  font-weight: 700;
  letter-spacing: -0.02em;
}

h1, .h1 { font-size: var(--ai-size-3xl); }
h2, .h2 { font-size: var(--ai-size-2xl); }
h3, .h3 { font-size: var(--ai-size-xl); }

/* Buttons are excluded on purpose, and :not(.btn) is the whole reason this
   works. custom.css is unlayered and Hummingbird's is in @layer, so a bare `a`
   rule outranks every .btn rule in the parent whatever the specificity. Without
   the exclusion an anchor styled as a button took the link colour in both
   states - and on .btn-outline-primary that meant indigo text sitting on the
   indigo fill the button takes on hover, which is unreadable. It affected every
   anchor-button in the shop: "All packages", "Explore other plans", "Read the
   FAQ", "View this plan". Buttons carry their own colours; a link rule has no
   business reaching them.

   :where() and not a bare :not(.btn), because :not() takes the specificity of
   its argument and :where() contributes none. Written as a:not(.btn) this rule
   scores 0,1,1 and outranks .product-miniature__title at 0,1,0 - which turned
   every product name in the shop indigo. Wrapped, it stays at 0,0,1, exactly
   where a bare `a` was. */
a:not(:where(.btn)) { color: var(--color-primary); }
a:not(:where(.btn)):hover,
a:not(:where(.btn)):focus { color: var(--color-primary-hover); }

/* The mockups label every section with a small uppercase indigo kicker
   ("STEP 1 — CHOOSE YOUR PACKAGE"). */
.ai-eyebrow {
  display: block;
  margin-bottom: var(--ai-space-2);
  color: var(--color-primary);
  font-family: var(--font-body);
  font-size: var(--ai-size-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
}

/* --------------------------------------------------------------------------
   Buttons — mapped onto Hummingbird's Bootstrap classes
   -------------------------------------------------------------------------- */

.btn-primary {
  background-color: var(--btn-primary-bg);
  border-color: var(--btn-primary-bg);
  color: var(--btn-primary-fg);
}

.btn-primary:hover,
.btn-primary:focus {
  background-color: var(--btn-primary-bg-hover);
  border-color: var(--btn-primary-bg-hover);
  color: var(--btn-primary-fg);
}

/* Outline buttons - "All packages", "Explore other plans", "Read the FAQ".
   Mapped through Bootstrap's own variables rather than by setting colours, so
   the hover text stays the #fff Bootstrap already puts there and only the blue
   becomes ours. They used to take the brand indigo by accident, from the global
   link rule reaching into them; that rule now excludes buttons, so the mapping
   has to be stated. */
.btn-outline-primary {
  --bs-btn-color: var(--color-primary);
  --bs-btn-border-color: var(--color-primary);
  --bs-btn-hover-bg: var(--color-primary);
  --bs-btn-hover-border-color: var(--color-primary);
  --bs-btn-active-bg: var(--color-primary-hover);
  --bs-btn-active-border-color: var(--color-primary-hover);
}

/* Checkout and add-to-cart are the commitment steps the mockups paint orange. */
.btn-action,
.add-to-cart,
.checkout .btn-primary,
#checkout .continue,
.cart-detailed-actions .btn-primary {
  background-color: var(--btn-action-bg);
  border-color: var(--btn-action-bg);
  border-radius: var(--btn-action-radius);
  color: var(--btn-action-fg);
  font-weight: 600;
  padding-inline: var(--ai-space-5);
}

.btn-action:hover,
.add-to-cart:hover,
.checkout .btn-primary:hover,
#checkout .continue:hover,
.cart-detailed-actions .btn-primary:hover {
  background-color: var(--btn-action-bg-hover);
  border-color: var(--btn-action-bg-hover);
  color: var(--btn-action-fg);
}

/* Visible focus ring — Hummingbird's default is easy to lose against the
   pale surfaces used throughout this design. */
:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   Surfaces
   -------------------------------------------------------------------------- */

.card,
.product-miniature .thumbnail-container,
.block-categories,
.page-content--checkout {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--card-radius);
}

.page-header h1,
.page-header .h1 {
  color: var(--color-heading);
  font-family: var(--font-display);
}

.product-price,
.price {
  color: var(--color-primary);
  font-family: var(--font-display);
  font-weight: 700;
}

/* --------------------------------------------------------------------------
   Package / top-up tier cards (mockup pages 02 and 04)
   -------------------------------------------------------------------------- */

.ai-tier-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--ai-space-4);
}

.ai-tier {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--card-padding);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--card-radius);
}

/* The highlighted tier is outlined, not filled — it must read as recommended
   without being mistaken for "already selected". */
.ai-tier--featured {
  border: 2px solid var(--card-selected-border);
  background: var(--color-page);
}

.ai-tier__flag {
  position: absolute;
  top: calc(var(--ai-space-4) * -1);
  left: 50%;
  transform: translateX(-50%);
  padding: var(--ai-space-1) var(--ai-space-4);
  background: var(--color-action);
  border-radius: var(--badge-radius);
  color: var(--color-action-fg);
  font-size: var(--badge-font-size);
  font-weight: 700;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  white-space: nowrap;
}

.ai-tier__name {
  margin: 0 0 var(--ai-space-1);
  font-family: var(--font-display);
  font-size: var(--ai-size-lg);
}

.ai-tier__tagline {
  margin: 0 0 var(--ai-space-3);
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
  font-style: italic;
}

.ai-tier__spec {
  margin: 0 0 var(--ai-space-3);
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
}

.ai-tier__price {
  margin: 0 0 var(--ai-space-4);
  color: var(--color-primary);
  font-family: var(--font-display);
  font-size: var(--ai-size-2xl);
  font-weight: 700;
}

.ai-tier__price-unit {
  color: var(--color-muted);
  font-family: var(--font-body);
  font-size: var(--ai-size-sm);
  font-weight: 400;
}

.ai-tier__note {
  margin-top: auto;
  padding-top: var(--ai-space-3);
  color: var(--color-muted);
  font-size: var(--ai-size-xs);
}

/* --------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */

/* The logo file carries its true 184x84 dimensions so the img element reserves
   the right aspect ratio and nothing shifts on load; the header caps the
   rendered height. */
.logo,
.header__logo img,
#_desktop_logo img {
  height: auto;
  max-height: 44px;
  width: auto;
}

/* --------------------------------------------------------------------------
   Homepage "how it works" band (ps_customtext content)
   -------------------------------------------------------------------------- */

.ps-customtext {
  padding-block: var(--ai-space-7);
}

.ai-home-section + .ai-home-section {
  margin-top: var(--ai-space-8);
}

.ai-home-section > h2 {
  margin: 0 0 var(--ai-space-5);
}

/* Three category cards (mockup 81). Each is a whole-card link rather than a
   card containing a link, so the click target matches what looks clickable. */
.ai-nav-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--ai-space-4);
}

.ai-nav-card {
  display: flex;
  flex-direction: column;
  padding: var(--card-padding);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--card-radius);
  color: inherit;
  text-decoration: none;
  transition: border-color 180ms ease, box-shadow 180ms ease;
}

.ai-nav-card:hover,
.ai-nav-card:focus-visible {
  border-color: var(--color-primary);
  box-shadow: var(--ai-shadow-md);
  color: inherit;
  text-decoration: none;
}

.ai-nav-card__icon {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  margin-bottom: var(--ai-space-4);
  background: var(--color-primary);
  border-radius: 50%;
  color: var(--color-on-dark);
}

.ai-nav-card__icon svg {
  width: 1.5rem;
  height: 1.5rem;
}

.ai-nav-card__title {
  margin-bottom: var(--ai-space-2);
  color: var(--color-heading);
  font-family: var(--font-display);
  font-size: var(--ai-size-lg);
  font-weight: 700;
}

.ai-nav-card__note {
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
}

/* "Why choose our prepaid SIMs?" trust row (mockup 81).

   Built on the pricing card the client sent as the reference for "more
   prominent": a coloured header curving into a white body, with a badge in the
   corner where that card puts its flag.

   Four cards, all the same size, two by two. It was five in two tiers - a pair
   at half-row each over three smaller ones - until the client struck the
   bandwidth card and asked for the rest to match the pair. With four, equal
   halves are the tidy arrangement and the hierarchy is no longer needed to make
   the row read.

   The blue is measured, not picked: #0073b9 is the landmass of the coverage map
   in the hero clip, sampled from the frame. Flat, at the client's word - it ran
   as a gradient into the SIM pack's deeper #00408f for a day, and they asked
   for the map's own single colour instead. The deeper blue still earns its
   keep on the badge and under the hero button.

   White measures 5.1:1 on it, so every piece of type on the band is above AA
   at any size; the indigo gradient this replaces only cleared it for display
   type. */
.ai-why__list {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--ai-space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 620px) {
  .ai-why__list {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 992px) {
  .ai-why__list {
    gap: var(--ai-space-5);
  }
}

.ai-why__item {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--color-page);
  border: 1px solid var(--color-border);
  border-radius: var(--card-radius);
  box-shadow: var(--ai-shadow-sm);
}

/* The coloured header.

   The bottom edge is an ellipse - 50% of the width horizontally, a fixed depth
   vertically - so the band hangs lowest in the middle and lifts away at both
   corners, which is the curve on the reference card. The extra bottom padding
   is what keeps the label clear of it: at the corners the band loses the full
   1.75rem of that curve. */
.ai-why__band {
  display: flex;
  flex-direction: column;
  gap: var(--ai-space-5);
  padding: var(--ai-space-6) var(--ai-space-6) var(--ai-space-7);
  background: var(--color-artwork-blue);
  border-radius: 0 0 50% 50% / 0 0 1.75rem 1.75rem;
  color: var(--color-on-dark);
}

.ai-why__band-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ai-space-3);
}

.ai-why__label {
  color: var(--color-on-dark);
  font-family: var(--font-display);
  font-size: var(--ai-size-xl);
  font-weight: 700;
  line-height: var(--leading-tight);
}

@media (min-width: 992px) {
  .ai-why__label {
    font-size: var(--ai-size-2xl);
  }
}

/* Solid white with the deep artwork blue on it, like the flag disc on the
   reference card, and not a tinted pill: white text on a lightened patch of the
   band drops to about 3.6:1, and this badge is the smallest type on the card. */
.ai-why__badge {
  flex: 0 0 auto;
  padding: var(--ai-space-1) var(--ai-space-3);
  background: var(--color-page);
  border-radius: var(--ai-radius-pill);
  color: var(--color-artwork-deep);
  font-size: var(--ai-size-xs);
  font-weight: 700;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

/* Lightened band rather than a solid disc, the same treatment the stat cards on
   the contact band use - a white disc this size would read as a hole punched in
   the gradient. */
.ai-why__icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 3.25rem;
  height: 3.25rem;
  background: rgba(255, 255, 255, 0.18);
  border: 1px solid rgba(255, 255, 255, 0.32);
  border-radius: 50%;
  color: var(--color-on-dark);
}

.ai-why__icon svg {
  width: 1.75rem;
  height: 1.75rem;
}

/* Centred in what is left of the card rather than sitting under the curve. The
   band is the tall half and the supporting line is short, so aligning it to the
   top left the bottom of every card visibly hollow; centred, the space reads as
   margin on both sides of the line. */
.ai-why__body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  justify-content: center;
  gap: var(--ai-space-2);
  padding: var(--ai-space-5) var(--ai-space-6) var(--ai-space-6);
}

.ai-why__note {
  max-width: 46ch;
  color: var(--color-body);
  font-size: var(--ai-size-base);
  line-height: var(--leading-normal);
}

/* Hero call to action inside the header caption. Indigo, not orange: the
   mockup reserves orange for Cart and checkout. */
.aceioot-hero__cta {
  margin-top: var(--ai-space-4);
}

.aceioot-hero__cta .btn {
  padding-inline: var(--ai-space-5);
  font-weight: 700;
}

/* --------------------------------------------------------------------------
   Homepage header image
   -------------------------------------------------------------------------- */

/* The header is a single static image, so the carousel's controls and
   indicators have nothing to navigate between. They are hidden rather than
   removed from the markup, so adding a second slide in the Back Office brings
   them straight back. */
.ps-imageslider:has(.carousel-item:only-child) .carousel-control-prev,
.ps-imageslider:has(.carousel-item:only-child) .carousel-control-next,
.ps-imageslider:has(.carousel-item:only-child) .carousel-indicators {
  display: none;
}

.ps-imageslider__figcaption {
  /* A navy plate at 72% opacity, rather than relying on the photograph. Even
     over a pure-white area of the image the blended background still gives
     white text about 5.8:1, so the caption cannot become unreadable when the
     picture behind it is changed. */
  left: 50%;
  right: auto;
  bottom: var(--ai-space-6);
  transform: translateX(-50%);
  width: min(90%, 46rem);
  padding: var(--ai-space-4) var(--ai-space-5);
  background: rgba(20, 37, 58, 0.72);
  border-radius: var(--ai-radius-md);
}

.ps-imageslider__figcaption h2,
.ps-imageslider__figcaption h3 {
  margin: 0 0 var(--ai-space-2);
  color: var(--color-on-dark);
  font-family: var(--font-display);
  /* The mockup sets headings in mixed case; Hummingbird uppercases them here. */
  text-transform: none;
}

.ps-imageslider__figcaption p {
  margin: 0;
  color: var(--color-on-dark);
}

/* The caption is hidden below lg by Hummingbird, which leaves the mobile header
   as a bare photograph with no message at all. */
@media (max-width: 991.98px) {
  .ps-imageslider__figcaption {
    display: block !important;
    position: static;
    width: 100%;
    transform: none;
    border-radius: 0;
  }

  .ps-imageslider__figcaption h2 {
    font-size: var(--ai-size-lg);
  }

  .ps-imageslider__figcaption p {
    font-size: var(--ai-size-sm);
  }
}

/* --------------------------------------------------------------------------
   Main menu and mega dropdown

   Hummingbird lays the dropdown out as a two-column tablist: second-level
   categories down the left, their children across the right. Unstyled, the
   third level renders at the same weight as the second, so "Camera" shouted as
   loudly as "Shop by Devices". These rules restore the hierarchy.
   -------------------------------------------------------------------------- */

/* The client wants Support and the search bar held to the right of the header
   while the rest of the menu sits by the logo. ps_mainmenu prints one flat
   list, so the split is made here, by pushing the last entry across.

   The auto margin can only open a gap if the list has width to spare. The
   col-xl wrapper does stretch between the logo and the search box, but it is
   itself a flex container, so the <nav> inside it was shrinking to its content
   and the list ended up exactly as wide as its links. Growing the nav hands
   that spare width down to the list.

   Support is last in MOD_BLOCKTOPMENU_ITEMS, set in seed_content.php - a new
   entry appended after it would land on the right-hand side instead. */
.ps-mainmenu--desktop .ps-mainmenu__desktop {
  flex: 1 1 auto;
}

.ps-mainmenu__tree > li:last-child {
  margin-left: auto;
}

.ps-mainmenu__tree-link {
  color: var(--color-heading);
  font-weight: 600;
  text-decoration: none;
}

.ps-mainmenu__tree-link:hover,
.ps-mainmenu__tree-link:focus-visible {
  color: var(--color-primary);
}

/* Hummingbird rings the dropdown chevron on :focus, so clicking one leaves the
   outline stranded there until something else takes focus. Drop it for pointer
   focus only - :focus-visible is still :focus, so the parent's ring survives
   untouched for keyboard users, which is who it is for. */
.ps-mainmenu__tree-dropdown-toggle:focus:not(:focus-visible) {
  outline: none;
}

.submenu {
  border-top: 1px solid var(--color-border);
  background: var(--color-page);
  box-shadow: var(--ai-shadow-lg);
}

.submenu .container {
  padding-block: var(--ai-space-5);
}

/* Left rail: the second level, and the only part that reads as navigation. */
.submenu__left {
  border-right: 1px solid var(--color-border);
}

/* A flat submenu - Support - has nothing that can ever fill the right-hand
   pane, so the rail would rule a divider across three quarters of a blank band.
   Collapse it to the width of the links.

   Keyed off whether any entry *can* have children, which is fixed markup, so
   this state never changes while the menu is open. That matters: see below.
   :has() is unsupported only on browsers that keep the two-column layout, which
   still works. */
.submenu:not(:has(.submenu__left-item[data-ps-has-child="true"])) .submenu__left {
  flex: 0 0 auto;
  width: auto;
  padding-block: 0;
  border-right: 0;
}

.submenu:not(:has(.submenu__left-item[data-ps-has-child="true"])) .submenu__right {
  display: none;
}

.submenu:not(:has(.submenu__left-item[data-ps-has-child="true"])) .container {
  padding-block: var(--ai-space-3);
}

/* A submenu that does switch tabs - Shop SIM Cards - gets nothing but the
   divider, and only its colour, so the border keeps its 1px whichever tab is
   open.

   Nothing here may alter geometry. Moving the rail while the pointer rests on
   it slides the entry out from under the cursor, which fires another
   mouseenter, which switches the tab back: the panel oscillates and the page
   appears to vibrate. Height still grows downwards when a tall pane opens, but
   the entries are top-aligned so the pointer never loses its target. */
.submenu:has(.submenu__left-item[data-ps-has-child="true"]) .submenu__left {
  border-right-color: transparent;
}

.submenu:has(.submenu__right-items.active) .submenu__left {
  border-right-color: var(--color-border);
}

.submenu__left-item {
  display: block;
  padding: var(--ai-space-3) var(--ai-space-4);
  border-radius: var(--ai-radius-md);
  color: var(--color-heading);
  font-weight: 600;
  text-decoration: none;
}

.submenu__left-item:hover,
.submenu__left-item:focus-visible,
.submenu__left-item[aria-selected="true"] {
  background: var(--color-surface);
  color: var(--color-primary-on-surface);
}

/* Right pane: the third level. Quieter than the rail, and laid out as a grid
   so four device categories do not stretch across the full width.

   Deliberately does NOT set `display`. Hummingbird shows and hides these panels
   by toggling .active / .not-active, and because this file is unlayered while
   the parent theme's CSS sits in @layer, anything declared here outranks the
   parent whatever its specificity. A `display: grid` here therefore pinned every
   panel open at once, so the menu showed one tab's contents while another tab
   was highlighted. Set the layout, leave the state alone. */
.submenu__right-items {
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--ai-space-2) var(--ai-space-4);
}

.submenu__right-items a {
  display: block;
  padding: var(--ai-space-2) var(--ai-space-3);
  border-radius: var(--ai-radius-sm);
  color: var(--color-body);
  font-size: var(--ai-size-sm);
  font-weight: 400;
  text-decoration: none;
}

.submenu__right-items a:hover,
.submenu__right-items a:focus-visible {
  background: var(--color-surface);
  color: var(--color-primary-on-surface);
}

/* Entries that carry artwork - the device categories - read as small cards
   instead of a list of links, so the dropdown shows the same pictures as the
   Shop by Devices page it leads to. Only entries with a NavItem.image get this;
   the rest of the third level is untouched.

   The padding moves off the link and onto the label: the picture has to run to
   the card's edges, and a padded <a> would inset it. */
.submenu__right-items .menu-item__group--media {
  margin-bottom: 0;
  padding-left: 0;
  list-style: none;
}

/* The category thumbnails behind these cards (img/c/{id}-1_thumb.jpg) are
   pre-composed as their own rounded card, complete with a soft drop shadow a
   few pixels inside the image edge - the same artwork the Shop by Devices
   page and home slider use. Wrapping that in this card's own border read as
   a second, mismatched outline hugging the first, so the frame here is
   transparent and the picture supplies it; the hover/focus shadow still
   gives the entry its interactive affordance. */
.submenu__right-items .menu-item__group--media .menu-item__group-main-item {
  overflow: hidden;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--ai-radius-md);
  background: var(--color-page);
  transition: border-color 180ms ease, box-shadow 180ms ease;
}

.submenu__right-items .menu-item__group--media .menu-item__group-main-item:hover,
.submenu__right-items .menu-item__group--media .menu-item__group-main-item:focus-visible {
  border-color: transparent;
  background: var(--color-page);
  box-shadow: var(--ai-shadow-md);
}

.menu-item__media {
  display: block;
  background: var(--color-surface);
}

/* Declared width/height on the img reserves the 16:10 box, so the dropdown does
   not resize under the pointer as the pictures arrive. */
.menu-item__media img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 8 / 5;
  object-fit: cover;
}

.menu-item__label {
  display: block;
  padding: var(--ai-space-2) var(--ai-space-3);
  color: var(--color-heading);
  font-weight: 600;
}

/* The mobile drawer shows the same artwork as a thumbnail beside the label. */
.ps-mainmenu--mobile .menu--media .menu__link {
  display: flex;
  align-items: center;
  gap: var(--ai-space-3);
}

.menu__media {
  flex: 0 0 3.5rem;
  overflow: hidden;
  border-radius: var(--ai-radius-sm);
  background: var(--color-surface);
  line-height: 0;
}

.menu__media img {
  width: 100%;
  height: auto;
  aspect-ratio: 8 / 5;
  object-fit: cover;
}

/* --------------------------------------------------------------------------
   Product cards

   Stock Hummingbird renders the product name as a small indigo link and the
   price as plain body text, which inverts the hierarchy: the price shouts and
   the product whispers. The name is the heading here.
   -------------------------------------------------------------------------- */

.module-products {
  padding-block: var(--ai-space-7);
}

.section-title {
  margin-bottom: var(--ai-space-5);
  color: var(--color-heading);
  font-family: var(--font-display);
  font-size: var(--ai-size-2xl);
}

.product-miniature__inner {
  height: 100%;
  padding: var(--ai-space-3);
  background: var(--color-page);
  border: 1px solid var(--color-border);
  border-radius: var(--card-radius);
  transition: border-color 180ms ease, box-shadow 180ms ease;
}

.product-miniature:hover .product-miniature__inner {
  border-color: var(--color-primary);
  box-shadow: var(--ai-shadow-md);
}

.product-miniature__image-container {
  background: var(--color-surface);
  border-radius: var(--ai-radius-md);
  overflow: hidden;
}

.product-miniature__image {
  mix-blend-mode: multiply; /* drops the photos' white box onto the tinted tile */
}

.product-miniature__infos {
  padding: var(--ai-space-4) var(--ai-space-2) var(--ai-space-2);
}

.product-miniature__title,
.product-miniature__title a {
  color: var(--color-heading);
  font-family: var(--font-display);
  font-size: var(--ai-size-lg);
  font-weight: 700;
  line-height: 1.25;
  text-decoration: none;
}

.product-miniature__title a:hover,
.product-miniature__title a:focus-visible {
  color: var(--color-primary-on-surface);
}

.product-miniature__price {
  color: var(--color-primary);
  font-family: var(--font-display);
  font-size: var(--ai-size-xl);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* The "Other Plans" dialog, opened from the main menu entry and from the card
   at the end of the home page row.

   A native <dialog>. ::backdrop, Escape, focus trapping and the top layer all
   come from the browser; the only thing styled here is the panel. */
.ai-plans-dialog {
  width: min(34rem, calc(100vw - 2rem));
  padding: 0;
  background: var(--color-page);
  border: 0;
  border-radius: var(--card-radius);
  box-shadow: var(--ai-shadow-lg);
  color: var(--color-body);
}

.ai-plans-dialog::backdrop {
  background: rgba(20, 37, 58, 0.55);
}

.ai-plans-dialog__inner {
  position: relative;
  padding: var(--ai-space-6);
}

.ai-plans-dialog__close {
  position: absolute;
  top: var(--ai-space-3);
  right: var(--ai-space-3);
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: 50%;
  color: var(--color-muted);
  font-size: var(--ai-size-xl);
  line-height: 1;
  cursor: pointer;
}

.ai-plans-dialog__close:hover,
.ai-plans-dialog__close:focus-visible {
  background: var(--color-surface);
  color: var(--color-heading);
}

.ai-plans-dialog__title {
  margin: 0 0 var(--ai-space-4);
  padding-right: var(--ai-space-6);
  font-size: var(--ai-size-xl);
}

.ai-plans-dialog__copy {
  margin: 0 0 var(--ai-space-5);
  line-height: var(--leading-normal);
}

.ai-plans-dialog__cta {
  font-weight: 700;
}

/* The "Other Plans" card that closes the home page product row.

   It borrows the product miniature's own classes so it matches the three cards
   beside it exactly - same frame, same image tile, same title - and adds only
   what a product does not have: a line of copy where the price sits, and a link
   where the quantity stepper and cart button sit.

   position: relative is scoped to this card alone, never to .product-miniature
   generally: it is what stretched-link needs to cover, and putting it on every
   product card would change the stacking context of three cards that do not
   need it. */
.ai-plans-card .product-miniature__inner {
  position: relative;
}

/* The client's Other Plans artwork is 3:2 where the product photographs are
   square. A square tile with the art contained inside keeps this card's text on
   the same line as the other three; the SIM simply sits in a shorter band
   within it, which is what the artwork is. */
.ai-plans-card .product-miniature__image {
  aspect-ratio: 1 / 1;
  width: 100%;
  height: auto;
  object-fit: contain;
}

.ai-plans-card .product-miniature__bottom {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
}

.ai-plans-card__note {
  margin: 0;
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
  line-height: var(--leading-normal);
}

/* Pushed to the foot of the card so it lines up with the add-to-cart row on the
   three products, however their titles wrap. */
.ai-plans-card__link {
  margin-top: auto;
  align-self: flex-start;
}

.product-miniature__actions {
  gap: var(--ai-space-2);
  margin-top: var(--ai-space-3);
}

/* Adding to the cart is a commitment step, so it takes the action colour. */
.product-miniature__add {
  background-color: var(--btn-action-bg);
  border-color: var(--btn-action-bg);
  color: var(--btn-action-fg);
}

.product-miniature__add:hover,
.product-miniature__add:focus-visible {
  background-color: var(--btn-action-bg-hover);
  border-color: var(--btn-action-bg-hover);
  color: var(--btn-action-fg);
}

/* The client doesn't want a "New" tag on product cards or the product page.
   Scoped to just this flag type - PrestaShop's other flags (on sale, pack,
   etc.) are untouched. */
.badge.new {
  display: none;
}

/* --------------------------------------------------------------------------
   Device pages (mockup 96 — "SIMs Matched to Your Device")
   -------------------------------------------------------------------------- */

.ai-device-intro {
  max-width: 46ch;
  margin-bottom: var(--ai-space-5);
  color: var(--color-muted);
  font-size: var(--ai-size-lg);
}

.ai-device-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--ai-space-4);
}

.ai-device-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--color-page);
  border: 1px solid var(--card-border);
  border-radius: var(--card-radius);
  color: inherit;
  text-decoration: none;
  transition: border-color 180ms ease, box-shadow 180ms ease;
}

.ai-device-card:hover,
.ai-device-card:focus-visible {
  border-color: var(--color-primary);
  box-shadow: var(--ai-shadow-md);
  color: inherit;
  text-decoration: none;
}

.ai-device-card__media {
  display: block;
  background: var(--color-surface);
}

.ai-device-card__media img {
  display: block;
  width: 100%;
  height: auto;
  /* Declared width/height on the img reserves the 16:10 box, so the card does
     not jump as the picture arrives. */
  aspect-ratio: 8 / 5;
  object-fit: cover;
}

.ai-device-card__body {
  display: flex;
  flex-direction: column;
  gap: var(--ai-space-2);
  padding: var(--card-padding);
}

.ai-device-card__title {
  color: var(--color-heading);
  font-family: var(--font-display);
  font-size: var(--ai-size-lg);
  font-weight: 700;
  line-height: 1.25;
}

/* The recommended tier is the point of the card, so it is a labelled chip
   rather than another line of prose. */
.ai-device-card__tier {
  align-self: flex-start;
  padding: 0.125rem var(--ai-space-3);
  background: var(--color-primary-soft);
  border-radius: var(--badge-radius);
  color: var(--color-primary-on-surface);
  font-size: var(--ai-size-xs);
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.ai-device-card__more {
  margin-top: auto;
  padding-top: var(--ai-space-2);
  color: var(--color-primary-on-surface);
  font-size: var(--ai-size-sm);
  font-weight: 700;
}

/* Recommended-plan callout on an individual device category page. */
.ai-tier-callout {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ai-space-2) var(--ai-space-5);
  max-width: 44rem;
  padding: var(--ai-space-5);
  background: var(--color-surface);
  border: 1px solid var(--card-border);
  border-radius: var(--card-radius);
}

.ai-tier-callout .ai-eyebrow {
  flex-basis: 100%;
  margin-bottom: 0;
}

.ai-tier-callout__name {
  color: var(--color-heading);
  font-family: var(--font-display);
  font-size: var(--ai-size-xl);
  font-weight: 700;
}

/* No price here on purpose - see the note in seed_catalogue.php. */
.ai-tier-callout__note {
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
}

.ai-tier-callout .btn {
  margin-left: auto;
}

/* --------------------------------------------------------------------------
   Newsletter — kept, but pulled onto the brand
   -------------------------------------------------------------------------- */

.ps-emailsubscription {
  background: var(--color-surface) !important;
  border-top: 1px solid var(--color-border);
}

.ps-emailsubscription h2,
.ps-emailsubscription .h2 {
  font-family: var(--font-display);
  font-size: var(--ai-size-xl);
}

/* --------------------------------------------------------------------------
   Contact band — foot of every page (mockup page 92)
   -------------------------------------------------------------------------- */

.aceioot-contact {
  padding-block: var(--ai-space-7);
  background: var(--color-heading);
  color: var(--color-on-dark);
}

.aceioot-contact__title {
  margin: 0 0 var(--ai-space-5);
  color: var(--color-on-dark);
  font-family: var(--font-display);
  font-size: var(--ai-size-2xl);
}

.aceioot-contact__stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--ai-space-4);
  margin: 0 0 var(--ai-space-5);
  padding: 0;
  list-style: none;
}

.aceioot-stat {
  padding: var(--ai-space-5);
  /* Lightened navy rather than a flat panel colour, so the cards stay in the
     same family as the band behind them. */
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: var(--ai-radius-md);
}

.aceioot-stat__figure {
  display: block;
  margin-bottom: var(--ai-space-1);
  color: var(--color-primary-on-dark);
  font-family: var(--font-display);
  font-size: var(--ai-size-2xl);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.aceioot-stat__label {
  display: block;
  margin-bottom: var(--ai-space-2);
  color: var(--color-on-dark);
  font-weight: 700;
}

.aceioot-stat__note {
  display: block;
  /* Kept at 0.82 alpha: below roughly 0.7 this drops under 4.5:1 on navy. */
  color: rgba(255, 255, 255, 0.82);
  font-size: var(--ai-size-sm);
}

/* Contact routes. Each is its own chip rather than links sharing one panel:
   the client asked for icons, and an icon needs a target of its own to belong
   to. Wrapping is per chip, so a narrow screen stacks them cleanly. */
.aceioot-contact__details {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ai-space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.aceioot-contact__details a {
  display: inline-flex;
  align-items: center;
  gap: var(--ai-space-3);
  padding: var(--ai-space-3) var(--ai-space-4);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: var(--ai-radius-md);
  color: var(--color-on-dark);
  font-weight: 600;
  text-decoration: none;
  transition: background-color 180ms ease, border-color 180ms ease;
}

.aceioot-contact__details a:hover,
.aceioot-contact__details a:focus {
  background: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.28);
  color: var(--color-on-dark);
  text-decoration: none;
}

.aceioot-contact__icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 2rem;
  height: 2rem;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 50%;
  color: var(--color-primary-on-dark);
}

.aceioot-contact__icon svg {
  width: 1.125rem;
  height: 1.125rem;
}

/* --------------------------------------------------------------------------
   "Partnership with DEEP" banner, between the newsletter and the contact band
   -------------------------------------------------------------------------- */

.aceioot-partnerband {
  /* Deliberately not the navy of the band below it. On navy the mark needs a
     white plate to stay legible, and the plate is what made the old footer
     lockup look boxed-in; on the page's own background it needs nothing. */
  padding-block: var(--ai-space-6);
  background: var(--color-page);
  border-block: 1px solid var(--color-border);
}

.aceioot-partnerband__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--ai-space-4);
}

.aceioot-partnerband__label {
  /* Heading navy, not muted grey: the client asked for this to be visible, and
     the band has no other weight on it to carry the eye. */
  color: var(--color-heading);
  font-family: var(--font-display);
  font-size: var(--ai-size-lg);
  font-weight: 700;
  letter-spacing: 0.02em;
}

.aceioot-partnerband__mark {
  display: block;
  width: auto;
  /* The asset is 438x320 and re-cut from design/brand at 320px tall, so this
     is a downscale at every viewport and stays crisp on 2x screens. */
  height: clamp(2.25rem, 3.4vw, 3.25rem);
}

/* --------------------------------------------------------------------------
   Placeholder notice on unwritten CMS pages
   -------------------------------------------------------------------------- */

.ai-pending {
  padding: var(--ai-space-4);
  background: var(--color-warning-soft);
  border-left: 4px solid var(--color-warning);
  border-radius: var(--ai-radius-sm);
  color: var(--color-heading);
}

.ai-pending--legal {
  background: #fdecea;
  border-left-color: var(--color-danger);
}

/* --------------------------------------------------------------------------
   Enter ICCID — the typed half of the top-up page's step 1 (mockup 04)
   --------------------------------------------------------------------------

   The mockup sets the field and the "select from my SIMs" control side by side
   with an "or" between them. Here the second half is the list underneath, so
   the row is field | or | a line pointing at it. Below the md breakpoint the
   three stack and the "or" is dropped: on one column it separates nothing. */

.ai-iccid {
  margin-bottom: var(--ai-space-5);
}

.ai-iccid__row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--ai-space-3);
}

/* Wide enough for 20 digits in groups of four, and allowed to give that up
   before the row wraps. */
.ai-iccid__field {
  flex: 1 1 22rem;
  min-width: 0;
}

.ai-iccid__or {
  padding-bottom: 0.55rem;
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
}

.ai-iccid__alt {
  margin: 0 0 0.55rem;
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
}

.ai-iccid__msg {
  margin: var(--ai-space-2) 0 0;
  color: var(--color-body);
  font-size: var(--ai-size-sm);
}

.ai-iccid__msg.is-invalid {
  color: var(--color-danger);
}

@media (max-width: 767.98px) {
  .ai-iccid__or {
    display: none;
  }

  .ai-iccid__alt {
    flex-basis: 100%;
    margin-bottom: 0;
  }
}

/* --------------------------------------------------------------------------
   Selectable option rows (physical SIM vs eSIM, mockup page 02 step 2)
   -------------------------------------------------------------------------- */

.ai-option {
  display: flex;
  align-items: center;
  gap: var(--ai-space-3);
  padding: var(--ai-space-4);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--ai-radius-md);
  cursor: pointer;
}

.ai-option--selected {
  border-color: var(--color-primary);
  background: var(--color-page);
  box-shadow: 0 0 0 1px var(--color-primary);
}

.ai-option__icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 2.75rem;
  height: 2.75rem;
  background: var(--color-primary-soft);
  border-radius: var(--ai-radius-md);
  color: var(--color-primary);
}

.ai-option--selected .ai-option__icon {
  background: var(--color-primary);
  color: var(--color-on-dark);
}

.ai-option__title {
  display: block;
  color: var(--color-heading);
  font-weight: 600;
}

.ai-option__hint {
  display: block;
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
}

/* --------------------------------------------------------------------------
   Quantity stepper — orders start at 10 SIMs and move in tens
   -------------------------------------------------------------------------- */

.ai-stepper {
  display: inline-flex;
  align-items: center;
  gap: var(--ai-space-2);
  padding: var(--ai-space-1);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--ai-radius-pill);
}

.ai-stepper__btn {
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  background: var(--color-page);
  border: 1px solid var(--card-border);
  border-radius: 50%;
  color: var(--color-primary);
  font-size: var(--ai-size-lg);
  line-height: 1;
}

.ai-stepper__btn:disabled {
  color: var(--color-inactive);
  cursor: not-allowed;
}

.ai-stepper__value {
  min-width: 3rem;
  border: 0;
  background: transparent;
  color: var(--color-heading);
  font-weight: 600;
  text-align: center;
}

/* --------------------------------------------------------------------------
   Two-step package selector (mockup 70)

   The tier and SIM-type choices are native radio inputs with the input itself
   visually hidden: the whole card is the label, so the click target matches
   what looks clickable, and keyboard focus and checked state still work.
   -------------------------------------------------------------------------- */

.ai-selector {
  padding-block: var(--ai-space-6) var(--ai-space-7);
}

.ai-selector__intro {
  margin-bottom: var(--ai-space-6);
}

.ai-selector__title {
  margin: 0;
  color: var(--color-heading);
  font-family: var(--font-display);
  font-size: var(--ai-size-2xl);
}

.ai-step {
  margin: 0 0 var(--ai-space-7);
  padding: 0;
  border: 0;
}

/* float:none undoes Bootstrap Reboot, which floats every <legend> left at
   width:100% - a workaround for browsers that could not make a legend a block.
   The float is invisible until something below it establishes its own
   formatting context, which a grid container does: a full-width float leaves no
   room beside it, so the grid is squeezed to zero width and pushed off the
   right of the page. Chrome only rescues the case where the grid is the
   legend's first in-flow sibling, which is why step 2 laid out correctly on the
   first package and collapsed on the other two - their option grids sit behind
   a display:none sibling. */
.ai-step__legend {
  float: none;
  width: 100%;
  margin-bottom: var(--ai-space-4);
  padding: 0;
  color: var(--color-heading);
  font-family: var(--font-display);
  font-size: var(--ai-size-lg);
  font-weight: 700;
}

/* Visually hidden, still focusable and still announced. */
.ai-tier__input,
.ai-option__input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

.ai-tier {
  cursor: pointer;
}

.ai-tier:has(.ai-tier__input:checked) {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 1px var(--color-primary);
  background: var(--color-page);
}

/* Focus must be visible on the card, since the input itself is hidden. */
.ai-tier:has(.ai-tier__input:focus-visible),
.ai-option:has(.ai-option__input:focus-visible) {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.ai-tier__spec {
  display: block;
  margin-bottom: var(--ai-space-3);
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
}

.ai-option-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--ai-space-4);
}

.ai-option:has(.ai-option__input:checked) {
  border-color: var(--color-primary);
  background: var(--color-page);
  box-shadow: 0 0 0 1px var(--color-primary);
}

.ai-option:has(.ai-option__input:checked) .ai-option__icon {
  background: var(--color-primary);
  color: var(--color-on-dark);
}

.ai-option__icon svg {
  width: 1.375rem;
  height: 1.375rem;
}

.ai-option__text {
  display: flex;
  flex-direction: column;
}

/* The client's description of the two SIM types, below the choice they belong
   to. Two cards side by side so the lists can be read against each other; the
   one matching the current selection is tied to it with the same border the
   option card uses, and the other stays quiet rather than hidden - comparing is
   the point of the block. */
.ai-sim-features {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--ai-space-4);
  margin-top: var(--ai-space-4);
}

.ai-sim-features__card {
  padding: var(--ai-space-4);
  background: var(--color-surface);
  border: 1px solid var(--card-border);
  border-radius: var(--ai-radius-md);
}

.ai-sim-features__card--selected {
  background: var(--color-page);
  border-color: var(--color-primary);
}

.ai-sim-features__title {
  margin: 0;
  color: var(--color-heading);
  font-family: var(--font-display);
  font-size: var(--ai-size-base);
  font-weight: 700;
}

.ai-sim-features__summary {
  margin: 0 0 var(--ai-space-3);
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
}

.ai-sim-features__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The tick is decoration, so it is drawn rather than listed: a real bullet
   would be read out before every line. */
.ai-sim-features__item {
  position: relative;
  padding-left: var(--ai-space-5);
  color: var(--color-body);
  font-size: var(--ai-size-sm);
  line-height: 1.5;
}

.ai-sim-features__item + .ai-sim-features__item {
  margin-top: var(--ai-space-2);
}

.ai-sim-features__item::before {
  content: "";
  position: absolute;
  top: 0.45em;
  left: 0.15rem;
  width: 0.45rem;
  height: 0.75rem;
  border: solid var(--color-primary);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

.ai-sim-features__link {
  color: var(--color-primary-on-surface);
  font-weight: 600;
  text-decoration: underline;
}

.ai-quantity {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ai-space-5);
  margin-bottom: var(--ai-space-3);
}

.ai-quantity__total {
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: var(--ai-space-2);
}

.ai-quantity__total-label {
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
  text-transform: uppercase;
  letter-spacing: var(--tracking-eyebrow);
}

.ai-quantity__total-value {
  color: var(--color-primary);
  font-family: var(--font-display);
  font-size: var(--ai-size-2xl);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.ai-quantity__total-note,
.ai-quantity__rule {
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
}

.ai-quantity__rule {
  margin: 0;
}

/* Over the online limit the checkout is replaced by an enquiry. */
.ai-enquiry {
  margin-top: var(--ai-space-4);
  padding: var(--ai-space-5);
  background: var(--color-action-soft);
  border: 1px solid var(--color-action);
  border-radius: var(--card-radius);
}

.ai-enquiry__text {
  margin: 0 0 var(--ai-space-3);
  color: var(--color-heading);
}

.ai-selector__continue {
  padding-inline: var(--ai-space-6);
  font-size: var(--ai-size-base);
}

.ai-selector__continue:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Identity in the footer's Store information block: our mark and what we sell.
   The mark is dark artwork on transparency and the footer is navy, so the white
   plate is what makes it legible; it is never recoloured. The DEEP mark used to
   share this plate - it has its own banner above the contact band now. */
.aceioot-identity {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--ai-space-3);
  margin-bottom: var(--ai-space-4);
}

/* No plate behind it any more: the mark is white artwork now, so it sits
   straight on the navy band. */
.aceioot-identity__mark {
  display: block;
  width: auto;
  height: 2.5rem;
}

.aceioot-identity__tagline {
  color: rgba(255, 255, 255, 0.7);
  font-size: var(--ai-size-sm);
}

/* --------------------------------------------------------------------------
   FAQ (CMS page, client copy of 25 Aug 2026)
   --------------------------------------------------------------------------

   Native <details>, so every answer is reachable with JavaScript off and the
   browser's own find-in-page can open a closed one. Nothing here touches
   `display` on the rows - the disclosure is the element's own, not a class the
   theme's JS toggles. */

.ai-faq__lead {
  max-width: 60ch;
  margin-bottom: var(--ai-space-6);
  color: var(--color-muted);
}

.ai-faq__group + .ai-faq__group {
  margin-top: var(--ai-space-7);
}

.ai-faq__heading {
  margin: 0 0 var(--ai-space-4);
  padding-bottom: var(--ai-space-3);
  border-bottom: 1px solid var(--color-border);
  font-size: var(--ai-size-xl);
}

.ai-faq__item {
  border-bottom: 1px solid var(--color-border);
}

/* The row itself is the control, so it gets the whole width and a marker of its
   own; the default triangle sits too far from the text to read as a button. */
.ai-faq__q {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--ai-space-4);
  padding: var(--ai-space-4) 0;
  color: var(--color-heading);
  font-family: var(--font-display);
  font-size: var(--ai-size-base);
  font-weight: 700;
  line-height: var(--leading-tight);
  list-style: none;
  cursor: pointer;
}

.ai-faq__q::-webkit-details-marker {
  display: none;
}

.ai-faq__q::after {
  content: "+";
  flex: 0 0 auto;
  width: 1.5rem;
  color: var(--color-primary);
  font-size: var(--ai-size-lg);
  font-weight: 400;
  line-height: 1;
  text-align: center;
}

.ai-faq__item[open] > .ai-faq__q::after {
  content: "\2013"; /* en dash, so the two states are the same weight */
}

.ai-faq__q:hover,
.ai-faq__item[open] > .ai-faq__q {
  color: var(--color-primary-on-surface);
}

/* Keyboard focus lands on the summary; without this the outline is invisible
   against the row. */
.ai-faq__q:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.ai-faq__a {
  max-width: 72ch;
  padding-bottom: var(--ai-space-4);
  color: var(--color-body);
}

.ai-faq__a p {
  margin: 0 0 var(--ai-space-3);
}

.ai-faq__a p:last-child {
  margin-bottom: 0;
}

.ai-about__image {
  max-width: 100%;
  height: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--card-radius);
}

/* --------------------------------------------------------------------------
   Coverage page - the roaming footprint
   --------------------------------------------------------------------------

   Replaces the 2880x12100 picture this page used to be. Same 42 countries and
   128 operators, now as text: readable on a phone, indexable, selectable, and
   editable without opening a design tool.

   One country to a row, as the artwork had it. It was a three-column grid for a
   day, to keep the page short; the client asked for the artwork's shape back,
   and the search box over the top is what answers the length - nobody scrolls
   42 rows to check one country, they type its name. */

.ai-coverage__lead {
  max-width: 60ch;
  color: var(--color-muted);
}

.ai-coverage__stats {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ai-space-6);
  margin-bottom: var(--ai-space-6);
  padding: var(--ai-space-5) var(--ai-space-6);
  background: var(--color-primary-soft);
  border-radius: var(--card-radius);
}

.ai-coverage__figure {
  display: block;
  color: var(--color-primary-on-surface);
  font-family: var(--font-display);
  font-size: var(--ai-size-3xl);
  font-weight: 700;
  line-height: var(--leading-tight);
  font-variant-numeric: tabular-nums;
}

.ai-coverage__label {
  display: block;
  color: var(--color-body);
  font-size: var(--ai-size-sm);
  font-weight: 700;
}

/* The search box. `hidden` in the markup until coverage-filter.js takes it off,
   so it never appears without the script that makes it work. */
.ai-coverage__search {
  margin-bottom: var(--ai-space-5);
}

.ai-coverage__search-label {
  display: block;
  margin-bottom: var(--ai-space-2);
  color: var(--color-heading);
  font-family: var(--font-display);
  font-size: var(--ai-size-sm);
  font-weight: 700;
}

.ai-coverage__input {
  width: 100%;
  max-width: 34rem;
  padding: var(--ai-space-3) var(--ai-space-4);
  background: var(--color-page);
  border: 1px solid var(--color-border);
  border-radius: var(--ai-radius-pill);
  color: var(--color-body);
  font-family: var(--font-body);
  font-size: var(--ai-size-base);
}

.ai-coverage__input:focus-visible {
  border-color: var(--color-artwork-blue);
  outline: 2px solid var(--color-artwork-blue);
  outline-offset: 1px;
}

.ai-coverage__status {
  margin: var(--ai-space-2) 0 0;
  min-height: 1.5em; /* holds its line, so the list does not jump as you type */
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
}

.ai-coverage__empty {
  padding: var(--ai-space-5);
  background: var(--color-surface);
  border-radius: var(--card-radius);
  color: var(--color-muted);
}

.ai-coverage__grid {
  display: grid;
  gap: var(--ai-space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.ai-coverage__country {
  display: flex;
  flex-direction: column;
  gap: var(--ai-space-3);
  padding: var(--ai-space-4) var(--ai-space-5);
  background: var(--color-page);
  border: 1px solid var(--color-border);
  border-radius: var(--card-radius);
}

/* The operator count sits out at the right end of the row, as the artwork has
   it, with the name pushing it there. */
.ai-coverage__head {
  display: flex;
  align-items: center;
  gap: var(--ai-space-3);
  padding-bottom: var(--ai-space-3);
  border-bottom: 1px solid var(--color-border);
}

/* The country code, as the artwork had it. aria-hidden in the markup: it is the
   country's name abbreviated, and a screen reader announcing "AD Andorra" adds
   nothing. */
.ai-coverage__code {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 2.25rem;
  height: 2.25rem;
  background: var(--color-primary);
  border-radius: var(--ai-radius-md);
  color: var(--color-on-dark);
  font-family: var(--font-display);
  font-size: var(--ai-size-xs);
  font-weight: 700;
  letter-spacing: 0.02em;
}

.ai-coverage__name {
  flex: 1 1 auto;
  margin: 0;
  color: var(--color-heading);
  font-size: var(--ai-size-base);
  font-weight: 700;
}

.ai-coverage__count {
  flex: 0 0 auto;
  color: var(--color-muted);
  font-size: var(--ai-size-xs);
  white-space: nowrap;
}

.ai-coverage__ops {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ai-space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.ai-coverage__op {
  padding: var(--ai-space-1) var(--ai-space-3);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--ai-radius-pill);
  color: var(--color-body);
  font-size: var(--ai-size-xs);
  line-height: var(--leading-normal);
}

.ai-coverage__note {
  margin-top: var(--ai-space-5);
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
}

.ai-about__image {
  max-width: 22rem;
}

/* Case Study / Use cases by industry (mockup page 09).

   The band renders from displayContentWrapperBottom, so it is the only
   .ai-home-section in its parent and the sibling rule that spaces the home page
   sections apart never matches it. Hence the explicit margins. */
.ai-cases-band {
  margin-block: var(--ai-space-8);
}

.ai-case-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--ai-space-4);
}

.ai-case {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--card-padding);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--card-radius);
  text-align: center;
}

.ai-case__icon {
  display: grid;
  place-items: center;
  width: 3.25rem;
  height: 3.25rem;
  margin-bottom: var(--ai-space-4);
  background: var(--color-primary);
  border-radius: 50%;
  color: var(--color-on-dark);
}

.ai-case__icon svg {
  width: 1.5rem;
  height: 1.5rem;
}

.ai-case h3 {
  margin: 0 0 var(--ai-space-2);
  font-size: var(--ai-size-lg);
}

.ai-case p {
  margin: 0;
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
}

/* --------------------------------------------------------------------------
   Device slider — home page ("SIM card for Devices Slider")

   A scroll-snapping row rather than a scripted carousel. All four cards fit on
   a wide screen; narrower screens swipe natively. The arrow buttons only nudge
   the scroll position, so the section works with JavaScript disabled and with
   a keyboard.
   -------------------------------------------------------------------------- */

.ai-devslider {
  position: relative;
}

.ai-devslider__viewport {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(260px, 1fr);
  gap: var(--ai-space-4);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* Room for the card hover shadow, which would otherwise be clipped. */
  padding-bottom: var(--ai-space-3);
  scrollbar-width: thin;
}

.ai-devslider__item {
  scroll-snap-align: start;
}

.ai-devslider__controls {
  display: flex;
  gap: var(--ai-space-2);
  justify-content: flex-end;
  margin-top: var(--ai-space-3);
}

.ai-devslider__btn {
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  background: var(--color-page);
  border: 1px solid var(--color-border);
  border-radius: 50%;
  color: var(--color-primary-on-surface);
  font-size: var(--ai-size-lg);
  line-height: 1;
  cursor: pointer;
}

.ai-devslider__btn:hover,
.ai-devslider__btn:focus-visible {
  border-color: var(--color-primary);
  background: var(--color-surface);
}

.ai-devslider__btn:disabled {
  color: var(--color-inactive);
  cursor: not-allowed;
  opacity: 0.6;
}

/* Once every card fits, scrolling is impossible and the arrows are noise. */
@media (min-width: 1200px) {
  .ai-devslider__controls {
    display: none;
  }
}

.ai-device-card__note {
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
}

/* --------------------------------------------------------------------------
   Footer

   The contact band and PrestaShop's footer were two different darks stacked on
   top of each other - navy against Bootstrap's neutral dark - which read as a
   rendering fault rather than a design. The footer now continues the same navy,
   separated by a rule instead of a colour change.
   -------------------------------------------------------------------------- */

.footer__main {
  background: var(--color-heading) !important;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  color: rgba(255, 255, 255, 0.82);
}

.footer__main .footer-block__title,
.footer__main h3,
.footer__main .h3 {
  color: var(--color-on-dark);
  font-family: var(--font-display);
  font-size: var(--ai-size-base);
  font-weight: 700;
}

/* Stock links are indigo, which sits at roughly 2.9:1 on navy. White at 82%
   opacity measures about 9:1 and keeps the hierarchy quiet. */
.footer__main a {
  color: rgba(255, 255, 255, 0.82);
  text-decoration: none;
}

.footer__main a:hover,
.footer__main a:focus-visible {
  color: var(--color-primary-on-dark);
  text-decoration: underline;
}

.footer__main li {
  margin-bottom: var(--ai-space-2);
}

.copyright {
  padding-top: var(--ai-space-5);
  margin-top: var(--ai-space-5);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  text-align: center;
}

.copyright__line {
  margin: 0;
  color: rgba(255, 255, 255, 0.7);
  font-size: var(--ai-size-sm);
}

/* Contact band sits directly on the footer now, so it drops its own bottom
   padding and the seam between them disappears. */
.aceioot-contact {
  padding-bottom: var(--ai-space-6);
}

/* The footer carries four link columns plus Store information. All five sit in
   one Bootstrap row at col-lg-3, so the fifth wrapped onto a line of its own and
   left three quarters of it empty. Five equal columns close that gap. */
@media (min-width: 992px) {
  .footer__main-top > .footer-block {
    width: 20%;
    max-width: 20%;
  }
}

/* The contact row was a full-width bar holding two short links, which left a
   large empty stretch to the right. */
.aceioot-contact__details {
  display: inline-flex;
  width: auto;
  max-width: 100%;
}

/* --------------------------------------------------------------------------
   Home page hero — two stills that cross-fade
   -------------------------------------------------------------------------- */

.ai-hero {
  position: relative;
  /* Only ever seen before the first still paints, so it is that still's own
     field: the stops are sampled from hero-impact.jpg down an empty column,
     #a5d4fe near its top through to white at the foot. Both stills share the
     template, so it stands in for either. */
  background: linear-gradient(
    180deg,
    #a5d4fe 0%,
    #cfecfe 32%,
    #e6f5fc 58%,
    #f7fbfd 82%,
    #ffffff 100%
  );
}

.ai-hero__stage {
  position: relative;
  /* The stage takes the stills' own ratio, 1920x1047 = 1.834:1, so at its
     natural size neither is cropped and the lettering sits exactly where the
     artwork puts it. 54.5vw is that ratio as a height.

     Capped to the height actually free under the header, because 1.834:1 is
     785px at 1440 wide against roughly 670px of viewport. When the cap bites
     the stage is wider than the artwork and `cover` crops it, which it has
     room for - but only just, and only at the bottom. That is the floor's
     doing: the EU map runs from 0.4% to 84.7% of the frame's height, so 15.3%
     of it may go before the coastline does, and 46.2vw is 54.5vw less that.
     Below the floor the hero grows past the fold and the page scrolls a little
     - a window too short to hold the map is the one case where fitting loses.

     Stated as a height, NOT as `aspect-ratio`: CSS transfers a max-height
     through a ratio into a max-width, which caps the stage's *width* and leaves
     a gutter down the side of any wider viewport. `min()` on the height has no
     such side effect.

     svh, not vh, so mobile toolbars are counted; the vh line is the fallback
     for anything that does not know the unit. */
  height: clamp(46.2vw, calc(100vh - 8rem), 54.5vw);
  height: clamp(46.2vw, calc(100svh - 8rem), 54.5vw);
  overflow: hidden;
}

/* The whole of the transition: one still fades out as the next fades in, over
   a background both of them share. Long and eased, because a hero that changes
   quickly reads as a fault rather than as a slideshow. */
.ai-hero__slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1100ms ease-in-out;
}

.ai-hero__slide.is-active {
  opacity: 1;
}

/* Cover, so the stage is filled edge to edge: bands either side of a key
   visual read as a broken image, and these stills' field is a gradient no flat
   colour can match. `cover` only ever crops them vertically, since the stage is
   never narrower than 1.834:1 - which is what keeps a percentage of the stage's
   width equal to the same percentage of the frame, and so keeps the CTA under
   the lettering at every size.

   Aligned to the top rather than weighted between the margins. The EU map opens
   0.4% into the frame and has 15.3% of empty field beneath it, so all of the
   crop has to come off the bottom; anchoring there costs the other still
   nothing, which has 41% empty below its SIM. */
.ai-hero__media {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 0%;
}

.ai-hero__scrim {
  position: absolute;
  inset: 0;
  /* Guarantees the headline stays legible over any frame of any clip. */
  background: linear-gradient(
    90deg,
    rgba(20, 37, 58, 0.92) 0%,
    rgba(20, 37, 58, 0.75) 42%,
    rgba(20, 37, 58, 0.35) 100%
  );
  transition: background 700ms ease;
}

/* No overlay copy on this slide, so the scrim has nothing to protect: lift it
   to a light wash and let the clip's own artwork carry the frame. */
.ai-hero.is-quiet .ai-hero__scrim {
  background: linear-gradient(
    90deg,
    rgba(20, 37, 58, 0.14) 0%,
    rgba(20, 37, 58, 0.06) 42%,
    rgba(20, 37, 58, 0) 100%
  );
}

.ai-hero__content {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
}

/* With the overlay copy stood down, the CTA is all that is left, and it belongs
   under the still's own headline and flush with its left edge - not indented to
   the page container, which is where being a child of .container had put it. So
   it is placed against the stage instead, and both numbers are measured off the
   artwork rather than guessed.

   Both stills letter from 14.4% of the frame's width, and the frame always
   fills the stage's width exactly, so that percentage carries straight over.

   The vertical is simple because the crop is anchored to the top: a feature at
   fraction f of the frame is at f x 54.5vw down the stage, whatever the stage's
   height. The lower of the two last lines ends at 46.6% of the frame - the map
   copy, against 46.2% for the SIM copy - which is 25.4vw, and the button clears
   it by 3.5vw. It therefore sits under both, and holds still across the fade.

   If either still is replaced, re-measure 14.4% and 46.6% and change them here;
   nothing in this block is a guess. */
.ai-hero.is-quiet .ai-hero__cta {
  position: absolute;
  top: 28.9vw;
  left: 14.4%;
}

.ai-hero__title {
  max-width: 18ch;
  margin: 0 0 var(--ai-space-3);
  color: var(--color-on-dark);
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 4vw, var(--ai-size-4xl));
  line-height: 1.1;
}

.ai-hero__lead {
  max-width: 42ch;
  margin: 0 0 var(--ai-space-5);
  color: rgba(255, 255, 255, 0.88);
  font-size: var(--ai-size-lg);
}

/* The hero button carries the whole frame on its own, so it is sized well above
   a body button. Clamped rather than fixed: at full width it has to hold its
   own against lettering several hundred pixels tall, and on a phone the stage
   is only a few hundred pixels high in total.

   It takes the map's blue rather than the indigo every other primary button
   wears, so that it belongs to the clip it is sitting on and to the cards below
   it. Done by redefining the two component tokens on this element alone:
   .btn-primary already resolves its background and its hover through them, so
   both states follow with no second rule and no specificity fight, and no other
   button in the shop moves. Hover goes to the SIM pack's deeper blue, which is
   a real state change rather than a tint. */
.ai-hero__cta {
  --btn-primary-bg: var(--color-artwork-blue);
  --btn-primary-bg-hover: var(--color-artwork-deep);
  padding: clamp(0.75rem, 1.1vw, 1.15rem) clamp(1.5rem, 2.6vw, 2.75rem);
  font-size: clamp(1rem, 1.35vw, 1.375rem);
  font-weight: 700;
}

/* Standing the overlay copy down for a clip that has its own.

   Taken out of the render, not merely faded: an opacity-0 <h1> would still be
   drag-selectable and would still reserve the space that pushes the CTA off
   centre. The clip technique keeps it in the accessibility tree, so the home
   page keeps its <h1> whichever clip is on screen.

   Note this changes the CTA's vertical position, so a hero mixing copy and
   no-copy slides would shift on every transition. Every clip supplied so far
   carries its own lettering, so nothing mixes today. */
.ai-hero.is-quiet .ai-hero__title,
.ai-hero.is-quiet .ai-hero__lead {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.ai-hero__dots {
  position: absolute;
  bottom: var(--ai-space-4);
  left: 50%;
  display: flex;
  gap: var(--ai-space-2);
  transform: translateX(-50%);
}

.ai-hero__dot {
  width: 2rem;
  height: 4px;
  padding: 0;
  border: 0;
  border-radius: var(--ai-radius-pill);
  background: rgba(255, 255, 255, 0.4);
  cursor: pointer;
}

/* Without the scrim the frame underneath is pale, and white on pale is nothing.
   Same swap the scrim makes, in reverse. */
.ai-hero.is-quiet .ai-hero__dot {
  background: rgba(20, 37, 58, 0.28);
}

.ai-hero.is-quiet .ai-hero__dot.is-active {
  background: var(--color-heading);
}

.ai-hero__dot.is-active {
  background: var(--color-on-dark);
}

/* Dots are small; give them a proper focus ring and a 44px hit area. */
.ai-hero__dot::before {
  content: "";
  position: absolute;
  inset: -20px -6px;
}

.ai-hero__dot:focus-visible {
  outline: 2px solid var(--color-on-dark);
  outline-offset: 4px;
}

@media (max-width: 767.98px) {
  /* The stage keeps the artwork's ratio at every width: a taller mobile crop
     would take it off the sides - where the lettering starts 14.4% in and the
     map ends at 94.2% - which is the whole message. Both stills are pale, so
     the scrim stays the light wash `is-quiet` sets.

     The button is the one thing that cannot scale with the frame: it has a
     floor of readable type and tappable padding, so on a 390px stage it is a
     third of the width rather than a seventh, and under the lettering it runs
     into Iberia. Moved to the empty bottom-left corner, which is clear on both
     stills - the map starts 45.8% across and the SIM further right still. */
  .ai-hero.is-quiet .ai-hero__cta {
    top: auto;
    bottom: 12%;
    left: 6%;
  }
}

/* --------------------------------------------------------------------------
   Category cards with imagery (Pic 6 / 7 / 8)
   -------------------------------------------------------------------------- */

.ai-nav-card--media {
  padding: 0;
  /* White, not the pale panel surface: these cards are product shots on white,
     and a tinted panel behind them showed as a border around the photograph. */
  background: var(--color-page);
  overflow: hidden;
}

.ai-nav-card--media .ai-nav-card__media {
  display: block;
  background: var(--color-page);
}

.ai-nav-card--media .ai-nav-card__media img {
  display: block;
  width: 100%;
  height: auto;
  /* The artwork is 8:5. Framing it in a wider box shrinks the picture without
     touching the text below: the box is the full card width, the image scales
     to fit inside it and centres, and the spare space either side is the same
     white as the card. Change this ratio, not the image files, to retune how
     large the photographs read.

     At 12/5 the picture filled two thirds of the card and the client asked for
     bigger; 2/1 takes it to four fifths, which is a fifth larger in both
     directions and still leaves the artwork clear of the card's edges. */
  aspect-ratio: 2 / 1;
  /* Contain, not cover: Pic 6 is portrait and cover cut the SIM pack in half. */
  object-fit: contain;
}

.ai-nav-card--media .ai-nav-card__body {
  display: flex;
  flex-direction: column;
  padding: var(--card-padding);
}

/* The Top-Ups card is the artwork and nothing else. The client's top-up banner
   carries its own wording, so a title and note beneath it would say the same
   thing twice; the picture takes the whole card instead.

   Hence cover where the other two contain: those are product shots that must
   stay whole, this is a banner with its subject in the middle and margin all
   round, so cropping a little off the top and bottom costs nothing. The aspect
   ratio is the artwork's own, which is what gives the card a height of its own
   when the grid drops to one column; flex-grow then stretches it to match the
   taller cards beside it on a wide screen. */
.ai-nav-card--cover {
  padding: 0;
  overflow: hidden;
  /* Kept, not dropped, so the hover state still has a border to colour. */
  border-color: transparent;
}

.ai-nav-card--cover .ai-nav-card__media {
  position: relative;
  flex: 1 1 auto;
  aspect-ratio: 8 / 5;
}

/* Absolute rather than height:100%, which would depend on the flex item having
   resolved a definite height before the image is laid out. */
.ai-nav-card--cover .ai-nav-card__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* --------------------------------------------------------------------------
   Top-up flow (mockup page 04) and the My SIMs additions

   Not in the shop's custom.css: the shop's top-up page is still a product grid.
   Step 2 reuses the package selector's .ai-tier cards unchanged; what is new is
   the SIM picker in step 1. Selection is indigo, like every other selection on
   the site — orange stays on the Check-out button.
   -------------------------------------------------------------------------- */

.ai-sim-pick__toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--ai-space-3);
  margin-bottom: var(--ai-space-3);
}

.ai-sim-pick__search {
  flex: 1 1 18rem;
  max-width: 28rem;
}

.ai-sim-pick__bulk {
  display: flex;
  align-items: center;
  gap: var(--ai-space-3);
  font-size: var(--ai-size-sm);
}

.ai-sim-pick__count {
  color: var(--color-muted);
}

/* Customers buy in tens, so the list scrolls inside the step rather than
   pushing the packages a hundred rows down the page. */
.ai-sim-pick {
  display: grid;
  gap: var(--ai-space-2);
  max-height: 28rem;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  list-style: none;
}

.ai-sim-pick__row {
  display: flex;
  align-items: center;
  gap: var(--ai-space-3);
  padding: var(--ai-space-3) var(--ai-space-4);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--ai-radius-md);
  cursor: pointer;
}

.ai-sim-pick__row:has(.ai-sim-pick__check:checked) {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 1px var(--color-primary);
  background: var(--color-page);
}

.ai-sim-pick__row.is-disabled {
  color: var(--color-muted);
  cursor: not-allowed;
}

.ai-sim-pick__check {
  flex: none;
  margin: 0;
}

.ai-sim-pick__main {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-width: 0;
}

.ai-sim-pick__title {
  color: var(--color-heading);
  font-weight: 600;
}

.ai-sim-pick__row.is-disabled .ai-sim-pick__title {
  color: var(--color-muted);
}

.ai-sim-pick__tag {
  margin-left: var(--ai-space-2);
  padding: 0 var(--ai-space-2);
  border-radius: var(--badge-radius);
  background: var(--color-surface-tint);
  color: var(--color-primary);
  font-size: var(--ai-size-xs);
  font-weight: 600;
}

.ai-sim-pick__side {
  display: flex;
  flex: none;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--ai-space-1);
  text-align: right;
}

.ai-sim-pick__data {
  color: var(--color-body, #23384f);
  font-size: var(--ai-size-sm);
}

.ai-sim-pick__data.is-low {
  color: var(--color-danger);
  font-weight: 600;
}

.ai-sim-pick__note {
  color: var(--color-warning, #a35b00);
  font-size: var(--ai-size-sm);
  font-weight: 600;
}

.ai-sim-pick__status {
  padding: var(--ai-space-3) 0;
  color: var(--color-muted);
}

@media (max-width: 575.98px) {
  .ai-sim-pick__row {
    flex-wrap: wrap;
  }

  /* Under the ICCID rather than beside it: a 23-character ICCID and a balance
     do not both fit on one line at phone width. */
  .ai-sim-pick__side {
    flex-direction: row;
    align-items: center;
    width: 100%;
    padding-left: calc(1em + var(--ai-space-3));
    text-align: left;
  }
}

.ai-topup__signin {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--ai-space-3);
  padding: var(--ai-space-4);
  background: var(--color-surface);
  border: 1px dashed var(--card-border);
  border-radius: var(--ai-radius-md);
}

.ai-topup__eligibility {
  margin: 0 0 var(--ai-space-4);
  color: var(--color-body);
  font-size: var(--ai-size-sm);
  line-height: 1.45;
}

.ai-topup__none-due {
  margin: var(--ai-space-3) 0 0;
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
}

.ai-topup__summary {
  margin-top: var(--ai-space-4);
}

.ai-topup-cta p {
  color: var(--color-muted);
}

.ai-topup-history {
  margin-top: var(--ai-space-7);
}

/* --------------------------------------------------------------------------
   My SIMs — one filterable table instead of the shop's card grid

   The colours are the dashboard's status rule (aceioot-front.css), carried
   onto rows: green only for an active, healthy SIM, red for data running out,
   amber for a suspended line or an approaching date, grey for a dead line.
   Filter selection is indigo like every other selection; no orange here.
   -------------------------------------------------------------------------- */

.ai-sims-loading {
  padding: var(--ai-space-6) 0;
  color: var(--color-muted);
}

.ai-sims-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--ai-space-2) var(--ai-space-5);
  margin-bottom: var(--ai-space-4);
}

.ai-sims-head .aceioot-account-ref {
  margin: 0;
}

.ai-sims-note {
  margin: 0;
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
}

.ai-sims-eligibility {
  margin: 0 0 var(--ai-space-4);
  color: var(--color-body);
  font-size: var(--ai-size-sm);
  line-height: 1.45;
}

.ai-sims-panel {
  background: var(--color-page);
  border: 1px solid var(--color-border);
  border-radius: var(--ai-radius-lg);
  box-shadow: var(--ai-shadow-sm);
  overflow: hidden;
}

.ai-sims-filters {
  display: grid;
  gap: var(--ai-space-3);
  padding: var(--ai-space-4);
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
}

.ai-sims-controls {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ai-space-2);
}

.ai-sims-search {
  position: relative;
  flex: 1 1 18rem;
  margin: 0;
}

.ai-sims-search .material-icons {
  position: absolute;
  top: 50%;
  left: var(--ai-space-3);
  color: var(--color-muted);
  font-size: 1.25rem;
  pointer-events: none;
  transform: translateY(-50%);
}

.ai-sims-search .form-control {
  padding-left: 2.5rem;
  background-color: var(--color-page);
}

.ai-sims-select {
  flex: 0 1 12rem;
  width: auto;
  background-color: var(--color-page);
}

/* The sort select stands in for the column headers, which only exist on
   wider screens. */
.ai-sims-sort {
  display: none;
}

.ai-sims-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ai-space-2);
}

.ai-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.5rem 0.3rem 0.75rem;
  background: var(--color-page);
  border: 1px solid var(--color-border);
  border-radius: var(--ai-radius-pill);
  color: var(--color-body);
  font-size: var(--ai-size-sm);
  font-weight: 600;
  line-height: 1.4;
  cursor: pointer;
  transition: border-color 0.15s, background-color 0.15s, color 0.15s;
}

.ai-chip:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.ai-chip:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.ai-chip[aria-pressed="true"] {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-on-dark);
}

.ai-chip__dot {
  flex: none;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
}

.ai-chip__dot--ok { background: var(--color-success); }
.ai-chip__dot--low { background: var(--color-danger); }
.ai-chip__dot--warn { background: var(--color-warning); }
.ai-chip__dot--muted { background: var(--color-inactive); }

.ai-chip[aria-pressed="true"] .ai-chip__dot {
  box-shadow: 0 0 0 2px var(--color-on-dark);
}

.ai-chip__count {
  min-width: 1.375rem;
  padding: 0 0.375rem;
  border-radius: var(--ai-radius-pill);
  background: var(--color-surface-tint);
  color: var(--color-muted);
  font-size: var(--ai-size-xs);
  line-height: 1.375rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.ai-chip[aria-pressed="true"] .ai-chip__count {
  background: rgba(255, 255, 255, 0.22);
  color: var(--color-on-dark);
}

.ai-sims-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--ai-space-2);
  padding: var(--ai-space-2) var(--ai-space-4);
  border-bottom: 1px solid var(--color-border);
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
}

.ai-sims-clear {
  font-size: var(--ai-size-sm);
}

.ai-sims-scroll {
  overflow-x: auto;
}

/* Shared by the SIM table and the top-up history. Not Bootstrap's .table, so
   Hummingbird's layered table rules do not need overriding cell by cell. */
.ai-data-table {
  width: 100%;
  margin: 0;
  border-collapse: separate;
  border-spacing: 0;
  color: var(--color-body);
  font-size: var(--ai-size-sm);
}

/* Hummingbird borders every cell; rows here are separated by rules only. */
.ai-data-table th,
.ai-data-table td {
  border: 0;
}

.ai-data-table thead th {
  padding: var(--ai-space-3) var(--ai-space-4);
  background: var(--color-page);
  border-bottom: 1px solid var(--color-border);
  color: var(--color-muted);
  font-size: var(--ai-size-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-align: left;
  text-transform: uppercase;
  white-space: nowrap;
}

.ai-data-table tbody td {
  padding: var(--ai-space-3) var(--ai-space-4);
  border-bottom: 1px solid var(--color-border);
  vertical-align: middle;
}

.ai-data-table tbody tr:last-child td {
  border-bottom: 0;
}

.ai-data-table tbody tr:hover td {
  background: var(--color-surface);
}

.ai-data-table .text-end {
  text-align: right;
}

.ai-sort {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  padding: 0;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
}

.ai-sort .material-icons {
  font-size: 1rem;
  opacity: 0.4;
}

.ai-sort:hover,
th[aria-sort] .ai-sort {
  color: var(--color-primary);
}

th[aria-sort] .ai-sort .material-icons {
  opacity: 1;
}

.ai-sort:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
  border-radius: 2px;
}

/* The row's state as a 4px rule down its left edge, so a column of rows can be
   scanned for red and amber without reading a single badge. */
.ai-sims-row {
  --row-accent: transparent;
}

.ai-sims-row td:first-child {
  box-shadow: inset 4px 0 0 var(--row-accent);
}

.ai-sims-row--ok { --row-accent: var(--color-success); }
.ai-sims-row--low { --row-accent: var(--color-danger); }
.ai-sims-row--warn { --row-accent: var(--color-warning); }
.ai-sims-row--muted { --row-accent: var(--color-inactive); }

.ai-sims-row--low td {
  background: color-mix(in srgb, var(--color-danger) 4%, var(--color-page));
}

.ai-sims-row--muted td,
.ai-sims-row--muted .ai-sims-plan,
.ai-sims-row--muted .aceioot-iccid {
  color: var(--color-muted);
}

.ai-sims-cell-sim {
  min-width: 15rem;
}

.ai-sims-iccid-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ai-space-1) var(--ai-space-2);
}

.ai-sims-cell-sim .aceioot-iccid {
  color: var(--color-heading);
  font-size: var(--ai-size-base);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.ai-sims-plan {
  color: var(--color-heading);
  font-weight: 600;
}

.ai-sims-cell {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.125rem;
  white-space: nowrap;
}

.ai-sims-sub {
  color: var(--color-muted);
  font-size: var(--ai-size-xs);
}

.ai-sims-data {
  color: var(--color-heading);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.ai-sims-row--muted .ai-sims-data {
  color: var(--color-muted);
}

.ai-sims-data.is-low,
.ai-sims-flag {
  color: var(--color-danger);
}

.ai-sims-flag {
  font-size: var(--ai-size-xs);
  font-weight: 600;
}

.ai-sims-soon,
.ai-sims-pending {
  color: var(--color-warning);
  font-size: var(--ai-size-xs);
  font-weight: 600;
}

.ai-sims-pending {
  margin-top: 0.25rem;
}

.ai-sims-due {
  margin-top: 0.25rem;
  color: var(--color-primary);
  font-size: var(--ai-size-xs);
  font-weight: 600;
}

.ai-sims-updated {
  color: var(--color-muted);
  font-variant-numeric: tabular-nums;
}

.ai-sims-empty {
  padding: var(--ai-space-6) var(--ai-space-4) !important;
  color: var(--color-muted);
  text-align: center;
}

/* Phones: each row becomes a stacked block, label on the left and value on the
   right, rather than a table that has to be scrolled sideways to find the
   balance. */
@media (max-width: 767.98px) {
  .ai-sims-sort {
    display: block;
  }

  .ai-sims-select {
    flex: 1 1 8rem;
  }

  /* One swipeable line of chips rather than four wrapped rows above the SIMs. */
  .ai-sims-chips {
    flex-wrap: nowrap;
    margin-inline: calc(-1 * var(--ai-space-4));
    padding: 2px var(--ai-space-4);
    overflow-x: auto;
    scrollbar-width: none;
  }

  .ai-chip {
    flex: none;
  }

  .ai-sims-table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
  }

  .ai-sims-table,
  .ai-sims-table tbody,
  .ai-sims-table tr,
  .ai-sims-table td {
    display: block;
  }

  .ai-sims-table tbody tr {
    padding: var(--ai-space-3) var(--ai-space-4) var(--ai-space-3) var(--ai-space-5);
    border-bottom: 1px solid var(--color-border);
    box-shadow: inset 4px 0 0 var(--row-accent, transparent);
  }

  .ai-sims-table tbody tr:last-child {
    border-bottom: 0;
  }

  .ai-sims-row--low {
    background: color-mix(in srgb, var(--color-danger) 4%, var(--color-page));
  }

  .ai-sims-table tbody td,
  .ai-sims-table tbody tr:hover td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--ai-space-4);
    padding: 0.3rem 0;
    background: none;
    border: 0;
    box-shadow: none;
  }

  .ai-sims-table tbody td::before {
    content: attr(data-label);
    flex: none;
    color: var(--color-muted);
    font-size: var(--ai-size-xs);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
  }

  .ai-sims-table .ai-sims-cell {
    align-items: flex-end;
    text-align: right;
  }

  /* The row carries the accent here, so the cell must not draw a second. */
  .ai-sims-table .ai-sims-row td.ai-sims-cell-sim {
    display: block;
    min-width: 0;
    padding-bottom: var(--ai-space-2);
    box-shadow: none;
  }

  .ai-sims-table td.ai-sims-cell-sim::before,
  .ai-sims-table td.ai-sims-empty::before {
    content: none;
  }

  .ai-sims-table td.ai-sims-empty {
    display: block;
  }
}

/* --------------------------------------------------------------------------
   Your account — profile card, primary My SIMs action, coming-soon rows
   -------------------------------------------------------------------------- */

.ai-account {
  display: grid;
  gap: var(--ai-space-5);
}

.ai-account-profile {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--ai-space-4);
  padding: var(--ai-space-5);
  background: var(--color-page);
  border: 1px solid var(--color-border);
  border-radius: var(--ai-radius-lg);
  box-shadow: var(--ai-shadow-sm);
}

.ai-account-profile__main {
  display: grid;
  gap: 0.25rem;
  min-width: 0;
}

.ai-account-profile__name {
  margin: 0;
  color: var(--color-heading);
  font-size: var(--ai-size-lg);
  font-weight: 700;
  line-height: 1.3;
}

.ai-account-profile__email {
  margin: 0;
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
  word-break: break-word;
}

.ai-account-profile .aceioot-account-ref {
  margin: var(--ai-space-2) 0 0;
}

.ai-account-profile__signout {
  flex: none;
}

.ai-account-primary {
  display: grid;
  gap: var(--ai-space-2);
}

.ai-account-card {
  display: flex;
  align-items: center;
  gap: var(--ai-space-4);
  padding: var(--ai-space-4) var(--ai-space-5);
  background: var(--color-page);
  border: 1px solid var(--color-border);
  border-radius: var(--ai-radius-lg);
  box-shadow: var(--ai-shadow-sm);
  color: inherit;
  text-decoration: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}

.ai-account-card:hover {
  border-color: var(--color-primary);
  box-shadow: var(--ai-shadow-md, var(--ai-shadow-sm));
  color: inherit;
  text-decoration: none;
}

.ai-account-card:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.ai-account-card__icon {
  display: grid;
  place-items: center;
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  background: var(--color-primary-soft, #eef1fd);
  border-radius: var(--ai-radius-md, 0.5rem);
  color: var(--color-primary);
}

.ai-account-card__icon .material-icons {
  font-size: 1.5rem;
}

.ai-account-card__body {
  display: grid;
  gap: 0.2rem;
  flex: 1 1 auto;
  min-width: 0;
}

.ai-account-card__title {
  display: inline-flex;
  align-items: center;
  color: var(--color-heading);
  font-size: var(--ai-size-md, 1.05rem);
  font-weight: 700;
}

.ai-account-card__desc {
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
  line-height: 1.45;
}

.ai-account-card__chevron {
  flex: none;
  color: var(--color-muted);
  font-size: 1.5rem;
}

.ai-account-primary__alt {
  margin: 0;
  padding-inline: var(--ai-space-1);
  color: var(--color-muted);
  font-size: var(--ai-size-sm);
}

.ai-account-soon__heading {
  margin: 0 0 var(--ai-space-2);
  color: var(--color-muted);
  font-size: var(--ai-size-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.ai-account-soon__list {
  margin: 0;
  padding: 0;
  list-style: none;
  background: var(--color-page);
  border: 1px solid var(--color-border);
  border-radius: var(--ai-radius-lg);
  overflow: hidden;
}

.ai-account-soon__list li + li {
  border-top: 1px solid var(--color-border);
}

.ai-account-soon__row {
  display: flex;
  align-items: center;
  gap: var(--ai-space-3);
  padding: var(--ai-space-3) var(--ai-space-4);
  color: var(--color-muted);
  cursor: default;
}

.ai-account-soon__row .material-icons {
  flex: none;
  font-size: 1.35rem;
  opacity: 0.7;
}

.ai-account-soon__label {
  flex: 1 1 auto;
  min-width: 0;
  font-weight: 600;
}

.ai-account-soon__badge {
  flex: none;
  padding: 0.15rem 0.55rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--ai-radius-pill);
  font-size: var(--ai-size-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
}

/* --------------------------------------------------------------------------
   Support page — contact next step under the CMS body
   -------------------------------------------------------------------------- */

.ai-support-contact {
  margin-top: 0;
  padding: var(--ai-space-5);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--color-primary);
  border-radius: var(--ai-radius-lg);
}

.ai-support-contact .h5 {
  margin: 0 0 var(--ai-space-2);
  color: var(--color-heading);
}

.ai-support-contact p {
  margin: 0;
  color: var(--color-body);
  line-height: 1.55;
}

.ai-support-contact a {
  font-weight: 600;
}
