/* ==========================================================================
   The gift/self-buy purchase form — WS-3 (BTS-3.2, C-4 half one)
   Prefix: gft-  ·  DESIGN §3.3 (gft-choice) and §3.4 (gft-details)

   SEPARATE FROM pack.css ON PURPOSE, and the boundary is not tidiness. pk- is
   the pack page's own furniture; gft- is the PURCHASE FORM, which is shared
   with the gift surfaces and outlives any one page. Keeping them apart is also
   what preserves pack.css's tested invariant that every selector in it names a
   pk- class — one gft- rule in that file breaks the test the day it lands.

   Contract (DESIGN §2.1, §4.6, design-contract §1.6), tested in
   tests/test_story_starter_pack_page.py:
   · Tokens are CONSUMED from styles.css:1-88; this sheet DEFINES none, and
     never names the four variables the slim footer renders from undefined
     values by design.
   · Every selector that names a class names a gft- one, so nothing outside
     this component is restyled from here.
   · Shell-agnostic: loaded through head_extra, so it depends on nothing
     either shell adds.
   ========================================================================== */

/* ==========================================================================
   gft-choice — the gift versus self-buy toggle (DESIGN §3.3)

   THE MOST CONSEQUENTIAL SMALL COMPONENT ON THE FORM. Gift and self-buy share
   one Stripe price id and are distinguished ONLY by metadata, so a visitor who
   cannot tell which they picked pays GBP 50 and receives the wrong artefact —
   and the wrong artefact now includes a PERMANENT entitlement that cannot be
   spent down and, per FR-217 case 4, cannot be clawed back from an innocent
   redeemer.
   ========================================================================== */

.gft-choice {
    margin: 0 0 var(--space-3);
    padding: 0;
    border: 0;
}

.gft-choice-legend {
    padding: 0;
    margin-bottom: var(--space-2);
    font-weight: 600;
    font-size: var(--text-sm);
    color: var(--color-text-primary);
}

/* ⛔ NEVER display:none, and this is the defect the shipped .radio-card has:
   a display:none input is removed from the accessibility tree and cannot be
   reached or operated by keyboard. Clipped-and-transparent keeps it focusable
   while the card carries the visuals. */
.gft-choice-input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
}

.gft-choice-card {
    display: block;
    margin-bottom: var(--space-2);
    cursor: pointer;
}

.gft-choice-body {
    position: relative;
    display: block;
    min-height: 56px;
    /* space-3 at <=375 only, on the same reasoning DESIGN §3.2 applies to the
       card's own padding: this component measures 270px against a 96px budget,
       so every in-spec pixel is taken before the overrun is reported. */
    padding: var(--space-3);
    background: var(--cloud);
    border: 2px solid var(--color-border);
    border-radius: var(--radius-md);
}

.gft-choice-label {
    display: block;
    font-weight: 600;
    font-size: var(--text-base);
    color: var(--color-text-primary);
}

/* Charcoal, NOT driftwood (R-1): driftwood measures 3.69:1 on cream. */
.gft-choice-desc {
    display: block;
    margin-top: var(--space-1);
    font-size: var(--text-sm);
    line-height: 1.5;
    color: var(--color-text-primary);
}

/* ⭐ THREE SIMULTANEOUS CUES — border, fill and glyph — so the checked state is
   never carried by colour alone (NFR-023, WCAG 1.4.1). The glyph is generated
   content and therefore decorative; the radio itself is what assistive
   technology reads, so nothing is announced twice and nothing is announced
   only in colour. #2C2418 on #f0f7f4 is 14.07:1. */
.gft-choice-input:checked + .gft-choice-body {
    border-color: var(--color-primary);
    background: #f0f7f4;
}

.gft-choice-input:checked + .gft-choice-body .gft-choice-label::before {
    content: "\2713\00a0";
    color: var(--forest-moss);
}

/* z-index so the ring is not clipped by the neighbouring card. */
.gft-choice-input:focus-visible + .gft-choice-body {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
    z-index: 1;
}

@media (min-width: 376px) {
    .gft-choice-body { padding: var(--space-4); }
}

/* Stacked below 768, side by side above it. The legend is taken out of the
   grid's flow by the fieldset's own layout, so it needs no placement rule. */
@media (min-width: 768px) {
    .gft-choice {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: var(--space-3);
    }

    .gft-choice-card {
        margin-bottom: 0;
    }
}

/* ==========================================================================
   gft-details — the recipient form (DESIGN §3.4)

   Five fields, ALL OPTIONAL: nothing here may block the purchase, because a
   blocked GBP 50 checkout on paid traffic is the most expensive failure on the
   page. Rendered VISIBLE by the server and hidden by script at parse time, so
   the no-JavaScript form is merely longer rather than broken.
   ========================================================================== */

.gft-details {
    margin: 0 0 var(--space-4);
    padding: var(--space-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--parchment);
}

.gft-details .form-group {
    margin-bottom: var(--space-3);
}

.gft-details-legend {
    padding: 0 var(--space-2);
    font-weight: 600;
    font-size: var(--text-sm);
    color: var(--color-text-primary);
}

.gft-intro,
.gft-clock {
    margin: 0 0 var(--space-3);
    font-size: var(--text-sm);
    line-height: 1.5;
    color: var(--color-text-primary);
}

.gft-clock {
    margin: var(--space-3) 0 0;
}

/* Charcoal, NOT .form-hint, which is driftwood (styles.css:427) and fails R-1
   at 3.69:1 on cream. */
.gft-hint-live,
.gft-hint {
    display: block;
    margin: var(--space-1) 0 0;
    font-size: var(--text-sm);
    line-height: 1.5;
    color: var(--color-text-primary);
}

/* ⭐ THE DELIVERY-CONSEQUENCE LINE, AND IT IS LIVE WITHOUT JAVASCRIPT.
   A blank optional field is a silent default on a decision that determines
   whether a stranger receives an email, so the line states which of the two
   things will happen. It swaps on :placeholder-shown rather than in script,
   which is why the field carries a placeholder at all.
   ⛔ The default (both lines visible) is the correct degradation where :has()
   is unsupported: DESIGN §3.4 asks the static form to state BOTH branches. */
.gft-email-group:has(input:placeholder-shown) .gft-hint-filled,
.gft-email-group:has(input:not(:placeholder-shown)) .gft-hint-empty {
    display: none;
}

.gft-send {
    margin: var(--space-3) 0 0;
    padding: 0;
    border: 0;
}

.gft-send-legend {
    padding: 0;
    margin-bottom: var(--space-2);
    font-weight: 500;
    font-size: var(--text-sm);
    color: var(--color-text-primary);
}

.gft-send-option {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-height: 44px;
    font-size: var(--text-sm);
    color: var(--color-text-primary);
    cursor: pointer;
}
