/* shared.css
   Design system shared by every KMCTCEM Café page: colour/spacing tokens,
   buttons, form controls, toast, spinner, error messages, and the page
   entrance/exit transition + route loader. Cached across pages after the
   first load, and the single place to tweak the theme. Page-specific
   layout (card shapes, grids, headers) stays in each page's own <style>.
*/

:root {
    --bg: #f3f4f6;
    --card: #ffffff;
    --primary: #e07b3c;
    --primary-hover: #c9692f;
    --text-main: #1e293b;
    --text-muted: #64748b;
    --border: #e2e8f0;
    --radius: 16px;
    --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.05);
    --shadow-md: 0 8px 30px rgba(0, 0, 0, 0.10);
    --shadow-lg: 0 20px 50px rgba(62, 46, 35, 0.14);
    --transition: 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
    font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
    background: var(--bg);
    min-height: 100vh;
    color: var(--text-main);
}

/* Entrance fade: pages start invisible and fade in once JS has decided what to
   show, so there's never a flash of the wrong screen.

   This sits on the page's own top-level boxes rather than on <body>, which is
   where it used to be. The route loader and the cold-start splash are body
   children too, so fading the body faded out the very overlays that exist to
   cover a page that isn't ready yet: the loader below was drawn on every page
   and never once visible to a student, and neither was its 8-second "this is
   taking longer than expected" escape hatch. Every wait was a blank screen,
   which is most of why switching pages felt like the app had hung.

   Nothing here forces opacity back to 1 — the hiding rule simply stops
   matching once the page is ready, so elements that manage their own opacity
   (the install banner, the toast) keep control of it.

   The mobile tab bar is excluded for the same reason as the loader, one step
   further on: it is chrome that has to outlive the page under it. This is a
   multi-page app, so switching tabs reloads the whole document, and a bar that
   faded out with the old page and back in with the new one would blink on
   every single tap — the one thing that gives away that an app is a website.
   Fading is only half of it; mobile.css also lifts the bar above the route
   loader and stops the loader short of it. */
body > * { transition: opacity 0.28s ease; }
body:not(.page-ready) > :not(.route-loader):not(.app-splash):not(.m-tabbar) { opacity: 0; }
body.page-leaving > :not(.route-loader):not(.app-splash):not(.m-tabbar) { opacity: 0; transition: opacity 0.18s ease; }

/* The route loader and the cafe mark that animates inside it used to live
   here. They now sit in /loader.css, which every page links alongside this
   file: the admin pages need the same loading animation but deliberately do
   not use this design system, and pulling all of it in to get one overlay
   would have dropped its body and button rules on top of theirs. */

/* The cold-start splash used to live here. It now sits inline in the <head>
   of index.html — the only page that has one — so that it can paint without
   waiting for this file to arrive over the network. See the comment above
   that block for why that matters. */

/* ---------- Buttons ---------- */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    padding: 14px 20px; border-radius: 9999px; font-size: 1rem; font-weight: 700;
    font-family: inherit; border: none; cursor: pointer; transition: all var(--transition);
    text-decoration: none; position: relative; white-space: nowrap;
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(1px) scale(0.98); }
.btn-primary { background: var(--primary); color: #fff; box-shadow: 0 4px 16px rgba(224, 123, 60, 0.3); }
.btn-primary:hover { background: var(--primary-hover); box-shadow: 0 6px 22px rgba(224, 123, 60, 0.4); }
.btn-outline { background: transparent; border: 1px solid var(--border); color: var(--text-muted); }
.btn-outline:hover { background: #f1f5f9; border-color: var(--primary); color: var(--primary); }
.btn-success { background: #10b981; color: #fff; }
.btn-success:hover { background: #059669; }
.btn:disabled, .btn:disabled:hover { opacity: 0.65; cursor: not-allowed; transform: none; }
.btn-full { width: 100%; margin-top: 6px; }
.btn-inline { width: auto; padding: 12px 18px; font-size: 0.9rem; height: 48px; margin-left: 8px; box-shadow: none; }

/* Any button using the spinner + btn-text pattern gets a consistent
   "busy" treatment: label fades out, spinner fades in, no layout jump. */
.spinner {
    display: none; width: 20px; height: 20px;
    border: 2.5px solid rgba(255, 255, 255, 0.35); border-top-color: #fff;
    border-radius: 50%; animation: spin 0.7s linear infinite;
}
.btn-outline .spinner, .btn-outline.loading .spinner {
    border-color: rgba(100, 116, 139, 0.35); border-top-color: var(--text-muted);
}
.btn.loading .spinner { display: inline-block; }
.btn.loading .btn-text { color: transparent; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- Form controls ---------- */
.form-group { margin-bottom: 18px; position: relative; }
.form-group label { display: block; font-size: 0.85rem; font-weight: 600; color: var(--text-main); margin-bottom: 6px; letter-spacing: 0.2px; }
.input-wrapper { position: relative; display: flex; align-items: center; }
.input-icon { position: absolute; left: 14px; font-size: 1.1rem; color: #b8a494; z-index: 2; }
input, select {
    width: 100%; padding: 13px 14px 13px 42px; font-size: 0.95rem; font-family: inherit;
    border: 1px solid var(--border); border-radius: 8px; background: var(--card); color: var(--text-main);
    transition: all var(--transition); outline: none; letter-spacing: 0.2px; appearance: none;
}
select {
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 14px center; background-size: 14px; padding-right: 36px;
}
input:focus, select:focus { border-color: var(--primary); box-shadow: 0 0 0 4px rgba(224, 123, 60, 0.1); background: #fff; }
input:disabled { background: #f8fafc; color: var(--text-muted); cursor: not-allowed; }
.input-wrapper:focus-within .input-icon { color: var(--primary); }
/* Visible keyboard focus ring for anything that isn't a text input */
a:focus-visible, button:focus-visible, [tabindex]:focus-visible {
    outline: 2px solid var(--primary); outline-offset: 2px;
}

.phone-row, .otp-row { display: flex; gap: 8px; align-items: flex-start; }
.phone-row .input-wrapper, .otp-row .input-wrapper { flex: 1; }

.error-message { font-size: 0.78rem; color: #ef4444; margin-top: 5px; display: none; align-items: center; gap: 5px; animation: shakeIn 0.35s ease; }
.error-message.show { display: flex; }
@keyframes shakeIn {
    0%, 100% { transform: translateX(0); }
    20% { transform: translateX(-6px); }
    40% { transform: translateX(6px); }
    60% { transform: translateX(-4px); }
    80% { transform: translateX(3px); }
}

/* ---------- Toast ---------- */
.toast {
    position: fixed; top: 25px; right: 25px; z-index: 1000;
    background: var(--card); border-radius: 12px; padding: 16px 24px;
    box-shadow: 0 10px 35px rgba(0, 0, 0, 0.15);
    display: flex; align-items: center; gap: 12px; font-weight: 500;
    /* Parked off-screen. Not translateX(120%): a percentage translate is
       measured against the toast's own width, so it has no way to account for
       the 25px the toast sits in from the edge. One wide enough to carry a
       sentence cleared it; the empty one on the login page is 85px, and 120%
       of that left 8px of card and its green border against the right edge of
       every single load. The offset has to be absolute. The extra 45px is for
       the shadow — 35px of blur, which would otherwise smudge on screen while
       the card itself was clear. */
    transform: translateX(calc(100% + 70px));
    transition: transform 0.4s cubic-bezier(.22, .61, .36, 1);
    border-left: 4px solid #10b981;
    max-width: calc(100vw - 50px);
}
.toast.show { transform: translateX(0); }
.toast.error-toast { border-left-color: #ef4444; }
.toast .toast-icon { font-size: 1.3rem; flex-shrink: 0; }

/* ---------- Skeleton loading placeholders ---------- */
.skeleton {
    background: linear-gradient(90deg, #eef1f5 25%, #e5e9ef 37%, #eef1f5 63%);
    background-size: 400% 100%; animation: skeleton-loading 1.4s ease infinite;
    border-radius: 10px;
}
@keyframes skeleton-loading { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

@media (max-width: 480px) {
    .toast { left: 16px; right: 16px; top: 16px; }
    .phone-row, .otp-row { flex-direction: column; }
    .btn-inline { width: 100%; margin-left: 0; margin-top: 8px; }
}

#recaptcha-container { margin-top: 10px; display: flex; justify-content: center; }

/* Respect users who've asked the OS for less motion */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }
}