/* DigiCard design system — loaded after app.css, so it also corrects the starter layout. */

/* Bundled Persian webfonts, all SIL OFL (licence files sit beside the woff2 in wwwroot/fonts).
   Vazirmatn is the interface and body face; Lalezar is a display face for headings; Gulzar is
   real nastaliq, used only for the couple's names on the card, where the calligraphic form is
   the whole point. font-display:swap so text is never invisible while a face loads. */

@font-face {
    font-family: 'Vazirmatn';
    src: url('fonts/Vazirmatn-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Vazirmatn';
    src: url('fonts/Vazirmatn-Medium.woff2') format('woff2');
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Vazirmatn';
    src: url('fonts/Vazirmatn-SemiBold.woff2') format('woff2');
    font-weight: 600;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Vazirmatn';
    src: url('fonts/Vazirmatn-Bold.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Lalezar';
    src: url('fonts/Lalezar-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Gulzar';
    src: url('fonts/Gulzar-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

:root {
    --dc-sans: 'Vazirmatn', 'Segoe UI', Tahoma, sans-serif;
    --dc-display: 'Lalezar', 'Vazirmatn', 'Segoe UI', Tahoma, sans-serif;
    --dc-nastaliq: 'Gulzar', 'Vazirmatn', serif;

    /* A cool, near-neutral interface. The artwork on every card is warm - blush, cream,
       sage - so a cool ground makes it read as art on a gallery wall instead of fighting it.
       The previous palette was warm cream throughout, which is what made the page look
       smoky and yellow next to pure white. */
    --dc-ground: #f5f7f9;
    --dc-surface: #ffffff;
    --dc-ink: #1e2833;
    --dc-muted: #66727f;
    --dc-line: #e3e8ed;
    --dc-brand: #2f5d70;
    --dc-brand-soft: #eef4f7;
    --dc-brand-ink: #244856;
    --dc-accent: #7c8b98;

    --dc-radius: 14px;
    --dc-radius-sm: 8px;
    /* Shadows carry the same cool cast; a warm shadow on a cool ground looks like dirt. */
    --dc-shadow: 0 1px 2px rgba(30, 40, 51, .05), 0 8px 24px rgba(30, 40, 51, .07);
    --dc-shadow-lift: 0 2px 6px rgba(30, 40, 51, .07), 0 16px 40px rgba(30, 40, 51, .12);

    --dc-step: 8px;
    --dc-gutter: clamp(16px, 5vw, 48px);
}

html, body {
    font-family: var(--dc-sans);
}

body {
    background: var(--dc-ground);
    color: var(--dc-ink);
    line-height: 1.85;
}

/* ---------------------------------------------------------------- responsive repair
   The starter pinned .feature-grid and .studio-grid to two columns with no media query,
   which is what overflows at 360-390px. Make them fluid instead of fixed. */

.feature-grid,
.studio-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
    gap: clamp(20px, 3vw, 36px);
    align-items: start;
}

.page-shell {
    max-width: 1100px;
    margin-inline: auto;
    padding-block: clamp(28px, 5vw, 48px);
    padding-inline: var(--dc-gutter);
    min-height: 70vh;
}

.site-header {
    padding-inline: var(--dc-gutter);
    flex-wrap: wrap;
    gap: 12px;
}

.site-header nav {
    flex-wrap: wrap;
    gap: 16px;
}

/* Nothing in the page body may scroll sideways. */
html, body {
    overflow-x: hidden;
}

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

/* ---------------------------------------------------------------- the card */

.card {
    position: relative;
    isolation: isolate;
    display: flex;
    flex-direction: column;
    /* 2:3 matches the native output size of the painted artwork, so nothing has to be
       cropped and corner flowers stay whole. */
    aspect-ratio: 2 / 3;
    width: 100%;
    max-width: 340px;
    margin-inline: auto;
    overflow: hidden;
    border-radius: var(--dc-radius-sm);
    background: var(--card-ground, #fbfaf7);
    color: var(--card-ink, #33332e);
    box-shadow: var(--dc-shadow);
    container-type: inline-size;
}

.card-artwork {
    position: absolute;
    inset: 0;
    z-index: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* The painting already carries the paper texture, so the CSS ground is irrelevant here. */
}

/* The moving painting sits on the still one (same box, later in the page, so above it) and
   starts on its first frame, which is that same still. Asked for less motion, the video goes and
   the still stays. */
.card-motion { background: transparent; }

@media (prefers-reduced-motion: reduce) {
    .card-motion { display: none; }
}

.card-art-layer {
    position: absolute;
    inset: 0;
    z-index: 0;
    color: var(--card-accent);
    pointer-events: none;
}

.card-art {
    display: block;
    width: 100%;
    height: 100%;
}

.card-body {
    position: relative;
    z-index: 2;
    display: flex;
    flex: 1;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: calc(var(--dc-step) * .75);
    padding: clamp(18px, 7cqi, 30px);
    text-align: center;
}

/* Painted templates position the text block inside the calm band measured from the
   artwork itself, instead of simply centring it in the card. */
.card-has-artwork .card-body {
    position: absolute;
    inset: var(--card-safe-top, 30%) 8% var(--card-safe-bottom, 25%);
    padding: 0;
}

/* A painting supplies its own framing; a CSS border on top of it looks pasted on. */
.card-has-artwork .card-body {
    border: 0 !important;
    box-shadow: none !important;
    margin: 0 !important;
    outline: 0 !important;
    background: transparent !important;
}

.card-has-artwork::before,
.card-has-artwork::after {
    display: none !important;
}

.card-kicker {
    margin: 0 0 .2em;
    font-family: var(--dc-sans);
    font-size: clamp(8px, 2.9cqi, 11px);
    font-weight: 500;
    letter-spacing: .12em;
    color: var(--card-accent);
    opacity: .8;
}

.card-names {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: center;
    gap: .3em;
    margin: 0;
    font-size: clamp(22px, 9.5cqi, 38px);
    line-height: 1.65;
    color: var(--card-ink);
    /* Long Persian names must wrap, never clip. */
    overflow-wrap: anywhere;
    max-width: 100%;
}

.card-amp {
    font-family: var(--dc-sans);
    font-size: .42em;
    font-weight: 400;
    color: var(--card-accent);
}

.card-rule {
    display: block;
    width: clamp(64px, 30cqi, 104px);
    margin-block: .35em;
    color: var(--card-accent);
    opacity: .75;
}

.card-rule svg {
    display: block;
    width: 100%;
    height: auto;
}

.card-message {
    margin: 0;
    font-family: var(--dc-sans);
    font-size: clamp(9px, 3.2cqi, 12px);
    line-height: 1.9;
    opacity: .7;
    /* Allow several lines, then fade out rather than overflow the card. */
    display: -webkit-box;
    -webkit-line-clamp: 4;
    line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
    max-width: 26ch;
}

/* ------------------------------------------------ frames */

.card-frame-thin .card-body {
    background: transparent;
    margin: clamp(9px, 3.4cqi, 14px);
    padding: clamp(14px, 5cqi, 22px);
    border: 1px solid color-mix(in srgb, var(--card-accent) 42%, transparent);
}

.card-frame-double .card-body {
    margin: clamp(9px, 3.4cqi, 14px);
    padding: clamp(14px, 5cqi, 22px);
    border: 1px solid color-mix(in srgb, var(--card-accent) 48%, transparent);
    outline: 1px solid color-mix(in srgb, var(--card-accent) 26%, transparent);
    outline-offset: 4px;
}

.card-frame-ornate .card-body {
    margin: clamp(10px, 3.8cqi, 16px);
    padding: clamp(14px, 5cqi, 22px);
    border: 1px solid color-mix(in srgb, var(--card-accent) 55%, transparent);
    border-radius: 3px;
    box-shadow: inset 0 0 0 4px color-mix(in srgb, var(--card-accent) 10%, transparent),
                inset 0 0 0 5px color-mix(in srgb, var(--card-accent) 32%, transparent);
}

/* ------------------------------------------------ layouts */

.card-layout-arch .card-body {
    border-start-start-radius: 50% 22%;
    border-start-end-radius: 50% 22%;
}

.card-family-persian.card-layout-arch::before,
.card-family-persian.card-frame-ornate .card-body {
    border: 0;
    box-shadow: none;
}

.card-layout-arch::before {
    content: "";
    position: absolute;
    inset: clamp(10px, 3.8cqi, 16px);
    border: 1px solid color-mix(in srgb, var(--card-accent) 38%, transparent);
    border-start-start-radius: 50% 26%;
    border-start-end-radius: 50% 26%;
    pointer-events: none;
}

.card-layout-banded::before {
    content: "";
    position: absolute;
    inset-inline: 0;
    top: 0;
    height: clamp(34px, 13cqi, 56px);
    background: color-mix(in srgb, var(--card-accent) 16%, transparent);
    border-bottom: 1px solid color-mix(in srgb, var(--card-accent) 40%, transparent);
}

.card-layout-banded .card-body {
    padding-top: clamp(44px, 17cqi, 70px);
}

.card-layout-photo {
    display: grid;
    grid-template-rows: 47% 1fr;
}

.card-photo {
    display: grid;
    place-items: center;
    background:
        repeating-linear-gradient(135deg,
            color-mix(in srgb, var(--card-accent) 9%, transparent) 0 10px,
            transparent 10px 20px),
        color-mix(in srgb, var(--card-accent) 15%, transparent);
    border-bottom: 1px solid color-mix(in srgb, var(--card-accent) 32%, transparent);
}

.card-photo-hint {
    display: grid;
    justify-items: center;
    gap: .35em;
    font-size: clamp(10px, 3.2cqi, 12px);
    color: color-mix(in srgb, var(--card-accent) 70%, var(--card-ink));
    opacity: .85;
}

.card-photo-hint svg {
    width: 2.6em;
    height: 2.6em;
}

/* An empty frame: a soft glow of the card's colour, so it reads as a place for a photo. */
.card-photo-clip:has(> .card-photo-hint) {
    background: radial-gradient(circle at 50% 42%, color-mix(in srgb, var(--card-accent) 16%, transparent), transparent 72%);
}

.card-layout-photo .card-body {
    justify-content: center;
    gap: var(--dc-step);
}

/* ------------------------------------------------ typefaces */

/* The three roles are genuinely different faces now, not three weights of one.
   Nastaliq needs far more line height and a larger optical size than a sans. */
.card-type-sans .card-names {
    font-family: var(--dc-sans);
    font-weight: 600;
}

.card-type-display .card-names {
    font-family: var(--dc-display);
    font-weight: 400;
    letter-spacing: .005em;
}

.card-type-serif .card-names {
    font-family: var(--dc-nastaliq);
    font-weight: 400;
    font-size: clamp(26px, 11cqi, 46px);
    line-height: 2.05;
    padding-block: .12em;
}

/* ------------------------------------------------ family accents */

/* ---------------------------------------------------------------- template tiles */

.template-tile {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px;
    background: var(--dc-surface);
    border: 1px solid var(--dc-line);
    border-radius: var(--dc-radius);
    transition: box-shadow .18s ease, transform .18s ease, border-color .18s ease;
}

.template-tile:hover,
.template-tile:focus-within {
    box-shadow: var(--dc-shadow-lift);
    border-color: color-mix(in srgb, var(--dc-brand) 30%, var(--dc-line));
    transform: translateY(-2px);
}

.template-tile h3 {
    margin: 0;
    font-size: 17px;
}

.template-tile .template-meta {
    margin: 0;
    font-size: 13px;
    color: var(--dc-muted);
}

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

    .template-tile:hover,
    .template-tile:focus-within {
        transform: none;
    }
}

/* ---------------------------------------------------------------- focus visibility */

a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
    outline: 2px solid var(--dc-brand);
    outline-offset: 2px;
}

/* ---------------------------------------------------------------- shell: header & footer */

.skip-link {
    position: absolute;
    inset-inline-start: -9999px;
    top: 0;
    z-index: 10;
    padding: 10px 16px;
    background: var(--dc-brand);
    color: #fff;
    border-radius: 0 0 var(--dc-radius-sm) var(--dc-radius-sm);
}

.skip-link:focus {
    inset-inline-start: 0;
}

.site-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding-block: 16px;
    background: var(--dc-surface);
    border-bottom: 1px solid var(--dc-line);
}

.brand {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 21px;
    font-weight: 700;
    text-decoration: none;
    color: var(--dc-ink);
}

/* The logo image (96 px drawn at 32 px, so it stays sharp on phone screens). alt="" because
   the name right beside it already says what it is; a screen reader would read it twice. */
.brand-mark {
    display: block;
    width: 32px;
    height: 32px;
    flex: none;
}

.footer-brand .brand-mark {
    width: 40px;
    height: 40px;
}

.site-nav {
    display: flex;
    flex-wrap: wrap;
    gap: 20px;
}

.site-nav a {
    color: var(--dc-ink);
    text-decoration: none;
    font-size: 15px;
}

.site-nav a:hover {
    color: var(--dc-brand);
    text-decoration: underline;
    text-underline-offset: 5px;
}

.site-actions {
    display: flex;
    align-items: center;
    gap: 6px;
}

/* The signed-in links in the header: small, quiet pills with an icon. */
.hdr-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 36px;
    padding: 0 13px;
    border-radius: 999px;
    background: var(--dc-ground);
    color: var(--dc-ink);
    font-size: 14px;
    text-decoration: none;
    white-space: nowrap;
    transition: background-color .15s ease, color .15s ease;
}

.hdr-pill svg,
.hdr-out svg { width: 17px; height: 17px; flex: none; }

.hdr-pill:hover { color: var(--dc-brand); background: color-mix(in srgb, var(--dc-brand) 10%, var(--dc-surface)); }

/* More specific than the site-wide button[type=submit], which would paint it as a big green button. */
.site-actions .hdr-out[type=submit] {
    display: inline-grid;
    place-items: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--dc-muted);
    cursor: pointer;
    transition: background-color .15s ease, color .15s ease;
}

.site-actions .hdr-out[type=submit]:hover:not(:disabled) { background: #fbeceb; color: #a8433b; }

.hdr-pill:focus-visible,
.site-actions .hdr-out:focus-visible { outline: 2px solid var(--dc-brand); outline-offset: 2px; }

/* A phone: «مدیریت» keeps only its icon, so the row still fits beside the logo. */
@media (max-width: 480px) {
    .hdr-pill { padding: 0 11px; font-size: 13px; }
    .hdr-pill[href="/panel"] span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
    .hdr-pill[href="/panel"] { width: 36px; padding: 0; justify-content: center; }
}

@media (max-width: 720px) {
    .site-nav {
        order: 3;
        width: 100%;
        gap: 14px;
        font-size: 14px;
    }
}

.site-footer {
    margin-top: 56px;
    padding-block: 36px 24px;
    padding-inline: var(--dc-gutter);
    background: var(--dc-surface);
    border-top: 1px solid var(--dc-line);
}

/* A heading above its list. app.css makes every nav a row (it was written for the header), and
   the footer's columns had their heading beside the links instead of over them. */
.site-footer nav { display: block; }

.footer-inner {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
    gap: 28px;
    max-width: 1100px;
    margin-inline: auto;
}

.site-footer h2 {
    margin: 0 0 10px;
    font-size: 14px;
    color: var(--dc-muted);
    font-weight: 600;
}

.site-footer ul {
    margin: 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: 7px;
}

.site-footer a {
    color: var(--dc-ink);
    text-decoration: none;
    font-size: 14px;
}

.site-footer a:hover {
    text-decoration: underline;
    text-underline-offset: 4px;
}

.footer-brand p {
    margin: 8px 0 0;
    font-size: 14px;
    color: var(--dc-muted);
}

.footer-legal {
    max-width: 1100px;
    margin: 24px auto 0;
    padding-top: 16px;
    border-top: 1px solid var(--dc-line);
    font-size: 13px;
    color: var(--dc-muted);
}

/* ---------------------------------------------------------------- buttons */

/* Any submit button gets the house style - unless it has been given a shape of its own.
   Without the :not(), button[type=submit] (specificity 0,1,1) quietly beats .icon-btn
   (0,1,0), which is why an icon button in the panel came out as a filled pill while the
   icon beside it, being a <summary>, stayed bare. */
.btn-primary,
.btn-quiet,
button[type=submit]:not(.icon-btn) {
    display: inline-block;
    padding: 12px 26px;
    border: 1px solid transparent;
    border-radius: var(--dc-radius-sm);
    font: inherit;
    text-decoration: none;
    cursor: pointer;
    transition: background-color .15s ease, border-color .15s ease;
}

.btn-primary,
button[type=submit]:not(.icon-btn) {
    background: var(--dc-brand);
    color: #fff;
}

.btn-primary:hover,
button[type=submit]:not(.icon-btn):hover:not(:disabled) {
    background: #244856;
}

.btn-quiet {
    background: transparent;
    color: var(--dc-ink);
    border-color: var(--dc-line);
}

.btn-quiet:hover {
    border-color: var(--dc-brand);
    color: var(--dc-brand);
}

.btn-small {
    padding: 8px 16px;
    font-size: 14px;
}

button:disabled {
    opacity: .6;
    cursor: default;
}

/* ---------------------------------------------------------------- page furniture */

.page-head {
    margin-bottom: 28px;
}

.page-head h1 {
    margin: 0 0 6px;
    font-size: clamp(26px, 4.5vw, 38px);
    line-height: 1.5;
}

.page-head p {
    margin: 0;
    color: var(--dc-muted);
}

.section {
    margin-block: clamp(40px, 7vw, 68px);
}

.section-head {
    margin-bottom: 22px;
}

.section-head h2 {
    margin: 0 0 5px;
    font-size: clamp(20px, 3vw, 27px);
    line-height: 1.5;
}

.section-head p {
    margin: 0;
    color: var(--dc-muted);
    font-size: 15px;
}

.section-more {
    margin-top: 22px;
}

.empty-note {
    padding: 18px;
    background: var(--dc-brand-soft);
    border-radius: var(--dc-radius-sm);
    color: var(--dc-ink);
}

.breadcrumb ol {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 18px;
    padding: 0;
    list-style: none;
    font-size: 13px;
    color: var(--dc-muted);
}

.breadcrumb li + li::before {
    content: "‹";
    margin-inline-end: 8px;
    color: var(--dc-line);
}

.breadcrumb a {
    color: var(--dc-muted);
}

/* ---------------------------------------------------------------- hero */

.hero {
    padding-block: clamp(40px, 7vw, 76px);
    text-align: center;
}

.hero-eyebrow {
    margin: 0 0 10px;
    color: var(--dc-accent);
    letter-spacing: .16em;
    font-size: 13px;
}

.hero h1 {
    margin: 0 0 16px;
    font-size: clamp(30px, 6vw, 56px);
    line-height: 1.45;
    font-weight: 700;
}

.hero-lead {
    max-width: 46ch;
    margin: 0 auto 26px;
    color: var(--dc-muted);
    font-size: clamp(15px, 2vw, 17px);
}

.hero-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 12px;
}

/* ---------------------------------------------------------------- categories */

.category-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 160px), 1fr));
    gap: 14px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.category-card {
    display: flex;
    flex-direction: column;
    gap: 3px;
    height: 100%;
    padding: 20px 18px;
    background: var(--dc-surface);
    border: 1px solid var(--dc-line);
    border-radius: var(--dc-radius);
    text-decoration: none;
    color: var(--dc-ink);
    transition: border-color .18s ease, box-shadow .18s ease, transform .18s ease;
}

.category-card:hover,
.category-card:focus-visible {
    border-color: color-mix(in srgb, var(--dc-brand) 45%, var(--dc-line));
    box-shadow: var(--dc-shadow);
    transform: translateY(-2px);
}

/* The icon sits in a soft tile so the row has a rhythm to it rather than six loose marks. */
.category-mark {
    display: grid;
    place-items: center;
    width: 42px;
    height: 42px;
    margin-bottom: 10px;
    border-radius: 11px;
    background: var(--dc-brand-soft);
    color: var(--dc-brand);
    transition: background-color .18s ease;
}

.category-card:hover .category-mark {
    background: color-mix(in srgb, var(--dc-brand) 14%, var(--dc-surface));
}

.cat-icon {
    width: 23px;
    height: 23px;
}

.category-title {
    font-weight: 600;
}

.category-tagline {
    font-size: 13px;
    color: var(--dc-muted);
}

@media (prefers-reduced-motion: reduce) {
    .category-card { transition: border-color .18s ease; }
    .category-card:hover,
    .category-card:focus-visible { transform: none; }
}

/* ---------------------------------------------------------------- chips */

.chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: 9px;
    margin-bottom: 26px;
}

.chip {
    display: inline-block;
    padding: 7px 15px;
    border: 1px solid var(--dc-line);
    border-radius: 999px;
    background: var(--dc-surface);
    color: var(--dc-ink);
    font-size: 14px;
    text-decoration: none;
}

.chip:hover {
    border-color: var(--dc-brand);
    color: var(--dc-brand);
}

.chip-active {
    background: var(--dc-brand);
    border-color: var(--dc-brand);
    color: #fff;
}

/* ---------------------------------------------------------------- template grid */

.template-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 230px), 1fr));
    gap: clamp(16px, 2.5vw, 28px);
    margin: 0;
    padding: 0;
    list-style: none;
}

.template-tile {
    text-decoration: none;
    color: var(--dc-ink);
    height: 100%;
}

/* ---- the eye on a tile, and the card it brings forward (TilePeek.razor) */

.template-grid > li {
    position: relative;
}

.tile-peek {
    position: absolute;
    top: 12px;
    left: 12px;
    z-index: 2;
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, .94);
    color: var(--dc-ink);
    box-shadow: 0 2px 10px rgba(30, 40, 51, .16);
    cursor: zoom-in;
    transition: transform .15s ease, box-shadow .15s ease;
}

.tile-peek svg { width: 19px; height: 19px; }

.tile-peek:hover {
    transform: scale(1.08);
    box-shadow: 0 4px 16px rgba(30, 40, 51, .24);
}

.tile-peek:focus-visible {
    outline: 2px solid var(--dc-brand);
    outline-offset: 2px;
}

/* The browser's own popover box, emptied: no border, no paper, no scrollbars - just the card
   floating over a dimmed page. */
.peek {
    /* fit-content, as the browser's own default is: with inset 0, "auto" would stretch the box
       over the whole window, so it would neither centre nor let a tap outside close it. */
    width: fit-content;
    height: fit-content;
    max-width: none;
    max-height: none;
    margin: auto;
    padding: 0;
    border: 0;
    background: transparent;
    overflow: visible;
}

.peek::backdrop {
    background: rgba(20, 14, 20, .72);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}

.peek-card {
    width: min(86vw, calc((88vh - 90px) * 2 / 3), 460px);
    width: min(86vw, calc((88dvh - 90px) * 2 / 3), 460px);
}

.peek-card .card {
    max-width: none;
    border-radius: 6px;
    box-shadow: 0 30px 80px rgba(0, 0, 0, .5);
}

/* It comes forward out of the page rather than simply appearing. */
.peek:popover-open .peek-card {
    animation: peek-in .45s cubic-bezier(.2, .8, .2, 1);
}

.peek:popover-open::backdrop {
    animation: peek-fade .3s ease;
}

@keyframes peek-in {
    from { opacity: 0; transform: translateY(24px) scale(.82); }
}

@keyframes peek-fade {
    from { opacity: 0; }
}

.peek-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px;
    margin-top: 14px;
}

.peek-btn {
    display: inline-flex;
    align-items: center;
    height: 40px;
    padding: 0 18px;
    border: 0;
    border-radius: 999px;
    background: rgba(255, 255, 255, .92);
    color: var(--dc-ink);
    font: inherit;
    font-size: 14px;
    text-decoration: none;
    cursor: pointer;
}

.peek-btn.is-primary {
    background: var(--dc-brand);
    color: #fff;
}

.peek-btn.is-quiet {
    background: transparent;
    color: #fff;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .45);
}

@media (prefers-reduced-motion: reduce) {
    .peek:popover-open .peek-card,
    .peek:popover-open::backdrop { animation: none; }
}

/* ---------------------------------------------------------------- detail page */

.detail-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
    gap: clamp(24px, 4vw, 44px);
    align-items: start;
}

.detail-preview {
    display: flex;
    justify-content: center;
}

/* The envelope must be told how wide to be. As a flex item it shrinks to its content, and the
   stage inside it is a size container - which by definition contributes no width of its own. So
   the two cancelled out to zero and the whole preview column rendered empty, for every
   template, classic envelope included. The stage keeps its own 640px cap and centres itself. */
.detail-preview > .env-root {
    width: 100%;
}

/* On this page the envelope stands beside the template's name, and the headroom the card needs
   to rise into would push it half a screen below it. So the headroom is not reserved up front:
   the envelope sits level with the title while it is closed, and slides down to make room in
   the same moment the card starts to rise. The home page keeps its fixed headroom. */
.detail-preview .env-scene {
    margin-top: 6cqi;
    transition: margin-top 1s cubic-bezier(.3, .7, .3, 1);
}

.detail-preview .env-switch-open:checked ~ .env-stage .env-scene {
    margin-top: 58cqi;
}

@container (max-width: 430px) {
    .detail-preview .env-switch-open:checked ~ .env-stage .env-scene { margin-top: 66cqi; }
}

/* Without motion the card is shown already risen, so the room has to be there from the start. */
@media (prefers-reduced-motion: reduce) {
    .detail-preview .env-scene { margin-top: 58cqi; transition: none; }
}

.detail-info h1 {
    margin: 0 0 8px;
    font-size: clamp(24px, 4vw, 34px);
}

.detail-lead {
    margin: 0 0 22px;
    color: var(--dc-muted);
}

.detail-specs {
    display: grid;
    gap: 12px;
    margin: 0 0 26px;
}

.detail-specs > div {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--dc-line);
}

.detail-specs dt {
    min-width: 11rem;
    color: var(--dc-muted);
    font-size: 14px;
}

.detail-specs dd {
    margin: 0;
    font-size: 14px;
}

.detail-note {
    margin-top: 14px;
    font-size: 13px;
    color: var(--dc-muted);
}

/* The two ways forward from a template: make one, or first see it the way a guest will. */
.detail-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: center;
}

.detail-demo {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.detail-demo svg {
    width: 16px;
    height: 16px;
}

/* ---------------------------------------------------------------- steps, features, faq */

.step-list {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
    gap: 20px;
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: step;
}

.step-list li {
    padding: 22px;
    background: var(--dc-surface);
    border: 1px solid var(--dc-line);
    border-radius: var(--dc-radius);
}

.step-list h3 {
    margin: 10px 0 6px;
    font-size: 17px;
}

.step-list p {
    margin: 0;
    font-size: 14px;
    color: var(--dc-muted);
}

.step-number {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: var(--dc-brand-soft);
    color: var(--dc-brand);
    font-weight: 700;
}

.step-upcoming {
    border-style: dashed;
    background: transparent;
}

.badge {
    display: inline-block;
    margin-inline-start: 6px;
    padding: 2px 9px;
    border-radius: 999px;
    background: #f4ead6;
    color: #7a5c22;
    font-size: 12px;
    font-weight: 600;
    vertical-align: middle;
}

.feature-card {
    padding: 22px;
    background: var(--dc-surface);
    border: 1px solid var(--dc-line);
    border-radius: var(--dc-radius);
}

.feature-card h3 {
    margin: 0 0 6px;
    font-size: 17px;
}

.feature-card p {
    margin: 0;
    font-size: 14px;
    color: var(--dc-muted);
}

.roadmap {
    margin-top: 22px;
    padding: 20px 22px;
    border: 1px dashed var(--dc-line);
    border-radius: var(--dc-radius);
}

.roadmap h3 {
    margin: 0 0 6px;
    font-size: 16px;
}

.roadmap p {
    margin: 0;
    font-size: 14px;
    color: var(--dc-muted);
}

.faq {
    display: grid;
    gap: 10px;
}

.faq details {
    padding: 16px 20px;
    background: var(--dc-surface);
    border: 1px solid var(--dc-line);
    border-radius: var(--dc-radius-sm);
}

.faq summary {
    cursor: pointer;
    font-weight: 600;
}

.faq p {
    margin: 10px 0 0;
    font-size: 14px;
    color: var(--dc-muted);
}

/* ---------------------------------------------------------------- studio */

.studio-grid form {
    padding: 24px;
    background: var(--dc-surface);
    border: 1px solid var(--dc-line);
    border-radius: var(--dc-radius);
}

.studio-grid label {
    display: block;
    margin-top: 14px;
    font-size: 14px;
    color: var(--dc-muted);
}

.studio-grid input,
.studio-grid select,
.studio-grid textarea {
    width: 100%;
    padding: 10px 12px;
    border: 1px solid var(--dc-line);
    border-radius: var(--dc-radius-sm);
    font: inherit;
    background: #fff;
    color: var(--dc-ink);
}

.studio-grid textarea {
    min-height: 110px;
    resize: vertical;
}

.studio-grid button[type=submit] {
    margin-top: 20px;
    width: 100%;
}

.studio-preview {
    position: sticky;
    top: 20px;
}

@media (max-width: 720px) {
    .studio-preview {
        position: static;
    }
}

.form-error {
    margin-top: 12px;
    padding: 10px 14px;
    border-radius: var(--dc-radius-sm);
    background: #fdecec;
    color: #8c2b2b;
    font-size: 14px;
}

/* ---------------------------------------------------------------- the envelope

   Five painted layers share one 3D space. Depth is set with translateZ rather than z-index,
   because inside a preserve-3d context translateZ is what actually decides occlusion.

   Three separate actions, never chained automatically:
     tap the envelope  -> it turns from its address side to its sealed side
     tap the wax seal  -> the flap swings back and the card rises out, turning upright
     tap the card      -> a full copy of it comes forward over the page

   .env-root deliberately has NO containment and NO perspective, so the popup and its
   backdrop can be position:fixed and cover the viewport. Everything that needs container
   units lives inside .env-stage instead. */

.env-root {
    position: relative;
}

.env-switch {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.env-stage {
    container-type: inline-size;
    width: 100%;
    max-width: 640px;
    margin-inline: auto;
}

.env-scene {
    position: relative;
    width: 100%;
    aspect-ratio: 3 / 2;
    /* Headroom for the card to rise into. */
    margin-top: 58cqi;
    perspective: 1600px;
    perspective-origin: 50% 65%;
}

.env-stack {
    position: absolute;
    inset: 0;
    transform-style: preserve-3d;
    transform: rotateY(180deg);
    transition: transform .9s cubic-bezier(.45, .05, .2, 1);
}

/* Instead of a caption telling people to tap, the unopened envelope breathes. It reads as
   "this is alive" without putting words on the artwork. */
.env-hit-turn::after {
    content: "";
    position: absolute;
    inset: 12% 8%;
    border-radius: 6px;
    box-shadow: 0 0 0 0 rgba(47, 93, 112, .18);
    animation: env-breathe 3.4s ease-in-out infinite;
    pointer-events: none;
}

@keyframes env-breathe {
    0%, 100% { box-shadow: 0 0 0 0 rgba(47, 93, 112, .16); }
    50%      { box-shadow: 0 0 0 10px rgba(47, 93, 112, 0); }
}

.env-layer {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
    backface-visibility: hidden;
    user-select: none;
    -webkit-user-drag: none;
}

/* Depth order. A fraction of a pixel apart is enough to settle occlusion with no parallax. */
.env-address { transform: rotateY(180deg) translateZ(1px); }
.env-back    { transform: translateZ(0); }
.env-lining  { transform: translateZ(.5px); opacity: 0; }
.env-front   { transform: translateZ(2px); }

.env-flap {
    transform-origin: top center;
    transform: translateZ(3px) rotateX(0deg);
    transition: transform .75s cubic-bezier(.6, .02, .25, 1);
}

/* ------------------------------------------------ the card inside the envelope */

.env-card {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 44cqi;
    transform-style: preserve-3d;
    /* Sideways inside the envelope: a portrait card only fits a landscape envelope on its
       side, so it starts turned and rights itself on the way out. */
    transform: translateZ(1px) translate(-50%, -50%) rotate(-90deg) scale(.96);
    transition: transform 1.2s cubic-bezier(.24, .86, .28, 1), opacity .35s ease;
    filter: drop-shadow(0 10px 22px rgba(70, 55, 50, .2));
}

.env-card-inner {
    position: relative;
    border-radius: 3px;
    overflow: hidden;
}

/* A slow band of light crossing the paper as it rises. Decorative only. */
.env-sheen {
    position: absolute;
    inset: -30% -60%;
    background: linear-gradient(105deg,
        transparent 38%,
        rgba(255, 255, 255, .5) 50%,
        transparent 62%);
    opacity: 0;
    pointer-events: none;
}

/* ------------------------------------------------ cues and hit areas */

.env-hit-turn {
    position: absolute;
    inset: 0;
    cursor: pointer;
    transition: opacity .3s ease;
}

/* Exactly over the wax seal, which the artwork paints at the flap's point. */
.env-hit-seal {
    position: absolute;
    left: 50%;
    top: 56%;
    width: 15cqi;
    height: 15cqi;
    transform: translate(-50%, -50%);
    border-radius: 50%;
    display: grid;
    place-items: center;
    opacity: 0;
    pointer-events: none;
    cursor: pointer;
    transition: opacity .35s ease;
}

.env-cue-ring {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    border: 1px solid rgba(186, 132, 132, .8);
    animation: env-pulse 2.6s ease-in-out infinite;
}

@keyframes env-pulse {
    0%, 100% { transform: scale(1);    opacity: .8; }
    50%      { transform: scale(1.22); opacity: .2; }
}

.env-hit-card {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 44cqi;
    aspect-ratio: 2 / 3;
    transform: translate(-50%, -50%);
    opacity: 0;
    pointer-events: none;
    cursor: zoom-in;
}

/* ------------------------------------------------ step 1: turned over */

.env-switch-turn:checked ~ .env-stage .env-stack {
    transform: rotateY(0deg);
}

.env-switch-turn:checked ~ .env-stage .env-hit-turn {
    opacity: 0;
    pointer-events: none;
}

.env-switch-turn:checked ~ .env-stage .env-hit-turn::after {
    animation: none;
}

.env-switch-turn:checked ~ .env-stage .env-hit-seal {
    /* Wait for the turn to finish before inviting the next tap. */
    opacity: 1;
    pointer-events: auto;
    transition: opacity .35s ease .75s;
}

/* ------------------------------------------------ step 2: opened */

.env-switch-open:checked ~ .env-stage .env-flap {
    transform: translateZ(3px) rotateX(-164deg);
}

.env-switch-open:checked ~ .env-stage .env-lining {
    opacity: 1;
    transition: opacity .01s linear .4s;
}

.env-switch-open:checked ~ .env-stage .env-card {
    transform: translateZ(1px) translate(-50%, -128%) rotate(0deg) scale(1);
    transition: transform 1.4s cubic-bezier(.22, .78, .24, 1) .5s;
}

.env-switch-open:checked ~ .env-stage .env-sheen {
    animation: env-sheen 1.1s ease-out 1.1s 1;
}

@keyframes env-sheen {
    0%   { opacity: 0;  transform: translateX(-70%); }
    35%  { opacity: 1; }
    100% { opacity: 0;  transform: translateX(70%); }
}

/* The envelope lies back and recedes, leaving the card standing on its own. */
.env-switch-open:checked ~ .env-stage .env-stack {
    transform: rotateY(0deg) translateY(9cqi) rotateX(26deg) scale(.82);
    transition: transform 1s cubic-bezier(.3, .7, .3, 1) .95s;
}

.env-switch-open:checked ~ .env-stage .env-hit-seal {
    opacity: 0;
    pointer-events: none;
    transition: opacity .3s ease;
}

.env-switch-open:checked ~ .env-stage .env-hit-card {
    pointer-events: auto;
    transform: translate(-50%, -128%);
    transition: transform 1.4s cubic-bezier(.22, .78, .24, 1) .5s;
}

/* ------------------------------------------------ step 3: the card comes forward */

.env-backdrop {
    position: fixed;
    inset: 0;
    z-index: 60;
    background: rgba(26, 22, 20, .74);
    backdrop-filter: blur(3px);
    opacity: 0;
    pointer-events: none;
    cursor: zoom-out;
    transition: opacity .4s ease;
}

.env-popup {
    position: fixed;
    inset: 0;
    z-index: 61;
    display: grid;
    place-items: center;
    gap: 18px;
    grid-auto-flow: row;
    align-content: center;
    padding: 24px;
    opacity: 0;
    pointer-events: none;
    transition: opacity .35s ease;
}

.env-popup-card {
    width: min(76vw, 46vh, 420px);
    /* Lifts out of the page: it starts small and slightly back, then settles forward. */
    transform: translateY(14px) scale(.9);
    transition: transform .55s cubic-bezier(.2, .9, .25, 1);
    filter: drop-shadow(0 30px 70px rgba(15, 12, 10, .6));
}

.env-popup-close {
    padding: 9px 22px;
    border-radius: 999px;
    background: rgba(255, 255, 255, .92);
    color: var(--dc-ink);
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
}

.env-switch-zoom:checked ~ .env-backdrop {
    opacity: 1;
    pointer-events: auto;
}

.env-switch-zoom:checked ~ .env-popup {
    opacity: 1;
    pointer-events: auto;
}

.env-switch-zoom:checked ~ .env-popup .env-popup-card {
    transform: translateY(0) scale(1);
}

/* The one in the envelope steps aside so the two copies never read as two cards. */
.env-switch-zoom:checked ~ .env-stage .env-card {
    opacity: 0;
}

/* Keyboard focus lands on the hidden checkbox; show it on whichever cue is live. */
.env-switch-turn:focus-visible ~ .env-stage .env-hit-turn,
.env-switch-open:focus-visible ~ .env-stage .env-hit-seal {
    outline: 2px solid var(--dc-brand);
    outline-offset: 4px;
    border-radius: 8px;
}

.env-switch-zoom:focus-visible ~ .env-popup .env-popup-close {
    outline: 2px solid #fff;
    outline-offset: 3px;
}

/* ------------------------------------------------ reduced motion

   The card is the content, so it is shown immediately and in full: no turning, no opening,
   nothing to wait through. */

@media (prefers-reduced-motion: reduce) {
    .env-stack,
    .env-flap,
    .env-card,
    .env-hit-card,
    .env-backdrop,
    .env-popup,
    .env-popup-card {
        transition: none !important;
    }

    .env-cue-ring,
    .env-sheen {
        animation: none !important;
    }

    .env-hit-turn::after { animation: none; box-shadow: none; }

    .env-stack {
        transform: rotateY(0deg) translateY(9cqi) rotateX(26deg) scale(.82);
    }

    .env-flap   { transform: translateZ(3px) rotateX(-164deg); }
    .env-lining { opacity: 1; }

    .env-card {
        transform: translateZ(1px) translate(-50%, -128%) rotate(0deg) scale(1);
    }

    .env-popup-card { transform: none; }

    .env-flat .env-flat-closed { opacity: 0; }

    .env-flat .env-flat-open { opacity: 1; }

    .env-flat .env-card {
        transform: translateZ(3px) translate(-50%, -128%) rotate(0deg) scale(1);
    }

    .env-hit-turn,
    .env-hit-seal { display: none; }

    .env-hit-card {
        pointer-events: auto;
        transform: translate(-50%, -128%);
    }
}

@container (max-width: 430px) {
    .env-card,
    .env-hit-card { width: 52cqi; }

    .env-scene { margin-top: 66cqi; }
}


/* ------------------------------------------------ uploaded envelopes: three pictures

   An admin-made envelope is photographs, and nothing in a photograph can be bent - so there is
   no flap to swing. The closed picture is simply lifted off the open one underneath it, and the
   card rises from behind the pocket in the same moment.

   The card starts at translateZ(0), behind the open picture, and ends at 3px, in front of it.
   Because the transform transitions as one, it crosses the picture's plane halfway through its
   travel - which is exactly where a real card stops being inside the envelope. */

.env-flat .env-flat-open {
    transform: translateZ(1.5px);
    /* Waiting, not merely behind.

       Two photographs of the same envelope do not have the same silhouette: the open one is
       taller, because its flap is standing up, and wider, because the untied ribbon hangs out
       past the paper. Left visible underneath, those extra millimetres show around the closed
       envelope's edge - a pink tip above the flap, two ribbon ends at the sides - and the
       envelope looks like it is already open before anyone has touched it.

       So the open picture is held at zero and brought up as the closed one is taken away. What
       the eye gets is a dissolve between two aligned photographs, which is the whole effect. */
    opacity: 0;
    transition: opacity .35s ease;
}

.env-flat .env-flat-closed { transform: translateZ(2.5px); transition: opacity .7s ease; }

.env-flat .env-switch-open:checked ~ .env-stage .env-flat-open {
    opacity: 1;
}

.env-flat .env-card {
    transform: translateZ(0) translate(-50%, -50%) rotate(-90deg) scale(.94);
}

.env-flat .env-switch-open:checked ~ .env-stage .env-card {
    transform: translateZ(3px) translate(-50%, -128%) rotate(0deg) scale(1);
}

.env-flat .env-switch-open:checked ~ .env-stage .env-flat-closed {
    opacity: 0;
}

/* A bow is wider than a wax seal and sits a little higher on the flap. */
.env-ribbon .env-hit-seal {
    top: 52%;
    width: 26cqi;
    height: 15cqi;
    border-radius: 999px;
}

.env-ribbon .env-cue-ring {
    border-radius: 999px;
}


/* ---------------------------------------------------------------- home hero */

.hero-split {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: clamp(24px, 4vw, 56px);
    align-items: center;
    text-align: start;
    padding-block: clamp(24px, 4vw, 56px);
}

.hero-split h1 {
    margin-inline: 0;
}

.hero-split .hero-lead {
    margin-inline: 0;
}

.hero-split .hero-actions {
    justify-content: flex-start;
}

.hero-hint {
    margin: 18px 0 0;
    font-size: 13px;
    color: var(--dc-muted);
}

.hero-envelope {
    /* The envelope keeps its own headroom for the card to rise into, so it is nudged up
       with a transform rather than by trimming that space - a margin here would eat the
       room the card needs and clip it on the way out. */
    padding-top: 0;
    transform: translateY(-7%);
}

@media (max-width: 860px) {
    .hero-split {
        grid-template-columns: 1fr;
        text-align: center;
    }

    .hero-split .hero-lead {
        margin-inline: auto;
    }

    .hero-split .hero-actions {
        justify-content: center;
    }

    /* On a narrow screen the envelope leads and the words follow it. */
    .hero-envelope {
        order: -1;
    }

    .hero-hint {
        display: none;
    }
}

/* ---------------------------------------------------------------- comparison */

.compare {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
    gap: 20px;
}

.compare article {
    padding: 24px;
    background: var(--dc-brand-soft);
    border-radius: var(--dc-radius);
}

.compare h3 {
    margin: 0 0 8px;
    font-size: 17px;
    color: var(--dc-brand);
}

.compare p {
    margin: 0;
    font-size: 14px;
    line-height: 1.85;
}

/* ---------------------------------------------------------------- gallery presentation

   A card laid over an opened envelope, the way a printed invitation is photographed.

   Stacking order: the flap stands open above the envelope, the body and pocket sit behind,
   and the card lies in front of all of it. Static on purpose - the listing pages show eleven
   of these, so they use the small layers and nothing animates.

   The card sits right of centre so the open flap and its lining stay visible down the left
   side; a perfectly centred card hides both. All proportions here were checked by
   compositing the real layers at these exact values before they were written. */

.tile-scene {
    position: relative;
    width: 100%;
    aspect-ratio: 1 / 1.22;
    container-type: inline-size;
}

.tile-flap,
.tile-back,
.tile-front,
.tile-open {
    position: absolute;
    inset-inline: 0;
    width: 100%;
    height: auto;
    user-select: none;
    -webkit-user-drag: none;
}

/* The envelope stands 55% of the tile tall at full width, anchored to the bottom. An uploaded
   envelope's open picture is a 3:2 canvas, which at full width is the same 55% - so it takes
   exactly the place the classic layers do and the card lands where it always has. */
.tile-back,
.tile-front,
.tile-open { bottom: 0; }

/* Stretched upward from its hinge, so the open flap reads as a tall standing triangle
   rather than a shallow fold. The origin keeps the hinge pinned to the envelope's edge. */
.tile-flap {
    bottom: 48%;
    transform: scaleY(1.4);
    transform-origin: bottom center;
}

/* An uploaded envelope in a tile.

   The classic reads tall because its flap stands up above the body; a photographed envelope
   has its flap inside a 3:2 picture, so at the tile's width it came out about 90px shorter and
   the card covered most of it. Measured on the wedding page: 240px of classic against 147px.

   So it is drawn a little wider than the tile - as far as the tile's own padding allows. The
   card lies in front of it exactly as it does on the classic: an earlier version laid the
   pocket over the card again to tuck it in, and on a tile that small it only read as a card
   cut off at the bottom. */
.tile-open {
    inset-inline: auto;
    left: -7%;
    width: 114%;
    max-width: none;
}

.tile-card {
    position: absolute;
    left: 57%;
    top: 19%;
    width: 58%;
    transform: translateX(-50%);
    filter: drop-shadow(0 10px 22px rgba(70, 55, 50, .26));
}

.tile-card .card {
    max-width: none;
    box-shadow: none;
    border-radius: 2px;
}

/* On a tile this small the message line is unreadable anyway, and dropping it lets the
   names breathe. */
@container (max-width: 250px) {
    .tile-card .card-message { display: none; }
}

/* ---------------------------------------------------------------- hero backdrop

   A decorative band behind the opening section only, fading into the plain page before the
   first scroll ends. It is full-bleed: the page shell is capped at 1100px, so the backdrop
   escapes it with the 100vw / translateX trick rather than by restructuring the layout.

   A white veil sits over the middle so the headline and the envelope never compete with the
   picture, whatever image is used underneath. */

.hero-split {
    position: relative;
    isolation: isolate;
}

.hero-backdrop {
    position: absolute;
    z-index: -1;
    top: calc(clamp(28px, 5vw, 48px) * -1);
    bottom: -6%;
    left: 50%;
    width: 100vw;
    transform: translateX(-50%);
    background-image:
        /* A light veil only. The artwork's own centre is already clean white, so this just
           softens the props nearest the text rather than washing the whole band out. */
        radial-gradient(105% 85% at 50% 48%,
            rgba(255, 255, 255, .55) 0%,
            rgba(255, 255, 255, .3) 45%,
            rgba(255, 255, 255, 0) 78%),
        url('card-art/hero-backdrop.webp');
    /* The band is a wide 2.4:1 strip and the hero is taller than that, so `cover` was
       cropping the props off the left and right edges. Sizing it to the full width instead
       keeps every object whole; the strip simply sits across the top and the plain page
       shows below it. */
    background-size: cover, 100% auto;
    background-position: center, center top;
    background-repeat: no-repeat, no-repeat;
    /* Dissolve into the page instead of ending on a hard edge. */
    -webkit-mask-image: linear-gradient(to bottom, #000 58%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 58%, transparent 100%);
    pointer-events: none;
}

@media (max-width: 860px) {
    .hero-backdrop {
        /* On a phone the strip would be only a couple of centimetres tall at full width,
           so let it fill instead - losing the far edges matters less than the props being
           too small to read. */
        bottom: 30%;
        background-size: cover, cover;
        background-position: center top, center top;
    }
}

/* =====================================================================================
   Element layer

   The card's text as a list of positioned boxes rather than a fixed stack. Everything an
   element needs is either a number the server clamped and wrote into the style attribute
   (position, size, rotation, type size) or a token class from a closed set (font, weight,
   alignment, colour). Nothing here reads a raw value from a card, which is what makes it
   safe to let people edit layouts.

   Type size arrives as a cqi value, so it scales with the card and the same layout holds
   on a phone tile and in the full-size preview. Positions are physical percentages: the
   card is right-to-left but a mouse is not, and the editor drags in these coordinates.
   ===================================================================================== */

.card-stage {
    position: absolute;
    inset: 0;
    z-index: 2;
    /* The painted artwork is the background; boxes must not intercept taps meant for the
       envelope or the tile link underneath. The editor re-enables this on its own canvas. */
    pointer-events: none;
}

.card-el {
    position: absolute;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: center;
    gap: .3em;
    margin: 0;
    color: var(--card-ink);
    /* Long Persian names and addresses wrap; they never clip and never push the box. */
    overflow-wrap: anywhere;
}

/* Only the roles that carry their own multi-line text keep the author's line breaks.
   This is deliberately not on .card-el: in a flex container, white-space: pre-wrap stops
   whitespace-only anonymous items being dropped, so the newlines between the name spans in
   the markup would become real wrap opportunities and could push a name onto its own line. */
.card-el-poem,
.card-el-text,
.card-el-address { white-space: pre-wrap; }

/* ---- alignment: both the box's text and how its inline pieces sit in it */
.card-align-center { text-align: center; justify-content: center; }
.card-align-right  { text-align: right;  justify-content: flex-start; }
.card-align-left   { text-align: left;   justify-content: flex-end; }

/* ---- faces */
.card-font-body     { font-family: var(--dc-sans); }
.card-font-display  { font-family: var(--dc-display); }
.card-font-nastaliq {
    font-family: var(--dc-nastaliq);
    /* Nastaliq sits low and needs room above and below, or descenders collide. */
    line-height: 2.1;
}

.card-weight-normal { font-weight: 400; }
.card-weight-medium { font-weight: 500; }
.card-weight-bold   { font-weight: 700; }

/* Lalezar ships one weight; asking for bold makes the browser synthesise a smeared face. */
.card-font-display.card-weight-bold,
.card-font-display.card-weight-medium,
.card-font-nastaliq.card-weight-bold,
.card-font-nastaliq.card-weight-medium { font-weight: 400; }

/* ---- tones, resolved against the card's own custom properties */
.card-tone-ink    { color: var(--card-ink); }
.card-tone-accent { color: var(--card-accent); }
.card-tone-muted  { color: var(--card-accent); opacity: .75; }
.card-tone-paper  { color: var(--card-ground); }

/* ---- per-role touches that are about the shape of the content, not its position */
.card-el-kicker { letter-spacing: .12em; }

.card-el-names .card-amp { font-size: .42em; }

.card-el-divider {
    align-items: center;
    justify-content: center;
    padding: 0;
}

.card-el-divider svg {
    display: block;
    width: 100%;
    height: auto;
}

.card-el-photo {
    align-items: center;
    justify-content: center;
    border: 1px dashed color-mix(in oklab, var(--card-accent) 55%, transparent);
    border-radius: var(--dc-radius-sm);
    background: color-mix(in oklab, var(--card-ground) 82%, transparent);
}

/* The gallery tile is a thumbnail: at that size a message is unreadable noise, and the
   fixed-stack rule above already hides .card-message there. */
.tile-card .card-el-message,
.tile-card .card-el-poem,
.tile-card .card-el-address { display: none; }

/* =====================================================================================
   Element variants, photo shapes and frames

   A variant is a presentation choice inside one role - a date read as a line of text or
   set inside a ring. The server validates variants per role, so the class names below are
   the only ones that can ever appear.
   ===================================================================================== */

/* ---- poem attribution */
.card-poet {
    display: block;
    width: 100%;
    margin-top: .5em;
    font-family: var(--dc-sans);
    font-size: .55em;
    opacity: .65;
    white-space: normal;
}

/* ---- date and time variants */
.card-el-date.card-var-circle,
.card-el-time.card-var-circle {
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .05em;
    aspect-ratio: 1;
    border-radius: 50%;
    box-shadow: inset 0 0 0 .07em currentColor;
    padding: .5em;
}

.card-el-date.card-var-stacked {
    flex-direction: column;
    align-items: center;
    gap: .05em;
}

.card-var-circle .d-day,
.card-var-stacked .d-day { font-size: 1.5em; line-height: 1; }

.card-var-circle .d-month,
.card-var-stacked .d-month { font-size: .62em; letter-spacing: .05em; }

.card-var-circle .d-year,
.card-var-stacked .d-year { font-size: .55em; opacity: .75; }

/* columns: «پنج‌شنبه │ ۱۵ │ شهریور». The day stands tall in the middle between two upright
   rules; the weekday and the month sit either side between a pair of level ones, the way it is
   set on printed Iranian cards. Right to left, so the weekday is read first. */
.card-el-date.card-var-columns {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 0;
}

.card-var-columns .d-weekday,
.card-var-columns .d-month {
    padding: .3em .2em;
    border-block: .05em solid color-mix(in oklab, currentColor 55%, transparent);
    font-size: .82em;
    white-space: nowrap;
}

.card-var-columns .d-day {
    padding: 0 .45em;
    border-inline: .03em solid color-mix(in oklab, currentColor 55%, transparent);
    font-size: 2.4em;
    font-weight: 700;
    line-height: 1.05;
}

/* calendar: a leaf torn from a desk calendar - the month and year in a band, the day large
   under it, the weekday at the foot. The band takes the element's own colour, so it follows
   whatever colour the date was given, and its text is the paper's white. */
.card-el-date.card-var-calendar {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 0;
    overflow: hidden;
    border-radius: .35em;
    box-shadow: inset 0 0 0 .06em currentColor;
    text-align: center;
}

.card-var-calendar .d-month {
    padding: .25em .3em;
    /* The band is the element's colour; the words in it are painted white with text-fill,
       which leaves `color` - and so the band - alone. */
    background: currentColor;
    -webkit-text-fill-color: #fff;
    font-size: .72em;
    white-space: nowrap;
}

.card-var-calendar .d-day {
    padding-top: .12em;
    font-size: 2.5em;
    font-weight: 700;
    line-height: 1.05;
}

.card-var-calendar .d-weekday {
    padding: 0 .3em .45em;
    font-size: .78em;
    opacity: .85;
}

.card-var-boxed {
    padding: .35em .7em;
    border-block: .06em solid currentColor;
}

/* ---- address with a location mark */
.card-el-address.card-var-pin {
    align-items: center;
    gap: .35em;
    /* The mark stays beside a long address rather than wrapping onto a line of its own above
       it: that lone line cost a whole row, and on a crowded card pushed the address onto the
       painting. The text shrinks and wraps inside its own box instead. */
    flex-wrap: nowrap;
}

.card-var-pin .d-pin {
    flex: none;
    width: 1.1em;
    height: 1.1em;
}

.card-var-pin .d-pin svg { display: block; width: 100%; height: 100%; }

.card-var-pin .d-text { white-space: pre-wrap; min-width: 0; }

/* ---- divider motifs */
.card-el-divider.card-var-dots::before {
    content: "◆ ◆ ◆";
    font-size: .5em;
    letter-spacing: .6em;
}

.card-el-divider.card-var-dots svg,
.card-el-divider.card-var-floral svg { display: none; }

.card-el-divider.card-var-floral::before {
    content: "❦";
    font-size: 1.1em;
}

/* ---- photo: shape, then the soft edge, then the frame */
.card-el-photo {
    padding: 0;
    /* Deliberately not hidden: the clipping moved to .card-photo-clip inside, so that a painted
       frame can be drawn around the picture. When the element itself clipped, every frame was
       cut off at the edge of the photo and ended up sitting on top of it. */
    overflow: visible;
    align-items: center;
    justify-content: center;
    background: color-mix(in oklab, var(--card-ground) 82%, transparent);
}

/* The picture's own box: fills the element, takes the element's shape, and crops whatever the
   fit and the zoom push outside it. */
.card-photo-clip {
    position: absolute;
    inset: 0;
    overflow: hidden;
    border-radius: inherit;
    display: grid;
    place-items: center;
}

.card-photo-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* ---- the design's own window. The photo is in .card-under, below the artwork, and the
   painting's transparent hole is its shape - so no border, no rounding, nothing drawn round it.
   Its box is meant to run a little past the hole on every side; the painted edge hides the rest.
   Until a picture is chosen the window shows a soft wash of the card's colour and the hint. */
.card-under {
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
}

.card-el-photo.card-var-behind {
    border: none;
    border-radius: 0;
    box-shadow: none;
    background: color-mix(in oklab, var(--card-accent) 18%, var(--card-ground));
}

.card-el-photo.card-var-behind .card-photo-hint {
    /* The painted edge usually dips into the bottom of the box, so the hint sits a little high
       of centre where it is sure to be inside the visible part of the window. */
    transform: translateY(-12%);
}

/* The painting is on top of the photo now, and must not catch the taps meant for it. */
.card-artwork { pointer-events: none; }

.card-el-photo.card-var-rounded { border-radius: 8%; }
.card-el-photo.card-var-circle,
.card-el-photo.card-var-oval { border-radius: 50%; }
.card-el-photo.card-var-arch { border-radius: 50% 50% 6% 6% / 42% 42% 3% 3%; }

/* A heart cannot be made from border-radius, so the photo is masked by a heart-shaped SVG
   carried inline in the stylesheet - no extra request, and it scales to any frame size. */
.card-el-photo.card-var-heart .card-photo-clip {
    --card-shape-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' preserveAspectRatio='none'%3E%3Cpath d='M50 94C10 66 2 46 2 32 2 16 14 4 29 4c9 0 17 5 21 13 4-8 12-13 21-13 15 0 29 12 29 28 0 14-12 34-50 62z' fill='%23000'/%3E%3C/svg%3E");
    -webkit-mask-image: var(--card-shape-mask);
    mask-image: var(--card-shape-mask);
    -webkit-mask-size: 100% 100%;
    mask-size: 100% 100%;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    background: none;
    border: none;
}

/* Heart plus a soft edge: two masks, kept only where they overlap. Without the composite the
   feather rule below would simply replace the heart and the photo would turn back into a box. */
.card-el-photo.card-var-heart[style*="--card-feather"] .card-photo-clip {
    -webkit-mask-image: radial-gradient(closest-side, #000 var(--card-feather), transparent 100%), var(--card-shape-mask);
    mask-image: radial-gradient(closest-side, #000 var(--card-feather), transparent 100%), var(--card-shape-mask);
    -webkit-mask-composite: source-in;
    mask-composite: intersect;
}

/* ---- stickers: a drawing that takes the card's own colour */
.card-el-sticker {
    padding: 0;
    display: block;
    line-height: 0;
}

.card-el-sticker svg {
    display: block;
    width: 100%;
    height: auto;
    overflow: visible;
}

/* The soft edge. --card-feather is the radius of the fully opaque centre, so a larger
   feather value from the editor arrives here as a smaller number and a wider fade. Set
   only when the user asked for one, which is why there is no default in this rule. */
.card-el-photo[style*="--card-feather"] .card-photo-clip {
    -webkit-mask-image: radial-gradient(closest-side, #000 var(--card-feather), transparent 100%);
    mask-image: radial-gradient(closest-side, #000 var(--card-feather), transparent 100%);
    background: none;
}

/* Rings follow the shape's border-radius because box-shadow does, so one rule covers
   every shape above. */
.card-frame-el-thin   { box-shadow: 0 0 0 .05em currentColor; }
.card-frame-el-double { box-shadow: 0 0 0 .04em currentColor, 0 0 0 .14em color-mix(in oklab, currentColor 35%, transparent); }
.card-frame-el-gold   { box-shadow: 0 0 0 .06em #c2a163, 0 0 0 .16em color-mix(in oklab, #c2a163 30%, transparent); }

/* A painted frame sits over the photo and bleeds past its edge, so it is drawn by a
   pseudo-element rather than a background on the box itself. A slug with no file behind
   it simply paints nothing. */
.card-frame-el-art { overflow: visible; }

/* A painted frame is drawn as a nine-slice border, not as a stretched picture. border-image
   keeps each corner at its own proportions and repeats only the straight runs between them, so
   the same artwork fits a tall portrait frame and a wide one without a single squashed flower.
   The thickness is in cqi - a percentage of the card's own width - so the frame scales with the
   card instead of with the screen. */
.card-frame-el-art::after {
    content: "";
    position: absolute;
    /* Around the picture, not on it: the clipping now happens one level in, so this can sit
       outside the photo's edge the way a frame sits around a print. */
    inset: -11%;
    border: 6cqi solid transparent;
    border-image-source: var(--card-frame-art);
    border-image-slice: 34;
    border-image-repeat: round;
    pointer-events: none;
}

/* A ring frame instead: stretched over the whole box, so a round photo gets a round frame and an
   oval one gets an oval frame. A nine-slice border cannot bend, which is why the rectangular
   frames and these are two different drawings rather than one drawing in two modes. */
.card-frame-el-art.card-frame-ring::after {
    inset: -13%;
    border: none;
    background-image: var(--card-frame-art);
    background-size: 100% 100%;
    background-repeat: no-repeat;
}

/* =====================================================================================
   The editor

   Only /studio loads this chrome. The card inside it is the ordinary CardPreview, which is
   the point: what is arranged here is literally the component the guests will open.
   ===================================================================================== */

.ed-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--dc-step);
    padding: calc(var(--dc-step) * .75) var(--dc-step);
    margin-bottom: var(--dc-step);
    border-radius: var(--dc-radius-sm);
    background: var(--dc-surface, #fff);
    box-shadow: var(--dc-shadow);
    position: sticky;
    top: 0;
    z-index: 20;
}

.ed-bar-group { display: flex; align-items: center; gap: .4rem; }
.ed-bar-add { flex-wrap: wrap; }
.ed-bar-end { margin-inline-start: auto; }

.ed-bar button,
.ed-panel button {
    padding: .35rem .7rem;
    border: 1px solid color-mix(in oklab, currentColor 18%, transparent);
    border-radius: var(--dc-radius-sm);
    background: transparent;
    font: inherit;
    font-size: .85rem;
    color: inherit;
    cursor: pointer;
}

.ed-bar button:hover:not(:disabled),
.ed-panel button:hover:not(:disabled) { background: color-mix(in oklab, currentColor 7%, transparent); }
.ed-bar button:disabled,
.ed-panel button:disabled { opacity: .4; cursor: not-allowed; }

.ed-inline { display: flex; align-items: center; gap: .4rem; font-size: .85rem; }

.ed-notice {
    display: flex;
    gap: .6rem;
    align-items: center;
    padding: .6rem .9rem;
    margin-bottom: var(--dc-step);
    border-radius: var(--dc-radius-sm);
    background: color-mix(in oklab, var(--dc-accent, #52796f) 10%, transparent);
}

/* ---- three columns on a desktop, stacked on a phone with the card first */
.ed-layout {
    display: grid;
    grid-template-columns: minmax(220px, 1fr) minmax(0, 1.6fr) minmax(230px, 1fr);
    gap: var(--dc-step);
    align-items: start;
}

/* Stacked on a narrow screen, and the card sticks to the top while the panels scroll under
   it. Without this the style panel ends up hundreds of pixels below the card: you pick a
   colour, cannot see the card, and reasonably conclude the button did nothing. The card is
   also made smaller here so there is still room to work in below it. */
@media (max-width: 1100px) {
    .ed-layout { grid-template-columns: 1fr; }
    .ed-bar { position: static; }

    .ed-canvas {
        order: -2;
        position: sticky;
        top: 0;
        z-index: 6;
        padding-block: .5rem;
        background: var(--dc-ground, #f5f7f9);
        box-shadow: 0 8px 12px -10px rgba(30, 40, 51, .35);
    }

    .ed-card { max-width: min(100%, 230px); }

    /* The panel for whatever is selected comes first, right under the card. */
    .ed-panel { order: -1; }
}

/* On a desktop each side column stays put and scrolls inside itself, so the card in the middle
   is always in view. Without this the panel for a photo - upload, fit, three sliders, presets,
   shape, border, feather - runs far below the card, and you change something you cannot see.
   Height is capped just under the viewport, leaving room for the sticky toolbar above. */
@media (min-width: 1101px) {
    .ed-content,
    .ed-panel {
        position: sticky;
        top: 4.5rem;
        max-height: calc(100vh - 5.5rem);
        overflow-y: auto;
        overscroll-behavior: contain;
    }
}

/* The sticker picker shows the drawings at thumbnail size - the only honest way to choose
   between twelve ornaments. */
.ed-stickers {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: .35rem;
}

.ed-panel .ed-sticker-btn {
    display: grid;
    place-items: center;
    aspect-ratio: 1;
    padding: .3rem;
    color: var(--dc-accent, #52796f);
}

.ed-panel .ed-sticker-btn svg { width: 100%; height: 100%; }

.ed-panel .ed-sticker-btn.is-on {
    background: color-mix(in oklab, var(--dc-accent, #52796f) 16%, transparent);
    border-color: var(--dc-accent, #52796f);
}

/* The tab strip. Only one group of controls is on screen at a time, which is what keeps the
   column short enough to stay beside the card rather than under it. */
.ed-tabs {
    display: flex;
    gap: .2rem;
    margin-bottom: var(--dc-step);
    border-bottom: 1px solid color-mix(in oklab, currentColor 12%, transparent);
}

.ed-tabs button {
    flex: 1;
    padding: .4rem .3rem;
    border: none;
    border-bottom: 2px solid transparent;
    border-radius: 0;
    background: none;
    font: inherit;
    font-size: .8rem;
    opacity: .65;
    cursor: pointer;
}

/* Specific enough to beat the panel's own button hover, which would otherwise paint a box
   behind a tab that is meant to read as a tab. */
.ed-tabs button:hover:not(:disabled) { opacity: .9; background: none; }

.ed-tabs button.is-on {
    opacity: 1;
    border-bottom-color: var(--dc-accent, #52796f);
    font-weight: 500;
}

.ed-content,
.ed-panel {
    padding: var(--dc-step);
    border-radius: var(--dc-radius-sm);
    background: var(--dc-surface, #fff);
    box-shadow: var(--dc-shadow);
}

.ed-content label,
.ed-panel label { display: block; font-size: .8rem; margin-bottom: .6rem; }

.ed-content input,
.ed-content textarea,
.ed-content select,
.ed-panel input[type="number"] {
    display: block;
    width: 100%;
    margin-top: .25rem;
    padding: .4rem .5rem;
    border: 1px solid color-mix(in oklab, currentColor 18%, transparent);
    border-radius: var(--dc-radius-sm);
    font: inherit;
    font-size: .85rem;
    background: transparent;
    color: inherit;
}

.ed-content fieldset,
.ed-panel fieldset { border: none; padding: 0; margin: 0 0 var(--dc-step); }
.ed-content legend,
.ed-panel legend { font-size: .75rem; opacity: .7; padding: 0 0 .35rem; }

.ed-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: .5rem; }
.ed-grid3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: .5rem; }

/* ---- canvas */
.ed-canvas { touch-action: none; }
.ed-canvas.is-dragging { cursor: grabbing; user-select: none; }

.ed-card {
    position: relative;
    width: 100%;
    max-width: 460px;
    margin-inline: auto;
    outline: none;
}

/* CardPreview caps itself at thumbnail width; the editor needs the whole column. */
.ed-card .card { max-width: none; }

.ed-safe {
    position: absolute;
    left: 0;
    right: 0;
    z-index: 3;
    pointer-events: none;
    border-block: 1px dashed color-mix(in oklab, var(--dc-accent, #52796f) 45%, transparent);
    background: color-mix(in oklab, var(--dc-accent, #52796f) 4%, transparent);
}

.ed-overlay { position: absolute; inset: 0; z-index: 4; }

.ed-hit {
    position: absolute;
    border: 1px solid transparent;
    border-radius: 2px;
    cursor: grab;
    touch-action: none;
}

.ed-hit:hover { border-color: color-mix(in oklab, var(--dc-accent, #52796f) 45%, transparent); }
.ed-hit.is-selected { border-color: var(--dc-accent, #52796f); }
.ed-hit.is-warned { border-style: dashed; border-color: #c2683f; }

.ed-frame {
    position: absolute;
    pointer-events: none;
    outline: 1px solid var(--dc-accent, #52796f);
}

/* ---- moving a picture inside its frame */
.ed-hit.is-panning {
    cursor: move;
    border: 2px dashed var(--dc-accent, #52796f);
    background: color-mix(in srgb, var(--dc-accent, #52796f) 6%, transparent);
}

.ed-canvas.is-dragging .ed-hit.is-panning { cursor: grabbing; }

.ed-pan {
    position: absolute;
    z-index: 5;
    display: flex;
    gap: 4px;
    /* Far enough down to clear the bottom height handle of a photo. */
    transform: translate(-50%, 18px);
    white-space: nowrap;
}

.ed-pan button {
    height: 30px;
    padding: 0 12px;
    border: 0;
    border-radius: 999px;
    background: #fff;
    color: var(--dc-ink);
    font: inherit;
    font-size: 12.5px;
    box-shadow: 0 2px 10px rgba(30, 40, 51, .22);
    cursor: pointer;
}

.ed-pan .ed-pan-toggle.is-on {
    background: var(--dc-accent, #52796f);
    color: #fff;
}

.ed-pan .ed-pan-zoom {
    width: 30px;
    padding: 0;
    font-size: 17px;
    line-height: 1;
}

.ed-pan-hint {
    color: var(--dc-ink);
}

.ed-handle {
    position: absolute;
    width: 14px;
    height: 14px;
    margin: -7px;
    border: 1px solid var(--dc-accent, #52796f);
    border-radius: 50%;
    background: #fff;
    pointer-events: auto;
    touch-action: none;
}

.ed-h-e { top: 50%; left: 100%; cursor: ew-resize; }
.ed-h-w { top: 50%; left: 0; cursor: ew-resize; }
/* Height handles are flat bars, so they read as "stretch up and down" rather than as two more
   of the round ones. */
.ed-h-n,
.ed-h-s { left: 50%; width: 26px; height: 10px; margin: -5px -13px; border-radius: 5px; cursor: ns-resize; }
.ed-h-n { top: 0; }
.ed-h-s { top: 100%; }
/* Raised clear of the top handle, which now sits on the same edge. */
.ed-h-rotate { top: -26px; left: 50%; cursor: grab; }

@media (pointer: coarse) {
    /* A fingertip is about 9mm; 14px handles are for a mouse. */
    .ed-handle { width: 22px; height: 22px; margin: -11px; }
    .ed-h-n, .ed-h-s { width: 34px; height: 16px; margin: -8px -17px; }
    .ed-h-rotate { top: -32px; }
}

.ed-warning {
    margin-top: .6rem;
    font-size: .8rem;
    color: #b25a34;
    text-align: center;
}

.ed-hint { font-size: .72rem; opacity: .65; margin: .3rem 0 0; }
.ed-hint.is-warned { color: #b25a34; opacity: 1; }

/* ---- style panel */
.ed-panel-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--dc-step); }
.ed-panel-head h3 { margin: 0; font-size: .95rem; }
.ed-panel-actions { display: flex; gap: .3rem; }
.ed-panel-actions .is-danger:hover { background: color-mix(in oklab, #c2683f 15%, transparent); }
.ed-panel-empty { font-size: .85rem; opacity: .7; }

.ed-row { display: flex; align-items: center; gap: .6rem; }
.ed-row input[type="range"] { flex: 1; }
.ed-num { font-size: .78rem; min-width: 2.4em; text-align: center; opacity: .7; }

/* Label at the start of a slider row. Fixed width so two stacked sliders line up. */
.ed-tag { font-size: .78rem; min-width: 3.2em; opacity: .75; }

.ed-seg { display: flex; gap: .3rem; }
.ed-seg-wrap { flex-wrap: wrap; }
.ed-seg button { flex: 1; min-width: max-content; }
.ed-seg button.is-on,
.ed-font-btn.is-on {
    background: color-mix(in oklab, var(--dc-accent, #52796f) 16%, transparent);
    border-color: var(--dc-accent, #52796f);
}

.ed-fonts { display: flex; gap: .3rem; }
.ed-font-btn { flex: 1; font-size: 1rem; }

.ed-swatches { display: flex; gap: .4rem; align-items: center; }

.ed-swatch {
    width: 26px;
    height: 26px;
    padding: 0;
    border-radius: 50%;
    background: currentColor;
    border: 2px solid transparent;
    box-shadow: 0 0 0 1px color-mix(in oklab, #000 18%, transparent);
    cursor: pointer;
}

.ed-swatch.is-on { border-color: #fff; box-shadow: 0 0 0 2px var(--dc-accent, #52796f); }

/* The palette swatches show the colours of the card being edited, not of the interface. */
.ed-swatches .card-tone-ink    { color: #33332e; }
.ed-swatches .card-tone-accent { color: var(--dc-accent, #52796f); }
.ed-swatches .card-tone-muted  { color: color-mix(in oklab, var(--dc-accent, #52796f) 55%, #fff); }
.ed-swatches .card-tone-paper  { color: #fbfaf7; }

.ed-swatch-custom {
    position: relative;
    overflow: hidden;
    background: conic-gradient(#e4574c, #e9b03a, #7bbf6a, #4aa3d8, #8f6fd0, #e4574c);
}

.ed-swatch-custom input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }

/* ---- poem picker */
.ed-poems { display: grid; gap: .4rem; max-height: 260px; overflow-y: auto; margin-top: .5rem; }

.ed-poem {
    display: block;
    width: 100%;
    text-align: right;
    padding: .5rem .6rem;
    line-height: 2;
}

.ed-poem-text { display: block; white-space: pre-wrap; font-size: .95rem; }
.ed-poem-poet { display: block; font-family: var(--dc-sans); font-size: .7rem; opacity: .6; margin-top: .2rem; }

/* A full-width action at the top of the style panel, for the one or two things that change the
   shape of an element rather than its appearance. */
.ed-panel .ed-wide {
    display: block;
    width: 100%;
    margin-bottom: var(--dc-step);
    font-size: .8rem;
}

/* ------------------------------------------------ my cards */
.mycard {
    display: flex;
    flex-direction: column;
    gap: .6rem;
    padding: var(--dc-step);
    border-radius: var(--dc-radius);
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
}

.mycard h3 { margin: 0; font-size: .95rem; }

.mycard-preview { display: block; text-decoration: none; }

/* The tile is a thumbnail: at that size a message or an address is unreadable noise. */
.mycard-preview .card-el-message,
.mycard-preview .card-el-address,
.mycard-preview .card-el-poem { display: none; }

.mycard-actions { display: flex; gap: .4rem; margin-top: auto; }
.mycard-actions .btn-primary,
.mycard-actions .btn-quiet { flex: 1; text-align: center; font-size: .82rem; padding: .4rem .6rem; }

/* Deliberately the quietest thing on the card: small, grey, and closed until asked for. */
.mycard-delete { margin-top: .5rem; font-size: .78rem; }

.mycard-delete > summary {
    cursor: pointer;
    color: #8a8a8a;
    list-style: none;
    padding: .15rem 0;
}

.mycard-delete > summary::-webkit-details-marker { display: none; }
.mycard-delete > summary:hover { color: #a8342f; }
.mycard-delete[open] > summary { color: #a8342f; }
.mycard-delete p { margin: .4rem 0; color: #6b6b6b; line-height: 1.6; }

.btn-danger {
    border: 1px solid #a8342f;
    background: #fff;
    color: #a8342f;
    border-radius: 6px;
    padding: .35rem .8rem;
    font: inherit;
    font-size: .8rem;
    cursor: pointer;
}

.btn-danger:hover { background: #a8342f; color: #fff; }

/* Cover fills the frame and crops; contain fits the whole picture inside it. The frame keeps its
   own shape either way - only the picture inside behaves differently. */
.card-fit-cover .card-photo-img { object-fit: cover; }
.card-fit-contain .card-photo-img { object-fit: contain; }

/* Which part of the photo survives the crop. The default is dead centre, and the variable is
   only written into the style attribute once it has been moved, so an untouched card carries
   no extra bytes. object-position moves the picture inside its box without moving the box, so
   the frame the user shaped stays exactly where they put it. */
.card-photo-img {
    object-position: var(--card-focus, 50% 50%);
    transform: scale(var(--card-zoom, 1));
    /* Scaled around the same point the crop is centred on, so zooming in moves towards the face
       the user picked instead of towards the middle of the frame. */
    transform-origin: var(--card-focus, 50% 50%);
}


/* =====================================================================================
   Signing in

   The page is the product: an envelope with its flap open and a card inside it. Someone
   arriving here has usually just clicked "save" on a card they spent an evening arranging,
   and this is the first page of ours they are asked to trust with anything. It costs a few
   hundred bytes of CSS and no JavaScript at all.
   ===================================================================================== */

.auth-stage {
    display: grid;
    place-items: center;
    min-height: 68vh;
    padding: calc(var(--dc-step) * 2) var(--dc-step);
}

.auth-card {
    position: relative;
    width: min(100%, 27rem);
    padding: calc(var(--dc-step) * 3) calc(var(--dc-step) * 2) calc(var(--dc-step) * 2);
    border-radius: 14px;
    background: var(--dc-surface, #fff);
    box-shadow: 0 24px 50px -30px rgba(40, 45, 40, .55), 0 2px 6px -3px rgba(40, 45, 40, .25);
    text-align: center;
    overflow: hidden;
}

/* A hairline of the card's own colour inside the paper edge, the way an invitation is printed. */
.auth-card::before {
    content: "";
    position: absolute;
    inset: 10px;
    border: 1px solid color-mix(in oklab, var(--dc-accent, #52796f) 28%, transparent);
    border-radius: 8px;
    pointer-events: none;
}

/* The open flap of the envelope, folded down over the top of the card. */
.auth-flap {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3.2rem;
    color: color-mix(in oklab, var(--dc-accent, #52796f) 12%, transparent);
    line-height: 0;
}

.auth-flap svg { width: 100%; height: 100%; }

.auth-seal {
    position: relative;
    width: 3rem;
    margin: 0 auto var(--dc-step);
    color: var(--dc-accent, #52796f);
    filter: drop-shadow(0 3px 5px rgba(40, 45, 40, .28));
}

.auth-seal svg { width: 100%; height: auto; display: block; }

.auth-head { margin-bottom: calc(var(--dc-step) * 1.5); }

.auth-eyebrow {
    margin: 0;
    font-size: .72rem;
    letter-spacing: .12em;
    opacity: .6;
}

.auth-head h1 {
    margin: .35rem 0 .5rem;
    font-family: 'Gulzar', serif;
    font-size: 1.9rem;
    font-weight: 400;
    line-height: 1.9;
}

.auth-lead { margin: 0; font-size: .88rem; opacity: .75; }

.auth-field { display: block; text-align: right; margin-bottom: var(--dc-step); }
.auth-field > span { display: block; font-size: .78rem; opacity: .7; margin-bottom: .35rem; }

.auth-field input {
    width: 100%;
    /* Without this the padding is added to the 100%, and the box grows wider than the card it
       sits in - which is exactly how it looked. */
    box-sizing: border-box;
    padding: .7rem .8rem;
    border: 1px solid color-mix(in oklab, currentColor 20%, transparent);
    border-radius: 8px;
    background: transparent;
    font: inherit;
    font-size: 1rem;
    color: inherit;
}

.auth-field input:focus-visible {
    outline: 2px solid color-mix(in oklab, var(--dc-accent, #52796f) 60%, transparent);
    outline-offset: 1px;
}

/* The code is five digits and nothing else, so it is shown the way it arrives: big and spaced. */
.auth-code {
    text-align: center;
    font-size: 1.6rem !important;
    letter-spacing: .5em;
    text-indent: .5em;
}

.auth-row { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; }

.auth-submit { width: 100%; box-sizing: border-box; margin-top: .4rem; padding-block: .7rem; }

.auth-fine { margin: .8rem 0 0; font-size: .74rem; opacity: .6; line-height: 1.8; }

.auth-sent { margin: 0 0 var(--dc-step); font-size: .85rem; opacity: .8; }
.auth-sent a { margin-inline-start: .4rem; }

.auth-note {
    margin: 0 0 var(--dc-step);
    padding: .6rem .8rem;
    border-radius: 8px;
    font-size: .84rem;
    background: color-mix(in oklab, var(--dc-accent, #52796f) 10%, transparent);
}

.auth-note.is-warned {
    background: color-mix(in oklab, #c2683f 14%, transparent);
    color: #8d3f1f;
}

.auth-resend { margin-top: .9rem; }

/* What the browser says when a field is empty or malformed. It used to render nothing at all,
   so a rejected form looked exactly like a button that did not work. */
.auth-invalid ul {
    margin: 0 0 var(--dc-step);
    padding: .6rem .8rem;
    border-radius: 8px;
    list-style: none;
    font-size: .82rem;
    text-align: right;
    background: color-mix(in oklab, #c2683f 14%, transparent);
    color: #8d3f1f;
}

.btn-link {
    border: none;
    background: none;
    font: inherit;
    font-size: .82rem;
    color: var(--dc-accent, #52796f);
    text-decoration: underline;
    cursor: pointer;
    padding: 0;
}

/* The administrators' door: the same card, in ink rather than green, so it is obvious at a
   glance which of the two you are standing in front of. */
.auth-stage.is-admin { --dc-accent: #3f4a5a; }

.auth-stage.is-admin .auth-head h1 { font-family: inherit; font-size: 1.35rem; font-weight: 600; }

@media (max-width: 480px) {
    .auth-card { padding-inline: var(--dc-step); }
    .auth-row { grid-template-columns: 1fr; }
}


/* ---- the admin panel's front page */
.panel-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: var(--dc-step);
    list-style: none;
    padding: 0;
    margin: 0;
}

.panel-tile {
    display: flex;
    flex-direction: column;
    gap: .5rem;
    height: 100%;
    padding: var(--dc-step);
    border-radius: var(--dc-radius-sm);
    background: var(--dc-surface, #fff);
    box-shadow: var(--dc-shadow);
}

.panel-tile h2 { margin: 0; font-size: 1rem; }
.panel-tile p { margin: 0; font-size: .85rem; opacity: .75; line-height: 1.8; }
.panel-tile .btn-quiet { align-self: flex-start; margin-top: auto; }

.panel-soon {
    align-self: flex-start;
    margin-top: auto;
    font-size: .72rem;
    opacity: .55;
}

.site-signout { display: inline; }


/* ---- the users table in the admin panel */
.panel-notice {
    margin: 0 0 var(--dc-step);
    padding: .65rem .9rem;
    border-radius: 8px;
    font-size: .86rem;
    background: color-mix(in oklab, var(--dc-accent, #52796f) 12%, transparent);
}

.panel-notice.is-warned { background: color-mix(in oklab, #c2683f 14%, transparent); color: #8d3f1f; }

.panel-search { display: flex; gap: .4rem; align-items: center; margin-bottom: var(--dc-step); }

.panel-search input {
    flex: 1;
    max-width: 22rem;
    box-sizing: border-box;
    padding: .5rem .7rem;
    border: 1px solid color-mix(in oklab, currentColor 18%, transparent);
    border-radius: 8px;
    background: transparent;
    font: inherit;
    font-size: .88rem;
    color: inherit;
}

/* A table is the right shape for this data, and on a phone it scrolls sideways rather than
   collapsing into something that no longer lines up. */
.panel-table-wrap { overflow-x: auto; border-radius: var(--dc-radius-sm); box-shadow: var(--dc-shadow); }

.panel-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--dc-surface, #fff);
    font-size: .85rem;
}

.panel-table th,
.panel-table td {
    padding: .6rem .8rem;
    text-align: right;
    border-bottom: 1px solid color-mix(in oklab, currentColor 8%, transparent);
    vertical-align: middle;
    white-space: nowrap;
}

.panel-table th { font-size: .76rem; opacity: .65; font-weight: 500; }
.panel-table tbody tr:last-child td { border-bottom: none; }
.panel-table tbody tr:hover { background: color-mix(in oklab, var(--dc-accent, #52796f) 4%, transparent); }

.panel-badge {
    display: inline-block;
    padding: .15rem .5rem;
    border-radius: 999px;
    font-size: .72rem;
    background: color-mix(in oklab, var(--dc-accent, #52796f) 16%, transparent);
}

.panel-badge.is-quiet { background: color-mix(in oklab, currentColor 10%, transparent); opacity: .7; }

.panel-actions { display: flex; gap: .4rem; align-items: center; }

/* Each action sits in its own wrapper - one in a form, one in a details - and those two
   elements do not line up on their own: an inline form aligns on the text baseline while a
   details block aligns on its box, which is why the shield sat lower than the bin. Making
   both wrappers flex boxes of their own puts the two icons on one line. */
.panel-actions form,
.panel-actions details {
    display: flex;
    align-items: center;
    margin: 0;
    line-height: 0;
}

.panel-edit > summary,
.panel-delete > summary {
    cursor: pointer;
    list-style: none;
}

.panel-edit > summary::-webkit-details-marker,
.panel-delete > summary::-webkit-details-marker { display: none; }

.panel-edit > summary { text-decoration: underline dotted; text-underline-offset: .25em; }
.panel-delete > summary { color: #a8342f; font-size: .8rem; }

.panel-edit form { display: flex; gap: .3rem; margin-top: .4rem; }

.panel-edit input {
    width: 7rem;
    box-sizing: border-box;
    padding: .3rem .4rem;
    border: 1px solid color-mix(in oklab, currentColor 18%, transparent);
    border-radius: 6px;
    background: transparent;
    font: inherit;
    font-size: .82rem;
    color: inherit;
}

.panel-delete p { margin: .4rem 0; font-size: .78rem; color: #6b6b6b; white-space: normal; max-width: 16rem; }

.panel-pages { display: flex; gap: .6rem; align-items: center; justify-content: center; margin-top: var(--dc-step); font-size: .82rem; }

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}


/* =====================================================================================
   The admin panel

   Dark, full width, with the sidebar on the right where a right-to-left reader's eye
   starts. It deliberately looks nothing like the shop: an administrator glancing at a
   screen should never have to wonder which of the two they are in.

   Charts are drawn by Chart.js, served from our own wwwroot rather than a CDN - a CDN is
   one more host that has to be reachable from Iran on the day you need the panel.
   ===================================================================================== */

.admin {
    --ink: #e6ecf4;
    --ink-muted: rgba(230, 236, 244, .62);
    --surface: #141a22;
    --surface-2: #1b232e;
    --line: rgba(230, 236, 244, .10);
    --brand: #3987e5;

    display: grid;
    /* In a right-to-left page the FIRST grid track is the rightmost one, so the sidebar's
       column is written first to put it on the right. Writing it second - which is what a
       left-to-right habit does - lands it on the left, which is where it was. */
    grid-template-columns: 15rem 1fr;
    gap: 0;
    min-height: 100vh;
    background: #0e131a;
    color: var(--ink);
    /* Full-bleed: the panel escapes the page shell and owns the window. */
    margin-inline: calc(50% - 50vw);
    width: 100vw;
}

/* The fold. A checkbox drives it, so the sidebar collapses with no script at all. */
.admin-fold { position: absolute; opacity: 0; pointer-events: none; }
.admin:has(.admin-fold:checked) { grid-template-columns: 3.6rem 1fr; }
.admin:has(.admin-fold:checked) .admin-text { display: none; }
.admin:has(.admin-fold:checked) .admin-nav a { justify-content: center; padding-inline: 0; }
.admin:has(.admin-fold:checked) .admin-brand a { justify-content: center; }
.admin:has(.admin-fold:checked) .admin-brand { flex-direction: column; gap: .6rem; }

.admin-side {
    grid-column: 1;
    display: flex;
    flex-direction: column;
    gap: 1.2rem;
    padding: 1rem .7rem;
    background: var(--surface);
    border-inline-end: 1px solid var(--line);
    position: sticky;
    top: 0;
    align-self: start;
    max-height: 100vh;
    overflow-y: auto;
}

.admin-brand { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }

.admin-brand a {
    display: flex;
    align-items: center;
    gap: .5rem;
    color: var(--ink);
    text-decoration: none;
    font-weight: 600;
}

/* The panel is dark and the envelope is dark teal with see-through gaps, so on the bare panel it
   all but vanishes. A small cream tile - the colour of the card inside the envelope - gives it
   the light ground it was drawn on. */
.admin-mark { display: block; width: 28px; height: 28px; flex: none; padding: 2px; border-radius: 7px; background: #fdf6ec; box-sizing: content-box; }

.admin-toggle {
    display: grid;
    place-items: center;
    width: 2rem;
    height: 2rem;
    border-radius: 8px;
    color: var(--ink-muted);
    cursor: pointer;
}

.admin-toggle:hover { background: rgba(230, 236, 244, .08); color: var(--ink); }

.admin-nav { display: grid; gap: .2rem; }

.admin-nav a {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .55rem .7rem;
    border-radius: 9px;
    color: var(--ink-muted);
    text-decoration: none;
    font-size: .88rem;
    white-space: nowrap;
}

.admin-nav a:hover { background: rgba(230, 236, 244, .07); color: var(--ink); }

.admin-nav a.is-on {
    background: color-mix(in oklab, var(--brand) 22%, transparent);
    color: #fff;
    font-weight: 500;
}

.admin-icon { width: 1.2rem; text-align: center; opacity: .9; }

.admin-foot { margin-top: auto; display: grid; gap: .4rem; font-size: .82rem; }
.admin-who { display: flex; align-items: center; gap: .6rem; color: var(--ink-muted); padding: .4rem .7rem; }
.admin-who .admin-icon { color: #199e70; font-size: .6rem; }

.admin-signout {
    display: flex;
    align-items: center;
    gap: .6rem;
    width: 100%;
    padding: .5rem .7rem;
    border: none;
    border-radius: 9px;
    background: none;
    color: var(--ink-muted);
    font: inherit;
    font-size: .85rem;
    cursor: pointer;
    text-align: start;
}

.admin-signout:hover { background: rgba(216, 90, 90, .16); color: #ffb4b4; }

.admin-main { grid-column: 2; padding: 1.6rem clamp(1rem, 3vw, 2.5rem) 3rem; min-width: 0; }

.admin-head { margin-bottom: 1.4rem; }
.admin-head h1 { margin: 0 0 .3rem; font-size: 1.5rem; }
.admin-head p { margin: 0; color: var(--ink-muted); font-size: .86rem; }

/* ---- the numbers */
.stat-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(10.5rem, 1fr));
    gap: .8rem;
    list-style: none;
    padding: 0;
    margin: 0 0 1.2rem;
}

.stat {
    display: flex;
    flex-direction: column;
    gap: .25rem;
    padding: .9rem 1rem;
    border-radius: 12px;
    background: var(--surface);
    border: 1px solid var(--line);
}

/* The one number that says whether the site works gets the brand's colour. */
.stat.is-key { border-color: color-mix(in oklab, var(--brand) 45%, transparent); }
.stat.is-key .stat-value { color: #8ab8f5; }

.stat-label { font-size: .76rem; color: var(--ink-muted); }
.stat-value { font-size: 1.8rem; font-weight: 600; line-height: 1.2; }
.stat-note { font-size: .73rem; color: var(--ink-muted); }

/* ---- charts */
.chart-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: .8rem;
    margin-bottom: .8rem;
}

.chart {
    margin: 0;
    padding: 1rem;
    border-radius: 12px;
    background: var(--surface);
    border: 1px solid var(--line);
    min-width: 0;
}

.chart-wide { grid-column: span 2; }

.chart figcaption {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .6rem;
    margin-bottom: .8rem;
}

.chart-title { font-size: .9rem; font-weight: 500; }
.chart-sub { font-size: .74rem; color: var(--ink-muted); }

/* A fixed height, so the canvas has something to size against and the page does not jump
   about while the chart script starts. */
.chart-box { height: 15rem; position: relative; }

.chart-table { margin-top: .6rem; }
.chart-table > summary { cursor: pointer; font-size: .82rem; color: var(--ink-muted); }
.chart-table-body { margin-top: .6rem; overflow-x: auto; }
.chart-table-body > table + table { margin-top: 1rem; }

/* ---- tables inside the panel */
.panel-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--surface);
    font-size: .85rem;
    border-radius: 12px;
    overflow: hidden;
}

.panel-table th,
.panel-table td {
    padding: .6rem .8rem;
    text-align: right;
    border-bottom: 1px solid var(--line);
    vertical-align: middle;
    white-space: nowrap;
}

.panel-table th { font-size: .76rem; color: var(--ink-muted); font-weight: 500; }
.panel-table tbody tr:last-child td { border-bottom: none; }
.panel-table tbody tr:hover { background: rgba(230, 236, 244, .04); }

.panel-table-wrap { overflow-x: auto; border-radius: 12px; border: 1px solid var(--line); }

/* ---- the rest of the panel's furniture, in the dark palette */
.panel-notice {
    margin: 0 0 1rem;
    padding: .65rem .9rem;
    border-radius: 10px;
    font-size: .86rem;
    background: color-mix(in oklab, var(--brand) 18%, transparent);
    color: var(--ink);
}

.panel-notice.is-warned { background: rgba(217, 89, 38, .18); color: #ffc0a4; }

.panel-search { display: flex; gap: .4rem; align-items: center; margin-bottom: 1rem; }

.panel-search input,
.panel-new input {
    box-sizing: border-box;
    padding: .5rem .7rem;
    border: 1px solid var(--line);
    border-radius: 9px;
    background: var(--surface-2);
    font: inherit;
    font-size: .86rem;
    color: var(--ink);
}

.panel-search input { flex: 1; max-width: 22rem; }
.panel-search input::placeholder, .panel-new input::placeholder { color: rgba(230, 236, 244, .35); }

.panel-badge {
    display: inline-block;
    padding: .15rem .5rem;
    border-radius: 999px;
    font-size: .72rem;
    background: color-mix(in oklab, var(--brand) 26%, transparent);
}

.panel-badge.is-quiet { background: rgba(230, 236, 244, .1); color: var(--ink-muted); }

.panel-actions { display: flex; gap: .4rem; align-items: center; }
.panel-actions form { display: inline; }

/* Prefixed with .admin to outrank the site-wide submit-button rule. That rule carries an
   attribute selector and a :not(), which together outweigh a two-class panel selector - so
   without the extra class here the panel's buttons come out in the shop's green. */
.admin .panel-actions .btn-quiet,
.admin .panel-search .btn-quiet,
.admin .panel-pages .btn-quiet,
.admin .panel-search button[type=submit] {
    border: 1px solid var(--line);
    background: var(--surface-2);
    color: var(--ink);
    border-radius: 8px;
    padding: .35rem .7rem;
    font-size: .78rem;
    cursor: pointer;
    text-decoration: none;
}

.admin .panel-actions .btn-quiet:hover,
.admin .panel-search .btn-quiet:hover { background: rgba(230, 236, 244, .1); }

/* ---- icon buttons in the table
   Square, quiet, and only coloured once you are on them. The point of a table is the data;
   six wide labelled buttons per row turn it into a wall of shouting. */
.icon-btn {
    display: inline-grid;
    place-items: center;
    width: 2rem;
    height: 2rem;
    padding: 0;
    border: 1px solid transparent;
    border-radius: 9px;
    background: none;
    color: var(--ink-muted);
    cursor: pointer;
    list-style: none;
}

.icon-btn svg { width: 1.15rem; height: 1.15rem; display: block; }
.icon-btn {
    line-height: 0;
    vertical-align: middle;
    font-size: 0;
    /* Both icons must be the same box: the summary carries a border that otherwise makes it
       two pixels taller than the button beside it. */
    box-sizing: border-box;
}

/* Quiet until you reach for it. A delete that is red at rest makes every row look like a
   warning; red is what the icon turns when the pointer is on it and the meaning matters. */
.panel-actions .icon-btn.is-danger { color: var(--ink-muted); }
.panel-actions .icon-btn.is-danger:hover { color: #ff9c9c; }
.icon-btn::-webkit-details-marker { display: none; }

.icon-btn:hover {
    background: rgba(230, 236, 244, .1);
    border-color: var(--line);
    color: var(--ink);
}

/* Already an administrator: the crown is simply lit. No pill behind it - a background turns an
   icon back into a button, which is what it was not supposed to look like. */
.icon-btn.is-on { color: #8ab8f5; }
.icon-btn.is-on:hover { background: rgba(230, 236, 244, .1); }

.icon-btn.is-danger:hover { background: rgba(216, 90, 90, .18); border-color: rgba(255, 140, 140, .4); color: #ff9c9c; }

/* Not a button at all - it says why the action is missing. */
.icon-btn.is-off { cursor: not-allowed; opacity: .4; }

/* The confirmation, anchored under the trash icon rather than pushing the row around. */
.panel-delete { position: relative; }

.panel-confirm {
    position: absolute;
    inset-inline-end: 0;
    top: 2.3rem;
    z-index: 5;
    width: 15rem;
    padding: .8rem;
    border-radius: 10px;
    background: var(--surface-2);
    border: 1px solid var(--line);
    box-shadow: 0 16px 30px -18px rgba(0, 0, 0, .8);
    white-space: normal;
}

.panel-confirm p { margin: 0 0 .6rem; font-size: .8rem; color: var(--ink-muted); line-height: 1.7; }

.btn-small { font-size: .78rem; padding: .35rem .8rem; }

.panel-edit > summary,
.panel-new > summary { cursor: pointer; list-style: none; }

.panel-edit > summary::-webkit-details-marker,
.panel-new > summary::-webkit-details-marker { display: none; }

.panel-edit > summary { text-decoration: underline dotted; text-underline-offset: .25em; }

.panel-edit form { display: flex; gap: .3rem; margin-top: .4rem; }
.panel-edit input {
    width: 7rem;
    box-sizing: border-box;
    padding: .3rem .4rem;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--surface-2);
    font: inherit;
    font-size: .82rem;
    color: var(--ink);
}

.panel-new { margin-bottom: 1rem; }

.panel-new > summary {
    display: inline-block;
    padding: .45rem .9rem;
    border-radius: 9px;
    background: color-mix(in oklab, var(--brand) 20%, transparent);
    font-size: .84rem;
}

/* A grid, not a flex row. As a flex item the icon picker was handed a narrow column and its
   own grid collapsed to one tile wide - which is how eleven icons ended up in a column down
   the page with the rest of the form squeezed underneath. Here every field is a track and the
   picker is told to span the whole row. */
.panel-new form {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    align-items: end;
    gap: .7rem;
    margin-top: .8rem;
    padding: 1rem;
    border-radius: 12px;
    background: var(--surface);
    border: 1px solid var(--line);
}

.panel-new form > .icon-pick,
.panel-new form > .panel-edit-full { grid-column: 1 / -1; }

/* The button sits on its own line at the start, not stretched across a track. */
.panel-new form > button { grid-column: 1 / -1; justify-self: start; }

.panel-new label { display: block; font-size: .76rem; color: var(--ink-muted); }
.panel-new label input { display: block; width: 100%; box-sizing: border-box; margin-top: .25rem; }
.panel-check { display: flex; align-items: center; gap: .35rem; padding-bottom: .5rem; }
.panel-check input { width: auto; }

.panel-pages { display: flex; gap: .6rem; align-items: center; justify-content: center; margin-top: 1rem; font-size: .82rem; color: var(--ink-muted); }
.panel-soon { font-size: .74rem; color: var(--ink-muted); }

.admin .empty-note,
.admin .breadcrumb { color: var(--ink-muted); }
.admin .breadcrumb a, .admin a { color: #8ab8f5; }
.admin .page-head h1 { color: var(--ink); }

.admin .btn-danger {
    border: 1px solid rgba(255, 140, 140, .5);
    background: transparent;
    color: #ff9c9c;
}

.admin .btn-danger:hover { background: rgba(216, 90, 90, .2); color: #fff; }

.admin .btn-primary,
.admin button[type=submit].btn-primary { background: var(--brand); border-color: var(--brand); color: #fff; }

/* Anything else that posts inside the panel - the new-user form, the delete confirmation -
   wears the panel's own blue rather than the shop's green. */
.admin form button[type=submit]:not(.icon-btn):not(.btn-danger) {
    background: var(--brand);
    border-color: var(--brand);
    color: #fff;
}

.admin .panel-search button[type=submit],
.admin .panel-actions button[type=submit]:not(.icon-btn) {
    background: var(--surface-2);
    border: 1px solid var(--line);
    color: var(--ink);
}

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* On a phone the sidebar becomes a row along the top: a 15rem column beside a 360px screen
   leaves nothing for the content. */
@media (max-width: 720px) {
    .admin, .admin:has(.admin-fold:checked) { grid-template-columns: 1fr; }
    .admin-side { grid-column: 1; grid-row: 1; position: static; max-height: none; flex-direction: row; align-items: center; gap: .6rem; overflow-x: auto; }
    .admin-nav { grid-auto-flow: column; }
    .admin-foot { margin: 0; grid-auto-flow: column; align-items: center; }
    .admin-main { grid-row: 2; padding-inline: 1rem; }
    .admin-toggle { display: none; }
    .chart-wide { grid-column: span 1; }
}


/* ---- the occasions page: a wider inline editor than the users table needs */
.panel-edit-wide {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: .5rem;
    align-items: end;
    margin-top: .6rem;
    padding: .8rem;
    border-radius: 10px;
    background: var(--surface-2);
    border: 1px solid var(--line);
    white-space: normal;
    min-width: 28rem;
}

.panel-edit-wide label { display: block; font-size: .74rem; color: var(--ink-muted); }
.panel-edit-wide input,
.panel-edit-wide select {
    display: block;
    width: 100%;
    box-sizing: border-box;
    margin-top: .2rem;
    padding: .35rem .5rem;
    border: 1px solid var(--line);
    border-radius: 7px;
    background: var(--surface);
    font: inherit;
    font-size: .82rem;
    color: var(--ink);
}

.panel-edit-wide .panel-edit-full { grid-column: 1 / -1; }
.panel-edit-wide button { align-self: end; }

.panel-new select {
    box-sizing: border-box;
    margin-top: .25rem;
    padding: .45rem .6rem;
    border: 1px solid var(--line);
    border-radius: 9px;
    background: var(--surface-2);
    font: inherit;
    font-size: .86rem;
    color: var(--ink);
}

.panel-hint { margin: .5rem 0 0; font-size: .76rem; color: var(--ink-muted); line-height: 1.8; white-space: normal; max-width: 28rem; }


/* ---- choosing a category's icon by looking at it
   Radios, so it works with no script, and the radio itself is hidden: the drawing is the
   control. Eleven Latin words in a dropdown is not a choice anyone can make quickly. */
.icon-pick { display: block; }
.icon-pick-title { display: block; font-size: .74rem; color: var(--ink-muted); margin-bottom: .4rem; }

.icon-pick-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(4.6rem, 1fr));
    gap: .4rem;
}

.icon-pick-grid label {
    display: grid;
    justify-items: center;
    gap: .25rem;
    padding: .5rem .3rem;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--surface);
    cursor: pointer;
    font-size: .72rem;
    color: var(--ink-muted);
}

.icon-pick-grid label:hover { background: rgba(230, 236, 244, .06); color: var(--ink); }

.icon-pick-grid input { position: absolute; opacity: 0; pointer-events: none; }

.icon-pick-face { display: block; width: 1.6rem; height: 1.6rem; }
.icon-pick-face .cat-icon { width: 100%; height: 100%; display: block; }

/* :has() carries the checked state up to the tile, which is what makes the whole card the
   button rather than the little circle nobody can hit on a phone. */
.icon-pick-grid label:has(input:checked) {
    border-color: var(--brand);
    background: color-mix(in oklab, var(--brand) 18%, transparent);
    color: #fff;
}

/* Keyboard users still need to see where they are, and the radio is invisible. */
.icon-pick-grid label:has(input:focus-visible) { outline: 2px solid var(--brand); outline-offset: 1px; }


/* ---- the categories page
   The same card as the home page's taster row, with room for one more line: how many
   templates are inside. That number is the useful part - it tells someone whether opening
   this is worth the tap. */
.category-grid-wide {
    grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
}

.category-count {
    display: block;
    margin-top: .5rem;
    font-size: .76rem;
    opacity: .6;
}

/* ---- the categories page, in colour (CategoryArt)
   Each card has a stage painted in its drawing's pale colour, with a soft light from the top
   corner; the drawing floats on it with a shadow under it and lifts a little under the pointer. */
.cat3d-grid { gap: 18px; }

.cat3d.category-card {
    gap: 0;
    padding: 0;
    overflow: hidden;
    border-radius: 20px;
    border-color: color-mix(in srgb, var(--cat-tint) 60%, var(--dc-line));
    box-shadow: 0 1px 2px rgba(30, 30, 40, .04);
}

.cat3d.category-card:hover,
.cat3d.category-card:focus-visible {
    border-color: color-mix(in srgb, var(--cat-tint) 30%, #c9c2b6);
    box-shadow: 0 14px 30px -12px rgba(40, 30, 20, .22);
    transform: translateY(-3px);
}

.cat3d-stage {
    position: relative;
    display: grid;
    place-items: center;
    height: 138px;
    background:
        radial-gradient(circle at 28% 18%, rgba(255, 255, 255, .95) 0, rgba(255, 255, 255, 0) 52%),
        radial-gradient(circle at 82% 110%, color-mix(in srgb, var(--cat-tint) 55%, #d9cbb8) 0, rgba(255, 255, 255, 0) 60%),
        var(--cat-tint);
}

/* A soft floor under the drawing, so it stands rather than hangs. */
.cat3d-stage::after {
    content: "";
    position: absolute;
    bottom: 18px;
    left: 50%;
    width: 64px;
    height: 10px;
    border-radius: 50%;
    background: rgba(60, 45, 30, .10);
    filter: blur(3px);
    transform: translateX(-50%);
}

.cat-art {
    position: relative;
    z-index: 1;
    width: 96px;
    height: 96px;
    filter: drop-shadow(0 8px 7px rgba(60, 40, 20, .2));
    transition: transform .35s cubic-bezier(.2, .8, .2, 1);
}

.cat3d:hover .cat-art,
.cat3d:focus-visible .cat-art { transform: translateY(-6px) rotate(-4deg) scale(1.05); }

.cat3d-body {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 14px 18px 16px;
}

.cat3d .category-title { font-size: 16.5px; font-weight: 700; }

.cat3d .category-count {
    align-self: flex-start;
    margin-top: 10px;
    padding: 2px 10px;
    border-radius: 999px;
    background: var(--cat-tint);
    color: var(--dc-ink);
    font-size: 12px;
    font-weight: 600;
    opacity: 1;
}

@media (max-width: 480px) {
    .cat3d-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
    .cat3d-stage { height: 112px; }
    .cat-art { width: 78px; height: 78px; }
    .cat3d-body { padding: 12px 13px 14px; }
    .cat3d .category-title { font-size: 15px; }
}

@media (prefers-reduced-motion: reduce) {
    .cat-art { transition: none; }
    .cat3d:hover .cat-art,
    .cat3d:focus-visible .cat-art { transform: none; }
}


/* ---- the envelope library in the panel */

/* The new-envelope form: name, address, closure, then the three pictures side by side. */
.env-new-files {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
    gap: .6rem;
    width: 100%;
}

.env-new-file {
    display: grid;
    gap: .35rem;
    padding: .6rem .7rem;
    border: 1px dashed color-mix(in oklab, currentColor 25%, transparent);
    border-radius: 10px;
    font-size: .85rem;
}

.env-new-file input { font-size: .8rem; max-width: 100%; }

.env-search { flex-wrap: wrap; }

.env-search select {
    padding: .45rem .6rem;
    border: 1px solid color-mix(in oklab, currentColor 18%, transparent);
    border-radius: 8px;
    background: transparent;
    color: inherit;
    font: inherit;
}

/* Landing on an envelope after saving it: a brief ring says "this one". */
.env-card-admin { scroll-margin-top: 1rem; }
.env-card-admin:target { animation: env-landed 1.6s ease-out 1; }

@keyframes env-landed {
    0%   { box-shadow: 0 0 0 3px color-mix(in oklab, var(--dc-accent, #52796f) 70%, transparent); }
    100% { box-shadow: 0 0 0 3px transparent; }
}
.env-cards { display: grid; gap: .8rem; }

.env-card-admin {
    padding: 1rem;
    border-radius: 12px;
    background: var(--surface);
    border: 1px solid var(--line);
}

.env-card-admin > header {
    display: flex;
    align-items: start;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: .8rem;
}

.env-card-admin h2 { margin: 0; font-size: 1rem; }
.env-meta { margin: .2rem 0 0; font-size: .76rem; color: var(--ink-muted); }

.env-slots {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
    gap: .7rem;
}

.env-slot {
    margin: 0;
    padding: .6rem;
    border-radius: 10px;
    background: var(--surface-2);
    border: 1px dashed var(--line);
    display: grid;
    gap: .45rem;
}

/* A slot that has its picture stops looking like an invitation to fill it. */
.env-slot.is-set { border-style: solid; }

/* A checkerboard, because these are transparent PNGs: on a flat dark panel a dark envelope
   with a transparent background is indistinguishable from an empty slot. */
.env-slot img {
    width: 100%;
    aspect-ratio: 3 / 2;
    object-fit: contain;
    border-radius: 6px;
    background-color: #2a3340;
    background-image:
        linear-gradient(45deg, rgba(255,255,255,.05) 25%, transparent 25%, transparent 75%, rgba(255,255,255,.05) 75%),
        linear-gradient(45deg, rgba(255,255,255,.05) 25%, transparent 25%, transparent 75%, rgba(255,255,255,.05) 75%);
    background-size: 16px 16px;
    background-position: 0 0, 8px 8px;
}

.env-slot-empty {
    display: grid;
    place-items: center;
    aspect-ratio: 3 / 2;
    border-radius: 6px;
    background: rgba(230, 236, 244, .04);
    font-size: 1.6rem;
    color: var(--ink-muted);
}

.env-slot figcaption { font-size: .76rem; color: var(--ink-muted); }

.env-slot form { display: grid; gap: .4rem; }

.env-slot input[type="file"] {
    font-size: .72rem;
    color: var(--ink-muted);
    max-width: 100%;
}

.env-slot input[type="file"]::file-selector-button {
    margin-inline-end: .5rem;
    padding: .3rem .6rem;
    border: 1px solid var(--line);
    border-radius: 7px;
    background: var(--surface);
    color: var(--ink);
    font: inherit;
    font-size: .74rem;
    cursor: pointer;
}

.env-card-admin .panel-hint { margin-bottom: .7rem; }


/* ------------------------------------------------ one envelope, previewed

   The panel is dark and the shop is pale, so an envelope judged only here would be judged
   against the wrong background. The tile starts pale - what a guest actually sees - and the
   toggle drops it to near-black, which is where a badly cut transparent PNG shows its halo. */

.env-preview-head { display: flex; align-items: baseline; gap: .8rem; margin-bottom: .4rem; }
.env-preview-head h2 { margin: 0; font-size: 1.05rem; }

.env-preview { margin-top: 1rem; }

.env-preview-switch { position: absolute; opacity: 0; pointer-events: none; }

.env-preview-stage {
    padding: clamp(1rem, 4vw, 2.6rem) 1rem 1rem;
    border: 1px solid var(--line);
    border-radius: 16px;
    background: linear-gradient(180deg, #f7f3ec, #efe7db);
    transition: background .3s ease;
}

.env-preview-switch:checked ~ .env-preview-stage {
    background: linear-gradient(180deg, #14181d, #0b0e12);
}

.env-preview-toggle { margin-top: .7rem; display: inline-block; cursor: pointer; }

.panel-back { color: var(--ink-muted); font-size: .8rem; }

/* The card inside the envelope is the shop's, so the shop's ink has to come with it or every
   preview would read as dark-on-dark. */
.env-preview-stage .env-root { color: #2c2723; }


/* ---------------------------------------------------------------- the template studio

   Two columns: what you change on the right-hand (first) side, and the card itself beside it.
   The card is the only thing on the page that is not dark, because it is not part of the panel -
   it is the thing being made, and it has to be judged against the paper it will live on. */

.admin .btn-primary,
.admin .tpl-forms button[type=submit],
.admin .panel-new button[type=submit] {
    border: 0;
    border-radius: 9px;
    padding: .45rem 1rem;
    background: var(--brand);
    color: #fff;
    font: inherit;
    font-size: .82rem;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
}

.admin .btn-primary:hover { filter: brightness(1.08); }

.admin .btn-quiet {
    display: inline-block;
    border: 1px solid var(--line);
    border-radius: 9px;
    padding: .42rem .9rem;
    background: var(--surface-2);
    color: var(--ink);
    font-size: .8rem;
    cursor: pointer;
    text-decoration: none;
}

.admin .btn-quiet:hover { background: rgba(230, 236, 244, .1); }

.admin .panel-new select,
.admin .tpl-forms select,
.admin .tpl-forms input,
.admin .tpl-forms textarea {
    box-sizing: border-box;
    width: 100%;
    padding: .5rem .7rem;
    border: 1px solid var(--line);
    border-radius: 9px;
    background: var(--surface-2);
    font: inherit;
    font-size: .86rem;
    color: var(--ink);
}

.admin .tpl-forms input[type="color"] { padding: .2rem; height: 2.4rem; cursor: pointer; }
.admin .tpl-forms input[type="file"] { border: 0; background: none; padding: 0; font-size: .74rem; }

/* ---- the list of templates */

/* ---- finding a template: search, state, order, and one chip per occasion */
.tpl-search { flex-wrap: wrap; }

.tpl-search select {
    padding: .45rem .6rem;
    border: 1px solid color-mix(in oklab, currentColor 18%, transparent);
    border-radius: 8px;
    background: transparent;
    color: inherit;
    font: inherit;
}

.tpl-cats {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    margin-bottom: .8rem;
}

.tpl-cats a {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .3rem .75rem;
    border-radius: 999px;
    border: 1px solid color-mix(in oklab, currentColor 18%, transparent);
    color: inherit;
    font-size: .85rem;
    text-decoration: none;
}

.tpl-cats a span {
    font-size: .75rem;
    opacity: .65;
}

.tpl-cats a[aria-current="true"] {
    background: var(--dc-accent, #52796f);
    border-color: var(--dc-accent, #52796f);
    color: #fff;
}

.tpl-cats a[aria-current="true"] span { opacity: .85; }

/* Back from a save, the template that was just changed gets a brief ring. */
.tpl-card { scroll-margin-top: 1rem; }
.tpl-card:target { animation: env-landed 1.6s ease-out 1; }

.tpl-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: 1rem;
}

.tpl-card {
    display: grid;
    grid-template-rows: auto 1fr;
    gap: .7rem;
    padding: .8rem;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: var(--surface);
}

/* A draft is dimmed rather than badged alone: at a glance the page should show which of these
   the site is actually showing, without anybody reading a word. */
.tpl-card.is-draft { border-style: dashed; }
.tpl-card.is-draft .tpl-face { opacity: .72; }

.tpl-face {
    display: block;
    padding: .8rem;
    border-radius: 10px;
    background: linear-gradient(180deg, #f7f3ec, #e9e0d2);
    color: #2c2723;
    text-decoration: none;
}

/* The real card, shrunk. It is the site's own renderer, so what is on this page is what the
   visitor gets - no second opinion, no mock-up that drifts. */
.tpl-face .card { max-width: 11rem; margin-inline: auto; }

.tpl-face-empty {
    display: grid;
    place-items: center;
    aspect-ratio: 2 / 3;
    max-width: 11rem;
    margin-inline: auto;
    border: 1px dashed rgba(44, 39, 35, .35);
    border-radius: 6px;
    font-size: .8rem;
    color: rgba(44, 39, 35, .6);
}

.tpl-body { display: grid; gap: .45rem; align-content: start; }
.tpl-body h2 { margin: 0; font-size: .96rem; }
.tpl-body h2 a { color: var(--ink); text-decoration: none; }
.tpl-body h2 a:hover { text-decoration: underline; }

.tpl-meta {
    margin: 0;
    font-size: .76rem;
    color: var(--ink-muted);
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    align-items: center;
}

.tpl-used { font-size: .74rem; }

/* ---- one template */

.tpl-studio {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 22rem);
    gap: 1.4rem;
    align-items: start;
}

.tpl-forms { display: grid; gap: 1rem; }

.panel-block {
    display: grid;
    gap: .6rem;
    padding: 1rem;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: var(--surface);
}

.panel-block h2 { margin: 0; font-size: .95rem; }
.panel-block label { display: grid; gap: .3rem; font-size: .8rem; color: var(--ink-muted); }

.tpl-form { display: grid; gap: 1rem; }
.tpl-row { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; }
.tpl-save { display: flex; gap: .6rem; align-items: center; }

.tpl-publish { border-color: color-mix(in oklab, var(--brand) 40%, var(--line)); }

.tpl-preview {
    position: sticky;
    top: 1rem;
    display: grid;
    gap: .6rem;
    padding: 1rem;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: linear-gradient(180deg, #f7f3ec, #e9e0d2);
}

.tpl-preview .panel-hint { color: rgba(44, 39, 35, .7); }
.tpl-preview-card { max-width: 17rem; margin-inline: auto; color: #2c2723; }

@media (max-width: 900px) {
    .tpl-studio { grid-template-columns: 1fr; }
    .tpl-preview { position: static; }
}


/* ---------------------------------------------------------------- the library */

.lib-tabs { display: flex; flex-wrap: wrap; gap: .4rem; margin-bottom: 1rem; }

.lib-tabs a {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .4rem .95rem;
    border: 1px solid var(--line);
    border-radius: 999px;
    color: var(--ink-muted);
    font-size: .84rem;
    text-decoration: none;
}

.admin .lib-tabs a { color: var(--ink-muted); }
.admin .lib-tabs a.is-on { background: var(--brand); border-color: var(--brand); color: #fff; }
.lib-tab-count { font-size: .72rem; opacity: .75; }

/* ---- search on one side, "add" on the other; the add form opens as a full-width row below */
.lib-bar { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: .7rem 1rem; margin-bottom: .6rem; }
.lib-search { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; flex: 1 1 26rem; }
.lib-search input[type=search], .lib-search select {
    box-sizing: border-box;
    padding: .45rem .65rem;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface-2);
    color: var(--ink);
    font: inherit;
    font-size: .84rem;
}
.lib-search input[type=search] { flex: 1 1 14rem; max-width: 22rem; }
.lib-search input::placeholder { color: rgba(230, 236, 244, .35); }
.admin .lib-search .btn-quiet,
.admin .lib-search button[type=submit] {
    padding: .42rem .85rem;
    border-radius: 8px;
    font-size: .8rem;
    text-decoration: none;
}
.admin .lib-search .btn-quiet:not(button) { border: 1px solid var(--line); background: var(--surface-2); color: var(--ink); }

.lib-add > summary { list-style: none; cursor: pointer; }
.lib-add > summary::-webkit-details-marker { display: none; }
.admin .lib-add > summary.btn-primary { padding: .45rem .95rem; border-radius: 8px; font-size: .82rem; background: var(--brand); color: #fff; }
.lib-add[open] { flex-basis: 100%; }
.lib-add-body {
    margin-top: .7rem;
    padding: 1rem;
    border-radius: 12px;
    background: var(--surface);
    border: 1px solid var(--line);
}
.lib-add-body form { display: grid; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); align-items: end; gap: .7rem; }
.lib-add-body form > button { grid-column: 1 / -1; justify-self: start; }
.lib-add-body label { display: block; font-size: .76rem; color: var(--ink-muted); }
.lib-add-body label input {
    display: block;
    width: 100%;
    box-sizing: border-box;
    margin-top: .25rem;
    padding: .45rem .65rem;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface-2);
    color: var(--ink);
    font: inherit;
    font-size: .84rem;
}
.admin .lib-add-body input[type="file"] { padding: .3rem 0; border: 0; background: none; }
.lib-add-body .panel-hint { max-width: none; margin-top: .8rem; }

.lib-summary { margin: 0 0 .8rem; font-size: .8rem; color: var(--ink-muted); }

/* ---- small labels under a name: hidden, "default of 3 templates", how a phone sees it */
.lib-tags { display: flex; flex-wrap: wrap; gap: .3rem; }
.lib-tags:empty { display: none; }
.lib-tag {
    padding: .1rem .5rem;
    border-radius: 999px;
    font-size: .7rem;
    background: color-mix(in oklab, var(--brand) 22%, transparent);
    color: #b9d4f7;
    white-space: nowrap;
}
.lib-tag.is-hidden { background: rgba(214, 178, 94, .2); color: #ecd08c; }
.lib-tag.is-quiet { background: rgba(230, 236, 244, .08); color: var(--ink-muted); }

/* ---- songs: one row each - name, player, icons */
.lib-list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); }
.lib-row {
    display: grid;
    grid-template-columns: minmax(10rem, 1fr) minmax(14rem, 22rem) auto;
    align-items: center;
    gap: .6rem 1rem;
    padding: .65rem .9rem;
    border-bottom: 1px solid var(--line);
}
.lib-row:last-child { border-bottom: 0; }
/* Dimmed piece by piece, not the whole row: opacity on the row would make it a layer of its own and
   trap the rename/delete box underneath the next row. */
.lib-row.is-hidden > .lib-row-name, .lib-row.is-hidden > audio { opacity: .72; }
.lib-row-name { display: grid; gap: .3rem; min-width: 0; }
.lib-row-name strong { font-size: .88rem; font-weight: 500; overflow-wrap: anywhere; }
.lib-row audio { width: 100%; height: 2.2rem; }

/* ---- backgrounds and stamps: cards whose picture is the point */
.lib-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: .9rem;
}
.lib-grid.is-small { grid-template-columns: repeat(auto-fill, minmax(11.5rem, 1fr)); }

.lib-card {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas: "media media" "name actions" "more more";
    align-items: start;
    align-content: start;
    gap: .6rem .5rem;
    padding: .7rem;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: var(--surface);
    min-width: 0;
}
.lib-card.is-hidden { border-style: dashed; }
.lib-card.is-hidden .lib-media { opacity: .6; }
.lib-media { grid-area: media; position: relative; border-radius: 9px; overflow: hidden; background: var(--surface-2); }
.lib-media img { display: block; width: 100%; aspect-ratio: 16 / 10; object-fit: cover; }
.lib-media.is-stamp { padding: .6rem; background: repeating-conic-gradient(rgba(230, 236, 244, .06) 0% 25%, transparent 0% 50%) 50% / 12px 12px; }
.lib-media.is-stamp img { aspect-ratio: 1; object-fit: contain; max-height: 8rem; }
.lib-card-name { grid-area: name; display: grid; gap: .35rem; min-width: 0; }
.lib-card-name strong { font-size: .86rem; font-weight: 500; overflow-wrap: anywhere; line-height: 1.6; }
.lib-actions { gap: .15rem; }
.lib-card .lib-actions { grid-area: actions; }
.lib-card .lib-phone { grid-area: more; }

/* The phone at the corner of the picture: what a guest holding a phone upright sees. */
.phone-peek.is-corner {
    position: absolute;
    inset-inline-start: .45rem;
    bottom: .45rem;
    width: 36px;
    border-width: 2px;
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, .5);
}

.lib-phone > summary { cursor: pointer; font-size: .78rem; color: var(--ink-muted); list-style: none; }
.lib-phone > summary::-webkit-details-marker { display: none; }
.lib-phone > summary::before { content: "▸ "; }
.lib-phone[open] > summary::before { content: "▾ "; }
.lib-phone .lib-phone-row { margin-top: .6rem; }
.lib-phone .lib-phone-tools { flex: 1; }
.lib-phone .lib-phone-tools button { justify-self: start; }
.lib-phone input[type="file"] { width: 100%; max-width: 100%; font-size: .72rem; color: var(--ink-muted); }
.lib-phone label { display: grid; gap: .3rem; font-size: .76rem; color: var(--ink-muted); }

/* The rename and delete boxes open just under the icons, measured against the card (or the
   song's row) rather than the icon - anchored to the icon, the box ran out of the card's side and,
   on the last column, under the sidebar. */
.lib-card, .lib-row { position: relative; }
.lib-card .lib-pop, .lib-row .lib-pop { position: static; }
.lib-card .lib-pop .panel-confirm { top: auto; inset-inline: .7rem; width: auto; margin-top: .3rem; }
.lib-row .lib-pop .panel-confirm { top: auto; inset-inline-start: auto; inset-inline-end: .9rem; width: 16rem; margin-top: .3rem; }
.lib-pop .lib-name { display: flex; gap: .4rem; }
.admin .lib-pop button[type=submit].btn-danger {
    border: 1px solid rgba(255, 140, 140, .5);
    background: transparent;
    color: #ff9c9c;
    padding: .4rem .8rem;
    font-size: .8rem;
    line-height: 1.8;
}
.admin .lib-pop button[type=submit].btn-danger:hover { background: rgba(216, 90, 90, .2); color: #fff; }

/* Stamps are small tiles: the icons get their own line under the name instead of squeezing it. */
.lib-grid.is-small .lib-card { grid-template-columns: 1fr; grid-template-areas: "media" "name" "actions"; }
.lib-grid.is-small .lib-actions { justify-content: flex-start; }

.lib-pages { flex-wrap: wrap; }
.lib-page { min-width: 2rem; padding: .3rem .5rem; border-radius: 8px; text-align: center; text-decoration: none; }
.admin .lib-page { color: var(--ink-muted); }
.admin .lib-page:hover { background: rgba(230, 236, 244, .08); color: var(--ink); }
.lib-page.is-on { background: var(--brand); color: #fff; }
.lib-page-gap { color: var(--ink-muted); }

@media (max-width: 720px) {
    .lib-row { grid-template-columns: 1fr auto; }
    .lib-row audio { grid-column: 1 / -1; grid-row: 2; }
}

/* ---- a background on a phone held upright: the panel's and the editor's little phone */
.phone-peek {
    flex: none;
    display: block;
    width: 64px;
    aspect-ratio: 9 / 19.5;
    border: 3px solid #1d1a1f;
    border-radius: 12px;
    background-color: #2a2330;
    background-size: cover;
    background-repeat: no-repeat;
    box-shadow: 0 6px 16px rgba(20, 14, 24, .22);
}

.lib-phone-row,
.ed-phone-row {
    display: flex;
    align-items: flex-start;
    gap: .8rem;
}

.lib-phone-tools {
    display: grid;
    gap: .45rem;
    min-width: 0;
    font-size: .8rem;
}

.lib-phone-tools .panel-hint { margin: 0; }

.lib-focus,
.lib-portrait {
    display: grid;
    gap: .3rem;
}

.lib-focus input[type="range"],
.ed-phone-row input[type="range"] { width: 100%; }

.lib-portrait input[type="file"] { max-width: 100%; font-size: .75rem; }

.ed-phone-row { margin-top: .8rem; }
.ed-phone-row > div { flex: 1; min-width: 0; }
.ed-phone-label { display: grid; gap: .35rem; font-size: .85rem; }

.admin .lib-name input {
    flex: 1;
    min-width: 0;
    padding: .4rem .6rem;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface-2);
    color: var(--ink);
    font: inherit;
    font-size: .84rem;
}

.admin .panel-new input[type="file"] { padding: .3rem 0; border: 0; background: none; }

/* In the template studio: the default song can be heard and the default ground seen right
   where they are chosen, instead of in another tab. */
.tpl-audio { width: 100%; }

.tpl-scene-thumb {
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    border-radius: 9px;
}


/* ---------------------------------------------------------------- editor steps

   Four numbered tabs above the editor. Not a wizard: every one is always open, nothing is
   locked behind "next", and the card is one object shared by all four. */

.ed-steps {
    display: flex;
    gap: .4rem;
    margin: 0 0 var(--dc-step, 16px);
    overflow-x: auto;
    scrollbar-width: none;
}

.ed-step {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    flex: 0 0 auto;
    padding: .45rem .95rem .45rem .7rem;
    border: 1px solid color-mix(in oklab, currentColor 14%, transparent);
    border-radius: 999px;
    background: var(--dc-surface, #fff);
    color: inherit;
    font: inherit;
    font-size: .86rem;
    cursor: pointer;
}

.ed-step-no {
    display: grid;
    place-items: center;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    background: color-mix(in oklab, currentColor 8%, transparent);
    font-size: .76rem;
}

.ed-step.is-on {
    border-color: var(--dc-accent, #52796f);
    color: var(--dc-accent, #52796f);
    font-weight: 600;
}

.ed-step.is-on .ed-step-no { background: var(--dc-accent, #52796f); color: #fff; }

/* ---- steps two and three: a form beside the card */

.ed-stage {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 340px);
    gap: var(--dc-step, 16px);
    align-items: start;
}

.ed-sheet {
    display: grid;
    gap: .7rem;
    padding: var(--dc-step, 16px);
    border-radius: var(--dc-radius-sm, 10px);
    background: var(--dc-surface, #fff);
    box-shadow: var(--dc-shadow);
}

.ed-sheet h3 { margin: 0; font-size: 1rem; }
.ed-sheet label { display: block; font-size: .8rem; }

.ed-sheet input:not([type="radio"]):not([type="file"]):not([type="checkbox"]),
.ed-sheet textarea {
    display: block;
    width: 100%;
    margin-top: .25rem;
    padding: .45rem .55rem;
    border: 1px solid color-mix(in oklab, currentColor 18%, transparent);
    border-radius: var(--dc-radius-sm, 10px);
    font: inherit;
    font-size: .88rem;
    background: transparent;
    color: inherit;
}

.ed-sheet fieldset { border: none; padding: 0; margin: 0; }
.ed-sheet legend { font-size: .78rem; opacity: .7; padding: 0 0 .35rem; }

.ed-side-card { position: sticky; top: 1rem; }
.ed-side-card .card { max-width: none; }

/* When step three has two sheets, the second goes where the card would have been. */
.ed-stage:has(> .ed-sheet + .ed-sheet) { grid-template-columns: 1fr 1fr; }

/* ---- the map */

.ed-map-head { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin-top: .4rem; }
.ed-map-head strong { font-size: .84rem; margin-inline-end: auto; }

.ed-map {
    width: 100%;
    height: 340px;
    border-radius: var(--dc-radius-sm, 10px);
    overflow: hidden;
    background: #eef0ec;
}

/* The map's attribution is a licence condition, not decoration, so it is made readable rather
   than hidden: OpenStreetMap's data is free on the condition that it is credited. */
.ed-map .leaflet-control-attribution {
    font-size: .62rem;
    direction: ltr;
}

/* ---- the venue from a pasted link

   Sits under the map and works without it. The field is left-to-right because a URL is. */

.ed-link-pick {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
    gap: .5rem;
    margin-top: .6rem;
}

.ed-link-pick label { display: grid; gap: .25rem; min-width: 0; font-size: .8rem; }
.ed-link-pick input { font-size: .82rem; }

@media (max-width: 520px) {
    .ed-link-pick { grid-template-columns: 1fr; align-items: stretch; }
}

/* ---- song choices */

.ed-choices { display: grid; gap: .5rem; }

.ed-choice {
    display: grid !important;
    grid-template-columns: auto 1fr;
    align-items: center;
    gap: .35rem .6rem;
    padding: .6rem .75rem;
    border: 1px solid color-mix(in oklab, currentColor 12%, transparent);
    border-radius: var(--dc-radius-sm, 10px);
    cursor: pointer;
}

.ed-choice.is-on { border-color: var(--dc-accent, #52796f); background: color-mix(in oklab, var(--dc-accent, #52796f) 6%, transparent); }
.ed-choice audio, .ed-choice small { grid-column: 1 / -1; width: 100%; height: 36px; }
.ed-choice small { height: auto; opacity: .6; }

/* ---- background choices */

.ed-scenes { display: grid; grid-template-columns: repeat(auto-fill, minmax(118px, 1fr)); gap: .55rem; }

.ed-scene {
    display: grid;
    gap: .35rem;
    padding: .35rem;
    border: 2px solid transparent;
    border-radius: var(--dc-radius-sm, 10px);
    background: none;
    color: inherit;
    font: inherit;
    font-size: .78rem;
    cursor: pointer;
    text-align: center;
}

.ed-scene.is-on { border-color: var(--dc-accent, #52796f); }

.ed-scene-img {
    display: block;
    aspect-ratio: 4 / 3;
    border-radius: 7px;
    background: #f3ede4 center / cover no-repeat;
}

.ed-scene-img.is-plain { background: linear-gradient(160deg, #fbfaf7, #efe7db); }

/* ---- uploads: a label that looks like a button, with the real file input hidden inside */

.ed-upload {
    position: relative;
    display: inline-block !important;
    justify-self: start;
    padding: .45rem .9rem;
    border: 1px dashed color-mix(in oklab, currentColor 30%, transparent);
    border-radius: 999px;
    font-size: .82rem !important;
    cursor: pointer;
}

.ed-upload input[type="file"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; }

/* ---- step four: what the guest meets */

.ed-guest {
    display: grid;
    justify-items: center;
    gap: 1rem;
    min-height: 70vh;
    padding: clamp(24px, 6vw, 64px) 16px;
    border-radius: var(--dc-radius, 14px);
    background: linear-gradient(160deg, #fbfaf7, #efe7db) center / cover no-repeat;
}

.ed-guest-card { width: min(360px, 86vw); filter: drop-shadow(0 24px 50px rgba(40, 30, 25, .28)); }
.ed-guest-card .card { max-width: none; }
.ed-guest-audio { width: min(360px, 86vw); }

.ed-guest-place {
    margin: 0;
    padding: .45rem 1rem;
    border-radius: 999px;
    background: rgba(255, 255, 255, .85);
    font-size: .86rem;
}

@media (max-width: 860px) {
    .ed-stage,
    .ed-stage:has(> .ed-sheet + .ed-sheet) { grid-template-columns: 1fr; }
    .ed-side-card { position: static; max-width: 320px; margin-inline: auto; }
    .ed-map { height: 280px; }
}

/* ---- step five: the real guest page, in a frame */
.ed-preview {
    display: grid;
    gap: .6rem;
}

.ed-preview-frame {
    display: block;
    width: 100%;
    height: min(82vh, 860px);
    border: 0;
    border-radius: 18px;
    background: #16131a;
    box-shadow: 0 20px 50px rgba(30, 20, 25, .25);
}

.ed-preview-bar {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: .5rem;
    margin: 0;
    font-size: .9rem;
    color: var(--dc-ink-muted, #6b6560);
}

.ed-preview-empty {
    justify-items: center;
    padding: 3rem 1rem;
    border-radius: 18px;
    background: linear-gradient(180deg, #f7f3ec, #efe7db);
    text-align: center;
}

/* The guest page's own "not found", which has no site header around it. */
.gs-missing {
    max-width: 30rem;
    margin: 20vh auto;
    padding: 0 16px;
    text-align: center;
}

/* ---- "print this on the card" switches in the ceremony step */

.ed-field-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .6rem;
    margin: .4rem 0 .3rem;
    font-size: .82rem;
}

.ed-sheet textarea.ed-plain { margin-top: 0; }

.ed-switch {
    display: inline-flex !important;
    align-items: center;
    gap: .4rem;
    font-size: .76rem !important;
    cursor: pointer;
    user-select: none;
}

/* The real checkbox stays in the page for keyboards and screen readers, but as a 1px dot inside
   its own label. It used to be caught by the sheet's "every input is full width" rule and grew
   to the width of the window; absolutely positioned against the page and hanging off to the
   left, it gave the right-to-left page a sideways scroll and shoved everything across. */
.ed-switch { position: relative; }

.ed-switch input,
.ed-sheet .ed-switch input {
    position: absolute;
    inset-inline-start: 0;
    top: 0;
    width: 1px;
    height: 1px;
    margin: 0;
    padding: 0;
    opacity: 0;
}

.ed-switch-track {
    position: relative;
    width: 2.1rem;
    height: 1.2rem;
    border-radius: 999px;
    background: color-mix(in oklab, currentColor 18%, transparent);
    transition: background .2s ease;
}

.ed-switch-track::after {
    content: "";
    position: absolute;
    top: .15rem;
    inset-inline-start: .15rem;
    width: .9rem;
    height: .9rem;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .25);
    transition: inset-inline-start .2s ease;
}

.ed-switch input:checked + .ed-switch-track { background: var(--dc-accent, #52796f); }
.ed-switch input:checked + .ed-switch-track::after { inset-inline-start: 1.05rem; }
.ed-switch input:focus-visible + .ed-switch-track { outline: 2px solid var(--dc-accent, #52796f); outline-offset: 2px; }

/* ---- the date and time rows

   These overlapped because a grid column will not shrink below its content's minimum width,
   and a time input's minimum is wider than a third of a phone. Two things fix it: every box
   counts its own padding (border-box), and every cell is told it may be narrower than its
   content (min-width: 0). The time pair also stacks on a narrow screen rather than squeezing. */

.ed-grid2 > *,
.ed-grid3 > * { min-width: 0; }

.ed-content input,
.ed-content textarea,
.ed-content select,
.ed-sheet input,
.ed-sheet textarea,
.ed-sheet select {
    box-sizing: border-box;
    min-width: 0;
    max-width: 100%;
}

.ed-date-row label,
.ed-time-row label { font-size: .74rem; opacity: .85; }

.ed-time-row input[type="time"] { text-align: center; }

/* Browsers draw a spinner on number inputs that eats half of a narrow box. */
.ed-date-row input[type="number"] { -moz-appearance: textfield; appearance: textfield; text-align: center; }
.ed-date-row input[type="number"]::-webkit-inner-spin-button,
.ed-date-row input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }

.ed-bound { margin-bottom: var(--dc-step, 16px); }

@media (max-width: 420px) {
    .ed-time-row { grid-template-columns: 1fr; }
}

/* ---- phones

   The editor was laid out for a desk. On a phone: the step tabs scroll sideways instead of
   wrapping into a wall, the forms take the full width, and the card preview in the ceremony
   step drops below the form instead of squeezing beside it. */

@media (max-width: 600px) {
    .ed-steps { margin-inline: -8px; padding-inline: 8px; }
    .ed-step { padding: .4rem .75rem .4rem .55rem; font-size: .8rem; }
    .ed-step-no { width: 1.3rem; height: 1.3rem; }

    .ed-sheet { padding: 12px; }
    .ed-map { height: 240px; }
    .ed-scenes { grid-template-columns: repeat(2, 1fr); }
    .ed-guest { min-height: 60vh; padding: 20px 10px; border-radius: 0; margin-inline: -8px; }
}

/* ---- the envelope step: choices on one side, the real envelope opening on the other */

.ed-stage-envelope { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }

.ed-envelopes {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: .6rem;
}

.ed-envelope {
    display: grid;
    gap: .4rem;
    padding: .45rem;
    border: 2px solid transparent;
    border-radius: var(--dc-radius-sm, 10px);
    background: color-mix(in oklab, currentColor 3%, transparent);
    color: inherit;
    font: inherit;
    font-size: .8rem;
    text-align: center;
    cursor: pointer;
}

.ed-envelope.is-on {
    border-color: var(--dc-accent, #52796f);
    background: color-mix(in oklab, var(--dc-accent, #52796f) 7%, transparent);
}

/* Every envelope picture is a 3:2 canvas, so the classic's layers stack on top of each other
   exactly and the uploaded ones fill the same box. */
.ed-envelope-img {
    position: relative;
    display: block;
    aspect-ratio: 3 / 2;
}

.ed-envelope-img img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
}

/* Deliberately not sticky. A sticky box makes its own stacking context, which trapped the
   card's full-screen view inside this column - and the editor's sticky toolbar, sitting higher
   up the page, was then drawn on top of it. */
.ed-envelope-live {
    padding: 1rem;
    border-radius: var(--dc-radius-sm, 10px);
    background: linear-gradient(180deg, #f7f3ec, #efe7db);
}

@media (max-width: 860px) {
    .ed-stage-envelope { grid-template-columns: 1fr; }
    .ed-envelopes { grid-template-columns: repeat(2, 1fr); }
}

/* ---- filter chips and "show more" in the envelope step */

.ed-chips { display: flex; flex-wrap: wrap; gap: .4rem; }

.ed-chip {
    padding: .35rem .85rem;
    border: 1px solid color-mix(in oklab, currentColor 16%, transparent);
    border-radius: 999px;
    background: none;
    color: inherit;
    font: inherit;
    font-size: .78rem;
    cursor: pointer;
}

.ed-chip.is-on {
    border-color: var(--dc-accent, #52796f);
    background: color-mix(in oklab, var(--dc-accent, #52796f) 10%, transparent);
    font-weight: 600;
}

.ed-more { justify-self: start; }

/* ---- occasion ticks on an envelope in the panel */

.env-tags > summary { cursor: pointer; font-size: .8rem; color: var(--ink-muted); margin-bottom: .5rem; }
.env-tags form { display: grid; gap: .6rem; justify-items: start; }

.env-tag-grid { display: flex; flex-wrap: wrap; gap: .5rem .9rem; }

.env-tag {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    font-size: .8rem;
    cursor: pointer;
}

.env-tag input { width: auto; margin: 0; }

/* ---- writing on the back of the envelope

   The address side is now a layer of its own: the painted picture, and on top of it whatever the
   sender wrote and the stamp they chose. Both are placed in percentages of the picture, which is
   the only thing every envelope has in common. Sizes are in cqi so the handwriting grows with the
   envelope instead of staying the size of a phone's. */

/* The envelope picture itself - and only it. This used to say `.env-back-side > img`, which also
   caught the stamp sitting on top of the picture: the stamp was then 100% tall with the artwork
   centred inside it by object-fit, which is why it appeared halfway down the envelope instead of
   where it had been dragged. */
.env-back-paper {
    width: 100%;
    height: 100%;
    object-fit: contain;
    user-select: none;
    -webkit-user-drag: none;
}

.env-back-text {
    position: absolute;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: .35em;
    font-size: 3.1cqi;
    line-height: 1.85;
    color: #4a4038;
    text-align: center;
    pointer-events: none;
}

/* Each line sits on one of the printed rules, so they are spaced evenly rather than stacked. */
.env-back-text span { display: block; }

/* Width only: the height follows the stamp's own proportions, exactly as it does on the canvas
   where it was dragged. Stated rather than left to inherit, because one stray height rule here
   moves the stamp on every card on the site. */
.env-back-stamp {
    position: absolute;
    height: auto;
    object-fit: contain;
    pointer-events: none;
}

/* ---- measuring the back of an envelope, in the panel */

.env-back > summary { cursor: pointer; font-size: .8rem; color: var(--ink-muted); margin-bottom: .5rem; }

.env-back-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 18rem);
    gap: 1rem;
    align-items: start;
}

.env-back-grid form { display: grid; gap: .7rem; justify-items: start; }
.env-back-grid fieldset { border: 1px solid var(--line); border-radius: 10px; padding: .6rem .7rem; width: 100%; }
.env-back-grid legend { font-size: .76rem; color: var(--ink-muted); padding-inline: .3rem; }

.env-back-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: .4rem; }
.env-back-row label { display: grid; gap: .2rem; font-size: .72rem; color: var(--ink-muted); }

.admin .env-back-row input {
    box-sizing: border-box;
    width: 100%;
    min-width: 0;
    padding: .35rem .4rem;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface-2);
    color: var(--ink);
    font: inherit;
    font-size: .82rem;
    text-align: center;
}

.env-back-preview { position: relative; margin: 0; }
.env-back-preview img { width: 100%; border-radius: 10px; display: block; }
.env-back-preview figcaption { margin-top: .4rem; font-size: .72rem; color: var(--ink-muted); }

/* The two rectangles, drawn exactly where the renderer will put them. */
.env-box {
    position: absolute;
    display: grid;
    place-items: center;
    border: 2px dashed rgba(57, 135, 229, .9);
    border-radius: 4px;
    background: rgba(57, 135, 229, .12);
    font-size: .7rem;
    color: #0e131a;
}

.env-box.is-stamp { border-color: rgba(216, 122, 60, .95); background: rgba(216, 122, 60, .14); }

@media (max-width: 800px) {
    .env-back-grid { grid-template-columns: 1fr; }
}

/* ---- the back of the envelope, in the editor */

.ed-back-sheet input.ed-plain { margin-bottom: .4rem; }

.ed-stamps { display: flex; flex-wrap: wrap; gap: .5rem; }

.ed-stamp {
    display: grid;
    place-items: center;
    width: 4.2rem;
    height: 4.2rem;
    padding: .3rem;
    border: 2px solid transparent;
    border-radius: 10px;
    background: color-mix(in oklab, currentColor 5%, transparent);
    cursor: pointer;
}

.ed-stamp.is-on { border-color: var(--dc-accent, #52796f); }
.ed-stamp img { width: 100%; height: 100%; object-fit: contain; }
.ed-stamp-none { font-size: .72rem; opacity: .7; }

/* ---- the two little tabs inside the envelope step */

.ed-subtabs { display: flex; gap: .3rem; margin-bottom: .2rem; }

.ed-subtabs button {
    padding: .4rem .85rem;
    border: 0;
    border-bottom: 2px solid transparent;
    background: none;
    color: inherit;
    font: inherit;
    font-size: .88rem;
    opacity: .6;
    cursor: pointer;
}

.ed-subtabs button.is-on {
    opacity: 1;
    border-bottom-color: var(--dc-accent, #52796f);
    font-weight: 600;
}

.ed-back-sheet { display: grid; gap: .6rem; }

/* The envelope beside the form keeps its own column; the step never grows a third one. */
.ed-stage-envelope > .ed-sheet { min-width: 0; }

/* ---- arranging the back of the envelope

   A picture of the envelope's back with two grabbable boxes on it. Percentages all the way
   through, so what is dragged here is what a guest sees on their phone. */

.bk-canvas {
    display: grid;
    gap: .4rem;
    touch-action: none;
    /* The envelope is drawn at most 640px wide, and the writing's size is in cqi - a percentage
       of the container. A wider canvas here would size the handwriting from a wider container
       and the same number would come out bigger, so the two surfaces share the cap. */
    max-width: 640px;
    margin-inline: auto;
}
.bk-canvas.is-dragging { user-select: none; cursor: grabbing; }

/* The same 3:2 frame the envelope itself uses, with the picture fitted inside it exactly the
   same way. That is what makes "left: 68%" mean the same place here and on the real envelope -
   they were two different frames before, which is why the stamp landed in two different spots. */
.bk-sheet {
    position: relative;
    container-type: inline-size;
    aspect-ratio: 3 / 2;
    border-radius: 8px;
    overflow: hidden;
    background: #efe7db;
}

.bk-sheet > img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
    user-select: none;
    -webkit-user-drag: none;
}

.bk-item {
    position: absolute;
    cursor: grab;
    outline: 1px dashed transparent;
    outline-offset: 3px;
    user-select: none;
    -webkit-user-drag: none;
}

/* With a mouse, pressing on a picture starts the browser's own image drag - the ghost image, the
   no-drop cursor - and our pointer events never arrive, which is why the stamp would barely
   budge on a desktop while it moved fine under a finger. The picture is taken out of the way
   entirely: the box around it is what gets grabbed. */
.bk-item img {
    pointer-events: none;
    user-select: none;
    -webkit-user-drag: none;
}

.bk-item:hover,
.bk-item.is-selected { outline-color: color-mix(in oklab, var(--dc-accent, #52796f) 70%, transparent); }

.bk-text {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: .35em;
    line-height: 1.85;
    text-align: center;
}

.bk-stamp img { display: block; width: 100%; height: auto; }

/* The handle sits on the leading corner - in a right-to-left page that is the left one. */
.bk-handle {
    position: absolute;
    inset-inline-start: -9px;
    bottom: -9px;
    width: 18px;
    height: 18px;
    border: 2px solid #fff;
    border-radius: 50%;
    background: var(--dc-accent, #52796f);
    cursor: nwse-resize;
    opacity: 0;
    transition: opacity .15s ease;
}

.bk-item:hover .bk-handle,
.bk-item.is-selected .bk-handle { opacity: 1; }

/* ---- ink colours for the writing */

.ed-inks { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }

.ed-ink {
    width: 1.6rem;
    height: 1.6rem;
    border: 2px solid transparent;
    border-radius: 50%;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .15);
    cursor: pointer;
}

.ed-ink.is-on { border-color: var(--dc-accent, #52796f); }

/* ================================================================ sending a card */

/* ------------------------------------------------ my cards: sent state */

.mycard-preview { position: relative; }

.mycard-badge {
    position: absolute;
    top: 10px;
    inset-inline-start: 10px;
    padding: 3px 10px;
    border-radius: 999px;
    background: rgba(30, 40, 51, .72);
    color: #fff;
    font-size: .72rem;
    font-weight: 600;
    backdrop-filter: blur(6px);
}

.mycard-badge.is-live {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: #1f7a55;
}

.mycard-badge.is-live::before {
    content: "";
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #9ef0c6;
    box-shadow: 0 0 0 0 rgba(158, 240, 198, .7);
    animation: dc-live 2.2s ease-out infinite;
}

@keyframes dc-live {
    70% { box-shadow: 0 0 0 7px rgba(158, 240, 198, 0); }
    100% { box-shadow: 0 0 0 0 rgba(158, 240, 198, 0); }
}

.mycard-stats {
    display: flex;
    gap: 6px;
    text-decoration: none;
    color: var(--dc-ink);
}

.mycard-stats span {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 9px;
    border-radius: 999px;
    background: var(--dc-ground);
    font-size: .78rem;
    font-variant-numeric: tabular-nums;
}

.mycard-stats svg { width: 14px; height: 14px; color: var(--dc-muted); }
.mycard-stats .is-yes { background: #e8f6ef; color: #1f6b4b; }
.mycard-stats .is-yes svg { color: #1f7a55; }
.mycard-stats .is-no { background: #f7eeee; color: #8a3b3b; }
.mycard-stats .is-no svg { color: #a8342f; }
.mycard-stats:hover span { box-shadow: inset 0 0 0 1px var(--dc-line); }

.mycard-publish { display: flex; flex: 1.4; margin: 0; }

.mycard-actions .mycard-publish button[type=submit] {
    flex: 1;
    padding: .4rem .6rem;
    font-size: .82rem;
}

.mycard.is-live { box-shadow: 0 0 0 1.5px #bfe6d3, var(--dc-shadow); }

/* ------------------------------------------------ share page */

.share-hero {
    --share-accent: var(--dc-brand);
    display: grid;
    grid-template-columns: 1.1fr 1fr;
    align-items: center;
    gap: 32px;
    margin-bottom: 24px;
    padding: 34px 36px;
    border-radius: 26px;
    background:
        radial-gradient(120% 140% at 100% 0%, color-mix(in srgb, var(--share-accent) 20%, transparent), transparent 60%),
        linear-gradient(160deg, color-mix(in srgb, var(--share-accent) 9%, #fff), #fff 70%);
    box-shadow: var(--dc-shadow);
    overflow: hidden;
}

.share-hero-off { grid-template-columns: 1fr; text-align: center; }
.share-hero-off form { margin-top: 18px; }

.share-hero h1 {
    margin: 4px 0 8px;
    font-family: var(--dc-display);
    font-weight: 400;
    font-size: clamp(28px, 4.6vw, 44px);
    line-height: 1.35;
    color: color-mix(in srgb, var(--share-accent) 55%, var(--dc-ink));
}

.share-kicker {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    padding: 5px 12px;
    border-radius: 999px;
    background: #e8f6ef;
    color: #1f6b4b;
    font-size: .85rem;
    font-weight: 600;
}

.share-live-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #1f7a55;
    animation: dc-live 2.2s ease-out infinite;
    box-shadow: 0 0 0 0 rgba(31, 122, 85, .5);
}

.share-sub { margin: 0 0 18px; color: var(--dc-muted); line-height: 1.9; }

.share-go { font-size: 1rem; padding: 14px 30px; border-radius: 14px; }

.share-stats {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    color: var(--dc-ink);
    text-decoration: none;
}

.share-stats span {
    padding: 8px 14px;
    border-radius: 14px;
    background: rgba(255, 255, 255, .85);
    box-shadow: inset 0 0 0 1px var(--dc-line);
    font-size: .88rem;
}

.share-stats b { font-size: 1.15rem; margin-inline-end: 4px; font-variant-numeric: tabular-nums; }
.share-stats .is-yes b { color: #1f7a55; }
.share-stats .is-no b { color: #a8342f; }
.share-stats svg { width: 18px; height: 18px; color: var(--dc-muted); transition: transform .2s ease; }
.share-stats:hover svg { transform: translateX(-3px); }

/* The link as a chat would show it: a bubble with the picture, the title and the address. */
.share-bubble {
    position: relative;
    margin: 0;
    padding: 18px;
    border-radius: 22px;
    background: #cfe1d4 url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40'%3E%3Cpath d='M20 8c3 0 5 2 5 5-3 0-5-2-5-5zm-12 20c2 0 4 1 4 4-2 0-4-2-4-4zm22 2c2 0 3 2 3 3-2 0-3-1-3-3z' fill='%23b8cfbe'/%3E%3C/svg%3E");
    transform: rotate(-1.2deg);
}

.share-bubble-card {
    position: relative;
    overflow: hidden;
    border-radius: 16px 16px 16px 4px;
    background: #effdde;
    box-shadow: 0 1px 1px rgba(0, 0, 0, .12), 0 10px 30px rgba(30, 40, 51, .18);
}

.share-bubble-card img { display: block; width: 100%; height: auto; aspect-ratio: 1200 / 630; object-fit: cover; background: #ddd; }

.share-bubble-meta {
    display: grid;
    gap: 2px;
    padding: 10px 14px 12px;
    border-inline-start: 3px solid #4fae4e;
    margin: 10px 12px 12px;
}

.share-bubble-meta strong { font-size: .92rem; color: #2f7d3c; }
.share-bubble-meta span { font-size: .82rem; color: #333; line-height: 1.7; }
.share-bubble-meta em { font-style: normal; font-size: .75rem; color: #6d8a72; text-align: end; }

.share-bubble figcaption {
    margin-top: 10px;
    font-size: .78rem;
    text-align: center;
    color: #50685a;
}

.share-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
}

.share-panel {
    padding: 24px;
    border-radius: 20px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
}

.share-panel h2 { margin: 0 0 14px; font-size: 1.05rem; }

.share-link { display: flex; gap: 8px; }

.share-link input {
    flex: 1;
    min-width: 0;
    height: 48px;
    padding: 0 14px;
    border: 0;
    border-radius: 12px;
    background: var(--dc-ground);
    box-shadow: inset 0 0 0 1px var(--dc-line);
    color: var(--dc-ink);
    font: inherit;
    font-size: .95rem;
    text-align: left;
}

.share-link button,
.share-link a {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0 18px;
    border-radius: 12px;
    white-space: nowrap;
}

.share-link button svg { width: 18px; height: 18px; }
.share-link button.is-done { background: #1f7a55; }

.share-message { display: grid; gap: 6px; margin-top: 18px; }
.share-message > span { font-size: .88rem; color: var(--dc-muted); }

.share-message textarea {
    box-sizing: border-box;
    width: 100%;
    padding: 12px 14px;
    border: 0;
    border-radius: 12px;
    background: var(--dc-ground);
    box-shadow: inset 0 0 0 1px var(--dc-line);
    color: var(--dc-ink);
    font: inherit;
    font-size: .92rem;
    line-height: 1.9;
    resize: vertical;
}

.share-message textarea:focus,
.share-link input:focus { outline: 0; box-shadow: inset 0 0 0 2px var(--dc-brand); }
.share-message small { color: var(--dc-muted); font-size: .76rem; }

.share-apps {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 14px 8px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.share-app {
    display: grid;
    justify-items: center;
    gap: 7px;
    width: 100%;
    padding: 6px 0;
    border: 0;
    background: none;
    color: var(--dc-ink);
    font: inherit;
    font-size: .8rem;
    text-decoration: none;
    cursor: pointer;
}

.share-app-logo {
    display: grid;
    place-items: center;
    width: 58px;
    height: 58px;
    border-radius: 18px;
    background: #fff;
    box-shadow: 0 0 0 1px var(--dc-line), 0 6px 16px rgba(30, 40, 51, .08);
    transition: transform .2s ease, box-shadow .2s ease;
}

.share-app-logo img { width: 36px; height: 36px; object-fit: contain; }
.share-app-logo svg { width: 28px; height: 28px; color: var(--dc-brand); }

.share-app:hover .share-app-logo { transform: translateY(-3px); box-shadow: 0 0 0 1px var(--dc-line), 0 12px 24px rgba(30, 40, 51, .14); }
.share-app:active .share-app-logo { transform: scale(.94); }

.share-note { margin: 16px 0 0; font-size: .76rem; color: var(--dc-muted); line-height: 1.8; }

.share-qr-panel { text-align: center; }
.share-qr-panel p { margin: 0 0 14px; color: var(--dc-muted); font-size: .88rem; line-height: 1.8; }

.share-qr {
    display: grid;
    place-items: center;
    width: max-content;
    margin-inline: auto;
    min-width: 240px;
    min-height: 240px;
    margin-bottom: 14px;
    padding: 14px;
    border-radius: 22px;
    background: #fff;
    box-shadow: 0 0 0 1px var(--dc-line), 0 14px 34px rgba(30, 40, 51, .1);
}

.share-qr canvas { display: block; }

.share-stop { align-self: start; }
.share-stop summary { cursor: pointer; color: #8a8a8a; font-size: .9rem; }
.share-stop summary:hover,
.share-stop details[open] summary { color: #a8342f; }
.share-stop p { color: var(--dc-muted); font-size: .85rem; line-height: 1.8; }

.share-toast {
    position: fixed;
    left: 50%;
    bottom: 28px;
    z-index: 50;
    max-width: calc(100vw - 32px);
    padding: 12px 20px;
    border-radius: 14px;
    background: #1e2833;
    color: #fff;
    font-size: .9rem;
    box-shadow: 0 14px 40px rgba(0, 0, 0, .25);
    opacity: 0;
    transform: translate(-50%, 16px);
    pointer-events: none;
    transition: opacity .25s ease, transform .35s cubic-bezier(.2, .8, .2, 1);
}

.share-toast.is-on { opacity: 1; transform: translate(-50%, 0); }

@media (max-width: 860px) {
    .share-hero { grid-template-columns: 1fr; padding: 24px 20px; gap: 22px; }
    .share-grid { grid-template-columns: 1fr; }
    .share-bubble { transform: none; }
}

@media (max-width: 420px) {
    .share-link { flex-wrap: wrap; }
    .share-link input { flex-basis: 100%; }
    .share-link button, .share-link a { flex: 1; justify-content: center; height: 44px; }
    .share-apps { gap: 12px 4px; }
    .share-app-logo { width: 52px; height: 52px; border-radius: 16px; }
}

/* ------------------------------------------------ guests' answers */

.rsvp-summary {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 24px;
    margin-bottom: 22px;
    padding: 22px 26px;
    border-radius: 22px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
}

/* The share of "yes" as a ring: a conic gradient needs no chart library and no script. */
.rsvp-ring {
    --rsvp-share: 0%;
    position: relative;
    display: grid;
    place-content: center;
    justify-items: center;
    width: 118px;
    height: 118px;
    border-radius: 50%;
    background: conic-gradient(#1f7a55 var(--rsvp-share), #efe7e7 0);
}

.rsvp-ring::before {
    content: "";
    position: absolute;
    inset: 12px;
    border-radius: 50%;
    background: var(--dc-surface);
}

.rsvp-ring b, .rsvp-ring span { position: relative; }
.rsvp-ring b { font-size: 1.9rem; line-height: 1.1; color: #1f7a55; }
.rsvp-ring span { font-size: .78rem; color: var(--dc-muted); }

.rsvp-numbers { display: flex; gap: 12px; margin: 0; }

.rsvp-numbers div {
    min-width: 92px;
    padding: 10px 14px;
    border-radius: 14px;
    background: var(--dc-ground);
}

.rsvp-numbers dt { font-size: .78rem; color: var(--dc-muted); }
.rsvp-numbers dd { margin: 2px 0 0; font-size: 1.35rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.rsvp-numbers .is-yes dd { color: #1f7a55; }
.rsvp-numbers .is-no dd { color: #a8342f; }

.rsvp-tools { display: flex; flex-wrap: wrap; gap: 8px; margin-inline-start: auto; }

.rsvp-filter {
    display: flex;
    gap: 6px;
    margin-bottom: 14px;
    padding-bottom: 2px;
    overflow-x: auto;
    scrollbar-width: none;
}

.rsvp-filter::-webkit-scrollbar { display: none; }
.rsvp-filter a { flex: none; white-space: nowrap; }

.rsvp-filter a {
    padding: 7px 14px;
    border-radius: 999px;
    background: var(--dc-surface);
    box-shadow: inset 0 0 0 1px var(--dc-line);
    color: var(--dc-ink);
    font-size: .86rem;
    text-decoration: none;
}

.rsvp-filter a[aria-current="page"] { background: var(--dc-ink); color: #fff; box-shadow: none; }

.rsvp-list {
    display: grid;
    gap: 8px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.rsvp-list li {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    border-radius: 16px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
}

.rsvp-avatar {
    display: grid;
    place-items: center;
    flex: none;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    font-weight: 700;
}

.rsvp-list .is-yes .rsvp-avatar { background: #e8f6ef; color: #1f7a55; }
.rsvp-list .is-no .rsvp-avatar { background: #f7eeee; color: #a8342f; }

.rsvp-who { display: grid; flex: 1; min-width: 0; }
.rsvp-who strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rsvp-who small { color: var(--dc-muted); font-size: .76rem; }

.rsvp-chip {
    padding: 4px 11px;
    border-radius: 999px;
    font-size: .78rem;
    font-weight: 600;
}

.rsvp-list .is-yes .rsvp-chip { background: #1f7a55; color: #fff; }
.rsvp-list .is-no .rsvp-chip { background: #f1e5e5; color: #8a3b3b; }

.rsvp-remove { position: relative; }

.rsvp-remove > summary {
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    color: #9aa3ab;
    cursor: pointer;
    list-style: none;
}

.rsvp-remove > summary::-webkit-details-marker { display: none; }
.rsvp-remove > summary:hover { background: #f7eeee; color: #a8342f; }
.rsvp-remove svg { width: 16px; height: 16px; }

.rsvp-remove form {
    position: absolute;
    top: 34px;
    inset-inline-end: 0;
    z-index: 3;
    padding: 8px;
    border-radius: 12px;
    background: #fff;
    box-shadow: var(--dc-shadow-lift);
    white-space: nowrap;
}

@media (max-width: 560px) {
    .rsvp-summary { justify-content: center; text-align: center; }
    .rsvp-tools { margin: 0; justify-content: center; }
}

/* ------------------------------------------------ share page: more */

.share-more p { margin: 0 0 14px; color: var(--dc-muted); font-size: .88rem; line-height: 1.9; }
.share-more-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.share-more-row form { margin: 0; }

/* ------------------------------------------------ guest list */

.guests-warn {
    margin: 0 0 18px;
    padding: 12px 16px;
    border-radius: 14px;
    background: #fff6e5;
    color: #7a5310;
    font-size: .9rem;
}

.guests-summary {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 10px;
    margin-bottom: 18px;
}

.guests-summary div {
    display: grid;
    justify-items: center;
    gap: 2px;
    padding: 14px 8px;
    border-radius: 16px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
    text-align: center;
}

.guests-summary b { font-size: 1.5rem; line-height: 1.2; font-variant-numeric: tabular-nums; }
.guests-summary span { font-size: .78rem; color: var(--dc-muted); }
.guests-summary .is-yes b { color: #1f7a55; }
.guests-summary .is-no b { color: #a8342f; }
.guests-summary .is-wait b { color: #b07a12; }

.guests-add {
    margin-bottom: 18px;
    padding: 16px 20px;
    border-radius: 18px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
}

.guests-add > summary {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: var(--dc-brand);
    font-weight: 600;
    cursor: pointer;
    list-style: none;
}

.guests-add > summary::-webkit-details-marker { display: none; }
.guests-add > summary svg { width: 18px; height: 18px; }
.guests-add form { margin-top: 14px; }
.guests-add .share-message { margin-top: 0; }

.guests-add-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-top: 12px;
}

.guests-add-row label { display: inline-flex; align-items: center; gap: 8px; font-size: .9rem; }

.guests-add-row select,
.guest-edit-box select,
.guest-edit-box input {
    height: 40px;
    padding: 0 10px;
    border: 0;
    border-radius: 10px;
    background: var(--dc-ground);
    box-shadow: inset 0 0 0 1px var(--dc-line);
    color: var(--dc-ink);
    font: inherit;
}

.guests-list {
    display: grid;
    gap: 8px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.guests-list > li {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 14px;
    padding: 12px 16px;
    border-radius: 16px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
    border-inline-start: 4px solid #d9dee3;
}

.guests-list > li.is-yes { border-inline-start-color: #1f7a55; }
.guests-list > li.is-no { border-inline-start-color: #c9716d; }
.guests-list > li.is-opened { border-inline-start-color: #e0b04a; }

.guest-main { display: grid; flex: 1; min-width: 140px; }
.guest-main strong { font-size: .98rem; }
.guest-main small { color: var(--dc-muted); font-size: .76rem; }

.guest-chip {
    padding: 4px 11px;
    border-radius: 999px;
    background: #eef1f4;
    color: #5b6670;
    font-size: .76rem;
    font-weight: 600;
    white-space: nowrap;
}

.is-yes > .guest-chip { background: #1f7a55; color: #fff; }
.is-no > .guest-chip { background: #f1e5e5; color: #8a3b3b; }
.is-opened > .guest-chip { background: #fff3d6; color: #8a6412; }

.guest-send { display: flex; gap: 6px; }

.guest-send a,
.guest-send button {
    position: relative;
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    padding: 0;
    border: 0;
    border-radius: 12px;
    background: #fff;
    box-shadow: inset 0 0 0 1px var(--dc-line);
    color: var(--dc-brand);
    cursor: pointer;
    transition: transform .15s ease, box-shadow .15s ease;
}

.guest-send a:hover,
.guest-send button:hover { transform: translateY(-2px); box-shadow: inset 0 0 0 1px var(--dc-line), 0 6px 14px rgba(30, 40, 51, .1); }
.guest-send img { width: 22px; height: 22px; }
.guest-send svg { width: 20px; height: 20px; }
.guest-send button.is-done { background: #1f7a55; color: #fff; }

.guest-send button[data-tip]::after {
    content: attr(data-tip);
    position: absolute;
    bottom: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%);
    padding: 3px 8px;
    border-radius: 8px;
    background: #1e2833;
    color: #fff;
    font-size: .72rem;
    white-space: nowrap;
}

.guest-edit { position: relative; }

.guest-edit > summary {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    color: #8a939c;
    cursor: pointer;
    list-style: none;
}

.guest-edit > summary::-webkit-details-marker { display: none; }
.guest-edit > summary:hover { background: var(--dc-ground); }
.guest-edit svg { width: 20px; height: 20px; }

.guest-edit-box {
    position: absolute;
    top: 40px;
    inset-inline-end: 0;
    z-index: 5;
    display: grid;
    gap: 10px;
    width: min(320px, 80vw);
    padding: 14px;
    border-radius: 14px;
    background: #fff;
    box-shadow: var(--dc-shadow-lift);
}

.guest-edit-box form { display: flex; flex-wrap: wrap; gap: 8px; margin: 0; }
.guest-edit-box input { flex: 1; min-width: 0; }
.guest-edit-box a { font-size: .85rem; }

@media (max-width: 720px) {
    .guests-summary { grid-template-columns: repeat(3, 1fr); }
    .guests-summary div:nth-child(n + 4) { grid-column: span 1; }
}

@media (max-width: 480px) {
    .guest-send { order: 3; width: 100%; }
}

/* ------------------------------------------------ wishes moderation */

.wishes-switch {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 22px;
    padding: 16px 20px;
    border-radius: 18px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
}

.wishes-switch p { margin: 0; color: var(--dc-muted); font-size: .9rem; }
.wishes-switch form { margin: 0; }
.wishes-on, .wishes-off { padding: 3px 10px; border-radius: 999px; font-size: .78rem; font-weight: 700; margin-inline-end: 6px; }
.wishes-on { background: #e8f6ef; color: #1f6b4b; }
.wishes-off { background: #eef1f4; color: #5b6670; }

.wishes-group { margin-bottom: 26px; }
.wishes-group h2 { margin: 0 0 12px; font-size: 1.05rem; }
.wishes-group h2 small { color: var(--dc-muted); font-weight: 400; }

.wishes-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 14px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.wishes-list li {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 16px;
    border-radius: 4px 16px 6px 14px;
    background: #fffdf6;
    box-shadow: 0 1px 1px rgba(0, 0, 0, .05), 0 10px 22px rgba(30, 40, 51, .08);
}

.wishes-list li.is-pending { background: #fff7e3; }
.wishes-list li.is-hidden { opacity: .6; }
.wishes-list p { margin: 0; line-height: 1.9; white-space: pre-line; overflow-wrap: anywhere; }

.wish-foot { display: grid; gap: 10px; margin-top: auto; }
.wish-foot > span { font-size: .85rem; font-weight: 600; color: var(--dc-muted); }
.wish-foot small { font-weight: 400; }
.wish-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.wish-actions form { margin: 0; }

.wish-actions .btn-primary,
.wish-actions .btn-quiet,
.wish-actions button[type=submit] { padding: 6px 12px; font-size: .8rem; }

/* =====================================================================================
   Front page - the shop window
   ===================================================================================== */

/* minmax(0, 1fr): a shelf's row of cards is far wider than the screen, and a plain grid column
   would grow to fit it and push the whole page off the side of a phone. */
.home { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(28px, 5vw, 56px); }
.home > * { min-width: 0; }

/* ------------------------------------------------ the promise */

.home-hero {
    position: relative;
    display: grid;
    grid-template-columns: 1fr 1.05fr;
    align-items: center;
    gap: clamp(20px, 4vw, 56px);
    min-height: min(560px, 78vh);
}

/* Full-bleed wash behind the promise: blush on one side, the brand's cool teal on the other,
   fading to the page before the shelves begin. */
.home-hero-glow {
    position: absolute;
    z-index: -1;
    top: calc(clamp(28px, 5vw, 48px) * -1 - 10px);
    bottom: -60px;
    left: 50%;
    width: 100vw;
    transform: translateX(-50%);
    background:
        radial-gradient(40% 55% at 22% 42%, rgba(232, 190, 196, .42), transparent 70%),
        radial-gradient(38% 50% at 80% 30%, rgba(47, 93, 112, .1), transparent 70%),
        radial-gradient(30% 40% at 60% 85%, rgba(214, 180, 120, .18), transparent 70%),
        linear-gradient(180deg, #fbf7f4 0%, var(--dc-ground) 100%);
    pointer-events: none;
}

/* The tea-and-roses table from the first front page, kept underneath. Its props sit at the two
   edges and its middle is clean white, so the headline and the fan of cards land on the empty
   part. Its own layer, so it can fade out at its own bottom edge: the picture is a wide strip,
   shorter than the hero, and ending it on a hard line halfway down looked like a mistake.
   Multiply lets the washes above show through its white instead of being painted over. */
.home-hero-glow::before {
    content: "";
    position: absolute;
    inset: 0 0 auto;
    aspect-ratio: 12 / 5;
    background: url('card-art/hero-backdrop.webp') center top / 100% auto no-repeat;
    mix-blend-mode: multiply;
    -webkit-mask-image: linear-gradient(to bottom, #000 60%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 60%, transparent 100%);
}

/* No phone override on purpose: enlarging the strip on a narrow screen crops the props off its
   two edges and leaves only the empty middle. At full width they stay whole, small, in the two
   top corners above the headline. */

.home-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 14px;
    padding: 6px 14px;
    border-radius: 999px;
    background: rgba(255, 255, 255, .8);
    box-shadow: 0 0 0 1px var(--dc-line);
    color: var(--dc-brand-ink);
    font-size: .85rem;
    font-weight: 600;
}

.home-eyebrow-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #d9869a;
    box-shadow: 0 0 0 4px rgba(217, 134, 154, .2);
}

.home-hero .home-title {
    margin: 0;
    font-family: var(--dc-display);
    font-weight: 400;
    font-size: clamp(40px, 7vw, 76px);
    line-height: 1.15;
    color: var(--dc-ink);
}

.home-hero .home-title em {
    font-style: normal;
    background: linear-gradient(100deg, #b0566f 0%, #d49a5c 55%, #2f5d70 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.home-lead {
    max-width: 30em;
    margin: 16px 0 26px;
    color: var(--dc-muted);
    font-size: clamp(15px, 1.6vw, 18px);
    line-height: 1.9;
}

.home-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }

.home-go {
    padding: 14px 32px;
    border-radius: 14px;
    font-size: 1.05rem;
    font-weight: 700;
    box-shadow: 0 10px 26px rgba(47, 93, 112, .28);
}

.home-play {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 8px 18px 8px 8px;
    border-radius: 999px;
    background: #fff;
    box-shadow: 0 0 0 1px var(--dc-line), 0 8px 20px rgba(30, 40, 51, .08);
    color: var(--dc-ink);
    font-weight: 600;
    text-decoration: none;
    transition: transform .2s ease, box-shadow .2s ease;
}

.home-play:hover { transform: translateY(-2px); box-shadow: 0 0 0 1px var(--dc-line), 0 14px 28px rgba(30, 40, 51, .14); }

.home-play-icon {
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    background: linear-gradient(135deg, #b0566f, #d49a5c);
    color: #fff;
    animation: home-pulse 2.4s ease-out infinite;
}

.home-play-icon svg { width: 18px; height: 18px; margin-inline-start: 2px; }

@keyframes home-pulse {
    0% { box-shadow: 0 0 0 0 rgba(176, 86, 111, .45); }
    70%, 100% { box-shadow: 0 0 0 12px rgba(176, 86, 111, 0); }
}

.home-facts {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 18px;
    margin: 26px 0 0;
    padding: 0;
    list-style: none;
    color: var(--dc-muted);
    font-size: .9rem;
}

.home-facts li { display: inline-flex; align-items: center; gap: 6px; }
.home-facts li::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: #d49a5c; }
.home-facts b { color: var(--dc-ink); font-size: 1.05rem; }

/* The fan: real cards, spread like a hand of invitations. One lifts out at a time. */
.home-fan {
    position: relative;
    height: clamp(340px, 42vw, 500px);
    --w: clamp(150px, 17vw, 230px);
}

.home-fan-card {
    --a: calc((var(--i) - (var(--n) - 1) / 2) * 9deg);
    position: absolute;
    left: 50%;
    bottom: 4%;
    width: var(--w);
    margin-left: calc(var(--w) / -2);
    transform-origin: 50% 170%;
    transform: rotate(var(--a));
    z-index: var(--z, 5);
    filter: drop-shadow(0 14px 26px rgba(60, 40, 50, .22));
    animation: home-lift 12.5s ease-in-out infinite;
    animation-delay: calc(var(--i) * 2.5s);
}

.home-fan-card .card { max-width: none; border-radius: 6px; box-shadow: none; }
.home-fan-card .card-el-message,
.home-fan-card .card-el-poem,
.home-fan-card .card-el-address { display: none; }

@keyframes home-lift {
    0%, 22%, 100% { transform: rotate(var(--a)) translateY(0); }
    8%, 14% { transform: rotate(calc(var(--a) * .6)) translateY(-14%) scale(1.05); z-index: 20; }
}

.home-fan:hover .home-fan-card { animation-play-state: paused; }

/* ------------------------------------------------ occasions as a row of chips */

.home-chips {
    display: flex;
    gap: 8px;
    margin-top: -12px;
    padding: 4px 2px 8px;
    overflow-x: auto;
    scrollbar-width: none;
}

.home-chips::-webkit-scrollbar { display: none; }

.home-chips a {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 16px;
    border-radius: 999px;
    background: var(--dc-surface);
    box-shadow: 0 0 0 1px var(--dc-line), 0 4px 12px rgba(30, 40, 51, .05);
    color: var(--dc-ink);
    font-size: .9rem;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    transition: transform .15s ease, box-shadow .15s ease;
}

.home-chips a:hover { transform: translateY(-2px); box-shadow: 0 0 0 1px color-mix(in srgb, var(--dc-brand) 35%, var(--dc-line)), 0 8px 18px rgba(30, 40, 51, .1); }
.home-chip-icon { display: grid; place-items: center; width: 22px; height: 22px; color: var(--dc-brand); }
.home-chip-icon svg { width: 100%; height: 100%; }

/* ------------------------------------------------ the names bar */

.home-names {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 16px 28px;
    padding: 22px 26px;
    border-radius: 24px;
    background:
        radial-gradient(60% 120% at 0% 50%, rgba(212, 154, 92, .16), transparent 60%),
        linear-gradient(135deg, #fff 0%, #fdf6f2 100%);
    box-shadow: 0 0 0 1px #f0e2da, 0 14px 34px rgba(120, 70, 60, .08);
}

.home-names h2 { margin: 0; font-size: clamp(17px, 2vw, 21px); }
.home-names p { margin: 4px 0 0; color: var(--dc-muted); font-size: .88rem; }

.home-names-fields { display: flex; align-items: center; gap: 10px; }
.home-names-fields span { font-family: var(--dc-nastaliq); font-size: 1.4rem; color: #b0566f; }

.home-names-fields input {
    width: clamp(110px, 16vw, 170px);
    height: 50px;
    padding: 0 16px;
    border: 0;
    border-radius: 14px;
    background: #fff;
    box-shadow: inset 0 0 0 1.5px #ead8cf;
    color: var(--dc-ink);
    font: inherit;
    font-size: 17px;
    font-weight: 600;
    text-align: center;
    transition: box-shadow .2s ease;
}

.home-names-fields input:focus { outline: 0; box-shadow: inset 0 0 0 2px #b0566f, 0 0 0 4px rgba(176, 86, 111, .12); }
.home-names-fields input::placeholder { color: #c9b3aa; font-weight: 400; }

/* The names landing on every card: a brief warm glow on each one. */
.home.names-flash .card-name,
.home.names-flash .card-el-name1,
.home.names-flash .card-el-name2 { animation: home-name-in .7s ease; }

@keyframes home-name-in {
    0% { opacity: .2; filter: blur(3px); }
    100% { opacity: 1; filter: none; }
}

/* ------------------------------------------------ the shelves */

.shelf { display: grid; gap: 14px; content-visibility: auto; contain-intrinsic-size: auto 480px; }

.shelf-head { display: flex; align-items: center; gap: 12px; }

.shelf-icon {
    display: grid;
    place-items: center;
    flex: none;
    width: 44px;
    height: 44px;
    border-radius: 14px;
    background: var(--dc-brand-soft);
    color: var(--dc-brand);
}

.shelf-icon svg { width: 24px; height: 24px; }
.shelf-title { flex: 1; min-width: 0; }
.shelf-title h2 { margin: 0; font-size: clamp(19px, 2.4vw, 24px); }
.shelf-title p { margin: 2px 0 0; color: var(--dc-muted); font-size: .85rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.shelf-nav { display: flex; align-items: center; gap: 6px; }

.shelf-arrow {
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--dc-surface);
    box-shadow: 0 0 0 1px var(--dc-line);
    color: var(--dc-ink);
    cursor: pointer;
}

.shelf-arrow[hidden] { display: none; }
.shelf-arrow svg { width: 18px; height: 18px; }

/* A finger swipes the row; arrows are for a mouse. */
@media (hover: none), (max-width: 600px) {
    .shelf-arrow { display: none; }
}
.shelf-arrow:disabled { opacity: .35; cursor: default; }
.shelf-arrow:not(:disabled):hover { box-shadow: 0 0 0 1px var(--dc-brand); color: var(--dc-brand); }

.shelf-more {
    padding: 8px 14px;
    border-radius: 999px;
    background: var(--dc-brand-soft);
    color: var(--dc-brand-ink);
    font-size: .85rem;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
}

.shelf-more:hover { background: var(--dc-brand); color: #fff; }

/* The row itself: native sideways scrolling that snaps to a card, so a thumb flick feels like
   turning a page. It runs to the screen's edge on a phone, so the next card peeks in. */
.shelf-track {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: clamp(170px, 21%, 236px);
    gap: 14px;
    margin: 0;
    padding: 6px 2px 14px;
    list-style: none;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: 2px;
    scrollbar-width: none;
}

.shelf-track::-webkit-scrollbar { display: none; }

.shelf-track > li { position: relative; scroll-snap-align: start; }

.shelf-tile { height: 100%; padding: 12px; gap: 8px; box-sizing: border-box; text-decoration: none; }
.shelf-tile h3 { font-size: 15px; }

.shelf-tile .tile-card { transition: transform .45s cubic-bezier(.2, .8, .2, 1); }
.shelf-tile:hover .tile-card,
.shelf-tile:focus-visible .tile-card { transform: translateX(-50%) translateY(-9%) rotate(-2deg); }

.shelf-tags { display: flex; flex-wrap: wrap; gap: 4px; margin: 0; }

.shelf-tags span {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--dc-ground);
    color: var(--dc-muted);
    font-size: .72rem;
}

.shelf-tags svg { width: 12px; height: 12px; }

.shelf-demo {
    position: absolute;
    top: 12px;
    left: 56px;
    z-index: 2;
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    background: linear-gradient(135deg, #b0566f, #d49a5c);
    color: #fff;
    box-shadow: 0 4px 12px rgba(176, 86, 111, .35);
    opacity: 0;
    transform: scale(.8);
    transition: opacity .2s ease, transform .2s ease;
}

.shelf-demo svg { width: 16px; height: 16px; margin-inline-start: 2px; }
.shelf-track > li:hover .shelf-demo,
.shelf-demo:focus-visible { opacity: 1; transform: none; }

/* On a touch screen there is no hover: the play button is simply always there. */
@media (hover: none) {
    .shelf-demo { opacity: 1; transform: none; }
}

.shelf-end a {
    display: grid;
    place-content: center;
    justify-items: center;
    gap: 6px;
    height: 100%;
    min-height: 260px;
    border-radius: var(--dc-radius);
    background: linear-gradient(160deg, var(--dc-brand-soft), #fff);
    box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--dc-brand) 25%, var(--dc-line));
    color: var(--dc-brand-ink);
    text-decoration: none;
}

.shelf-end-count { font-family: var(--dc-display); font-size: 2.4rem; line-height: 1; }
.shelf-end b { margin-top: 6px; }

/* ------------------------------------------------ what the guest gets */

.home-guest {
    position: relative;
    display: grid;
    grid-template-columns: 1.2fr 1fr;
    align-items: center;
    gap: clamp(20px, 5vw, 64px);
    padding: clamp(24px, 4vw, 48px);
    border-radius: 32px;
    background:
        radial-gradient(70% 90% at 15% 20%, rgba(212, 154, 92, .25), transparent 60%),
        radial-gradient(60% 80% at 90% 90%, rgba(176, 86, 111, .28), transparent 60%),
        #1f1a24;
    color: #f4efe9;
    overflow: hidden;
}

.home-guest h2 { margin: 0; font-family: var(--dc-display); font-weight: 400; font-size: clamp(28px, 4vw, 44px); }
.home-guest-copy > p { margin: 6px 0 22px; color: rgba(244, 239, 233, .7); }

.home-features {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    margin: 0 0 24px;
    padding: 0;
    list-style: none;
}

.home-features li {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-rows: auto auto;
    column-gap: 10px;
    align-items: center;
    padding: 12px;
    border-radius: 16px;
    background: rgba(255, 255, 255, .06);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .08);
}

.home-feature-icon {
    grid-row: span 2;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 12px;
    background: linear-gradient(135deg, rgba(212, 154, 92, .35), rgba(176, 86, 111, .35));
    color: #fff;
}

.home-feature-icon svg { width: 20px; height: 20px; }
.home-features b { font-size: .95rem; }
.home-features li span:last-child { font-size: .78rem; color: rgba(244, 239, 233, .6); }

.home-guest .btn-primary { background: #fff; color: #1f1a24; }
.home-guest .btn-primary:hover { background: #f4e9e3; }

/* The phone: a real guest page, playing itself. */
.home-phone {
    justify-self: center;
    width: min(290px, 70vw);
    aspect-ratio: 9 / 19;
    padding: 12px;
    border-radius: 44px;
    background: linear-gradient(145deg, #3b3440, #121015);
    box-shadow: 0 0 0 2px #4a4250, 0 40px 80px rgba(0, 0, 0, .5), inset 0 0 0 1px rgba(255, 255, 255, .06);
    transform: rotate(-3deg);
}

.home-phone-screen {
    position: relative;
    width: 100%;
    height: 100%;
    overflow: hidden;
    border-radius: 34px;
    background: #16131a;
}

.home-phone-screen::before {
    content: "";
    position: absolute;
    top: 10px;
    left: 50%;
    z-index: 2;
    width: 34%;
    height: 22px;
    margin-left: -17%;
    border-radius: 999px;
    background: #000;
}

.home-phone iframe { display: block; width: 100%; height: 100%; border: 0; pointer-events: none; }

/* ------------------------------------------------ three steps */

.home-steps { display: grid; justify-items: center; gap: 18px; text-align: center; }
.home-steps h2 { margin: 0; font-size: clamp(22px, 3vw, 30px); }

.home-steps ol {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 14px;
    width: 100%;
    margin: 0;
    padding: 0;
    list-style: none;
}

.home-steps li {
    display: grid;
    justify-items: center;
    gap: 4px;
    padding: 22px 14px;
    border-radius: 20px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
}

.home-steps li span {
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
    margin-bottom: 6px;
    border-radius: 50%;
    background: linear-gradient(135deg, #b0566f, #d49a5c);
    color: #fff;
    font-family: var(--dc-display);
    font-size: 1.3rem;
}

.home-steps small { color: var(--dc-muted); }

.home-faq { display: grid; gap: 14px; }
.home-faq h2 { margin: 0; font-size: clamp(20px, 2.6vw, 26px); }

/* ------------------------------------------------ small screens */

@media (max-width: 860px) {
    .home-hero { grid-template-columns: minmax(0, 1fr); min-height: 0; text-align: center; }
    .home-hero-copy { display: grid; justify-items: center; }
    .home-actions, .home-facts { justify-content: center; }
    .home-fan { height: 300px; --w: 140px; }
    .home-guest { grid-template-columns: minmax(0, 1fr); }
    .home-phone { transform: none; }
}

@media (max-width: 600px) {
    .home-names { padding: 18px; }
    .home-names-fields { width: 100%; }
    .home-names-fields input { flex: 1; width: auto; min-width: 0; }
    .shelf-track {
        grid-auto-columns: 62%;
        margin-inline: calc(var(--dc-gutter) * -1);
        padding-inline: var(--dc-gutter);
        scroll-padding-inline: var(--dc-gutter);
    }
    .shelf-title p { display: none; }
    .home-features { grid-template-columns: 1fr; }
    .home-steps ol { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
    .home-fan-card, .home-play-icon { animation: none; }
    .shelf-tile .tile-card { transition: none; }
}

/* ------------------------------------------------ «ویژه» / «رایگان» (docs/HANDOFF.md 9-B)
   A small tag beside a template wherever templates are listed, so the price is known from the
   first look. Gold for premium, a quiet green for free; both readable on the white tile. More
   specific than .shelf-tags span, which would otherwise paint it grey on the front page. */
.plan-tag,
.shelf-tags span.plan-tag {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    margin-inline-end: 6px;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: .72rem;
    font-weight: 600;
    line-height: 1.7;
    white-space: nowrap;
    vertical-align: 1px;
}

.plan-tag svg { width: 11px; height: 11px; flex: none; }

.plan-tag.is-premium,
.shelf-tags span.plan-tag.is-premium {
    background: linear-gradient(135deg, #f7ebc9, #ecd49a);
    color: #6a4c10;
}

.plan-tag.is-free,
.shelf-tags span.plan-tag.is-free {
    background: #e5f1e9;
    color: #2d6546;
}

.detail-specs dd .plan-tag { margin-inline-end: 8px; }

/* «متحرک» beside a template whose painting moves (MotionTag). The price tag's shape, in the
   birthday card's dusty rose so the two never read as one tag. More specific than
   .shelf-tags span for the same reason as the price tag. */
.motion-tag,
.shelf-tags span.motion-tag {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    margin-inline-end: 6px;
    padding: 1px 8px;
    border-radius: 999px;
    background: #f5e6ed;
    color: #86405f;
    font-size: .72rem;
    font-weight: 600;
    line-height: 1.7;
    white-space: nowrap;
    vertical-align: 1px;
}

.motion-tag svg { width: 12px; height: 12px; flex: none; }

.detail-specs dd .motion-tag { margin-inline-end: 8px; }

/* The panel is dark; the same gold, lit for it. */
.panel-badge.is-premium { background: rgba(214, 178, 94, .22); color: #ecd08c; }
.panel-badge.is-free { background: rgba(120, 190, 150, .16); color: #a8dcbc; }

.tpl-plan-warn { color: #ecd08c; }

/* The editor says it beside the template picker: premium is free to make, paid to send. */
.ed-plan-note {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: .78rem;
    color: #6a4c10;
}

/* ------------------------------------------------ the card's plan page (/my-cards/{id}/plan) */
.plan-notice {
    margin: 0 0 18px;
    padding: 12px 16px;
    border-radius: 14px;
    background: #e8f4ec;
    color: #245a3c;
    font-size: .92rem;
}

.plan-notice.is-warned { background: #fff6e5; color: #7a5310; }

.plan-need, .plan-free, .plan-ready, .plan-admin { margin-bottom: 18px; }

.plan-reasons {
    margin: 0 0 14px;
    padding-inline-start: 1.2em;
    line-height: 2;
}

.plan-price { margin: 0 0 14px; font-size: 1rem; }
.plan-price strong { font-size: 1.15rem; }
.plan-price span { color: var(--dc-muted); font-size: .85rem; }

.plan-small { margin: 10px 0 0; color: var(--dc-muted); font-size: .85rem; line-height: 1.9; }

.plan-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.plan-actions form { display: inline; }

.plan-free-form { display: flex; flex-wrap: wrap; gap: 10px; align-items: end; }
.plan-free-form label { display: grid; gap: 6px; font-size: .9rem; }
.plan-free-form select {
    min-width: 200px;
    height: 44px;
    padding: 0 12px;
    border: 0;
    border-radius: 12px;
    background: var(--dc-ground);
    box-shadow: inset 0 0 0 1px var(--dc-line);
    font: inherit;
}

.plan-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
    gap: 14px;
    margin: 6px 0 22px;
}

.plan-card {
    position: relative;
    display: grid;
    align-content: start;
    gap: 6px;
    padding: 20px;
    border-radius: 18px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
}

.plan-card h3 { margin: 0; font-size: 1rem; }
.plan-card-price { margin: 0; font-size: 1.2rem; font-weight: 700; }
.plan-card ul { margin: 6px 0 0; padding-inline-start: 1.1em; color: var(--dc-muted); font-size: .88rem; line-height: 1.9; }

.plan-card.is-owned { box-shadow: var(--dc-shadow), inset 0 0 0 2px #7fb895; }
.plan-card.is-needed { box-shadow: var(--dc-shadow), inset 0 0 0 2px #d9b65f; }

.plan-card-tag {
    justify-self: start;
    margin-top: 8px;
    padding: 2px 10px;
    border-radius: 999px;
    background: #e5f1e9;
    color: #2d6546;
    font-size: .76rem;
    font-weight: 600;
}

.plan-card-tag.is-needed { background: linear-gradient(135deg, #f7ebc9, #ecd49a); color: #6a4c10; }

.plan-admin { box-shadow: var(--dc-shadow), inset 0 0 0 1px #e6d3a3; }
.plan-admin h2 { color: #7a5310; }

/* «ویژه» beside the editor's paid choices. On a picture (an envelope, a stamp) it sits in the
   corner; beside a word it follows the word. */
.ed-paid { margin-inline: 5px 0; padding: 0 6px; font-size: .62rem; line-height: 1.7; vertical-align: 1px; }
.ed-envelope, .ed-stamp { position: relative; }
.ed-envelope .ed-paid,
.ed-stamp .ed-paid { position: absolute; top: 5px; inset-inline-start: 5px; margin: 0; }
.ed-stamp .ed-paid { top: 2px; inset-inline-start: 2px; padding: 0 4px; font-size: .56rem; }

/* ------------------------------------------------ receipts and payments */
.receipt-rows { display: grid; gap: 0; margin: 0 0 18px; }
.receipt-rows > div {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--dc-line);
}
.receipt-rows > div:last-child { border-bottom: 0; }
.receipt-rows dt { color: var(--dc-muted); }
.receipt-rows dd { margin: 0; font-weight: 600; text-align: end; overflow-wrap: anywhere; }

.receipt-status { padding: 1px 10px; border-radius: 999px; font-size: .8rem; background: #eef1f4; color: #4b5763; }
.receipt-status.is-paid { background: #e5f1e9; color: #2d6546; }
.receipt-status.is-pending { background: #fff6e5; color: #7a5310; }
.receipt-status.is-failed,
.receipt-status.is-canceled { background: #fbeceb; color: #8a3a33; }

.receipt-refund { margin-top: 16px; }
.receipt-refund summary { cursor: pointer; color: var(--dc-muted); font-size: .88rem; }
.receipt-refund form { margin-top: 10px; }
.receipt-refund p { margin: 0 0 10px; font-size: .88rem; line-height: 1.9; }

.plan-card-buy { margin-top: 10px; }
.plan-card-buy button { width: 100%; }

.plan-orders ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 8px; font-size: .9rem; }

.pay-error { display: block; margin-top: 4px; opacity: .7; font-size: .72rem; }

/* ------------------------------------------------ the panel's money pages (/panel/finance)
   Same dark furniture as the dashboard. Numbers are tabular so a column of amounts lines up
   digit under digit - these pages are for checking money, and misaligned digits make that harder. */
.fin { font-variant-numeric: tabular-nums; }

.fin-tabs { display: flex; gap: .3rem; margin: -.4rem 0 1.1rem; border-bottom: 1px solid var(--line); }
.fin-tabs a {
    padding: .55rem 1rem;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    color: var(--ink-muted);
    text-decoration: none;
    font-size: .9rem;
    display: inline-flex;
    align-items: center;
    gap: .4rem;
}
.admin .fin-tabs a { color: var(--ink-muted); }
.admin .fin-tabs a:hover { color: var(--ink); }
.admin .fin-tabs a.is-on { color: var(--ink); border-bottom-color: var(--brand); }
.fin-count {
    min-width: 1.3rem;
    padding: 0 .35rem;
    border-radius: 999px;
    background: rgba(214, 178, 94, .28);
    color: #ecd08c;
    font-size: .72rem;
    text-align: center;
}

/* The buttons of these pages wear the panel's quiet style, not the shop's. */
.admin .fin .btn-quiet,
.admin .fin .fin-filter button[type=submit],
.admin .fin .fin-custom button[type=submit] {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    border: 1px solid var(--line);
    background: var(--surface-2);
    color: var(--ink);
    border-radius: 8px;
    padding: .4rem .8rem;
    font-size: .8rem;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
}
.admin .fin .btn-quiet:hover,
.admin .fin .fin-filter button[type=submit]:hover,
.admin .fin .fin-custom button[type=submit]:hover { background: rgba(230, 236, 244, .1); }
.admin .fin .btn-quiet.is-urgent { border-color: rgba(214, 178, 94, .6); color: #ecd08c; }

/* ---- the period: quick choices, a custom range, the spreadsheet */
.fin-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .6rem 1rem;
    margin-bottom: 1.1rem;
}
.fin-ranges { display: inline-flex; padding: .2rem; gap: .2rem; border-radius: 10px; background: var(--surface); border: 1px solid var(--line); }
.fin-ranges a { padding: .35rem .75rem; border-radius: 8px; font-size: .82rem; text-decoration: none; }
.admin .fin-ranges a { color: var(--ink-muted); }
.admin .fin-ranges a:hover { color: var(--ink); }
.admin .fin-ranges a.is-on { background: var(--brand); color: #fff; }

.fin-custom, .fin-filter { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
.fin-custom label, .fin-filter label { display: inline-flex; align-items: center; gap: .35rem; font-size: .8rem; color: var(--ink-muted); }
.fin-custom input, .fin-filter input, .fin-filter select {
    box-sizing: border-box;
    padding: .42rem .6rem;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface-2);
    color: var(--ink);
    font: inherit;
    font-size: .82rem;
}
.fin-custom input, .fin-filter label input { width: 7.2rem; text-align: center; }
.fin-custom input::placeholder, .fin-filter input::placeholder { color: rgba(230, 236, 244, .35); }
.fin-filter { margin-bottom: .9rem; }
.fin-filter input[type=search] { flex: 1 1 18rem; min-width: 12rem; max-width: 26rem; }
.fin-export { margin-inline-start: auto; }

/* ---- the tiles: money needs a little more room than a count */
.fin-stats { grid-template-columns: repeat(auto-fit, minmax(max(12.5rem, 30%), 1fr)); }
.fin-stats .stat-value { font-size: 1.45rem; overflow-wrap: anywhere; }
.fin-delta { font-weight: 600; }
.fin-delta.is-good { color: #6fd3a8; }
.fin-delta.is-bad { color: #ff9c7c; }
.fin-delta.is-flat { color: var(--ink-muted); }

.chart-empty {
    margin: 0;
    min-height: 6rem;
    display: grid;
    place-items: center;
    color: var(--ink-muted);
    font-size: .85rem;
    text-align: center;
}

/* A small table under a chart: the same numbers, in words. */
.fin-mini { width: 100%; margin-top: .7rem; border-collapse: collapse; font-size: .8rem; }
.fin-mini th, .fin-mini td { padding: .35rem .2rem; border-top: 1px solid var(--line); text-align: right; font-weight: 400; }
.fin-mini thead th { border-top: 0; color: var(--ink-muted); font-size: .74rem; }
.fin-mini td { color: var(--ink-muted); white-space: nowrap; }
.fin-mini td:last-child { text-align: left; color: var(--ink); }
.fin-reasons tbody th { line-height: 1.7; }

.fin-section { margin: 1.6rem 0 1rem; }
.fin-section h2 { margin: 0 0 .3rem; font-size: 1.05rem; }
.fin-sub { margin: 1rem 0 .5rem; font-size: .9rem; font-weight: 500; }
.fin-lead { margin: 0 0 .9rem; color: var(--ink-muted); font-size: .82rem; line-height: 1.8; }
.fin-section > .panel-table-wrap, .fin-section > .stat-row { margin-top: .6rem; }

.fin-side { grid-template-columns: 1fr; margin: 0; align-content: start; }
.fin-funnel-box { height: 13rem; }

.fin-wrap { white-space: normal; min-width: 14rem; line-height: 1.7; }
.fin-muted { color: var(--ink-muted); }

/* ---- the orders list */
.fin-summary { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .5rem 1rem; margin-bottom: .8rem; }
.fin-summary p { margin: 0; font-size: .86rem; }
.fin-orders td { vertical-align: top; }
.fin-number { font-weight: 600; text-decoration: none; }
.fin-who { display: grid; gap: .1rem; }
.fin-who bdi { font-size: .76rem; }
.fin-orders .pay-error { max-width: 16rem; white-space: normal; line-height: 1.6; }
.fin-inline { display: inline; margin: 0; }

/* ---- one order */
.fin-back { margin: 0 0 .6rem; font-size: .82rem; }
.fin-order-head { display: flex; align-items: center; flex-wrap: wrap; gap: .6rem; }
.fin-order-head h1 { margin: 0; }

.fin-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr)); gap: .8rem; margin-bottom: .8rem; }
.fin-card-box { padding: 1rem 1.1rem; border-radius: 12px; background: var(--surface); border: 1px solid var(--line); min-width: 0; }
.fin-card-box h2 { margin: 0 0 .7rem; font-size: .95rem; font-weight: 600; }
.fin-card-box p { margin: 0 0 .6rem; font-size: .85rem; line-height: 1.9; }

.fin-rows { margin: 0; display: grid; }
.fin-rows > div { display: flex; justify-content: space-between; gap: 1rem; padding: .45rem 0; border-bottom: 1px solid var(--line); font-size: .85rem; }
.fin-rows > div:last-child { border-bottom: 0; }
.fin-rows dt { color: var(--ink-muted); }
.fin-rows dd { margin: 0; text-align: left; overflow-wrap: anywhere; }
.fin-code { font-family: ui-monospace, Consolas, monospace; font-size: .76rem; overflow-wrap: anywhere; }
code.fin-code { display: inline-block; padding: .3rem .5rem; border-radius: 6px; background: var(--surface-2); color: var(--ink-muted); }

.fin-timeline { list-style: none; margin: 0; padding: 0; display: grid; gap: .1rem; }
.fin-timeline li {
    position: relative;
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: .45rem 1.1rem .45rem 0;
    font-size: .85rem;
}
.fin-timeline li::before {
    content: "";
    position: absolute;
    inset-inline-start: .15rem;
    top: .95rem;
    width: .5rem;
    height: .5rem;
    border-radius: 50%;
    background: var(--ink-muted);
}
.fin-timeline li.is-good::before { background: #199e70; }
.fin-timeline li.is-warn::before { background: #c98500; }
.fin-timeline li.is-bad::before { background: #d95926; }
.fin-timeline time { color: var(--ink-muted); white-space: nowrap; font-size: .8rem; }

.fin-act { margin-bottom: .8rem; }
.fin-act.is-urgent { border-color: rgba(214, 178, 94, .55); }
.fin-steps { margin: 0 0 .8rem; padding-inline-start: 1.2rem; font-size: .85rem; line-height: 2; }
.fin-confirm > summary { list-style: none; }
.fin-confirm > summary::-webkit-details-marker { display: none; }
.fin-confirm form { margin-top: .7rem; padding: .8rem; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--line); max-width: 30rem; }
.fin-confirm form p { color: var(--ink-muted); font-size: .82rem; }

@media (max-width: 720px) {
    .fin-export { margin-inline-start: 0; }
    .fin-cards { grid-template-columns: 1fr; }
    .fin-rows > div, .fin-timeline li { flex-direction: column; gap: .15rem; }
    .fin-rows dd { text-align: right; }
}

/* The orders table has to fit a laptop screen without scrolling sideways: long card names and
   the gateway's reasons wrap inside their own columns instead of widening the table. */
.fin-orders .fin-card { white-space: normal; min-width: 8rem; max-width: 13rem; overflow-wrap: anywhere; }
.fin-orders .fin-status { white-space: normal; min-width: 8rem; max-width: 15rem; }
.fin-orders .fin-status .panel-badge { margin-block: .1rem; }
.fin-orders td:last-child { white-space: nowrap; }
.fin-timeline small { display: block; margin-top: .1rem; }

/* The site-wide submit rule (button[type=submit]:not(.icon-btn)) outranks ".admin .btn-danger",
   which painted the refund confirmation in the shop's colour. One more class settles it here. */
.admin .fin button[type=submit].btn-danger {
    border: 1px solid rgba(255, 140, 140, .5);
    background: transparent;
    color: #ff9c9c;
    padding: .45rem .9rem;
    font-size: .82rem;
}
.admin .fin button[type=submit].btn-danger:hover { background: rgba(216, 90, 90, .2); color: #fff; }

/* ---------------------------------------------------------------- gallery pages (script 64)
   Page links under a gallery once it holds more than one page of templates. Same pill shape as
   the occasion chips above the grid, so the two read as one set of controls. */

.pager {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 8px;
    margin: 32px 0 8px;
}

.pager-num,
.pager-step {
    /* border-box: the site does not set it globally, and without it a "42px" pill was 72. */
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 42px;
    height: 42px;
    padding: 0 14px;
    border: 1px solid var(--dc-line);
    border-radius: 999px;
    background: var(--dc-surface);
    color: var(--dc-ink);
    font-size: 15px;
    text-decoration: none;
}

a.pager-num:hover,
a.pager-step:hover {
    border-color: var(--dc-brand);
    color: var(--dc-brand);
}

.pager-num[aria-current="page"] {
    background: var(--dc-brand);
    border-color: var(--dc-brand);
    color: #fff;
}

.pager-gap {
    padding: 0 2px;
    color: var(--dc-muted);
}

/* On a phone the row has to fit in one line: seven numbers and two words at the desktop size
   are about 410px, a phone has about 360. */
@media (max-width: 480px) {
    .pager { gap: 4px; }
    .pager-num,
    .pager-step { min-width: 34px; height: 36px; padding: 0 8px; font-size: 14px; }
    .pager-far,
    .pager-gap { display: none; }
}

/* ---------------------------------------------------------------- words for search (script 67)
   The occasion under a template's name in its heading, the paragraphs about a template, and the
   questions under an occasion's gallery. Quiet on purpose: they are for the reader who scrolls,
   and for search engines; the cards stay the page. */

.detail-kind {
    display: block;
    margin-top: .25em;
    font-family: var(--dc-sans);
    font-size: .5em;
    font-weight: 500;
    color: var(--dc-muted);
}

.detail-about,
.occasion-about {
    max-width: 760px;
}

.detail-about h2,
.occasion-about h2 {
    margin: 0 0 12px;
    font-size: 20px;
}

.detail-about p,
.occasion-about p {
    margin: 0 0 12px;
    line-height: 2;
    color: var(--dc-ink);
}

.occasion-faq-title { margin-top: 28px !important; }

.occasion-faq details {
    border-bottom: 1px solid var(--dc-line);
    padding: 12px 0;
}

.occasion-faq summary {
    cursor: pointer;
    font-weight: 600;
    list-style-position: inside;
}

.occasion-faq details p {
    margin: 10px 0 0;
    color: var(--dc-muted);
}

/* ---------------------------------------------------------------- the site's own pages (68, 69)
   Prices, about, contact and the rules, in the home page's language: the same wash, the same
   display face for headlines, the same pills. Built from a handful of pieces - a hero, tiles,
   steps, a question list and a closing band - so a new page of this kind is mostly words. */

.site-hero {
    position: relative;
    display: grid;
    align-items: center;
    gap: clamp(24px, 4vw, 56px);
    padding-block: 0 clamp(28px, 4vw, 44px);
    margin-bottom: clamp(18px, 3vw, 30px);
}

.site-hero.has-art { grid-template-columns: 1.05fr .95fr; min-height: min(520px, 72vh); }
.site-hero.is-centred { text-align: center; justify-items: center; }
.site-hero.is-centred .site-hero-copy { max-width: 720px; }
.site-hero.is-centred .breadcrumb ol { justify-content: center; }

/* Full width behind the words, reaching up under the header: blush, a little gold, the
   brand's teal, fading into the page. */
.site-hero-wash {
    position: absolute;
    z-index: -1;
    top: calc(clamp(28px, 5vw, 48px) * -1);
    bottom: 0;
    left: 50%;
    width: 100vw;
    transform: translateX(-50%);
    background:
        radial-gradient(38% 60% at 18% 40%, rgba(232, 190, 196, .38), transparent 70%),
        radial-gradient(34% 55% at 84% 30%, rgba(47, 93, 112, .10), transparent 70%),
        radial-gradient(30% 45% at 55% 95%, rgba(214, 180, 120, .16), transparent 70%),
        linear-gradient(180deg, #fbf7f4 0%, var(--dc-ground) 100%);
    /* Fades out at its lower edge, so the band never ends on a visible line. */
    -webkit-mask-image: linear-gradient(to bottom, #000 65%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 65%, transparent 100%);
    pointer-events: none;
}

.site-hero-crumb { margin-bottom: 18px; }

.site-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 14px;
    padding: 6px 14px;
    border-radius: 999px;
    background: rgba(255, 255, 255, .85);
    box-shadow: 0 0 0 1px var(--dc-line);
    color: var(--dc-brand-ink);
    font-size: .85rem;
    font-weight: 600;
}

.site-eyebrow span {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #d9869a;
    box-shadow: 0 0 0 4px rgba(217, 134, 154, .2);
}

.site-hero h1 {
    margin: 0;
    font-family: var(--dc-display);
    font-weight: 400;
    font-size: clamp(34px, 5.4vw, 60px);
    line-height: 1.25;
    color: var(--dc-ink);
}

.site-hero h1 em {
    font-style: normal;
    background: linear-gradient(100deg, #b0566f 0%, #d49a5c 55%, #2f5d70 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.site-lead {
    max-width: 34em;
    margin: 16px 0 0;
    color: var(--dc-muted);
    font-size: clamp(15px, 1.6vw, 18px);
    line-height: 2;
}

.site-hero.is-centred .site-lead { margin-inline: auto; }

.site-hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: 26px; }

.site-go {
    padding: 13px 30px;
    border-radius: 14px;
    font-weight: 700;
    box-shadow: 0 10px 26px rgba(47, 93, 112, .26);
}

.site-quiet {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 11px 20px;
    border-radius: 14px;
    background: #fff;
    box-shadow: 0 0 0 1px var(--dc-line), 0 8px 20px rgba(30, 40, 51, .06);
    color: var(--dc-ink);
    font-weight: 600;
    text-decoration: none;
    transition: transform .2s ease, box-shadow .2s ease;
}

.site-quiet:hover { transform: translateY(-2px); box-shadow: 0 0 0 1px var(--dc-line), 0 12px 26px rgba(30, 40, 51, .1); }

.site-icon { width: 22px; height: 22px; flex: none; }
.site-quiet .site-icon { width: 19px; height: 19px; color: var(--dc-brand); }

.site-section { margin-block: clamp(40px, 6vw, 72px); }

.site-h2 {
    margin: 0 0 22px;
    font-family: var(--dc-display);
    font-weight: 400;
    font-size: clamp(24px, 3.2vw, 34px);
    line-height: 1.4;
}

.site-h2.is-centred { text-align: center; }

/* ------------------------------------------------ tiles: an icon, a heading, a sentence */

.tile-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr));
    gap: 16px;
}

.tile {
    padding: 22px;
    border-radius: 20px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
    transition: transform .2s ease, box-shadow .2s ease;
}

.tile:hover { transform: translateY(-3px); box-shadow: var(--dc-shadow-lift); }
.tile h3 { margin: 14px 0 6px; font-size: 1.02rem; }
.tile p { margin: 0; color: var(--dc-muted); font-size: .92rem; line-height: 1.95; }

.tile-icon {
    display: inline-grid;
    place-items: center;
    width: 46px;
    height: 46px;
    flex: none;
    border-radius: 14px;
    background: linear-gradient(135deg, #fbeef0, #eef4f7);
    color: var(--dc-brand);
}

/* ------------------------------------------------ prices */

.price-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 270px), 1fr));
    gap: 18px;
    align-items: stretch;
}

.price-card {
    display: flex;
    flex-direction: column;
    padding: 28px 26px 24px;
    border-radius: 24px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
    transition: transform .2s ease, box-shadow .2s ease;
}

.price-card:hover { transform: translateY(-4px); box-shadow: var(--dc-shadow-lift); }

/* The plan most cards need, set apart by colour alone - no badge claiming it is the favourite. */
.price-card.is-featured {
    background:
        radial-gradient(80% 60% at 90% 0%, rgba(214, 180, 120, .28), transparent 70%),
        linear-gradient(160deg, #35677c 0%, #244856 100%);
    color: #fff;
    box-shadow: 0 18px 44px rgba(36, 72, 86, .32);
}

.price-card-icon {
    display: grid;
    place-items: center;
    width: 52px;
    height: 52px;
    border-radius: 16px;
    background: linear-gradient(135deg, #fbeef0, #eef4f7);
    color: var(--dc-brand);
}

.price-card.is-featured .price-card-icon { background: rgba(255, 255, 255, .14); color: #f3d9a4; }
.price-card h2 { margin: 18px 0 4px; font-size: 1.08rem; }

.price-amount { display: flex; align-items: baseline; gap: 8px; margin: 6px 0 0; }
.price-amount b { font-family: var(--dc-display); font-weight: 400; font-size: 2.9rem; line-height: 1.2; }
.price-amount span { font-weight: 600; }

.price-per { margin: 0; color: var(--dc-muted); font-size: .88rem; }
.price-card.is-featured .price-per { color: rgba(255, 255, 255, .72); }

.price-list {
    display: grid;
    gap: 10px;
    margin: 20px 0 24px;
    padding: 18px 0 0;
    border-top: 1px solid var(--dc-line);
    list-style: none;
    font-size: .93rem;
    line-height: 1.8;
}

.price-card.is-featured .price-list { border-top-color: rgba(255, 255, 255, .16); }
.price-list li { display: flex; gap: 10px; align-items: flex-start; }
.price-list .site-icon { width: 19px; height: 19px; margin-top: 4px; color: #3d8a63; }
.price-card.is-featured .price-list .site-icon { color: #f3d9a4; }

.price-go {
    margin-top: auto;
    padding: 12px 18px;
    border-radius: 14px;
    background: var(--dc-brand-soft);
    color: var(--dc-brand-ink);
    font-weight: 700;
    text-align: center;
    text-decoration: none;
    transition: background-color .15s ease;
}

.price-go:hover { background: #e2edf2; }
.price-card.is-featured .price-go { background: #fff; color: var(--dc-brand-ink); }
.price-card.is-featured .price-go:hover { background: #f6efe4; }

/* The comparison: sideways scroll inside its own box on a narrow phone, never the page. */
.plan-table-wrap {
    overflow-x: auto;
    border-radius: 22px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
}

.plan-table { width: 100%; border-collapse: collapse; font-size: .93rem; }

.plan-table th,
.plan-table td { padding: 13px 16px; border-bottom: 1px solid var(--dc-line); }

.plan-table tbody tr:last-child th,
.plan-table tbody tr:last-child td { border-bottom: 0; }

.plan-table thead th { padding-block: 18px; font-size: .95rem; text-align: center; white-space: nowrap; }
.plan-table tbody th { font-weight: 500; text-align: start; }
.plan-table td { text-align: center; width: 17%; }
.plan-table .is-featured { background: rgba(47, 93, 112, .06); }
.plan-table thead .is-featured { color: var(--dc-brand); }
.plan-table-yes { display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; background: #e6f3ec; color: #3d8a63; }
.plan-table-yes .site-icon { width: 17px; height: 17px; }
.plan-table-no { color: #b7c0c9; }
.plan-table-no .site-icon { width: 18px; height: 18px; }
.plan-table-text { font-size: .85rem; font-weight: 600; }
.plan-table-short { display: none; }

/* ------------------------------------------------ questions */

.site-faq-wrap { max-width: 820px; margin-inline: auto; }
.site-faq-wrap .site-h2 { text-align: center; }
.site-faq { display: grid; gap: 12px; }

.site-faq details {
    border-radius: 18px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
    transition: box-shadow .2s ease;
}

.site-faq details[open] { box-shadow: var(--dc-shadow-lift); }

.site-faq summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 18px 22px;
    font-weight: 600;
    cursor: pointer;
    list-style: none;
}

.site-faq summary::-webkit-details-marker { display: none; }

.site-faq summary::after {
    content: "+";
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    flex: none;
    border-radius: 50%;
    background: var(--dc-brand-soft);
    color: var(--dc-brand);
    font-size: 1.2rem;
    line-height: 1;
    transition: transform .2s ease;
}

.site-faq details[open] summary::after { transform: rotate(45deg); }
.site-faq details p { margin: 0; padding: 0 22px 20px; color: var(--dc-muted); line-height: 2; }

/* ------------------------------------------------ the closing band */

.cta-band {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 18px 28px;
    margin-block: clamp(40px, 6vw, 72px) 0;
    padding: clamp(26px, 4vw, 40px);
    border-radius: 28px;
    background:
        radial-gradient(60% 90% at 10% 20%, rgba(232, 190, 196, .35), transparent 70%),
        radial-gradient(50% 80% at 95% 90%, rgba(214, 180, 120, .25), transparent 70%),
        linear-gradient(135deg, #35677c 0%, #244856 100%);
    color: #fff;
    box-shadow: 0 18px 44px rgba(36, 72, 86, .28);
}

.cta-band h2 { margin: 0 0 6px; font-family: var(--dc-display); font-weight: 400; font-size: clamp(24px, 3vw, 32px); }
.cta-band p { margin: 0; color: rgba(255, 255, 255, .8); line-height: 1.9; }

.cta-band-go {
    padding: 13px 30px;
    border-radius: 14px;
    background: #fff;
    color: var(--dc-brand-ink);
    font-weight: 700;
    text-decoration: none;
    white-space: nowrap;
    transition: transform .2s ease;
}

.cta-band-go:hover { transform: translateY(-2px); }

/* ------------------------------------------------ about */

/* The picture: three painted cards rising out of the painted envelope, on the roses-and-silk
   scene. Layers, back to front: the envelope's back, the cards, the envelope's front (whose V
   is cut out, so the cards show through it). */
.about-art {
    position: relative;
    aspect-ratio: 5 / 4;
    overflow: hidden;
    border-radius: 30px;
    background: #f6efe6 url('card-art/envelope/scene.webp') center / cover no-repeat;
    box-shadow: 0 24px 60px rgba(30, 40, 51, .16);
}

.about-env { position: absolute; left: 14%; bottom: -10%; width: 72%; height: auto; }
.about-env-back { z-index: 1; filter: drop-shadow(0 16px 26px rgba(90, 60, 40, .18)); }
.about-env-front { z-index: 5; }

.about-card {
    position: absolute;
    z-index: 3;
    bottom: 26%;
    left: 50%;
    width: 28%;
    aspect-ratio: 2 / 3;
    transform-origin: 50% 100%;
    border-radius: 6px;
    background: #fbf6ee;
    box-shadow: 0 10px 26px rgba(70, 50, 40, .22);
    animation: about-breathe 7s ease-in-out infinite;
}

.about-card img { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }

.about-card-1 { --r: -16deg; --x: -135%; bottom: 22%; animation-delay: -1.5s; }
.about-card-2 { --r: 0deg; --x: -50%; z-index: 4; bottom: 30%; width: 30%; animation-delay: -3s; }
.about-card-3 { --r: 16deg; --x: 35%; bottom: 22%; animation-delay: -4.5s; }

/* The words on the front card, in the display face - the one thing that says "invitation". */
.about-card-words {
    position: absolute;
    inset: 30% 8% auto;
    color: #2f4b67;
    font-family: var(--dc-display);
    font-size: clamp(13px, 1.8vw, 21px);
    line-height: 1.6;
    text-align: center;
}

@keyframes about-breathe {
    0%, 100% { transform: translateX(var(--x)) rotate(var(--r)) translateY(0); }
    50% { transform: translateX(var(--x)) rotate(var(--r)) translateY(-10px); }
}

@media (prefers-reduced-motion: reduce) {
    .about-card { animation: none; transform: translateX(var(--x)) rotate(var(--r)); }
}

.about-story {
    display: grid;
    grid-template-columns: 1.4fr 1fr;
    gap: clamp(24px, 4vw, 48px);
    align-items: center;
}

.about-story-text p { margin: 0 0 14px; line-height: 2.1; }

.about-glance {
    display: grid;
    gap: 12px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.about-glance li {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 16px 18px;
    border-radius: 18px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
}

.about-glance b { display: block; }
.about-glance small { color: var(--dc-muted); font-size: .85rem; }

.site-steps {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
    gap: 16px;
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: none;
}

.site-steps li {
    position: relative;
    padding: 26px 22px 22px;
    border-radius: 20px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
}

.site-steps h3 { margin: 14px 0 6px; font-size: 1.02rem; }
.site-steps p { margin: 0; color: var(--dc-muted); font-size: .92rem; line-height: 1.95; }

.site-step-n {
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: linear-gradient(135deg, #b0566f, #d49a5c);
    color: #fff;
    font-family: var(--dc-display);
    font-size: 1.3rem;
}

/* ------------------------------------------------ contact */

.contact-layout {
    display: grid;
    grid-template-columns: 1.6fr 1fr;
    gap: clamp(18px, 3vw, 28px);
    align-items: start;
}

.contact-card {
    padding: clamp(22px, 3.5vw, 36px);
    border-radius: 26px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow-lift);
}

.contact-title { display: flex; align-items: center; gap: 10px; margin: 0 0 20px; font-size: 1.2rem; }
.contact-title .site-icon { color: var(--dc-brand); }

.contact-problem {
    margin: 0 0 16px;
    padding: 12px 16px;
    border-radius: 14px;
    background: #fbeceb;
    color: #8f3a33;
}

.contact-form { display: grid; gap: 16px; }
.contact-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); gap: 16px; }

.contact-field { display: grid; gap: 7px; }
.contact-field > span { font-size: .88rem; font-weight: 600; color: var(--dc-ink); }

.contact-field input,
.contact-field textarea {
    width: 100%;
    box-sizing: border-box;
    padding: 13px 15px;
    border: 1px solid var(--dc-line);
    border-radius: 14px;
    background: #fafbfc;
    color: var(--dc-ink);
    font: inherit;
    line-height: 1.9;
    transition: border-color .15s ease, box-shadow .15s ease, background-color .15s ease;
}

.contact-field textarea { resize: vertical; min-height: 150px; }
.contact-field input::placeholder,
.contact-field textarea::placeholder { color: #a3adb7; }

.contact-field input:focus,
.contact-field textarea:focus {
    outline: none;
    border-color: var(--dc-brand);
    background: #fff;
    box-shadow: 0 0 0 4px rgba(47, 93, 112, .12);
}

/* More specific than the site-wide button[type=submit]. */
.contact-form button.contact-send[type=submit] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    width: 100%;
    padding: 14px 20px;
    border-radius: 14px;
    font-weight: 700;
    box-shadow: 0 10px 24px rgba(47, 93, 112, .24);
}

.contact-send .site-icon { width: 20px; height: 20px; transform: scaleX(-1); }
.contact-fine { margin: 0; color: var(--dc-muted); font-size: .82rem; text-align: center; }

.contact-sent { text-align: center; padding-block: 10px; }
.contact-sent h2 { margin: 14px 0 6px; font-family: var(--dc-display); font-weight: 400; font-size: 1.8rem; }
.contact-sent p { margin: 0 auto 22px; max-width: 26em; color: var(--dc-muted); }
.contact-sent-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }

.contact-sent-icon {
    display: inline-grid;
    place-items: center;
    width: 64px;
    height: 64px;
    border-radius: 50%;
    background: #e6f3ec;
    color: #3d8a63;
}

.contact-sent-icon .site-icon { width: 32px; height: 32px; }

.contact-side { display: grid; gap: 12px; }

.contact-way {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 16px 18px;
    border-radius: 18px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
}

.contact-way small { display: block; color: var(--dc-muted); font-size: .8rem; }
.contact-way bdi,
.contact-way span:not(.tile-icon) { font-weight: 600; }

.contact-help {
    padding: 20px;
    border-radius: 18px;
    background: linear-gradient(135deg, #fbf3f0, #eef4f7);
}

.contact-help h3 { margin: 0 0 8px; font-size: .98rem; }
.contact-help ul { margin: 0 0 10px; padding-inline-start: 1.2em; line-height: 2.1; }
.contact-help a { color: var(--dc-brand-ink); }
.contact-help p { margin: 0; color: var(--dc-muted); font-size: .85rem; line-height: 1.9; }

/* Off-screen rather than display:none: some scripts skip fields that are not displayed. */
.contact-trap {
    position: absolute;
    inset-inline-start: -10000px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

/* ------------------------------------------------ the rules pages */

.legal-page { line-height: 2.05; }
.legal-page h2 { margin: 30px 0 10px; font-size: 1.15rem; color: var(--dc-brand-ink); }
.legal-page h2:first-child { margin-top: 0; }
.legal-page ul,
.legal-page ol { margin: 0 0 12px; padding-inline-start: 1.3em; }
.legal-page li { margin-bottom: 6px; }
.legal-page p { margin: 0 0 12px; }

.legal-card {
    max-width: 820px;
    margin-inline: auto;
    padding: clamp(22px, 4vw, 44px);
    border-radius: 26px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
}

/* ------------------------------------------------ narrower screens */

@media (max-width: 860px) {
    .site-hero.has-art { grid-template-columns: 1fr; min-height: 0; }
    .about-story,
    .contact-layout { grid-template-columns: 1fr; }
}

@media (max-width: 560px) {
    .plan-table-long { display: none; }
    .plan-table-short { display: inline; }
    .plan-table th,
    .plan-table td { padding: 11px 8px; }
    .plan-table tbody th { font-size: .85rem; }
    .plan-table-text { font-size: .75rem; }
    .cta-band { text-align: center; justify-content: center; }
}

/* The menu: the page you are on, marked; on a phone one row that scrolls sideways rather than
   wrapping onto a second. */
.site-nav a.active { color: var(--dc-brand); font-weight: 600; }

@media (max-width: 720px) {
    /* .site-header nav (earlier, and more specific) asks for wrapping; this overrules it. */
    .site-header .site-nav {
        flex-wrap: nowrap;
        gap: 13px;
        overflow-x: auto;
        scrollbar-width: none;
        white-space: nowrap;
    }

    .site-header .site-nav::-webkit-scrollbar { display: none; }
}

@media (max-width: 400px) {
    .site-header .site-nav { gap: 11px; font-size: 13.5px; }
    .site-header .site-nav a { font-size: 13.5px; }
}

/* The footer's seller line and Enamad badge. */
.footer-trust {
    max-width: 1100px;
    margin: 20px auto 0;
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    align-items: center;
    justify-content: space-between;
    font-size: 13px;
    color: var(--dc-muted);
}

.footer-trust p { margin: 0; }
.footer-enamad img { display: block; width: 88px; height: auto; }

/* The panel's inbox. */
.admin-count {
    margin-inline-start: auto;
    min-width: 1.4rem;
    padding: 0 .35rem;
    border-radius: 999px;
    background: var(--brand);
    color: #fff;
    font-size: .72rem;
    line-height: 1.4rem;
    text-align: center;
}

.admin:has(.admin-fold:checked) .admin-count { display: none; }

.panel-messages { display: grid; gap: .8rem; max-width: 820px; }

.panel-message {
    padding: .9rem 1rem;
    border-radius: 12px;
    background: var(--surface);
    box-shadow: inset 0 0 0 1px var(--line);
}

.panel-message.is-new { box-shadow: inset 0 0 0 1px var(--brand); }

.panel-message header { display: flex; flex-wrap: wrap; gap: .4rem .8rem; align-items: center; }
.panel-message header time { margin-inline-start: auto; color: var(--ink-muted); font-size: .8rem; }
.panel-message > p { margin: .6rem 0; white-space: pre-line; line-height: 1.9; }

/* ---------------------------------------------------------------- «متن و شعر کارت» (script 70)
   One card per text: the words large and airy, a verse in the nastaliq face the card uses, and
   two actions under it - copy, or start a card with it. */

.texts-occasions {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 240px), 1fr));
    gap: 14px;
}

.texts-occasion {
    display: grid;
    gap: 4px;
    align-content: start;
    padding: 20px;
    border-radius: 20px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
    color: var(--dc-ink);
    text-decoration: none;
    transition: transform .2s ease, box-shadow .2s ease;
}

.texts-occasion:hover { transform: translateY(-3px); box-shadow: var(--dc-shadow-lift); }
.texts-occasion .tile-icon { margin-bottom: 8px; }
.texts-occasion .tile-icon svg { width: 24px; height: 24px; }
.texts-occasion-title { font-weight: 700; font-size: 1.02rem; }
.texts-occasion-count { color: var(--dc-brand); font-size: .85rem; font-weight: 600; }
.texts-occasion-sample { margin-top: 6px; color: var(--dc-muted); font-size: .85rem; line-height: 1.9; }

.texts-chips { margin-bottom: 8px; }
.texts-section { margin-block: clamp(28px, 4vw, 48px); }

.text-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr));
    gap: 16px;
}

.text-card {
    display: flex;
    flex-direction: column;
    padding: 24px 22px 18px;
    border-radius: 22px;
    background: var(--dc-surface);
    box-shadow: var(--dc-shadow);
}

/* A verse: centred, on a faint paper tone, like a line on a card. */
.text-card.is-poem {
    text-align: center;
    background: linear-gradient(180deg, #fffdf9 0%, #fbf6ef 100%);
    box-shadow: var(--dc-shadow), inset 0 0 0 1px rgba(184, 146, 90, .18);
}

.text-card-body {
    flex: 1;
    margin: 0;
    white-space: pre-line;
    font-size: 1.02rem;
    line-height: 2.2;
}

.text-card.is-poem .text-card-body { font-size: 1.3rem; line-height: 2.3; color: #3b3326; }
.text-card-poet { margin: 8px 0 0; color: #9a7b4c; font-size: .88rem; }

.text-card-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px solid var(--dc-line);
}

.text-card.is-poem .text-card-actions { justify-content: center; border-top-color: rgba(184, 146, 90, .2); }

.text-card-copy {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 14px;
    border: 0;
    border-radius: 12px;
    background: var(--dc-ground);
    color: var(--dc-ink);
    font: inherit;
    font-size: .85rem;
    cursor: pointer;
    transition: background-color .15s ease, color .15s ease;
}

.text-card-copy .site-icon { width: 17px; height: 17px; }
.text-card-copy:hover { background: var(--dc-brand-soft); color: var(--dc-brand); }
.text-card-copy.is-copied { background: #e6f3ec; color: #2f7a52; }

.text-card-use {
    display: inline-flex;
    align-items: center;
    padding: 8px 16px;
    border-radius: 12px;
    background: var(--dc-brand);
    color: #fff;
    font-size: .85rem;
    font-weight: 700;
    text-decoration: none;
    transition: background-color .15s ease;
}

.text-card-use:hover { background: var(--dc-brand-ink); }

.texts-guide { margin-top: clamp(36px, 5vw, 56px); line-height: 2.1; }
.texts-guide h2 { margin: 0 0 12px; font-size: 1.15rem; color: var(--dc-brand-ink); }
.texts-guide p { margin: 0 0 10px; }

.occasion-texts-link { margin: 4px 0 18px !important; }

.occasion-texts-link a {
    display: inline-flex;
    padding: 8px 16px;
    border-radius: 12px;
    background: var(--dc-brand-soft);
    color: var(--dc-brand-ink);
    font-weight: 600;
    text-decoration: none;
}

/* The editor: the occasion's ready texts, folded under the «متن دعوت» box. */
.ed-texts { margin-top: .4rem; }
.ed-texts > summary { cursor: pointer; font-size: .85rem; color: var(--dc-brand); }
.ed-prose .ed-poem-text { font-size: .88rem; line-height: 1.9; }

/* The panel's «متن‌ها». */
.ptx-filter { display: flex; flex-wrap: wrap; gap: .4rem; margin: 0 0 1rem; }

.ptx-filter a {
    padding: .35rem .8rem;
    border-radius: 999px;
    background: var(--surface);
    box-shadow: inset 0 0 0 1px var(--line);
    color: var(--ink-muted);
    font-size: .85rem;
    text-decoration: none;
}

.ptx-filter a.is-on { background: var(--brand); color: #fff; box-shadow: none; }
.ptx-filter small { opacity: .75; }
.ptx-orphans { align-self: center; color: #ffc0a4; font-size: .8rem; }

.ptx-list { display: grid; gap: .7rem; max-width: 860px; }

.ptx-item {
    padding: .9rem 1rem;
    border-radius: 12px;
    background: var(--surface);
    box-shadow: inset 0 0 0 1px var(--line);
}

.ptx-item.is-off { opacity: .55; }
.ptx-item > header { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; font-size: .8rem; color: var(--ink-muted); }
.ptx-order { margin-inline-start: auto; }
.ptx-text { margin: .6rem 0 .2rem; white-space: pre-line; line-height: 2; }
.ptx-text.card-font-nastaliq { font-size: 1.15rem; }
.ptx-poet { margin: 0; color: var(--ink-muted); font-size: .85rem; }
.ptx-actions { display: flex; flex-wrap: wrap; gap: .4rem; align-items: flex-start; margin-top: .6rem; }
.ptx-edit { flex-basis: 100%; }
.ptx-edit > summary { display: inline-block; cursor: pointer; list-style: none; }
.ptx-edit > summary::-webkit-details-marker { display: none; }

.ptx-form { display: grid; gap: .7rem; margin-top: .7rem; }
.ptx-form label { display: grid; gap: .3rem; font-size: .85rem; }
.ptx-form small { color: var(--ink-muted); }
.ptx-row { display: flex; flex-wrap: wrap; gap: .8rem; align-items: end; }
.ptx-row > label { flex: 1 1 12rem; }
.ptx-sort { flex: 0 1 7rem !important; }
.ptx-kind { display: flex; gap: .8rem; margin: 0; padding: .3rem .6rem; border: 1px solid var(--line); border-radius: 9px; }
.ptx-kind legend { padding: 0 .3rem; font-size: .8rem; color: var(--ink-muted); }
.ptx-kind label { display: inline-flex; gap: .3rem; align-items: center; }

.ptx-form select,
.ptx-form textarea,
.ptx-form input:not([type=checkbox]):not([type=radio]) {
    box-sizing: border-box;
    width: 100%;
    padding: .5rem .7rem;
    border: 1px solid var(--line);
    border-radius: 9px;
    background: var(--surface-2);
    color: var(--ink);
    font: inherit;
    font-size: .88rem;
    line-height: 1.9;
}

.ptx-form textarea { resize: vertical; }

/* ---------------------------------------------------------------- discount codes (script 71) */

/* The plan page's discount code box: its own panel, always open - folded behind a small link it
   went unseen. */
.plan-code {
    margin: 14px 0 18px;
    padding: 16px 18px;
    border: 1.5px dashed color-mix(in srgb, var(--dc-brand) 45%, transparent);
    border-radius: 16px;
    background: var(--dc-brand-soft);
}

.plan-code-title { margin: 0; font-size: 1rem; }
.plan-code-lead { margin: 4px 0 0; color: var(--dc-muted); font-size: .85rem; }
.plan-code-form { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.plan-code-form input {
    flex: 1 1 10rem;
    max-width: 16rem;
    padding: 10px 14px;
    border: 1px solid var(--dc-line);
    border-radius: 12px;
    background: #fff;
    font: inherit;
    letter-spacing: .08em;
    text-transform: uppercase;
}

.plan-code-form input:focus { outline: none; border-color: var(--dc-brand); box-shadow: 0 0 0 4px rgba(47, 93, 112, .12); }
.plan-code-note { margin: 8px 0 0; font-size: .88rem; }
.plan-code-note.is-ok { color: #2f7a52; }
.plan-code-note.is-warned { color: #a8433b; }
.plan-price s { color: var(--dc-muted); margin-inline-end: 6px; }

.plan-code-tag {
    display: inline-block;
    margin-inline-start: 6px;
    padding: 2px 10px;
    border-radius: 999px;
    background: #e6f3ec;
    color: #2f7a52;
    font-size: .8rem;
    font-weight: 600;
}

/* The panel's list of codes. */
.dsc-list { display: grid; gap: .8rem; max-width: 900px; }

.dsc-item {
    padding: 1rem 1.1rem;
    border-radius: 12px;
    background: var(--surface);
    box-shadow: inset 0 0 0 1px var(--line);
}

.dsc-item.is-off { opacity: .6; }
.dsc-item > header { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.dsc-code { font-family: ui-monospace, Consolas, monospace; font-size: 1.15rem; font-weight: 700; letter-spacing: .06em; }

.dsc-percent {
    padding: .1rem .6rem;
    border-radius: 999px;
    background: var(--brand);
    color: #fff;
    font-weight: 700;
    font-size: .85rem;
}

.dsc-note { margin: .5rem 0 0; }
.dsc-facts { margin: .4rem 0 0; color: var(--ink-muted); font-size: .82rem; }
.dsc-hint { margin: 0; color: var(--ink-muted); font-size: .82rem; }
.dsc-hint.is-warned { color: #ffc0a4; }
.dsc-audience { flex-wrap: wrap; }
.dsc-uses { margin: .6rem 0 0; padding-inline-start: 1.1rem; font-size: .85rem; line-height: 2; }
.dsc-uses a { color: var(--ink); }
