/*
  Plain, hand-written CSS. No build step, no preprocessor, no framework.
  Tokens and component specs come from DESIGN.md — keep the two in sync.
*/

/* ---------- View transitions ---------- */

/*
  Cross-document view transitions for plain page navigations (login <-> register,
  marketing -> auth, etc). Chromium/Safari crossfade automatically; browsers
  without support just navigate normally, so this is a free upgrade.
*/
@view-transition {
    navigation: auto;
}

/* ---------- Reset ---------- */

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

html {
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
}

img,
svg {
    display: block;
    max-width: 100%;
}

button,
input,
textarea {
    font: inherit;
    color: inherit;
}

a {
    color: inherit;
}

/* ---------- Tokens ---------- */

:root {
    --bg: #F7F5F1;
    --surface: #FFFFFF;
    --chrome: #FBFAF7;
    --ink: #211F1D;
    --muted: #6B655C;
    --faint: #8B857D;
    --accent: #3E5C4B;
    --accent-strong: #324A3C;
    --brass: #B08D57;
    --line: #E5E1D8;
    --wash: #F1EEE7;
    --danger: #A3453B;

    --radius: 12px;
    --radius-input: 10px;
    --shadow-card: 0 1px 2px rgba(33, 31, 29, .05), 0 12px 32px rgba(33, 31, 29, .07);
    --ease: 150ms ease-out;

    --font-display: 'Fraunces', Georgia, serif;
    --font-body: 'Inter', system-ui, sans-serif;

    --content-max: 1100px;
}

/* ---------- Base ---------- */

body {
    background: var(--bg);
    color: var(--ink);
    font-family: var(--font-body);
    font-size: 14.5px;
    line-height: 1.55;
}

h1,
h2,
h3 {
    font-family: var(--font-display);
    font-weight: 600;
    line-height: 1.2;
    margin: 0;
}

p {
    margin: 0;
}

a {
    text-decoration: none;
}

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    * {
        transition: none !important;
        animation: none !important;
    }

    ::view-transition-group(*),
    ::view-transition-old(*),
    ::view-transition-new(*) {
        animation: none !important;
    }
}

/* ---------- Layout ---------- */

.container {
    width: 100%;
    max-width: var(--content-max);
    margin-inline: auto;
    padding-inline: 20px;
}

/* ---------- Site chrome ---------- */

.site-header {
    border-bottom: 1px solid var(--line);
    background: var(--chrome);
}

.site-header .container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding-block: 16px;
}

.brand {
    font-family: var(--font-display);
    font-size: 19px;
    font-weight: 600;
    color: var(--ink);
}

.nav-links {
    display: flex;
    align-items: center;
    gap: 12px;
}

.site-footer {
    border-top: 1px solid var(--line);
}

.site-footer .container {
    padding-block: 20px;
    font-size: 13px;
    color: var(--muted);
}

/* ---------- Guest shell (share page) ---------- */

/*
  Guest pages get a shell of their own: a wordmark bar over the page background, no app
  nav, no sidebar. Someone opening a share link is meeting the product for the first time,
  so the list is the interface — the chrome just says whose app it is.
*/
.guest-bar {
    position: sticky;
    top: 0;
    z-index: 20;
    background: var(--bg);
    border-bottom: 1px solid var(--line);
}

.guest-bar .container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding-block: 14px;
}

.guest-main {
    padding-block: 32px 72px;
}

/* ---------- Buttons ---------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    height: 40px;
    padding-inline: 20px;
    border-radius: 999px;
    font-family: var(--font-body);
    font-size: 13px;
    font-weight: 600;
    border: 1px solid transparent;
    cursor: pointer;
    transition: background var(--ease), border-color var(--ease), color var(--ease);
    white-space: nowrap;
}

.btn-primary {
    background: var(--accent);
    color: #fff;
}

.btn-primary:hover {
    background: var(--accent-strong);
}

.btn-ghost {
    background: transparent;
    border-color: var(--line);
    color: var(--ink);
}

.btn-ghost:hover {
    border-color: var(--accent);
}

.btn:disabled {
    opacity: .45;
    cursor: not-allowed;
}

.btn-text {
    background: none;
    border: none;
    height: auto;
    padding: 0;
    color: var(--muted);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.btn-small {
    height: 32px;
    padding-inline: 14px;
}

.btn-block {
    width: 100%;
}

/*
  The copy button (see components/copy-link.blade.php). A ghost button so it stays quiet next to
  whatever it shares a row with, going accent only for the moment it is confirming. Both faces sit
  on one another in a one-cell grid and crossfade, so the label is the wider of "Copy link" and
  "Copied" at all times and the button never changes width under the pointer.
*/
.copy-link {
    position: relative;
    z-index: 1;
}

.copy-link svg {
    width: 16px;
    height: 16px;
}

.copy-link__icon,
.copy-link__label {
    display: grid;
    flex: none;
}

.copy-link__face {
    grid-area: 1 / 1;
    transition: opacity var(--ease);
}

.copy-link__face--done {
    opacity: 0;
}

.copy-link.is-copied {
    border-color: var(--accent);
    color: var(--accent);
}

.copy-link.is-copied .copy-link__face--idle {
    opacity: 0;
}

.copy-link.is-copied .copy-link__face--done {
    opacity: 1;
}

/* ---------- Auth pages ---------- */

.auth-shell {
    display: flex;
    justify-content: center;
    padding-block: 56px;
}

.auth-card {
    width: 100%;
    max-width: 380px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow-card);
    padding: 32px;
}

.auth-title {
    font-size: 22px;
}

.auth-sub {
    margin-top: 6px;
    color: var(--muted);
    font-size: 14px;
}

.auth-form {
    display: flex;
    flex-direction: column;
    gap: 16px;
    margin-top: 22px;
}

.field {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.field-label {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--muted);
}

.field input {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-input);
    padding: 10px 13px;
    font-size: 14px;
}

.field input:focus-visible {
    border-color: var(--accent);
}

/*
  The line that says what an optional field is for, under its label. Same size as the error it
  shares the column with, muted rather than red: a hint is help, not a correction, and the label
  above is still the one thing the field says.
*/
.field-hint {
    color: var(--muted);
    font-size: 12.5px;
}

.field-error {
    margin-top: -10px;
    color: var(--danger);
    font-size: 12.5px;
}

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

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

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

.auth-footer a {
    color: var(--accent);
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* ---------- Hero ---------- */

.hero {
    padding-block: 64px 56px;
    display: flex;
    align-items: center;
    gap: 56px;
}

.hero-copy {
    flex: 1;
    min-width: 0;
}

.hero-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 18px;
}

.hero-eyebrow::before {
    content: '';
    width: 7px;
    height: 7px;
    border-radius: 999px;
    background: var(--accent);
}

.hero-title {
    font-size: 40px;
    max-width: 15ch;
}

.hero-sub {
    margin-top: 18px;
    max-width: 52ch;
    color: var(--muted);
    font-size: 16px;
}

.hero-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 14px;
    margin-top: 28px;
}

.hero-sample {
    flex: none;
    width: 320px;
}

.hero-sample__row {
    flex-wrap: wrap;
    cursor: default;
}

.hero-sample__row .item-row__tier {
    width: 100%;
    padding-top: 0;
}

.hero-sample__caption {
    margin-top: 14px;
    text-align: center;
    color: var(--faint);
    font-size: 12px;
}

@media (max-width: 860px) {
    .hero {
        flex-direction: column;
        align-items: stretch;
        gap: 36px;
    }

    .hero-sample {
        width: 100%;
        max-width: 360px;
    }
}

/* ---------- Steps ---------- */

.steps {
    padding-block: 48px;
    border-top: 1px solid var(--line);
    display: grid;
    gap: 28px;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

.step-number {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 999px;
    border: 1px solid var(--line);
    background: var(--surface);
    font-family: var(--font-body);
    font-size: 12.5px;
    font-weight: 600;
    color: var(--accent);
    margin-bottom: 14px;
}

.step-title {
    font-family: var(--font-body);
    font-size: 15px;
    font-weight: 600;
    margin-bottom: 6px;
}

.step-body {
    color: var(--muted);
    font-size: 14px;
    max-width: 34ch;
}

/* ---------- Feature cards ---------- */

.features {
    padding-block: 48px;
    border-top: 1px solid var(--line);
    display: grid;
    gap: 20px;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}

.feature-card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow-card);
    padding: 24px;
}

.feature-card h3 {
    font-size: 17px;
    margin-bottom: 8px;
}

.feature-card p {
    color: var(--muted);
    font-size: 14px;
}

/* ---------- Dashboard shell ---------- */

.dashboard-shell {
    display: flex;
    min-height: 100vh;
}

.dashboard-sidebar {
    display: flex;
    flex-direction: column;
    width: 240px;
    flex-shrink: 0;
    padding: 24px 16px;
    background: var(--chrome);
    border-right: 1px solid var(--line);
}

.dashboard-sidebar__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.dashboard-nav-toggle {
    display: none;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border: 1px solid var(--line);
    border-radius: var(--radius-input);
    background: transparent;
    color: var(--ink);
}

.dashboard-nav-toggle__icon {
    width: 18px;
    height: 18px;
}

.dashboard-sidebar__brand {
    padding-inline: 8px;
    margin-bottom: 28px;
}

.dashboard-nav {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.dashboard-nav__link {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 8px;
    border-radius: var(--radius-input);
    font-size: 13px;
    font-weight: 600;
    color: var(--muted);
}

.dashboard-nav__link:hover {
    color: var(--ink);
}

.dashboard-nav__link.is-active {
    background: var(--surface);
    color: var(--accent);
}

.dashboard-nav__icon {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}

.dashboard-sidebar__footer {
    margin-top: auto;
    padding-top: 16px;
    border-top: 1px solid var(--line);
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding-inline: 8px;
}

.dashboard-user {
    font-size: 13px;
    font-weight: 600;
    color: var(--ink);
}

.dashboard-main {
    flex: 1;
    min-width: 0;
    padding: 40px 48px;
}

.dashboard-header {
    margin-bottom: 28px;
}

.dashboard-header h1 {
    font-size: 26px;
}

.dashboard-header__sub {
    margin-top: 4px;
    color: var(--muted);
    font-size: 14px;
}

.dashboard-empty {
    color: var(--muted);
    font-size: 14px;
}

[x-cloak] {
    display: none !important;
}

@media (max-width: 780px) {
    .dashboard-shell {
        flex-direction: column;
    }

    /* The wide thumbnail is a desktop affordance; on a phone it just eats the row. */
    .item-row__thumb {
        width: 56px;
        height: 56px;
        font-size: 20px;
    }

    .dashboard-sidebar {
        width: 100%;
        flex-direction: column;
        padding: 12px 16px;
    }

    .dashboard-sidebar__brand {
        margin-bottom: 0;
    }

    .dashboard-nav-toggle {
        display: inline-flex;
    }

    .dashboard-nav {
        display: none;
        flex-direction: column;
        margin-top: 12px;
    }

    .dashboard-nav.is-open {
        display: flex;
    }

    .dashboard-sidebar__footer {
        display: none;
        margin-top: 12px;
        padding-top: 12px;
        border-top: 1px solid var(--line);
        flex-direction: column;
        align-items: flex-start;
    }

    .dashboard-sidebar__footer.is-open {
        display: flex;
    }

    .dashboard-main {
        padding: 24px 20px;
    }
}

/* ---------- List cards ---------- */

.list-grid {
    display: grid;
    gap: 18px;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
}

.list-card {
    display: flex;
    flex-direction: column;
    gap: 9px;
    align-items: flex-start;
    padding: 18px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow-card);
    /* The title's link stretches against the card, not against its own text. */
    position: relative;
}

/* The card's one link, holding the monogram and the title. It carries the card's click target: the
   pseudo-element below covers the whole tile, so everything but the copy button opens the list. */
.list-card__link {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 9px;
}

.list-card__link::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: var(--radius);
}

.list-card__monogram {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: 999px;
    background: var(--wash);
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 18px;
    font-weight: 600;
}

.list-card__title {
    font-size: 17px;
}

.list-card__meta {
    color: var(--muted);
    font-size: 12.5px;
}

/*
  The copy button is the one thing on the card that must not open the list; the shared component
  keeps it above the stretched link, and the card only says where it sits in the column.
*/
.list-card__copy {
    align-self: flex-start;
}

/* The dashed tile that adds something: the first cell of the list grid, and of the item grid. */
.new-card {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 150px;
    background: transparent;
    border: 1px dashed var(--line);
    border-radius: var(--radius);
    color: var(--muted);
    font-family: var(--font-body);
    font-size: 14px;
    font-weight: 600;
    transition: border-color var(--ease), color var(--ease);
}

.new-card:hover {
    border-color: var(--accent);
    color: var(--accent);
}

.new-card:disabled {
    color: var(--faint);
    cursor: not-allowed;
}

.new-card:disabled:hover {
    border-color: var(--line);
    color: var(--faint);
}

/* ---------- Friends ---------- */

/*
  Finding someone, and the lists they are sharing. The search row is one line: the field takes the
  width it can, the button sits at its foot, and whatever the lookup has to say lands right under it.
*/
.find-friend {
    display: flex;
    align-items: flex-end;
    gap: 12px;
    flex-wrap: wrap;
}

.find-friend__field {
    flex: 1 1 260px;
}

.find-friend__note {
    margin: 12px 0 0;
    color: var(--muted);
    font-size: 13.5px;
}

/* The person the search turned up, on a surface of its own so it reads as an answer, not as chrome. */
.find-friend__result {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-top: 12px;
    padding: 14px 16px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-input);
}

.find-friend__name {
    margin: 0;
    font-family: var(--font-display);
    font-size: 16px;
    font-weight: 600;
}

.find-friend__email {
    margin: 3px 0 0;
    color: var(--muted);
    font-size: 12.5px;
}

/*
  One person's lists. A hairline over each block rather than a card around it: the lists are cards
  already, and a surface behind them would be a box inside a box.
*/
.friend {
    margin-top: 28px;
    padding-top: 24px;
    border-top: 1px solid var(--line);
}

.friend__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

.friend__name {
    margin: 0;
    font-family: var(--font-display);
    font-size: 20px;
    font-weight: 600;
}

.friend__meta {
    margin: 4px 0 0;
    color: var(--muted);
    font-size: 13.5px;
}

.friend__lists {
    margin-top: 16px;
}

/* The search row brings no bottom margin of its own; the line that stands in for an empty page does. */
.find-friend + .empty-state {
    padding-top: 28px;
}

/* ---------- Toast ---------- */

.toast-region {
    position: fixed;
    top: 20px;
    right: 20px;
    z-index: 50;
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-width: min(360px, calc(100vw - 40px));
    pointer-events: none;
}

.toast {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px 14px;
    border-radius: var(--radius);
    background: var(--ink);
    color: var(--surface);
    box-shadow: var(--shadow-card);
    font-size: 13px;
    pointer-events: auto;
}

.toast__text {
    flex: 1;
    padding-top: 1px;
}

/* The word that carries the message, in brass: "Reserved" is the point of the toast. */
.toast__text b {
    color: var(--brass);
    font-weight: 600;
}

.toast__close {
    flex: none;
    display: flex;
    padding: 0;
    border: 0;
    background: none;
    color: var(--brass);
    cursor: pointer;
    line-height: 0;
}

.toast__close:hover {
    color: var(--surface);
}

/* ---------- Forms (create / edit) ---------- */

.wishlist-form {
    display: flex;
    flex-direction: column;
    gap: 16px;
    max-width: 640px;
}

.field textarea {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-input);
    padding: 10px 13px;
    font-family: inherit;
    font-size: 14px;
    resize: vertical;
}

.field textarea:focus-visible {
    border-color: var(--accent);
}

.field select {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-input);
    padding: 10px 13px;
    font-family: inherit;
    font-size: 14px;
    color: var(--ink);
}

.field select:focus-visible {
    border-color: var(--accent);
}

.field-row {
    display: flex;
    gap: 16px;
    flex-wrap: wrap;
}

.field-row .field {
    flex: 1;
    min-width: 180px;
}

/*
  A radio group is not a label + input pair, so the avatar picker is a fieldset. Browsers give
  fieldsets their own border, padding and min-width, and a legend is not a flex item, so this
  one stays a plain block and spaces its picker by hand.
*/
.field--group {
    display: block;
    margin: 0;
    padding: 0;
    border: 0;
    min-width: 0;
}

.field--group .emoji-picker {
    margin-top: 6px;
}

.emoji-picker {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.emoji-choice {
    position: relative;
    cursor: pointer;
}

/*
  The radio stays in the tab order and in the accessibility tree; the tile is what the eye
  sees, and what carries the checked and focus states below.
*/
.emoji-choice input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
}

.emoji-choice__tile {
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-input);
    font-size: 20px;
    line-height: 1;
    transition: border-color var(--ease), box-shadow var(--ease);
}

.emoji-choice:hover .emoji-choice__tile {
    border-color: var(--accent);
}

/* The ring from the item card, so "this one is chosen" reads the same everywhere. */
.emoji-choice input:checked + .emoji-choice__tile {
    box-shadow: 0 0 0 2px var(--accent);
}

.emoji-choice input:focus-visible + .emoji-choice__tile {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* "No avatar" — the list keeps falling back to the first letter of its title. */
.emoji-choice__tile--none {
    color: var(--muted);
}

.form-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 20px;
    margin-top: 4px;
}

/* Destructive action on the left, confirm/cancel on the right. */
.form-actions--split {
    justify-content: space-between;
}

.form-actions__group {
    display: flex;
    align-items: center;
    gap: 20px;
}

/* ---------- Tier dots (used inline in copy) ---------- */

.tier-dot {
    display: inline-block;
    width: 7px;
    height: 7px;
    border-radius: 999px;
    margin-right: 6px;
}

.tier-dot--must {
    background: var(--accent);
}

.tier-dot--love {
    background: var(--brass);
}

.tier-dot--nice {
    background: var(--faint);
}

/* ---------- Item list (wishlist show) ---------- */

.item-list {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.item-row {
    display: flex;
    align-items: stretch;
    gap: 18px;
    width: 100%;
    padding: 16px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow-card);
    text-align: left;
    font: inherit;
    color: inherit;
}

.item-row__thumb {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 88px;
    height: 88px;
    flex-shrink: 0;
    align-self: flex-start;
    border-radius: var(--radius-input);
    background: var(--wash);
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 30px;
    font-weight: 600;
}

.item-row__body {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
    flex: 1;
}

.item-row__title,
.item-card__title {
    font-family: var(--font-display);
    font-size: 17px;
    font-weight: 600;
    line-height: 1.3;
}

.item-tier {
    display: inline-flex;
    align-items: center;
    flex-shrink: 0;
    padding: 4px 10px;
    border-radius: 999px;
    border: 1px solid var(--line);
    color: var(--muted);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
}

.item-tier--must {
    color: var(--accent);
    border-color: var(--accent);
}

.item-row__note,
.item-card__note {
    font-style: italic;
    font-size: 14px;
    color: var(--ink);
    border-left: 2px solid var(--brass);
    padding-left: 10px;
}

.item-row__meta,
.item-card__meta {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin-top: auto;
    color: var(--muted);
    font-size: 13px;
}

.item-row__meta b,
.item-card__meta b {
    color: var(--ink);
    font-size: 14.5px;
    font-weight: 600;
}

/*
  Pinned to the right edge on its own, so badges line up down the list regardless of how
  long each title is.
*/
.item-row__tier {
    display: flex;
    align-items: flex-start;
    flex-shrink: 0;
    padding-top: 2px;
}

/*
  Below the breakpoint the card is too narrow to hold a right-hand column, so the badge
  drops back under the text.
*/
@media (max-width: 640px) {
    .item-row {
        flex-wrap: wrap;
    }

    .item-row__tier {
        width: 100%;
        padding-top: 0;
    }
}

/* ---------- Gifter view (share page) ---------- */

/*
  What a guest sees at /g/{wishlist}. Same card vocabulary as the owner list — title, tier
  badge, note and price row come from the rules above — but laid out as a grid, with the
  reservation state showing rather than the edit controls.
*/

/*
  Two columns, so the title block holds the left one and a list avatar can be dropped in
  beside it later without re-laying-out the header. The blurb spans the full width: it is
  prose about the list, not a third column.
*/
.list-head {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    gap: 18px;
    padding-bottom: 24px;
    border-bottom: 1px solid var(--line);
}

/*
  The list avatar — the owner's emoji, or the title's first letter. Same circle language as
  .list-card__monogram on the dashboard, one size up, and clipped so a long string cannot
  push the title off the row.
*/
.list-head__avatar {
    display: grid;
    place-items: center;
    flex: none;
    width: 58px;
    height: 58px;
    border-radius: 999px;
    background: var(--wash);
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 26px;
    font-weight: 600;
    line-height: 1;
    overflow: hidden;
}

.list-head h2 {
    font-size: 26px;
}

.chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 8px;
}

.chip {
    display: inline-flex;
    align-items: center;
    padding: 4px 12px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 999px;
    color: var(--muted);
    font-size: 12.5px;
    font-weight: 600;
}

/* A date inside a fortnight is the one chip that points at something. */
.chip--soon {
    color: var(--accent);
    border-color: var(--accent);
}

.chip.ghosted {
    background: transparent;
}

.blurb {
    grid-column: 1 / -1;
    max-width: 66ch;
    color: var(--muted);
    font-size: 14.5px;
}

/*
  Single column on phones, the design's card grid once there is room for two. No media
  query: auto-fill drops to one column on its own below ~500px.
*/
.item-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(235px, 1fr));
    gap: 22px;
    padding-top: 24px;
}

/* The private way back to a gifter's own reservations, under the grid it belongs to. */
.gifter-manage {
    padding-top: 28px;
}

/*
  A list owner is looking at their own share link, where the cards have no actions they can use.
  One italic line, then the way back: without it the page reads as broken rather than as a preview.
*/
.gifter-own-note {
    padding-top: 24px;
    font-style: italic;
}

/*
  A line of help on the share page: what the gifter's name is for, under the reserve dialog's fields,
  and why the owner is reading their own list. Muted and a size down, so the copy it explains still
  leads and this reads as the footnote to it.
*/
.set-hint {
    color: var(--muted);
    font-size: 12.5px;
}

.item-card {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow-card);
    transition: transform var(--ease);
}

.item-card:hover {
    transform: translateY(-2px);
}

/*
  Photo area. When the item has no image the gap is filled with the merchant's monogram —
  paper, not a missing-image glyph.
*/
.item-card__image {
    position: relative;
    display: grid;
    place-items: center;
    aspect-ratio: 3 / 2;
    background: var(--wash);
}

.item-card__image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.item-card__monogram {
    font-family: var(--font-display);
    font-size: 44px;
    font-weight: 600;
    color: var(--ink);
}

.item-card__body {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 9px;
    padding: 16px;
}

.item-card__badges {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

/*
  Reservation pill. Over a photo it needs its own backing to stay legible, so the placement
  below is what keeps it a pill instead of floating text; the same pill inline in the card
  body reads as a status line.
*/
.reserve-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 999px;
    color: var(--ink);
    font-size: 12.5px;
    font-weight: 600;
}

.reserve-pill::before {
    content: '✓';
    color: var(--accent);
}

.item-card__image>.reserve-pill {
    position: absolute;
    top: 10px;
    left: 10px;
}

.item-card__body>.reserve-pill {
    align-self: flex-start;
}

/*
  Whatever the caller puts over the photo, in the corner opposite the reserve pill: the card's own
  affordances, kept away from the action at the bottom, which is about where the item goes rather
  than what it is.
*/
.item-card__overlay {
    position: absolute;
    top: 8px;
    right: 8px;
    display: flex;
    gap: 4px;
}

/*
  A button that is only an icon, on the same pill language as the reserve pill it sits opposite.
  It carries the surface backing for the same reason that does: the merchant's photo is whatever it
  is, and a bare stroke disappears against half of them.
*/
.btn-icon {
    width: 30px;
    height: 30px;
    padding: 0;
    background: var(--surface);
}

.btn-icon svg {
    width: 16px;
    height: 16px;
}

.btn-icon--danger:hover {
    border-color: var(--danger);
    color: var(--danger);
}

/* Reserved by someone else: the card recedes — dashed border, veiled photo. */
.item-card--reserved {
    border-style: dashed;
}

.item-card--reserved .item-card__image img,
.item-card--reserved .item-card__monogram {
    opacity: .45;
}

/* Reserved by you: the one card on the page that gets a ring. */
.item-card--mine {
    box-shadow: 0 0 0 2px var(--accent), var(--shadow-card);
}

/* ---------- Gifter filters (share page) ---------- */

/*
  One row under the header: a tier, or everything, plus a switch for what is still free. Radios and
  a checkbox rather than buttons, so the browser lights the choice up on the click itself - before
  the request that re-renders the grid has come back.
*/
.wish-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    min-width: 0;
    margin: 0;
    padding: 24px 0 0;
    border: 0;
}

/* A grid brings its own top padding; the line that stands in for it when nothing matches doesn't. */
.wish-filters + .empty-state {
    padding-top: 28px;
}

.filter-chip {
    position: relative;
    cursor: pointer;
}

/* The input keeps its place in the tab order and in the accessibility tree; the face is the chip. */
.filter-chip input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
}

.filter-chip__face {
    display: inline-flex;
    align-items: center;
    padding: 4px 12px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 999px;
    color: var(--muted);
    font-size: 12.5px;
    font-weight: 600;
    transition:
        background var(--ease),
        border-color var(--ease),
        color var(--ease);
}

.filter-chip:hover .filter-chip__face {
    border-color: var(--muted);
}

/* Chosen wears ink, so the accent in this header goes on meaning "the date is close". */
.filter-chip input:checked + .filter-chip__face {
    background: var(--ink);
    border-color: var(--ink);
    color: var(--bg);
}

.filter-chip input:focus-visible + .filter-chip__face {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* ---------- Item dialog ---------- */

dialog.item-dialog {
    width: calc(100% - 40px);
    max-width: 480px;
    padding: 28px;
    background: var(--surface);
    border: none;
    border-radius: var(--radius);
    box-shadow: var(--shadow-card);
}

dialog.item-dialog::backdrop {
    background: rgba(33, 31, 29, .45);
}

dialog.item-dialog .wishlist-form {
    max-width: none;
}

/*
  A dialog scrolls once a phone keyboard shortens the viewport, so its action row sticks to the
  bottom instead of scrolling out of reach.
*/
dialog.item-dialog .form-actions {
    position: sticky;
    bottom: 0;
    padding-top: 12px;
    background: var(--surface);
}

/*
  The live preview of the share header, inside the edit dialog, on the page background it actually
  lives on. Quiet on purpose: it is the list as gifters receive it, not a widget.
*/
.share-preview {
    display: grid;
    gap: 6px;
    padding: 16px;
    background: var(--bg);
    border: 1px solid var(--line);
    border-radius: var(--radius);
}

/* The preview renders the share header itself, so it drops that header's divider and spacing. */
.share-preview .list-head {
    gap: 14px;
    padding-bottom: 0;
    border-bottom: 0;
}

.share-preview .list-head h2 {
    font-size: 19px;
}

.share-preview .list-head__avatar {
    width: 44px;
    height: 44px;
    font-size: 20px;
}

/* ---------- Bookmarklet queue ---------- */

.queue {
    margin-top: 40px;
    padding-top: 28px;
    border-top: 1px solid var(--line);
}

.queue__title {
    font-family: var(--font-display);
    font-size: 20px;
    font-weight: 600;
    margin: 0;
}

.queue__sub {
    margin: 4px 0 0;
    color: var(--muted);
    font-size: 13.5px;
}

/* A row with content and a trailing action. The queue's cards took over the queue, so the trash is
   what uses this now; it stays named for where it came from rather than for its one caller. */
.queue-item {
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
}

/*
  The action at the bottom of a queued card: pick a list, then move it. Pushed to the end of the
  body, so a card carrying a note still lines its action up with the cards either side of it, and
  ruled off from the item above, which the body's own gap would not say.
*/
.assign-form {
    display: grid;
    gap: 8px;
    margin-top: auto;
    padding-top: 14px;
    border-top: 1px solid var(--line);
}

/* The same place on the card, for an owner with no list to file it under yet. */
.assign-hint {
    margin: auto 0 0;
    padding-top: 14px;
    border-top: 1px solid var(--line);
    color: var(--muted);
    font-size: 13px;
}

/* ---------- Save popup ---------- */

.save-header {
    margin-bottom: 20px;
}

.save-header__sub {
    margin: 6px 0 0;
    color: var(--muted);
    font-size: 13.5px;
}

.save-form {
    margin-top: 0;
}

.save-form .form-actions {
    justify-content: flex-end;
}

.save-footer {
    margin-top: 18px;
    color: var(--muted);
    font-size: 13px;
}

.save-footer a {
    color: var(--accent);
    text-decoration: underline;
    text-underline-offset: 3px;
}

/*
  The line that takes the form's place once the save lands. It is doing the form's job - saying the
  thing worked - so it carries a heading's weight rather than body copy's.
*/
.save-success {
    margin: 0;
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 24px;
    font-weight: 600;
    line-height: 1.25;
}

/* ---------- Bookmarklet install page ---------- */

.bookmarklet-step {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow-card);
    padding: 24px;
    margin-bottom: 20px;
}

.bookmarklet-step__body h2 {
    font-family: var(--font-display);
    font-size: 17px;
    font-weight: 600;
    margin: 0 0 6px;
}

.bookmarklet-step__body p {
    margin: 0 0 16px;
    color: var(--muted);
    font-size: 13.5px;
}

.bookmarklet-step__body kbd {
    font-family: var(--font-body);
    font-size: 12px;
    background: var(--wash);
    border: 1px solid var(--line);
    border-radius: 4px;
    padding: 1px 5px;
}

.bookmarklet-link {
    display: inline-flex;
    align-items: center;
    height: 40px;
    padding-inline: 20px;
    border-radius: 999px;
    background: var(--accent);
    color: #fff;
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
    cursor: grab;
}

/* ---------- Trash / destructive actions ---------- */

.dashboard-header__row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

/*
  The avatar and the title block are one item, not two: as separate children of the header row
  they wrap onto their own lines the moment the row runs out of width, which reads as the avatar
  floating above the title. Centred, so a 58px circle sits against a wrapped title or a blurb.
*/
.dashboard-header__heading {
    display: flex;
    align-items: center;
    gap: 18px;
    flex: 1 1 auto;
    min-width: 0;
}

/* The header's quiet actions travel together, so adding one does not spread them across the row. */
.dashboard-header__actions {
    display: flex;
    align-items: center;
    gap: 18px;
}

.btn-danger {
    background: var(--danger);
    color: #fff;
}

.btn-danger:hover {
    background: #8e3a31;
}

.btn-danger-text {
    color: var(--danger);
}

.trash {
    border-top-color: var(--line);
}

.trash-item {
    justify-content: space-between;
}

.trash-item__title {
    font-family: var(--font-display);
    font-size: 15.5px;
    font-weight: 600;
    margin: 0;
    color: var(--muted);
}

.trash-item__meta {
    margin: 3px 0 0;
    color: var(--faint);
    font-size: 12.5px;
}

.dialog-title {
    font-family: var(--font-display);
    font-size: 18px;
    font-weight: 600;
    margin: 0 0 8px;
}

.dialog-body {
    margin: 0 0 20px;
    color: var(--muted);
    font-size: 13.5px;
    line-height: 1.55;
}

.trash-hint {
    margin: 32px 0 0;
    padding-top: 20px;
    border-top: 1px solid var(--line);
    color: var(--muted);
    font-size: 13px;
}

.trash-hint a {
    color: var(--accent);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.empty-state {
    margin: 0;
    color: var(--muted);
    font-size: 13.5px;
}
