/* ═══════════════════════════════════════════════════════════════
   CourtPoach / Thomson Park — site.css
   All tokens locked to DESIGN.md §3–§9. Canon wins every conflict.
   Red means YOU. Green means DO IT. Navy means the club.
   ═══════════════════════════════════════════════════════════════ */

:root {
    /* Surface */
    --tp-cream:       #FCF8ED;
    --tp-cream-high:  #F5EFDF;
    --tp-white:       #FFFFFF;

    /* Identity (canon) */
    --tp-navy:        #1F2C68;  /* matches the painted sign */
    --tp-red:         #C8282C;  /* sign lozenge red */
    --tp-green:       #CEE04A;  /* ball yellow-green */
    --tp-silver:      #B8BFC6;  /* recurring block bands */
    --tp-grey:        #8A8A80;  /* past / locked */
    --tp-light-grey:  #D8D8D0;  /* subtle borders, read-only field chrome */

    /* Type */
    --tp-font-display: 'Big Shoulders Display', 'Arial Black', sans-serif;
    --tp-font-body:    'Public Sans', system-ui, sans-serif;

    /* Radii */
    --tp-r-chip:   12px;
    --tp-r-cell:   12px;
    --tp-r-button: 16px;
    --tp-r-modal:  20px;

    /* Shadow (modal cards only) */
    --tp-shadow-modal: 0 4px 8px rgba(31, 44, 104, 0.08);
}

/* ═══════════════════════════════════════
   Base
   ═══════════════════════════════════════ */

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

html, body {
    margin: 0;
    padding: 0;
    background: var(--tp-cream);
    color: var(--tp-navy);
    font-family: var(--tp-font-body);
    font-size: 18px;
    line-height: 1.4;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

body {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

a {
    color: var(--tp-navy);
    text-decoration: none;
}

button, input, select {
    font-family: inherit;
}

/* ═══════════════════════════════════════
   Loader (overlay content) — tennis ball drop with squash + shadow.
   ═══════════════════════════════════════ */

.page-overlay {
    background: var(--tp-cream);
}

.tp-loader {
    position: relative;
    width: 56px;
    height: 96px;
    color: var(--tp-navy);
}

.tp-ball {
    position: absolute;
    left: 50%;
    top: 0;
    margin-left: -16px;
    width: 32px;
    height: 32px;
    transform-origin: 50% 100%;
    animation: tp-drop 1400ms cubic-bezier(.5,.05,.5,.95) infinite;
}

.tp-ball-rot {
    width: 100%;
    height: 100%;
    animation: tp-spin 1400ms cubic-bezier(.35,.1,.65,.9) infinite;
}

.tp-ball .tp-ball-svg {
    display: block;
    width: 100%;
    height: 100%;
}

.tp-loader-shadow {
    position: absolute;
    left: 50%;
    bottom: 5px;
    margin-left: -18px;
    width: 36px;
    height: 5px;
    border-radius: 50%;
    background: var(--tp-navy);
    opacity: 0.175;
    filter: blur(3px);
    animation: tp-drop-shadow 1400ms cubic-bezier(.5,.05,.5,.95) infinite;
}

@keyframes tp-drop {
    0%   { top: 0;    transform: scale(1, 1); }
    42%  { top: 52px; transform: scale(1, 1); }
    48%  { top: 56px; transform: scale(1.06, 0.92); }
    55%  { top: 55px; transform: scale(1.02, 0.97); }
    100% { top: 0;    transform: scale(1, 1); }
}

/* Rotation: most of the spin (300°) happens during descent (0–42%).
   Only ~15° during impact/squash; remaining ~45° drifts out through the slower ascent.
   Rate: ~7°/% falling vs ~1°/% rising — matches physical energy loss on bounce. */
@keyframes tp-spin {
    0%   { transform: rotate(0deg); }
    42%  { transform: rotate(300deg); }
    55%  { transform: rotate(315deg); }
    100% { transform: rotate(360deg); }
}

@keyframes tp-drop-shadow {
    0%        { transform: scale(0.35); opacity: 0.15; }
    42%, 55%  { transform: scale(1);    opacity: 0.4; }
    100%      { transform: scale(0.35); opacity: 0.15; }
}

/* ═══════════════════════════════════════
   Wordmark (DESIGN.md §7 — centered, racquets flanking)
   ═══════════════════════════════════════ */

.tp-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 16px;
    max-width: 640px;
    margin: 0 auto;
    width: 100%;
    position: sticky;
    top: 0;
    z-index: 20;
    background: var(--tp-cream);
}

.tp-wordmark {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--tp-navy);
    flex-shrink: 1;
    min-width: 0;
}

/* Admin site link — thin sticky footer. Only rendered for admins (ViewBag.IsAdmin).
   Navy bar pinned to bottom; page content reserves space via body padding-bottom. */
.tp-admin-footer {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 25;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 8px 16px calc(8px + env(safe-area-inset-bottom, 0px));
    background: var(--tp-navy);
    color: var(--tp-cream);
    font-family: var(--tp-font-body);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    text-decoration: none;
}

.tp-admin-footer svg { display: block; }

body:has(.tp-admin-footer) { padding-bottom: 40px; }

/* User chip — member name + upcoming-bookings badge, links to /Booking/My. */
.tp-user-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
    padding: 6px 10px 6px 12px;
    background: var(--tp-white);
    border: 1px solid var(--tp-navy);
    border-radius: var(--tp-r-chip);
    color: var(--tp-navy);
    font-family: var(--tp-font-body);
    font-size: 14px;
    font-weight: 600;
    text-decoration: none;
}

.tp-user-chip-icon {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    opacity: 0.85;
}

.tp-user-chip-name {
    max-width: 96px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.tp-user-chip-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: 6px;
    background: var(--tp-red);
    color: var(--tp-cream);
    font-size: 12px;
    font-weight: 700;
    line-height: 1;
}

.tp-wordmark-emblem {
    display: inline-block;
    width: 40px;
    height: 40px;
    color: var(--tp-navy);
}

.tp-wordmark-emblem .tp-racquets {
    width: 100%;
    height: 100%;
}

.tp-wordmark-text {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    line-height: 0.95;
    font-family: var(--tp-font-display);
    font-weight: 900;
    font-size: 20px;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.tp-wordmark-line {
    display: block;
}

@media (min-width: 420px) {
    .tp-wordmark-emblem { width: 48px; height: 48px; }
    .tp-wordmark-text   { font-size: 24px; }
}

/* ═══════════════════════════════════════
   Main content
   ═══════════════════════════════════════ */

.tp-main {
    flex: 1;
    padding: 0 16px 32px;
    max-width: 640px;
    margin: 0 auto;
    width: 100%;
}

/* ═══════════════════════════════════════
   Type utilities
   ═══════════════════════════════════════ */

.tp-display {
    font-family: var(--tp-font-display);
    font-weight: 900;
    font-size: 32px;
    line-height: 1.1;
    color: var(--tp-navy);
    margin: 0 0 12px;
    letter-spacing: 0.01em;
}

.tp-body {
    font-family: var(--tp-font-body);
    font-size: 20px;
    color: var(--tp-navy);
    margin: 0 0 16px;
}

/* ═══════════════════════════════════════
   Buttons (primary = green DO IT; destructive = red)
   ═══════════════════════════════════════ */

.tp-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 56px;
    padding: 0 24px;
    border: 0;
    border-radius: var(--tp-r-button);
    font-family: var(--tp-font-display);
    font-weight: 900;
    font-size: 20px;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    cursor: pointer;
    text-decoration: none;
}

.tp-btn-primary {
    background: var(--tp-green);
    color: var(--tp-navy);
}

.tp-btn-destructive {
    background: var(--tp-red);
    color: var(--tp-cream);
}

/* ═══════════════════════════════════════
   Full-screen state (success / error / limit / unknown)
   DESIGN.md §7 — unified composition
   ═══════════════════════════════════════ */

.tp-fullscreen-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 16px;
    min-height: calc(100vh - 140px);
    text-align: center;
    padding: 32px 24px;
}

.tp-fullscreen-emblem {
    width: 96px;
    height: 96px;
    color: var(--tp-navy);
    margin-bottom: 8px;
}

.tp-fullscreen-emblem .tp-racquets { width: 100%; height: 100%; }

.tp-request-id {
    /* Dev-only debug breadcrumb; keeps at the hard floor so text-budget compliance holds. */
    font-family: var(--tp-font-body);
    font-size: 14px;
    color: var(--tp-grey);
    margin-top: 24px;
    letter-spacing: 0.02em;
}

/* ═══════════════════════════════════════
   Placeholder (Ring 1 bootstrap page)
   ═══════════════════════════════════════ */

.tp-placeholder {
    padding: 48px 0;
    text-align: center;
}

/* ═══════════════════════════════════════
   Grid page — date chips, booking pill, 3-court grid
   DESIGN.md §7
   ═══════════════════════════════════════ */

.tp-grid-page {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* Single sticky block that holds date chips, optional limit callout, and court
   column labels. One sticky container = no gap-covering hacks, no multi-element
   top syncing. JS sets `top` to the measured header height. */
.tp-sticky-top {
    position: sticky;
    top: 0; /* JS overrides to .tp-header.offsetHeight */
    z-index: 15;
    background: var(--tp-cream);
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding-bottom: 8px; /* breathing room before the scrolling grid */
}

/* --- Date chips (Today + next 3) --- */

.tp-date-chips {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 8px;
    padding: 8px 0 0; /* matches pre-scroll breathing below .tp-header */
}

.tp-date-chip {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 10px 8px;
    min-height: 64px;
    border: 2px solid var(--tp-navy);
    border-radius: var(--tp-r-chip);
    background: var(--tp-white);
    color: var(--tp-navy);
    text-decoration: none;
}

.tp-date-chip-label {
    font-family: var(--tp-font-body);
    font-weight: 700;
    font-size: 14px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.tp-date-chip-num {
    font-family: var(--tp-font-body);
    font-weight: 700;
    font-size: 22px;
    margin-top: 2px;
    line-height: 1;
}

.tp-date-chip--selected {
    background: var(--tp-navy);
    color: var(--tp-cream);
    border-color: var(--tp-navy);
}

.tp-date-chip--selected .tp-date-chip-label,
.tp-date-chip--selected .tp-date-chip-num {
    color: var(--tp-cream);
}

/* --- Booking-count pill --- */

.tp-pill {
    align-self: center;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 48px;
    padding: 0 24px;
    border: 2px solid var(--tp-navy);
    border-radius: var(--tp-r-button);
    background: var(--tp-white);
    color: var(--tp-navy);
    font-family: var(--tp-font-body);
    font-size: 18px;
    font-weight: 600;
    text-decoration: none;
}

.tp-pill--muted {
    opacity: 0.6;
}

/* Callout — informational FYI, not a button. No border/bg.
   Rendered inside .tp-sticky-top so it inherits the sticky behavior. */
.tp-callout {
    margin: 0;
    padding: 0 16px;
    color: var(--tp-navy);
    font-family: var(--tp-font-body);
    font-size: 18px;
    font-weight: 700;
    text-align: center;
}

.tp-callout-icon {
    display: inline-block;
    vertical-align: -4px;
    width: 20px;
    height: 20px;
    margin-right: 6px;
}

.tp-callout-link {
    color: inherit;
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-thickness: 2px;
}

/* Persistent booking-limit status line — always shown under the date chips
   when signed in. Neutral tone (no color shift at cap) because grid cells
   already grey out when a limit is reached. */
.tp-limit-status {
    margin: 0;
    padding: 4px 16px 0;
    display: flex;
    justify-content: center;
    gap: 10px;
    color: var(--tp-navy);
    font-family: var(--tp-font-body);
    font-size: 14px;
    font-weight: 500;
}

.tp-limit-status strong { font-weight: 700; }

.tp-limit-sep { color: var(--tp-grey); }

/* Toast-style alerts (override for the Common RCL Alert component). */
.tp-alerts {
    position: fixed;
    top: 12px;
    right: 12px;
    z-index: 1000;
    display: flex;
    flex-direction: column;
    gap: 8px;
    pointer-events: none;
}

.tp-alert {
    padding: 10px 16px;
    border-radius: var(--tp-r-button);
    background: var(--tp-navy);
    color: var(--tp-cream);
    font-family: var(--tp-font-body);
    font-size: 14px;
    font-weight: 600;
    box-shadow: var(--tp-shadow-modal);
    opacity: 1;
    transition: opacity 300ms ease-out;
    max-width: 320px;
}

.tp-alert--danger { background: var(--tp-red); }
.tp-alert--success { background: var(--tp-navy); }
.tp-alert--fade { opacity: 0; }

/* --- Grid --- */

.tp-grid {
    display: grid;
    grid-template-columns: 52px repeat(3, 1fr);
    column-gap: 8px;
    row-gap: 8px;
}

/* Court-column labels row — lives inside .tp-sticky-top, not inside the grid.
   Its own mini-grid matches the main grid's column layout so labels align. */
.tp-grid-head {
    display: grid;
    grid-template-columns: 52px repeat(3, 1fr);
    column-gap: 8px;
}

.tp-col-court {
    font-family: var(--tp-font-body);
    font-weight: 700;
    font-size: 14px;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--tp-navy);
    text-align: center;
    padding: 4px 0;
}

.tp-grid-row {
    display: contents;
}

.tp-col-time {
    font-family: var(--tp-font-body);
    font-weight: 600;
    font-size: 14px;
    color: var(--tp-navy);
    text-align: right;
    padding-right: 4px;
    align-self: center;
}

.tp-grid-row--past .tp-col-time {
    color: var(--tp-grey);
}

/* Past rows stay visible so earlier bookings aren't "lost" on today's grid,
   but cells are non-interactive. Only --mine needs dimming — the other states
   are already visually subdued in their base form, so double-dimming hurts
   legibility without adding "past-ness". */
.tp-grid-row--past .tp-cell {
    pointer-events: none;
    cursor: default;
}
.tp-grid-row--past .tp-cell--mine {
    opacity: 0.5;
}

/* --- Cells (DESIGN.md §7 cell states) --- */

.tp-cell {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 64px;
    border: 1px solid var(--tp-navy);
    border-radius: var(--tp-r-cell);
    background: var(--tp-white);
    color: var(--tp-navy);
    position: relative;
    text-decoration: none;
    font-family: var(--tp-font-body);
    font-size: 16px;
    font-weight: 500;
}

.tp-cell--free .tp-ball-svg {
    width: 28px;
    height: 28px;
}

.tp-cell--mine {
    background: var(--tp-red);
    border-color: var(--tp-red);
    color: var(--tp-cream);
}

.tp-check {
    width: 32px;
    height: 32px;
}

/* Unbookable cells — past hours and slots booked by another member.
   Same "grey disabled" treatment; "other" keeps navy name for readability. */
.tp-cell--past,
.tp-cell--other {
    background: var(--tp-cream-high);
    border-color: var(--tp-grey);
    cursor: default;
}

.tp-cell--past  { color: var(--tp-grey); }
.tp-cell--other { color: var(--tp-navy); }

.tp-cell--mine .tp-cell-name {
    padding: 0 6px;
    text-align: center;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
    font-weight: 700;
}

.tp-cell--other .tp-cell-name {
    padding: 0 6px;
    text-align: center;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
}

.tp-cell--blocked,
.tp-band {
    background: var(--tp-silver);
    border-color: var(--tp-silver);
    color: var(--tp-navy);
}

.tp-cell--blocked .tp-cell-block-label {
    font-family: var(--tp-font-body);
    font-weight: 700;
    font-size: 14px;
    letter-spacing: 0.01em;
    text-align: center;
    padding: 0 4px;
    line-height: 1.05;
    word-break: break-word;
    hyphens: auto;
    max-width: 100%;
    overflow: hidden;
}

/* Full-row band (CourtId=null block) — spans across all 3 court columns */

.tp-band {
    grid-column: 2 / -1;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 64px;
    border-radius: var(--tp-r-cell);
    border-width: 1px;
    border-style: solid;
    /* Match the per-cell blocked label so bands and single-court blocks read as
       the same class (body font, bold all-caps). Slightly larger + more tracking
       than the cell variant since the band has horizontal room to breathe. */
    font-family: var(--tp-font-body);
    font-weight: 700;
    font-size: 15px;
    letter-spacing: 0.04em;
}

.tp-band-label {
    padding: 0 12px;
    text-align: center;
}

/* ═══════════════════════════════════════
   Dev sign-in panel (Development only)
   ═══════════════════════════════════════ */

.tp-dev-panel {
    max-width: 480px;
    margin: 48px auto;
    padding: 24px;
    background: var(--tp-cream);
    border: 2px solid var(--tp-navy);
    border-radius: var(--tp-r-modal);
}

.tp-dev-list {
    list-style: none;
    padding: 0;
    margin: 16px 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.tp-dev-list .tp-btn { width: 100%; }

/* ═══════════════════════════════════════
   Full-page booking detail (confirm / success / cancel / state pages)
   DESIGN.md §7 — unified composition
   ═══════════════════════════════════════ */

.tp-full-page {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: calc(100vh - 120px);
    padding: 24px 0;
}

.tp-booking-detail {
    width: 100%;
    max-width: 420px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
    text-align: center;
}

.tp-booking-emblem {
    width: 72px;
    height: 72px;
    color: var(--tp-navy);
}

.tp-booking-emblem .tp-racquets { width: 100%; height: 100%; }

/* Spinning tennis ball on the booking Confirm/Cancel/Success screens — avoids
   repeating the crossed-racquets emblem that already sits in the top-left
   wordmark. The inner SVG spins so the ground-shadow pseudo-element (::after)
   can stay still underneath, giving the "rolling along the ground" read. */
.tp-booking-ball {
    width: 72px;
    height: 72px;
    position: relative;
}

.tp-booking-ball .tp-ball-svg {
    width: 100%;
    height: 100%;
    display: block;
    animation: tp-spin-steady 2400ms linear infinite;
}

/* ::before so the shadow paints underneath the SVG in DOM paint order —
   the opaque green circle occludes any shadow that would otherwise bleed
   through the ball's transparent viewBox corners. */
.tp-booking-ball::before {
    content: "";
    position: absolute;
    left: 50%;
    bottom: 2px;
    /* Mirror of the previous right-tailing shadow: element is now anchored
       mostly to the left of center, dark core tucked under the ball on its
       right side, tail fading out to the left — reads as a light source
       from the upper-right (ball rolling toward the sun). */
    transform: translateX(-90%);
    width: 114%;
    height: 8.5px;
    border-radius: 50%;
    background: radial-gradient(ellipse at 75% 50%,
        rgba(31, 44, 104, 0.2) 0%,
        rgba(31, 44, 104, 0.1) 45%,
        rgba(31, 44, 104, 0) 85%);
    filter: blur(2.5px);
    pointer-events: none;
}

@keyframes tp-spin-steady {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

.tp-booking-stack {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    line-height: 1.05;
}

.tp-booking-stack--inline {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 8px;
    justify-content: center;
    font-family: var(--tp-font-display);
    font-weight: 900;
    font-size: 22px;
}

.tp-booking-day,
.tp-booking-time,
.tp-booking-court {
    font-family: var(--tp-font-display);
    font-weight: 900;
    font-size: 40px;
    color: var(--tp-navy);
}

.tp-booking-stack--inline .tp-booking-day,
.tp-booking-stack--inline .tp-booking-time,
.tp-booking-stack--inline .tp-booking-court {
    font-size: 22px;
}

.tp-booking-dot { color: var(--tp-navy); font-size: 22px; }

.tp-booking-meta {
    margin: 0;
    color: var(--tp-navy);
    font-size: 18px;
}

.tp-booking-actions {
    width: 100%;
    margin-top: 8px;
}

.tp-btn-full { width: 100%; }

.tp-btn-locked {
    background: var(--tp-grey);
    color: var(--tp-cream);
    cursor: not-allowed;
    pointer-events: none;
}

.tp-back-link {
    color: var(--tp-navy);
    font-size: 16px;
    text-decoration: underline;
    padding: 8px 0;
}

.tp-display-hero {
    font-size: 40px;
    margin: 0;
}

.tp-hero-check {
    width: 140px;
    height: 140px;
}

.tp-hero-check svg { width: 100%; height: 100%; }

/* ═══════════════════════════════════════
   My bookings list
   ═══════════════════════════════════════ */

.tp-mybookings {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 16px 0;
}

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

.tp-booking-card {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    background: transparent;
    border: 1px solid var(--tp-navy);
    border-radius: var(--tp-r-modal);
    padding: 12px 16px;
}

.tp-booking-card-body {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.tp-booking-card-day {
    font-family: var(--tp-font-display);
    font-weight: 900;
    font-size: 22px;
    color: var(--tp-navy);
}

.tp-booking-card-time {
    font-family: var(--tp-font-body);
    font-size: 18px;
    color: var(--tp-navy);
}

.tp-booking-card-x {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 44px;
    padding: 0 12px;
    background: var(--tp-white);
    border: 1px solid var(--tp-navy);
    border-radius: var(--tp-r-button);
    color: var(--tp-navy);
    font-family: var(--tp-font-body);
    font-weight: 700;
    font-size: 13px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    text-decoration: none;
}

.tp-booking-card-x svg { width: 20px; height: 20px; }

/* ═══════════════════════════════════════
   Motion — DESIGN.md §8
   Every animation must respect prefers-reduced-motion.
   ═══════════════════════════════════════ */

/* Date chip press: scale to 96% then spring back via transition */
.tp-date-chip {
    transition: transform 120ms cubic-bezier(0.2, 1, 0.3, 1);
}
.tp-date-chip:active {
    transform: scale(0.96);
}

/* Cell tap (bookable Free cell): scale to 102% briefly */
.tp-cell--free {
    transition: transform 120ms ease-out;
}
.tp-cell--free:active {
    transform: scale(1.02);
}

/* Mine cell press gives tactile feedback before cancel page loads */
.tp-cell--mine:active {
    transform: scale(0.98);
    transition: transform 120ms ease-out;
}

/* Buttons: subtle press */
.tp-btn {
    transition: transform 120ms ease-out, background 120ms ease-out;
}
.tp-btn:active:not(.tp-btn-locked) {
    transform: scale(0.98);
}

/* Success: stroke-by-stroke checkmark draw */
.tp-hero-check svg circle {
    transform-origin: 60px 60px;
    animation: tp-pop 260ms cubic-bezier(0.2, 1, 0.3, 1) both;
}
.tp-hero-check svg path {
    stroke-dasharray: 90;
    stroke-dashoffset: 90;
    animation: tp-draw 250ms 200ms ease-out both;
}

@keyframes tp-pop {
    0%   { transform: scale(0.6); opacity: 0; }
    100% { transform: scale(1);    opacity: 1; }
}
@keyframes tp-draw {
    to { stroke-dashoffset: 0; }
}

@media (prefers-reduced-motion: reduce) {
    .tp-date-chip,
    .tp-cell--free,
    .tp-cell--mine,
    .tp-btn {
        transition: none;
    }
    .tp-date-chip:active,
    .tp-cell--free:active,
    .tp-cell--mine:active,
    .tp-btn:active:not(.tp-btn-locked) {
        transform: none;
    }
    .tp-hero-check svg circle,
    .tp-hero-check svg path,
    .tp-ball,
    .tp-ball-rot,
    .tp-loader-shadow,
    .tp-booking-ball .tp-ball-svg {
        animation: none;
    }
    .tp-hero-check svg path {
        stroke-dashoffset: 0;
    }
}
