@import url('brand-fonts.css');
:root {
    --accent: #0088ff; --accent-soft: #4facfe; --bg-main: #f0f4f8;
    --glass-bg: rgba(255, 255, 255, 0.95); --border-light: rgba(0, 0, 0, 0.08);
    --text-main: #0f172a; --text-muted: #64748b; --input-bg: #ffffff;
    --tab-track-bg: rgba(0, 0, 0, 0.05); --tab-slider-bg: #ffffff;
    /* --font-en is the MONO stack on purpose: it dresses the latin-only
       fields (email, password, IMEI) where 0/O must not be confusable. */
    --font-fa: var(--font-ui); --font-en: var(--font-mono);
    --success: #10b981; --warning: #f59e0b; --danger: #ef4444;
    --modal-bg: rgba(0,0,0,0.5);
}

body.dark-theme {
    --accent: #38bdf8; --accent-soft: #818cf8; --bg-main: #0b1120;
    --glass-bg: rgba(30, 41, 59, 0.95); --border-light: rgba(255, 255, 255, 0.1);
    --text-main: #f8fafc; --text-muted: #94a3b8; --input-bg: rgba(15, 23, 42, 0.8);
    --tab-track-bg: rgba(0, 0, 0, 0.3); --tab-slider-bg: #1e293b;
}

* { box-sizing: border-box; margin: 0; padding: 0; outline: none; }
body { background-color: var(--bg-main); font-family: var(--font-fa); color: var(--text-main); min-height: 100vh; display: flex; justify-content: center; align-items: center; opacity: 0; transition: opacity 0.4s, background-color 0.4s; padding: 15px; user-select: none; -webkit-user-select: none; }
/* One family for both languages: the stack covers Latin and Persian. */

.auth-container { background: var(--glass-bg); backdrop-filter: blur(20px); border: 1px solid var(--border-light); border-radius: 24px; padding: 35px 30px; width: 100%; max-width: 440px; box-shadow: 0 30px 60px -15px rgba(0,0,0,0.15); position: relative; transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); }
.auth-container:hover { transform: translateY(-5px); box-shadow: 0 40px 70px -15px rgba(0,0,0,0.2); }

.top-controls { display: flex; justify-content: space-between; margin-bottom: 25px; }
.control-btn { background: var(--input-bg); border: 1px solid var(--border-light); border-radius: 12px; padding: 8px 16px; color: var(--text-main); cursor: pointer; font-weight: bold; font-size: 13px; transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); box-shadow: 0 2px 4px rgba(0,0,0,0.02); }
.control-btn:hover { border-color: var(--accent); color: var(--accent); transform: translateY(-2px) scale(1.05); box-shadow: 0 8px 15px var(--accent-glow); }

.auth-header { text-align: center; margin-bottom: 30px; }
.logo-box { width: 65px; height: 65px; border-radius: 18px; margin: 0 auto 15px; display: flex; align-items: center; justify-content: center; overflow: hidden; box-shadow: 0 10px 25px var(--accent-glow); transition: all 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); cursor: pointer; }
.logo-box img { width: 100%; height: 100%; object-fit: cover; }
.logo-box:hover { transform: scale(1.15) rotate(8deg); box-shadow: 0 15px 35px var(--accent-glow); }

/* ---- Iran mode ------------------------------------------------------------
   The logo's own mark is NOT here: it lives in src/IranBadge.php so that the
   auth screens, the public navbar and the panel shell cannot drift apart. What
   stays here is the note under the password field, which only this page has.
   Red, because it is the same warning the logo is giving. */
.iran-note {
    align-self: flex-start; margin: -4px 0 0; font-size: 12px; line-height: 1.7;
    color: #e11d48; opacity: .95; unicode-bidi: plaintext; text-align: start;
}
.iran-note-link {
    color: #be123c; font-weight: bold; text-decoration: underline;
    cursor: pointer; transition: opacity .3s;
}
.iran-note-link:hover { opacity: .75; }
/* Rose-600 goes muddy on the dark card; these are the same hues lifted. */
body.dark-theme .iran-note      { color: #fb7185; }
body.dark-theme .iran-note-link { color: #fda4af; }
/* Same idea inside a toast: when the reply names a page that resolves the
   problem, the whole line becomes the way to get there.

   NOT underlined at rest. This line is a whole sentence — often two — and a rule
   drawn under every word of it reads as damage rather than as a link, which is
   what the registration toast looked like in Iran mode. The affordance is the
   arrow and the hover instead: enough to say "this goes somewhere", quiet enough
   to still read as a sentence. */
a.mako-text {
    text-decoration: none; cursor: pointer;
    text-underline-offset: 3px;
}
a.mako-text::after {
    content: '\00A0\2190';          /* nbsp + a left arrow: the RTL "onward" */
    font-weight: 700; opacity: .75;
}
[dir="ltr"] a.mako-text::after { content: '\00A0\2192'; }
a.mako-text:hover { opacity: .8; text-decoration: underline; }
.auth-header h2 { font-size: 22px; font-weight: 800; }

.tab-track { display: flex; background: var(--tab-track-bg); padding: 6px; border-radius: 14px; margin-bottom: 5px; position: relative; }
.tab-slider { position: absolute; width: calc(50% - 6px); top: 6px; bottom: 6px; background: var(--tab-slider-bg); border-radius: 10px; transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); z-index: 1; box-shadow: 0 2px 10px rgba(0,0,0,0.05); }
body[dir="rtl"] .tab-slider.pos-0 { right: 6px; }
body[dir="rtl"] .tab-slider.pos-1 { right: 50%; }
body[dir="ltr"] .tab-slider.pos-0 { left: 6px; }
body[dir="ltr"] .tab-slider.pos-1 { left: 50%; }

.tab-btn { flex: 1; padding: 12px; border: none; background: transparent; color: var(--text-muted); font-weight: bold; font-size: 14px; z-index: 2; cursor: pointer; transition: color 0.3s; }
.tab-btn.active { color: var(--accent); }

.forms-wrapper { position: relative; width: 100%; min-height: 250px; }
.auth-form { display: flex; flex-direction: column; gap: 16px; width: 100%; animation: fadeInSlide 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) forwards; }

/* One field per row. Side by side, each field got half the card — enough to
   clip a full name mid-word and to hide most of a long password behind its own
   edge, with no way for the visitor to see what they had typed. */
.form-row { display: flex; flex-direction: column; gap: 12px; width: 100%; }
.form-group { position: relative; width: 100%; }
.form-group input { width: 100%; padding: 16px 18px; background: var(--input-bg); border: 1px solid var(--border-light); border-radius: 14px; color: var(--text-main); font-size: 14px; transition: all 0.3s ease; }
.form-group input:focus { border-color: var(--accent); box-shadow: 0 0 0 4px rgba(0, 136, 255, 0.15); outline: none; }
.form-group input.invalid { border-color: var(--danger); box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.15); }
.form-group input.valid { border-color: var(--success); }

.en-input { font-family: var(--font-en) !important; text-align: left !important; direction: ltr !important; }

/* ------------------------------------------------------ floating field labels
   The field name used to live in the placeholder, so it VANISHED the moment
   anyone started typing: half way through a form you could no longer tell
   which box was the username and which the email. It is a real <label> now,
   resting where the placeholder used to sit and lifting onto the top border as
   soon as the field is focused or filled, where it stays readable for good.

   The (i) button that used to explain each field is gone with it — a label
   that names the field explains it better than a modal you have to open. */
.form-group > label {
    position: absolute; top: 50%; transform: translateY(-50%);
    max-width: calc(100% - 34px); overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
    padding: 0 6px; font-size: 13.5px; font-weight: 500; line-height: 1;
    color: var(--text-muted); pointer-events: none; border-radius: 6px;
    /* Transparent at rest so the field reads as one surface; opaque once it is
       floating, which is what cuts the gap in the border it sits on. */
    background: transparent;
    transition: top .18s ease, font-size .18s ease, color .18s ease, background-color .18s ease;
}
body[dir="rtl"] .form-group > label { right: 12px; left: auto; }
body[dir="ltr"] .form-group > label { left: 12px; right: auto; }

.form-group input:focus + label,
.form-group input:not(:placeholder-shown) + label {
    top: 0; font-size: 11.5px; font-weight: 700;
    color: var(--accent); background: var(--input-bg);
}
/* The label carries the field's state too, so the colour is not only in a
   border that a red-green-blind eye may not separate. */
.form-group input.valid:focus + label,
.form-group input.valid:not(:placeholder-shown) + label { color: var(--success); }
.form-group input.invalid:focus + label,
.form-group input.invalid:not(:placeholder-shown) + label { color: var(--danger); }

.global-farsi-warning {
    background: var(--danger); color: white; font-size: 13px; padding: 10px; border-radius: 10px;
    font-weight: bold; text-align: center; margin-bottom: 15px; display: none;
    box-shadow: 0 4px 12px rgba(239,68,68,0.3); animation: shake 0.4s;
}

/* The eye sits at the reading END of the field, opposite the label, so the two
   never overlap; the field reserves room for it on that side only. */
.toggle-password { position: absolute; top: 50%; transform: translateY(-50%); background: none; border: none; cursor: pointer; padding: 5px; z-index: 5; transition: all 0.3s ease; color: var(--text-muted); font-size: 18px; display: flex; align-items: center; justify-content: center;}
.toggle-password:hover { transform: translateY(-50%) scale(1.15); color: var(--text-main); }

body[dir="rtl"] .toggle-password { right: auto; left: 14px; }
body[dir="ltr"] .toggle-password { left: auto; right: 14px; }

body[dir="rtl"] .has-eye { padding-left: 46px !important; padding-right: 18px !important; }
body[dir="ltr"] .has-eye { padding-right: 46px !important; padding-left: 18px !important; }

/* ------------------------------------------------------- password rule sheet
   The rules are a checklist that ticks itself off while you type, and it is
   absolutely positioned so showing it costs the card no height — the reason it
   is a popover and not a block of text under the field. */
/* Opens UPWARD. Absolute positioning keeps it out of the layout, but a box that
   hangs below the last field still counts toward .auth-container's scrollable
   overflow — which is what put a scrollbar on the sign-up form the moment the
   password field was focused. Above the field that space already exists. */
.pass-rules {
    position: absolute; bottom: calc(100% + 8px); inset-inline-start: 0; z-index: 30;
    width: 100%; box-sizing: border-box; text-align: start;
    background: var(--glass-bg); border: 1px solid var(--border-light); border-radius: 12px;
    box-shadow: 0 14px 34px rgba(0,0,0,0.16); padding: 9px 12px;
    opacity: 0; visibility: hidden; transform: translateY(6px);
    transition: opacity .18s ease, transform .18s ease, visibility .18s;
}
.pass-rules.open { opacity: 1; visibility: visible; transform: none; }
.pass-rules div {
    display: flex; align-items: center; gap: 7px;
    font-size: 11.5px; line-height: 1.85; color: var(--text-muted);
    transition: color .2s ease;
}
.pass-rules div::before {
    content: "•"; flex: none; width: 13px; text-align: center; font-weight: 800; opacity: .6;
}
.pass-rules div.ok { color: var(--success); }
.pass-rules div.ok::before { content: "✓"; opacity: 1; }

/* Password and its confirmation stack instead of splitting the row in two.
   A password long enough to pass the rules does not fit in half a card, so the
   visitor could never read back what they had typed — the reason the two boxes
   in the report showed a handful of characters each. The confirmation still
   appears only once the first password is strong enough; it now grows downward
   rather than squeezing in from the side. */
.pass-anim-row { display: flex; flex-direction: column; width: 100%; transition: gap 0.4s ease; gap: 0; }
.pass-anim-row.show-confirm { gap: 12px; }

.pass-col-1 { width: 100%; flex: none; }
.pass-col-2 {
    width: 100%; flex: none; max-height: 0; opacity: 0; overflow: hidden; visibility: hidden;
    transition: max-height 0.4s ease, opacity 0.3s ease, visibility 0.3s;
}
.pass-anim-row.show-confirm .pass-col-2 { max-height: 90px; opacity: 1; visibility: visible; overflow: visible; }

.password-strength { position: absolute; bottom: 3px; left: 6px; right: 6px; height: 4px; border-radius: 4px; background: var(--strength-color, transparent); width: calc(var(--strength, 0%) - 12px); transition: width 0.4s ease, background-color 0.4s ease; z-index: 2; pointer-events: none; }

.btn-action { width: 100%; padding: 16px; background: linear-gradient(135deg, var(--accent), var(--accent-soft)); border: none; border-radius: 14px; color: white; font-weight: bold; font-size: 15px; cursor: pointer; transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); box-shadow: 0 8px 25px rgba(0, 136, 255, 0.25); margin-top: 10px; position: relative; overflow: hidden; }
.btn-action:hover { transform: translateY(-3px) scale(1.02); box-shadow: 0 15px 35px rgba(0, 136, 255, 0.4); }
.btn-action:active { transform: translateY(1px) scale(0.98); }
.btn-action:disabled { opacity: 0.7; cursor: not-allowed; transform: none; box-shadow: none; }

.cf-wrapper { min-height: 65px; display: flex; justify-content: center; margin-top: 5px; width: 100%; }
.text-link { color: var(--text-muted); font-size: 14px; text-decoration: none; cursor: pointer; text-align: center; display: block; margin-top: 10px; font-weight: bold; transition: all 0.3s; }
.text-link:hover { color: var(--accent); transform: translateY(-1px); }


/* "Forgot your password?" is the escape hatch for someone who is already stuck,
   so it cannot be the faintest thing on the screen. It carries the accent
   colour at the muted size, which reads as a link without competing with the
   sign-in button. */
.text-link-inline { align-self: flex-start; margin-top: -8px; color: var(--accent); font-size: 13px; font-weight: bold; text-decoration: none; cursor: pointer; transition: color 0.3s, text-decoration-color 0.3s; }
.text-link-inline:hover { color: var(--accent); text-decoration: underline; }

.alert-box { display: none; padding: 14px; border-radius: 12px; font-size: 13px; text-align: center; margin-bottom: 20px; font-weight: bold; animation: fadeInSlide 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) forwards; width: 100%; line-height: 1.6; }
.alert-error { background: rgba(239, 68, 68, 0.1); color: var(--danger); border: 1px solid rgba(239, 68, 68, 0.3); }
.alert-success { background: rgba(16, 185, 129, 0.1); color: var(--success); border: 1px solid rgba(16, 185, 129, 0.3); }

.timer-badge { background: rgba(245, 158, 11, 0.15); color: var(--warning); padding: 10px 24px; border-radius: 12px; font-size: 18px; font-family: var(--font-en); font-weight: bold; margin-bottom: 15px; display: inline-block; letter-spacing: 3px; border: 1px solid rgba(245, 158, 11, 0.3); box-shadow: inset 0 0 15px rgba(245, 158, 11, 0.1); }

#loaderOverlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: var(--glass-bg); backdrop-filter: blur(10px); z-index: 9999; display: none; justify-content: center; align-items: center; flex-direction: column; font-weight: bold; }
.spinner { border: 4px solid var(--border-light); border-top: 4px solid var(--accent); border-radius: 50%; width: 50px; height: 50px; animation: spin 1s cubic-bezier(0.5, 0.1, 0.4, 0.9) infinite; margin-bottom: 15px; }

.ui-modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: var(--modal-bg); backdrop-filter: blur(5px); z-index: 10000; display: flex; justify-content: center; align-items: center; opacity: 0; visibility: hidden; transition: all 0.3s ease; }
.ui-modal-overlay.active { opacity: 1; visibility: visible; }
.ui-modal { background: var(--glass-bg); border: 1px solid var(--border-light); border-radius: 24px; padding: 30px; width: 90%; max-width: 400px; box-shadow: 0 25px 50px rgba(0,0,0,0.2); transform: scale(0.9) translateY(20px); transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); text-align: center; }
.ui-modal-overlay.active .ui-modal { transform: scale(1) translateY(0); }
.ui-modal-icon { width: 60px; height: 60px; border-radius: 50%; background: rgba(0, 136, 255, 0.1); color: var(--accent); display: flex; align-items: center; justify-content: center; font-size: 28px; margin: 0 auto 20px; }
.ui-modal-icon.error-style { background: rgba(239, 68, 68, 0.1); color: var(--danger); }
.ui-modal-title { font-size: 18px; font-weight: 800; margin-bottom: 10px; color: var(--text-main); }
/* pre-line: the password and email guides are LISTS, one rule per line. Run
   together in a paragraph, "8 characters, uppercase, lowercase, number, symbol"
   reads as one vague sentence and nobody can tell which part they failed.
   text-align:start keeps the list edge-aligned instead of centred, so the
   bullets line up under each other. */
.ui-modal-desc { font-size: 14px; color: var(--text-muted); line-height: 1.9; margin-bottom: 25px; white-space: pre-line; text-align: start; }
.ui-modal-btn { width: 100%; padding: 12px; background: var(--input-bg); border: 1px solid var(--border-light); border-radius: 12px; font-weight: bold; color: var(--text-main); cursor: pointer; transition: 0.3s; }
.ui-modal-btn:hover { background: var(--accent); color: white; border-color: var(--accent); }

body div[style*="z-index: 2147483646"] {
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
}
body div[style*="z-index: 2147483646"] > div {
    display: block !important;
    width: auto !important;
    height: auto !important;
}


@media (max-width: 600px), (max-height: 780px) {
    body { padding: 10px; }

    .auth-container { padding: 20px 18px; border-radius: 20px; }

    .top-controls { margin-bottom: 14px; }
    .control-btn { padding: 7px 14px; }

    .auth-header { margin-bottom: 16px; }
    .logo-box { width: 52px; height: 52px; margin-bottom: 10px; border-radius: 15px; }
    .auth-header h2 { font-size: 19px; }

    .tab-track { padding: 4px; }
    .tab-slider { width: calc(50% - 4px); top: 4px; bottom: 4px; }
    body[dir="rtl"] .tab-slider.pos-0 { right: 4px; }
    body[dir="ltr"] .tab-slider.pos-0 { left: 4px; }
    .tab-btn { padding: 9px; font-size: 13px; }

    .forms-wrapper { min-height: 0; }
    .auth-form { gap: 11px; }
    .form-group input { padding: 13px 16px; }

    .cf-wrapper { min-height: 0; margin-top: 0; }
    .btn-action { padding: 13px; margin-top: 3px; }
    .text-link { margin-top: 4px; font-size: 13px; }
    .text-link-inline { margin-top: -5px; }


    body .oauth-divider { margin: 7px 0 5px; font-size: 12px; }
    body .social-btn { min-height: 44px; padding: 10px 42px; font-size: 13px; }

    body .social-btn + .social-btn { margin-top: -3px; }
    body .social-btn .social-ico { inset-inline-start: 14px; }

    .alert-box { margin-bottom: 12px; padding: 11px; }
    .global-farsi-warning { margin-bottom: 10px; padding: 8px; }
}


@media (max-height: 720px) {
    .auth-container { padding: 14px 16px; }

    .top-controls { margin-bottom: 10px; }
    .control-btn { padding: 6px 12px; font-size: 12px; }

    .auth-header { margin-bottom: 10px; }
    .logo-box { width: 42px; height: 42px; margin-bottom: 6px; border-radius: 13px; }
    .auth-header h2 { font-size: 17px; }

    .tab-track { margin-bottom: 3px; }
    .tab-btn { padding: 8px; }

    .auth-form { gap: 9px; }
    .form-group input { padding: 11px 15px; }

    .btn-action { padding: 12px; margin-top: 2px; }
    .text-link-inline { font-size: 12px; margin-top: -4px; }

    body .oauth-divider { margin: 5px 0 4px; }
    body .social-btn { min-height: 40px; padding: 9px 40px; font-size: 12.5px; }

    body .social-btn + .social-btn { margin-top: -2px; }
    body .social-btn .social-ico { inset-inline-start: 13px; width: 18px; height: 18px; }
    body .social-btn .social-ico svg { width: 18px; height: 18px; }


    body .math-cap-card { padding: 9px 12px; }
    body .math-cap-head { margin-bottom: 6px; font-size: 11px; }
    body .math-cap-svg { min-height: 34px; padding: 3px 7px; }
    body .math-cap-svg svg { max-height: 32px; }
    body .math-cap-input { padding: 9px 8px !important; font-size: 16px; }
}


@media (hover: none) {
    .auth-container:hover { transform: none; box-shadow: 0 30px 60px -15px rgba(0,0,0,0.15); }
}

@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
@keyframes fadeInSlide { from { opacity: 0; transform: translateY(-15px); } to { opacity: 1; transform: translateY(0); } }
@keyframes shake { 0%, 100% {transform: translateY(-50%) translateX(0);} 25% {transform: translateY(-50%) translateX(-4px);} 75% {transform: translateY(-50%) translateX(4px);} }

.mako-stack {
    /* Top CENTER, not a corner. The stack used to sit on the reading-start
       side, which put it under the right edge in Persian and the left edge in
       English — two different places for the same message, and in both cases
       far from where the eye is (the form). Centering with a translate keeps
       it language-independent: `left:50%` is a physical edge, so it does not
       flip with `dir`. */
    position: fixed; top: 16px; left: 50%; transform: translateX(-50%); z-index: 4000;
    display: flex; flex-direction: column; gap: 10px;
    width: min(360px, calc(100vw - 32px));
    pointer-events: none;


    --mako-font: "Vazirmatn", "IRANSans", "Segoe UI", system-ui, -apple-system,
                 "Noto Sans Arabic", "Noto Sans", Tahoma, Arial, sans-serif;
    font-family: var(--mako-font);
}

.mako {
    position: relative; overflow: hidden;
    display: flex; align-items: flex-start; gap: 11px;
    padding: 13px 14px;
    background: var(--glass-bg);
    border: 1px solid var(--border-light);

    border-inline-start: 3px solid var(--mako-accent, var(--accent));
    border-radius: 12px;
    box-shadow: 0 12px 30px rgba(0,0,0,0.18);
    backdrop-filter: blur(10px);
    color: var(--text-main);
    pointer-events: auto; cursor: pointer;
    animation: makoIn .32s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
.mako.out { animation: makoOut .22s ease forwards; }

.mako-ico {
    flex: none; width: 22px; height: 22px; border-radius: 7px;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 12px; font-weight: 800; line-height: 1;
    background: color-mix(in srgb, var(--mako-accent, var(--accent)) 16%, transparent);
    color: var(--mako-accent, var(--accent));
}

@supports not (background: color-mix(in srgb, red 10%, transparent)) {
    .mako-ico { background: rgba(127,127,127,.14); }
}

.mako-body { min-width: 0; flex: 1; }
.mako-title {
    font-family: var(--mako-font);
    font-size: 12px; font-weight: 700; line-height: 1.5;
    letter-spacing: .01em;
    color: var(--mako-accent, var(--accent)); margin-bottom: 3px;

    unicode-bidi: plaintext; text-align: start;
}
.mako-text {
    font-family: var(--mako-font);

    font-size: 13px; line-height: 1.85; font-weight: 500;
    color: var(--text-main);
    word-break: break-word; overflow-wrap: anywhere; opacity: .95;


    unicode-bidi: plaintext;
    text-align: start;
}

.mako-x {
    flex: none; background: none; border: 0; padding: 0; cursor: pointer;
    color: var(--text-muted); font-size: 15px; line-height: 1; opacity: .5;
}
.mako-x:hover { opacity: 1; color: var(--text-main); }


.mako-bar {
    position: absolute; bottom: 0; inset-inline-start: 0; height: 2px;
    background: var(--mako-accent, var(--accent)); opacity: .5;
    animation: makoBar linear forwards;
}

@keyframes makoIn  { from { opacity: 0; transform: translateY(-10px) scale(.98); } to { opacity: 1; transform: none; } }
@keyframes makoOut { to { opacity: 0; transform: translateY(-8px) scale(.98); } }
@keyframes makoBar { from { width: 100%; } to { width: 0%; } }

@media (prefers-reduced-motion: reduce) {
    .mako, .mako.out { animation: none; }
    .mako-bar { animation: none; width: 0; }
}

@media (max-width: 520px) {
    .mako-stack { top: 10px; width: calc(100vw - 20px); }
    .mako-text { font-size: 12.5px; line-height: 1.8; }
}


/* ============================================================================
   THE SIGN-IN PAGE DOES NOT SCROLL.

   Everything above sizes itself in fixed pixels, which is fine on a tall
   window and pushes the sign-up form off the bottom of a short one — the card
   grew, the page grew with it, and the visitor had to scroll a form that is
   supposed to be one screen.

   The page is now pinned to the viewport (body cannot scroll at all) and the
   card's own metrics are tied to viewport height, so it shrinks to fit instead
   of overflowing. The ladder below is ordered shortest-wins. `dvh` is used
   because a mobile URL bar changes the usable height as it hides and shows.

   The card keeps `overflow-y: auto` as a LAST RESORT: on a window too short
   for any layout (a phone in landscape, a 400px browser window) content must
   stay reachable rather than be cut off. In every ordinary window nothing
   scrolls, which is what the report asked for.
   ========================================================================== */
/* dvh on both, or the document scrolls by exactly the height of a mobile URL
   bar: 100% here resolves against the large viewport, body against the dynamic
   one, and body's overflow:hidden cannot contain a taller <html>. */
html { height: 100dvh; overflow: hidden; }
body {
    height: 100dvh; min-height: 0; overflow: hidden;
    padding: clamp(8px, 1.2vh, 15px);
}
.auth-container {
    /* 100% of the flex parent's content box, so this tracks body padding as it
       grows with the viewport. The old calc() hard-coded the 8px-per-side
       minimum, so on a tall window the card claimed up to 14px more than it was
       given and flex centring clipped that off the top, out of reach. */
    max-height: 100%;
    overflow-y: auto; overscroll-behavior: contain;
    scrollbar-width: thin;
    padding: clamp(14px, 2.6vh, 35px) clamp(16px, 2.2vw, 30px);
}
/* Lifting the whole card on hover inside a height-constrained viewport just
   pushes its own bottom edge out of view. */
.auth-container:hover { transform: none; }

.forms-wrapper { min-height: 0; }
.top-controls  { margin-bottom: clamp(8px, 1.6vh, 25px); }
.auth-header   { margin-bottom: clamp(8px, 1.8vh, 30px); }
.logo-box      { width: clamp(40px, 6.2vh, 65px); height: clamp(40px, 6.2vh, 65px); margin-bottom: clamp(5px, 1vh, 15px); }
.auth-header h2 { font-size: clamp(16px, 2.3vh, 22px); }
.auth-form     { gap: clamp(9px, 1.6vh, 16px); }
.form-group input { padding: clamp(10px, 1.6vh, 16px) 18px; }
.btn-action    { padding: clamp(11px, 1.7vh, 16px); margin-top: clamp(2px, 0.6vh, 10px); }
.tab-btn       { padding: clamp(8px, 1.3vh, 12px); }
.cf-wrapper    { min-height: 0; margin-top: 0; }
body .social-btn { min-height: clamp(38px, 5vh, 48px); }
body .oauth-divider { margin: clamp(4px, 1vh, 16px) 0 clamp(3px, 0.8vh, 12px); }

/* The label rides on the border, so it has to shrink with the field or it will
   sit taller than the box it belongs to. */
.form-group > label { font-size: clamp(12px, 1.7vh, 13.5px); }
.form-group input:focus + label,
.form-group input:not(:placeholder-shown) + label { font-size: clamp(10px, 1.4vh, 11.5px); }

/* The remaining fixed heights, tied to the viewport for the same reason as the
   block above: on a short window the sign-up form reaches its tallest state
   (confirmation field revealed) and these were the pixels that pushed it past
   the bottom edge. */
.form-row { gap: clamp(8px, 1.3vh, 12px); }
.pass-anim-row.show-confirm { gap: clamp(6px, 1.1vh, 12px); }
.tab-track { margin-bottom: clamp(2px, 0.6vh, 5px); }
.global-farsi-warning { margin-bottom: clamp(6px, 1.2vh, 15px); padding: clamp(6px, 1vh, 10px); }
.text-link { margin-top: clamp(3px, 0.8vh, 10px); }

/* Below this the window is shorter than any arrangement of a five-field form.
   The logo is the one element that carries no information the visitor needs to
   fill it in, so it is what goes — losing it keeps every field and the button
   on screen, which is the point. */
/* A laptop window this short still has to show the whole sign-up form in its
   tallest state. Everything here is chrome, not content: the mark shrinks, the
   gaps close up, the social buttons lose a few pixels of padding. No field and
   no button is removed or made smaller than a comfortable tap target. */
@media (max-height: 720px) {
    .logo-box { width: 34px; height: 34px; margin-bottom: 4px; border-radius: 11px; }
    .auth-header { margin-bottom: 6px; }
    .auth-header h2 { font-size: 15px; }
    .top-controls { margin-bottom: 6px; }
    .auth-form { gap: 7px; }
    body .social-btn { min-height: 36px; padding-top: 7px; padding-bottom: 7px; }
    body .oauth-divider { margin: 3px 0 3px; }
}

@media (max-height: 620px) {
    .logo-box { display: none; }
    .auth-header { margin-bottom: 6px; }
    .auth-header h2 { font-size: 15px; }
    .top-controls { margin-bottom: 6px; }
    .auth-form { gap: 6px; }
    .form-group input { padding: 9px 16px; }
    .btn-action { padding: 10px; margin-top: 2px; }
    body .social-btn { min-height: 34px; }
    body .math-cap-card { padding: 6px 10px; }
    body .math-cap-head { margin-bottom: 3px; }
}

/* The project face (IRANSansX) sits taller than the Tahoma it replaced, which
   put the fully-expanded sign-up form back over the edge on a short window.
   This tier gives those pixels back where they are least missed. */
@media (max-height: 820px) {
    .auth-form { gap: 8px; }
    .form-group input { padding-top: 10px; padding-bottom: 10px; }
    .btn-action { padding-top: 12px; padding-bottom: 12px; }
    body .social-btn { min-height: 40px; }
    .auth-header { margin-bottom: 8px; }
    .auth-container, .auth-container p, .auth-container span { line-height: 1.55; }
}

/* Source order decides between equal-specificity media rules, and the 820px
   tier above sits after the 720/620 ones — which made the SHORTEST windows use
   the loosest metrics. These re-state the tight tiers last, so shortest wins. */
@media (max-height: 720px) {
    .auth-form { gap: 7px; }
    .form-group input { padding-top: 9px; padding-bottom: 9px; }
    .btn-action { padding-top: 11px; padding-bottom: 11px; }
    body .social-btn { min-height: 36px; }
    .auth-header { margin-bottom: 6px; }
    .form-row { gap: 8px; }
    .pass-anim-row.show-confirm { gap: 7px; }
    .tab-btn { padding: 7px; }
    .tab-track { margin-bottom: 0; }
    .text-link-inline { margin-top: -6px; }
    .iran-note { margin-top: -5px; font-size: 11px; line-height: 1.5; }
    .auth-container { padding-top: 12px; padding-bottom: 12px; }
}
@media (max-height: 620px) {
    .auth-form { gap: 6px; }
    .form-group input { padding-top: 8px; padding-bottom: 8px; }
    .btn-action { padding-top: 10px; padding-bottom: 10px; }
    body .social-btn { min-height: 34px; }
    .logo-box { display: none; }
    .form-row { gap: 6px; }
    .pass-anim-row.show-confirm { gap: 5px; }
    .tab-btn { padding: 6px; }
    .auth-container { padding: 10px 14px; }
}

/* ---- preferences, not choices -------------------------------------------
   Row 145: the theme and language buttons were the same weight as everything
   else on the sign-in screen, so three controls competed where one form was the
   point. They keep their place (someone who cannot read the page has to be able
   to switch language before anything else) and lose their loudness. */
.lg-prefs { display: flex; gap: 6px; }
.lg-prefs .control-btn.is-quiet {
    padding: 6px 10px; font-size: 12px; font-weight: 700;
    background: transparent; border-color: transparent;
    color: var(--text-muted); box-shadow: none; opacity: .75;
}
.lg-prefs .control-btn.is-quiet:hover {
    opacity: 1; transform: none; box-shadow: none;
    border-color: var(--border-light); color: var(--accent);
}

/* ===========================================================================
   REGISTER FIT — part 1 of 2: one monotone ladder instead of a stepped one.

   Every metric on this card is clamp(min, N vh, max). The ladder that steps
   those metrics down begins at (max-height: 820px), but the register card's
   LOOSEST layout measures ~1003px, so every window between 821px and roughly
   1050px tall renders metrics it has no room for. That is why 1440x900
   overflowed by 121px while 1366x768 overflowed by only 63: the TALLER window
   was on the LOOSER rung.

   These replace the ceilings AND lower each clamp's floor to the value the old
   (max-height: 720px)/(620px) tiers were already using, so the ladder is
   continuous: nothing jumps at a breakpoint and the card gets monotonically
   tighter as the window shortens. Appended at the END of login-style.css, so
   it wins over the stepped tiers above it on equal specificity.

   One floor deliberately goes UP: the social buttons had a 34-38px floor, and
   34px is not a tap target. They now start at 40px. The refresh button in the
   captcha was 32px on a short window and is now a flat 40px, which costs no
   height at all because the answer box beside it is taller.
   ========================================================================= */

.auth-container   { padding-top: clamp(10px, 1.7vh, 18px); padding-bottom: clamp(10px, 1.7vh, 18px); }
.top-controls     { margin-bottom: clamp(6px, 1vh, 10px); }
.auth-header      { margin-bottom: clamp(6px, 0.9vh, 9px); }
.auth-header h2   { font-size: clamp(15px, 2vh, 18px); }
.logo-box         { width: clamp(32px, 4vh, 42px); height: clamp(32px, 4vh, 42px);
                    margin-bottom: clamp(4px, 0.6vh, 6px); }
.tab-track        { margin-bottom: clamp(0px, 0.3vh, 3px); }

.auth-form        { gap: clamp(6px, 1vh, 11px); }
.form-row         { gap: clamp(6px, 0.9vh, 9px); }
.pass-anim-row.show-confirm { gap: clamp(5px, 0.8vh, 8px); }

.form-group input { padding-top: clamp(8px, 1.1vh, 11px); padding-bottom: clamp(8px, 1.1vh, 11px); }
.btn-action       { padding-top: clamp(10px, 1.3vh, 12px); padding-bottom: clamp(10px, 1.3vh, 12px);
                    margin-top: clamp(2px, 0.4vh, 4px); }

body .oauth-divider { margin: clamp(3px, 0.6vh, 6px) 0 clamp(3px, 0.5vh, 5px); }
body .social-btn,
body .social-row.dual .social-btn { min-height: clamp(40px, 4.4vh, 42px); }

/* The math captcha is the tallest non-field block in the card (83-104px before
   this). Same treatment, and the answer box stays at or above 40px. */
body .math-cap-card  { padding-top: clamp(6px, 0.9vh, 8px); padding-bottom: clamp(6px, 0.9vh, 8px); }
body .math-cap-head  { margin-bottom: clamp(3px, 0.5vh, 5px); }
body .math-cap-svg   { min-height: clamp(30px, 3.6vh, 34px); }
body .math-cap-svg svg, body .math-cap-svg img { max-height: clamp(28px, 3.4vh, 32px); }
body .math-cap-input { padding-top: clamp(8px, 1vh, 10px) !important;
                       padding-bottom: clamp(8px, 1vh, 10px) !important;
                       font-size: clamp(14px, 1.8vh, 16px); }
body .math-cap-refresh { width: 40px; height: 40px; }


/* ---------------------------------------------------------------------------
   THE 40px FLOOR, stated once instead of chased through the padding.
   Before this, the old ladder shrank real tap targets to get the card to fit
   and STILL did not fit: at 900x600 the name field was 34px, the tab buttons
   27px, the submit button 37px and the captcha's refresh 32px. A min-height is
   both cheaper and honest -- padding can keep breathing with the viewport, the
   box cannot go under the threshold, and the one field whose Persian line box
   is shorter than the latin ones (the full-name box, 34px while every
   .en-input beside it was 39px) stops being the odd one out. */
.form-group input     { min-height: 40px; }
.tab-btn              { min-height: 40px; }
.btn-action           { min-height: 40px; }
.control-btn          { min-height: 40px; }
body .math-cap-input  { min-height: 40px; }
body .social-btn      { min-height: 40px; }

/* The logo was already dropped below 620px of viewport for exactly this
   reason: it is the one element in the card that carries nothing the visitor
   needs in order to fill the form in. The threshold moves up to 760px, which
   is what buys the 1280x720 case its fit once the tap targets are at 40px. */
@media (max-height: 760px) { .logo-box { display: none; } }


/* ===========================================================================
   REGISTER FIT -- part 2 of 2: when it genuinely cannot fit, scroll the FORM,
   not the card.

   Below roughly 660px of usable viewport the sign-up form is simply taller
   than the window once every tap target is at 40px; see the arithmetic in the
   report. The card already had overflow-y:auto as a last resort, but the whole
   card is the scroller, so the header, the logo and the LOGIN/REGISTER tab row
   scroll away with the fields -- which is what reads as "the page scrolls".

   Making the card a flex column and handing the overflow to .forms-wrapper
   pins the chrome and scrolls only the fields. `flex: 0 1 auto` (not 1 1 auto)
   so the wrapper never GROWS to fill a tall card -- it only ever shrinks, and
   on every window where the form fits nothing scrolls at all and nothing about
   the layout changes. The card keeps its own overflow-y:auto underneath as the
   outer last resort, for a window too short even for the pinned chrome.

   BEHIND A HEIGHT QUERY, because it is not free. A scroll container clips BOTH
   axes, so the 4px focus ring needs 4px of padding back -- which narrows the
   content box by 8px -- and `scrollbar-gutter: stable` reserved another 15.
   Measured, that came off the .social-row.dual pair at 11.5px EACH: the Google
   pill went 185.0 -> 173.5 at 1440x900, dropping it under Google's own
   min-content button width (177.4 signin / 182.1 signup) and re-opening the
   very gap the sibling fix above closes. The gutter is gone (the layout here is
   static -- there is no scrollbar appearing mid-session for it to stabilise)
   and the rest only applies at 719px and under, the tallest window measured to
   still need it being 640. Above that the card is exactly what it is today. */
@media (max-height: 719px) {
    .auth-container { display: flex; flex-direction: column; }
    .auth-container > .forms-wrapper {
        flex: 0 1 auto; min-height: 0;
        overflow-y: auto; overscroll-behavior: contain;
        /* A focused field draws a 4px ring; without this the new clipping edge
           shaves it off the sides of the first and last field. */
        padding-inline: 4px; margin-inline: -4px;
    }
}

/* The "?" beside the invite code is a 20x20 target. It is absolutely
   positioned, so a bigger hit area costs the card no height at all. */
.inv-help { position: absolute; }
.inv-help::after { content: ""; position: absolute; inset: -10px; border-radius: 50%; }


/* OPTIONAL refinement: the logo only has to go on the REGISTER tab -- the
   sign-in card has 225px of slack at 1280x720 and never needed to lose it.
   Behind @supports so an engine without :has() simply keeps the plain rule
   above (logo hidden on both tabs under 760px), which is a cosmetic loss, not
   a break. */
@supports selector(:has(*)) {
  @media (max-height: 760px) {
    .auth-container:not(:has(#registerForm)) .logo-box { display: flex; }
  }
}
