@charset "UTF-8";
/* ==========================================================================
   SchoolPad UI Framework — components
   --------------------------------------------------------------------------
   THIS FILE IS THE SINGLE SOURCE OF TRUTH FOR EVERY REUSABLE CONTROL.

   Read docs/design-system.md before editing. The short version:

     1. A module NEVER writes its own CSS. It uses the classes below.
     2. If a class you need is missing, you add it HERE (once), document it in
        the contract, and every module gets it. You do not add it to your view.
     3. css/sp-modern.css is FROZEN. It is the legacy adapter: it restyles
        old markup that nobody has migrated yet. Do not add new components
        there and do not add new `body.sp-<page>-page` selectors anywhere.

   Load order (see css/common.css.php):
        MODERN_UI = 1:  style.css -> satoshi.css -> sp-modern.css -> sp-components.css
        MODERN_UI = 0:  style.css -> sp-components.css

   THIS FILE IS NOT GATED ON MODERN_UI. It must load at both values, or a
   migrated screen renders as bare browser controls on every client still on 0.
   It is self-sufficient: it defines its own control/spacing/type tokens and
   supplies a fallback for every token it borrows from sp-modern.css. Verified
   collision-free on a rendered legacy page -- 400 elements, 0 computed-style
   changes.
   This file loads last, so it wins without needing specificity tricks. There
   are exactly two `!important` declarations in this file, both in section 13,
   both only to beat the frozen adapter's own `!important` on native form
   controls. Delete them when the adapter's form rules go. Add no others.

   See the live, interactive reference at:  <base_url>/designSystem
   ========================================================================== */


/* --------------------------------------------------------------------------
   1. Component tokens

   Global tokens (colour, font, radius, shadow) live in sp-modern.css :root and
   are referenced here with a fallback, so this file still renders correctly if
   it is ever loaded on its own.

   NOTE — a known inconsistency, deliberately preserved: the values below are
   the ones that actually ship today. Some of them (#0f172a, #cbd5e1, #f8fafc)
   come from a slate palette used by the sidebar/topbar work, while the global
   tokens use a slightly different family (#1c2430, #cfd6de, #f7f8fa). They are
   NOT unified here, because unifying them would visibly change every screen
   that is already live. Aligning the two palettes is a separate, reviewed task.
   Until then, use these tokens — never the raw hex.
   -------------------------------------------------------------------------- */
:root {
    /* Control geometry — every interactive control is 40px tall so buttons,
       inputs and selects line up on one row without per-page fixes. */
    --sp-control-h: 40px;
    --sp-control-h-sm: 32px;
    --sp-control-px: 16px;
    --sp-control-radius: 4px;
    --sp-btn-radius: 2rem;

    /* Ink and lines used by controls */
    --sp-control-ink: #0f172a;
    --sp-control-border: #cbd5e1;
    --sp-control-border-hover: #94a3b8;
    --sp-control-bg: #ffffff;
    --sp-control-bg-hover: #f8fafc;
    --sp-control-placeholder: #94a3b8;
    --sp-focus-ring: 0 0 0 3px rgba(60, 113, 220, .14);

    /* Spacing scale — the only gaps you should use */
    --sp-space-1: 4px;
    --sp-space-2: 8px;
    --sp-space-3: 12px;
    --sp-space-4: 16px;
    --sp-space-5: 24px;
    --sp-space-6: 32px;

    /* Type scale */
    --sp-text-xs: 12px;
    --sp-text-sm: 13px;
    --sp-text-md: 15px;
    --sp-text-lg: 18px;
    --sp-text-xl: 22px;
}


/* --------------------------------------------------------------------------
   2. Buttons

   Markup:  <button class="sp-btn sp-btn--primary">Save</button>
            <a href="#" class="sp-btn sp-btn--secondary">Cancel</a>

   Always: base class + exactly one variant. Never a variant on its own.
   -------------------------------------------------------------------------- */
.sp-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-space-2);
    box-sizing: border-box;
    min-height: var(--sp-control-h);
    padding: 0 var(--sp-control-px);
    border: 1px solid transparent;
    border-radius: var(--sp-btn-radius);
    font-family: var(--sp-font, inherit);
    font-size: var(--sp-text-md);
    font-weight: 500;
    line-height: 1;
    text-align: center;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    box-shadow: none;
    transition: background-color .12s ease, border-color .12s ease, color .12s ease;
}

.sp-btn:focus-visible {
    outline: none;
    box-shadow: var(--sp-focus-ring);
}

/* Native disabled behaviour on <button>; .is-disabled for <a>, which cannot
   be disabled natively — pair it with aria-disabled="true". */
.sp-btn[disabled],
.sp-btn.is-disabled {
    opacity: .55;
    cursor: not-allowed;
    pointer-events: none;
}

/* Loading: keeps the label (so width does not jump) and adds a spinner. */
.sp-btn.is-loading {
    position: relative;
    color: transparent;
    pointer-events: none;
}

.sp-btn.is-loading::after {
    content: "";
    position: absolute;
    width: 16px;
    height: 16px;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    color: #ffffff;
    animation: sp-spin .6s linear infinite;
}

.sp-btn--secondary.is-loading::after,
.sp-btn--ghost.is-loading::after {
    color: var(--sp-control-ink);
}

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

/* Variants */
.sp-btn--primary {
    border-color: var(--sp-primary, #2f6fd0);
    background: var(--sp-primary, #2f6fd0);
    color: #ffffff;
}

.sp-btn--primary:hover,
.sp-btn--primary:focus {
    border-color: var(--sp-primary-hover, #2559ab);
    background: var(--sp-primary-hover, #2559ab);
    color: #ffffff;
}

.sp-btn--secondary {
    border-color: var(--sp-control-border);
    background: var(--sp-control-bg);
    color: var(--sp-control-ink);
}

.sp-btn--secondary:hover,
.sp-btn--secondary:focus {
    border-color: var(--sp-control-border-hover);
    background: var(--sp-control-bg-hover);
    color: var(--sp-control-ink);
}

.sp-btn--danger {
    border-color: var(--sp-danger, #d64545);
    background: var(--sp-danger, #d64545);
    color: #ffffff;
}

.sp-btn--danger:hover,
.sp-btn--danger:focus {
    border-color: #b83a3a;
    background: #b83a3a;
    color: #ffffff;
}

/* Ghost — for tertiary actions inside a toolbar or table row. */
.sp-btn--ghost {
    border-color: transparent;
    background: transparent;
    color: var(--sp-primary-ink, #1d4f9c);
}

.sp-btn--ghost:hover,
.sp-btn--ghost:focus {
    background: var(--sp-primary-soft, #eaf1fc);
    color: var(--sp-primary-ink, #1d4f9c);
}

/* Modifiers — combine with any variant. */
.sp-btn--sm {
    min-height: var(--sp-control-h-sm);
    padding: 0 var(--sp-space-3);
    font-size: var(--sp-text-sm);
}

.sp-btn--icon {
    width: var(--sp-control-h);
    padding: 0;
    border-radius: 50%;
}

.sp-btn--sm.sp-btn--icon {
    width: var(--sp-control-h-sm);
}

.sp-btn--block {
    display: flex;
    width: 100%;
}

/* Groups actions with the correct gap. Use it instead of &nbsp; or <br>. */
.sp-btn-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
}

.sp-btn-row--end { justify-content: flex-end; }


/* --------------------------------------------------------------------------
   3. Form controls

   Markup:  <div class="sp-field">
              <label class="sp-label" for="x">Student Name <span class="sp-req">*</span></label>
              <input type="text" id="x" class="sp-input">
              <p class="sp-help">As printed on the birth certificate.</p>
            </div>
   -------------------------------------------------------------------------- */
.sp-field {
    display: block;
    margin-bottom: var(--sp-space-4);
}

.sp-label {
    display: block;
    margin-bottom: var(--sp-space-1);
    color: var(--sp-text, #1c2430);
    font-size: var(--sp-text-sm);
    font-weight: 600;
    line-height: 1.4;
}

.sp-req { color: var(--sp-danger, #d64545); }

.sp-input,
.sp-select,
.sp-textarea {
    box-sizing: border-box;
    width: 100%;
    min-height: var(--sp-control-h);
    padding: 0 var(--sp-space-3);
    border: 1px solid var(--sp-control-border);
    border-radius: var(--sp-control-radius);
    background-color: var(--sp-control-bg);
    color: #334155;
    font-family: var(--sp-font, inherit);
    font-size: var(--sp-text-md);
    line-height: 1.4;
}

.sp-textarea {
    min-height: 96px;
    padding: var(--sp-space-2) var(--sp-space-3);
    resize: vertical;
}

.sp-select {
    padding-right: var(--sp-space-6);
    background-image: url('../images/tabler-icons/outline/chevron-down.svg');
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 16px 16px;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
}

.sp-input::placeholder,
.sp-textarea::placeholder { color: var(--sp-control-placeholder); }

.sp-input:focus,
.sp-select:focus,
.sp-textarea:focus {
    border-color: var(--sp-primary, #2f6fd0);
    outline: none;
    box-shadow: var(--sp-focus-ring);
}

.sp-input[disabled],
.sp-select[disabled],
.sp-textarea[disabled],
.sp-input[readonly] {
    background-color: var(--sp-surface-sunken, #f1f3f5);
    color: var(--sp-text-muted, #667485);
    cursor: not-allowed;
}

/* Error state. Put .sp-field--error on the wrapper, not on the input, so the
   label, control and message all move together. */
.sp-field--error .sp-input,
.sp-field--error .sp-select,
.sp-field--error .sp-textarea {
    border-color: var(--sp-danger, #d64545);
}

.sp-field--error .sp-input:focus,
.sp-field--error .sp-select:focus,
.sp-field--error .sp-textarea:focus {
    box-shadow: 0 0 0 3px rgba(214, 69, 69, .15);
}

.sp-help,
.sp-error {
    margin: var(--sp-space-1) 0 0;
    font-size: var(--sp-text-xs);
    line-height: 1.45;
}

.sp-help { color: var(--sp-text-muted, #667485); }
.sp-error { color: var(--sp-danger, #d64545); }

/* Checkbox / radio — one row, label clickable, aligned baseline. */
.sp-check {
    display: inline-flex;
    align-items: flex-start;
    gap: var(--sp-space-2);
    margin: 0 var(--sp-space-4) var(--sp-space-2) 0;
    font-size: var(--sp-text-md);
    line-height: 1.4;
    cursor: pointer;
}

.sp-check input[type="checkbox"],
.sp-check input[type="radio"] {
    width: 16px;
    height: 16px;
    margin: 2px 0 0;
    flex: 0 0 auto;
    accent-color: var(--sp-primary, #2f6fd0);
    cursor: pointer;
}

/* Two-column form. Collapses to one column when the CONTAINER is narrow,
   not the viewport — a narrow content column on a wide screen still wraps.
   Requires container queries; the flex fallback below covers older engines. */
.sp-form-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 0 var(--sp-space-4);
    container-type: inline-size;
}

.sp-form-grid > .sp-field {
    flex: 1 1 260px;
    min-width: 0;
}

.sp-form-grid > .sp-field--full { flex-basis: 100%; }


/* --------------------------------------------------------------------------
   4. Page and panel shell
   -------------------------------------------------------------------------- */
.sp-section {
    margin-bottom: var(--sp-space-5);
}

.sp-card {
    box-sizing: border-box;
    border: 1px solid var(--sp-border, #e4e8ed);
    border-radius: var(--sp-radius, 8px);
    background: var(--sp-surface, #ffffff);
}

.sp-card__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-space-3);
    padding: var(--sp-space-3) var(--sp-space-4);
    border-bottom: 1px solid var(--sp-border, #e4e8ed);
    background: var(--sp-surface-alt, #f7f8fa);
    border-radius: var(--sp-radius, 8px) var(--sp-radius, 8px) 0 0;
}

.sp-card__title {
    margin: 0;
    color: var(--sp-text, #1c2430);
    font-size: var(--sp-text-lg);
    font-weight: 600;
    line-height: 1.3;
}

.sp-card__body { padding: var(--sp-space-4); }

/* Toolbar above a grid: title/filters on the left, actions on the right. */
.sp-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-space-3);
    margin-bottom: var(--sp-space-3);
}

.sp-toolbar__group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
}


/* --------------------------------------------------------------------------
   5. Table

   For NEW tables only. Existing grids come from Commonlib::createMasterGrid()
   and are already styled by the frozen adapter — do not add .sp-table to them.
   -------------------------------------------------------------------------- */
.sp-table-wrap {
    width: 100%;
    overflow-x: auto;
    border: 1px solid var(--sp-border, #e4e8ed);
    border-radius: var(--sp-radius, 8px);
}

.sp-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--sp-text-md);
}

.sp-table th {
    padding: var(--sp-space-3) var(--sp-space-3);
    border-bottom: 1px solid var(--sp-border, #e4e8ed);
    background: var(--sp-surface-alt, #f7f8fa);
    color: var(--sp-text-muted, #667485);
    font-size: var(--sp-text-sm);
    font-weight: 600;
    text-align: left;
    white-space: nowrap;
}

.sp-table td {
    padding: var(--sp-space-3);
    border-bottom: 1px solid #eeeeee;
    color: #393939;
    line-height: 1.45;
    vertical-align: middle;
}

.sp-table tbody tr:last-child td { border-bottom: 0; }
.sp-table tbody tr:hover td { background: #edf5ff; }

.sp-table--numeric td.sp-num,
.sp-table--numeric th.sp-num { text-align: right; }


/* --------------------------------------------------------------------------
   6. Alerts, badges, empty state
   -------------------------------------------------------------------------- */
.sp-alert {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-space-2);
    padding: var(--sp-space-3) var(--sp-space-4);
    border: 1px solid transparent;
    border-radius: var(--sp-radius, 8px);
    font-size: var(--sp-text-md);
    line-height: 1.5;
}

.sp-alert--info {
    border-color: #cfe0f8;
    background: var(--sp-primary-soft, #eaf1fc);
    color: var(--sp-primary-ink, #1d4f9c);
}

.sp-alert--success {
    border-color: #bfe4cf;
    background: var(--sp-success-soft, #e8f6ee);
    color: var(--sp-success, #1f9254);
}

.sp-alert--warning {
    border-color: #f0dcae;
    background: var(--sp-warning-soft, #fdf4e3);
    color: var(--sp-warning, #a8760b);
}

.sp-alert--danger {
    border-color: #f4c9c9;
    background: var(--sp-danger-soft, #fdecec);
    color: var(--sp-danger, #d64545);
}

.sp-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    padding: 2px var(--sp-space-2);
    border-radius: 999px;
    font-size: var(--sp-text-xs);
    font-weight: 600;
    line-height: 18px;
    white-space: nowrap;
}

.sp-badge--neutral { background: var(--sp-surface-sunken, #f1f3f5); color: var(--sp-text-muted, #667485); }
.sp-badge--info    { background: var(--sp-primary-soft, #eaf1fc); color: var(--sp-primary-ink, #1d4f9c); }
.sp-badge--success { background: var(--sp-success-soft, #e8f6ee); color: var(--sp-success, #1f9254); }
.sp-badge--warning { background: var(--sp-warning-soft, #fdf4e3); color: var(--sp-warning, #a8760b); }
.sp-badge--danger  { background: var(--sp-danger-soft, #fdecec);  color: var(--sp-danger, #d64545); }

.sp-empty {
    padding: var(--sp-space-6) var(--sp-space-4);
    color: var(--sp-text-muted, #667485);
    font-size: var(--sp-text-md);
    text-align: center;
}

.sp-empty__title {
    margin: 0 0 var(--sp-space-1);
    color: var(--sp-text, #1c2430);
    font-size: var(--sp-text-lg);
    font-weight: 600;
}


/* --------------------------------------------------------------------------
   7. Payment gateway section

   Required shape from docs/multi-gateway-payment-contract.md: one bordered
   "Choose Payment Gateway" section per transaction axis (fee and transport are
   separate sections), equal-width controls, one column when the CONTAINER is
   narrow. Do not hand-roll this layout in a payment view.
   -------------------------------------------------------------------------- */
.sp-gateway {
    box-sizing: border-box;
    margin: var(--sp-space-4) 0;
    padding: var(--sp-space-4);
    border: 1px solid var(--sp-border-strong, #cfd6de);
    border-radius: var(--sp-radius, 8px);
    background: var(--sp-surface, #ffffff);
    container-type: inline-size;
}

.sp-gateway__title {
    margin: 0 0 var(--sp-space-3);
    color: var(--sp-text, #1c2430);
    font-size: var(--sp-text-md);
    font-weight: 600;
}

.sp-gateway__options {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-space-3);
}

.sp-gateway__options > * { min-width: 0; }
.sp-gateway__options .sp-btn { width: 100%; }

.sp-gateway__status {
    margin-top: var(--sp-space-3);
    font-size: var(--sp-text-sm);
}

@container (max-width: 520px) {
    .sp-gateway__options { grid-template-columns: minmax(0, 1fr); }
}


/* --------------------------------------------------------------------------
   8. Utilities — the complete list. Do not invent more.
   -------------------------------------------------------------------------- */
.sp-mt-0 { margin-top: 0; }
.sp-mb-0 { margin-bottom: 0; }
.sp-mb-2 { margin-bottom: var(--sp-space-2); }
.sp-mb-3 { margin-bottom: var(--sp-space-3); }
.sp-mb-4 { margin-bottom: var(--sp-space-4); }
.sp-mb-5 { margin-bottom: var(--sp-space-5); }

.sp-muted  { color: var(--sp-text-muted, #667485); }
.sp-strong { font-weight: 600; }
.sp-nowrap { white-space: nowrap; }
.sp-right  { text-align: right; }
.sp-center { text-align: center; }

.sp-hidden { display: none; }

/* Visible to screen readers only — use for labels you cannot show. */
.sp-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}


/* --------------------------------------------------------------------------
   9. Responsive

   Container queries above handle "narrow parent column". These viewport rules
   handle the actual phone. Both are required by the payment contract.
   -------------------------------------------------------------------------- */
@media (max-width: 768px) {
    .sp-form-grid > .sp-field { flex-basis: 100%; }

    .sp-toolbar { align-items: stretch; }
    .sp-toolbar__group { width: 100%; }
    .sp-toolbar__group .sp-btn { flex: 1 1 auto; }

    .sp-gateway__options { grid-template-columns: minmax(0, 1fr); }
}


/* --------------------------------------------------------------------------
   10. Reduced motion
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    .sp-btn { transition: none; }
    .sp-btn.is-loading::after { animation-duration: 2s; }
}


/* --------------------------------------------------------------------------
   11. Print
   -------------------------------------------------------------------------- */
@media print {
    .sp-btn,
    .sp-toolbar,
    .sp-gateway { display: none; }

    .sp-card { border-color: #999999; }
}


/* --------------------------------------------------------------------------
   12. The legacy button aliases are NOT ours

   sp-modern.css defines .sp-btn-primary / .sp-btn-secondary (twice, with
   conflicting geometry at ~1648 and ~2485), and those two class names are
   emitted from Commonlib::createMasterGrid() and classManager.php onto roughly
   600 live screens.

   This file deliberately does NOT restyle them. An earlier version aliased them
   onto the canonical component; measured against HEAD on a
   body.sp-designation-grid-page screen that changed the rendered button from
   48px to 46px, because the alias added `box-sizing: border-box`. Radius and
   font size were already identical, so the alias bought nothing and cost a
   visual change on ~600 screens.

   They keep whatever the frozen adapter gives them until a screen is migrated,
   at which point its markup moves to `sp-btn sp-btn--primary` and this file owns
   it. Do not use the single-dash names in new markup.
   -------------------------------------------------------------------------- */


/* --------------------------------------------------------------------------
   13. Compatibility: form controls — TEMPORARY

   sp-modern.css styles inputs with `input[type="text"]` (specificity 0,1,1),
   which outranks a plain `.sp-input` (0,1,0). Without this block a field
   silently renders at 13px while the select beside it renders at 15px, and
   `.sp-field--error` cannot turn the border red at all, because line ~2466 of
   the adapter sets `border-color: ... !important` on the element selector.

   Raising the component to element+class ties the specificity, and this file
   loads later, so it wins on cascade order. `!important` appears only where
   the adapter already used it. Delete this block together with the adapter's
   form-control rules.
   -------------------------------------------------------------------------- */
input.sp-input,
select.sp-select,
textarea.sp-textarea {
    padding: 0 var(--sp-space-3);
    border: 1px solid var(--sp-control-border);
    border-radius: var(--sp-control-radius);
    font-size: var(--sp-text-md);
    color: #334155;
}

textarea.sp-textarea {
    padding: var(--sp-space-2) var(--sp-space-3);
    line-height: 1.4;
}

select.sp-select { padding-right: var(--sp-space-6); }

.sp-field--error input.sp-input,
.sp-field--error select.sp-select,
.sp-field--error textarea.sp-textarea {
    border-color: var(--sp-danger, #d64545) !important;
}

.sp-field--error input.sp-input:focus,
.sp-field--error select.sp-select:focus,
.sp-field--error textarea.sp-textarea:focus {
    box-shadow: 0 0 0 3px rgba(214, 69, 69, .15);
}

/* The adapter paints every control `background-color: #ffffff !important`,
   so the disabled/read-only fill needs !important to show at all. */
input.sp-input[disabled],
input.sp-input[readonly],
select.sp-select[disabled],
textarea.sp-textarea[disabled] {
    background-color: var(--sp-surface-sunken, #f1f3f5) !important;
    color: var(--sp-text-muted, #667485);
}
