/*
  MudBlazor provides essentially all styling. These few rules exist only for the
  statically rendered Identity forms, which use plain <InputText> elements so the
  browser can post them without a Blazor circuit.
*/

html,
body {
    /* System font stack: no webfont request, so nothing blocks first paint and
       nothing violates the 'self'-only CSP. */
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Helvetica Neue", Arial, sans-serif;
}

.aries-field {
    margin-bottom: 1.15rem;
}

.aries-field > label {
    display: block;
    margin-bottom: 0.35rem;
    font-size: 0.875rem;
    font-weight: 500;
}

.aries-input {
    box-sizing: border-box;
    width: 100%;
    /* 16px minimum: anything smaller makes iOS Safari zoom on focus, which
       breaks the layout on a phone. */
    font-size: 1rem;
    padding: 0.65rem 0.75rem;
    border: 1px solid var(--mud-palette-lines-inputs);
    border-radius: var(--mud-default-borderradius);
    background-color: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
}

.aries-input:focus {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 1px;
    border-color: var(--mud-palette-primary);
}

.aries-input.invalid {
    border-color: var(--mud-palette-error);
}

.aries-validation {
    display: block;
    margin-top: 0.3rem;
    font-size: 0.8rem;
    color: var(--mud-palette-error);
}

.aries-checkbox {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.9rem;
}

.aries-checkbox input {
    /* 18px keeps the tap target usable on touch screens. */
    width: 18px;
    height: 18px;
}

/* --- Admin ------------------------------------------------------------- */

.cursor-pointer {
    cursor: pointer;
}

.admin-drawer {
    /* Border rather than elevation: the admin drawer sits inside the main
       layout, and a second shadow reads as a floating panel. */
    border-right: 1px solid var(--mud-palette-divider);
}

/* Content that an administrator authored, rendered as HTML in the preview
   pane. Scoped so page markup cannot restyle the admin UI around it. */
.content-preview {
    max-width: 70ch;
    line-height: 1.6;
}

.content-preview img {
    max-width: 100%;
    height: auto;
}

.content-preview table {
    width: 100%;
    border-collapse: collapse;
}

@media print {
    /* Printing an invoice should produce the invoice, not the whole admin
       shell around it. */
    .mud-appbar,
    .mud-drawer,
    .mud-snackbar-provider,
    .mud-breadcrumbs {
        display: none !important;
    }

    .mud-main-content {
        padding: 0 !important;
    }

    #invoice-print {
        box-shadow: none !important;
    }
}

/* --- Storefront --------------------------------------------------------- */

/* Fonts come from settings, injected as custom properties by the layout, so a
   new company restyles the type without touching this file. */
body {
    font-family: var(--aries-body-font, inherit);
}

h1, h2, h3, h4, h5, h6,
.mud-typography-h1, .mud-typography-h2, .mud-typography-h3,
.mud-typography-h4, .mud-typography-h5, .mud-typography-h6 {
    font-family: var(--aries-heading-font, inherit);
}

.aries-hero {
    background: var(--mud-palette-primary-hover);
    border-bottom: 1px solid var(--mud-palette-divider);
}

.aries-hero-inner {
    max-width: 46ch;
}

.aries-hero-headline {
    /* Scales with the viewport rather than stepping at breakpoints, so the
       headline never wraps awkwardly on a mid-size phone. */
    font-size: clamp(2rem, 6vw, 3.5rem);
    line-height: 1.1;
}

.aries-hero-subtext {
    font-weight: 400;
    opacity: .9;
}

.aries-product-card {
    transition: transform .15s ease, box-shadow .15s ease;
}

.aries-product-card:hover {
    transform: translateY(-2px);
}

@media (prefers-reduced-motion: reduce) {
    /* Respect the setting rather than overriding it: the lift is decoration. */
    .aries-product-card,
    .aries-product-card:hover {
        transition: none;
        transform: none;
    }
}

.aries-product-image {
    position: relative;
    aspect-ratio: 4 / 3;
    overflow: hidden;
    background: var(--mud-palette-background-gray);
}

.aries-product-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.aries-product-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    color: var(--mud-palette-text-disabled);
    background: var(--mud-palette-background-gray);
}

.aries-product-badge {
    position: absolute;
    top: .5rem;
    left: .5rem;
}

/* Line clamps keep cards the same height without truncating mid-word. */
.aries-clamp-2,
.aries-clamp-4 {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.aries-clamp-2 {
    -webkit-line-clamp: 2;
}

.aries-clamp-4 {
    -webkit-line-clamp: 4;
}

.aries-category-tile {
    transition: border-color .15s ease;
}

.aries-category-tile:hover {
    border-color: var(--mud-palette-primary);
}

.aries-scoop-banner {
    background: var(--mud-palette-secondary-hover);
    border: 1px solid var(--mud-palette-divider);
}

.aries-gallery-main {
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    border-radius: var(--mud-default-borderradius);
}

.aries-thumb {
    min-width: 0;
    padding: 0;
    border: 1px solid var(--mud-palette-divider);
    border-radius: var(--mud-default-borderradius);
    overflow: hidden;
}

.aries-cart-body {
    flex: 1 1 auto;
    overflow-y: auto;
}

.aries-cart-line + .aries-cart-line {
    border-top: 1px solid var(--mud-palette-divider);
}

.aries-cart-foot {
    border-top: 1px solid var(--mud-palette-divider);
    background: var(--mud-palette-surface);
}

/* The footer takes the header colour, so the page is bracketed by the same
   band top and bottom. Its text is inherited from the appbar text variable for
   the same reason the header picks its own: whatever colour a shop chooses for
   the band, the type on it has to stay readable. */
.aries-footer {
    border-top: 1px solid var(--mud-palette-divider);
    background-color: var(--mud-palette-appbar-background);
    color: var(--mud-palette-appbar-text);
}

/* MudBlazor colours these from the page palette, which is the wrong ground
   underneath them now.

   MudLink in particular renders with mud-primary-text, so on a footer that has
   taken the header colour the links come out the same violet as the ground
   they sit on — legible only if you already know they are there. Every text
   class MudBlazor puts on footer content is listed, because missing one is
   invisible until somebody cannot find a link. */
/* The selectors are deliberately over-specified.

   MudThemeProvider injects its palette as a style block at runtime, which
   lands after app.css in the document. At equal specificity that later rule
   wins, so a plain ".aries-footer .mud-link" lost to MudBlazor's own
   ".mud-link.mud-primary-text" and the footer links came out the same violet
   as the footer itself — legible only if you already knew they were there.
   Naming the element as well as the classes puts these above it. */
footer.aries-footer,
footer.aries-footer .mud-typography,
footer.aries-footer .mud-typography-overline,
footer.aries-footer .mud-typography-body2,
footer.aries-footer .mud-typography-caption,
footer.aries-footer a.mud-link,
footer.aries-footer a.mud-link.mud-primary-text,
footer.aries-footer .mud-primary-text,
footer.aries-footer a,
footer.aries-footer .mud-text-secondary,
footer.aries-footer .mud-icon-root {
    color: var(--mud-palette-appbar-text) !important;
}

.aries-footer .mud-text-secondary,
.aries-footer .mud-typography-overline {
    opacity: .8;
}

@media (min-width: 960px) {
    /* Filters and the order summary follow the page rather than scrolling off
       the top of a long grid. */
    .aries-filters,
    .aries-summary {
        position: sticky;
        top: 88px;
    }
}

/* Settings screen swatch and image preview. */
.aries-swatch {
    width: 40px;
    height: 40px;
    border: 1px solid var(--mud-palette-divider);
    border-radius: var(--mud-default-borderradius);
}

.aries-setting-preview {
    border: 1px solid var(--mud-palette-divider);
    border-radius: var(--mud-default-borderradius);
    background: var(--mud-palette-background-gray);
    padding: 4px;
}

/* --- Customer account --------------------------------------------------- */

.aries-product-card {
    position: relative;
}

.aries-wishlist-corner {
    position: absolute;
    top: .25rem;
    right: .25rem;
    z-index: 1;
    background: color-mix(in srgb, var(--mud-palette-surface) 80%, transparent);
}

.aries-account-nav .mud-nav-link {
    border-radius: var(--mud-default-borderradius);
}

/* A hairline between rows, but not above the first one. */
.aries-account-row + .aries-account-row {
    border-top: 1px solid var(--mud-palette-divider);
}

/* --- Sale pricing and media -------------------------------------------- */

.aries-was-price {
    text-decoration: line-through;
    color: var(--mud-palette-text-secondary);
}

.aries-thumb-inner {
    position: relative;
    display: block;
    line-height: 0;
}

/* Marks a thumbnail as a video without needing a separate strip for them. */
.aries-thumb-play {
    position: absolute;
    inset: 0;
    margin: auto;
    color: #fff;
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .6));
}

video.aries-gallery-main {
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    border-radius: var(--mud-default-borderradius);
    background: #000;
}

/* Cart page rows: a hairline between, but not above the first. */
.aries-cart-row + .aries-cart-row {
    border-top: 1px solid var(--mud-palette-divider);
}

/* --- Connection and error UI -------------------------------------------- */

/*
  Blazor Server runs the page over a WebSocket. When that drops — a phone
  moving between wifi and data, a lift, a tunnel — the framework looks for
  these two elements by id. Without them the page simply stops responding to
  clicks and says nothing, which reads as "this shop is broken" rather than
  "your signal went". On a South African mobile connection that is not an edge
  case, it is Tuesday.

  The ids and state classes are fixed by the framework; only the styling here
  is ours.
*/

#components-reconnect-modal {
    display: none;
}

/* Shown while it is retrying. */
#components-reconnect-modal.components-reconnect-show,
#components-reconnect-modal.components-reconnect-failed,
#components-reconnect-modal.components-reconnect-rejected {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 20000;
    align-items: center;
    justify-content: center;
    /* Dimmed rather than opaque: seeing the page underneath is what tells the
       customer their basket is still there. */
    background: rgba(0, 0, 0, .45);
    backdrop-filter: blur(2px);
}

.aries-reconnect-card {
    max-width: 22rem;
    margin: 1rem;
    padding: 1.5rem;
    border-radius: var(--mud-default-borderradius, 6px);
    background: var(--mud-palette-surface, #fff);
    color: var(--mud-palette-text-primary, #1a1a1a);
    box-shadow: 0 10px 40px rgba(0, 0, 0, .3);
    text-align: center;
    font-size: .95rem;
    line-height: 1.5;
}

.aries-reconnect-card h2 {
    margin: 0 0 .5rem;
    font-size: 1.05rem;
    font-weight: 600;
}

.aries-reconnect-card p {
    margin: 0;
    color: var(--mud-palette-text-secondary, #555);
}

/* Each state shows one message. The framework only ever sets one class. */
.aries-reconnect-retrying,
.aries-reconnect-failed {
    display: none;
}

.components-reconnect-show .aries-reconnect-retrying,
.components-reconnect-failed .aries-reconnect-failed,
.components-reconnect-rejected .aries-reconnect-failed {
    display: block;
}

.aries-reconnect-spinner {
    width: 2rem;
    height: 2rem;
    margin: 0 auto 1rem;
    border: 3px solid var(--mud-palette-divider, #ddd);
    border-top-color: var(--mud-palette-primary, #1f4e79);
    border-radius: 50%;
    animation: aries-spin 1s linear infinite;
}

@keyframes aries-spin {
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .aries-reconnect-spinner {
        animation-duration: 3s;
    }
}

.aries-reconnect-button {
    margin-top: 1rem;
    padding: .6rem 1.2rem;
    border: 0;
    border-radius: var(--mud-default-borderradius, 6px);
    background: var(--mud-palette-primary, #1f4e79);
    color: var(--mud-palette-primary-text, #fff);
    font: inherit;
    font-weight: 500;
    cursor: pointer;
}

/*
  The framework's own error element. Shown when an exception has torn the
  circuit down, which reconnecting cannot fix — only a reload will.
*/
#blazor-error-ui {
    display: none;
    position: fixed;
    inset: auto 0 0 0;
    z-index: 20001;
    padding: .9rem 1.25rem;
    background: #fff4d5;
    border-top: 1px solid #e0c169;
    color: #4a3a08;
    box-shadow: 0 -2px 12px rgba(0, 0, 0, .12);
    font-size: .9rem;
}

#blazor-error-ui .aries-error-inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .75rem;
    max-width: 60rem;
    margin: 0 auto;
}

#blazor-error-ui a {
    color: inherit;
    font-weight: 600;
}

#blazor-error-ui .aries-error-dismiss {
    margin-left: auto;
    padding: 0 .35rem;
    border: 0;
    background: none;
    color: inherit;
    font-size: 1.25rem;
    line-height: 1;
    cursor: pointer;
}

#blazor-error-ui .aries-error-reload {
    padding: .35rem .85rem;
    border: 1px solid #b8933a;
    border-radius: var(--mud-default-borderradius, 6px);
    background: transparent;
    color: inherit;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}

/* ======================================================================
   Novaidan Treasures
   ----------------------------------------------------------------------
   Colours are read from custom properties the layout writes out of the
   settings table, never hard-coded here. Restyling for another shop stays a
   settings job; this file only decides how the palette is *used*.

   The ratio the brand asks for — roughly 60% cream and lilac, 25% gold and
   elegant type, 15% black and deep lavender — is held by what each colour is
   allowed to do, not by counting pixels. Gold is confined to hairlines, small
   fills and solid CTAs. Cream carries the ground.
   ====================================================================== */

/* --- Brand faces -------------------------------------------------------
   Self-hosted woff2, so the CSP stays at 'self' and no visitor's IP goes to a
   font CDN. Both are variable fonts covering their whole weight range in one
   file, which is why there is a single face per family rather than one per
   weight.

   font-display: swap — the fallback shows immediately and is replaced when the
   file lands, so a shopper on a slow connection reads the page rather than
   staring at invisible text. */
@font-face {
    font-family: 'Cormorant Garamond';
    src: url('fonts/cormorant-garamond-latin.woff2') format('woff2');
    font-weight: 300 700;
    font-style: normal;
    font-display: swap;
    /* Latin only. Everything the shop writes in English or Afrikaans lives in
       this range, accented Afrikaans characters included. */
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2018-201A,
        U+201C-201E, U+2020-2022, U+2039-203A, U+2044, U+2122, U+2212;
}

@font-face {
    font-family: 'Montserrat';
    src: url('fonts/montserrat-latin.woff2') format('woff2');
    font-weight: 300 600;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2018-201A,
        U+201C-201E, U+2020-2022, U+2039-203A, U+2044, U+2122, U+2212;
}

/* --- Typographic voice -------------------------------------------------
   An elegant serif against a clean sans. The contrast between the two is the
   whole effect, so the headings are given room to be seen. */
.mud-typography-h1,
.mud-typography-h2,
.mud-typography-h3,
.mud-typography-h4 {
    font-weight: 500;
    letter-spacing: .01em;
    line-height: 1.15;
}

/* The boutique signature: section labels set in widely-spaced uppercase sans
   rather than yet another serif heading. */
.nt-eyebrow {
    display: block;
    font-family: var(--aries-body-font, inherit);
    font-size: .72rem;
    font-weight: 500;
    letter-spacing: .22em;
    text-transform: uppercase;
    color: var(--nt-secondary);
}

/* --- Paper ------------------------------------------------------------
   A barely-there grain over the cream, so large flat areas do not read as a
   screen full of beige. Inline SVG as a data URI: no extra request, and the
   CSP already permits data: for images.

   The opacity sits at the edge of perception on purpose. Texture you can
   consciously notice has been overdone. */
body {
    /* Set from the MudBlazor palette further down so it follows the theme. */
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23g)' opacity='.035'/%3E%3C/svg%3E");
}

/* --- Gold rules -------------------------------------------------------
   Gold behaves like jewellery: hairlines, small marks, and solid CTAs with
   dark text on top. Never text on a pale ground, never a large flat fill. */
.nt-rule {
    width: 3.5rem;
    height: 1px;
    margin: 1.25rem auto;
    border: 0;
    background: linear-gradient(90deg, transparent, var(--nt-accent), transparent);
}

.nt-rule-left {
    margin-left: 0;
    margin-right: 0;
    background: linear-gradient(90deg, var(--nt-accent), transparent);
}

/* A gold hairline, not a gold border: one pixel, only on the edges that
   actually define the shape. */
.nt-gilded {
    border: 1px solid color-mix(in srgb, var(--nt-accent) 45%, transparent);
}

/* --- The contrast guard -----------------------------------------------
   MudBlazor's primary is gold, so filled buttons come out gold with dark text
   on them — what the brand asks for, and about 7:1.

   Text-only primary elements are a different problem. Gold on cream lands near
   2.6:1 and fails AA outright, so links, text buttons and outlined buttons are
   moved onto the deep lavender, which clears AA on the same ground. The brand
   keeps its gold exactly where gold works. */
.mud-button-text-primary,
.mud-button-outlined-primary,
.mud-link.mud-primary-text,
.mud-typography.mud-primary-text,
a.mud-primary-text {
    color: var(--nt-primary) !important;
}

.mud-button-outlined-primary {
    border-color: color-mix(in srgb, var(--nt-primary) 50%, transparent) !important;
}

/* --- Product cards ----------------------------------------------------
   Clean and spacious, white against the cream page so each one lifts a little
   without needing a shadow. Gold appears only as the hairline. */
.aries-product-card {
    /* Surface colour is set further down, from the MudBlazor palette, so it
       follows light and dark. Only the hairline is decided here. */
    border: 1px solid color-mix(in srgb, var(--nt-accent) 28%, transparent);
}

.aries-product-card:hover {
    border-color: color-mix(in srgb, var(--nt-accent) 65%, transparent);
}


/* --- Hero -------------------------------------------------------------
   Cream into lilac, with the botanical green kept to a whisper in one corner.
   No photograph needed for it to feel considered. */
.aries-hero {
    background:
        radial-gradient(120% 90% at 15% 0%,
            color-mix(in srgb, var(--nt-botanical) 16%, transparent), transparent 60%),
        linear-gradient(135deg, var(--nt-surface) 0%,
            color-mix(in srgb, var(--nt-primary) 14%, var(--nt-surface)) 100%);
    border-bottom: 1px solid color-mix(in srgb, var(--nt-accent) 35%, transparent);
}

.aries-hero-headline {
    font-weight: 400;
    letter-spacing: .005em;
}

.aries-hero-subtext {
    font-size: 1.05rem;
    opacity: .82;
}



.mud-appbar .mud-button-root {
    letter-spacing: .12em;
    text-transform: uppercase;
    font-size: .78rem;
    font-weight: 500;
}

/* --- Following the theme ----------------------------------------------
   These derive from MudBlazor's own palette variables rather than from the
   brand hexes directly.

   MudBlazor 9 switches between light and dark by swapping --mud-palette-*,
   not by adding a class to the body — so a rule hung on a class name like
   .mud-theme-dark never matches and quietly does nothing. Reading the
   variables means the surfaces follow the theme wherever the toggle is, and
   keeps working if the mechanism changes again.

   The palette values themselves are set in BuildTheme, where dark mode
   becomes the brand's campaign look: soft black ground, gold hairlines,
   cream text. */
body {
    background-color: var(--mud-palette-background, var(--nt-surface, #F8F4EE));
}

.aries-product-card {
    background-color: var(--mud-palette-surface, #FFFFFF);
}

.aries-product-image {
    background: linear-gradient(160deg,
        color-mix(in srgb, var(--nt-botanical) 12%, var(--mud-palette-surface, #FFFFFF)),
        var(--mud-palette-background, var(--nt-surface)));
}

/* The grain is left on in both themes, at an opacity low enough that over a
   near-black ground it is imperceptible anyway. It used to be lifted under
   prefers-color-scheme, which fired for anyone whose laptop was set to dark
   regardless of which theme the shop was actually showing — the same trap the
   section fades fell into. */

/* --- Card scale ---------------------------------------------------------
   Product tiles a step smaller than the default, so a listing shows more of
   the range in a screenful without the grid having to change shape.

   Done here rather than by editing the column widths on each page: six pages
   render these cards, and a rule in one file keeps them agreeing with each
   other. The columns are still what decide how many fit per row; this decides
   how tall and how heavy each one is.

   Applies to gift boxes as well as products — they share the card markup, and
   a gift box that stayed large beside a shrunken product would look like a
   mistake rather than a choice. */
.aries-product-image {
    /* Wider than 4:3, so the well is shallower: height is width divided by the
       ratio, which takes about a tenth off every tile before a word of text is
       set. A taller ratio here would make the cards bigger, not smaller. */
    aspect-ratio: 3 / 2;
}

.aries-product-card .mud-card-content {
    padding: .75rem .85rem;
}

.aries-product-card .mud-card-actions {
    padding: 0 .85rem .75rem;
}

/* The name and price carry the tile, so they shrink least — the room comes
   from the space around them. */
.aries-product-card .mud-typography-subtitle1 {
    font-size: .95rem;
    line-height: 1.3;
}

.aries-product-card .mud-typography-body2 {
    font-size: .8rem;
}

.aries-product-card .mud-button-root {
    font-size: .78rem;
}

.aries-product-badge {
    font-size: .68rem;
}
}

/* --- Feature bundles ----------------------------------------------------
   The tier cards on the settings screen. The whole card is the control, so it
   needs to look like one: a pointer, a hover state, and a visible focus ring
   for anybody arriving by keyboard. */
.aries-tier {
    cursor: pointer;
    transition: border-color .15s ease, background-color .15s ease;
}

.aries-tier:hover {
    border-color: var(--mud-palette-primary);
}

.aries-tier:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 2px;
}

.aries-tier-active {
    border-color: var(--mud-palette-primary) !important;
    background-color: var(--mud-palette-primary-hover);
}

@media (prefers-reduced-motion: reduce) {
    .aries-tier {
        transition: none;
    }
}

/* --- Buttons ------------------------------------------------------------
   Three styles, straight off the brand sheet:

     Primary      gold ground, dark text        SHOP NOW
     Secondary    lilac ground, dark text       DISCOVER
     Alternative  black ground, gold text       VIEW COLLECTION

   All three put dark on light or gold on black, never gold on a pale ground —
   the one pairing in this palette that cannot be read. Contrast for each is
   noted beside it.

   Slightly rounded rather than a bubble, and letter-spaced: the sheet asks for
   restraint, and restraint is what reads as expensive. */
.mud-button-filled-primary {
    font-weight: 600;
    letter-spacing: .08em;
}

/* Secondary: the soft lilac, with the same near-black text. About 9:1. */
.mud-button-filled-secondary {
    background-color: var(--nt-lilac) !important;
    color: var(--nt-ink) !important;
    font-weight: 600;
    letter-spacing: .08em;
}

.mud-button-filled-secondary:hover {
    background-color: var(--nt-lavender) !important;
}

/* Alternative: the campaign button. Soft black with gold type, about 8:1 —
   gold works here precisely because the ground is dark.

   Applied by class rather than by MudBlazor colour, because there is no
   palette slot that means "inverted". Use it with Variant.Filled:
     <MudButton Class="nt-button-alt" Variant="Variant.Filled"> */
.nt-button-alt {
    background-color: var(--nt-ink) !important;
    color: var(--nt-accent) !important;
    border: 1px solid var(--nt-accent);
    font-weight: 600;
    letter-spacing: .08em;
}

.nt-button-alt:hover {
    background-color: color-mix(in srgb, var(--nt-ink) 88%, var(--nt-accent)) !important;
}

/* --- Collection colours -------------------------------------------------
   The four collections from the sheet. Each is a ground plus a hairline, set
   as custom properties so a panel only has to say which collection it is:

     <div class="nt-collection nt-collection-botanical">

   Text stays the near-black in every one, including Luxury where it flips to
   cream — checked rather than assumed, since a collection panel nobody can
   read is worse than one that is off-brand. */
.nt-collection {
    background-color: var(--nt-collection-bg);
    border: 1px solid var(--nt-collection-line);
    color: var(--nt-collection-ink);
}

.nt-collection-lavender {
    --nt-collection-bg: var(--nt-lilac);
    --nt-collection-line: color-mix(in srgb, var(--nt-primary) 40%, transparent);
    --nt-collection-ink: var(--nt-ink);
}

.nt-collection-botanical {
    --nt-collection-bg: var(--nt-botanical);
    --nt-collection-line: color-mix(in srgb, var(--nt-secondary) 45%, transparent);
    --nt-collection-ink: var(--nt-ink);
}

.nt-collection-luxury {
    --nt-collection-bg: var(--nt-ink);
    --nt-collection-line: var(--nt-accent);
    --nt-collection-ink: var(--nt-surface);
}

.nt-collection-romantic {
    --nt-collection-bg: color-mix(in srgb, var(--nt-lilac) 60%, var(--nt-surface));
    --nt-collection-line: color-mix(in srgb, var(--nt-accent) 45%, transparent);
    --nt-collection-ink: var(--nt-ink);
}

/* --- Trust bar ----------------------------------------------------------
   The black band from the foot of the brand sheet. Soft black ground, gold
   marks, cream type — the campaign palette, used once per page where it
   carries weight rather than everywhere, where it would stop meaning
   anything. */
.nt-trust {
    background-color: var(--nt-ink);
    color: var(--nt-surface);
    border-top: 1px solid color-mix(in srgb, var(--nt-accent) 50%, transparent);
    border-bottom: 1px solid color-mix(in srgb, var(--nt-accent) 50%, transparent);
}

.nt-trust-item {
    display: flex;
    align-items: center;
    gap: .6rem;
    justify-content: center;
    text-align: left;
}

.nt-trust-item svg {
    flex: 0 0 auto;
    width: 1.35rem;
    height: 1.35rem;
    color: var(--nt-accent);
}

.nt-trust-label {
    font-size: .72rem;
    font-weight: 500;
    letter-spacing: .12em;
    text-transform: uppercase;
    line-height: 1.35;
}

/* The hairline separators between claims, on wide screens only — stacked on a
   phone they would be lines to nowhere. */
@media (min-width: 960px) {
    .nt-trust-item + .nt-trust-item {
        border-left: 1px solid color-mix(in srgb, var(--nt-accent) 28%, transparent);
    }
}

/* --- Brand marks --------------------------------------------------------
   The decorative elements: sprig, moon, sparkle, wreath. Sized in ems so they
   scale with whatever they sit beside. */
.nt-mark {
    display: inline-block;
    width: 1em;
    height: 1em;
    vertical-align: -.125em;
    color: var(--nt-accent);
}

.nt-mark-lg {
    width: 2.5rem;
    height: 2.5rem;
}


.aries-descband-text {
    color: var(--nt-ink);
    opacity: .92;
}

/* --- The ground ---------------------------------------------------------
   The page itself. The paper grain stays, at half strength: over a colour this
   saturated the texture reads as noise rather than as paper.

   No theme selector on it. .mud-theme-dark is a class MudBlazor 9 does not
   actually add — it swaps palette variables instead — so a rule hung on it
   never matched anything. At this opacity the grain is invisible over the dark
   ground regardless, which is the outcome the selector was reaching for. */
body {
    background-image:
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23g)' opacity='.02'/%3E%3C/svg%3E");
}

/* --- Faded sections -----------------------------------------------------
   Every section fades from its own colour toward the page ground rather than
   sitting as a flat block of paint, so the page reads as one continuous wash —
   deep violet at the header, through lavender sections, down to the soft lilac
   ground — instead of three hard stripes.

   Built from MudBlazor's palette variables rather than the brand hexes, and
   with no prefers-color-scheme anywhere.

   That second point matters and cost me a bug: the shop's light and dark are
   chosen by the toggle in the header, not by the operating system. A rule that
   keys off prefers-color-scheme fires for a visitor whose laptop is set to
   dark while they are looking at the light site — which is how these fades
   came to be missing on a page that was plainly lavender. Reading the palette
   means the gradients follow whichever theme is actually showing, and in dark
   mode they fade between two near-blacks and effectively disappear on their
   own. */
.aries-navband {
    background-color: var(--mud-palette-surface);
    background-image: linear-gradient(
        180deg,
        var(--mud-palette-surface) 0%,
        color-mix(in srgb, var(--mud-palette-surface) 55%, var(--mud-palette-background)) 100%);
    border-bottom: 1px solid color-mix(in srgb, var(--nt-accent) 45%, transparent);
}

/* Continues where the menu band left off, so the two read as one graded block
   rather than two with a seam between them. */
.aries-descband {
    background-color: var(--mud-palette-background);
    background-image: linear-gradient(
        180deg,
        color-mix(in srgb, var(--mud-palette-surface) 55%, var(--mud-palette-background)) 0%,
        var(--mud-palette-background) 100%);
    border-bottom: 1px solid color-mix(in srgb, var(--nt-accent) 30%, transparent);
}

/* Cards and raised panels. Subtler than the bands — a card is small enough
   that a strong gradient across it reads as a rendering fault. A light wash at
   the top edge, settling toward the ground colour at the foot. */
.aries-product-card,
.aries-tier,
.nt-collection {
    background-image: linear-gradient(
        170deg,
        color-mix(in srgb, #FFFFFF 20%, transparent) 0%,
        transparent 55%,
        color-mix(in srgb, var(--mud-palette-background) 45%, transparent) 100%);
}

/* The hero carries the fade furthest, being the tallest thing on the page and
   the one most likely to band if it were flat. */
.aries-hero {
    background:
        radial-gradient(120% 90% at 15% 0%,
            color-mix(in srgb, var(--mud-palette-surface) 60%, transparent), transparent 62%),
        linear-gradient(180deg,
            color-mix(in srgb, var(--mud-palette-surface) 70%, var(--mud-palette-background)) 0%,
            var(--mud-palette-background) 100%);
    border-top: 1px solid color-mix(in srgb, var(--nt-accent) 35%, transparent);
    border-bottom: 1px solid color-mix(in srgb, var(--nt-accent) 35%, transparent);
}

/* --- Brand bar ----------------------------------------------------------
   Violet, fading down to the section colour at its foot so the bar hands off to
   the menu band beneath rather than stopping at a hard line.

   No artwork. The botanical sprigs that used to sit at either end were removed:
   with the logo now carrying the laurel itself, a second set of leaves either
   side of it was the same idea said twice, and the bar reads cleaner as a plain
   wash of colour.

   The text colour is not set here. It is chosen in BuildTheme from the
   luminance of whatever the header colour happens to be, so a shop that picks a
   pale header gets dark type and one that picks this violet gets cream. */
.mud-appbar {
    background-image: linear-gradient(
        180deg,
        color-mix(in srgb, #000 8%, var(--mud-palette-appbar-background)) 0%,
        var(--mud-palette-appbar-background) 45%,
        color-mix(in srgb, var(--mud-palette-appbar-background) 72%, var(--mud-palette-surface)) 100%);
    box-shadow: none !important;
    border-bottom: 1px solid var(--nt-accent);
}
/* --- Section headings ---------------------------------------------------
   Headings inside the page take the header colour and set bold, so the violet
   that brackets the page top and bottom also runs through it. The brand mark,
   the bands and the headings then read as one system rather than three
   unrelated decisions.

   Read from the palette rather than a literal, so changing the header colour
   in settings carries the headings with it. */
.mud-main-content .mud-typography-h1,
.mud-main-content .mud-typography-h2,
.mud-main-content .mud-typography-h3,
.mud-main-content .mud-typography-h4,
.mud-main-content .mud-typography-h5,
.mud-main-content .mud-typography-h6 {
    color: var(--nt-heading, var(--mud-palette-appbar-background));
    font-weight: 700;
}

/* The brand name in the bar, bold to match. */
.mud-appbar .mud-typography-h6 {
    font-weight: 700;
}

/* The hero headline is the one exception: it sits on a tinted panel of its own
   where the violet would be heavy, and it is already the largest thing on the
   page without it. */
.aries-hero .aries-hero-headline {
    color: var(--mud-palette-text-primary);
    font-weight: 500;
}

/* --- Four to a row ------------------------------------------------------
   Four across on wide screens. The class is still named for the grid it
   overrides rather than for the number, so changing the count is this one
   rule rather than an edit to eight pages.

   Only above 1264px. Below that the grid's own breakpoints stay in charge,
   because four cards on a laptop leaves each one too narrow to judge a
   product by. */
@media (min-width: 1264px) {
    .aries-grid-5 > .mud-grid-item {
        flex-basis: 25%;
        max-width: 25%;
    }
}

/* --- Filter panel -------------------------------------------------------
   The category list scrolls once it outgrows a screenful, so price, rating and
   everything below it stay reachable in a shop with thirty categories. */
.aries-filter-scroll {
    max-height: 18rem;
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* A hairline to say the list continues, rather than leaving the scroll to be
   discovered by accident. */
.aries-filter-scroll {
    border-bottom: 1px solid var(--mud-palette-divider);
}

/* The expansion panel wrapping the categories should read as part of the
   panel, not as a raised card sitting inside it. */
.aries-filter-group,
.aries-filter-group .mud-expand-panel {
    background-color: transparent;
}

.aries-filter-group .mud-expand-panel-header {
    padding-left: 0;
    padding-right: 0;
}

.aries-filter-group .mud-expand-panel-content {
    padding: 0;
}

/* --- One card size --------------------------------------------------------
   Every product tile is the same height, whatever is in it.

   Left alone, a card grows with its content: a two-line name, a missing
   summary, a rating row that only reviewed products have. A row of five then
   sits at four different heights, which reads as broken rather than as
   variety, and the buttons along the bottom stop lining up.

   So each block inside the card is given the height it would have when full,
   and keeps it when empty. The name and summary clamp rather than truncate
   mid-word, and nothing is hidden that was not already going to overflow.

   Heights are in em against each block's own font size, so they follow the
   type scale rather than breaking the moment a shop picks a larger body font. */
.aries-product-card {
    /* The flex column is what lets the actions sit at the foot regardless of
       how much content is above them. */
    display: flex;
    flex-direction: column;
}

.aries-product-card .mud-card-content {
    display: flex;
    flex-direction: column;
}

/* Two lines, always. A one-line name still occupies two. */
.aries-card-name {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
    min-height: 2.6em;
    line-height: 1.3;
}

/* Reserved whether or not this product has reviews. */
.aries-card-rating {
    min-height: 1.5rem;
}

/* Two lines, and the space is held when a product has no summary at all. */
.aries-card-summary {
    min-height: 2.8em;
    line-height: 1.4;
}

/* Pushed to the foot of the content block, so the price sits on the same line
   across the whole row even when the text above it is shorter.

   The height is reserved because a reduced product carries a struck-through
   was-price beside the current one, and that second element has a slightly
   taller line box — half a pixel, which is invisible on its own and becomes a
   row of cards that do not quite line up. */
.aries-card-price {
    margin-top: auto;
    min-height: 1.5rem;
    align-items: center;
}

/* The action row is reserved at its tallest. At five to a row the cards are
   narrow enough that "Add to bag" wraps to two lines while "Sold out" does
   not, and without this the two sit at different heights side by side.

   Reserved rather than forced onto one line: nowrap would push a long label
   out of a narrow card, which is a worse problem than a two-line button. */
.aries-product-card .mud-card-actions {
    margin-top: auto;
    min-height: 4.5rem;
    align-items: flex-start;
}

/* --- Rota ---------------------------------------------------------------
   Seven columns, one per day, scrolling sideways on a narrow screen rather
   than reflowing — a week that wraps onto two rows stops being a week. */
.aries-rota {
    display: grid;
    grid-template-columns: repeat(7, minmax(9rem, 1fr));
    gap: .5rem;
    min-width: 63rem;
}

.aries-rota-day {
    border: 1px solid var(--mud-palette-divider);
    border-radius: var(--mud-default-borderradius);
    padding: .5rem;
    min-height: 9rem;
}

.aries-rota-today {
    border-color: var(--mud-palette-primary);
}

.aries-rota-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: .35rem;
}

.aries-rota-shift {
    border: 1px solid var(--mud-palette-lines-default);
    border-left: 3px solid var(--mud-palette-primary);
    border-radius: var(--mud-default-borderradius);
    padding: .4rem .5rem;
    margin-bottom: .35rem;
    cursor: pointer;
    background-color: var(--mud-palette-surface);
}

.aries-rota-shift:hover {
    border-color: var(--mud-palette-primary);
}

.aries-rota-shift:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 2px;
}

/* The slide-out menu wears the site header's colours.

   Painted from the app bar variables rather than a copy of the hex, so a shop
   that changes its header colour in settings gets the panel to match without
   anybody remembering this rule exists. */
.aries-drawer-header {
    background: var(--mud-palette-appbar-background);
    color: var(--mud-palette-appbar-text);
    min-height: 64px;
    align-items: center;
}

.aries-drawer-header .mud-typography {
    color: var(--mud-palette-appbar-text);
}

/* An absence on the rota. Hatched and faded so a week of cover can be read at
   a glance without mistaking somebody's leave for somebody's shift — the one
   misreading the grid exists to prevent. Colour alone would not do it: this has
   to survive a monochrome print-out pinned to the staffroom wall. */
.aries-rota-away {
    opacity: .82;
    background-image: repeating-linear-gradient(
        135deg,
        transparent,
        transparent 5px,
        var(--mud-palette-divider) 5px,
        var(--mud-palette-divider) 6px);
}

/* A password field with a reveal button beside it.

   The button sits inside the field's box rather than after it, so the field
   keeps its full width and the form does not reflow when the button appears. */
.aries-password {
    position: relative;
    display: block;
}

.aries-password .aries-input {
    /* Room for the button, so a long password never runs underneath it. */
    padding-right: 3rem;
}

.aries-password button {
    position: absolute;
    top: 50%;
    right: 0.35rem;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;

    /* 2.25rem square: comfortably past the 24px minimum for a touch target,
       without crowding the text it sits beside. */
    width: 2.25rem;
    height: 2.25rem;

    padding: 0;
    border: 0;
    border-radius: var(--mud-default-borderradius);
    background: transparent;
    cursor: pointer;
    font-size: 1.05rem;
    line-height: 1;
}

.aries-password button:hover {
    background-color: var(--mud-palette-action-default-hover);
}

.aries-password button:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: -2px;
}

/* The mystery box invitation on the home page.

   A soft tint rather than a hard border, so it reads as an aside on a quiet
   page instead of an advert wedged into it. Painted from the brand accent so it
   follows a colour change in settings. */
.nt-scoop-invite {
    background: color-mix(in srgb, var(--nt-accent, var(--mud-palette-secondary)) 10%, transparent);
    border-color: color-mix(in srgb, var(--nt-accent, var(--mud-palette-secondary)) 35%, transparent);
}

/* A gift box card whose picture lifts to show the contents.

   The panel is always in the DOM and always readable by a screen reader; only
   its opacity and offset change. Building it on hover would hide it from anyone
   not using a mouse, which on a phone is everybody. */
.nt-box-lid {
    display: block;
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
    text-align: left;
    position: relative;
    overflow: hidden;
}

.nt-box-lid:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: -2px;
}

.nt-box-hint {
    position: absolute;
    left: .5rem;
    bottom: .5rem;
    display: inline-flex;
    align-items: center;
    gap: .3rem;

    padding: .2rem .55rem;
    border-radius: 999px;

    /* Dark plate under light text: the picture underneath is whatever the shop
       uploaded, and a hint that only reads on pale photographs is no hint. */
    background: rgba(0, 0, 0, .62);
    color: #fff;
    font-size: .72rem;
    line-height: 1.5;

    transition: opacity .18s ease;
}

.nt-box-contents {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: .35rem;

    padding: 1rem;
    background: rgba(0, 0, 0, .78);
    color: #fff;

    /* Starts just below its resting place and slides up. Kept small: a card
       that leaps is a card people stop hovering over. */
    opacity: 0;
    transform: translateY(6px);
    transition: opacity .18s ease, transform .18s ease;

    /* The button underneath handles every pointer event, so the panel never
       steals the click that closes it. */
    pointer-events: none;

    overflow-y: auto;
}

.nt-box-open .nt-box-contents {
    opacity: 1;
    transform: translateY(0);
}

.nt-box-open .nt-box-hint {
    opacity: 0;
}

.nt-box-contents-title {
    font-size: .72rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    opacity: .8;
}

.nt-box-list {
    display: flex;
    flex-direction: column;
    gap: .2rem;
}

.nt-box-item {
    font-size: .85rem;
    line-height: 1.35;
}

/* Somebody who has asked for less movement gets the reveal without the slide.
   The information still appears; only the animation goes. */
@media (prefers-reduced-motion: reduce) {
    .nt-box-contents,
    .nt-box-hint {
        transition: none;
    }

    .nt-box-contents {
        transform: none;
    }
}

/* ==========================================================================
   Brand sheet: the Mystery Scoops styling, applied as reusable parts.

   Everything here is painted from the --nt-* variables the layout writes out
   of settings, so a shop that changes its purple or its gold in the admin gets
   the whole look moving with it rather than a page that half-changes.
   ========================================================================== */

/* The announcement strip above the header. Purple, quiet, one line.

   Deliberately not dismissible: it carries the shop's standing promise rather
   than a campaign, and a close button on a permanent line trains people to shut
   things without reading them. */
.nt-announce {
    /* A shade deeper than the brand bar above it. The sheet puts this strip on
       a white header, where plain primary reads as its own band; ours is
       already purple, so an identical fill would simply disappear into it. */
    background: color-mix(in srgb, #000 22%, var(--nt-primary));
    color: #F8F4EE;
    text-align: center;
    padding: .45rem 1rem;
    font-size: .78rem;
    letter-spacing: .12em;
    text-transform: uppercase;
}

.nt-announce .nt-heart {
    color: var(--nt-champagne);
    margin: 0 .6rem;
}

/* A heart used as punctuation. The brand sheet puts one either side of most
   headings; this is that, as a class rather than a pasted character. */
.nt-heart {
    color: var(--nt-accent);
    font-style: normal;
    line-height: 1;
}

/* The script face, for the two or three headings the brand sheet sets by hand.

   A stack, not a webfont: the designer's script is not among the two faces this
   site self-hosts, and pulling one from a third party for three headings would
   cost every visitor a request to somebody else's server. The stack lands on
   something cursive nearly everywhere; drop the real face into /fonts and add
   it at the front to match the sheet exactly. */
.nt-script {
    font-family: "Segoe Script", "Bradley Hand", "Brush Script MT",
                 "Lucida Handwriting", cursive;
    font-weight: 400;
    line-height: 1.15;
}

/* A centred section heading with a heart either side, as used throughout the
   sheet above "CHOOSE YOUR SCOOPS" and "YOUR DETAILS". */
.nt-section-heading {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .6rem;

    color: var(--nt-heading);
    font-size: 1.05rem;
    font-weight: 600;
    letter-spacing: .12em;
    text-transform: uppercase;
}

/* Cards: white, generously rounded, hairline lavender edge. The sheet's cards
   sit on a pale ground and are separated by their edge rather than a shadow. */
.nt-card {
    background: var(--mud-palette-surface);
    border: 1px solid color-mix(in srgb, var(--nt-lilac) 65%, transparent);
    border-radius: 14px;
}

/* The pale band the trust row and the hero sit on. */
.nt-band {
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--nt-lilac) 22%, var(--mud-palette-surface)) 0%,
        var(--mud-palette-surface) 100%);
}

/* ------------------------------------------------------- the scoop tiers */

/* One tier: a numeral, a label, a picture and a price pill. Hover lifts it
   slightly so the row reads as choosable rather than as a table. */
.nt-tier {
    position: relative;
    height: 100%;
    padding: 1.5rem 1rem 1.25rem;
    text-align: center;

    background: var(--mud-palette-surface);
    border: 1px solid color-mix(in srgb, var(--nt-lilac) 65%, transparent);
    border-radius: 14px;

    transition: transform .16s ease, border-color .16s ease, box-shadow .16s ease;
}

.nt-tier:hover,
.nt-tier:focus-within {
    transform: translateY(-3px);
    border-color: var(--nt-primary);
    box-shadow: 0 6px 20px color-mix(in srgb, var(--nt-primary) 18%, transparent);
}

/* The one the shop wants noticed. A full-strength border rather than a colour
   wash, so the card still reads as the same kind of thing as its neighbours. */
.nt-tier-featured {
    border-color: var(--nt-primary);
    border-width: 2px;
}

.nt-tier-count {
    font-size: 3rem;
    line-height: 1;
    color: var(--nt-heading);
}

.nt-tier-label {
    font-size: .72rem;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary);
}

/* The price, as a filled pill. */
.nt-tier-price {
    display: inline-block;
    margin-top: .75rem;
    padding: .3rem 1.1rem;
    border-radius: 999px;

    background: var(--nt-primary);
    color: #F8F4EE;
    font-weight: 600;
}

/* The ribbon on a featured tier. Positioned over the top edge, which is why the
   card is position:relative and the grid needs padding above it. */
.nt-tier-flag {
    position: absolute;
    top: -.7rem;
    left: 50%;
    transform: translateX(-50%);
    white-space: nowrap;

    padding: .18rem .7rem;
    border-radius: 999px;

    font-size: .65rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
}

.nt-flag-popular {
    background: var(--nt-primary);
    color: #F8F4EE;
}

.nt-flag-value {
    background: var(--nt-accent);
    color: #2A2118;
}

/* ---------------------------------------------------------- the trust row */

.nt-trust {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: 1px;

    /* The gap shows the background through as hairline dividers, which is how
       the sheet separates the four columns. One rule, no extra elements. */
    background: color-mix(in srgb, var(--nt-accent) 30%, transparent);
    border-radius: 14px;
    overflow: hidden;
}

.nt-trust-item {
    display: flex;
    align-items: flex-start;
    gap: .7rem;

    padding: 1.1rem 1.25rem;
    background: color-mix(in srgb, var(--nt-champagne) 12%, var(--mud-palette-surface));
}

.nt-trust-item .mud-icon-root {
    color: var(--nt-primary);
    flex-shrink: 0;
}

.nt-trust-title {
    color: var(--nt-heading);
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
}

.nt-trust-text {
    font-size: .82rem;
    color: var(--mud-palette-text-secondary);
    line-height: 1.4;
}

/* ------------------------------------------------------------- the wave */

/* The curved edge the sheet puts between the page and the footer. An inline
   SVG rather than a border-radius trick, so the curve is the designer's shape
   and not an approximation of it. It sits flush on the footer below. */
.nt-wave {
    display: block;
    width: 100%;
    height: 48px;
    margin-bottom: -1px;
    color: var(--nt-primary);
}

.nt-wave svg {
    display: block;
    width: 100%;
    height: 100%;
}

/* The round seal beside the hero heading: "EVERY SCOOP — A Surprise".

   A circle of type rather than an image, so it stays sharp, weighs nothing and
   follows the brand colours when they change in settings. */
.nt-seal {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .15rem;

    width: 156px;
    height: 156px;
    flex-shrink: 0;

    border-radius: 50%;
    border: 2px solid color-mix(in srgb, var(--nt-primary) 45%, transparent);
    background: color-mix(in srgb, var(--nt-lilac) 18%, var(--mud-palette-surface));
    color: var(--nt-heading);
}

.nt-seal .mud-icon-root {
    color: var(--nt-primary);
}

.nt-seal-top {
    font-size: .68rem;
    letter-spacing: .14em;
    text-transform: uppercase;
}

.nt-seal-script {
    font-size: 1.5rem;
    line-height: 1;
    color: var(--nt-primary);
}

/* Below the seal's own width the hero stacks, and a 156px circle beside a
   paragraph on a phone is just a hole in the layout. */
@media (max-width: 599px) {
    .nt-seal {
        width: 124px;
        height: 124px;
    }

    .nt-seal-script {
        font-size: 1.2rem;
    }
}

/* ==========================================================================
   Content sections: the same fade the brand bar uses, carried through the page.

   Three changes, applied together because they are one decision:

   - A soft vertical wash instead of a flat fill, so a card or a panel has the
     same top-lit quality as the bar above it rather than sitting on the page
     as a plain rectangle.
   - A lighter ground than before, so white product photography and the lilac
     hairline both have somewhere to sit.
   - Near-black headings inside content, rather than the brand violet. The
     violet still brackets the page — bar, bands, footer — but running it
     through every heading inside every card made the type compete with the
     product it was labelling.

   Written against the palette variables rather than literal colours, so the
   wash follows a shop that changes its lilac, and the "black" follows the
   light/dark toggle rather than turning invisible on a dark ground.
   ========================================================================== */

.aries-product-card,
.mud-main-content .mud-paper:not(.mud-alert):not(.nt-tier):not(.mud-drawer),
.nt-card,
.nt-tier {
    background-image: linear-gradient(
        180deg,
        var(--mud-palette-surface) 0%,
        color-mix(in srgb, var(--nt-lilac) 7%, var(--mud-palette-surface)) 100%);
}

/* Headings inside content go to ink. The rule below the brand-bar block sets
   them to the header violet for the page as a whole; this narrows that to the
   page's own titles by overriding it wherever a heading sits inside a card, a
   panel or a tier.

   text-primary rather than a literal black: it is near-black in the light
   theme, which is what was asked for, and stays readable when somebody hits
   the dark toggle instead of disappearing into the background. */
.aries-product-card .mud-typography-h1,
.aries-product-card .mud-typography-h2,
.aries-product-card .mud-typography-h3,
.aries-product-card .mud-typography-h4,
.aries-product-card .mud-typography-h5,
.aries-product-card .mud-typography-h6,
.aries-product-card .mud-typography-subtitle1,
.aries-product-card .mud-typography-subtitle2,
.mud-main-content .mud-paper .mud-typography-h4,
.mud-main-content .mud-paper .mud-typography-h5,
.mud-main-content .mud-paper .mud-typography-h6,
.mud-main-content .mud-paper .mud-typography-subtitle1,
.nt-card .mud-typography-h4,
.nt-card .mud-typography-h5,
.nt-card .mud-typography-h6,
.nt-tier .mud-typography-h4,
.nt-tier .mud-typography-h5,
.nt-tier .mud-typography-h6 {
    color: var(--mud-palette-text-primary);
}

/* The tier numeral goes with them. It is the product's name in this layout,
   not decoration. */
.nt-tier-count {
    color: var(--mud-palette-text-primary);
}

/* The hero band gets a deeper version of the same wash, so the top of the page
   and the cards below it are recognisably the same treatment at two strengths. */
.nt-band {
    background: linear-gradient(
        180deg,
        color-mix(in srgb, var(--nt-lilac) 30%, var(--mud-palette-surface)) 0%,
        color-mix(in srgb, var(--nt-lilac) 8%, var(--mud-palette-surface)) 70%,
        var(--mud-palette-surface) 100%);
}

/* Alerts keep their own colour. They are a signal, and washing them in lilac
   would make a warning look like a panel. */
.mud-main-content .mud-alert {
    background-image: none;
}

/* --- The message panel --------------------------------------------------
   The bell's popover. Sized so six messages fit without scrolling and a
   seventh scrolls rather than running off the screen. */
.aries-bell-popover {
    width: 22rem;
    max-width: calc(100vw - 2rem);
    max-height: 70vh;
    overflow-y: auto;
}

.aries-bell-head {
    padding: .6rem .5rem .6rem 1rem;
}

/* Each message is a button rather than a link or a menu item: reading one must
   not close the panel, because somebody working through three unread messages
   would otherwise have to reopen it three times. */
.aries-bell-item {
    display: block;
    width: 100%;
    padding: .7rem 1rem;

    border: 0;
    background: none;
    text-align: left;
    cursor: pointer;

    border-bottom: 1px solid var(--mud-palette-divider);
}

.aries-bell-item:hover {
    background-color: var(--mud-palette-action-default-hover);
}

.aries-bell-item:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: -2px;
}

/* Unread carries weight and a dot, never colour alone: a list where the only
   difference is a shade is unusable to anybody who cannot see that shade. */
.aries-bell-unread .aries-bell-subject {
    font-weight: 700;
}

.aries-bell-dot {
    flex-shrink: 0;
    width: .5rem;
    height: .5rem;
    margin-top: .4rem;
    border-radius: 50%;
    background: var(--mud-palette-primary);
}

.aries-bell-subject {
    font-size: .88rem;
    line-height: 1.3;
    color: var(--mud-palette-text-primary);
}

/* Two lines of the message, then it stops. The panel is a prompt to go and
   read, not the place to read. */
.aries-bell-body {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;

    margin-top: .15rem;
    font-size: .8rem;
    line-height: 1.35;
    color: var(--mud-palette-text-secondary);
}

.aries-bell-when {
    margin-top: .25rem;
    font-size: .72rem;
    color: var(--mud-palette-text-secondary);
}

.aries-bell-all {
    border-radius: 0;
}

/* --- Editable page sections ---------------------------------------------
   About us and Contact us are built from blocks the shop edits in admin. The
   shape lives here rather than in the words, so nothing anybody types can
   knock the page out of alignment. */

.aries-page-sections {
    display: flex;
    flex-direction: column;
    gap: 2.5rem;
    margin-top: 2.5rem;
}

.aries-page-section {
    max-width: 70ch;
}

.aries-section-heading {
    margin-bottom: 0.75rem;
}

.aries-section-image {
    border-radius: var(--mud-default-borderradius);
    max-height: 320px;
    width: 100%;
}

/* The promises. Wraps to as many columns as fit, so six claims sit in a neat
   block on a laptop and stack cleanly on a phone rather than becoming a long
   thin list nobody reads to the end of. */
.aries-promise-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 0.75rem 1.5rem;
}

.aries-promise {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.6rem 0.9rem;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
    background: var(--mud-palette-surface);
}
