/* Karuna Foundation - design tokens and components ported from Figma */

:root {
    --k-primary: #ea580c;
    --k-primary-dark: #c2410c;
    --k-primary-soft: #fff2ea;
    --k-bg: #f7f9f8;
    --k-surface: #ffffff;
    --k-text: #1e2923;
    --k-muted: #68736d;
    --k-border: #e4e9e6;
    --k-avatar-bg: #f4efea;
    --k-avatar-fg: #8a5a3b;
    --k-danger: #b42318;
    --k-success: #067647;

    --k-r-sm: 8px;
    --k-r: 10px;
    --k-r-lg: 14px;

    --k-shell: 1280px;
    /* Width the receipt sheet is designed at; the print scale is derived from it. */
    --k-sheet-w: 520px;
    --k-font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --k-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* Inputs are width:100% with their own padding and border, so without this they
   overflow the card they sit in. */
*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    font-size: 14px;
}

/* A single element pushed wider than the shell - a long unbroken token, a row
   that doesn't wrap - would otherwise widen the whole document and eat the
   .k-shell gutter it sits inside, rather than just its own box. This clips
   that at the document edge; it never touches an element's own deliberate
   internal scrolling, like .k-tablescroll. */
html,
body {
    overflow-x: hidden;
}

body {
    margin: 0;
    background: var(--k-bg);
    color: var(--k-text);
    font-family: var(--k-font);
    font-size: 14px;
    line-height: 1.45;
    -webkit-font-smoothing: antialiased;
}

a {
    color: var(--k-primary);
    text-decoration: none;
}

a:hover {
    color: var(--k-primary-dark);
}

/* ---------- icons ---------- */
/* Figma exports are stroke-based and normalised to currentColor, so an icon
   inherits the colour of whatever it sits inside. Both leaf dimensions are set
   explicitly - never `auto` - so the designed geometry survives. */
.k-ico {
    display: block;
    width: 16px;
    height: 16px;
    flex: 0 0 auto;
}

.k-ico-11 { width: 11px; height: 11px; }
.k-ico-14 { width: 14px; height: 14px; }
.k-ico-15 { width: 15px; height: 15px; }
.k-ico-18 { width: 18px; height: 18px; }
.k-ico-22 { width: 22px; height: 22px; }
.k-ico-24 { width: 24px; height: 24px; }

/* ---------- shell ---------- */
.k-shell {
    max-width: var(--k-shell);
    margin: 0 auto;
    padding: 0 24px;
}

/* Vertical spacing only - .k-shell owns the side gutters, and every page's
   <main> carries both classes. The old shorthand here ("24px 0 48px") set
   left/right to 0 too, and being declared after .k-shell it won by source
   order - silently zeroing the side padding everywhere above the 600px
   breakpoint, where a later, more specific rule happened to re-add it and
   hid the bug. */
.k-page {
    padding-top: 24px;
    padding-bottom: 48px;
}

.k-page-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 24px;
}

.k-page-title {
    font-size: 24px;
    font-weight: 700;
    line-height: 32px;
    margin: 0;
}

.k-page-sub {
    margin: 4px 0 0;
    font-size: 14px;
    color: var(--k-muted);
}

/* ---------- top nav ---------- */
.k-topnav {
    background: rgba(255, 255, 255, .9);
    backdrop-filter: blur(8px);
    border-bottom: .8px solid var(--k-border);
    position: sticky;
    top: 0;
    z-index: 20;
}

.k-topnav-bar {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 12px 24px;
    max-width: var(--k-shell);
    margin: 0 auto;
}

.k-brand {
    display: flex;
    align-items: center;
    gap: 12px;
    color: inherit;
}

.k-brand-mark {
    width: 40px;
    height: 40px;
    border-radius: 12px;
    background: var(--k-primary);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
}

.k-brand-name {
    font-size: 14px;
    font-weight: 700;
    line-height: 17.5px;
    margin: 0;
}

.k-brand-tag {
    font-size: 11px;
    line-height: 16.5px;
    color: var(--k-muted);
    margin: 0;
}

.k-topnav-spacer {
    flex: 1 1 auto;
}

.k-identity {
    display: flex;
    align-items: center;
    gap: 8px;
    padding-left: 12px;
    border-left: .8px solid var(--k-border);
}

.k-avatar {
    width: 36px;
    height: 36px;
    border-radius: 999px;
    background: var(--k-avatar-bg);
    color: var(--k-avatar-fg);
    font-weight: 700;
    font-size: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.k-identity-name {
    font-size: 13px;
    font-weight: 600;
    line-height: 16.25px;
    margin: 0;
}

.k-identity-role {
    font-size: 11px;
    line-height: 13.75px;
    color: var(--k-muted);
    margin: 0;
}

/* Opens the nav as a side sheet. Only ever visible below the nav breakpoint -
   see the responsive block at the end of the file. */
.k-burger {
    display: none;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    flex: 0 0 auto;
    padding: 0;
    background: none;
    border: .8px solid var(--k-border);
    border-radius: var(--k-r-sm);
    color: var(--k-text);
    cursor: pointer;
}

.k-burger:hover {
    background: var(--k-bg);
}

/* The side sheet's own header. Belongs to the panel, so it is not rendered
   while the nav is a row. */
.k-sidenav-head {
    display: none;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 16px;
    border-bottom: .8px solid var(--k-border);
}

.k-sidenav-title {
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--k-muted);
}

.k-sidenav-close {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    background: none;
    border: 0;
    border-radius: var(--k-r-sm);
    color: var(--k-muted);
    cursor: pointer;
}

.k-sidenav-close:hover {
    background: var(--k-bg);
    color: var(--k-text);
}

/* Dims the page behind the open side sheet and catches the tap that closes it. */
.k-nav-scrim {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 1;
    background: rgba(30, 41, 35, .45);
}

.k-nav-scrim[hidden] {
    display: none;
}

/* nav row */
.k-navrow {
    max-width: var(--k-shell);
    margin: 0 auto;
    padding: 0 16px;
    display: flex;
    gap: 4px;
    overflow-x: auto;
    scrollbar-width: none;
}

.k-navrow::-webkit-scrollbar {
    display: none;
}

.k-navlink {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 14px;
    font-size: 13px;
    font-weight: 500;
    color: var(--k-muted);
    white-space: nowrap;
    border-bottom: 2px solid transparent;
    background: none;
    border-top: 0;
    border-left: 0;
    border-right: 0;
}

.k-navlink:hover {
    color: var(--k-text);
}

.k-navlink.active {
    color: var(--k-primary);
    border-bottom-color: var(--k-primary);
}

/* ---------- surfaces ---------- */
.k-card {
    background: var(--k-surface);
    border: .8px solid var(--k-border);
    border-radius: var(--k-r-lg);
}

.k-card-pad {
    padding: 20px;
}

.k-section {
    background: var(--k-surface);
    border: .8px solid var(--k-border);
    border-radius: var(--k-r-lg);
    padding: 20px;
    margin-bottom: 16px;
}

.k-section-head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 18px;
}

.k-section-title {
    font-size: 14px;
    font-weight: 700;
    margin: 0;
}

.k-step {
    width: 24px;
    height: 24px;
    border-radius: 999px;
    background: var(--k-primary);
    color: #fff;
    font-size: 12px;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
}

/* ---------- stat tiles ---------- */
.k-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 16px;
    margin-bottom: 20px;
}

.k-stat {
    background: var(--k-surface);
    border: .8px solid var(--k-border);
    border-radius: var(--k-r-lg);
    padding: 18px 20px;
}

.k-stat-label {
    font-size: 13px;
    color: var(--k-muted);
    margin: 0 0 6px;
}

.k-stat-value {
    font-size: 26px;
    font-weight: 700;
    line-height: 1.15;
    margin: 0;
}

/* icon-led stat (User List / RBU old receipts) */
.k-stat-icon {
    display: flex;
    align-items: center;
    gap: 14px;
}

.k-stat-badge {
    width: 40px;
    height: 40px;
    border-radius: var(--k-r);
    background: var(--k-primary-soft);
    color: var(--k-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
}

/* ---------- forms ---------- */
.k-grid {
    display: grid;
    gap: 16px;
}

.k-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.k-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* Title (Shree / Mr / Ms) beside the donor's full name - a fixed-width column
   next to whatever room is left, which is fine until the phone breakpoint,
   where 120px for the title leaves too little for a name to be usable. */
.k-grid-title { grid-template-columns: 120px minmax(0, 1fr); }

@media (max-width: 900px) {
    .k-grid-2,
    .k-grid-3 { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 600px) {
    .k-grid-title { grid-template-columns: minmax(0, 1fr); }
}

.k-field {
    display: flex;
    flex-direction: column;
}

.k-label {
    font-size: 13px;
    font-weight: 500;
    line-height: 19.5px;
    color: var(--k-text);
    margin-bottom: 6px;
}

.k-req {
    color: var(--k-primary);
    margin-left: 2px;
}

.k-input,
.k-select,
.k-textarea {
    width: 100%;
    min-height: 40px;
    padding: 9px 12px;
    background: var(--k-surface);
    border: .8px solid var(--k-border);
    border-radius: var(--k-r);
    color: var(--k-text);
    font-family: inherit;
    font-size: 14px;
    line-height: 20px;
}

.k-textarea {
    min-height: 72px;
    resize: vertical;
}

.k-input::placeholder,
.k-textarea::placeholder {
    color: #9aa3a0;
}

.k-input:focus,
.k-select:focus,
.k-textarea:focus {
    outline: none;
    border-color: var(--k-primary);
    box-shadow: 0 0 0 3px rgba(234, 88, 12, .12);
}

.k-input[readonly] {
    background: #fafbfb;
}

.k-input:disabled,
.k-select:disabled,
.k-textarea:disabled {
    background: #f3f5f4;
    color: var(--k-muted);
    cursor: not-allowed;
}

.k-hint {
    font-size: 11px;
    color: var(--k-muted);
    margin-top: 4px;
}

/* Read-only value shown in place of an input (User ID / User Name). */
.k-static {
    margin: 0;
    font-size: 14px;
    line-height: 20px;
    color: var(--k-text);
}

.k-input-wrap {
    position: relative;
}

.k-input-affix {
    position: absolute;
    top: 50%;
    right: 12px;
    transform: translateY(-50%);
    background: none;
    border: 0;
    padding: 0;
    color: var(--k-muted);
    cursor: pointer;
}

.k-input-icon {
    padding-left: 38px;
}

.k-input-lead {
    position: absolute;
    top: 50%;
    left: 12px;
    transform: translateY(-50%);
    color: var(--k-muted);
    pointer-events: none;
}

.k-amount {
    font-size: 20px;
    font-weight: 600;
    min-height: 48px;
}

.field-validation-error,
.k-error {
    display: block;
    color: var(--k-danger);
    font-size: 12px;
    margin-top: 4px;
}

.input-validation-error {
    border-color: var(--k-danger);
}

.k-check {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--k-muted);
}

.k-check input {
    width: 13px;
    height: 13px;
    accent-color: var(--k-primary);
    margin: 0;
}

/* ---------- buttons ---------- */
.k-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-height: 40px;
    padding: 9px 16px;
    border-radius: var(--k-r);
    border: .8px solid transparent;
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    line-height: 20px;
    cursor: pointer;
    white-space: nowrap;
}

.k-btn-primary {
    background: var(--k-primary);
    color: #fff;
    box-shadow: 0 1px 1.5px rgba(234, 88, 12, .2), 0 1px 1px rgba(234, 88, 12, .2);
}

.k-btn-primary:hover {
    background: var(--k-primary-dark);
    color: #fff;
}

.k-btn-ghost {
    background: var(--k-surface);
    border-color: var(--k-border);
    color: var(--k-muted);
}

.k-btn-ghost:hover {
    color: var(--k-text);
    border-color: #d4dbd7;
}

.k-btn-outline {
    background: var(--k-surface);
    border-color: var(--k-border);
    color: var(--k-primary);
}

.k-btn-outline:hover {
    background: var(--k-primary-soft);
    color: var(--k-primary-dark);
}

/* Destructive confirmation - outlined rather than filled, so it never competes
   with the primary action sitting beside it. */
.k-btn-danger {
    background: var(--k-surface);
    border-color: #fecdc9;
    color: var(--k-danger);
}

.k-btn-danger:hover {
    background: #fef3f2;
    border-color: var(--k-danger);
}

.k-btn-block {
    width: 100%;
}

.k-btn-sm {
    min-height: 32px;
    padding: 6px 10px;
    font-size: 12px;
}

.k-iconbtn {
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    background: none;
    border-radius: var(--k-r-sm);
    color: var(--k-muted);
    cursor: pointer;
}

.k-iconbtn:hover {
    background: var(--k-bg);
    color: var(--k-primary);
}

/* segmented tabs (Reports) */
.k-segment {
    display: inline-flex;
    gap: 4px;
    padding: 4px;
    background: var(--k-surface);
    border: .8px solid var(--k-border);
    border-radius: 12px;
    margin-bottom: 16px;
}

.k-segment a {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    border-radius: var(--k-r-sm);
    font-size: 13px;
    font-weight: 600;
    color: var(--k-muted);
}

.k-segment a.active {
    background: var(--k-primary);
    color: #fff;
}

/* ---------- tables ---------- */
.k-tablecard {
    background: var(--k-surface);
    border: .8px solid var(--k-border);
    border-radius: var(--k-r-lg);
    overflow: hidden;
}

.k-tablescroll {
    overflow-x: auto;
}

.k-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}

.k-table th {
    text-align: left;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--k-muted);
    padding: 14px 16px;
    border-bottom: .8px solid var(--k-border);
    white-space: nowrap;
}

.k-table td {
    padding: 14px 16px;
    border-bottom: .8px solid var(--k-border);
    color: var(--k-text);
    vertical-align: middle;
}

.k-table tbody tr:last-child td {
    border-bottom: 0;
}

.k-table tbody tr:hover {
    background: #fcfdfd;
}

.k-table .k-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.k-table tfoot td {
    background: var(--k-bg);
    font-weight: 700;
    border-top: .8px solid var(--k-border);
}

.k-code {
    font-family: var(--k-mono);
    font-size: 12px;
    color: var(--k-primary);
    white-space: nowrap;
}

.k-strong {
    font-weight: 600;
}

.k-dash {
    color: var(--k-muted);
}

.k-empty {
    padding: 48px 16px;
    text-align: center;
    color: var(--k-muted);
}

.k-badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 600;
    background: var(--k-bg);
    color: var(--k-muted);
    border: .8px solid var(--k-border);
}

.k-badge-yes {
    background: #ecfdf3;
    color: var(--k-success);
    border-color: #abefc6;
}

.k-badge-no {
    background: #fef3f2;
    color: var(--k-danger);
    border-color: #fecdc9;
}

/* ---------- filter bar ---------- */
.k-filters {
    background: var(--k-surface);
    border: .8px solid var(--k-border);
    border-radius: var(--k-r-lg);
    padding: 16px;
    margin-bottom: 16px;
    display: grid;
    gap: 12px;
}

.k-filters-row {
    display: grid;
    gap: 12px;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

.k-filters-row-search {
    grid-template-columns: 200px minmax(0, 1fr);
}

/* A lone dropdown does not need the whole bar. */
.k-filters-row-narrow {
    grid-template-columns: minmax(0, 220px);
}

.k-filters-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}

/* ---------- pagination ---------- */
.k-pager {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 14px 16px;
    border-top: .8px solid var(--k-border);
    background: var(--k-surface);
}

/* Rows-per-page, the page jump and the page links, as one group opposite the
   count. Was an inline style on the markup; it is a class so the responsive
   rules can let it wrap. */
.k-pager-controls {
    display: flex;
    align-items: center;
    gap: 16px;
}

.k-pager-count {
    font-size: 13px;
    color: var(--k-muted);
}

.k-pager-count b {
    color: var(--k-text);
    font-weight: 600;
}

.k-pager-list {
    display: flex;
    align-items: center;
    gap: 6px;
}

.k-pager-link {
    min-width: 30px;
    height: 30px;
    padding: 0 9px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--k-r-sm);
    font-size: 13px;
    font-weight: 500;
    color: var(--k-muted);
    border: .8px solid transparent;
}

.k-pager-link:hover {
    background: var(--k-bg);
    color: var(--k-text);
}

.k-pager-link.active {
    background: var(--k-primary);
    border-color: var(--k-primary);
    color: #fff;
    font-weight: 600;
}

.k-pager-link.active:hover {
    background: var(--k-primary);
    color: #fff;
}

.k-pager-link.disabled {
    color: #b9c2be;
    pointer-events: none;
}

.k-pager-gap {
    color: var(--k-muted);
    padding: 0 2px;
}

.k-pager-size {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    color: var(--k-muted);
}

.k-pager-size select {
    min-height: 30px;
    padding: 4px 8px;
    font-size: 12px;
    border: .8px solid var(--k-border);
    border-radius: var(--k-r-sm);
    background: var(--k-surface);
    color: var(--k-text);
    font-family: inherit;
}

.k-pager-jump {
    display: flex;
    align-items: center;
    gap: 8px;
}

.k-pager-jump label {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    color: var(--k-muted);
}

.k-pager-jump-input {
    width: 56px;
    min-height: 30px;
    padding: 4px 8px;
    font-size: 12px;
    border: .8px solid var(--k-border);
    border-radius: var(--k-r-sm);
    background: var(--k-surface);
    color: var(--k-text);
    font-family: inherit;
    text-align: center;
}

/* ---------- auth ---------- */
.k-auth {
    display: grid;
    grid-template-columns: 785.9fr 748.5fr;
    min-height: 100vh;
}

@media (max-width: 900px) {
    .k-auth { grid-template-columns: minmax(0, 1fr); }

    /* A display:none for .k-auth-hero would belong here, and the rule below
       this point would beat it anyway at equal specificity. It is left out on
       purpose: the sign-in art stacks above the form on a narrow screen, which
       is how the page is meant to read. */
}

.k-auth-hero {
    position: relative;
    background: var(--k-primary);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding: 48px;
    color: #fff;
}

.k-auth-hero-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: .3;
    pointer-events: none;
}

.k-auth-hero-wash {
    position: absolute;
    inset: 0;
    background: linear-gradient(0deg, rgb(124, 45, 18) 0%, rgba(153, 53, 16, .85) 25%, rgba(171, 59, 14, .775) 37.5%, rgba(194, 65, 12, .7) 50%, rgba(194, 65, 12, .3) 100%);
}

.k-auth-hero > *:not(.k-auth-hero-img):not(.k-auth-hero-wash) {
    position: relative;
    z-index: 1;
}

.k-auth-brand {
    display: flex;
    align-items: center;
    gap: 12px;
}

.k-auth-brand-mark {
    width: 44px;
    height: 44px;
    border-radius: 12px;
    background: rgba(255, 255, 255, .15);
    display: flex;
    align-items: center;
    justify-content: center;
}

.k-auth-brand-name {
    font-size: 15px;
    font-weight: 700;
    line-height: 18.75px;
    margin: 0;
}

.k-auth-brand-tag {
    font-size: 12px;
    line-height: 16px;
    color: rgba(255, 255, 255, .7);
    margin: 0;
}

.k-auth-copy {
    max-width: 448px;
}

.k-auth-copy h1 {
    font-size: 30px;
    font-weight: 700;
    line-height: 41.25px;
    margin: 0;
}

.k-auth-copy p {
    font-size: 14px;
    line-height: 22.75px;
    color: rgba(255, 255, 255, .8);
    margin: 16px 0 0;
}

.k-auth-trust {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 24px;
    font-size: 12px;
    color: rgba(255, 255, 255, .7);
}

.k-auth-panel {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
}

.k-auth-form {
    width: 100%;
    max-width: 384px;
}

.k-auth-form h2 {
    font-size: 24px;
    font-weight: 700;
    line-height: 32px;
    margin: 0;
}

.k-auth-form > p {
    font-size: 14px;
    line-height: 20px;
    color: var(--k-muted);
    margin: 4px 0 0;
}

.k-auth-fields {
    margin-top: 28px;
    display: grid;
    gap: 16px;
}

.k-auth-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.k-auth-alt {
    margin-top: 20px;
    text-align: center;
    font-size: 13px;
    color: var(--k-muted);
}

.k-auth-note {
    margin-top: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 10px 12px;
    border-radius: var(--k-r-sm);
    background: var(--k-primary-soft);
    color: var(--k-primary);
    font-size: 12px;
    text-align: center;
}

.k-auth-switch {
    margin-top: 16px;
    text-align: center;
    font-size: 12px;
    color: var(--k-muted);
}

/* A cancelled receipt stays in the register for audit. It is struck through and
   tinted so it can never be mistaken for a live one. */
.k-row-cancelled {
    background: #fef5f4;
}

.k-row-cancelled td {
    text-decoration: line-through;
    color: var(--k-muted);
}

/* The actions cell is not part of the record, so it is not struck through. */
.k-row-cancelled td:first-child {
    text-decoration: none;
}

/* Sits in the actions cell beside the 32px icon buttons. align-self matters:
   as a flex item it would otherwise stretch to their height and the label would
   ride at the top of an oversized pill. It is not struck through because the
   cell itself opts out above - a descendant cannot undo an inherited
   text-decoration. */
.k-tag-cancelled {
    align-self: center;
    padding: 3px 10px;
    border-radius: 999px;
    background: #fee4e2;
    color: var(--k-danger);
    font-size: 11px;
    font-weight: 600;
    line-height: 16px;
    white-space: nowrap;
}

/* ---------- misc blocks ---------- */
.k-alert {
    padding: 10px 14px;
    border-radius: var(--k-r-sm);
    font-size: 13px;
    margin-bottom: 16px;
}

.k-alert-error {
    background: #fef3f2;
    color: var(--k-danger);
    border: .8px solid #fecdc9;
}

.k-alert-success {
    background: #ecfdf3;
    color: var(--k-success);
    border: .8px solid #abefc6;
}

/* A notice, not a fault: e.g. a receipt is being written into a finished year. */
.k-alert-warning {
    background: #fffaeb;
    color: #93370d;
    border: .8px solid #fedf89;
}

/* display:block is load-bearing - this is a <label>, so it is inline by default.
   It used to be blockified for free as a flex item of .k-field; now that it sits
   inside .k-upload-wrap it has to say so itself, or the padded panel shrink-wraps
   and overflows onto the label and hint around it. */
.k-upload {
    display: block;
    border: 1px dashed var(--k-border);
    border-radius: var(--k-r);
    background: #fafbfb;
    padding: 28px;
    text-align: center;
    color: var(--k-muted);
    cursor: pointer;
}

/* Thumbnail of whatever is currently selected - the only way to check a photo
   just taken on a phone, where the file name is always "image.jpg". Clickable:
   it opens the same photo dialog a stored photo does. */
.k-upload-preview {
    display: block;
    max-width: 160px;
    max-height: 120px;
    margin: 12px auto 0;
    border-radius: var(--k-r-sm);
    cursor: pointer;
}

.k-upload-preview[hidden] {
    display: none;
}

/* With a file chosen, the upload icon and the browse/drag hint are just
   clutter beside an actual preview - the zone collapses to the thumbnail and
   its name, and the thumbnail gets the room that freed up. */
.k-upload-has-file {
    padding: 16px;
}

.k-upload-has-file .k-upload-mark,
.k-upload-has-file .k-upload-hint {
    display: none;
}

.k-upload-has-file .k-upload-preview {
    max-width: 220px;
    max-height: 220px;
}

/* Taking a photo needs a camera, so the button appears only where the pointer
   is coarse and there is no hover - phones and tablets, not a mouse. */
.k-upload-camera {
    display: none;
    margin-top: 12px;
}

@media (hover: none) and (pointer: coarse) {
    .k-upload-camera {
        display: block;
    }
}

/* Holds the panel and its cross button, which overlaps the panel's corner.
   Width is explicit so the wrap fills the field whatever it is nested in. */
.k-upload-wrap {
    position: relative;
    display: block;
    width: 100%;
}

/* A sibling of the panel, never a child: inside the label a click would only
   reopen the file dialog. It is placed over the corner instead. */
.k-upload-clear {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    background: var(--k-surface);
    border: .8px solid var(--k-border);
    border-radius: 999px;
    color: var(--k-muted);
    cursor: pointer;
    box-shadow: 0 1px 2px rgba(30, 41, 35, .08);
}

.k-upload-clear:hover {
    background: #fef3f2;
    border-color: #fecdc9;
    color: var(--k-danger);
}

.k-upload-clear[hidden] {
    display: none;
}

/* Deleting what is already stored - applied on save, not on click. */
.k-photo-remove {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 8px;
    font-size: 12px;
    color: var(--k-muted);
    cursor: pointer;
}

.k-photo-remove:hover {
    color: var(--k-danger);
}

.k-upload-over {
    border-color: var(--k-primary);
    background: var(--k-primary-soft);
}

.k-upload-mark {
    width: 40px;
    height: 40px;
    margin: 0 auto 10px;
    border-radius: 999px;
    background: var(--k-primary-soft);
    color: var(--k-primary);
    display: flex;
    align-items: center;
    justify-content: center;
}

.k-upload-title {
    font-size: 13px;
    font-weight: 600;
    color: var(--k-text);
    margin: 0 0 4px;
}

.k-upload-hint {
    font-size: 12px;
    margin: 0;
}

/* Donor fields filled from a chosen Danpeti - visible but not editable. A select
   cannot be read-only, so it ignores the pointer instead and still posts. */
.k-locked {
    background: #f3f5f4;
    color: var(--k-muted);
}

select.k-locked {
    pointer-events: none;
}

/* The donation box's own photo, shown in place of the upload controls. */
.k-photo-current {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 10px;
    border: .8px solid var(--k-border);
    border-radius: var(--k-r);
    background: var(--k-surface);
}

.k-photo-current[hidden],
.k-photo-thumb[hidden],
[data-box-photo-link][hidden] {
    display: none;
}

.k-photo-thumb {
    display: block;
    width: 96px;
    height: 96px;
    object-fit: cover;
    border-radius: var(--k-r);
    border: .8px solid var(--k-border);
    cursor: zoom-in;
}

.k-photo-caption {
    margin: 0;
    font-size: 13px;
    color: var(--k-muted);
}

/* Location picker on the receipt forms - see initLocationPicker in karuna.js. */
.k-map {
    width: 100%;
    height: 260px;
    border: .8px solid var(--k-border);
    border-radius: var(--k-r);
    overflow: hidden;
    background: #eef1f0;
    /* Leaflet gives its tile/marker/control layers z-index 400-1000 with no
       stacking context of their own, so without this they would cover the
       suggestion list below - it would open, but out of sight behind the map. */
    isolation: isolate;
}

.k-map-search {
    position: relative;
    margin-bottom: 8px;
}

/* Sits over the map rather than pushing it down, so a suggestion list opening
   and closing does not shift the layout underneath it. */
.k-map-results {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 20;
    list-style: none;
    margin: 0;
    padding: 4px;
    border: .8px solid var(--k-border);
    border-radius: var(--k-r);
    background: var(--k-surface);
    box-shadow: 0 8px 24px rgba(15, 23, 20, .12);
    max-height: 240px;
    overflow-y: auto;
}

.k-map-results[hidden] {
    display: none;
}

.k-map-result {
    width: 100%;
    padding: 8px 10px;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: var(--k-text);
    font: inherit;
    font-size: 13px;
    text-align: left;
    cursor: pointer;
}

.k-map-result:hover,
.k-map-result:focus-visible,
.k-map-result.k-map-result-active {
    background: var(--k-primary-soft);
    outline: none;
}

.k-map-bar {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 8px;
    flex-wrap: wrap;
}

.k-disclosure {
    background: var(--k-primary-soft);
    border-radius: var(--k-r-sm);
    padding: 10px 14px;
    color: var(--k-primary);
    font-size: 13px;
    font-weight: 500;
}

.k-disclosure summary {
    cursor: pointer;
    list-style: none;
}

.k-disclosure summary::-webkit-details-marker {
    display: none;
}

.k-disclosure[open] .k-disclosure-body {
    margin-top: 14px;
}

/* UPI card */
.k-upi {
    display: flex;
    flex-wrap: wrap;
    gap: 20px;
    align-items: flex-start;
}

.k-upi-qr {
    width: 176px;
    height: 176px;
    border-radius: var(--k-r-sm);
    object-fit: cover;
    flex: 0 0 auto;
}

/* The text/UPI-ID column. Without min-width:0 a flex item never shrinks below
   its own content's natural width - and the UPI ID is one unbroken token with
   no spaces to wrap at, so it was forcing this column, and with it the whole
   card, wider than .k-shell on anything narrower than a tablet. flex-wrap
   above lets it drop under the QR code entirely if 220px still doesn't fit. */
.k-upi-body {
    flex: 1 1 220px;
    min-width: 0;
}

@media (max-width: 480px) {
    /* Narrower than this, 176px of QR code plus any usable width left over for
       the text is too tight to read - stack instead. */
    .k-upi {
        flex-direction: column;
    }

    .k-upi-qr {
        margin: 0 auto;
    }

    /* flex-basis applies along whichever axis is currently the main one -
       220px was sized as a target WIDTH for the row layout above, but once
       flex-direction flips to column here that same value reads as a MINIMUM
       HEIGHT instead, forcing 220px tall regardless of how little the text
       actually needs and leaving dead space below the UPI ID row. Column mode
       wants this sized by its own content instead. */
    .k-upi-body {
        flex: 0 1 auto;
    }
}

.k-upi-tag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: 999px;
    background: var(--k-primary-soft);
    color: var(--k-primary);
    font-size: 12px;
    font-weight: 600;
}

.k-upi-id {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 12px;
    margin-top: 16px;
    padding: 10px 12px;
    background: var(--k-bg);
    border-radius: var(--k-r-sm);
}

/* The label + value pair. min-width:0 so it can shrink below its content's
   natural width instead of pushing the Copy button off - the value itself is
   the one thing that still needs an explicit wrap rule, below. */
.k-upi-id > div {
    min-width: 0;
}

.k-upi-id-label {
    font-size: 11px;
    color: var(--k-muted);
    margin: 0;
}

.k-upi-id-value {
    font-family: var(--k-mono);
    font-size: 13px;
    margin: 0;
    /* A UPI ID is one unbroken token (no spaces), which a browser will never
       wrap on its own - it just keeps pushing everything around it wider.
       This is the one line in the card actually responsible for the overflow
       that was eating .k-shell's side margin between the phone and desktop
       breakpoints. */
    overflow-wrap: anywhere;
}

/* Action bar sits at the end of the form. It used to be position:sticky, which
   floated it over the next section and hid the fields underneath. */
.k-formbar {
    display: flex;
    gap: 12px;
    background: var(--k-surface);
    border: .8px solid var(--k-border);
    border-radius: var(--k-r-lg);
    padding: 16px;
    margin-top: 16px;
}

.k-formbar .k-btn-primary {
    flex: 1 1 auto;
}

.k-backlink {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    font-weight: 500;
    color: var(--k-muted);
    margin-bottom: 12px;
}

.k-backlink:hover {
    color: var(--k-primary);
}

/* charts */
.k-charts {
    display: grid;
    grid-template-columns: 1.55fr 1fr;
    gap: 16px;
    margin-bottom: 16px;
}

@media (max-width: 900px) {
    .k-charts { grid-template-columns: minmax(0, 1fr); }
}

.k-chart-title {
    font-size: 14px;
    font-weight: 700;
    margin: 0 0 16px;
}

/*
    Each chart is drawn twice. The wide version is laid out on a canvas 700-1160
    units across and shrinks to fit, which on a phone leaves its axis labels a
    few pixels tall and its long category names colliding - no single font size
    fixes both. The phone version is laid out on a canvas close to a phone's own
    width, so the 12-unit labels print at about 12px, and is swapped in below.
    Its width is capped so a large phone or a tablet does not blow it up.

    It stays in use up to 1100px, not just on phones: the wide canvas is sized
    for a full desktop, and on a tablet - or a laptop window beside the sidebar -
    it is still scaled down to labels about 6px tall. Between 601px and 1100px
    there is more room than a phone has, so the canvas is allowed to grow and the
    text is set smaller in its own units to land at about the same 13px.
*/
.k-chart-phone {
    display: none;
    width: 100%;
    max-width: 380px;
    height: auto;
    margin: 0 auto;
}

@media (max-width: 1100px) {
    .k-chart-wide { display: none; }
    .k-chart-phone { display: block; }
}

@media (min-width: 601px) and (max-width: 1100px) {
    .k-chart-phone { max-width: 440px; }
    .k-chart-phone text { font-size: 8.5px; }
}

.k-legend {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 14px;
    margin-top: 12px;
    font-size: 12px;
    color: var(--k-muted);
}

.k-legend span {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.k-legend i {
    width: 8px;
    height: 8px;
    border-radius: 999px;
}

/* modal */
.k-modal {
    border: 0;
    padding: 0;
    border-radius: var(--k-r-lg);
    background: var(--k-surface);
    color: var(--k-text);
    width: min(640px, calc(100vw - 32px));
    box-shadow: 0 24px 48px rgba(30, 41, 35, .18);
}

.k-modal::backdrop {
    background: rgba(30, 41, 35, .45);
}

/* Script adds this while any modal is open. A native <dialog> blocks clicks
   behind it but not the wheel, so the page would otherwise scroll under the
   backdrop whenever the pointer sat outside the dialog. */
.k-scroll-locked {
    overflow: hidden;
}

/* Edit dialogs carry the same sectioned form as the create pages, so they need
   room for two columns rather than the 640px a confirm box wants. */
.k-modal-wide {
    width: min(1080px, calc(100vw - 48px));
}

/* Sections inside a dialog sit flush - the dialog is already the card. */
.k-modal-body .k-section {
    padding: 0;
    border: 0;
    box-shadow: none;
    background: none;
}

.k-modal-body .k-section + .k-section {
    margin-top: 28px;
    padding-top: 24px;
    border-top: .8px solid var(--k-border);
}

.k-modal-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    padding: 20px 20px 0;
}

.k-modal-title {
    font-size: 16px;
    font-weight: 700;
    margin: 0;
}

.k-modal-sub {
    font-family: var(--k-mono);
    font-size: 12px;
    color: var(--k-muted);
    margin: 2px 0 0;
}

.k-modal-body {
    padding: 20px;
    max-height: 60vh;
    overflow-y: auto;
}

.k-modal-foot {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    padding: 0 20px 20px;
}

/* Photo viewer. Bounded by the viewport so a large upload cannot push the
   dialog off screen - by the same 60vh as .k-modal-body itself, less that
   element's own 20px top and bottom padding, or the image would overflow its
   padding by exactly that much and force the body into its scrollbar. */
.k-photo {
    display: block;
    max-width: 100%;
    max-height: calc(60vh - 40px);
    margin: 0 auto;
    border-radius: var(--k-r);
    background: var(--k-bg);
}

.k-modal-close {
    background: none;
    border: 0;
    color: var(--k-muted);
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
}

/* ---------- search selection (a select you can type into) ----------
   Built around the real <select>, which stays in the DOM and keeps posting.
   The control below is what the user sees once script upgrades it. */
.k-searchselect {
    position: relative;
}

/* Reads as .k-select until focused, then behaves as a text field. */
.k-searchselect-input {
    width: 100%;
    min-height: 40px;
    padding: 9px 34px 9px 12px;
    background: var(--k-surface);
    border: .8px solid var(--k-border);
    border-radius: var(--k-r);
    color: var(--k-text);
    font-family: inherit;
    font-size: 14px;
    line-height: 20px;
    cursor: pointer;
    text-overflow: ellipsis;
}

.k-searchselect-input:focus {
    outline: none;
    border-color: var(--k-primary);
    box-shadow: 0 0 0 3px rgba(234, 88, 12, .12);
    cursor: text;
}

.k-searchselect-input::placeholder {
    color: #9aa3a0;
}

.k-searchselect-caret {
    position: absolute;
    top: 50%;
    right: 13px;
    width: 0;
    height: 0;
    margin-top: -2px;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 5px solid var(--k-muted);
    pointer-events: none;
}

.k-searchselect-menu {
    position: absolute;
    z-index: 40;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    max-height: 240px;
    overflow-y: auto;
    margin: 0;
    padding: 0;
    list-style: none;
    background: var(--k-surface);
    border: .8px solid var(--k-border);
    border-radius: var(--k-r);
    box-shadow: 0 12px 24px rgba(30, 41, 35, .14);
}

.k-searchselect-menu[hidden] {
    display: none;
}

.k-searchselect-option {
    padding: 11px 14px;
    font-size: 14px;
    line-height: 20px;
    color: var(--k-text);
    cursor: pointer;
    border-bottom: .8px solid var(--k-border-soft, #f1f4f2);
}

.k-searchselect-option:last-child {
    border-bottom: 0;
}

/* Semantic's highlight: the row under the cursor / arrow keys goes bold. */
.k-searchselect-option:hover,
.k-searchselect-option.k-is-active {
    background: #f7f9f8;
    font-weight: 600;
}

.k-searchselect-option.k-is-selected {
    color: var(--k-primary);
}

.k-searchselect-empty {
    padding: 11px 14px;
    font-size: 13px;
    color: var(--k-muted);
    cursor: default;
}

/* ---------- status pill ----------
   Read-only. The switch lives on the edit form, so this only reports state. */
.k-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 600;
    line-height: 16px;
    white-space: nowrap;
}

.k-pill::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 999px;
    background: currentColor;
    flex: 0 0 auto;
}

.k-pill-on {
    background: #ecfdf3;
    color: var(--k-success);
}

.k-pill-off {
    background: #f1f3f2;
    color: var(--k-muted);
}

/* A deactivated box is still a real record - unlike a cancelled receipt it is
   not struck through, just drained of colour so it recedes from the live ones. */
.k-row-inactive {
    background: #fafbfb;
}

.k-row-inactive td {
    color: var(--k-muted);
}

.k-row-inactive .k-code,
.k-row-inactive .k-strong {
    color: var(--k-muted);
    font-weight: 500;
}

/* The actions cell stays fully legible - it is how the box is switched back on. */
.k-row-inactive td:first-child {
    color: var(--k-text);
}

/* ---------- row menu ---------- */
/* Fixed, because the row it belongs to sits inside .k-tablescroll, which would
   otherwise clip it. Script positions it against the button that opened it. */
.k-menu {
    position: fixed;
    z-index: 60;
    min-width: 180px;
    padding: 6px;
    background: var(--k-surface);
    border: .8px solid var(--k-border);
    border-radius: var(--k-r);
    box-shadow: 0 12px 24px rgba(30, 41, 35, .14);
}

.k-menu[hidden] {
    display: none;
}

.k-menu-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 8px 10px;
    background: none;
    border: 0;
    border-radius: var(--k-r-sm);
    color: var(--k-text);
    font-family: inherit;
    font-size: 13px;
    text-align: left;
    cursor: pointer;
}

.k-menu-item:hover {
    background: var(--k-bg);
}

.k-menu-item-danger {
    color: var(--k-danger);
}

.k-menu-item-danger:hover {
    background: #fef3f2;
}

/* ---------- toast ---------- */
.k-toast {
    position: fixed;
    right: 20px;
    bottom: 20px;
    z-index: 80;
    max-width: min(360px, calc(100vw - 40px));
    padding: 12px 16px;
    background: var(--k-text);
    color: #fff;
    border-radius: var(--k-r);
    font-size: 13px;
    line-height: 18px;
    box-shadow: 0 12px 24px rgba(30, 41, 35, .22);
    opacity: 0;
    transform: translateY(8px);
    transition: opacity .18s ease, transform .18s ease;
}

.k-toast-visible {
    opacity: 1;
    transform: translateY(0);
}

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

/* utilities */
.k-mt-16 { margin-top: 16px; }
.k-mb-16 { margin-bottom: 16px; }
.k-muted { color: var(--k-muted); }
.k-right { text-align: right; }
.k-nowrap { white-space: nowrap; }

/* ---------- receipt preview drawer ----------
   Slides in over the Receipts list. Not a <dialog>: the edit dialog opens on
   top of it, which one modal dialog inside another would not allow. */
.k-drawer-scrim {
    position: fixed;
    inset: 0;
    z-index: 60;
    background: rgba(30, 41, 35, .4);
}

.k-drawer {
    position: fixed;
    top: 0;
    right: 0;
    z-index: 61;
    display: flex;
    flex-direction: column;
    /* Wide enough to hold an A4 page at its natural size, which is what the
       embedded PDF viewer lays the receipt out at - at 560px the page was wider
       than the panel and the drawer grew a horizontal scrollbar. Widening
       removes the overflow rather than hiding it, so nothing is clipped out of
       reach. The figure is arrived at rather than picked:

           794px  A4 at 96dpi (210mm)
          +  15   the viewer's own vertical scrollbar
          +  40   .k-drawer-body's 20px padding, both sides
          ------
           849    rounded up to 860 for a little slack

       100vw keeps it from exceeding a narrow screen. */
    width: min(860px, 100vw);
    height: 100vh;
    background: var(--k-bg);
    box-shadow: 0 20px 25px -5px rgba(0, 0, 0, .1), 0 8px 10px -6px rgba(0, 0, 0, .1);
    transform: translateX(100%);
    transition: transform .22s ease;
}

.k-drawer-open {
    transform: translateX(0);
}

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

/* Stays put while the receipt below it scrolls. */
.k-drawer-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex: 0 0 auto;
    padding: 16px 20px;
    background: var(--k-surface);
    border-bottom: .8px solid var(--k-border);
}

.k-drawer-code {
    margin: 0;
    font-family: var(--k-mono);
    font-size: 14px;
    font-weight: 600;
    line-height: 20px;
    color: var(--k-primary);
}

.k-drawer-sub {
    margin: 0;
    font-size: 12px;
    line-height: 16px;
    color: var(--k-muted);
}

.k-drawer-actions {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* The drawer's buttons are outlined in the brand colour rather than the neutral
   border the outline button carries elsewhere. */
.k-drawer .k-btn-outline {
    border-color: rgba(234, 88, 12, .3);
}

.k-drawer .k-btn-outline:hover {
    border-color: var(--k-primary);
}

/* A column that does not scroll itself. The receipt pane inside it takes
   whatever height is left over, so the PDF viewer's own scrollbar is the only
   one in the drawer - nesting a second one around it made both hard to use. */
.k-drawer-body {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    /* The receipt pane is the only child and it flexes to fit exactly, so there
       is nothing here that could overflow. */
    overflow: hidden;
    padding: 20px;
}

/* ---------- the receipt document itself ----------
   Sized as the printed sheet, so the preview and the print are the same page. */
.k-receipt-sheet {
    border-radius: var(--k-r);
    overflow: hidden;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, .05), 0 10px 15px -3px rgba(0, 0, 0, .1),
                0 4px 6px -4px rgba(0, 0, 0, .1);
}

/* In the drawer the sheet is the pane that flexes. min-height:0 is what lets a
   flex child actually shrink - without it the iframe's intrinsic height wins and
   the pane overflows the drawer. */
.k-drawer-body .k-receipt-sheet {
    flex: 1 1 auto;
    min-height: 0;
}

/* The generated receipt shown in the preview drawer. It fills the pane rather
   than being given a page's aspect ratio: the document is two pages, so a
   fixed-ratio box could never show it whole and only added a second scrollbar
   around the viewer's own. */
.k-receipt-pdf {
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
    background: #525659;
}

.k-receipt {
    position: relative;
    display: flex;
    flex-direction: column;
    min-height: 735px;
    padding: 28px 32px;
    background: var(--k-surface);
}

.k-receipt p {
    margin: 0;
}

.k-receipt-head {
    display: flex;
    gap: 12px;
    align-items: flex-start;
    padding-bottom: 16px;
    border-bottom: 1.6px solid var(--k-primary);
}

.k-receipt-mark {
    display: grid;
    place-items: center;
    width: 48px;
    height: 48px;
    flex: 0 0 auto;
    border-radius: var(--k-r-sm);
    background: var(--k-primary);
    color: #fff;
}

.k-receipt-org {
    min-width: 0;
}

.k-receipt-org-name {
    margin: 0;
    font-size: 17px;
    font-weight: 700;
    line-height: 21.25px;
    color: var(--k-primary);
}

.k-receipt-org-tag {
    font-size: 11px;
    font-weight: 500;
    line-height: 16.5px;
    color: var(--k-avatar-fg);
}

.k-receipt-org-line {
    font-size: 10px;
    line-height: 15px;
    color: var(--k-muted);
}

.k-receipt-org-tag + .k-receipt-org-line {
    padding-top: 4px;
}

.k-receipt-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding-top: 16px;
}

.k-receipt-badge {
    display: inline-block;
    padding: 4px 10px;
    border-radius: 4px;
    background: var(--k-primary-soft);
    color: var(--k-primary);
    font-size: 11px;
    font-weight: 700;
    line-height: 16.5px;
    letter-spacing: 1.1px;
    text-transform: uppercase;
}

.k-receipt-meta-lines {
    text-align: right;
    font-size: 11px;
    line-height: 16.5px;
    color: var(--k-muted);
}

.k-receipt-meta-lines strong {
    font-weight: 600;
    color: var(--k-text);
}

.k-receipt-no {
    font-family: var(--k-mono);
    font-weight: 600;
    color: var(--k-text);
}

.k-receipt-donor {
    margin-top: 16px;
    padding: 14px;
    border: .8px solid var(--k-border);
    border-radius: var(--k-r-sm);
}

.k-receipt-donor-lead {
    font-size: 11px;
    line-height: 16.5px;
    color: var(--k-muted);
}

.k-receipt-donor-name {
    padding-top: 2px;
    font-size: 15px;
    font-weight: 700;
    line-height: 22.5px;
    color: var(--k-text);
}

/* Two columns of "label: value" lines. */
.k-receipt-pairs {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 4px 16px;
    font-size: 11px;
    line-height: 16.5px;
    color: var(--k-muted);
}

.k-receipt-pairs strong {
    color: var(--k-text);
}

.k-receipt-donor .k-receipt-pairs {
    padding-top: 8px;
}

/* In the donor block the value is only darkened, not weighted - the block is
   already led by the donor's name in bold. */
.k-receipt-donor .k-receipt-pairs strong {
    font-weight: 400;
}

.k-receipt-details {
    margin-top: 12px;
    gap: 8px 16px;
}

.k-receipt-details strong {
    font-weight: 600;
}

.k-receipt-amount {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    margin-top: 16px;
    padding: 12px 16px;
    border-radius: var(--k-r-sm);
    background: var(--k-primary);
    color: #fff;
}

.k-receipt-amount-label {
    font-size: 10px;
    line-height: 15px;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .7);
}

.k-receipt-amount-value {
    font-size: 26px;
    font-weight: 700;
    line-height: 26px;
}

.k-receipt-amount-mode {
    text-align: right;
}

.k-receipt-amount-mode-value {
    font-size: 14px;
    font-weight: 600;
    line-height: 20px;
}

/* The amount spelled out, on its own tinted line. */
.k-receipt-words {
    margin-top: 8px;
    padding: 8px 12px;
    border-radius: var(--k-r-sm);
    background: #fdf6e8;
    font-size: 11px;
    line-height: 16.5px;
    color: var(--k-muted);
}

.k-receipt-words strong {
    font-weight: 600;
    color: #8a6410;
}

.k-receipt-note {
    margin-top: 16px;
    font-size: 10px;
    line-height: 16.25px;
    color: var(--k-muted);
}

/* Held to the base of the sheet however short the receipt is. */
.k-receipt-foot {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 16px;
    margin-top: auto;
    padding-top: 12px;
    border-top: .8px solid var(--k-border);
}

.k-receipt-foot-note {
    font-size: 10px;
    line-height: 15px;
    color: var(--k-muted);
}

.k-receipt-sign {
    width: 128px;
}

.k-receipt-sign-rule {
    display: block;
    height: 32px;
    border-bottom: .8px solid rgba(30, 41, 35, .4);
}

.k-receipt-sign-label {
    padding-top: 4px;
    font-size: 10px;
    font-weight: 500;
    line-height: 15px;
    text-align: center;
    color: var(--k-muted);
}

/* A cancelled receipt must not read as a valid one, in the preview or on paper. */
.k-receipt-void {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    font-size: 64px;
    font-weight: 700;
    letter-spacing: 8px;
    text-transform: uppercase;
    color: rgba(180, 35, 24, .16);
    transform: rotate(-18deg);
    pointer-events: none;
}

/* The standalone printable page - the receipt is the whole document there. */
.k-printpage {
    display: grid;
    place-items: start center;
    min-height: 100vh;
    padding: 24px;
}

.k-printpage .k-receipt-sheet {
    width: min(var(--k-sheet-w), 100%);
}

/* ==========================================================================
   Responsive
   --------------------------------------------------------------------------
   Two breakpoints, both already used above for the form grids and the charts:

     900px  the eight-item nav row no longer fits, so it becomes a side sheet
            opened by the burger, and the wider bars start wrapping
     600px  a phone held upright - anything that is still two things side by
            side goes to one, and labels that only repeat an icon are dropped

   The desktop layout is untouched above 900px.
   ========================================================================== */

@media (max-width: 900px) {

    /* The burger replaces the row; the panel and its scrim are position:fixed,
       and backdrop-filter on the header would make the header their containing
       block instead of the viewport - so the blur goes and the bar turns
       opaque, which it has to be anyway once the page scrolls under it. */
    .k-topnav {
        backdrop-filter: none;
        background: var(--k-surface);
    }

    .k-burger {
        display: inline-flex;
    }

    .k-nav-scrim:not([hidden]) {
        display: block;
    }

    /* Off-canvas panel. Parked just off the left edge and slid in, rather than
       toggled with display, so it animates and stays in the tab order. */
    .k-navrow {
        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        z-index: 2;
        width: min(284px, 82vw);
        max-width: none;
        margin: 0;
        padding: 0 0 16px;
        display: flex;
        flex-direction: column;
        gap: 2px;
        background: var(--k-surface);
        border-right: .8px solid var(--k-border);
        box-shadow: 0 20px 25px -5px rgba(0, 0, 0, .1), 0 8px 10px -6px rgba(0, 0, 0, .1);
        overflow-x: hidden;
        overflow-y: auto;
        transform: translateX(-100%);
        transition: transform .22s ease;
    }

    .k-sidenav-open {
        transform: translateX(0);
    }

    .k-sidenav-head {
        display: flex;
    }

    /* The row's underline marks the active tab from below; a vertical list is
       marked down its side instead. */
    .k-navlink {
        padding: 12px 16px;
        border-bottom: 0;
        border-left: 3px solid transparent;
    }

    .k-navlink.active {
        border-bottom-color: transparent;
        border-left-color: var(--k-primary);
        background: var(--k-primary-soft);
    }

    /* Bars that put two groups at opposite ends: at this width they are allowed
       to stack instead of squeezing. */
    .k-page-head,
    .k-pager,
    .k-drawer-head,
    .k-filters-actions,
    .k-modal-head {
        flex-wrap: wrap;
    }

    .k-pager {
        gap: 12px;
    }
}

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

@media (max-width: 600px) {

    /* Tighter gutters - 24px each side is a seventh of a 360px screen. */
    .k-shell,
    .k-topnav-bar {
        padding-left: 16px;
        padding-right: 16px;
    }

    .k-page-title {
        font-size: 20px;
        line-height: 28px;
    }

    /* The avatar carries the identity on a phone; the name, the role and the
       word "Logout" are what push the bar wider than the screen. */
    .k-identity-text,
    .k-logout-text,
    .k-brand-tag {
        display: none;
    }

    .k-identity {
        gap: 6px;
        padding-left: 8px;
    }

    .k-logout {
        padding-left: 8px;
        padding-right: 8px;
    }

    .k-brand-mark {
        width: 34px;
        height: 34px;
        border-radius: 10px;
        flex: 0 0 auto;
    }

    /* The trust name is the one thing here that can give, so it is the one thing
       allowed to: the burger and the avatar hold their size and it takes an
       ellipsis. A flex item will not shrink past its own content without
       min-width:0, which is what let the bar overflow a 360px screen. */
    .k-brand {
        min-width: 0;
    }

    .k-brand > span:not(.k-brand-mark) {
        min-width: 0;
        overflow: hidden;
    }

    .k-brand-name {
        display: block;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .k-identity {
        flex: 0 0 auto;
    }

    /* A page's title and its one action read better stacked than cramped. */
    .k-page-head > .k-btn,
    .k-formbar > .k-btn,
    .k-filters-actions > .k-btn {
        flex: 1 1 auto;
        justify-content: center;
    }

    /* Two side-by-side buttons share the width equally. */
    .k-filters-actions > .k-btn {
        flex: 1 1 0;
        min-width: 0;
    }

    .k-filters-actions {
        flex-wrap: nowrap;
    }

    .k-filters-row-search {
        grid-template-columns: minmax(0, 1fr);
    }

    .k-filters-row-narrow {
        grid-template-columns: minmax(0, 200px);
    }

    .k-formbar {
        flex-direction: column;
    }

    .k-filters-actions {
        justify-content: stretch;
    }

    /* The tabs are wider than the screen once both labels are shown, so they
       scroll rather than wrap into a two-row block. */
    .k-segment {
        display: flex;
        width: 100%;
        overflow-x: auto;
        scrollbar-width: none;
    }

    .k-segment::-webkit-scrollbar {
        display: none;
    }

    .k-segment a {
        white-space: nowrap;
    }

    /* Both halves of the pager go full width and read left to right. The three
       control groups wrap onto their own lines rather than running off the
       card, which clipped Next out of reach on a 320px screen. */
    .k-pager > * {
        width: 100%;
    }

    .k-pager-controls,
    .k-pager-list {
        flex-wrap: wrap;
        gap: 8px;
    }

    /* A dialog is nearly the whole screen here, so its chrome tightens up and
       the body is given back the height the head and foot were taking. */
    .k-modal,
    .k-modal-wide {
        width: calc(100vw - 24px);
    }

    .k-modal-head {
        padding: 16px 16px 0;
    }

    .k-modal-body {
        padding: 16px;
        max-height: 70vh;
    }

    .k-photo {
        max-height: calc(70vh - 32px);
    }

    .k-modal-foot {
        padding: 0 16px 16px;
    }

    .k-modal-foot > .k-btn {
        flex: 1 1 auto;
        justify-content: center;
    }

    .k-section,
    .k-card-pad {
        padding: 16px;
    }

    .k-drawer-body {
        padding: 12px;
    }

    .k-drawer-actions {
        flex-wrap: wrap;
    }
}

/* ---------- printing ----------
   Only the sheet goes on paper. Hiding by visibility rather than display keeps
   the sheet's own layout intact, so the printed page matches the preview. */
@media print {
    body * {
        visibility: hidden;
    }

    .k-receipt-sheet,
    .k-receipt-sheet * {
        visibility: visible;
    }

    /* The sheet is drawn at its designed 520px and then scaled up to the whole
       page, rather than being widened - widening would stretch the layout while
       leaving the 10-11px type at its screen size, which prints too small to
       read.

       It scales to the FULL sheet of paper, not to a printable area inside a
       printer margin, because the receipt already carries its own padding: at
       this scale the designed 32px sides become 12.9mm and the 28px top and
       bottom become 11.3mm. Those are the margins on the printed page, and being
       the document's own padding they are equal on all four edges by
       construction - no dependence on what the browser would otherwise inset.
       That is why @page below sets margin: 0.

       The design's sheet is A4-proportioned already (520 x 735 is 1.4135, A4 is
       1.4143), so scaling to the width fills the height to within half a
       millimetre. 210mm = 793.7px at 96dpi: 793.7 / 520 = 1.5264.

       The selector carries the page and drawer classes so it outranks the
       .k-printpage rule that caps the sheet at 520px on screen. */
    .k-printpage .k-receipt-sheet,
    .k-drawer .k-receipt-sheet,
    .k-receipt-sheet {
        position: absolute;
        left: 0;
        top: 0;
        width: var(--k-sheet-w);
        transform: scale(1.5264);
        transform-origin: top left;
        border-radius: 0;
        box-shadow: none;
    }

    /* The orange amount band and the receipt badge carry meaning, so they are
       printed rather than dropped by the browser's default of leaving background
       graphics off. */
    .k-receipt-sheet {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }

    /* Printing from the drawer: it is fixed to the right of the viewport, and an
       absolutely positioned sheet would anchor to it rather than to the page. The
       drawer is taken out of the way so the sheet lands on the paper square, and
       the scroll lock is lifted so the receipt is not cut off after one page. */
    .k-scroll-locked {
        overflow: visible;
    }

    .k-drawer {
        position: static;
        width: auto;
        height: auto;
        transform: none;
        box-shadow: none;
    }

    .k-drawer-body {
        overflow: visible;
        padding: 0;
    }

    .k-drawer-scrim {
        display: none;
    }

    .k-printpage {
        padding: 0;
    }

    /* No printer margin: the receipt's own padding is the margin, as explained
       above. Anything inset here would be added on top of it, and would push the
       full-page sheet onto a second sheet. */
    @page {
        size: A4;
        margin: 0;
    }
}

/* ---------- Privacy policy (public, standalone page) ---------- */

.k-policy-top {
    background: linear-gradient(135deg, var(--k-primary-dark), var(--k-primary));
    color: #fff;
}

.k-policy-top-in {
    max-width: 860px;
    margin: 0 auto;
    padding: 28px 20px 84px;
}

.k-policy-brand {
    display: flex;
    align-items: center;
    gap: 12px;
}

.k-policy-brand-mark {
    width: 44px;
    height: 44px;
    border-radius: 12px;
    background: rgba(255, 255, 255, .15);
    display: flex;
    align-items: center;
    justify-content: center;
}

.k-policy-brand-name {
    margin: 0;
    font-size: 15px;
    font-weight: 700;
    line-height: 18.75px;
}

.k-policy-brand-tag {
    margin: 0;
    font-size: 12px;
    line-height: 16px;
    color: rgba(255, 255, 255, .75);
}

.k-policy-top h1 {
    margin: 32px 0 6px;
    font-size: 32px;
    line-height: 1.2;
}

.k-policy-updated {
    margin: 0;
    font-size: 13px;
    color: rgba(255, 255, 255, .8);
}

.k-policy {
    max-width: 860px;
    margin: -56px auto 0;
    padding: 0 20px 56px;
}

.k-policy-card {
    background: var(--k-surface);
    border: 1px solid var(--k-border);
    border-radius: var(--k-r-lg);
    box-shadow: 0 1px 2px rgba(16, 24, 40, .05);
    padding: 36px 40px;
    line-height: 1.7;
    font-size: 14.5px;
}

.k-policy-card h2 {
    margin: 32px 0 8px;
    font-size: 17px;
    line-height: 1.3;
}

.k-policy-card h2:first-child {
    margin-top: 0;
}

.k-policy-card h3 {
    margin: 18px 0 6px;
    font-size: 14.5px;
}

.k-policy-card p,
.k-policy-card ul {
    margin: 0 0 12px;
}

.k-policy-card ul {
    padding-left: 20px;
}

.k-policy-card li + li {
    margin-top: 4px;
}

.k-policy-card a {
    color: var(--k-primary-dark);
    text-decoration: underline;
}

.k-policy-card code {
    font-family: var(--k-mono);
    font-size: 13px;
    background: var(--k-bg);
    padding: 1px 5px;
    border-radius: 4px;
}

.k-policy-table {
    width: 100%;
    border-collapse: collapse;
    margin: 0 0 14px;
    font-size: 13.5px;
}

.k-policy-table th,
.k-policy-table td {
    border: 1px solid var(--k-border);
    padding: 9px 12px;
    text-align: left;
    vertical-align: top;
}

.k-policy-table th {
    background: var(--k-bg);
    font-weight: 600;
}

.k-policy-foot {
    margin-top: 20px;
    text-align: center;
    font-size: 12px;
    color: var(--k-muted);
}

@media (max-width: 600px) {
    .k-policy-top-in {
        padding: 20px 16px 72px;
    }

    .k-policy-top h1 {
        font-size: 26px;
    }

    .k-policy {
        padding: 0 16px 40px;
    }

    .k-policy-card {
        padding: 24px 20px;
    }
}
