/*
| khodkasb - the whole visual layer, hand written.
|
| No Tailwind and no Alpine, and that is a decision rather than a shortcut.
| Tailwind needs a node build step this project does not have; every animation
| on the verify page is imperative anyway (staged fills, a paste that lands one
| digit at a time, six boxes merging into one capsule), which is code, not
| classes. Hand-written CSS plus ~200 lines of vanilla JS costs less than a
| toolchain and adds nothing to the dependency list.
|
| THERE IS NOT ONE COLOUR IN THIS FILE. Every hex code, every channel triplet
| and both typefaces live in tokens.css and this file only ever asks for a role
| - var(--text-muted), not "the grey one". A translucent tint is written as
| rgb(var(--ok-rgb) / .12): the channels come from the token file and only the
| alpha, which is a number rather than a colour, is written here.
|
| The counter that proves this is a plain grep, so the prose above avoids
| writing a literal even as an example. A comment that has to be excluded by
| hand is a comment that will one day be excluded by mistake.
|
| That is what AC-BR-1 counts, and the count has to stay at zero. If a value is
| needed that is not in tokens.css, it is either derivable from what is there or
| it is a brand decision, and a brand decision does not get made inside a
| stylesheet rule at midnight.
*/

/*
| tokens.css is NOT imported here. It is linked in the layout, ahead of this
| file, so the two download in parallel; an @import would make the token file
| wait for this one to arrive before it was even discovered. Every var() below
| resolves because the layout guarantees the order, and any page that links
| this file must link tokens.css first.
*/

/* ----------------------------------------------------------------- base -- */

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

html,
body {
    margin: 0;
    padding: 0;
}

body {
    background: var(--surface);
    color: var(--text);
    font-family: var(--font-body);
    font-size: 16px;
    line-height: 1.7;
    -webkit-text-size-adjust: 100%;
}

/*
| The heading face, applied by element rather than by class.
|
| Every heading in this product is a real h1-h6, so binding the face to the tag
| means a page added next month gets it without anyone remembering a class
| name. The three named classes below are headings that are not tags: the price
| on a card and the figure in a stat block are display type by role.
|
| YekanBakh ships at one weight, 700, and every one of these is already bold -
| so nothing here asks the browser to synthesise a weight it does not have.
*/
h1, h2, h3, h4, h5, h6,
.section__title,
.empty__title,
.stat__num {
    font-family: var(--font-heading);
    font-weight: 700;
}

a {
    color: var(--accent-ink);
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

/* The focus ring is never removed - only made worth looking at. Someone
   navigating by keyboard has to be able to see where they are. */
:focus-visible {
    outline: 2px solid var(--accent-ink);
    outline-offset: 2px;
    border-radius: 4px;
}

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* ------------------------------------------------------------ auth shell -- */

.auth {
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 24px 20px 40px;
    gap: 20px;
}

.auth__card {
    width: 100%;
    max-width: 380px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow);
    padding: 28px 24px;
}

.auth__brand {
    font-size: 22px;
    font-weight: 700;
    text-align: center;
    margin: 0 0 4px;
}

.auth__title {
    font-size: 18px;
    font-weight: 700;
    margin: 0 0 6px;
}

.auth__lead {
    color: var(--text-muted);
    font-size: 14px;
    margin: 0 0 20px;
}

.auth__foot {
    font-size: 13px;
    color: var(--text-muted);
    text-align: center;
    margin: 0;
}

/* ----------------------------------------------------------------- form -- */

.field {
    margin-bottom: 16px;
}

.field__label {
    display: block;
    font-size: 14px;
    font-weight: 700;
    margin-bottom: 8px;
}

.field__input {
    width: 100%;
    height: 52px;
    padding: 0 14px;
    font: inherit;
    font-size: 17px;
    color: var(--text);
    background: var(--surface);
    border: 1.5px solid var(--border);
    border-radius: var(--radius-input);
    transition: border-color var(--fast) var(--ease), background-color var(--fast) var(--ease);
}

.field__input:focus {
    outline: none;
    background: var(--bg);
    border-color: var(--accent-ink);
}

/*
| The ring comes straight back for anyone navigating by keyboard.
|
| The rule above is more specific than the global :focus-visible one, so
| without this line it would win and take the ring away from exactly the people
| who need it. Removing a focus ring is not a style decision.
*/
.field__input:focus-visible {
    outline: 2px solid var(--accent-ink);
    outline-offset: 2px;
}

.field__input--phone {
    /* Digits fill left to right even though the page is right to left.
       A phone number typed into an RTL field puts the leading zero in the
       wrong place and the caret jumps while typing. */
    direction: ltr;
    text-align: left;
    letter-spacing: .06em;
    font-variant-numeric: tabular-nums;
}

.field__input[aria-invalid='true'] {
    border-color: var(--danger);
}

/*
| The error slot is ALWAYS in the layout, empty or not.
|
| An error that appears out of nothing pushes the button down and moves the
| thing the user was about to tap. Reserving the space costs 22 pixels and
| removes a whole class of layout shift (AC-03-V3).
*/
.field__error {
    display: block;
    min-height: 22px;
    font-size: 13px;
    color: var(--danger);
    margin-top: 6px;
    opacity: 0;
    transform: translateY(-4px);
    transition: opacity var(--fast) var(--ease), transform var(--fast) var(--ease);
}

.field__error.is-visible {
    opacity: 1;
    transform: translateY(0);
}

/* --------------------------------------------------------------- button -- */

.btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 52px;
    padding: 0 20px;
    font: inherit;
    font-size: 16px;
    font-weight: 700;
    color: var(--accent-on);
    background: var(--accent);
    border: 0;
    border-radius: var(--radius-pill);
    cursor: pointer;
    transition: transform var(--fast) var(--ease), opacity var(--fast) var(--ease);
}

/* A link wearing the button's clothes must not also wear the link underline. */
a.btn:hover {
    text-decoration: none;
}

.btn:hover:not(:disabled) {
    opacity: .92;
}

.btn:active:not(:disabled) {
    transform: scale(.985);
}

/* aria-disabled as well as disabled: a link cannot carry the attribute the
   browser understands, and a link dressed as a button still has to be able to
   say it is unavailable. */
.btn:disabled,
.btn[aria-disabled='true'] {
    opacity: .5;
    cursor: not-allowed;
}

.btn--ghost {
    color: var(--accent-ink);
    background: transparent;
    border: 1.5px solid var(--border);
}

/*
| The secondary button.
|
| This variant used to be transparent, borderless, grey and 400 weight — which
| is a precise description of a paragraph. The first seller on production
| reported that the panel had "no link to the wallet" and no way into the Bale
| settings. Both existed, both were .btn--quiet, and neither looked like
| anything you could press. Roughly thirty controls across the product had the
| same problem.
|
| So it keeps its job — quieter than the accent button, never competing with
| it — and gets back the two things that make a control a control: an outline
| that says where it begins and ends, and enough weight to read as a label
| rather than as a sentence. Same height family, same radius, same component;
| no new class was invented for the call sites to migrate to, so every one of
| those thirty places was fixed by this rule alone.
|
| 44px, not 40: it is the smallest target a thumb hits reliably, and this is
| the variant that ends up in toolbars and card footers where the misses land.
*/
.btn--quiet {
    min-height: 44px;
    font-size: 14px;
    font-weight: 700;
    color: var(--accent-ink);
    background: var(--bg);
    border: 1.5px solid var(--border-strong);
}

/* The base rule fades on hover; an outlined button has somewhere better to go. */
.btn--quiet:hover:not(:disabled) {
    opacity: 1;
    border-color: var(--accent);
    background: rgb(var(--sky-rgb) / .08);
}

/* Destructive and quiet at once — "لغو سفارش", "حذف". The colour is the
   warning, the outline is what makes it pressable. */
.btn--quiet.btn--danger {
    color: var(--danger);
    border-color: rgb(var(--bad-rgb) / .35);
}

.btn--quiet.btn--danger:hover:not(:disabled) {
    border-color: var(--danger);
    background: rgb(var(--bad-rgb) / .08);
}

/*
| Touch targets. A mouse can hit 38px; a thumb on a moving bus cannot.
| Anything the finger is the only pointer for gets the 44px floor, including
| the small variants that are deliberately compact on a desktop.
*/
@media (pointer: coarse) {
    .btn--sm,
    .btn--quiet {
        min-height: 44px;
    }
}

/*
| Loading state: the label goes transparent and a spinner is laid on top of it.
| The label keeps occupying its space, so the button does not resize and
| nothing around it moves - the requirement in D-61 5.2.
*/
.btn__label {
    transition: opacity var(--fast) var(--ease);
}

.btn.is-loading .btn__label {
    opacity: 0;
}

.btn__spinner {
    position: absolute;
    inset: 0;
    display: none;
    align-items: center;
    justify-content: center;
}

.btn.is-loading .btn__spinner {
    display: flex;
}

.spinner {
    width: 20px;
    height: 20px;
    border: 2.5px solid rgb(var(--ink-rgb) / .3);
    border-top-color: var(--accent-on);
    border-radius: 50%;
    animation: spin 700ms linear infinite;
}

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

/* ------------------------------------------------------------- otp boxes --
| The star of the piece.
|
| The group is LTR inside an RTL page: a code is filled left to right, always.
| The whole thing is one flex row whose gap is animatable, which is what makes
| the merge in step 5 possible without measuring anything in JavaScript.
*/

.otp {
    direction: ltr;
    display: flex;
    justify-content: center;
    gap: 8px;
    margin: 4px 0 14px;
    transition: gap var(--slow) var(--ease);
}

.otp__box {
    width: 46px;
    height: 56px;
    padding: 0;
    font: inherit;
    font-size: 22px;
    font-weight: 700;
    text-align: center;
    color: var(--text);
    background: var(--surface);
    border: 1.5px solid var(--border);
    border-radius: var(--radius-input);
    caret-color: var(--accent-ink);
    font-variant-numeric: tabular-nums;
    transition:
        border-color var(--fast) var(--ease),
        background-color var(--fast) var(--ease),
        border-radius var(--slow) var(--ease),
        width var(--slow) var(--ease),
        transform var(--fast) var(--ease);
}

.otp__box:focus {
    outline: none;
    border-color: var(--accent-ink);
    background: var(--bg);
}

/* Same again for the boxes: pointer focus is shown by the border, keyboard
   focus additionally gets the ring. */
.otp__box:focus-visible {
    outline: 2px solid var(--accent-ink);
    outline-offset: 2px;
}

/* Step 1: the boxes arrive one after another, 40ms apart. The delay is set
   inline per box by the template so this stays one rule. */
.otp__box {
    animation: otp-in var(--slow) var(--ease) both;
}

@keyframes otp-in {
    from {
        opacity: 0;
        transform: translateY(10px);
    }

    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* Step 2: a digit lands. */
.otp__box.is-filled {
    border-color: var(--accent-ink);
}

.otp__box.is-pop {
    animation: otp-pop 180ms var(--ease);
}

@keyframes otp-pop {
    0% {
        transform: scale(1);
    }

    55% {
        transform: scale(1.06);
    }

    100% {
        transform: scale(1);
    }
}

/* The anchor for the capsule that covers the row while the code is checked. */
.otp__wrap {
    position: relative;
}

/*
| Step 5: six boxes become one capsule.
|
| The gap goes to zero, every box narrows, the corners round off to a pill and
| the whole row reads as a single object with a spinner in it. Only the
| container class changes; the boxes follow because their own transition
| already covers width and border-radius.
*/
.otp.is-merging {
    gap: 0;
}

.otp.is-merging .otp__box {
    width: 34px;
    border-radius: 0;
    border-inline-color: transparent;
    background: var(--surface);
    color: transparent;
}

.otp.is-merging .otp__box:first-child {
    border-start-start-radius: var(--radius-pill);
    border-end-start-radius: var(--radius-pill);
    border-inline-start-color: var(--border);
}

.otp.is-merging .otp__box:last-child {
    border-start-end-radius: var(--radius-pill);
    border-end-end-radius: var(--radius-pill);
    border-inline-end-color: var(--border);
}

.otp__capsule {
    position: absolute;
    inset: 0;
    display: none;
    align-items: center;
    justify-content: center;
}

.otp__wrap.is-busy .otp__capsule,
.otp__wrap.is-done .otp__capsule {
    display: flex;
}

.otp__capsule .spinner {
    border-color: rgb(var(--sky-rgb) / .4);
    border-top-color: var(--accent-ink);
}

/* Step 6: it worked. */
.otp.is-done .otp__box {
    border-color: var(--success);
    background: rgb(var(--ok-rgb) / .08);
}

.otp__tick {
    width: 26px;
    height: 26px;
    stroke: var(--success);
    stroke-width: 3;
    stroke-linecap: round;
    stroke-linejoin: round;
    fill: none;
}

.otp__tick path {
    stroke-dasharray: 32;
    stroke-dashoffset: 32;
}

.otp__wrap.is-done .otp__tick path {
    animation: tick-draw var(--slow) var(--ease) forwards;
}

@keyframes tick-draw {
    to {
        stroke-dashoffset: 0;
    }
}

/* Step 7: it did not. Three shakes, six pixels. */
.otp.is-error .otp__box {
    border-color: var(--danger);
    background: rgb(var(--bad-rgb) / .06);
}

.otp.is-shaking {
    animation: shake 360ms var(--ease);
}

@keyframes shake {
    0%, 100% {
        transform: translateX(0);
    }

    16% {
        transform: translateX(-6px);
    }

    33% {
        transform: translateX(6px);
    }

    50% {
        transform: translateX(-6px);
    }

    66% {
        transform: translateX(6px);
    }

    83% {
        transform: translateX(-3px);
    }
}

/* ------------------------------------------------------------- countdown --
| A ring around the resend button that fills over 60 seconds. The dash offset
| is driven from JS; without JS the ring is simply not drawn and the button
| behaves like a button - the server refuses an early resend anyway.
*/

.resend {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    margin-top: 6px;
}

.resend__ring {
    position: relative;
    width: 34px;
    height: 34px;
    flex: 0 0 34px;
}

.resend__ring svg {
    width: 100%;
    height: 100%;
    transform: rotate(-90deg);
}

.resend__ring circle {
    fill: none;
    stroke-width: 2.5;
}

.resend__ring .track {
    stroke: var(--border);
}

.resend__ring .progress {
    stroke: var(--accent-ink);
    stroke-linecap: round;
    transition: stroke-dashoffset 1s linear;
}

.resend__seconds {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------- notes -- */

.note {
    font-size: 13px;
    color: var(--text-muted);
    text-align: center;
    margin: 12px 0 0;
}

.note--success {
    color: var(--success);
}

.dev-code {
    margin: 0 0 16px;
    padding: 10px 12px;
    font-size: 13px;
    text-align: center;
    color: var(--text);
    background: rgb(var(--warn-rgb) / .12);
    border: 1px dashed rgb(var(--warn-rgb) / .45);
    border-radius: var(--radius-input);
}

.dev-code strong {
    font-size: 18px;
    letter-spacing: .2em;
    direction: ltr;
    display: inline-block;
}

/* ------------------------------------------------------- "no code came" --
| A numbered list, because the four checks are in the order that resolves the
| problem most often and the numbers say "start at the top".
*/

.help {
    margin: 0 0 24px;
    padding-inline-start: 22px;
    font-size: 14px;
    line-height: 1.9;
    color: var(--text-muted);
}

.help li + li {
    margin-top: 12px;
}

.help strong {
    color: var(--text);
}

/* ---------------------------------------------------------------- panel -- */

.panel {
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    background: var(--surface);
}

.panel__header {
    position: sticky;
    top: 0;
    z-index: 10;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    height: 60px;
    padding: 0 16px;
    background: var(--bg);
    border-bottom: 1px solid var(--border);
}

.panel__brand {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 700;
}

.panel__brand img {
    display: block;
    width: 28px;
    height: 28px;
}

.panel__user {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 14px;
    color: var(--text-muted);
}

/* The sign-out button sits in a row, so it is sized by its text rather than
   taking the full width every other button in this product has. */
.panel__user .btn {
    width: auto;
    padding: 0 12px;
}

.panel__body {
    flex: 1;
    width: 100%;
    max-width: 900px;
    margin: 0 auto;
    padding: 20px 16px 92px;
}

.panel__nav {
    position: fixed;
    inset-inline: 0;
    bottom: 0;
    display: flex;
    background: var(--bg);
    border-top: 1px solid var(--border);
    padding: 6px 4px calc(6px + env(safe-area-inset-bottom));
}

/*
| "بیشتر" is a <button> and the rest are <a>, because one opens a panel on this
| page and the others go somewhere. They have to be indistinguishable to the
| eye and different to the machine, so the shape rules name both and the button
| gives back the appearance a <button> starts with.
*/
.panel__nav a,
.panel__nav-more {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    padding: 6px 0;
    font: inherit;
    font-size: 11px;
    color: var(--text-muted);
    background: none;
    border: 0;
    border-radius: var(--radius-input);
    cursor: pointer;
}

.panel__nav a:hover,
.panel__nav-more:hover {
    text-decoration: none;
    background: var(--surface);
}

/*
| Two attributes for one appearance. A link on the page it points at says
| aria-current="page"; "بیشتر" is not a page, so it says data-current instead —
| lying to a screen reader about which page it is on would be worse than the
| bar looking unlit.
*/
.panel__nav a[aria-current='page'],
.panel__nav-more[data-current='true'] {
    color: var(--accent-ink);
    font-weight: 700;
}

/* Phone: the extra items live in the sheet, so the flat copies of them and the
   divider that separates them are not in the document's box tree at all.

   Written through .panel__nav so it outranks the shape rule above, which is a
   class plus an element and would otherwise put display:flex back. */
.panel__nav .panel__nav-rule,
.panel__nav .panel__nav-extra {
    display: none;
}

.panel__nav svg {
    width: 22px;
    height: 22px;
    stroke: currentColor;
    stroke-width: 1.8;
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
}

@media (min-width: 860px) {
    .panel {
        flex-direction: row;
    }

    .panel__nav {
        position: sticky;
        top: 0;
        inset-inline: auto;
        bottom: auto;
        flex-direction: column;
        width: 220px;
        height: 100dvh;
        padding: 16px 12px;
        border-top: 0;
        border-inline-start: 1px solid var(--border);
        gap: 4px;
    }

    .panel__nav a {
        flex: 0 0 auto;
        flex-direction: row;
        justify-content: flex-start;
        gap: 10px;
        padding: 10px 12px;
        font-size: 14px;
    }

    /*
    | The column has the height for the whole list, so it shows the whole list.
    | A desktop seller reaching their wallet through a sheet designed for a
    | thumb would be the mobile pattern leaking upward.
    */
    .panel__nav-more {
        display: none;
    }

    .panel__nav .panel__nav-rule {
        display: block;
        flex: 0 0 auto;
        height: 1px;
        margin: 8px 12px;
        background: var(--border);
    }

    .panel__nav .panel__nav-extra {
        display: flex;
    }

    .panel__main {
        flex: 1;
        min-width: 0;
    }

    .panel__body {
        padding-bottom: 40px;
    }
}

.card {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    padding: 20px;
}

/* --------------------------------------------------------- empty state -- */

.empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 36px 20px 32px;
}

.empty svg {
    width: 132px;
    height: 108px;
    margin-bottom: 18px;
}

/*
| The drawing in an empty state, in three inks.
|
| These used to be three hex codes typed into the SVG, which is exactly the
| place AC-BR-1 says a colour may not live: a stroke attribute in a Blade file
| is a colour nobody grepping the stylesheet will ever find. The markup now
| names a role - outline, faint, accent - and the roles resolve here.
|
| The outline is deliberately the mid grey and not the text colour. The picture
| is the quietest thing in an empty state; the sentence under it is the loudest.
*/
.empty__art {
    stroke: var(--ink-400);
}

.empty__art .art--faint {
    stroke: var(--border);
}

.empty__art .art--accent {
    stroke: var(--accent-ink);
}

.empty__title {
    font-size: 18px;
    font-weight: 700;
    margin: 0 0 6px;
}

.empty__text {
    max-width: 380px;
    color: var(--text-muted);
    font-size: 14px;
    margin: 0 0 20px;
}

.empty .btn {
    width: auto;
    min-width: 200px;
}

/* ---------------------------------------------------- modern auth theme --
| A dark, tactile interpretation of the supplied OTP reference. The numeric
| orb is CSS/HTML rather than a raster asset, so it remains crisp and costs no
| network request. Product logic and the no-script form remain untouched.
*/

.auth {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    color-scheme: dark;
    background:
        radial-gradient(circle at 50% -12%, rgb(var(--teal-rgb) / .13), transparent 34%),
        radial-gradient(circle at 8% 92%, rgb(var(--sky-rgb) / .13), transparent 30%),
        var(--ink-950);
}

.auth::before {
    content: '';
    position: absolute;
    z-index: -2;
    inset: 0;
    opacity: .16;
    background-image:
        linear-gradient(rgb(var(--paper-rgb) / .025) 1px, transparent 1px),
        linear-gradient(90deg, rgb(var(--paper-rgb) / .025) 1px, transparent 1px);
    background-size: 34px 34px;
    mask-image: linear-gradient(to bottom, rgb(var(--black-rgb) / 1), transparent 78%);
}

.auth__ambient {
    position: absolute;
    z-index: -1;
    width: 280px;
    aspect-ratio: 1;
    border-radius: 50%;
    filter: blur(90px);
    opacity: .14;
    pointer-events: none;
}

.auth__ambient--one {
    inset: 10% auto auto -150px;
    background: var(--teal-400);
}

.auth__ambient--two {
    inset: auto -170px 4% auto;
    background: var(--sky-500);
}

.auth__card {
    position: relative;
    max-width: 440px;
    overflow: hidden;
    color: var(--ink-050);
    background: linear-gradient(145deg, var(--ink-870), var(--ink-930));
    border: 1px solid rgb(var(--paper-rgb) / .1);
    border-radius: 30px;
    box-shadow:
        0 32px 80px rgb(var(--black-rgb) / .46),
        inset 0 1px 0 rgb(var(--paper-rgb) / .055);
    padding: 34px 32px 30px;
}

.auth__card::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    background: linear-gradient(135deg, rgb(var(--paper-rgb) / .045), transparent 36%);
}

.auth__brand {
    position: relative;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    color: var(--ink-050);
    font-size: 15px;
    letter-spacing: -.02em;
    margin-bottom: 24px;
}

/*
| The mark is a link home now. `.auth a` paints links teal, which is right for
| the terms line under the form and wrong for the wordmark, so this puts the
| brand's own colour back and gives it a focus ring - it is the first thing in
| the tab order on this screen.
*/
.auth .auth__home {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    /* Written with the .auth prefix on purpose: `.auth a` below is (0,1,1) and
       would otherwise win over a bare .auth__home and paint the wordmark
       teal. */
    color: var(--ink-050);
    border-radius: var(--radius-sm);
}

.auth .auth__home:hover {
    text-decoration: none;
    opacity: .85;
}

.auth .auth__home:focus-visible {
    outline: 2px solid var(--teal-300);
    outline-offset: 4px;
}

/*
| The mark on the dark sign-in screen.
|
| A soft halo behind it, not a border around it: the artwork already has its
| own edges, and a ring drawn on top of a logo reads as a badge rather than a
| brand. The glow is what keeps a dark-on-dark shape from disappearing into the
| --ink-950 background.
*/
.auth__brand-mark {
    width: 26px;
    height: 26px;
    display: block;
    filter: drop-shadow(0 0 14px rgb(var(--teal-rgb) / .35));
}

.auth__title {
    position: relative;
    z-index: 1;
    color: var(--paper);
    font-size: clamp(23px, 6vw, 30px);
    line-height: 1.35;
    text-align: center;
    letter-spacing: -.04em;
    margin-bottom: 8px;
}

.auth__lead {
    position: relative;
    z-index: 1;
    max-width: 340px;
    color: var(--ink-400);
    font-size: 14px;
    line-height: 1.85;
    text-align: center;
    margin: 0 auto 25px;
}

.auth a {
    color: var(--teal-300);
}

.auth .field__label {
    color: var(--ink-200);
    font-size: 13px;
}

.auth .field__input {
    color: var(--paper);
    background: rgb(var(--paper-rgb) / .055);
    border-color: rgb(var(--paper-rgb) / .1);
    box-shadow: inset 0 1px 0 rgb(var(--paper-rgb) / .025);
}

.auth .field__input::placeholder {
    color: var(--ink-500);
}

.auth .field__input:focus {
    background: rgb(var(--paper-rgb) / .075);
    border-color: var(--teal-400);
    box-shadow: 0 0 0 4px rgb(var(--teal-rgb) / .1), 0 0 25px rgb(var(--teal-rgb) / .08);
}

.auth .field__input:focus-visible,
.auth .otp__box:focus-visible {
    outline-color: var(--teal-200);
}

.auth .btn {
    color: var(--ink-950);
    background: linear-gradient(135deg, var(--teal-300), var(--teal-400));
    box-shadow: 0 10px 30px rgb(var(--teal-rgb) / .18), inset 0 1px 0 rgb(var(--paper-rgb) / .55);
}

.auth .btn:hover:not(:disabled) {
    opacity: 1;
    transform: translateY(-1px);
    box-shadow: 0 14px 36px rgb(var(--teal-rgb) / .25), inset 0 1px 0 rgb(var(--paper-rgb) / .6);
}

.auth .btn--quiet {
    color: var(--ink-300);
    background: transparent;
    box-shadow: none;
}

.auth .btn--quiet:hover:not(:disabled) {
    color: var(--teal-300);
    transform: none;
    box-shadow: none;
}

.auth .note,
.auth__foot {
    color: var(--ink-400);
}

/*
| The number sphere from the supplied reference.
|
| Everything that makes it a sphere - the spherical placement, the perspective
| projection and the per-digit depth - is done per frame in orb.js on the
| canvas. This file only reserves the box, puts a faint glow behind it and lets
| the whole thing breathe. Nothing here fakes depth, because faking it is
| exactly what the flat ring did.
*/
.otp-orb {
    position: relative;
    z-index: 1;
    width: 180px;
    height: 180px;
    margin: -10px auto 14px;
    animation: orb-float 5.6s ease-in-out infinite;
}

/* Behind the digits, not on them: an atmosphere so the ball sits in the card
   rather than floating on top of it. */
.otp-orb::before {
    content: '';
    position: absolute;
    inset: -12%;
    border-radius: 50%;
    background: radial-gradient(circle at 50% 46%,
        rgb(var(--teal-rgb) / .11) 0,
        rgb(var(--teal-rgb) / .045) 36%,
        rgb(var(--ink-rgb) / 0) 68%);
    pointer-events: none;
}

.otp-orb__canvas {
    position: relative;
    display: block;
    width: 100%;
    height: 100%;
}

@keyframes orb-float {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-5px); }
}

.auth .otp {
    gap: 8px;
    margin: 8px 0 14px;
}

.auth .otp__box {
    width: 50px;
    height: 58px;
    color: var(--ink-050);
    background: rgb(var(--paper-rgb) / .055);
    border: 2px solid transparent;
    border-radius: 13px;
    box-shadow: inset 0 0 0 1px rgb(var(--paper-rgb) / .055), 0 8px 18px rgb(var(--black-rgb) / .14);
    caret-color: transparent;
}

.auth .otp__box:focus,
.auth .otp__box.is-filled {
    background: rgb(var(--paper-rgb) / .075);
    border-color: var(--teal-400);
    box-shadow: 0 0 0 3px rgb(var(--teal-rgb) / .08), 0 0 25px rgb(var(--teal-rgb) / .09);
}

.auth .otp.is-merging .otp__box {
    background: rgb(var(--paper-rgb) / .075);
}

.auth .otp.is-done .otp__box {
    border-color: var(--teal-400);
    background: rgb(var(--teal-rgb) / .09);
}

.auth .otp__capsule .spinner {
    border-color: rgb(var(--teal-rgb) / .2);
    border-top-color: var(--teal-300);
}

.auth .otp__tick {
    stroke: var(--teal-300);
    filter: drop-shadow(0 0 7px rgb(var(--teal-rgb) / .5));
}

.auth .otp.is-error .otp__box {
    border-color: var(--bad-lift);
    background: rgb(var(--bad-rgb) / .08);
    box-shadow: 0 0 20px rgb(var(--bad-rgb) / .08);
}

.auth .resend__ring .track {
    stroke: rgb(var(--paper-rgb) / .1);
}

.auth .resend__ring .progress {
    stroke: var(--teal-400);
}

.auth .resend__seconds {
    color: var(--ink-300);
}

@media (max-width: 430px) {
    .auth {
        justify-content: flex-start;
        padding: 18px 12px 28px;
    }

    .auth__card {
        margin-top: max(12px, 5vh);
        padding: 28px 18px 24px;
        border-radius: 26px;
    }

    .auth__brand {
        margin-bottom: 20px;
    }

    .otp-orb {
        width: 156px;
        height: 156px;
        margin-bottom: 10px;
    }

    .auth .otp {
        gap: 4px;
    }

    .auth .otp__box {
        width: clamp(36px, 11.5vw, 48px);
        height: 55px;
        font-size: 20px;
    }
}

/* ============================================================ piece four ==
| The shop, the product list and the public page.
|
| Everything below is built out of the tokens and the shapes already declared
| above - the same radii, the same border colour, the same pill button. Nothing
| here introduces a second look for the same kind of object, because a panel
| whose pages were each designed on their own day is a panel that feels like
| four products.
*/

/* -------------------------------------------------------- section heads -- */

.section__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 16px;
}

.section__head .btn {
    width: auto;
    min-height: 44px;
    font-size: 14px;
}

.section__title {
    font-size: 18px;
    font-weight: 700;
    margin: 0 0 6px;
}

.section__lead {
    color: var(--text-muted);
    font-size: 14px;
    line-height: 1.8;
    margin: 0 0 18px;
}

.card + .card {
    margin-top: 16px;
}

/* --------------------------------------------------------- form extras -- */

.field__hint {
    font-size: 12.5px;
    color: var(--text-muted);
    line-height: 1.7;
    margin: -2px 0 0;
}

.field__optional {
    font-weight: 400;
    color: var(--text-muted);
}

/* A value that is shown but cannot be typed into. Deliberately NOT a disabled
   input: a greyed-out box still looks like a field somebody could enable. */
.field__static {
    font-size: 17px;
    font-variant-numeric: tabular-nums;
    margin: 0 0 4px;
}

.field__input--area {
    min-height: 92px;
    padding: 12px 14px;
    line-height: 1.9;
    resize: vertical;
}

.field-pair {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0 12px;
}

/* -------------------------------------------------------- the slug box --
| The address is shown as an address: the fixed part in front, the part the
| seller chooses after it, inside one frame so it reads as a single thing.
|
| The frame carries the focus state instead of the input, which is why the
| input's own border is removed here - two nested outlines on one control is a
| box inside a box.
*/

.slugbox {
    display: flex;
    align-items: center;
    gap: 2px;
    padding-inline-start: 12px;
    background: var(--surface);
    border: 1.5px solid var(--border);
    border-radius: var(--radius-input);
    transition: border-color var(--fast) var(--ease), background-color var(--fast) var(--ease);
    overflow: hidden;
}

.slugbox:focus-within {
    background: var(--bg);
    border-color: var(--accent-ink);
    /*
    | The ring belongs to the box, not to the input inside it.
    |
    | The input has no border of its own - the address prefix and the field
    | look like one control, so a ring drawn around the input alone would cut
    | the control in half. It is drawn here instead, at the same 2px the rest
    | of the panel uses, so a keyboard user gets the same indicator everywhere
    | rather than a slightly bluer border here.
    */
    outline: 2px solid var(--accent-ink);
    outline-offset: 2px;
}

.slugbox.is-locked {
    opacity: .75;
}

.slugbox__prefix {
    flex: 0 0 auto;
    font-size: 13px;
    color: var(--text-muted);
    white-space: nowrap;
    user-select: all;
}

.slugbox__input {
    flex: 1 1 auto;
    min-width: 0;
    padding-inline: 2px 12px;
    font-size: 16px;
    background: transparent;
    border: 0;
    border-radius: 0;
}

.slugbox__input:focus,
.slugbox__input:focus-visible {
    background: transparent;
    border: 0;
    outline: none;
}

/* The verdict light. One element, three states, and it is never the only
   channel: the sentence under the field says the same thing in words. */
.slugbox__state {
    flex: 0 0 auto;
    width: 10px;
    height: 10px;
    margin-inline-end: 12px;
    border-radius: 50%;
    background: transparent;
    transition: background-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}

.slugbox__state.is-checking {
    background: var(--border);
    animation: slugpulse 1s var(--ease) infinite;
}

.slugbox__state.is-free {
    background: var(--success);
    box-shadow: 0 0 0 4px rgb(var(--ok-rgb) / .14);
}

.slugbox__state.is-taken {
    background: var(--danger);
    box-shadow: 0 0 0 4px rgb(var(--bad-rgb) / .14);
}

@keyframes slugpulse {
    50% { opacity: .35; }
}

/* The live verdict borrows the error slot, so it needs a green voice too. */
.field__error.is-ok {
    color: var(--success);
}

/* ----------------------------------------------------- badges and stats -- */

.badge {
    display: inline-flex;
    align-items: center;
    height: 24px;
    padding: 0 10px;
    font-size: 12px;
    font-weight: 700;
    border-radius: var(--radius-pill);
    white-space: nowrap;
}

.badge--live {
    color: var(--ok-ink);
    background: rgb(var(--ok-rgb) / .12);
}

.badge--draft {
    color: var(--text-muted);
    background: var(--surface);
    box-shadow: inset 0 0 0 1px var(--border);
}

.badge--warn {
    color: var(--warn-ink2);
    background: rgb(var(--warn-rgb) / .14);
}

.stat-row {
    display: flex;
    gap: 10px;
    margin: 18px 0;
}

.stat {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 14px;
    background: var(--surface);
    border-radius: var(--radius-input);
}

.stat__num {
    font-size: 22px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.stat__label {
    font-size: 12.5px;
    color: var(--text-muted);
}

/* ------------------------------------------------------- the shop head -- */

.store-head__row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

.store-head__name {
    font-size: 20px;
    font-weight: 700;
    margin: 0 0 4px;
}

.store-head__addr {
    font-size: 13px;
    color: var(--text-muted);
    margin: 0;
    word-break: break-all;
}

.store-head__actions {
    display: flex;
    gap: 10px;
}

.store-head__actions .btn {
    width: auto;
    flex: 1;
    min-height: 46px;
    font-size: 14px;
}

.kv {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 0;
    margin: 0;
    font-size: 14px;
    border-bottom: 1px solid var(--border);
}

.kv:last-of-type {
    border-bottom: 0;
    margin-bottom: 8px;
}

.kv__key {
    color: var(--text-muted);
}

.kv__val {
    word-break: break-all;
}

/* ------------------------------------------------------- notes, louder -- */

.note--warn {
    color: var(--warn-ink);
    background: rgb(var(--warn-rgb) / .1);
    border-radius: var(--radius-input);
    padding: 10px 12px;
    text-align: start;
    line-height: 1.9;
}

.note--error {
    color: var(--danger);
    background: rgb(var(--bad-rgb) / .08);
    border-radius: var(--radius-input);
    padding: 10px 12px;
    text-align: start;
}

/* ------------------------------------------------------ the switch row -- */

.switch {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 4px 0 20px;
    cursor: pointer;
    user-select: none;
}

/* The real checkbox stays in the page and stays focusable - it is only made
   invisible. Replacing it with a div would take the control away from the
   keyboard and from every screen reader. */
.switch input[type='checkbox'] {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.switch__track {
    position: relative;
    flex: 0 0 auto;
    width: 44px;
    height: 26px;
    background: var(--border);
    border-radius: var(--radius-pill);
    transition: background-color var(--fast) var(--ease);
}

.switch__dot {
    position: absolute;
    top: 3px;
    inset-inline-start: 3px;
    width: 20px;
    height: 20px;
    background: var(--paper);
    border-radius: 50%;
    box-shadow: 0 1px 3px rgb(var(--ink-rgb) / .25);
    transition: transform var(--fast) var(--ease);
}

.switch input:checked + .switch__track {
    background: var(--accent);
}

/* Logical, not left: in RTL the dot has to travel the other way. */
.switch input:checked + .switch__track .switch__dot {
    transform: translateX(-18px);
}

[dir='ltr'] .switch input:checked + .switch__track .switch__dot {
    transform: translateX(18px);
}

.switch input:focus-visible + .switch__track {
    outline: 2px solid var(--accent-ink);
    outline-offset: 3px;
}

.switch__text {
    font-size: 14px;
}

/* ------------------------------------------------------ the product list -- */

.plist {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.plist__item {
    display: grid;
    grid-template-columns: 72px 1fr;
    gap: 12px;
    padding: 12px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
}

/* An inactive product is dimmed, but its text keeps full contrast - the state
   is carried by the badge, not by making the name hard to read. */
.plist__item.is-off .plist__thumb {
    opacity: .5;
}

.plist__thumb {
    display: block;
    width: 72px;
    height: 72px;
    border-radius: var(--radius-input);
    overflow: hidden;
    background: var(--surface);
}

.plist__thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.plist__nothumb {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    color: var(--text-muted);
}

.plist__nothumb svg {
    width: 26px;
    height: 26px;
}

.plist__body {
    min-width: 0;
}

.plist__name {
    display: block;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 4px;
    overflow-wrap: anywhere;
}

.plist__price {
    font-size: 14px;
    font-weight: 700;
    color: var(--text);
    font-variant-numeric: tabular-nums;
    margin: 0 0 8px;
}

.plist__tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.plist__side {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 8px;
    padding-top: 10px;
    border-top: 1px solid var(--border);
}

.btn--sm {
    width: auto;
    min-height: 38px;
    padding: 0 14px;
    font-size: 13px;
}

.btn--danger {
    color: var(--danger);
}

.stockform {
    display: flex;
    align-items: center;
    gap: 8px;
}

.stockform__label {
    font-size: 12.5px;
    color: var(--text-muted);
}

.stockform__input {
    width: 68px;
    height: 38px;
    padding: 0 10px;
    font: inherit;
    font-size: 15px;
    text-align: center;
    font-variant-numeric: tabular-nums;
    color: var(--text);
    background: var(--surface);
    border: 1.5px solid var(--border);
    border-radius: var(--radius-input);
}

.stockform__input:focus {
    outline: none;
    background: var(--bg);
    border-color: var(--accent-ink);
}

/* Taken away above for the mouse, handed straight back for the keyboard. */
.stockform__input:focus-visible {
    outline: 2px solid var(--accent-ink);
    outline-offset: 2px;
}

@media (min-width: 640px) {
    .plist__item {
        grid-template-columns: 72px 1fr auto;
        align-items: center;
    }

    .plist__side {
        grid-column: auto;
        align-items: center;
        padding-top: 0;
        border-top: 0;
    }
}

/* ------------------------------------------------------------- the pager -- */

.pager__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-top: 18px;
}

.pager__btn {
    display: inline-flex;
    align-items: center;
    height: 40px;
    padding: 0 14px;
    font-size: 13.5px;
    color: var(--accent-ink);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
}

.pager__btn:hover {
    text-decoration: none;
}

.pager__btn.is-off {
    color: var(--text-muted);
    opacity: .5;
}

.pager__at {
    font-size: 12.5px;
    color: var(--text-muted);
}

/* ---------------------------------------------------------------- photos -- */

.shots {
    list-style: none;
    margin: 0 0 16px;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 12px;
}

.shots__item {
    position: relative;
    padding: 8px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    transition: transform var(--fast) var(--ease), opacity var(--fast) var(--ease);
}

.shots__item img {
    display: block;
    width: 100%;
    aspect-ratio: 1;
    object-fit: cover;
    border-radius: var(--radius-input);
    background: var(--bg);
}

/* The one being dragged, and the gap it will drop into. */
.shots__item.is-dragging {
    opacity: .4;
}

.shots__item.is-over {
    transform: scale(1.02);
    box-shadow: 0 0 0 2px var(--accent-ink);
}

.shots__cover {
    position: absolute;
    top: 14px;
    inset-inline-start: 14px;
    height: 22px;
    display: inline-flex;
    align-items: center;
    padding: 0 8px;
    font-size: 11px;
    font-weight: 700;
    color: var(--accent-on);
    background: var(--accent);
    border-radius: var(--radius-pill);
}

.shots__acts {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 8px;
}

.shots__acts .btn {
    flex: 1;
    min-height: 34px;
    padding: 0 8px;
    font-size: 12px;
}

/* ---------------------------------------------------------------- upload -- */

.upload {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* The whole dashed area is the label, so tapping anywhere in it opens the
   picker. The file input inside is hidden but still present and still
   focusable. */
.upload__drop {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    min-height: 96px;
    padding: 16px;
    text-align: center;
    background: var(--surface);
    border: 1.5px dashed var(--border);
    border-radius: var(--radius-card);
    cursor: pointer;
    transition: border-color var(--fast) var(--ease), background-color var(--fast) var(--ease);
}

.upload__drop:hover {
    border-color: var(--accent-ink);
}

.upload__drop input[type='file'] {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
}

.upload__drop:focus-within {
    border-color: var(--accent-ink);
    background: var(--bg);
}

.upload__text {
    font-size: 15px;
    font-weight: 700;
    color: var(--accent-ink);
}

.upload__hint {
    font-size: 12.5px;
    color: var(--text-muted);
}

/* Filled in by the script once a file is chosen, so the name of the file is
   visible before the upload rather than after it. */
.upload__drop.is-picked .upload__text {
    color: var(--text);
    overflow-wrap: anywhere;
}

/* ----------------------------------------------------- the public page --
| The shopfront and the product page - F-04, and the two screens a customer
| ever sees. They are deliberately plain: the shop's own name is the largest
| thing on the page and the platform's mark is small and at the bottom. This
| page belongs to the seller, not to us.
|
| THERE IS NO JAVASCRIPT BEHIND ANY OF THIS. The grid is CSS grid, the gallery
| is the browser's own overflow scrolling with scroll snapping, and every
| control is an anchor. A customer with a blocked script, a slow connection or
| an old phone gets the whole page, because the whole page is markup.
|
| Everything is sized from the 360px phone up. AC-04-5 is not a media query
| added at the end - it is the width the layout is written at, with the wider
| screens getting more columns rather than the narrow one getting a special
| case. Anything that could push past the viewport (a long product name, a
| pasted description, a shop name with no spaces in it) carries
| overflow-wrap: anywhere.
*/

.shop {
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 24px;
    padding: 32px 16px 40px;
    background: var(--surface);
}

.shop__head {
    width: 100%;
    max-width: 900px;
    text-align: center;
}

.storebar {
    width: 100%;
    max-width: 900px;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    margin: 0 auto 22px;
}

.shop > .storebar {
    margin-bottom: 0;
}

.storebar__account,
.storebar__notifications {
    min-height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 7px 11px;
    color: var(--text);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    font-size: 13px;
    font-weight: 700;
    transition: border-color var(--fast) var(--ease);
}

.storebar__account:hover,
.storebar__notifications:hover {
    text-decoration: none;
    border-color: var(--accent-ink);
}

.storebar svg {
    width: 18px;
    height: 18px;
    flex: none;
}

.shop__head--tight {
    text-align: start;
}

.shop__name {
    font-size: clamp(22px, 6vw, 28px);
    font-weight: 700;
    margin: 0 0 8px;
    letter-spacing: -.02em;
    overflow-wrap: anywhere;
}

.shop__about {
    max-width: 520px;
    margin: 0 auto;
    color: var(--text-muted);
    font-size: 15px;
    line-height: 1.9;
    overflow-wrap: anywhere;
}

/* The seller's number. On the phone this shop is opened on, tapping it dials -
   so it is a target with real padding, not a line of text with a link in it. */
.shop__call {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-top: 14px;
    padding: 8px 14px;
    font-size: 14px;
    font-weight: 700;
    color: var(--accent-ink);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
}

.shop__call:hover {
    text-decoration: none;
    border-color: var(--accent-ink);
}

.shop__call svg {
    width: 16px;
    height: 16px;
    flex: none;
}

.shop__back {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 14px;
    color: var(--text-muted);
    overflow-wrap: anywhere;
}

/* The chevron points the way back, which in RTL is to the right. */
.shop__back svg {
    width: 18px;
    height: 18px;
    flex: none;
}

/* D-14/D-17: the demo shop says on its own face that it is a demo. A visitor
   must never have to work out whether these products are real. */
.shop__demo {
    width: 100%;
    max-width: 900px;
    margin: 0;
    padding: 12px 14px;
    font-size: 13px;
    line-height: 1.9;
    color: var(--warn-ink);
    background: rgb(var(--warn-rgb) / .1);
    border-radius: var(--radius-input);
    text-align: center;
}

/* It grew from one <p> into a notice with a way out of it, so the box owns the
   spacing now and the paragraphs give theirs up. */
.shop__demo > p {
    margin: 0;
}

.shop__demo > p + p {
    margin-top: 4px;
}

/* Deliberately a text link and not a .btn. This sits on a page whose job is to
   show somebody a shopfront; a second full-weight button competing with the
   product grid would be selling over the top of the demonstration. */
.shop__demo-cta {
    display: inline-block;
    margin-top: 8px;
    font-weight: 700;
    color: var(--warn-ink);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.shop__demo-cta:focus-visible {
    outline: 2px solid var(--warn-ink);
    outline-offset: 3px;
    border-radius: var(--radius-input);
}

.shop__main {
    width: 100%;
    max-width: 900px;
}

/* The "coming soon" panel. It has exactly two callers left - a draft shop and
   a published shop with nothing in it - and on a published shop with an active
   product it must not render at all. That count reaching zero is the proof
   this piece shipped rather than merely added. */
.shop__panel {
    width: 100%;
    max-width: 460px;
    margin: 0 auto;
    padding: 28px 20px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    text-align: center;
}

.shop__soon {
    font-size: 15px;
    margin: 0;
}

.shop__soonsub {
    font-size: 13.5px;
    color: var(--text-muted);
    margin: 8px 0 0;
}

.shop__foot {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: auto;
    padding-top: 16px;
    font-size: 12.5px;
    color: var(--text-muted);
}

.shop__foot a {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    color: var(--text-muted);
}

.shop__foot img {
    display: block;
    opacity: .85;
}

/* ------------------------------------------------------ the product grid --
| Two columns at 360px and as many as fit after that.
|
| auto-fill with a minmax floor is what keeps this from needing breakpoints:
| the browser decides the column count from the space it actually has, so a
| 360px phone, a 412px phone and a tablet are all the same rule. The floor is
| 140px because two of them plus the gap and the page padding is 328px, which
| leaves room inside 360 rather than exactly filling it.
*/

.grid {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 12px;
}

@media (min-width: 560px) {
    .grid {
        grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
        gap: 16px;
    }
}

.grid__cell {
    display: flex;
}

.tile {
    display: flex;
    flex-direction: column;
    width: 100%;
    color: var(--text);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    overflow: hidden;
    transition: border-color 140ms ease, transform 140ms ease, box-shadow 140ms ease;
}

.tile:hover {
    text-decoration: none;
    border-color: var(--accent-ink);
    transform: translateY(-2px);
    box-shadow: 0 8px 24px rgb(var(--ink-rgb) / .08);
}

/* A square box reserved before any byte of the picture arrives.
   Without this the grid reflows once per image as they land, and the largest
   element keeps being re-measured - which is the thing AC-04-6 is timing. */
.tile__frame {
    position: relative;
    display: block;
    aspect-ratio: 1;
    background: var(--surface);
}

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

.tile__nophoto {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    color: var(--ink-200);
}

.tile__nophoto svg {
    width: 38%;
    max-width: 56px;
}

.tile__flag {
    position: absolute;
    inset-block-end: 8px;
    inset-inline-start: 8px;
    padding: 3px 8px;
    font-size: 11.5px;
    font-weight: 700;
    color: var(--paper);
    background: rgb(var(--ink-rgb) / .78);
    border-radius: var(--radius-pill);
}

.tile__name {
    padding: 10px 12px 0;
    font-size: 14px;
    line-height: 1.7;
    overflow-wrap: anywhere;
}

.tile__price {
    padding: 4px 12px 12px;
    margin-top: auto;
    font-size: 14px;
    font-weight: 700;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------- the product --
| One product. Single column on a phone, gallery beside the text once there is
| width for both.
*/

.pdp {
    width: 100%;
    max-width: 900px;
    display: grid;
    gap: 20px;
}

@media (min-width: 720px) {
    .pdp {
        grid-template-columns: 1.1fr 1fr;
        gap: 28px;
        align-items: start;
    }
}

.pdp__gallery {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    overflow: hidden;
}

/* The gallery is a scroll-snap strip, and that is why this page needs no
   script. A thumbnail switcher needs a click handler; a strip is the browser's
   own overflow scrolling, which works with a thumb, with a trackpad and with
   JavaScript switched off. */
.pdp__strip {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: thin;
    overscroll-behavior-x: contain;
}

.pdp__slide {
    flex: 0 0 100%;
    scroll-snap-align: center;
    aspect-ratio: 1;
    background: var(--surface);
}

.pdp__slide img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}

.pdp__count {
    margin: 0;
    padding: 8px 12px;
    font-size: 12px;
    color: var(--text-muted);
    text-align: center;
    border-top: 1px solid var(--border);
}

.pdp__nophoto {
    display: grid;
    place-items: center;
    aspect-ratio: 1;
    background: var(--surface);
    color: var(--ink-200);
}

.pdp__nophoto svg {
    width: 28%;
    max-width: 96px;
}

.pdp__body {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    padding: 20px 18px;
}

.pdp__name {
    font-size: clamp(19px, 5vw, 23px);
    font-weight: 700;
    line-height: 1.6;
    margin: 0 0 10px;
    overflow-wrap: anywhere;
}

.pdp__price {
    font-size: 20px;
    font-weight: 700;
    color: var(--text);
    margin: 0 0 10px;
    font-variant-numeric: tabular-nums;
}

.pdp__stock {
    display: inline-block;
    margin: 0 0 16px;
    padding: 3px 10px;
    font-size: 12.5px;
    font-weight: 700;
    border-radius: var(--radius-pill);
}

.pdp__stock.is-in {
    color: var(--ok-ink);
    background: rgb(var(--ok-rgb) / .1);
}

.pdp__stock.is-out {
    color: var(--danger);
    background: rgb(var(--bad-rgb) / .1);
}

/* The seller's own words, kept as they typed them: a description written with
   one item per line has to arrive with one item per line. */
.pdp__about {
    font-size: 14.5px;
    line-height: 2;
    color: var(--text-muted);
    white-space: pre-line;
    overflow-wrap: anywhere;
    margin-bottom: 20px;
}

.pdp__note {
    margin: 12px 0 0;
    font-size: 12.5px;
    line-height: 1.9;
    color: var(--text-muted);
}

.btn--wide {
    display: flex;
    width: 100%;
    justify-content: center;
}

/*
| The commit button: basket, checkout, code, place order.
|
| It is the same button as everywhere else with one addition — a soft accent
| glow underneath it — because on these four pages it is competing with a
| price, a summary and a set of fields for attention and it has to win. The
| glow is the brand hue at 28% through the alpha channel, so no colour literal
| appears here (AC-BR-1).
|
| Nothing here changes the label, the height or the radius. A "primary" button
| that is a different shape from every other button in the product teaches the
| customer that this one is a different kind of thing, which is exactly the
| doubt a checkout cannot afford.
*/
.btn--go {
    box-shadow: 0 6px 18px rgb(var(--sky-rgb) / .28);
}

/* ------------------------------------------------------ the buying flow --
| Basket, checkout, code, order, my orders, terms — F-05 and F-06.
|
| ONE COLUMN, ALWAYS. These pages are read on a phone held in one hand, half
| of them while the other hand is doing something else. There is no two-column
| desktop variant and no sidebar: the widest this ever gets is 620px of centred
| column, and the extra room a laptop has is left as margin rather than filled.
|
| NO JAVASCRIPT BEHIND ANY OF IT. The quantity stepper is two submit buttons,
| the remove control is a submit button, the payment choice is a radio group.
| Everything below is styling on markup that already worked.
|
| MONEY IS NEVER A BRAND COLOUR. `.money` is --text, the near-black the rest of
| the page is written in. A total painted sky-blue reads as an advertisement;
| a total in ink reads as a fact, and this is the page where the difference
| costs real trust. The brand appears on the button and nowhere near a figure.
|
| NOTHING HERE MOVES. No hover lift, no slide-in, no transform: every state
| change below is a colour or a border. That is why the reduced-motion block at
| the bottom of this file needed no new exceptions for any of it.
*/

.shop--flow {
    padding-top: 20px;
    gap: 18px;
}

/* The back-link and the basket link share the header row. */
.shop__head--tight {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

/*
| The basket link, rendered on the shopfront and the product page whether or
| not there is anything in it. A control that appears only once it has contents
| leaves a customer who added something yesterday with no way back to it.
*/
.shop__cart {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex: none;
    padding: 7px 12px;
    font-size: 13.5px;
    font-weight: 700;
    color: var(--text);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    transition: border-color var(--fast) var(--ease);
}

.shop__cart:hover {
    text-decoration: none;
    border-color: var(--accent-ink);
}

.shop__cart svg {
    width: 17px;
    height: 17px;
    flex: none;
}

.shop__cartnum {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 5px;
    font-size: 12px;
    color: var(--accent-on);
    background: var(--accent);
    border-radius: var(--radius-pill);
}

/* ------------------------------------------------------------ the column -- */

.flow {
    width: 100%;
    max-width: 620px;
}

/* The code step and the locked list have one thing to say each. */
.flow--narrow {
    max-width: 420px;
}

.flow__title {
    font-family: var(--font-heading);
    font-size: clamp(20px, 5.5vw, 25px);
    font-weight: 700;
    margin: 0 0 16px;
    letter-spacing: -.02em;
}

.flow__sub {
    font-size: 15px;
    font-weight: 700;
    margin: 0 0 10px;
}

.flow__lead {
    font-size: 14.5px;
    line-height: 2;
    color: var(--text-muted);
    margin: 0 0 18px;
}

/* A phone number is latin digits inside a Persian sentence. */
.flow__phone {
    display: inline-block;
    font-weight: 700;
    color: var(--text);
    font-variant-numeric: tabular-nums;
    letter-spacing: .04em;
}

.flow__hint {
    font-size: 12.5px;
    line-height: 1.9;
    color: var(--text-muted);
    margin: 16px 0;
    text-align: center;
}

/*
| Empty basket, and no orders yet.
|
| D-15: nothing is invented to fill this space. No "you might also like", no
| sample products. An empty basket says it is empty and points at the one place
| that can change that.
*/
.flow__empty {
    padding: 32px 20px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    text-align: center;
}

.flow__emptytitle {
    font-size: 15.5px;
    font-weight: 700;
    margin: 0 0 8px;
}

.flow__emptysub {
    font-size: 13.5px;
    line-height: 2;
    color: var(--text-muted);
    margin: 0 0 18px;
}

.flow__empty .btn {
    margin-top: 4px;
}

/* --------------------------------------------------------------- notices --
| The error table from the work order, rendered.
|
| Three tones and they are the STATUS hues, never the brand: "this failed",
| "look at this", "this worked" are system messages, and a customer who learns
| that sky-blue can mean either an advert or a problem has learned nothing.
|
| Each one is a tint of its hue through the alpha channel with the darker cut
| of the same hue as text, so the contrast holds on the light canvas.
*/
.notice {
    margin: 0 0 16px;
    padding: 11px 14px;
    font-size: 13.5px;
    line-height: 1.9;
    border-radius: var(--radius-input);
    overflow-wrap: anywhere;
}

.notice--ok {
    color: var(--ok-ink);
    background: rgb(var(--ok-rgb) / .1);
}

.notice--warn {
    color: var(--warn-ink);
    background: rgb(var(--warn-rgb) / .1);
}

.notice--bad {
    color: var(--danger);
    background: rgb(var(--bad-rgb) / .1);
}

/* ------------------------------------------------------------ the basket --
| One row per product: photo, then everything about it, then the remove
| control. At 360px the photo is 72px and the middle column takes what is left.
*/

.cart {
    list-style: none;
    margin: 0 0 20px;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.cart__line {
    display: grid;
    grid-template-columns: 72px 1fr auto;
    gap: 12px;
    align-items: start;
    padding: 12px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
}

/*
| AC-05-4: a product the seller has switched off or deleted.
|
| It STAYS ON THE PAGE, faded and labelled, with its remove button. It is not
| silently dropped — a basket that quietly loses a line is a basket the customer
| cannot trust — and it is not counted in the total, which CartView enforces
| rather than this rule.
*/
.cart__line.is-dead {
    opacity: .62;
}

.cart__thumb {
    display: block;
    width: 72px;
    height: 72px;
    border-radius: var(--radius-input);
    overflow: hidden;
    background: var(--sunken);
}

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

/* A product with no photo, or one whose file has gone: a drawn stand-in,
   never the browser's broken-image icon. */
.cart__nophoto {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    color: var(--ink-300);
}

.cart__nophoto svg {
    width: 26px;
    height: 26px;
}

.cart__body {
    min-width: 0;
}

.cart__name {
    display: block;
    font-size: 14.5px;
    font-weight: 700;
    color: var(--text);
    line-height: 1.7;
    overflow-wrap: anywhere;
}

.cart__unit {
    margin: 4px 0 0;
    font-size: 12.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* «دیگر موجود نیست» and «فقط N عدد موجود است» — the sentence sits on the line
   it is about, not in a banner at the top where it would name no product. */
.cart__flag {
    margin: 6px 0 0;
    font-size: 12.5px;
    line-height: 1.8;
    font-weight: 700;
    color: var(--danger);
}

.cart__flag--warn {
    color: var(--warn-ink2);
}

.cart__controls {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 10px;
}

.cart__linetotal {
    margin: 0;
    font-size: 14.5px;
    font-weight: 700;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------- the qty stepper --
| Two forms and a number between them. Each button is its own POST, which is
| why they are separate <form>s and why a refresh cannot repeat one.
|
| 36px square is above the 34px this product treats as the floor for a thumb
| target, and the two are 4px apart so a mis-tap lands on nothing rather than
| on the other one.
*/
.qty {
    display: flex;
    align-items: center;
    gap: 4px;
    background: var(--sunken);
    border-radius: var(--radius-pill);
    padding: 3px;
}

.qty__btn {
    width: 36px;
    height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font: inherit;
    font-size: 18px;
    line-height: 1;
    color: var(--text);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 50%;
    cursor: pointer;
    transition: border-color var(--fast) var(--ease);
}

.qty__btn:hover:not(:disabled) {
    border-color: var(--accent-ink);
}

/* The + button when the basket already holds every one the seller has. It is
   a stepper, not a buy button — AC-BR-6 is about the product page. */
.qty__btn:disabled {
    opacity: .45;
    cursor: not-allowed;
}

.qty__val {
    min-width: 28px;
    text-align: center;
    font-size: 14.5px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.cart__rm {
    display: flex;
}

.cart__rmbtn {
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--text-faint);
    background: transparent;
    border: 0;
    border-radius: 50%;
    cursor: pointer;
    transition: color var(--fast) var(--ease), background-color var(--fast) var(--ease);
}

.cart__rmbtn:hover {
    color: var(--danger);
    background: rgb(var(--bad-rgb) / .08);
}

.cart__rmbtn svg {
    width: 16px;
    height: 16px;
}

/* ---------------------------------------------------------- the totals --
| Goods, delivery, total. The total is the only line with weight, because it is
| the only figure anybody checks twice.
*/
.sums {
    padding: 14px 16px;
    margin-bottom: 18px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
}

.sums--tight {
    padding: 12px 14px;
    margin-bottom: 0;
}

.sum {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin: 0 0 8px;
    font-size: 13.5px;
    color: var(--text-muted);
}

.sum__k {
    flex: none;
}

.sum__v {
    font-variant-numeric: tabular-nums;
}

.sum--total {
    margin: 12px 0 0;
    padding-top: 12px;
    border-top: 1px solid var(--border);
    font-size: 16px;
    font-weight: 700;
    color: var(--text);
}

/*
| EVERY PRICE, EVERY TOTAL, EVERY LINE FIGURE ON THESE PAGES.
|
| Neutral strong ink and tabular figures. It is deliberately NOT --accent-ink:
| the brand hue sells things, and a number that a person is about to pay should
| not be selling anything. Tabular numerals so the digits in a column line up
| and a total can be checked against its parts at a glance.
*/
.money {
    color: var(--text);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------- the basket recap --
| The basket folded down on the checkout and the receipt. The customer has just
| come from the basket and does not need it again in full; they do need to be
| able to check the figure before they commit.
*/
.recap {
    padding: 14px 16px;
    margin-bottom: 18px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
}

.recap__list {
    list-style: none;
    margin: 0 0 12px;
    padding: 0;
}

.recap__row {
    display: grid;
    grid-template-columns: 1fr auto auto;
    gap: 10px;
    align-items: baseline;
    padding: 8px 0;
    border-bottom: 1px solid var(--border);
    font-size: 13.5px;
}

.recap__row:last-child {
    border-bottom: 0;
}

.recap__name {
    min-width: 0;
    overflow-wrap: anywhere;
}

.recap__qty {
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.recap__qty::before {
    /* "× 2", drawn by the stylesheet so the Blade prints only the number. */
    content: '\00D7\00A0';
}

.recap__val {
    white-space: nowrap;
}

/* ---------------------------------------------------------- the checkout --
| Name, number, address, note, payment, terms. Nothing else, in that order,
| because that is the order a person says them out loud.
*/
.checkout {
    margin: 0;
}

.pay {
    border: 0;
    padding: 0;
    margin: 0 0 16px;
    min-width: 0;
}

.pay legend {
    padding: 0;
}

/*
| One row per method the SELLER switched on. The radio itself stays visible and
| focusable — a hidden input styled back in with :has() is a control that
| disappears the moment a browser disagrees, and this is the page where a
| control that disappears costs an order.
*/
.pay__opt {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 14px;
    margin-bottom: 8px;
    background: var(--bg);
    border: 1.5px solid var(--border);
    border-radius: var(--radius-input);
    cursor: pointer;
    transition: border-color var(--fast) var(--ease);
}

.pay__opt input[type='radio'] {
    margin: 3px 0 0;
    accent-color: var(--accent);
    width: 18px;
    height: 18px;
    flex: none;
}

.pay__opt:hover {
    border-color: var(--border-strong);
}

.pay__opt:has(input:checked) {
    border-color: var(--accent-ink);
}

.pay__opt:has(input:focus-visible) {
    outline: 2px solid var(--accent-ink);
    outline-offset: 2px;
}

.pay__body {
    display: block;
    min-width: 0;
}

.pay__name {
    display: block;
    font-size: 14.5px;
    font-weight: 700;
}

.pay__note {
    display: block;
    margin-top: 3px;
    font-size: 12.5px;
    line-height: 1.9;
    color: var(--text-muted);
}

/* The terms line. The link inside it goes to a real page — asking somebody to
   accept a href="#" is worse than not asking (debt row 36). */
.terms {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin: 4px 0 18px;
    font-size: 13px;
    line-height: 1.9;
    color: var(--text-muted);
    cursor: pointer;
}

.terms input[type='checkbox'] {
    margin: 3px 0 0;
    width: 18px;
    height: 18px;
    flex: none;
    accent-color: var(--accent);
}

.terms a {
    color: var(--accent-ink);
    font-weight: 700;
}

/* ----------------------------------------------------------- the code box --
| Six digits, and the only field on its page. Large, spaced and centred: this
| is read off a notification and typed with a thumb.
*/
.field__input--code {
    text-align: center;
    font-size: 24px;
    font-weight: 700;
    letter-spacing: .5em;
    /* The tracking is added on the right of the last glyph too, which pushes
       the group visually off-centre. Half of it back as padding. */
    padding-inline-start: .5em;
    font-variant-numeric: tabular-nums;
}

.resend {
    margin-top: 12px;
    text-align: center;
}

/* ------------------------------------------------------------ the receipt --
| The tracking number is the largest thing on the page because it is what a
| customer reads out on the phone to the seller. It cannot open this page — the
| 40-character token in the address is the only thing that can.
*/
.ticket {
    padding: 22px 18px;
    margin-bottom: 18px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    text-align: center;
}

.ticket__k {
    margin: 0 0 6px;
    font-size: 12.5px;
    color: var(--text-muted);
}

.ticket__num {
    margin: 0 0 16px;
    font-family: var(--font-heading);
    font-size: clamp(28px, 9vw, 36px);
    font-weight: 700;
    letter-spacing: .08em;
    font-variant-numeric: tabular-nums;
}

.ticket__status {
    display: inline-block;
    margin: 0;
    padding: 5px 14px;
    font-size: 13px;
    font-weight: 700;
    color: var(--accent-ink);
    background: rgb(var(--sky-rgb) / .14);
    border-radius: var(--radius-pill);
}

.ticket__note {
    margin: 10px 0 0;
    font-size: 13px;
    line-height: 1.9;
    color: var(--text-muted);
}

.ticket__when {
    margin: 12px 0 0;
    font-size: 12px;
    color: var(--text-faint);
}

/* Delivery details, as a definition list because that is what they are. */
.pairs {
    margin: 0;
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 8px 14px;
    font-size: 13.5px;
    line-height: 1.9;
}

.pairs dt {
    color: var(--text-muted);
    white-space: nowrap;
}

.pairs dd {
    margin: 0;
    overflow-wrap: anywhere;
}

/*
| The seller's card number, on a card-to-card order and on no other kind.
| A shop's bank details printed on a cash-on-delivery receipt is an invitation
| to be phished, so the Blade renders this block conditionally and this rule
| never has to care.
*/
.cardbox {
    margin-top: 16px;
    padding: 14px 16px;
    background: var(--sunken);
    border-radius: var(--radius-input);
    text-align: center;
}

.cardbox__k {
    margin: 0 0 6px;
    font-size: 12.5px;
    color: var(--text-muted);
}

.cardbox__num {
    margin: 0;
    font-size: 19px;
    font-weight: 700;
    letter-spacing: .06em;
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}

.cardbox__who {
    margin: 6px 0 0;
    font-size: 13px;
}

.cardbox__note {
    margin: 8px 0 0;
    font-size: 12.5px;
    line-height: 1.9;
    color: var(--text-muted);
}

/* ------------------------------------------------------------ my orders --
| One list, every shop. The shop's name is on each row because that is the
| thing a customer remembers — not the order number.
*/
.orders {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

/* min-width on the flex item, so a shop name with no spaces in it wraps
   inside the row instead of pushing the row past the viewport. */
.orders__row {
    min-width: 0;
}

.orders__link {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 4px 12px;
    padding: 14px 16px;
    color: var(--text);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    transition: border-color var(--fast) var(--ease);
}

.orders__link:hover {
    text-decoration: none;
    border-color: var(--accent-ink);
}

.orders__shop {
    font-size: 14.5px;
    font-weight: 700;
    overflow-wrap: anywhere;
}

.orders__total {
    text-align: end;
    white-space: nowrap;
}

.orders__num {
    font-size: 12.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.orders__num::before {
    content: '\00A0';
}

.orders__when {
    grid-column: 1;
    font-size: 12.5px;
    color: var(--text-faint);
}

.orders__status {
    font-size: 12.5px;
    color: var(--accent-ink);
    font-weight: 700;
}

.flow__toolbar {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 18px;
}

.flow__toolbar .flow__title {
    margin-bottom: 4px;
}

.flow__toolbar .flow__lead {
    margin-bottom: 0;
}

.orders__method {
    text-align: end;
    font-size: 12.5px;
    color: var(--text-muted);
}

.orders__badges {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 5px;
}

.orders__payment {
    padding: 2px 7px;
    font-size: 11.5px;
    font-weight: 700;
    color: var(--text-muted);
    background: var(--sunken);
    border-radius: var(--radius-pill);
}

.pager {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-top: 18px;
}

.pager__count {
    font-size: 12.5px;
    color: var(--text-muted);
}

.pager [aria-disabled='true'] {
    opacity: .45;
}

.order-state {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
}

.order-state p,
.receipt-state {
    margin: 0;
    padding: 10px 12px;
    background: var(--sunken);
    border-radius: var(--radius-input);
}

.order-state span,
.receipt-state span {
    display: block;
    margin-bottom: 4px;
    font-size: 11.5px;
    color: var(--text-muted);
}

.order-state strong,
.receipt-state strong {
    display: block;
    font-size: 13px;
}

.receipt-state {
    margin-top: 16px;
}

.timeline {
    list-style: none;
    margin: 0;
    padding: 0;
}

.timeline li {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 9px 0;
    border-bottom: 1px solid var(--border);
    font-size: 13px;
}

.timeline li:last-child {
    border-bottom: 0;
}

.timeline time {
    color: var(--text-muted);
    white-space: nowrap;
}

/* ------------------------------------------------------------- the terms --
| Long-form Persian prose, which needs a wider line height than anything else
| in the product and a hard cap on measure.
*/
.legal {
    padding: 20px 18px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    font-size: 14px;
    line-height: 2.1;
    color: var(--text-muted);
}

.legal p {
    margin: 0 0 16px;
}

.legal__h {
    font-size: 15px;
    font-weight: 700;
    color: var(--text);
    margin: 24px 0 8px;
}

.legal__h:first-of-type {
    margin-top: 0;
}

/* D-76, said first and said plainly: this is a pre-launch build and the data
   can be wiped. It goes away with the launch, not with a redesign. */
.legal__warn {
    padding: 12px 14px;
    color: var(--warn-ink);
    background: rgb(var(--warn-rgb) / .1);
    border-radius: var(--radius-input);
}

/* ----------------------------------------------------- the buy block, F-05 --
| Debt row 35, closed.
|
| Until this piece the product page offered a phone number and nothing else,
| because there was no basket to add to and a disabled "add to basket" reads as
| a broken shop rather than an unfinished one.
|
| THE HIERARCHY BELOW IS THE POINT. Adding to the basket is the full-width
| button. The call link stays, because the buyers of these shops really do
| phone — but it is one small line underneath. If it kept equal weight the
| product would slide straight back into the direct messages it exists to
| replace, one tap at a time.
*/
.pdp__buy {
    margin: 4px 0 0;
}

.pdp__call {
    margin: 12px 0 0;
    font-size: 13px;
    line-height: 1.9;
    color: var(--text-muted);
    text-align: center;
}

.pdp__call a {
    color: var(--accent-ink);
    font-weight: 700;
}

.pdp__call span {
    font-variant-numeric: tabular-nums;
}

/* ------------------------------------------- the pre-launch line, on dark --
| The auth card is dark and `.auth .note` greys every note inside it. The
| pre-launch warning has to stay legible there, so it brings its own colours
| rather than inheriting a grey meant for hint text on a light background.
| It goes away with the block that renders it, on launch day.
*/
.auth .note--warn {
    color: var(--warn-lift);
    background: rgb(var(--warn-rgb) / .14);
    margin: 0 0 18px;
    text-align: center;
}

/* ------------------------------------------------------ reduced motion --
| Someone who has asked their operating system for less movement has asked for
| less movement here too. Everything above degrades to a plain fade; nothing
| translates, scales, shakes, spins or slides (AC-03-V2).
|
| Note what is NOT switched off: colour changes and the focus ring. Those carry
| meaning, and removing them would take information away rather than motion.
*/
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 1ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 1ms !important;
        scroll-behavior: auto !important;
    }

    .otp__box {
        animation: otp-fade 160ms linear both;
    }

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

        to {
            opacity: 1;
        }
    }

    .otp.is-shaking {
        animation: none;
    }

    /* The shopfront tile lifts on hover, and a lift is movement. The border
       colour stays: that is the part carrying "this is the one under your
       pointer", and removing it would take information rather than motion. */
    .tile:hover {
        transform: none;
    }

    /* A spinner that does not spin is a dot. Keep it turning, slowly - it is
       the only signal that something is still happening. */
    .spinner {
        animation: spin 1.4s linear infinite !important;
    }

    .otp__tick path {
        stroke-dashoffset: 0;
    }
}

.panel-page__heading { display:flex; justify-content:space-between; align-items:center; gap:1rem; margin-bottom:1rem; }
.orders-heading { margin-bottom:.85rem; }
.orders-heading h1 { margin-bottom:.25rem; }
.orders-heading p { color:var(--text-muted); margin:0; }
.action-summary { display:flex; align-items:center; gap:.55rem; padding:.6rem .85rem; border:1px solid rgb(var(--warn-rgb) / .35); border-radius:var(--radius-lg); background:rgb(var(--warn-rgb) / .09); color:var(--text); }
.action-summary strong { font-size:1.2rem; font-variant-numeric:tabular-nums; }
.action-summary span { color:var(--text-muted); font-size:.85rem; }
.orders-overview { display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:.65rem; margin:0 0 1rem; }
.orders-overview__item { display:flex; flex-direction:column; gap:.25rem; padding:.8rem .9rem; border:1px solid var(--border); border-radius:var(--radius-lg); background:var(--surface); }
.orders-overview__item span { color:var(--text-muted); font-size:.8rem; }
.orders-overview__item strong { font-size:1.1rem; font-variant-numeric:tabular-nums; }
.orders-overview__item--attention { border-color:rgb(var(--warn-rgb) / .4); background:rgb(var(--warn-rgb) / .07); }
.order-filters { display:flex; gap:.5rem; overflow-x:auto; margin-bottom:1rem; padding-bottom:.2rem; scrollbar-width:thin; }
.order-filters a { white-space:nowrap; padding:.65rem .9rem; border-radius:var(--radius-pill); color:var(--text-muted); }
.order-filters a.is-active { background:rgb(var(--sky-rgb) / .14); color:var(--text); font-weight:700; }
.order-search { display:grid; grid-template-columns:minmax(220px, 2fr) minmax(140px, 1fr) minmax(140px, 1fr) auto auto; gap:.7rem; align-items:end; margin-bottom:1rem; }
.order-search__query { min-width:0; }
.order-search .field__label { display:block; margin-bottom:.35rem; }
.order-search .btn { white-space:nowrap; }
.order-list { display:grid; gap:.7rem; }
.order-card { display:grid; grid-template-columns:minmax(0, 1.3fr) minmax(170px, 1fr) auto auto; align-items:center; gap:1rem; padding:1rem 1.1rem; border:1px solid var(--border); border-radius:var(--radius-lg); background:var(--surface); color:inherit; text-decoration:none; transition:border-color 140ms ease, box-shadow 140ms ease, transform 140ms ease; }
.order-card:hover { border-color:var(--accent); box-shadow:0 8px 24px rgb(var(--ink-rgb) / .07); transform:translateY(-1px); text-decoration:none; }
.order-card--action { border-inline-start:4px solid var(--warn); }
.order-card__identity, .order-card__number { min-width:0; display:flex; flex-direction:column; gap:.35rem; }
.order-card__number { flex-direction:row; align-items:center; flex-wrap:wrap; gap:.5rem; }
.order-card__number strong { font-size:1rem; }
.order-card__customer { overflow:hidden; color:var(--text-muted); text-overflow:ellipsis; white-space:nowrap; }
.order-card__status, .order-card__badges { display:flex; flex-wrap:wrap; gap:.4rem; }
.order-card__amount { display:flex; flex-direction:column; align-items:flex-end; gap:.3rem; white-space:nowrap; }
.order-card__amount strong { font-size:1rem; color:var(--text); font-variant-numeric:tabular-nums; }
.order-card__amount time { color:var(--text-muted); font-size:.78rem; }
.order-card__open { color:var(--accent-ink); font-size:.82rem; font-weight:700; white-space:nowrap; }
.order-card__open span { font-size:1.1rem; }
.needs-action { padding:.2rem .45rem; border-radius:var(--radius-pill); color:var(--warn-ink); background:rgb(var(--warn-rgb) / .14); font-size:.72rem; font-weight:700; }
.order-detail__header { display:flex; justify-content:space-between; align-items:flex-start; gap:1rem; padding-bottom:1rem; border-bottom:1px solid var(--border); }
.order-detail__header h1 { margin:.15rem 0 .45rem; }
.order-detail__eyebrow { margin:0; color:var(--text-muted); font-size:.82rem; }
.order-detail__stage { display:flex; align-items:center; gap:.45rem; margin:0; color:var(--text-muted); }
.order-detail__stage strong { color:var(--accent-ink); }
.order-detail__grid { display:grid; grid-template-columns:minmax(0, 1.65fr) minmax(260px, .9fr); gap:1rem; align-items:start; }
.order-detail__main, .order-detail__aside { min-width:0; }
.order-detail__aside { position:sticky; top:1rem; }
.order-section { margin-top:1rem; }
.order-section h2 { margin-top:0; }
.section-heading { display:flex; justify-content:space-between; align-items:flex-start; gap:1rem; }
.section-heading > span { color:var(--text-muted); font-size:.82rem; }
.order-line { display:flex; justify-content:space-between; gap:1rem; align-items:center; padding:.8rem 0; border-bottom:1px solid var(--border); }
.order-line:last-child { border-bottom:0; }
.order-line div { min-width:0; display:flex; flex-direction:column; gap:.2rem; }
.order-line small { color:var(--text-muted); }
.order-line > strong, .order-totals dd, .receipt-meta dd { font-variant-numeric:tabular-nums; white-space:nowrap; }
.receipt-section { overflow:hidden; }
.receipt-review { display:grid; grid-template-columns:minmax(0, 1.2fr) minmax(210px, .8fr); gap:1rem; align-items:start; }
.receipt-preview { min-height:220px; display:grid; place-items:center; overflow:hidden; border:1px solid var(--border); border-radius:var(--radius-lg); background:var(--sunken); }
.receipt-preview img, .receipt-preview object { display:block; width:100%; max-height:460px; min-height:220px; object-fit:contain; }
.receipt-meta { display:grid; gap:.7rem; margin:0; }
.receipt-meta div, .detail-list div { display:flex; justify-content:space-between; gap:1rem; padding-bottom:.6rem; border-bottom:1px solid var(--border); }
.receipt-meta dt, .detail-list dt { color:var(--text-muted); font-size:.82rem; }
.receipt-meta dd, .detail-list dd { margin:0; text-align:end; }
.receipt-links { grid-column:1 / -1; display:flex; flex-wrap:wrap; gap:.5rem; }
.receipt-decisions { display:flex; flex-wrap:wrap; gap:.6rem; margin-top:1rem; padding-top:1rem; border-top:1px solid var(--border); }
.order-actions form { margin-bottom:.55rem; }
.order-actions form:last-of-type { margin-bottom:0; }
.back-link { display:inline-block; margin-bottom:.9rem; color:var(--accent-ink); font-weight:700; }
@media (max-width: 1050px) { .order-search { grid-template-columns:1fr 1fr; } .order-search__query { grid-column:1 / -1; } }
@media (max-width: 859px) { .panel-page__heading { align-items:flex-start; flex-direction:column; } .orders-overview { gap:.45rem; } .order-card { grid-template-columns:1fr auto; gap:.7rem; } .order-card__status { grid-column:1 / -1; order:3; } .order-card__amount { align-items:flex-start; } .order-card__open { justify-self:end; } .order-detail__header { flex-direction:column; } .order-detail__grid { display:block; } .order-detail__aside { position:static; } .receipt-review { grid-template-columns:1fr; } }
@media (max-width: 540px) { .orders-overview__item { padding:.65rem; } .orders-overview__item strong { font-size:1rem; } .action-summary { width:100%; justify-content:space-between; } .order-search { grid-template-columns:1fr; } .order-search__query { grid-column:auto; } .order-search .btn { width:100%; } .order-card { padding:.85rem; } .order-card__amount strong { font-size:.9rem; } .order-line { align-items:flex-start; } .receipt-links .btn { flex:1 1 100%; text-align:center; } }

/*
| P-07 — the notification centre and the day's open work.
|
| Nothing new is invented here: the cards borrow the surface, border and radius
| the order list already uses, and every colour resolves in tokens.css. The one
| genuinely new shape is the count on the nav item, and it is positioned
| absolutely so that adding a number to a label cannot make the bottom bar wider
| than the phone it is sitting on.
*/
.panel__nav a { position:relative; }
.nav-dot { position:absolute; top:2px; inset-inline-end:calc(50% - 22px); min-width:16px; padding:0 4px; border-radius:var(--radius-pill); background:var(--warn); color:var(--paper); font-size:10px; line-height:16px; text-align:center; font-variant-numeric:tabular-nums; }

.tasks { margin-top:1rem; }
.tasks__title { margin:0 0 .7rem; font-size:1rem; }
.tasks__list { list-style:none; margin:0; padding:0; display:grid; gap:.5rem; }
.tasks__list a, .tasks__note { display:flex; align-items:center; gap:.7rem; padding:.7rem .85rem; border:1px solid var(--border); border-radius:var(--radius-card); background:var(--surface); color:inherit; }
.tasks__list a:hover { border-color:var(--accent); text-decoration:none; }
.tasks__num { min-width:2rem; color:var(--accent-ink); font-size:1.15rem; font-weight:700; font-variant-numeric:tabular-nums; text-align:center; }
.tasks__text { min-width:0; }
.tasks__note { border-color:rgb(var(--warn-rgb) / .4); background:rgb(var(--warn-rgb) / .07); color:var(--warn-ink); }

.notif-list { list-style:none; margin:0 0 1rem; padding:0; display:grid; gap:.6rem; }
.notif { display:flex; align-items:center; justify-content:space-between; gap:1rem; padding:.9rem 1rem; border:1px solid var(--border); border-radius:var(--radius-card); background:var(--surface); }
/* Read and unread differ by weight, not only by colour: a tinted background
   alone is invisible to a seller who cannot distinguish it. */
.notif.is-unread { border-inline-start:4px solid var(--accent); background:rgb(var(--sky-rgb) / .05); }
.notif.is-unread .notif__text { font-weight:700; }
.notif__body { min-width:0; display:flex; flex-direction:column; gap:.35rem; }
.notif__head { display:flex; align-items:center; flex-wrap:wrap; gap:.5rem; margin:0; }
.notif__at { color:var(--text-muted); font-size:.78rem; }
.notif__text { margin:0; overflow-wrap:anywhere; }
.notif__go { white-space:nowrap; }
.notifs-page form { margin:0; }

@media (max-width: 540px) {
    /* Stacked, so a long Persian sentence never pushes the button off the
       side and turns the list into a horizontal scroller. */
    .notif { flex-direction:column; align-items:stretch; gap:.7rem; padding:.8rem; }
    .notif__go { width:100%; }
    .tasks__list a, .tasks__note { padding:.65rem; }
}

@media (max-width: 380px) {
    /* Six items in the bottom bar instead of five. One point smaller keeps
       every label on one line at 320px. */
    .panel__nav a { font-size:10px; }
    .panel__nav svg { width:20px; height:20px; }
    .nav-dot { inset-inline-end:calc(50% - 20px); }
}

/*
| P-08.1 — the seller's wallet page.
|
| No new colour and no new radius: the cards borrow --surface, --border and
| --radius-card from the order and notification lists, and the three signals
| below resolve to the status hues already declared in tokens.css.
|
| .badge--bad is defined here and it is not new either - two panel views have
| been asking for it since the orders redesign (a failed payment, a cancelled
| order) and nothing in this stylesheet answered, so those badges rendered as
| bare pills. It belongs with its siblings above; it is written here so the
| commit that needs it is the commit that adds it.
*/
.badge--bad { color:var(--bad); background:rgb(var(--bad-rgb) / .12); }

.wallet-balance { text-align:center; }
.wallet-balance__label { margin:0; color:var(--text-muted); font-size:.85rem; }
/* tabular-nums so the balance does not jump sideways between two page loads
   that differ by one digit. */
.wallet-balance__num { margin:.2rem 0 0; font-family:var(--font-heading); font-size:2.1rem; line-height:1.2; font-variant-numeric:tabular-nums; }
.wallet-balance__num.is-negative { color:var(--danger); }
.wallet-balance__unit { margin:0 0 .8rem; color:var(--text-muted); font-size:.85rem; }

.wallet-facts { display:flex; justify-content:center; gap:1.6rem; margin:1rem 0 0; padding-top:.9rem; border-top:1px solid var(--border); }
.wallet-facts div { display:flex; flex-direction:column; gap:.2rem; }
.wallet-facts dt { color:var(--text-muted); font-size:.78rem; }
.wallet-facts dd { margin:0; font-weight:700; font-variant-numeric:tabular-nums; }

.wallet-warn { margin:.9rem 0 0; }

.wallet-totals { display:grid; grid-template-columns:repeat(auto-fit, minmax(8rem, 1fr)); gap:.5rem; margin:1rem 0; }
.wallet-total { display:flex; flex-direction:column; gap:.25rem; padding:.7rem .85rem; border:1px solid var(--border); border-radius:var(--radius-card); background:var(--surface); }
.wallet-total span { color:var(--text-muted); font-size:.78rem; }
.wallet-total strong { font-size:1.05rem; font-variant-numeric:tabular-nums; }
/* The support correction is deliberately the quietest box on the row. It is
   shown so nothing is hidden, not so it competes with money the seller paid. */
.wallet-total--adjust { border-style:dashed; }
.wallet-total--adjust strong { color:var(--text-muted); }

.wallet-listtitle { margin:1.4rem 0 .7rem; font-size:1rem; }

.wallet-list { list-style:none; margin:0 0 1rem; padding:0; display:grid; gap:.6rem; }
.wallet-row { display:flex; align-items:center; justify-content:space-between; gap:1rem; padding:.85rem 1rem; border:1px solid var(--border); border-radius:var(--radius-card); background:var(--surface); }
.wallet-row__what { min-width:0; display:flex; flex-direction:column; align-items:flex-start; gap:.35rem; }
.wallet-row__desc { overflow-wrap:anywhere; }
.wallet-row__at { color:var(--text-muted); font-size:.78rem; }
.wallet-row__money { flex-shrink:0; display:flex; flex-direction:column; align-items:flex-end; gap:.2rem; }
/* A charge is the ordinary case and stays in the text colour; credit is the
   exception and is the only thing on the row that is green. Weight carries it
   as well as hue, so the two are not told apart by colour alone. */
.wallet-row__amount { font-variant-numeric:tabular-nums; }
.wallet-row__amount.is-plus { color:var(--ok-ink); }
.wallet-row__after { color:var(--text-faint); font-size:.75rem; font-variant-numeric:tabular-nums; }

.wallet-howto { margin:1.2rem 0 0; color:var(--text-muted); font-size:.82rem; line-height:1.9; }

@media (max-width: 540px) {
    /* Stacked, so a long Persian description never pushes the amount off the
       side and turns the ledger into a horizontal scroller. */
    .wallet-row { flex-direction:column; align-items:stretch; gap:.6rem; padding:.8rem; }
    .wallet-row__money { flex-direction:row; align-items:baseline; justify-content:space-between; }
    .wallet-balance__num { font-size:1.8rem; }
    .wallet-facts { gap:1.1rem; }
}

/*
| The low-credit line in "کارهای امروزت" became a link to the page above.
|
| It needs saying again at this specificity and that is not a redundancy: the
| shared rule is written as `.tasks__list a, .tasks__note`, so once the note IS
| an anchor inside that list the `a` half matches at (0,0,1,1) and takes the
| neutral colour, border and background back off it. The warning would have
| gone quietly grey.
*/
.tasks__list a.tasks__note { border-color:rgb(var(--warn-rgb) / .4); background:rgb(var(--warn-rgb) / .07); color:var(--warn-ink); }
.tasks__list a.tasks__note:hover { border-color:var(--warn); text-decoration:none; }

/* ------------------------------------------------------- the bale wizard --

   Two small additions, both on /panel/settings/bale.

   .guide is a numbered list of things the seller does BY HAND inside Bale.
   It is an <ol> and not a styled <div> stack because the order is the content:
   you cannot get a provider token before the arm exists. Screen readers should
   hear "1 of 3", and a numbered list is how they do.

   The counter is drawn rather than left to the default marker so the digits
   render Persian-side of the text in RTL without the marker sitting outside
   the card's padding.
*/
.guide { margin:.4rem 0 1.1rem; padding:0; list-style:none; counter-reset:guide; }
.guide li {
    counter-increment:guide;
    position:relative;
    padding:0 2.2rem .1rem 0;
    margin-bottom:.9rem;
    color:var(--text-muted);
    font-size:.86rem;
    line-height:2;
}
.guide li:last-child { margin-bottom:0; }
.guide li::before {
    content:counter(guide, persian);
    position:absolute;
    inset-inline-start:0;
    top:.35rem;
    width:1.5rem;
    height:1.5rem;
    display:grid;
    place-items:center;
    border-radius:50%;
    background:rgb(var(--sky-rgb) / .12);
    color:var(--accent-ink);
    font-size:.78rem;
    font-weight:700;
}
.guide b { color:var(--text); font-weight:700; }

/* The test/enable pair. They are two forms, because each is a separate POST
   with its own token, and forms are block elements — without this they would
   stack into two full-width rows for two buttons the seller reads as a pair. */
.bale-actions { display:flex; flex-wrap:wrap; gap:.6rem; margin:1rem 0; }

/* --------------------------------------------------------- "بیشتر" sheet --

   The panel outgrew a five-item bottom bar. Rather than shrink the labels
   until they are unreadable, the four daily destinations stay on the bar and
   everything else moves behind one more item, into a panel that slides up from
   the bottom edge — the gesture a phone already uses for "there is more here".

   It exists only below 860px. Above that the side column shows every item
   flat and this whole block is inert markup with display:none on it.

   Notes that are easy to get wrong and are not decoration:

     • the veil is a sibling, not a parent, so a tap that lands on the panel
       does not bubble through it and close the thing being tapped.
     • .sheet is fixed to the viewport, not to .panel, because .panel is a flex
       column with its own stacking context and a sheet inside it would be
       clipped by the nav's z-index rather than sitting over it.
     • padding-bottom carries env(safe-area-inset-bottom) like the nav does.
       Without it the last row of the list sits under the iOS home indicator,
       where taps go to the system and not to the page.
*/
.sheet {
    position: fixed;
    inset: 0;
    z-index: 60;
    display: flex;
    align-items: flex-end;
}

.sheet[hidden] {
    display: none;
}

.sheet__veil {
    position: absolute;
    inset: 0;
    background: rgb(var(--ink-rgb) / .45);
    animation: sheet-veil var(--fast) var(--ease);
}

.sheet__panel {
    position: relative;
    width: 100%;
    max-height: 82dvh;
    overflow-y: auto;
    padding: 10px 16px calc(18px + env(safe-area-inset-bottom));
    background: var(--bg);
    border-start-start-radius: 20px;
    border-start-end-radius: 20px;
    box-shadow: var(--shadow);
    animation: sheet-rise var(--slow) var(--ease);
}

/* The handle. Drawn because people expect one on a panel that came up from
   the bottom; it is not draggable and does not pretend to be — aria-hidden in
   the markup, no pointer cursor here. */
.sheet__grip {
    width: 40px;
    height: 4px;
    margin: 0 auto 12px;
    border-radius: var(--radius-pill);
    background: var(--border-strong);
}

.sheet__title {
    margin: 0 0 .8rem;
    font-family: var(--font-heading);
    font-size: 1rem;
}

.sheet__list {
    list-style: none;
    margin: 0 0 1rem;
    padding: 0;
    display: grid;
    gap: .5rem;
}

/* ------------------------------------------------------------- link row --

   A whole row that is one destination: icon, name, a line of explanation, an
   optional status badge, and a chevron saying it goes somewhere.

   It exists because a link with a status beside it kept being written as a
   sentence with an <a> at the end of it — which is how the entry into the Bale
   settings ended up invisible on /panel/settings/store. A row cannot be
   mistaken for a paragraph: it has an edge, it has a chevron, and all 56px of
   it are the target.

   Three call sites and one rule: the "بیشتر" sheet, the Bale entry in store
   settings, and the wallet entry on the panel's home page.
*/
.linkrow {
    display: flex;
    align-items: center;
    gap: .75rem;
    min-height: 56px;
    padding: .6rem .85rem;
    color: inherit;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
}

.linkrow:hover {
    border-color: var(--accent);
    text-decoration: none;
}

/* Only ever set on the sheet's rows: a link to the page you are already on. */
.linkrow[aria-current='page'] {
    border-color: var(--accent);
    background: rgb(var(--sky-rgb) / .1);
    color: var(--accent-ink);
}

.linkrow svg {
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    stroke: currentColor;
    stroke-width: 1.8;
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.linkrow__text {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.linkrow__text strong {
    font-size: .95rem;
}

.linkrow__text small {
    color: var(--text-muted);
    font-size: .76rem;
}

/* The chevron points the way the language reads, so it is the RTL single
   quotation mark rather than a second glyph swapped in by a media query. */
.linkrow__chev {
    flex: 0 0 auto;
    color: var(--text-faint);
    font-size: 1.2rem;
    line-height: 1;
}

.linkrow__badge {
    flex: 0 0 auto;
}

@keyframes sheet-veil {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@keyframes sheet-rise {
    from { transform: translateY(12%); opacity: .6; }
    to   { transform: translateY(0);   opacity: 1; }
}

/* Above the breakpoint the column already lists everything, so the sheet can
   never be opened — and its trigger is display:none, so it cannot be either. */
@media (min-width: 860px) {
    .sheet {
        display: none;
    }
}

/*
| Scroll lock, set on <body> while the sheet is open so the page behind does
| not travel under the seller's finger.
|
| overflow:hidden alone does not hold on iOS Safari. position:fixed does, at
| the cost of throwing the page to the top — so panel-more.js writes the
| scroll offset into `top` on the way in and puts it back on the way out. The
| seller returns to the same paragraph they left.
*/
body.is-sheet-open {
    position: fixed;
    inset-inline: 0;
    width: 100%;
    overflow: hidden;
}

/* ------------------------------------------------ the wallet's order link --

   Every commission row in the ledger already knew which order it belonged to;
   the page was printing the number and not the word. A seller read
   "کارمزد سفارش 918854" beside a sale they had just watched settle, could not
   tell what kind of number that was, and concluded it referred to some other
   order entirely.

   So the number became a labelled link. It is styled as a link on purpose —
   accent ink, a chevron, an underline on hover — because the whole complaint
   was about text that carried information nobody could act on.
*/
.wallet-row__order {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    min-height: 24px;
    color: var(--accent-ink);
    font-weight: 700;
    font-size: .9rem;
}

.wallet-row__go {
    color: var(--text-faint);
    font-size: 1rem;
    line-height: 1;
}

/* The commission pair on the order page: the same two facts from the other
   side, so the relationship reads in both directions. */
.order-commission {
    margin-top: .6rem;
    padding-top: .6rem;
    border-top: 1px dashed var(--border);
}

.order-commission__note {
    margin: .5rem 0 0;
    color: var(--text-muted);
    font-size: .8rem;
    line-height: 1.9;
}

.order-commission__note a {
    color: var(--accent-ink);
    font-weight: 700;
}

/* ------------------------------------------- disclosures and filter chips --

   The last two families of "interactive element drawn as typography" found in
   the panel audit.

   1. THREE BARE <summary> ELEMENTS on the order page — لغو سفارش, بارگذاری
      دوباره فایل رسید, فایل‌های قبلی رسید. The two dangerous disclosures next
      to them already wore .btn; these three were a default marker and body
      text, so "لغو سفارش" read as a heading for a section that was not there.

      They keep their own shape rather than becoming .btn, because that is what
      they are: a thing that opens, not a thing that submits. The chevron
      rotating on open is what says so, and the confirm button inside each one
      is still the only control that acts.

   2. INACTIVE FILTER CHIPS on the order list. The selected one had a tinted
      pill behind it and the rest had nothing, so a row of five filters looked
      like one control and four words.
*/
.cancel-order > summary,
.receipt-replace > summary,
.receipt-history > summary {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    min-height: 44px;
    padding: 0 .9rem;
    border: 1.5px solid var(--border-strong);
    border-radius: var(--radius-pill);
    color: var(--accent-ink);
    font-size: 14px;
    font-weight: 700;
    cursor: pointer;
    list-style: none;
}

/* Safari draws its own triangle through a pseudo-element that list-style
   cannot reach. */
.cancel-order > summary::-webkit-details-marker,
.receipt-replace > summary::-webkit-details-marker,
.receipt-history > summary::-webkit-details-marker {
    display: none;
}

.cancel-order > summary::after,
.receipt-replace > summary::after,
.receipt-history > summary::after {
    content: '⌄';
    line-height: 1;
    transition: transform var(--fast) var(--ease);
}

.cancel-order[open] > summary::after,
.receipt-replace[open] > summary::after,
.receipt-history[open] > summary::after {
    transform: rotate(180deg);
}

.cancel-order > summary:hover,
.receipt-replace > summary:hover,
.receipt-history > summary:hover {
    border-color: var(--accent);
    background: rgb(var(--sky-rgb) / .08);
}

/* Cancelling an order cannot be undone. The outline says so before the panel
   inside it does. */
.cancel-order > summary {
    color: var(--danger);
    border-color: rgb(var(--bad-rgb) / .35);
}

.cancel-order > summary:hover {
    border-color: var(--danger);
    background: rgb(var(--bad-rgb) / .08);
}

.order-filters a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    border: 1px solid var(--border);
    background: var(--bg);
}

.order-filters a:hover {
    border-color: var(--accent);
    text-decoration: none;
}

.order-filters a.is-active {
    border-color: var(--accent);
}
