/* Related tools — subtle internal links row inside footer (discovery + SEO) */
.related-tools {
    padding-bottom: 7px;
    margin-bottom: 7px;
    border-bottom: 1px solid var(--color-border, #e2e8f0);
    line-height: 1.3;
}
.related-tools-label {
    color: var(--color-text-light, #718096);
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    font-size: 0.7rem;
    margin-right: 12px;
    vertical-align: middle;
}
.related-tools .footer-link {
    color: var(--color-text-medium, #4a5568);
    font-weight: 400;
    font-size: 0.85rem;
    border-bottom: none;
    vertical-align: middle;
}
.related-tools .footer-link:hover {
    color: var(--color-accent, #00a8e8);
    border-bottom: none;
}

/* ============================================================
   GIFT DIARY — Try Swiss Knife
   ── "The tag" ───────────────────────────────────────────────
   Every record in this diary is drawn as the small card tied to
   a present: a stub with a punched hole and a string, a To or a
   From written by hand, the gift itself set in a serif. The
   direction is the whole structure of the tool, so it is the
   loudest thing on the tag — rose for given, eucalyptus for
   received. Plans, which are not yet gifts, take iris.

   The ground is warm paper with a faint line-drawn gift pattern
   showing through, like tissue in a box. The same pattern shows
   stronger through each tag's stub. Nothing on the page is a
   solid block of colour: fills are washes, and the only saturated
   marks are the direction words and the amounts.

   Chrome — header, menu, footer — is the platform standard and
   deliberately plain. Body type is the system stack at 1rem, as on
   every other tool; Newsreader and Caveat carry only the tag.
   ============================================================ */

:root {
    --color-primary:      #2f2a36;   /* ink */
    --color-accent:       #7b4b67;   /* berry — buttons, links, focus */
    --color-accent-hover: #653c55;
    --color-accent-soft:  #f3e9ef;
    --color-accent-line:  #dcc6d3;
    --color-white:        #ffffff;
    --color-background:   #f6f1ea;   /* warm paper ground */
    --color-border:       #e6ddd4;
    --color-border-strong:#cfc3b8;
    --color-text-dark:    #2f2a36;
    --color-text-medium:  #6b6474;   /* 5.0:1 on the ground */
    --color-text-light:   #7d7686;   /* 4.4:1 on white — captions only */
    --color-success:      #2f8f6b;
    --color-warning:      #c28b2c;
    --color-error:        #b3423f;
    --color-danger-light: #fbeeed;
    --color-danger-line:  #efd3d0;

    /* The three directions of a gift. Text weights are AA on the paper. */
    --gd-given:       #a84c66;
    --gd-given-wash:  #fbeef2;
    --gd-given-line:  #e9c3cf;
    --gd-recv:        #367169;
    --gd-recv-wash:   #e9f3f0;
    --gd-recv-line:   #bcd9d2;
    --gd-plan:        #5f4f98;
    --gd-plan-wash:   #efeaf7;
    --gd-plan-line:   #cfc3e6;

    --gd-paper:       #fffdfa;       /* tag stock */
    --gd-string:      #b08d6e;       /* the string through the hole */

    --font:       -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    --font-serif: 'Newsreader', Georgia, 'Times New Roman', serif;
    --font-hand:  'Caveat', 'Segoe Script', 'Bradley Hand', cursive;

    --fs-micro: 0.75rem;
    --fs-xs:    0.8125rem;
    --fs-sm:    0.875rem;
    --fs-base:  1rem;
    --fs-md:    1.0625rem;
    --fs-lg:    1.25rem;

    --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 20px; --s6: 24px; --s8: 32px;

    --shadow-sm: 0 1px 2px rgba(47,42,54,0.06);
    --shadow-md: 0 4px 14px rgba(47,42,54,0.09);
    --shadow-lg: 0 12px 32px rgba(47,42,54,0.16);
    --shadow-tag: 0 1px 2px rgba(47,42,54,0.05), 0 6px 18px rgba(120,86,110,0.10);

    --radius-sm: 6px; --radius-md: 8px; --radius-lg: 12px; --radius-xl: 16px;

    --stub-w: 92px;
    --control-h: 40px;

    /* ── Platform chrome — pinned to the shared TSK values ── */
    --chrome-white: #ffffff;
    --chrome-border: #e0e6ed;
    --chrome-bg: #f5f7fa;
    --chrome-text: #555f6d;
    --chrome-radius: 8px;
}

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

body {
    font-family: var(--font);
    background-color: var(--color-background);
    background-image: url('gift-pattern.webp');
    background-size: 640px auto;
    background-repeat: repeat;
    min-height: 100vh;
    color: var(--color-text-dark);
    font-size: var(--fs-base);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    padding-bottom: env(safe-area-inset-bottom);
}

.hidden { display: none !important; }

.seo-h1, .sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: 0;
    overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

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

button { font-family: inherit; }

/* ─────────────────────────────── HEADER ─────────────────────────────── */
.header {
    width: 100%;
    background-color: #ffffff;
    border-bottom: 1px solid var(--chrome-border);
    position: sticky;
    top: 0;
    z-index: 1000;
    box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
.header-inner {
    max-width: 1080px;
    margin: 0 auto;
    padding: 0.5rem 1.5rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
}
.header-left { display: flex; align-items: center; gap: var(--s3); }
.header-logo-link { display: flex; align-items: center; text-decoration: none; transition: opacity 0.2s ease; }
.header-logo-link:hover { opacity: 0.85; }
.logo-image { height: 36px; width: auto; display: block; flex-shrink: 0; }
.tool-name-btn {
    font-size: 1.5rem; font-weight: 600; color: #1a2332;
    white-space: nowrap; line-height: 1.2; letter-spacing: -0.015em;
    background: none; border: none; padding: 0; cursor: pointer; transition: color 0.15s;
}
.tool-name-btn:hover { color: var(--color-accent); }
.header-icons { display: flex; align-items: center; gap: 8px; flex-shrink: 0; position: relative; }
.header-icon-btn {
    display: flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; padding: 0;
    background: var(--chrome-white); border: 1px solid var(--chrome-border);
    border-radius: var(--chrome-radius); cursor: pointer; transition: all 0.2s ease; color: var(--chrome-text);
}
.header-icon-btn:hover { border-color: var(--color-accent); background: var(--chrome-bg); color: var(--color-accent); }
.header-icon-btn svg { width: 20px; height: 20px; }
.lang-short { font-size: 0.875rem; font-weight: 600; color: var(--chrome-text); letter-spacing: 0.02em; }
.header-icon-btn:hover .lang-short { color: var(--color-accent); }

/* Language dropdown — in the menu; `.active` is the contract with i18n.js */
.language-selector { position: relative; }
.language-dropdown {
    position: absolute; top: calc(100% + 6px); right: 0; min-width: 150px;
    background: var(--chrome-white); border: 1px solid var(--chrome-border);
    border-radius: var(--chrome-radius); box-shadow: var(--shadow-md); overflow: hidden; display: none; z-index: 1100;
}
.language-dropdown.active { display: block; }
.lang-option {
    display: flex; align-items: center; gap: 0.5rem; width: 100%; padding: 0.6rem 1rem;
    background: none; border: none; font-size: 0.875rem; color: var(--color-text-dark); text-align: left; cursor: pointer;
}
.lang-option:hover { background: var(--color-background); }
.lang-option.active { background: var(--color-accent-soft); color: var(--color-accent); }
.lang-check { font-size: 0.75rem; opacity: 0; }
.lang-option.active .lang-check { opacity: 1; }

/* ─────────────────────────────── LAYOUT ─────────────────────────────── */
.container { width: 100%; max-width: 1080px; margin: 0 auto; padding: var(--s5) var(--s5) 0; }
.view { animation: viewIn 0.18s ease; }
@keyframes viewIn { from { opacity: 0; transform: translateY(3px); } to { opacity: 1; transform: none; } }

.info-banner {
    display: flex; align-items: flex-start; gap: var(--s2);
    background: var(--gd-paper); border: 1px solid var(--color-accent-line); border-radius: var(--radius-lg);
    padding: var(--s2) var(--s3); margin-bottom: var(--s4);
    font-size: var(--fs-xs); line-height: 1.45; color: var(--color-text-medium);
}
.info-icon { flex-shrink: 0; font-size: var(--fs-sm); line-height: 1.4; }
.info-text strong { color: var(--color-primary); margin-right: var(--s1); }
.info-close { margin-left: auto; background: none; border: none; font-size: 1.1rem; line-height: 1; color: var(--color-text-light); cursor: pointer; padding: 0 2px; flex-shrink: 0; }
.info-close:hover { color: var(--color-text-dark); }

/* Type roles */
.eyebrow {
    font-size: var(--fs-micro); font-weight: 700; text-transform: uppercase; letter-spacing: 0.12em;
    color: var(--color-text-medium); font-variant-numeric: tabular-nums;
}

/* ─────────────────────────────── PAGE NAV ─────────────────────────────── */
.page-nav {
    display: flex; gap: 4px; padding: 4px; margin-bottom: var(--s4);
    background: rgba(255,253,250,0.85); border: 1px solid var(--color-border); border-radius: 999px;
    width: fit-content; max-width: 100%; overflow-x: auto;
}
.page-nav-btn {
    display: inline-flex; align-items: center; gap: 4px; height: 36px; padding: 0 16px;
    border-radius: 999px; border: none; background: none; font-size: var(--fs-sm); font-weight: 600;
    color: var(--color-text-medium); cursor: pointer; text-decoration: none; white-space: nowrap; transition: background 0.15s, color 0.15s;
}
.page-nav-btn:hover { color: var(--color-text-dark); background: var(--color-background); }
.page-nav-btn.is-on { background: var(--color-primary); color: #fff; }
.page-nav-link { color: var(--gd-plan); }

/* ─────────────────────────────── WELCOME ─────────────────────────────── */
.welcome {
    position: relative;
    display: grid; grid-template-columns: 1fr; gap: var(--s5);
    background: var(--gd-paper); border: 1px solid var(--color-border); border-radius: var(--radius-xl);
    padding: var(--s6); margin-bottom: var(--s4); box-shadow: var(--shadow-sm); overflow: hidden;
}
.welcome-tag {
    position: relative; justify-self: start;
    width: 230px; padding: 26px 18px 16px 30px;
    background: #fff url('gift-pattern-strong.webp') repeat; background-size: 240px auto;
    border: 1px solid var(--color-border); border-radius: 6px 16px 16px 6px;
    clip-path: polygon(0 24%, 10% 0, 100% 0, 100% 100%, 10% 100%, 0 76%);
    box-shadow: var(--shadow-tag); transform: rotate(-3deg);
}
.welcome-tag-hole {
    position: absolute; left: 12px; top: 50%; width: 14px; height: 14px; margin-top: -7px;
    border-radius: 50%; background: var(--color-background); box-shadow: inset 0 1px 2px rgba(0,0,0,0.2), 0 0 0 2px #fff;
}
.welcome-string { position: absolute; left: -46px; top: 14px; width: 70px; height: 40px; color: var(--gd-string); }
.welcome-tag-line { display: flex; align-items: baseline; gap: 8px; line-height: 1.1; }
.welcome-tag-line + .welcome-tag-line { margin-top: 6px; }
.welcome-tag-word { font-size: 10px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--gd-given); min-width: 42px; }
.welcome-tag-line:last-child .welcome-tag-word { color: var(--gd-recv); }
.welcome-tag-hand { font-family: var(--font-hand); font-size: 30px; font-weight: 500; color: var(--color-text-dark); }
.welcome-badge {
    display: inline-flex; align-items: center; margin-bottom: var(--s3); padding: 4px 12px; border-radius: 999px;
    background: var(--color-accent); color: #fff; font-size: var(--fs-micro); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
}
.welcome-title {
    font-family: var(--font-serif); font-size: clamp(1.7rem, 1.2rem + 2vw, 2.4rem); font-weight: 500;
    line-height: 1.15; letter-spacing: -0.01em; color: var(--color-primary); margin-bottom: var(--s3); text-wrap: balance;
}
.welcome-sub { font-size: var(--fs-base); line-height: 1.65; color: var(--color-text-medium); max-width: 64ch; }
.welcome-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: var(--s2); }
.wel-btn {
    display: flex; align-items: center; gap: var(--s3); padding: var(--s3) var(--s4);
    background: var(--color-white); border: 1px solid var(--color-border-strong); border-radius: var(--radius-lg);
    text-align: left; cursor: pointer; transition: border-color 0.15s, background 0.15s; min-height: 60px;
}
.wel-btn:hover { border-color: var(--color-accent); background: var(--color-accent-soft); }
.wel-btn-primary { background: var(--color-accent); border-color: var(--color-accent); color: #fff; }
.wel-btn-primary:hover { background: var(--color-accent-hover); border-color: var(--color-accent-hover); }
.wel-btn-glyph { font-size: 1.4rem; flex-shrink: 0; }
.wel-btn-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.wel-btn-label { font-size: var(--fs-base); font-weight: 600; }
.wel-btn-note { font-size: var(--fs-xs); opacity: 0.8; }
.welcome-samples { display: flex; flex-wrap: wrap; gap: var(--s2); align-items: center; font-size: var(--fs-xs); color: var(--color-text-medium); }
.welcome-samples-label { font-weight: 600; }

/* ── How it works — welcome card only ──────────────────────────────────────────────
   The four verbs in the order they happen, which is not the order of the buttons
   above them and is deliberately not numbered: an occasion is not step one, it is
   optional, and planning happens before a gift exists. Each step draws its own
   connector to the next, so the rail can be dashed while the steps are optional and
   solid from the gift onwards — dashed being this tool's existing mark for something
   that is not a gift yet. Hairlines rather than a border: the welcome card is already
   a bordered box and a second one inside it flattens the hierarchy. */
.welcome-how {
    border-top: 1px solid var(--color-border); border-bottom: 1px solid var(--color-border);
    padding: var(--s4) 0;
}
.how-head { display: flex; align-items: center; gap: var(--s2); margin-bottom: var(--s3); }
.how-head-label { font-size: var(--fs-micro); font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--color-text-light); }
.how-head-rule { flex: 1; height: 1px; background: var(--color-border); }

.how-rail { display: flex; flex-direction: column; gap: 11px; }
.how-step {
    position: relative; display: grid; grid-template-columns: 28px 1fr; gap: 11px; align-items: start;
    width: 100%; padding: 0; margin: 0; background: none; border: none;
    font: inherit; text-align: left; color: inherit; text-decoration: none;
}
/* Scoped to the element, not a class: a step that is only a step — the reaction, which
   has nothing to open before a gift exists — is a plain div and gets no affordance. */
button.how-step, a.how-step { cursor: pointer; }
/* From this node down to the next, across the row gap. */
.how-step::after {
    content: ''; position: absolute; left: 13px; top: 29px; bottom: -11px;
    border-left: 1px solid var(--gd-plan-line);
}
.how-step.is-dashed::after { border-left-style: dashed; }
.how-node {
    position: relative; z-index: 1; width: 28px; height: 28px; border-radius: 50%;
    display: grid; place-items: center; font-size: 14px; line-height: 1;
    background: var(--gd-plan-wash); border: 1px solid var(--gd-plan-line);
}
.how-step.is-optional .how-node { border-style: dashed; }
.how-step.is-given .how-node { background: var(--gd-given-wash); border-color: var(--gd-given-line); }
.how-step.is-recv .how-node { background: var(--gd-recv-wash); border-color: var(--gd-recv-line); }
.how-text { min-width: 0; }
.how-label { display: block; font-size: var(--fs-sm); font-weight: 600; line-height: 1.3; color: var(--color-text-dark); }
.how-note { display: block; font-size: var(--fs-xs); line-height: 1.35; color: var(--color-text-medium); }
/* Said on both optional steps rather than once above them: two eight-character words
   cost no height, and neither leaves the reader working out how far the word reaches. */
.how-optional {
    margin-left: 7px; font-size: 10px; font-weight: 700; letter-spacing: 0.1em;
    text-transform: uppercase; color: var(--gd-plan); opacity: 0.8; white-space: nowrap;
}
button.how-step:hover .how-label, a.how-step:hover .how-label,
.how-step:focus-visible .how-label { text-decoration: underline; text-underline-offset: 2px; }
.how-return { display: grid; grid-template-columns: 28px 1fr; gap: 11px; align-items: center; }
.how-return .how-note { font-style: italic; }
.how-node-return { background: none; border-style: dashed; color: var(--gd-plan); font-size: 15px; }

/* The same rail, rotated. Not at 760px where the card goes two-column: four columns
   are ~170px there, which is fine in English and three lines deep in German. */
@media (min-width: 900px) {
    .how-rail { flex-direction: row; align-items: flex-start; gap: 0; }
    .how-step { grid-template-columns: 1fr; gap: 0; flex: 1 1 0; padding-right: var(--s5); }
    .how-step::after {
        left: 30px; right: 0; top: 14px; bottom: auto;
        border-left-style: none; border-top: 1px solid var(--gd-plan-line);
    }
    .how-step.is-dashed::after { border-left-style: none; border-top-style: dashed; }
    .how-node { margin-bottom: 9px; }
    .how-label { margin-bottom: 2px; }
    .how-return { grid-template-columns: 1fr; gap: 0; flex: 0 0 96px; align-items: start; }
    .how-return .how-node { margin-bottom: 9px; }
}

@media (min-width: 760px) {
    .welcome { grid-template-columns: 250px 1fr; grid-template-areas: "tag copy" "how how" "actions actions" "samples samples"; align-items: center; }
    .welcome-tag { grid-area: tag; margin-left: 30px; }
    .welcome-copy { grid-area: copy; }
    .welcome-how { grid-area: how; }
    .welcome-actions { grid-area: actions; }
    .welcome-samples { grid-area: samples; }
}

/* Section head — used by the planner page, which shares this stylesheet. */
.section-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3); margin-bottom: var(--s2); }

/* ─────────────────────────────── COMING UP / PLANNER RIBBON ───────────────────────────────
   One line above the ledger holding two things: the nearest occasion on the left and the
   state of planning on the right. Occasions beyond the first fold into the drawer behind
   "+N more" — with one occasion, which is the common case, the whole block is 46px. */
.ribbon-wrap { margin-bottom: var(--s4); }
.ribbon {
    display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap;
    min-height: 46px; padding: 5px 14px;
    background: var(--gd-paper); border: 1px solid var(--color-border); border-radius: 999px;
    box-shadow: var(--shadow-sm); font-size: var(--fs-sm);
}
.ribbon-occ {
    display: flex; align-items: baseline; gap: var(--s2); flex: 1 1 auto; min-width: 0;
    background: none; border: none; padding: 4px 0; margin: 0; font: inherit; text-align: left;
    color: inherit; cursor: pointer;
}
.rb-dot {
    flex: none; align-self: center; width: 10px; height: 10px; border-radius: 50%;
    background: var(--occ-wash, var(--gd-plan-wash)); border: 1px solid var(--color-border-strong);
}
.rb-eyebrow { flex: none; font-size: var(--fs-micro); font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; color: var(--color-text-light); }
.rb-name { font-family: var(--font-serif); font-size: 1.05rem; font-weight: 500; color: var(--color-text-dark); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rb-when { flex: none; font-weight: 600; color: var(--gd-given); }
.rb-when.is-window { color: var(--gd-plan); font-weight: 500; }
.rb-meta { flex: none; font-size: var(--fs-xs); color: var(--color-text-medium); white-space: nowrap; }
.rb-act { flex: none; margin-left: 4px; font-size: var(--fs-xs); font-weight: 600; color: var(--gd-plan); white-space: nowrap; }
.rb-act::after { content: ' \203A'; }
.ribbon-occ:hover .rb-name, .ribbon-occ:focus-visible .rb-name { text-decoration: underline; text-underline-offset: 2px; }
.ribbon-occ:hover .rb-act { text-decoration: underline; text-underline-offset: 2px; }

.ribbon-more {
    flex: none; display: inline-flex; align-items: center; gap: 4px;
    font-size: var(--fs-micro); font-weight: 700; font-family: inherit; cursor: pointer;
    color: var(--gd-plan); background: var(--gd-plan-wash); border: 1px solid var(--gd-plan-line);
    border-radius: 999px; padding: 3px 10px;
}
.ribbon-more::after { content: '\2304'; line-height: 1; transform: translateY(-1px); transition: transform 0.15s; }
.ribbon-more[aria-expanded="true"]::after { transform: translateY(1px) rotate(180deg); }
.ribbon-more:hover { border-color: var(--gd-plan); }

/* Shrinkable, so a long plan name ellipsises instead of pushing the planner link off
   the pill. Only the name gives way: everything after it is the part worth keeping. */
.ribbon-plan {
    flex: 0 1 auto; min-width: 0; display: flex; align-items: center; gap: 6px; margin-left: auto;
    padding: 4px 0 4px var(--s3); text-decoration: none; color: inherit;
    border-left: 1px solid var(--color-border); white-space: nowrap;
}
.ribbon-occ.hidden + .ribbon-more + .ribbon-plan { border-left: none; padding-left: 0; margin-left: 0; }
.rb-plan-name { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.rb-plan-name { font-weight: 600; }
.rb-plan-meta { flex: none; font-size: var(--fs-xs); color: var(--color-text-medium); }
.rb-plan-more { flex: none; font-size: var(--fs-micro); font-weight: 700; color: var(--gd-plan); background: var(--gd-plan-wash); border-radius: 999px; padding: 2px 8px; }
.rb-go { flex: none; font-size: var(--fs-xs); font-weight: 600; color: var(--gd-plan); }
.ribbon-plan:hover .rb-go { text-decoration: underline; text-underline-offset: 2px; }
.rb-bar { flex: none; width: 38px; height: 5px; border-radius: 999px; background: rgba(95,79,152,0.16); overflow: hidden; }
.rb-bar span { display: block; height: 100%; border-radius: 999px; background: linear-gradient(90deg, #a294d1, var(--gd-plan)); }

/* The drawer — every occasion after the first, then a way to all of them.
   The pill squares off its bottom corners while this is open so the two read as one card. */
.ribbon-wrap.is-open .ribbon { border-radius: var(--radius-lg) var(--radius-lg) 0 0; }
.ribbon-drawer {
    padding: 4px 15px 6px;
    background: rgba(255,253,250,0.72); border: 1px solid var(--color-border); border-top: none;
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}
.rb-row {
    display: flex; align-items: baseline; gap: var(--s2); width: 100%;
    padding: 8px 2px; background: none; border: none; border-bottom: 1px solid var(--color-border);
    font: inherit; font-size: var(--fs-sm); text-align: left; color: inherit; cursor: pointer;
}
.rb-row:last-child { border-bottom: none; }
.rb-row:hover .rb-name, .rb-row:focus-visible .rb-name { text-decoration: underline; text-underline-offset: 2px; }
.rb-row .rb-name { font-size: 1rem; }
.rb-row .rb-act { margin-left: var(--s2); }
.rb-row .rb-when { margin-left: auto; }
.rb-all { justify-content: flex-end; color: var(--color-accent); font-size: var(--fs-xs); font-weight: 600; }

/* ─────────────────────────────── LEAD ─────────────────────────────── */
/* Count, search and the two actions on one line. The search takes the slack the row used to
   waste between the text and the buttons, and is the only part that flexes — the buttons keep
   their natural width and the text keeps its own. */
.diary-lead { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; margin-bottom: var(--s3); }
.diary-lead-text { flex: 1 1 auto; min-width: 0; }
.lead-title { font-family: var(--font-serif); font-size: 1.5rem; font-weight: 500; line-height: 1.15; color: var(--color-primary); }
.lead-meta { font-size: var(--fs-xs); color: var(--color-text-medium); margin-top: 2px; }
.lead-actions { display: flex; gap: var(--s2); flex-wrap: wrap; flex: none; }

/* ─────────────────────────────── BUTTONS ─────────────────────────────── */
.btn-primary, .btn-outline, .btn-quiet {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    min-height: 44px; padding: 0 18px; border-radius: 999px; font-size: var(--fs-sm); font-weight: 600;
    cursor: pointer; transition: background 0.15s, border-color 0.15s, color 0.15s; white-space: nowrap; text-decoration: none;
}
.btn-primary { background: var(--color-accent); border: 1px solid var(--color-accent); color: #fff; }
.btn-primary:hover { background: var(--color-accent-hover); border-color: var(--color-accent-hover); }
.btn-primary:disabled { opacity: 0.55; cursor: not-allowed; }
.btn-outline { background: var(--gd-paper); border: 1px solid var(--color-border-strong); color: var(--color-text-dark); }
.btn-outline:hover { border-color: var(--color-accent); color: var(--color-accent); }
.btn-quiet { background: none; border: 1px solid transparent; color: var(--color-text-medium); padding: 0 12px; }
.btn-quiet:hover { color: var(--color-text-dark); background: rgba(47,42,54,0.05); }
.btn-danger-quiet { color: var(--color-error); }
.btn-danger-quiet:hover { background: var(--color-danger-light); color: var(--color-error); }
.btn-danger { background: var(--color-error); border-color: var(--color-error); }
.btn-danger:hover { background: #953532; border-color: #953532; }
.btn-plus { font-size: 1.2em; line-height: 1; margin-top: -2px; }
.btn-sm { min-height: 36px; padding: 0 14px; font-size: var(--fs-xs); }
.link-btn {
    background: none; border: none; padding: 0; font-size: var(--fs-xs); font-weight: 600; color: var(--color-accent);
    cursor: pointer; text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--color-accent-line);
}
.link-btn:hover { text-decoration-color: currentColor; }

/* ─────────────────────────────── FORM CONTROLS ─────────────────────────────── */
.input, .select, .search {
    width: 100%; min-height: var(--control-h); padding: 8px 12px;
    background: #fff; border: 1px solid var(--color-border-strong); border-radius: 10px;
    font-family: inherit; font-size: var(--fs-base); color: var(--color-text-dark); line-height: 1.4;
}
.input:focus, .select:focus, .search:focus { outline: 2px solid var(--color-accent); outline-offset: 0; border-color: var(--color-accent); }
textarea.input { resize: vertical; min-height: 64px; }
.select {
    appearance: none; -webkit-appearance: none; padding-right: 30px; cursor: pointer;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%236b6474' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 11px center;
}
.select-block { width: 100%; }
.select-year { max-width: 108px; }
.select-day { max-width: 120px; }
.input-num { max-width: 84px; }   /* three digits and the spinner — the ceiling is 365 */
.month-picker { display: flex; gap: 6px; }
.month-picker .select:first-child { flex: 1; min-width: 0; }
.field-label { display: block; font-size: var(--fs-xs); font-weight: 600; color: var(--color-text-medium); margin: var(--s4) 0 6px; }
.field-label:first-child { margin-top: 0; }
.field-hint { font-size: var(--fs-xs); color: var(--color-text-light); line-height: 1.45; margin-top: 6px; }
/* The row carries the gap its labels cannot: `.field-label:first-child` zeroes the top
   margin, and a label inside a column is always first-child — so without this the row sat
   flush against the input above it. */
.field-row { display: flex; gap: var(--s3); margin-top: var(--s4); }
.field-col { flex: 1; min-width: 0; }
.field-col-day { flex: 0 0 auto; }
/* A label and the shortcut that fills the field under it, on one line. `.field-label` is
   still :first-child inside this row, so its zeroed top margin survives the wrapper. */
.label-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3); }
/* The `Today` shortcut reuses `.link-btn` untouched — only its placement is set here.
   The bottom margin matches `.field-label`'s so the two sit on one baseline. */
.label-row .link-btn { margin-bottom: 6px; white-space: nowrap; }
.qa-settings .link-btn { align-self: center; white-space: nowrap; }
.field-picked { font-size: var(--fs-xs); color: var(--color-text-medium); margin-top: 6px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.check-row { display: flex; align-items: center; gap: 10px; margin-top: var(--s3); font-size: var(--fs-sm); cursor: pointer; min-height: 32px; }
/* A field and the checkbox that qualifies it, side by side. Wraps rather than squeezes, so
   the checkbox drops under the date on a narrow screen instead of clipping its label. */
.date-row { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
.date-row .check-row { margin-top: 0; }
.check-row input { width: 18px; height: 18px; accent-color: var(--color-accent); }
/* dd/mm/yyyy and the calendar button — a full-width date input is mostly empty. */
.input-date { width: auto; flex: 0 0 auto; }
.lead-row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: var(--s4); }
.lead-row .field-label { margin: 0; }
.lead-unit { font-size: var(--fs-xs); color: var(--color-text-medium); white-space: nowrap; }
.more-fields { margin-top: var(--s4); }
.more-fields summary { font-size: var(--fs-xs); font-weight: 600; color: var(--color-accent); cursor: pointer; }

/* Segmented control */
.seg { display: inline-flex; padding: 3px; background: rgba(47,42,54,0.06); border-radius: 999px; gap: 2px; }
.seg-wide { display: flex; width: 100%; }
.seg-wide .seg-btn { flex: 1; }
.seg-btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 4px;
    min-height: 34px; padding: 0 14px; border-radius: 999px; border: none; background: none;
    font-size: var(--fs-xs); font-weight: 600; color: var(--color-text-medium); cursor: pointer; white-space: nowrap; transition: background 0.15s, color 0.15s;
}
.seg-btn:hover { color: var(--color-text-dark); }
.seg-btn.is-on { background: #fff; color: var(--color-text-dark); box-shadow: var(--shadow-sm); }
.seg-btn.seg-given.is-on { background: var(--gd-given); color: #fff; }
.seg-btn.seg-recv.is-on { background: var(--gd-recv); color: #fff; }
.seg-arrow { font-size: 1.05em; }

/* Chips */
.chip-set { display: flex; flex-wrap: wrap; gap: 6px; }
/* A list of chips or links sitting directly above the row that adds to it: without this the
   last chip touches the input. Adjacent-sibling and `:not(:empty)` on purpose — a list
   followed by the next field's own label already has that label's margin, and an empty list
   has nothing to be spaced away from. */
.chip-set:not(:empty) + .media-add,
.chip-set:not(:empty) + .ta-wrap,
.media-list:not(:empty) + .media-add { margin-top: var(--s3); }
.chip {
    display: inline-flex; align-items: center; gap: 4px; min-height: 30px; padding: 3px 11px; border-radius: 999px;
    background: rgba(47,42,54,0.06); font-size: var(--fs-micro); font-weight: 500; color: var(--color-text-medium); white-space: nowrap;
}
.chip-btn {
    display: inline-flex; align-items: center; gap: 6px; min-height: 36px; padding: 0 13px; border-radius: 999px;
    border: 1px solid var(--color-border-strong); background: #fff; font-size: var(--fs-xs); color: var(--color-text-dark); cursor: pointer;
}
.chip-btn:hover { border-color: var(--color-accent); }
.chip-btn.is-on { background: var(--color-accent); border-color: var(--color-accent); color: #fff; }
.chip-btn .chip-x { color: inherit; opacity: 0.7; font-size: 1.05em; line-height: 1; }
.chip-btn.is-custom { border-style: dashed; }

/* Type-ahead */
.ta-wrap { position: relative; }
.ta-list {
    display: none; position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 20;
    background: #fff; border: 1px solid var(--color-border-strong); border-radius: 12px; box-shadow: var(--shadow-md);
    max-height: 260px; overflow-y: auto; padding: 4px;
}
.ta-list.is-open { display: block; }
.ta-row {
    display: flex; align-items: center; gap: 10px; width: 100%; min-height: 44px; padding: 6px 10px;
    border: none; border-radius: 9px; background: none; text-align: left; cursor: pointer; font-size: var(--fs-sm); color: var(--color-text-dark);
}
.ta-row:hover, .ta-row.is-active { background: var(--color-accent-soft); }
.ta-avatar {
    flex-shrink: 0; width: 28px; height: 28px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
    font-size: 11px; font-weight: 700; color: hsl(var(--hue, 200) 35% 32%); background: hsl(var(--hue, 200) 55% 90%);
}
.ta-avatar-new { background: var(--color-accent); color: #fff; font-size: 16px; }
.ta-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ta-badge { font-size: 10px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--gd-plan); background: var(--gd-plan-wash); border-radius: 999px; padding: 2px 7px; }
.ta-rel { font-size: var(--fs-micro); color: var(--color-text-light); }
.ta-create { color: var(--color-accent); font-weight: 600; }

/* Reaction row */
.reaction-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.reaction-btn {
    display: flex; flex-direction: column; align-items: center; gap: 2px; min-height: 58px; padding: 6px 4px;
    border: 1px solid var(--color-border-strong); border-radius: 12px; background: #fff; cursor: pointer; font-size: var(--fs-micro); color: var(--color-text-medium);
}
.reaction-btn .rx-emoji { font-size: 1.3rem; line-height: 1; }
.reaction-btn.is-on { border-color: var(--color-accent); background: var(--color-accent-soft); color: var(--color-accent); font-weight: 600; }

/* Media links (editor) */
.media-list { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 8px; }
.media-list:empty { display: none; }
.media-item { position: relative; width: 84px; }
.media-thumb {
    display: block; width: 84px; height: 84px; border-radius: 10px; overflow: hidden; background: var(--color-background);
    border: 1px solid var(--color-border); cursor: pointer; padding: 0;
}
.media-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.media-thumb .media-ph { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; font-size: 1.4rem; }
.media-thumb.is-broken { border-color: var(--color-danger-line); }
.media-remove {
    position: absolute; top: -6px; right: -6px; width: 24px; height: 24px; border-radius: 50%; border: none;
    background: var(--color-text-dark); color: #fff; font-size: 14px; line-height: 1; cursor: pointer;
}
.media-add { display: flex; gap: 6px; }
.media-add .input { flex: 1; min-width: 0; }
.media-status { font-size: var(--fs-xs); margin-top: 6px; }
.media-status.ok { color: var(--color-success); }
.media-status.err { color: var(--color-error); }

/* ─────────────────────────────── QUICK ADD ─────────────────────────────── */
.quick-add {
    background: var(--gd-paper); border: 1px solid var(--gd-plan-line); border-radius: var(--radius-xl);
    padding: var(--s4); margin-bottom: var(--s4); box-shadow: var(--shadow-sm);
}
.qa-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s3); margin-bottom: var(--s3); }
.qa-sub { font-size: var(--fs-xs); color: var(--color-text-medium); line-height: 1.45; margin-top: 4px; max-width: 60ch; }
.qa-settings { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: var(--s3); }
.qa-settings .select { width: auto; min-width: 150px; }
.qa-settings .month-picker { flex: 1; min-width: 190px; }
.qa-row { display: grid; grid-template-columns: 1.2fr 1.4fr 88px auto; gap: 6px; align-items: start; }
.qa-add { min-height: var(--control-h); padding: 0 16px; }
.qa-foot { display: flex; justify-content: space-between; gap: var(--s3); margin-top: 8px; font-size: var(--fs-xs); color: var(--color-text-medium); }
.qa-count { font-weight: 600; }
.qa-recent { margin-top: 8px; border-top: 1px solid var(--color-border); }
.qa-recent:empty { display: none; }
.qa-recent-row { display: flex; align-items: center; gap: 8px; min-height: 36px; font-size: var(--fs-xs); border-bottom: 1px dashed var(--color-border); }
.qa-recent-row .qr-name { font-weight: 600; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.qa-recent-row .qr-title { flex: 1.3; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--color-text-medium); }
.qa-recent-row .qr-amount { font-variant-numeric: tabular-nums; font-weight: 600; }
.qa-recent-row .link-btn { font-size: var(--fs-micro); }

/* ─────────────────────────────── TOOLBAR ─────────────────────────────── */
.toolbar { margin-bottom: var(--s3); }
/* Lives inside `.diary-lead` — a search field is only ever a name or two wide, so it is
   capped rather than stretched. It reclaims its full-width line below 768px, where the row
   cannot hold four things. */
.search-row { display: flex; align-items: center; gap: 8px; flex: 0 1 330px; min-width: 190px; }
.search-wrap { position: relative; flex: 1; min-width: 0; }
.search-glyph { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); color: var(--color-text-light); font-size: 1.1rem; pointer-events: none; }
.search { padding-left: 38px; border-radius: 999px; min-height: 44px; background: rgba(255,255,255,0.9); }
.filters { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
/* The four dropdowns and the thank-you toggle. `flex-basis: 100%` so they take a line of
   their own under the direction switch rather than trailing off the end of it. */
.filters-rest { display: none; flex: 1 1 100%; flex-wrap: wrap; gap: 6px; align-items: center; }
.toolbar.filters-open .filters-rest { display: flex; }
/* Same shape as a `.select-chip` so the row reads as one set of controls, and the same
   funnel glyph as the mobile fold so the two are recognisably one idea. */
.filter-more {
    display: inline-flex; align-items: center; gap: 6px; min-height: 34px; padding: 0 12px;
    font: inherit; font-size: var(--fs-xs); font-weight: 500; color: var(--color-text-medium);
    background: rgba(255,255,255,0.9); border: 1px solid var(--color-border-strong);
    border-radius: 999px; cursor: pointer; white-space: nowrap;
}
.filter-more svg { width: 15px; height: 15px; }
.filter-more:hover { border-color: var(--color-accent-line); color: var(--color-accent); }
.filter-more[aria-expanded="true"] { background: var(--color-accent-soft); border-color: var(--color-accent-line); color: var(--color-accent); }
/* Inline here rather than a corner dot on an icon — no cut-out ring needed. */
.filter-more .filter-btn-count { position: static; border: none; height: 16px; min-width: 16px; }
.filter-more[aria-expanded="true"] .filter-btn-count { background: var(--color-accent); color: #fff; }

/* The filter fold — narrow screens only. Five wrapped rows of chips push the first gift
   below the fold, so there they collapse behind this button and the count carries what
   is hidden: a filtered ledger must never read as a short one. */
.filter-btn {
    display: none; position: relative; flex: none; width: 44px; height: 44px;
    align-items: center; justify-content: center; cursor: pointer;
    background: rgba(255,255,255,0.9); border: 1px solid var(--color-border-strong);
    border-radius: 999px; color: var(--color-text-medium);
}
.filter-btn svg { width: 20px; height: 20px; }
.filter-btn[aria-expanded="true"] { background: var(--color-accent-soft); border-color: var(--color-accent-line); color: var(--color-accent); }
.filter-btn.is-on { background: var(--color-accent); border-color: var(--color-accent); color: #fff; }
.filter-btn-count {
    position: absolute; top: -2px; right: -2px; min-width: 18px; height: 18px; padding: 0 4px;
    display: flex; align-items: center; justify-content: center;
    background: var(--color-accent); color: #fff; border: 2px solid var(--color-background);
    border-radius: 999px; font-size: 0.65rem; font-weight: 700; line-height: 1;
}
.filter-btn-count:empty { display: none; }
.filter-btn.is-on .filter-btn-count { background: var(--gd-paper); color: var(--color-accent); }
.seg-sm .seg-btn { min-height: 32px; padding: 0 12px; }
.select-chip { width: auto; min-height: 36px; padding: 4px 28px 4px 12px; border-radius: 999px; font-size: var(--fs-xs); font-weight: 500; color: var(--color-text-medium); background-color: #fff; max-width: 180px; text-overflow: ellipsis; }
.select-chip.is-on { border-color: var(--color-accent); color: var(--color-accent); font-weight: 600; }
.chip-toggle {
    display: inline-flex; align-items: center; gap: 5px; min-height: 36px; padding: 0 12px; border-radius: 999px;
    border: 1px solid var(--color-border-strong); background: #fff; font-size: var(--fs-xs); font-weight: 500; color: var(--color-text-medium); cursor: pointer;
}
.chip-toggle[aria-pressed="true"] { background: var(--gd-recv); border-color: var(--gd-recv); color: #fff; }
.chip-count { font-weight: 700; }
.chip-count:empty { display: none; }

/* ─────────────────────────────── THE LEDGER ─────────────────────────────── */
.ledger { display: flex; flex-direction: column; gap: 12px; }
.month-divider { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
.month-divider:first-child { margin-top: 0; }
.month-divider .eyebrow { color: var(--color-text-medium); }
.month-divider .rule { flex: 1; height: 1px; background: linear-gradient(90deg, var(--color-border-strong), transparent); }
.month-divider .count { font-size: var(--fs-micro); color: var(--color-text-light); font-variant-numeric: tabular-nums; }
.ledger-empty {
    padding: var(--s6) var(--s4); text-align: center; color: var(--color-text-medium); font-size: var(--fs-sm);
    background: rgba(255,253,250,0.7); border: 1px dashed var(--color-border-strong); border-radius: var(--radius-xl);
}
.ledger-empty .ledger-empty-title { font-family: var(--font-serif); font-size: 1.25rem; color: var(--color-text-dark); margin-bottom: 4px; }
.ledger-more { display: flex; justify-content: center; padding: var(--s3) 0; }
@media (min-width: 900px) {
    .ledger { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 14px; align-items: start; }
    .month-divider, .ledger-empty { grid-column: 1 / -1; }
}

/* ── The gift tag ──
   A stub on the left holds the hole, the string, the direction word, the first
   photo when the gift has one, and the date; the body holds the name
   (handwritten), the gift with its amount, and the details.
   Direction is a custom property so one rule set serves both colours. */
.gift-tag {
    --dir: var(--gd-given); --dir-wash: var(--gd-given-wash); --dir-line: var(--gd-given-line);
    position: relative; display: grid; grid-template-columns: var(--stub-w) minmax(0, 1fr);
    background: var(--gd-paper); border: 1px solid var(--color-border); border-radius: 14px;
    box-shadow: var(--shadow-tag); cursor: pointer; transition: transform 0.15s, box-shadow 0.15s;
}
.gift-tag:hover { transform: translateY(-1px); box-shadow: var(--shadow-md); }
.gift-tag.is-received { --dir: var(--gd-recv); --dir-wash: var(--gd-recv-wash); --dir-line: var(--gd-recv-line); }
.gift-tag.is-group::before {
    /* a second tag peeking out behind: the gift went to more than one person */
    content: ''; position: absolute; inset: 6px -5px -5px 7px; z-index: -1;
    background: var(--dir-wash); border: 1px solid var(--dir-line); border-radius: 14px;
}
.tag-stub {
    position: relative; overflow: hidden; border-radius: 13px 0 0 13px; background: var(--dir-wash);
    padding: 30px 8px 10px 12px; display: flex; flex-direction: column; min-width: 0;
}
.tag-stub::before {
    content: ''; position: absolute; inset: 0; background: url('gift-pattern-strong.webp') repeat; background-size: 230px auto; opacity: 0.85; pointer-events: none;
}
.tag-stub > * { position: relative; }
.tag-hole {
    position: absolute; top: 9px; left: 9px; width: 13px; height: 13px; border-radius: 50%;
    background: var(--color-background); box-shadow: inset 0 1px 2px rgba(0,0,0,0.22), 0 0 0 2px rgba(255,255,255,0.85);
}
.tag-string { position: absolute; top: -13px; left: -9px; width: 46px; height: 32px; color: var(--gd-string); pointer-events: none; }
/* The stub clips, so the direction word must fit inside it in all four languages. The long
   one is DE "GESCHENKT", not EN — with the "← " / " →" arrows it needed 80-85px against a
   72px stub and was cut off mid-glyph at the body's dashed edge, at every width including
   desktop. The arrows went rather than the word: direction is already carried three other
   ways — the stub's wash (rose given, eucalyptus received), the word itself, and the
   handwritten To/From in the body — so they were the one signal that could be spared.
   Re-measure all four languages before touching these numbers. */
.tag-dir { font-size: 10px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--dir); white-space: nowrap; }
/* The date is the stub's floor, so it takes the `auto` margin the amount used to hold.
   Everything above it — the direction word, and the photo when there is one — stacks from
   the top, and a card with no photo is exactly what it was before. */
.tag-date { font-size: 11px; color: var(--color-text-medium); margin-top: auto; padding-top: 8px; line-height: 1.2; }
/* A snapshot pinned to the tag: white mount, full stub width, landscape crop. Rendered only
   when the gift carries media — see tagHtml().

   The HEIGHT IS FIXED, and that is the whole point of the rule. A square frame (72px on
   desktop) made the stub taller than the body on most cards, so the photo — not the record —
   decided the card's height: 160px against 115px for the same card without one, and a
   ledger where the cards with photos towered over the rest. At 48px the stub only outgrows
   a minimal body by ~16px, and on any card with a thank-you row or a wrapped title it costs
   nothing at all. Raising it means measuring both again. */
.tag-photo {
    display: block; width: 100%; height: 48px; margin-top: 9px; padding: 3px;
    position: relative; cursor: zoom-in; background: #fff; border: 1px solid var(--color-border);
    border-radius: 8px; box-shadow: 0 1px 3px rgba(26,35,50,0.14);
}
.tag-photo:hover { border-color: var(--dir-line); box-shadow: 0 2px 7px rgba(26,35,50,0.2); }
.tag-photo-img {
    display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;
    overflow: hidden; border-radius: 5px; background: var(--color-background); font-size: 14px;
}
.tag-photo-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* "+2" for the ones not shown. The frame opens the first; the rest are in the editor. */
.tag-photo-more {
    position: absolute; right: -3px; bottom: -3px; min-width: 18px; padding: 0 4px;
    border-radius: 999px; background: var(--color-text-dark); color: #fff;
    font-size: 9px; font-weight: 700; line-height: 18px; text-align: center;
}
.tag-body { padding: 11px 13px 11px 14px; border-left: 1.5px dashed var(--dir-line); min-width: 0; display: flex; flex-direction: column; gap: 6px; }
/* Title and amount share a baseline; the title wraps under a fixed-width amount. */
.tag-headline { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; min-width: 0; }
.tag-amount { flex: none; font-size: 1.1rem; font-weight: 600; line-height: 1.2; color: var(--color-text-dark); font-variant-numeric: tabular-nums; white-space: nowrap; }
.tag-line { display: flex; align-items: baseline; gap: 7px; min-width: 0; }
.tag-to { font-size: 10px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--color-text-light); flex-shrink: 0; }
/* The `padding-right`/negative-margin pair on every handwritten name is not decoration.
   Caveat's terminal strokes paint past the glyph's advance width, and `overflow: hidden`
   clips at the padding box — so "Chen Wei" lost the tail of its "i" while the browser
   reported no overflow at all (`scrollWidth === clientWidth`, because that measures advance
   width, not ink). The padding gives the overhang room inside the clip; the equal negative
   margin gives the space back, so nothing moves. Any hand-font element that clips needs
   both — see `.person-name`, `.lb-caption`, and `.entry-name` in plan.css. */
.tag-name { font-family: var(--font-hand); font-size: 1.55rem; font-weight: 500; line-height: 1; color: var(--color-text-dark); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding-right: 0.2em; margin-right: -0.2em; }
.tag-group { font-size: 9px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--gd-plan); background: var(--gd-plan-wash); border-radius: 999px; padding: 2px 6px; flex-shrink: 0; align-self: center; }
.tag-title { flex: 1 1 auto; min-width: 0; font-family: var(--font-serif); font-size: 1.1rem; font-weight: 500; line-height: 1.25; color: var(--color-text-dark); overflow-wrap: anywhere; }
.tag-meta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: var(--fs-micro); color: var(--color-text-medium); }
/* `flex-basis: auto`, not `0` — reversed September 2026. A zero basis guaranteed the row
   never broke, and the occasion paid for it: flex shrank the only flexible item and the name
   was ellipsised away to "Birthday ·…" on a phone and in the 2-column grid at 1024px, which
   is the half nobody needs. With `auto`, flex lays the line out from each item's
   *hypothetical* size and gives the occasion a line of its own when it genuinely cannot
   share one — a short name still sits inline and the card keeps its height. The name is
   never cut while there is a line it could have. */
.tag-meta > .chip { flex: none; }
.tag-event { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The reaction chip is the button that sets it — see rxButtonHtml(). Unset, it is a quiet
   outline face rather than four emoji on every card in the ledger; the tool's saturated
   marks are meant to be the direction words and the amounts, nothing else. */
.tag-rx {
    margin-left: auto; display: inline-flex; align-items: center; gap: 4px;
    font: inherit; font-size: 11px; font-weight: 600; white-space: nowrap; cursor: pointer;
    color: var(--dir); background: var(--dir-wash); border: 1px solid transparent;
    border-radius: 999px; padding: 4px 8px;
}
.tag-rx:hover { border-color: var(--dir-line); }
.tag-rx-empty { padding: 3px; background: none; color: var(--color-text-light); opacity: 0.5; }
.tag-rx-empty svg { width: 18px; height: 18px; display: block; }
.tag-rx-empty:hover { opacity: 1; color: var(--dir); border-color: transparent; }
.tag-rx[aria-expanded="true"] { opacity: 1; color: var(--dir); background: var(--dir-wash); border-color: var(--dir-line); }
.tag-rx-picker { display: flex; gap: 6px; flex-wrap: wrap; }
.rx-pick {
    display: inline-flex; align-items: center; gap: 5px; min-height: 34px; padding: 0 11px;
    font: inherit; font-size: var(--fs-micro); font-weight: 500; color: var(--color-text-medium);
    background: #fff; border: 1px solid var(--color-border-strong); border-radius: 999px; cursor: pointer;
}
.rx-pick .rx-emoji { font-size: 1rem; line-height: 1; }
.rx-pick:hover { border-color: var(--dir); color: var(--dir); }
.rx-pick.is-on { background: var(--dir-wash); border-color: var(--dir); color: var(--dir); font-weight: 600; }
.tag-foot { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding-top: 6px; border-top: 1px solid var(--color-border); font-size: var(--fs-micro); color: var(--color-text-medium); }
.tag-foot:empty { display: none; }
/* Both live on `.tag-meta` — see tagHtml(). `flex: none` so the occasion, not the thank-you,
   is what gives way when the row is tight. */
.tag-thanked { flex: none; color: var(--gd-recv); font-weight: 600; white-space: nowrap; }
/* A link, not a capsule. The capsule was a 32px control in a row of its own, which is what
   made every unthanked card taller than a given one. The vertical padding is cancelled by an
   equal negative margin: the tap area stays ~28px while the row's height is still set by the
   reaction chip, so turning a card thanked never reflows the ledger. */
.tag-thank-btn {
    flex: none; padding: 6px 2px; margin: -6px 0; border: none; background: none;
    font: inherit; font-size: var(--fs-micro); font-weight: 600; color: var(--gd-recv);
    cursor: pointer; white-space: nowrap;
    text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--gd-recv-line);
}
.tag-thank-btn:hover { text-decoration-color: currentColor; }
.tag-note { font-size: var(--fs-micro); color: var(--color-text-medium); font-style: italic; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }

/* ─────────────────────────────── PEOPLE ─────────────────────────────── */
.view-head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--s3); flex-wrap: wrap; margin-bottom: var(--s4); }
.view-title { font-family: var(--font-serif); font-size: 1.6rem; font-weight: 500; line-height: 1.15; color: var(--color-primary); }
.view-sub { font-size: var(--fs-xs); color: var(--color-text-medium); margin-top: 3px; max-width: 64ch; line-height: 1.5; }
.view-actions { display: flex; gap: var(--s2); flex-wrap: wrap; }
.people-list { display: flex; flex-direction: column; gap: 8px; }
.person-row {
    display: grid; grid-template-columns: 40px minmax(0, 1fr) auto auto; align-items: center; gap: 12px;
    padding: 10px 12px 10px 12px; background: var(--gd-paper); border: 1px solid var(--color-border); border-radius: 14px;
    cursor: pointer; transition: border-color 0.15s, transform 0.15s; text-align: left; width: 100%;
}
.person-row:hover { border-color: var(--color-accent-line); transform: translateY(-1px); }
.avatar {
    width: 40px; height: 40px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
    font-size: 13px; font-weight: 700; color: hsl(var(--hue, 200) 35% 32%); background: hsl(var(--hue, 200) 55% 90%); flex-shrink: 0;
}
.avatar-group { border-radius: 12px; }
.person-main { min-width: 0; }
.person-name { font-family: var(--font-hand); font-size: 1.5rem; line-height: 1; color: var(--color-text-dark); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding-right: 0.2em; margin-right: -0.2em; }
.person-sub { font-size: var(--fs-micro); color: var(--color-text-medium); margin-top: 3px; display: flex; gap: 8px; flex-wrap: wrap; }
.person-counts { display: flex; flex-direction: column; gap: 2px; align-items: flex-end; font-size: var(--fs-micro); font-weight: 600; white-space: nowrap; }
.count-given { color: var(--gd-given); }
.count-recv { color: var(--gd-recv); }
.person-edit {
    width: 40px; height: 40px; border-radius: 50%; border: 1px solid var(--color-border-strong); background: #fff;
    color: var(--color-text-medium); cursor: pointer; font-size: 1rem; display: inline-flex; align-items: center; justify-content: center;
}
.person-edit:hover { border-color: var(--color-accent); color: var(--color-accent); }
.person-row.is-hidden { opacity: 0.7; }
.hidden-people { margin-top: var(--s4); }
.hidden-people summary { font-size: var(--fs-xs); font-weight: 600; color: var(--color-text-medium); cursor: pointer; margin-bottom: 8px; }
@media (min-width: 900px) {
    .people-list { display: grid; grid-template-columns: 1fr 1fr; }
}

/* ─────────────────────────────── EVENTS ─────────────────────────────── */
.event-list { display: flex; flex-direction: column; gap: 8px; }
.event-row {
    display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: 12px;
    padding: 10px 12px 10px 14px; background: var(--gd-paper); border: 1px solid var(--color-border); border-radius: 14px;
    cursor: pointer; text-align: left; width: 100%; transition: border-color 0.15s, transform 0.15s; position: relative; overflow: hidden;
}
.event-row::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 5px; background: var(--occ-wash, var(--gd-plan-wash)); }
.event-row:hover { border-color: var(--color-accent-line); transform: translateY(-1px); }
/* `evt_none` is not editable — `renderEvents()` withholds the pencil, and it cannot be
   renamed, dated or deleted — but it *is* clickable, and opens the report for every gift
   filed under no occasion. So the dashed border and paler fill stay (it is not a
   user-made occasion) while the pointer and the hover lift do not: it inherits both from
   `.event-row`. Marking it visually distinct is right; making it feel dead is not. */
.event-row.is-system { background: rgba(255,253,250,0.6); border-style: dashed; }
.event-main { min-width: 0; }
.event-name { font-family: var(--font-serif); font-size: 1.15rem; font-weight: 500; line-height: 1.2; color: var(--color-text-dark); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.event-sub { font-size: var(--fs-micro); color: var(--color-text-medium); margin-top: 3px; display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.event-cat { font-weight: 600; color: var(--gd-plan); }
.event-count { font-size: var(--fs-micro); font-weight: 600; color: var(--color-text-medium); white-space: nowrap; text-align: right; }
.event-pin { font-size: var(--fs-micro); font-weight: 600; color: var(--gd-plan); }
@media (min-width: 900px) {
    .event-list { display: grid; grid-template-columns: 1fr 1fr; }
}

/* ─────────────────────────────── REPORTS ─────────────────────────────── */
.back-link {
    display: inline-flex; align-items: center; gap: 6px; min-height: 40px; margin-bottom: var(--s3);
    background: none; border: none; font-size: var(--fs-sm); font-weight: 600; color: var(--color-text-medium); cursor: pointer; padding: 0;
}
.back-link:hover { color: var(--color-accent); }
.report-masthead {
    background: var(--gd-paper); border: 1px solid var(--color-border); border-radius: 18px; overflow: hidden;
    box-shadow: var(--shadow-sm); margin-bottom: var(--s4);
}
.masthead-band { height: 58px; position: relative; background: linear-gradient(135deg, var(--gd-given-wash), var(--gd-plan-wash) 55%, var(--gd-recv-wash)); }
.masthead-band::after { content: ''; position: absolute; inset: 0; background: url('gift-pattern-strong.webp') repeat; background-size: 300px auto; opacity: 0.8; }
.masthead-body { padding: 14px 18px 18px; }
.masthead-top { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
/* `flex-basis: 0`, and it has to be 0 rather than `auto`: flex breaks lines from each item's
   *hypothetical* size, so with `auto` a long name makes this block wider than the row and it
   wraps whole — stranding the avatar alone on the line above. With a zero basis it stays
   beside the avatar and the name wraps inside it, which is what it should have done. (The
   opposite call to `.tag-event`, which wants the line to break; same mechanism, and it is
   the basis that decides which you get.) */
.masthead-id { flex: 1 1 0; min-width: 0; }
.masthead-name { font-family: var(--font-serif); font-size: 1.8rem; font-weight: 500; line-height: 1.05; color: var(--color-text-dark); }
.masthead-meta { font-size: var(--fs-xs); color: var(--color-text-medium); display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.masthead-actions { margin-left: auto; display: flex; gap: 6px; }
.stat-tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 14px; }
.stat-tile { border-radius: 14px; padding: 11px 13px; position: relative; overflow: hidden; }
.stat-tile.is-given { background: var(--gd-given-wash); }
.stat-tile.is-received { background: var(--gd-recv-wash); }
.stat-tile::after { content: ''; position: absolute; inset: 0; background: url('gift-pattern-strong.webp') repeat; background-size: 200px auto; opacity: 0.55; pointer-events: none; }
.stat-tile > * { position: relative; }
.stat-dir { font-size: 10px; font-weight: 700; letter-spacing: 0.13em; text-transform: uppercase; }
.stat-tile.is-given .stat-dir { color: var(--gd-given); }
.stat-tile.is-received .stat-dir { color: var(--gd-recv); }
.stat-count { display: flex; align-items: baseline; gap: 6px; margin-top: 8px; }
.stat-count b { font-size: 1.5rem; font-weight: 600; line-height: 1; font-variant-numeric: tabular-nums; }
.stat-count span { font-size: var(--fs-micro); color: var(--color-text-medium); }
.stat-total { font-size: var(--fs-sm); font-weight: 500; color: var(--color-text-medium); margin-top: 6px; font-variant-numeric: tabular-nums; }
.masthead-note { font-family: var(--font-hand); font-size: 1.1rem; color: var(--color-text-light); margin-top: 12px; }
.masthead-also { font-size: var(--fs-xs); color: var(--color-text-medium); margin-top: 10px; }
.masthead-also .link-btn { font-size: inherit; }
.masthead-types { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; align-items: center; }
.masthead-types .eyebrow { margin-right: 4px; }
.report-columns { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; align-items: start; }
.report-col { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.col-head { font-size: 10px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; text-align: center; border-radius: 999px; padding: 7px 10px; }
.col-head.is-given { color: var(--gd-given); background: var(--gd-given-wash); }
.col-head.is-received { color: var(--gd-recv); background: var(--gd-recv-wash); }
.mini-tag {
    background: var(--gd-paper); border: 1px solid var(--color-border); border-radius: 12px; padding: 9px 10px 9px 12px;
    box-shadow: var(--shadow-sm); cursor: pointer; text-align: left; width: 100%; position: relative; overflow: hidden; transition: border-color 0.15s;
}
.mini-tag::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: var(--dir-line, var(--gd-given-line)); }
.mini-tag.is-given { --dir-line: var(--gd-given-line); }
.mini-tag.is-received { --dir-line: var(--gd-recv-line); }
.mini-tag:hover { border-color: var(--color-accent-line); }
.mini-date { font-size: var(--fs-micro); color: var(--color-text-light); }
.mini-title { font-family: var(--font-serif); font-size: 0.98rem; line-height: 1.25; color: var(--color-text-dark); margin-top: 3px; overflow-wrap: anywhere; }
/* Rendered only when there is one — the em-dash placeholder went the same way as the gift
   tag's, and for the same reason: most gifts carry no amount. */
.mini-amount { font-size: var(--fs-xs); font-weight: 600; margin-top: 5px; font-variant-numeric: tabular-nums; }
.mini-foot { font-size: 10px; font-weight: 600; margin-top: 5px; }
.mini-foot.is-given { color: var(--gd-given); }
.mini-foot.is-received { color: var(--gd-recv); }
.col-empty { font-size: var(--fs-xs); color: var(--color-text-light); text-align: center; padding: var(--s3); font-style: italic; }
.col-more { text-align: center; padding: 4px; }

/* ─────────────────────────────── MENU ─────────────────────────────── */
:root {
    --tsk-menu-align: 1080px;
    --tsk-menu-z: 1400;
    --tsk-menu-scrim: rgba(47,42,54,0.5);
    --tsk-menu-bg: var(--gd-paper);
}
.menu-header { flex-shrink: 0; display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.85rem; gap: 8px; }
.menu-header h3 { margin: 0; color: var(--color-text-dark); font-size: 1.1rem; }
.menu-header-right { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.close-menu {
    background: var(--chrome-bg); border: 1px solid var(--chrome-border); border-radius: var(--chrome-radius);
    font-size: 1.25rem; color: var(--chrome-text); cursor: pointer; width: 40px; height: 40px;
    display: flex; align-items: center; justify-content: center; line-height: 1;
}
.close-menu:hover { background: var(--color-danger-light); color: var(--color-error); border-color: var(--color-danger-line); }
/* Every row is a <button> today. `text-decoration` and `font-family` are set anyway because
   neither is inherited by the elements a row could reasonably be built from — an <a> row
   arrives underlined and a <button> row in the browser's UI font, and both look like a
   styling bug rather than a missing declaration. */
.menu-action {
    width: 100%; background: var(--color-background); border: 1px solid var(--color-border); padding: 11px 14px;
    border-radius: 12px; margin-bottom: 8px; cursor: pointer; transition: all 0.2s; display: flex; align-items: center; gap: 12px;
    font-size: 0.95rem; font-family: inherit; color: var(--color-text-dark); font-weight: 500; text-align: left;
    text-decoration: none;
}
.menu-action:hover { background: var(--color-white); border-color: var(--color-accent); transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.menu-action.danger { color: var(--color-error); border-color: var(--color-danger-line); }
.menu-action.danger:hover { background: var(--color-danger-light); border-color: var(--color-error); }
.action-icon { font-size: 1.35rem; flex-shrink: 0; }
.action-content { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; }
.action-hint { font-size: var(--fs-micro); color: var(--color-text-light); font-weight: 400; font-style: italic; }
.menu-divider { height: 1px; background: var(--color-border); margin: 2px 0 10px; }

/* ─────────────────────────────── MODALS ─────────────────────────────── */
.modal-overlay {
    position: fixed; inset: 0; background: rgba(47,42,54,0.46); z-index: 1500;
    display: flex; align-items: flex-start; justify-content: center; padding: 72px var(--s4) var(--s6); overflow-y: auto;
}
/* Every modal is capped to the viewport, not just the two long ones. Uncapped, a tall modal
   grew past the bottom of the screen — its actions row out of reach — and `.modal-body`'s
   `overflow-y: auto` had nothing to scroll, so `overscroll-behavior: contain` swallowed the
   wheel instead of chaining it to the overlay: the pointer had to be moved off the modal to
   scroll at all. Capped, the body is a real scroller and the actions row stays pinned.
   The number is the overlay's own vertical padding — keep the two in step. */
.modal {
    width: 100%; max-width: 480px; background: var(--gd-paper); border-radius: var(--radius-xl);
    box-shadow: var(--shadow-lg); animation: modalIn 0.16s ease; display: flex; flex-direction: column;
    max-height: calc(100dvh - 96px);
}
@keyframes modalIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.modal-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s3); padding: var(--s5) var(--s5) var(--s2); flex-shrink: 0; }
.modal-head-text { min-width: 0; }
.modal-eyebrow { font-size: var(--fs-micro); font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-text-light); margin-bottom: 2px; }
.modal-title { font-family: var(--font-serif); font-size: 1.4rem; font-weight: 500; line-height: 1.15; color: var(--color-primary); }
.modal-x { width: 36px; height: 36px; border-radius: 50%; border: 1px solid var(--color-border-strong); background: #fff; font-size: 1.2rem; line-height: 1; color: var(--color-text-medium); cursor: pointer; flex-shrink: 0; }
.modal-x:hover { color: var(--color-error); border-color: var(--color-danger-line); }
.modal-body { padding: var(--s2) var(--s5) var(--s4); flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
.modal-sub { font-size: var(--fs-sm); color: var(--color-text-medium); line-height: 1.5; margin-bottom: var(--s3); }
.modal-actions {
    display: flex; justify-content: flex-end; gap: 8px; flex-wrap: wrap; flex-shrink: 0;
    padding: var(--s3) var(--s5); border-top: 1px solid var(--color-border); background: rgba(246,241,234,0.6); border-radius: 0 0 var(--radius-xl) var(--radius-xl);
}
.modal-actions-spread { justify-content: space-between; }
.modal-actions-left, .modal-actions-right { display: flex; gap: 6px; flex-wrap: wrap; }
.modal-actions-right { margin-left: auto; }

/* ─────────────────────────────── LIGHTBOX ─────────────────────────────── */
.lightbox { position: fixed; inset: 0; z-index: 1600; background: rgba(20,16,24,0.9); display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 48px 12px 12px; }
.lb-close { position: absolute; top: 10px; right: 10px; width: 44px; height: 44px; border-radius: 50%; border: none; background: rgba(255,255,255,0.14); color: #fff; font-size: 1.5rem; cursor: pointer; }
.lb-stage { width: min(960px, 100%); flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; }
.lb-stage img, .lb-stage video { max-width: 100%; max-height: 100%; border-radius: 8px; }
.lb-stage iframe { width: 100%; max-width: 900px; aspect-ratio: var(--lb-ratio, 16/9); max-height: 100%; border: none; border-radius: 8px; background: #000; }
.lb-fallback { color: #fff; text-align: center; font-size: var(--fs-sm); }
.lb-bar { width: min(960px, 100%); display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-top: 10px; color: #fff; font-size: var(--fs-xs); }
.lb-caption { font-family: var(--font-hand); font-size: 1.2rem; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding-right: 0.2em; margin-right: -0.2em; }
.lb-open { color: #fff; font-weight: 600; white-space: nowrap; }
/* Gallery nav. Outside `.lb-stage` so it never overlaps an iframe's own controls,
   and vertically centred against the stage rather than the padded box. */
.lb-nav {
    position: absolute; top: 50%; transform: translateY(-50%);
    width: 44px; height: 44px; border-radius: 50%; border: none;
    background: rgba(255,255,255,0.14); color: #fff;
    font-size: 1.75rem; line-height: 1; cursor: pointer;
    display: flex; align-items: center; justify-content: center;
}
.lb-nav:hover { background: rgba(255,255,255,0.26); }
/* `display: flex` above is an AUTHOR rule and outranks the UA's
   `[hidden] { display: none }`, so a single-photo gift would still show both
   arrows. Anything given a `display` needs this alongside it. */
.lb-nav[hidden] { display: none; }
.lb-prev { left: 10px; }
.lb-next { right: 10px; }
/* `.lb-caption` is the flexible one, so the counter keeps its width and the
   caption ellipses instead of the digits being squeezed out. */
.lb-count { flex: 0 0 auto; color: rgba(255,255,255,0.75); font-variant-numeric: tabular-nums; }
.lb-caption { flex: 1 1 auto; }

/* ─────────────────────────────── TOAST ─────────────────────────────── */
.toast {
    position: fixed; left: 50%; bottom: 20px; transform: translate(-50%, 16px); max-width: min(400px, 90vw);
    padding: var(--s2) var(--s4); background: var(--color-text-dark); color: #fff; border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg); font-size: var(--fs-sm); opacity: 0; pointer-events: none; transition: opacity 0.2s, transform 0.2s; z-index: 1800;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
.toast.error { background: var(--color-error); }

/* ─────────────────────────────── ABOUT SECTION ─────────────────────────────── */
.about-section { background: var(--gd-paper); border: 1px solid var(--color-border); border-radius: var(--radius-lg); margin: var(--s6) 0 var(--s5); overflow: hidden; }
.about-toggle {
    display: flex; align-items: center; gap: var(--s3); width: 100%; padding: var(--s3) var(--s4);
    background: none; border: none; font-size: var(--fs-sm); font-weight: 500; color: var(--color-text-medium); text-align: left; cursor: pointer;
}
.about-toggle:hover { background: var(--color-background); color: var(--color-text-dark); }
.about-icon { font-size: var(--fs-sm); }
.about-title { flex: 1; }
.toggle-icon { color: var(--color-text-light); font-size: var(--fs-xs); transition: transform 0.2s; }
.about-toggle[aria-expanded="true"] .toggle-icon { transform: rotate(180deg); }
.about-content { padding: 0 var(--s5) var(--s5); border-top: 1px solid var(--color-border); }
.about-content h2 { font-family: var(--font-serif); font-size: var(--fs-lg); font-weight: 500; color: var(--color-primary); margin: var(--s5) 0 var(--s3); }
.about-content h3 { font-size: var(--fs-md); font-weight: 600; color: var(--color-primary); margin: var(--s5) 0 var(--s2); }
.about-content p { font-size: var(--fs-sm); line-height: 1.55; color: var(--color-text-medium); margin-bottom: var(--s2); }
.about-content ul, .about-content ol { margin: 0 0 var(--s3) var(--s4); }
.about-content li { font-size: var(--fs-sm); line-height: 1.55; color: var(--color-text-medium); margin-bottom: 5px; }
.about-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); gap: var(--s5); }
.how-to-steps li { margin-bottom: var(--s2); }
.how-to-steps p { margin: 2px 0 0; }
.features-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--s3); }
.feature-item { padding: var(--s3); background: var(--color-background); border-radius: var(--radius-lg); }
.feature-item strong { display: block; font-size: var(--fs-sm); color: var(--color-primary); margin-bottom: 2px; }
.feature-item p { font-size: var(--fs-xs); margin: 0; }
.keywords-section { margin-top: var(--s5); color: var(--color-text-light); }

/* ─────────────────────────────── FOOTER ─────────────────────────────── */
.app-footer { padding: var(--s4) 0 var(--s8); text-align: center; font-size: var(--fs-xs); color: var(--color-text-light); }
.app-footer p { margin-bottom: 3px; }
.footer-link { color: var(--color-text-medium); text-decoration: none; border-bottom: 1px solid transparent; }
.footer-link:hover { color: var(--color-accent); border-bottom-color: var(--color-accent); }
.footer-separator { margin: 0 var(--s2); color: var(--color-border-strong); }
.version-badge { background: none; border: none; padding: 0; font-size: var(--fs-xs); color: var(--color-text-medium); cursor: pointer; border-bottom: 1px solid transparent; }
.version-badge:hover { color: var(--color-accent); border-bottom-color: var(--color-accent); }

/* ─────────────────────────────── RESPONSIVE ─────────────────────────────── */
@media (max-width: 768px) {
    .header-inner { padding: 0.5rem 1rem; }
    .logo-image { height: 34px; }
    .tool-name-btn { font-size: 1.25rem; }
    .container { padding: var(--s4) var(--s4) 0; }
    /* The ribbon sheds its parts in priority order rather than wrapping into a block:
       the date goes first ("in 3 days" already carries it), then the action word — the
       whole row stays the tap target — and last of all the plan takes its own line. */
    .rb-meta { display: none; }
    /* Search drops to a line of its own, below the count and the buttons — the order it had
       when it lived in the toolbar. */
    .diary-lead-text { order: 1; }
    .lead-actions    { order: 2; }
    .search-row      { order: 3; flex: 1 1 100%; }
    /* The filter fold. Below this width vertical space is always short. */
    .filter-btn { display: inline-flex; }
    .filters { display: none; }
    .toolbar.filters-open .filters { display: flex; }
    /* One fold, not two: the funnel already reveals the whole block here, so the rest is
       always out inside it and "More filters" has nothing left to do. */
    .filter-more { display: none; }
    .filters-rest { display: flex; }
}
@media (max-width: 620px) {
    /* Two lines, always: the occasion owns the first, and the "+N more" pill shares the
       second with the planner rather than wrapping onto a third of its own. */
    .ribbon { border-radius: var(--radius-lg); padding: 6px 14px; }
    .rb-act { display: none; }
    .ribbon-occ {
        flex: 1 1 100%; padding-bottom: 5px; margin-bottom: 0;
        border-bottom: 1px dashed var(--color-border);
    }
    .ribbon-plan { flex: 0 1 auto; margin-left: auto; padding: 4px 0; border-left: none; }
    /* No plan zone, nothing to divide the occasion from — and no second line to reach. */
    .ribbon-wrap.no-plan .ribbon-occ { border-bottom: none; padding-bottom: 4px; }
    /* With no pill to share the line with, it has no reason to sit off to the right. */
    .ribbon-more.hidden + .ribbon-plan { margin-left: 0; }
    /* Same shedding order as the occasion line: the bar says nothing "2 of 2 decided"
       does not, and giving up its 38px is what keeps the plan name readable at 360px. */
    .rb-bar { display: none; }

    /* The examples line reads as a sentence, so below the width where it stops fitting
       on one line it has to wrap like one. As a flex row it wrapped into 40px-tall touch
       targets on separate lines with the "·" stranded alone between them. */
    .welcome-samples { display: block; line-height: 1.9; }
    .welcome-samples .link-btn { display: inline; min-height: 0; padding: 6px 0; white-space: nowrap; }

    /* Two chips to a row once one per row would be wider than it is useful. */
    .filters .select-chip { flex: 1 1 calc(50% - 3px); min-width: 0; max-width: none; }
    .filters .chip-toggle { flex: 1 1 100%; justify-content: center; }
    .filters .seg-sm { display: flex; flex: 1 1 100%; }
    .filters .seg-sm .seg-btn { flex: 1; }
}
@media (max-width: 600px) {
    .qa-row { grid-template-columns: 1fr 1fr; }
    .qa-row .qa-title { grid-column: 1 / -1; grid-row: 2; }
    .qa-row .qa-person { grid-column: 1 / -1; grid-row: 1; }
    .qa-row .qa-amount { grid-row: 3; }
    .qa-row .qa-add { grid-row: 3; }
    .qa-settings .select { flex: 1; min-width: 0; }
    .field-row-date { flex-wrap: wrap; }
    .field-col-day { flex: 1 1 100%; }
    .select-day { max-width: none; }
    .reaction-btn { font-size: 10px; }
}
@media (max-width: 560px) {
    /* Arrows move onto the bar's row rather than floating over the picture,
       where at 44px they cover a third of the width of a portrait photo. */
    .lb-nav { top: auto; bottom: 10px; transform: none; width: 40px; height: 40px; font-size: 1.5rem; }
    .lb-bar { padding: 0 52px; }
}
@media (max-width: 480px) {
    :root { --stub-w: 78px; }
    .tag-dir { font-size: 9px; letter-spacing: 0.03em; }
    /* DE "21. Feb. 2026" and FR "21 févr. 2026" are longer than the English date and
       wrapped the stub to a third line at 11px. */
    .tag-date { font-size: 10px; }
    .tag-photo { height: 42px; margin-top: 7px; }
    .header-inner { padding: 0.4rem 0.75rem; }
    .logo-image { height: 30px; }
    .tool-name-btn { font-size: 1.25rem; }
    .header-icon-btn svg { width: 18px; height: 18px; }
    .container { padding: var(--s3) var(--s3) 0; }
    .welcome { padding: var(--s5) var(--s4); }
    .welcome-tag { width: 200px; margin-left: 26px; }
    /* The occasion is the story the card tells — "this was for Mum's birthday". The type is
       metadata, usually implied by the title and always one tap away in the editor. On a
       375px card the meta row cannot hold both plus a reaction and a thank-you, so the chip
       is what steps aside rather than the occasion being cut to "Birthday ·…". */
    .tag-meta > .chip { display: none; }
    .tag-stub { padding: 28px 6px 9px 10px; }
    .tag-amount { font-size: 1rem; }
    .tag-name { font-size: 1.4rem; }
    .tag-title { font-size: 1.02rem; }
    .tag-body { padding: 10px 11px 10px 12px; }
    .modal-overlay { padding: 56px var(--s2) var(--s4); }
    .modal { max-height: calc(100dvh - 72px); }   /* 56 + 16, as above */
    .modal-head, .modal-body { padding-left: var(--s4); padding-right: var(--s4); }
    .modal-actions { padding-left: var(--s4); padding-right: var(--s4); }
    .modal-actions .btn-primary, .modal-actions .btn-quiet { padding-left: 12px; padding-right: 12px; }
    .lead-actions { width: 100%; }
    .lead-actions > * { flex: 1; }
    .masthead-name { font-size: 1.5rem; }
    /* Their own row, left-aligned. `margin-left: auto` pinned them right with a wide gap to
       the left, reading as floating; and giving them a full-width basis keeps them off the
       avatar's line, so the name has the whole width beside the avatar rather than the ~67px
       left over after the buttons. */
    .masthead-actions { flex: 1 1 100%; margin-left: 0; }
    .stat-count b { font-size: 1.3rem; }
    .person-row { grid-template-columns: 36px minmax(0, 1fr) auto auto; gap: 8px; padding: 8px 8px 8px 10px; }
    .avatar { width: 36px; height: 36px; }
    .person-name { font-size: 1.35rem; }
}
@media (max-width: 380px) {
    :root { --stub-w: 78px; }
    .tag-rx { margin-left: 0; }
}

/* Touch devices get full-size hit areas regardless of viewport width. */
@media (hover: none) and (pointer: coarse) {
    .seg-btn, .chip-btn, .select-chip, .chip-toggle, .link-btn { min-height: 40px; }
    .tag-rx { min-height: 32px; }
    .rx-pick { min-height: 40px; }
    .link-btn { display: inline-flex; align-items: center; }
    /* The 40px target makes `Today` taller than the label beside it, and a baseline that
       was right for two lines of text is not right for a box against a line. */
    .label-row { align-items: center; }
    .ribbon-occ, .ribbon-plan { padding-top: 10px; padding-bottom: 10px; }
    .ribbon-more { padding-top: 8px; padding-bottom: 8px; }
    .rb-row { padding-top: 12px; padding-bottom: 12px; }
}

/* ─────────────────────────────── ACCESSIBILITY ─────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* ─────────────────────────────── PRINT ─────────────────────────────── */
@media print {
    body { background: #fff; }
    .header, .info-banner, .page-nav, .lead-actions, .search-row, .toolbar, .quick-add, .about-section, .app-footer, .menu-overlay, .toast, .ledger-more, .back-link, .view-actions { display: none !important; }
    .gift-tag, .person-row, .event-row { box-shadow: none; break-inside: avoid; }
    .tag-stub::before, .stat-tile::after, .masthead-band::after { display: none; }
}
