/* ldc-theme */
/* ==========================================================================
   Lamduan shared theme -- loaded by every plugin in the suite.
   Keep all color/spacing decisions here so every module stays visually
   identical without duplicating CSS.
   ========================================================================== */

:root {
    --ldc-red: #DF301C;
    --ldc-orange: #FF9100;
    --ldc-cream: #FFF1D1;
    --ldc-teal: #00B7CD;

    --ldc-text: #2b2b2b;
    --ldc-text-soft: #746552;    /* between body text and the muted grey */
    /* Was #8a7a68, which measured 3.7:1 on the cream page and 4.15:1 on a
       white card -- under AA on both, and this token carries almost every
       label, hint and subtitle in the app, so the whole interface sat just
       under the line. #7a6a56 clears 4.5:1 on the page, on a card and on a
       tinted panel, and is still visibly quieter than the body colour, which
       is the job the token exists to do. */
    --ldc-text-muted: #746552;
    /* The bottom bar is primary navigation, not secondary text, so it gets its
       own token rather than borrowing the muted grey. On the glass bar that
       grey measures 4.1:1 -- under AA -- and every future tweak to "muted"
       would silently drag the navigation with it. Each theme sets this to a
       value that clears 4.5:1 on its own bar; the four other palettes already
       did, which is why only this default needed moving. */
    --ldc-nav-ink: #7a6a56;
    --ldc-bg: #FFF1D1;          /* page background -- cream, never white */
    --ldc-card-bg: #ffffff;      /* cards lift off the cream */
    --ldc-border: #e9d2a8;
    --ldc-border-strong: #c9a86a; /* outlines meant to be seen, not just felt */

    /* ---- roles the modules kept re-inventing as raw hex ------------------
       Every one of these was written out by hand in three or four plugins,
       which meant a second theme was impossible: swapping four brand colours
       left a hundred hard-coded creams and whites behind. Named by ROLE, not
       by colour, so a dark theme can invert them without renaming anything. */
    --ldc-surface-soft: #fff8ec;   /* tinted panel on a card */
    --ldc-surface-cool: #f4feff;   /* the same, on the teal side */
    --ldc-surface-alert: #fdeceb;  /* and on the red side */
    --ldc-surface-accent: #ffe6c4; /* selected / highlighted block */
    --ldc-nav-pill: #ffe0c7;       /* the capsule behind the active nav icon */
    --ldc-on-accent: #ffffff;      /* text and icons ON a filled brand colour */
    --ldc-ok: #1c7a4d;             /* target met, streak intact */
    --ldc-info: #0d7f92;
    --ldc-warn: #9a5a00;
    --ldc-surface-ok: #e6f7ee;
    --ldc-surface-warn: #fff4e0;
    --ldc-axis: #a9793f;           /* chart axis numbers */
    /* Two role tokens split off from the brand palette, because the brand
       colours are chosen to look right as FILLS and neither of them survives
       being small text. --ldc-teal at #00B7CD measures 2.4:1 as a link on
       white; --ldc-axis measures 3.8:1 as a stat label on the accent panel.
       The brand values are untouched -- these are what text uses. */
    /* The text palette. Every one of these was derived by walking the matching
       brand colour toward the ground until it cleared 4.5:1 against EVERY
       surface the theme paints -- card, page, accent, alert, soft, cool, warn
       and ok -- so a component can move between surfaces without anyone
       re-measuring. The brand values themselves are untouched and still used
       for fills, borders and anything large. */
    --ldc-link: #007380;           /* teal, as small text */
    --ldc-red-ink: #c42a19;        /* brand red, as small text */
    --ldc-label: #845e31;          /* small labels and chart axis numbers */
    --ldc-accent-ink: #995700;     /* brand orange, as small text */
    --ldc-axis-strong: #8d6428;
    --ldc-track: #f3e4cb;          /* the unfilled part of a ring or a bar */
    --ldc-teal-soft: #7fdcea;
    /* Translucent surfaces need their own token: a frosted bar is not
       "the card colour at 92%", it is a colour of its own, and a hard-coded
       white one turns a dark theme's nav back into a white bar. */
    --ldc-glass: rgba(255, 255, 255, .92);
    --ldc-glass-fill: rgba(255, 255, 255, .5);
    --ldc-ink: #56818c;            /* line art that is neither brand nor text */
    --ldc-leaf: #5f9a52;

    --ldc-radius: 14px;
    --ldc-radius-sm: 8px;
    --ldc-shadow: 0 2px 10px rgba(223, 48, 28, 0.08);

    /* The CJK names at the tail are what Chinese is painted in. No webfont is
       shipped for it and none should be: a subset covering these pages would
       be megabytes against 30 KB for Thai, and every device that reads Chinese
       already has a good face for it. The names cost nothing to a Thai or
       English reader -- a family is only consulted for a glyph the ones before
       it do not have, and Plex and Poppins cover Latin and Thai between them.
       Both scripts are listed: PingFang SC / Microsoft YaHei are Simplified,
       PingFang TC / Microsoft JhengHei Traditional, and a device has whichever
       it has. */
    --ldc-font-cjk: 'PingFang SC', 'PingFang TC', 'Hiragino Sans GB',
        'Microsoft YaHei', 'Microsoft JhengHei', 'Noto Sans CJK SC',
        'Noto Sans CJK TC', 'Source Han Sans SC', 'Heiti SC', 'SimHei';
    --ldc-font-body: 'IBM Plex Sans Thai', 'Poppins', -apple-system, BlinkMacSystemFont,
        'Segoe UI', 'Helvetica Neue', var(--ldc-font-cjk), sans-serif;
    /* Poppins carries no Thai glyphs on purpose: Latin headings match the
       logo wordmark, Thai headings fall through to IBM Plex Sans Thai. */
    --ldc-font-display: 'Poppins', 'IBM Plex Sans Thai', -apple-system, BlinkMacSystemFont,
        'Segoe UI', var(--ldc-font-cjk), sans-serif;

    /* See "Thai marks and boxes that clip" below. */
    --ldc-clip-pad: .3em;

    --ldc-topbar-h: 112px;       /* two rows: logo row + menu row */
    --ldc-bottomnav-h: 64px;
    /* There is deliberately no --ldc-navspace token here. env() is not allowed
       inside a custom property: browsers drop the whole declaration, the
       variable resolves to nothing, and every calc() built on it silently
       collapses. The nav's real height -- 64px plus the home-indicator strip
       iOS reserves under it -- is therefore written out at each of the two
       places that need it, and they must be changed together.
       The fallback is 0px, not 0: a unitless zero inside calc() is a number,
       not a length, and makes the declaration invalid. */
    --ldc-breakpoint: 1024px;
}

/* ---- reset-ish basics scoped to Lamduan content, not the whole theme ---- */
.ldc-page,
/* border-box, from us rather than from Elementor.
   Every app page is set to a full-screen template, and until now the one
   supplying the border-box reset for anything outside a card was Elementor
   -- its ".elementor *" rule was quietly holding 227 elements on this page
   together. Switching the template away from Elementor would have taken
   that with it and moved every padded box by its own padding.

   So the reset is stated here, for the two roots the app renders under:
   its own canvas template, and the page wrapper each module draws inside
   (which covers a page laid out any other way too). */
body.ldc-canvas,
body.ldc-canvas *,
body.ldc-canvas *::before,
body.ldc-canvas *::after,
.ldc-page,
.ldc-page *,
.ldc-page *::before,
.ldc-page *::after,
.ldc-topbar,
.ldc-topbar *,
.ldc-bottomnav,
.ldc-bottomnav *,
.ldc-footer,
.ldc-footer *,
.ldc-dash-grid,
.ldc-dash-grid * {
    box-sizing: border-box;
}

.ldc-card,
.ldc-form,
.ldc-table {
    box-sizing: border-box;
}
.ldc-page *,
.ldc-card *,
.ldc-form *,
.ldc-table * {
    box-sizing: inherit;
}

html,
body {
    /* The browser gives body an 8px margin of its own. Nothing here ever zeroed
       it -- WordPress's global styles did, invisibly, and the day those were
       dropped from these pages every one of them would have gained an eight
       pixel band down both edges. A reset this page depends on belongs in this
       page's stylesheet. */
    margin: 0;
    background: var(--ldc-bg) !important;
    font-family: var(--ldc-font-body);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

body {
    padding-top: var(--ldc-topbar-h);
}

/* ==========================================================================
   BETWEEN ONE PAGE AND THE NEXT -- and why there is no transition here

   A cross-document view transition (@view-transition { navigation: auto })
   was tried on 23 Sep 2026 and TAKEN BACK OUT the same hour, because it was
   measured on the phone rather than admired in a browser.

   The idea was sound: every screen is a full page load, the browser holds
   the old page until the new one can paint, and then swaps them in a single
   frame -- a still moment followed by a hard cut, which is what reads as a
   web page rather than an app. A cross-fade fills that moment.

   What it actually did, counted frame by frame off two screen recordings of
   the same phone doing the same thing:

       before   5 dark gaps in 119 s, 33 ms at the median
       after   13 dark gaps in 110 s, 50 ms at the median

   Nearly three times as many, and each one longer. The owner's words were
   "รู้สึกว่ามันกระพริบๆ" and he was right.

   The reason is a WKWebView artifact this app already had: for one to three
   frames during a navigation the incoming document is laid out at about 35
   pixels wide -- the page squeezed into a strip down the left, the rest of
   the screen the web view's own background. It was there before any of this
   (visible in the 15:41 recording as a narrow strip beside a field of cream,
   which is what sent us looking at the web view's background colour in the
   first place). A cross-fade does not skip past that broken frame; it holds
   the outgoing snapshot and animates ACROSS it, so a flicker that used to be
   one frame becomes three.

   So: no transition until the squeeze itself is understood. Adding motion on
   top of a layout bug makes the bug longer, not smoother.
   ========================================================================== */

/* ==========================================================================
   MOVING BETWEEN SCREENS

   The page's contents are replaced rather than the document being reloaded
   (see core.js). Two things are drawn here, and between them they are what
   the reader actually experiences as the change:

   1. A hairline across the top while the next screen is being fetched. It
      starts at 30% and creeps, because it cannot know how far along it is
      and a bar that pretends to is worse than one that admits it. It is the
      answer to "I tapped and nothing happened".

   2. The arriving content rises a few pixels as it fades in. Six pixels and
      .16s -- enough to read as an arrival, not enough to be a wait. This is
      NOT a cross-fade between the two screens: that was tried on 23 Sep,
      measured, and made things worse, because it holds the outgoing page on
      screen and animates across the web view's broken first frame instead of
      skipping past it. This plays on the new content only, after it is
      already in the document, so it cannot lengthen anything.
   ========================================================================== */
#ldc-canvas-main {
    position: relative;
}

#ldc-canvas-main.is-loading::before {
    content: '';
    position: fixed;
    top: 0;
    left: 0;
    height: 2px;
    width: 30%;
    background: var(--ldc-red, #DF301C);
    border-radius: 0 2px 2px 0;
    z-index: 100000;
    animation: ldc-crawl 8s cubic-bezier(.2, .8, .3, 1) forwards;
}

@keyframes ldc-crawl {
    0%   { width: 0; }
    12%  { width: 32%; }
    40%  { width: 62%; }
    100% { width: 88%; }
}

/* NO ANIMATION ON THE ARRIVING CONTENT, and the reason is worth keeping.

   It was a .16s rise-and-fade: opacity 0 to 1 with transform translateY(6px).
   On the phone it produced a visible fault at the left of the screen -- the
   day strip's numbers sliced in half for two or three frames, text appearing
   to flicker, then snapping right. The owner saw it before anybody else and
   described it exactly: "ที่ขอบจอด้านซ้าย เหมือนมีตัวหนังสือวูบๆวืดๆ".

   A transform promotes the element to a layer of its own for the length of
   the animation, and anything drawn outside that layer's box is clipped
   while it lasts. The Thai type in this suite deliberately overflows its
   boxes -- see --ldc-clip-pad and the negative margins on .ldc-day, which
   exist so vowel marks above and below a line are not cut off. Those are
   exactly the pixels a transform layer removes.

   So: the content simply appears. Motion on arrival is worth very little;
   this is the second time in two days that adding it has cost more than it
   paid, and both times the phone said so and the browser did not.

   The hairline across the top stays. It is information, not decoration, and
   it is fixed-position chrome that clips nothing.
   ========================================================================== */

/* keep content clear of the WP admin bar too */
body.admin-bar {
    padding-top: calc(var(--ldc-topbar-h) + 32px);
}
@media screen and (max-width: 782px) {
    body.admin-bar {
        padding-top: calc(var(--ldc-topbar-h) + 46px);
    }
}

@media (max-width: 1024px) {
    :root {
        --ldc-topbar-h: 72px; /* menu row hides on mobile, so topbar is shorter */
    }
    body {
        /* the nav's real height, plus a little, so the last button on a page
           is never flush against it */
        padding-bottom: calc(var(--ldc-bottomnav-h) + env(safe-area-inset-bottom, 0px) + 14px);
    }
}

/* ==========================================================================
   TOP BAR -- row 1: logo (centered) / row 2: menu links
   ========================================================================== */
.ldc-topbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    background: var(--ldc-card-bg);
    border-bottom: 2px solid var(--ldc-orange);
    z-index: 9999;
}

body.admin-bar .ldc-topbar {
    top: 32px;
}
@media screen and (max-width: 782px) {
    body.admin-bar .ldc-topbar {
        top: 46px;
    }
}

.ldc-topbar-logo-row {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 10px 16px 6px;
}

.ldc-logo {
    display: inline-flex;
    align-items: center;
}
.ldc-logo img {
    height: 52px !important;
    max-height: 52px !important;
    width: auto !important;
    max-width: 300px !important;
    display: block;
    object-fit: contain;
}

/* The logo row is centred, so anything left in its flow lands beside the
   logo. The controls belong at the right edge instead -- as one group, so
   the language switch and the menu button cannot drift apart. */
.ldc-topbar-actions {
    position: absolute;
    right: 16px;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    gap: 10px;
}
.ldc-topbar-actions .ldc-langswitch {
    position: static;
    transform: none;
    right: auto;
    top: auto;
}

/* ---- language switcher (TH / EN), pinned to the right of the logo row ---- */
.ldc-langswitch {
    position: absolute;
    right: 16px;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    gap: 2px;
    background: var(--ldc-cream);
    border: 1px solid var(--ldc-border);
    border-radius: 999px;
    padding: 2px;
}
.ldc-lang-btn {
    /* --ldc-font-display already ends in the CJK stack, so 简 and 繁 have a
       face to land on; Poppins has neither glyph. */
    font-family: var(--ldc-font-display);
    font-size: 12px;
    font-weight: 600;
    /* Letter-spacing on a CJK glyph pushes it off centre in its own pill, so
       it is applied to the Latin pair only. Four buttons instead of two also
       means the padding has to come in, or the row leaves the topbar on a
       320px phone. */
    padding: 4px 6px;
    border-radius: 999px;
    color: var(--ldc-text-muted);
    text-decoration: none;
    line-height: 1;
    transition: background .15s ease, color .15s ease;
}
.ldc-lang-btn[hreflang="th"],
.ldc-lang-btn[hreflang="en"] {
    letter-spacing: .04em;
}
.ldc-lang-btn:hover {
    color: var(--ldc-red-ink);
}
.ldc-lang-btn.is-active {
    background: var(--ldc-red);
    color: var(--ldc-on-accent);
}

.ldc-topbar-menu-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 0 16px 8px;
    flex-wrap: wrap;
}

.ldc-topnav-link {
    font-family: var(--ldc-font-display);
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 7px 14px;
    border-radius: 999px;
    color: var(--ldc-text);
    text-decoration: none;
    font-weight: 600;
    font-size: 14px;
    transition: background 0.15s ease, color 0.15s ease;
    white-space: nowrap;
}
.ldc-topnav-link:hover {
    background: var(--ldc-cream);
    color: var(--ldc-red-ink);
}
.ldc-topnav-link.is-active {
    background: var(--ldc-red);
    color: var(--ldc-on-accent);
}
.ldc-topnav-link .ldc-nav-icon {
    font-size: 16px;
    line-height: 1;
}

/* on phones/tablets the menu row hides; bottom nav takes over */
@media (max-width: 1024px) {
    .ldc-topbar-menu-row {
        display: none;
    }
    .ldc-logo img {
        height: 44px !important;
        max-height: 44px !important;
    }
}

/* ==========================================================================
   BOTTOM NAV -- sticky tab bar for phones & tablets
   ========================================================================== */
.ldc-bottomnav {
    display: none;
}

@media (max-width: 1024px) {
    .ldc-bottomnav {
        display: flex;
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        /* border-box on purpose: the nav sits outside .ldc-page, so it does not
           inherit the suite's border-box and its height would otherwise be 64px
           PLUS the safe-area padding -- taller than anything reserved for it. */
        box-sizing: border-box;
        height: calc(var(--ldc-bottomnav-h) + env(safe-area-inset-bottom, 0px));
        background: var(--ldc-card-bg);
        border-top: 1px solid var(--ldc-border);
        z-index: 9999;
        padding-bottom: env(safe-area-inset-bottom, 0px);
        box-shadow: 0 -2px 10px rgba(223, 48, 28, 0.08);
    }

    .ldc-bottomnav-link {
        font-family: var(--ldc-font-display);
        flex: 1 1 0;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 2px;
        text-decoration: none;
        color: var(--ldc-nav-ink);
        font-size: 11px;
        font-weight: 600;
        min-width: 0;
    }
    .ldc-bottomnav-link .ldc-nav-icon {
        font-size: 20px;
        line-height: 1;
    }
    .ldc-bottomnav-link .ldc-nav-label {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        max-width: 100%;
        /* clip-rect breathing room for Thai tone marks; see --ldc-clip-pad */
        padding-top: var(--ldc-clip-pad);
        padding-bottom: var(--ldc-clip-pad);
        margin-top: calc(-1 * var(--ldc-clip-pad));
        margin-bottom: calc(-1 * var(--ldc-clip-pad));
}
    .ldc-bottomnav-link.is-active {
        color: var(--ldc-red-ink);
    }
    .ldc-bottomnav-link.is-active .ldc-nav-icon {
        transform: translateY(-1px);
    }
}

/* ==========================================================================
   SHARED COMPONENTS -- every module plugin can reuse these classes
   ========================================================================== */
.ldc-page {
    max-width: 720px;
    margin: 0 auto;
    padding: 20px 16px 40px;
    color: var(--ldc-text);
    font-size: 15px;
    line-height: 1.5;
}

.ldc-page h1 {
    font-family: var(--ldc-font-display);
    letter-spacing: -0.01em;
    font-size: 22px;
    margin: 0 0 4px;
    color: var(--ldc-red-ink);
}
.ldc-page .ldc-subtitle {
    color: var(--ldc-text-muted);
    margin: 0 0 20px;
    font-size: 14px;
}

.ldc-card {
    background: var(--ldc-card-bg);
    border: 1px solid var(--ldc-border);
    border-radius: var(--ldc-radius);
    box-shadow: var(--ldc-shadow);
    padding: 18px;
    margin-bottom: 16px;
}

.ldc-card-title {
    font-family: var(--ldc-font-display);
    font-weight: 600;
    color: var(--ldc-red-ink);
    margin: 0 0 12px;
    font-size: 15px;
}

.ldc-stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 10px;
}
.ldc-stat {
    background: var(--ldc-cream);
    border: 1px solid var(--ldc-border);
    border-radius: var(--ldc-radius-sm);
    padding: 10px 12px;
}
.ldc-stat-label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--ldc-label);
    display: block;
    margin-bottom: 2px;
}
.ldc-stat-value {
    font-family: var(--ldc-font-display);
    font-variant-numeric: tabular-nums;
    font-size: 20px;
    font-weight: 700;
    color: var(--ldc-text);
}

.ldc-form label {
    display: block;
    font-weight: 600;
    font-size: 13px;
    color: var(--ldc-text);
    margin-bottom: 4px;
}
.ldc-form .ldc-field {
    margin-bottom: 14px;
}

/* Field help text -- every input in the suite explains what goes in it.
   Sits under the input, quiet enough not to compete with the label. */
/* Small grey text beside a value. It carries the weight prefix for
   historical reasons and is printed by core, exercise, fasting, nutrition
   and weight alike -- so the rule belongs in the sheet every page loads,
   not in one module's. Use .ldc-muted in anything new. */
.ldc-muted,
.ldw-muted {
    color: var(--ldc-text-muted);
    font-size: 11px;
    font-weight: 400;
}

.ldc-hint,
.ldm-field-hint,
.ldw-field-hint {
    display: block;
    margin: 5px 0 0;
    font-size: 12px;
    line-height: 1.45;
    color: var(--ldc-text-muted);
    font-weight: 400;
}
.ldc-hint strong {
    color: var(--ldc-label);
    font-weight: 600;
}
.ldc-form label .ldc-optional {
    font-weight: 400;
    color: var(--ldc-text-muted);
    font-size: 12px;
}
.ldc-form input[type="text"],
.ldc-form input[type="email"],
.ldc-form input[type="password"],
.ldc-form input[type="number"],
.ldc-form input[type="date"],
.ldc-form input[type="time"],
.ldc-form select,
.ldc-form textarea {
    width: 100%;
    padding: 10px 12px;
    border: 1px solid var(--ldc-border);
    border-radius: var(--ldc-radius-sm);
    font-size: 15px;
    background: var(--ldc-card-bg);
    color: var(--ldc-text);
}
.ldc-form input:focus,
.ldc-form select:focus,
.ldc-form textarea:focus {
    outline: none;
    border-color: var(--ldc-teal);
    box-shadow: 0 0 0 3px rgba(0, 183, 205, 0.15);
}

.ldc-btn {
    font-family: var(--ldc-font-display);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 11px 20px;
    border-radius: 999px;
    font-weight: 700;
    font-size: 14px;
    border: none;
    cursor: pointer;
    text-decoration: none;
    transition: filter 0.15s ease, transform 0.05s ease;
}
.ldc-btn:active {
    transform: scale(0.98);
}
.ldc-btn-primary {
    background: var(--ldc-red);
    color: var(--ldc-on-accent);
}
.ldc-btn-primary:hover { filter: brightness(1.08); }
/* The fill is --ldc-link, not --ldc-teal: white on the brand teal measures
   2.4:1, which is the worst reading on any screen in the app, and a button is
   the last place to accept that. Same hue, deep enough to carry white text. */
.ldc-btn-secondary {
    background: var(--ldc-link);
    color: var(--ldc-on-accent);
}
.ldc-btn-secondary:hover { filter: brightness(1.08); }
.ldc-btn-outline {
    /* not transparent: an outline button often sits on the page rather than
       on a card, and a theme with a saturated ground would then be asked to
       carry small text directly */
    background: var(--ldc-card-bg);
    color: var(--ldc-red-ink);
    border: 1.5px solid var(--ldc-red);
}
.ldc-btn-block {
    width: 100%;
}

.ldc-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
}
.ldc-table th,
.ldc-table td {
    text-align: left;
    padding: 8px 10px;
    border-bottom: 1px solid var(--ldc-border);
}
.ldc-table th {
    color: var(--ldc-text-muted);
    font-size: 11px;
    text-transform: uppercase;
}

.ldc-badge {
    font-family: var(--ldc-font-display);
    display: inline-flex;
    align-items: center;
    padding: 3px 10px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 700;
    background: var(--ldc-cream);
    color: var(--ldc-red-ink);
}

.ldc-alert {
    padding: 12px 14px;
    border-radius: var(--ldc-radius-sm);
    font-size: 13px;
    margin-bottom: 14px;
}
.ldc-alert-success { background: var(--ldc-surface-ok); color: var(--ldc-ok); }
.ldc-alert-error   { background: var(--ldc-surface-alert); color: var(--ldc-red-ink); }
.ldc-alert-info    { background: var(--ldc-surface-cool); color: var(--ldc-info); }
.ldc-alert-warning { background: var(--ldc-surface-warn); color: var(--ldc-warn); }

.ldc-guest-note {
    /* a notice needs a surface of its own: on --ldc-cream it was page-colour
       on page colour, which in a strongly tinted theme leaves the text
       sitting straight on the wallpaper */
    background: var(--ldc-surface-warn);
    border: 1px dashed var(--ldc-orange);
    border-radius: var(--ldc-radius-sm);
    padding: 12px 14px;
    font-size: 13px;
    color: var(--ldc-axis-strong);
    margin-bottom: 16px;
}
.ldc-guest-note a {
    color: var(--ldc-red-ink);
    font-weight: 700;
}

/* ==========================================================================
   USER MANUAL (rendered by [lamduan_manual])
   ========================================================================== */
.ldc-manual-toc ol {
    margin: 0;
    padding-left: 20px;
}
.ldc-manual-toc li {
    margin-bottom: 4px;
}
.ldc-manual-toc a {
    color: var(--ldc-text);
    text-decoration: none;
    font-weight: 600;
}
.ldc-manual-toc a:hover {
    color: var(--ldc-red-ink);
    text-decoration: underline;
}

.ldc-manual-section {
    scroll-margin-top: calc(var(--ldc-topbar-h) + 12px);
}

.ldc-manual-body p {
    margin: 0 0 12px;
}
.ldc-manual-body ul,
.ldc-manual-body ol {
    margin: 0 0 12px;
    padding-left: 22px;
}
.ldc-manual-body li {
    margin-bottom: 6px;
}
.ldc-manual-body h4 {
    color: var(--ldc-red-ink);
    font-size: 14px;
    margin: 16px 0 8px;
}

.ldc-tip {
    /* same reason as the guest note: a tip is a panel, and --ldc-cream is the
       page's own colour, which leaves it invisible on a tinted ground */
    background: var(--ldc-surface-soft);
    border: 1px dashed var(--ldc-orange);
    border-radius: var(--ldc-radius-sm);
    padding: 12px 14px;
    font-size: 13px;
    color: var(--ldc-axis-strong);
    margin: 4px 0 14px;
}
/* Small text, so it uses the readable red rather than the brand red: at 13px
   #DF301C measures 4.35:1 on this panel, just under the line. Headings keep
   the brand value, where the size carries them. */
.ldc-tip strong {
    display: block;
    color: var(--ldc-red-ink);
    margin-bottom: 4px;
}


/* ==========================================================================
   SHARED EXTRAS for module plugins (charts, segmented tabs, empty states)
   ========================================================================== */
.ldc-chart {
    width: 100%;
    height: auto;
    display: block;
    overflow: visible;
}
.ldc-chart-wrap {
    background: var(--ldc-cream);
    border: 1px solid var(--ldc-border);
    border-radius: var(--ldc-radius-sm);
    padding: 12px 10px 6px;
}

.ldc-segmented {
    display: flex;
    gap: 6px;
    background: var(--ldc-cream);
    border: 1px solid var(--ldc-border);
    border-radius: 999px;
    padding: 4px;
    margin-bottom: 14px;
}
.ldc-segmented button {
    font-family: var(--ldc-font-display);
    flex: 1;
    padding: 8px 10px;
    border: none;
    background: transparent;
    border-radius: 999px;
    font-size: 13px;
    font-weight: 600;
    color: var(--ldc-text-muted);
    cursor: pointer;
}
.ldc-segmented button.is-active {
    background: var(--ldc-red);
    color: var(--ldc-on-accent);
}

.ldc-empty {
    text-align: center;
    color: var(--ldc-text-muted);
    font-size: 13px;
    padding: 22px 10px;
}

.ldc-inline-actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}
.ldc-linkbtn {
    background: none;
    border: none;
    padding: 0;
    font-size: 12px;
    font-weight: 600;
    color: var(--ldc-link);
    cursor: pointer;
    text-decoration: none;
}
.ldc-linkbtn.is-danger { color: var(--ldc-red-ink); }

.ldc-row-2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
}
@media (max-width: 420px) {
    .ldc-row-2 { grid-template-columns: 1fr; }
}
/* Most pairs in a row are short -- a date and a time, a dose and its unit --
   and they read better side by side even on a small phone. A pair whose
   label runs to two or three lines does not: each column is then about
   200px, the labels stack taller than the fields they belong to, and the
   two halves stop looking like one row.

   420px was too low to catch it. The owner saw it on a 440pt screen while
   his own phone, at 390pt, had been stacking them all along -- so the same
   form looked right in one hand and wrong in the other. This is judged by
   the label, not by the device, which is why it is a class on the row and
   not a different breakpoint for everybody. */
@media (max-width: 640px) {
    .ldc-row-2.is-wordy { grid-template-columns: 1fr; }
}

/* ==========================================================================
   APP MODE + INSTALL PROMPT
   When the site runs as an installed app there is no browser chrome, so the
   layout has to respect the phone's own safe areas itself.
   ========================================================================== */
body.ldc-app .ldc-topbar {
    padding-top: env(safe-area-inset-top, 0px);
}
body.ldc-app {
    padding-top: calc(var(--ldc-topbar-h) + env(safe-area-inset-top, 0px));
}

/* the installed app needs no special case any more: the body reserve above
   already carries the safe-area inset in every context */
/* an installed app should not offer to install itself */
body.ldc-app .ldc-install-bar { display: none !important; }

.ldc-install-bar {
    position: fixed;
    left: 12px;
    right: 12px;
    bottom: calc(var(--ldc-bottomnav-h) + 12px + env(safe-area-inset-bottom, 0px));
    z-index: 10000;
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    background: var(--ldc-card-bg);
    border: 1px solid var(--ldc-border);
    border-left: 4px solid var(--ldc-red);
    border-radius: var(--ldc-radius);
    box-shadow: 0 6px 24px rgba(223, 48, 28, 0.18);
    padding: 12px 14px;
}
@media (min-width: 1025px) {
    .ldc-install-bar {
        left: auto;
        right: 20px;
        bottom: 20px;
        max-width: 380px;
    }
}
/* The install box is now a set of steps, not one line, so it stacks
   instead of sitting in a row. */
.ldc-install-head { width: 100%; }
.ldc-install-head strong {
    display: block;
    font-family: var(--ldc-font-display);
    font-size: 15px;
    color: var(--ldc-red-ink);
    margin-bottom: 2px;
}
.ldc-install-head span {
    display: block;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--ldc-text-soft);
}
/* Folded away until asked for. The summary is the only thing visible in
   the closed state, so it has to look like something you can press. */
.ldc-install-more { width: 100%; margin-top: 8px; }
.ldc-install-more > summary {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    list-style: none;
    cursor: pointer;
    font-family: var(--ldc-font-display);
    font-size: 12.5px;
    font-weight: 600;
    color: var(--ldc-link);
    padding: 3px 0;
}
.ldc-install-more > summary::-webkit-details-marker { display: none; }
.ldc-install-more > summary::before {
    content: "▸";
    font-size: 11px;
    color: var(--ldc-accent-ink);
}
.ldc-install-more[open] > summary::before { content: "▾"; }
.ldc-install-more > summary:focus-visible {
    outline: 2px solid var(--ldc-accent-ink);
    outline-offset: 2px;
    border-radius: 4px;
}

.ldc-install-steps {
    width: 100%;
    margin: 10px 0 0;
    padding: 0 0 0 1.6em;
    font-size: 12.5px;
    line-height: 1.6;
    color: var(--ldc-text);
}
.ldc-install-steps li { margin-bottom: 7px; }
.ldc-install-steps li:last-child { margin-bottom: 0; }
.ldc-install-steps li::marker {
    color: var(--ldc-accent-ink);
    font-weight: 700;
}
.ldc-install-steps strong { color: var(--ldc-red-ink); }
.ldc-install-done {
    width: 100%;
    margin: 9px 0 0 0;
    padding-top: 8px;
    border-top: 1px solid var(--ldc-border);
    font-size: 12px;
    line-height: 1.5;
    color: var(--ldc-text-muted);
}
/* The "your version is different" line: present, and clearly an aside
   rather than another thing to do. */
.ldc-install-note {
    width: 100%;
    margin: 6px 0 0;
    font-size: 11.5px;
    line-height: 1.5;
    color: var(--ldc-text-muted);
    font-style: italic;
}
.ldc-install-actions { width: 100%; display: flex; gap: 8px; align-items: center; margin-top: 10px; }

/* The box is taller than the old one-liner, so on a short phone it gets a
   ceiling and scrolls inside itself rather than covering the whole screen. */
.ldc-install-bar { max-height: min(70vh, 460px); overflow-y: auto; }
.ldc-install-actions {
    display: flex;
    gap: 8px;
    align-items: center;
}
.ldc-install-go {
    font-family: var(--ldc-font-display);
    border: none;
    background: var(--ldc-red);
    color: var(--ldc-on-accent);
    font-weight: 700;
    font-size: 13px;
    padding: 9px 16px;
    border-radius: 999px;
    cursor: pointer;
}
.ldc-install-later {
    font-family: var(--ldc-font-display);
    /* On iOS and Mac Safari there is no install button beside it, so this is
       the only control in the box -- a bare word does not read as one. */
    border: 1px solid var(--ldc-border-strong);
    background: none;
    color: var(--ldc-text-soft);
    font-weight: 600;
    font-size: 13px;
    padding: 8px 16px;
    border-radius: 999px;
    cursor: pointer;
}

/* ==========================================================================
   "A NEW VERSION IS READY"
   Sits where the install bar sits, and for the same reason: it is the app
   speaking about itself, not about the page. It never appears in an app that
   has nothing newer to offer, and it never does anything on its own -- one
   button reloads, the other dismisses, and ignoring it costs nothing.
   ========================================================================== */
.ldc-update-bar {
    position: fixed;
    left: 12px;
    right: 12px;
    bottom: calc(var(--ldc-bottomnav-h) + 12px + env(safe-area-inset-bottom, 0px));
    z-index: 10000;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border-radius: 14px;
    background: var(--ldc-card-bg);
    border: 1px solid var(--ldc-border-strong);
    box-shadow: 0 6px 24px rgba(0, 0, 0, .16);
}
@media (min-width: 1025px) {
    /* no bottom bar on a wide screen, so nothing to clear */
    .ldc-update-bar { left: auto; right: 16px; bottom: 16px; max-width: 380px; }
}
.ldc-update-text {
    flex: 1 1 auto;
    font-size: 13px;
    font-weight: 600;
    color: var(--ldc-text);
    line-height: 1.4;
}
.ldc-update-go {
    flex: 0 0 auto;
    font-family: var(--ldc-font-display);
    border: none;
    background: var(--ldc-red);
    color: var(--ldc-on-accent);
    font-weight: 700;
    font-size: 13px;
    padding: 8px 16px;
    border-radius: 999px;
    cursor: pointer;
}
.ldc-update-close {
    flex: 0 0 auto;
    /* 32px is below the 44px target the rest of the suite keeps, so the tap
       area is pushed back out with padding the glyph does not fill */
    min-width: 44px;
    min-height: 44px;
    border: none;
    background: none;
    color: var(--ldc-text-muted);
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
}
.ldc-update-close:hover,
.ldc-update-close:focus-visible { color: var(--ldc-text); }

/* ==========================================================================
   DASHBOARD  [lamduan_dashboard]
   ========================================================================== */

/* --- the day strip -------------------------------------------------------
   Seven cells, Sunday first, sized to fit 360px without scrolling: the whole
   week has to be visible at once or it stops being a strip and becomes a
   carousel nobody scrolls. Future days are dimmed and are spans, not links.
   ------------------------------------------------------------------------- */
.ldc-daystrip {
    display: flex;
    align-items: stretch;
    gap: 2px;
    margin: 0 0 18px;
    padding: 6px 4px;
    border: 1px solid var(--ldc-border);
    border-radius: var(--ldc-radius);
    background: var(--ldc-card-bg);
}
.ldc-daystrip-days {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
    flex: 1 1 auto;
    min-width: 0;
    list-style: none;
    margin: 0;
    padding: 0;
}
.ldc-daystrip-days > li { min-width: 0; }

.ldc-day {
    /* flex, not block, so the clip-pad margins below cannot collapse into one
       another: two adjacent -0.3em margins in block flow collapse to a single
       -0.3em and the cell grows. Flex adds them, which is the arithmetic the
       padding was cancelled against. */
    display: flex;
    flex-direction: column;
    min-width: 0;
    padding: 4px 0 6px;
    border: 2px solid transparent;
    border-radius: 12px;
    text-align: center;
    text-decoration: none;
    color: var(--ldc-text);
}
/* The month chip has to sit inside its own column, not spill over the day
   either side of it, or it stops reading as a label on that day. Every cell
   reserves the row whether it has a chip or not, so the day numbers stay on
   one line across the week. */
.ldc-day-chip {
    display: block;
    /* 15px on a 9px font is line-height 1.67, which is enough for มิ.ย. and
       มี.ค.: the Thai months abbreviate to vowels above the consonant and
       never to a tone mark on top of one. test/thaimarks.php holds the case. */
    height: 15px;
    line-height: 15px;
    font-size: 9px;
    font-weight: 700;
    color: var(--ldc-on-accent);
    white-space: nowrap;
}
.ldc-day-chip:not(:empty) {
    background: var(--ldc-red);
    border-radius: 999px;
    margin: 0 auto 1px;
    padding: 0 4px;
    width: -moz-fit-content;
    width: fit-content;
    max-width: 100%;
    overflow: hidden;
}
.ldc-day-name {
    display: block;
    font-size: 11px;
    font-weight: 600;
    color: var(--ldc-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    /* clip-rect breathing room for Thai tone marks; see --ldc-clip-pad */
    padding-top: var(--ldc-clip-pad);
    padding-bottom: var(--ldc-clip-pad);
    margin-top: calc(-1 * var(--ldc-clip-pad));
    margin-bottom: calc(-1 * var(--ldc-clip-pad));
}
.ldc-day-num {
    display: block;
    font-family: var(--ldc-font-display);
    font-size: 17px;
    font-weight: 700;
    line-height: 1.25;
    font-variant-numeric: tabular-nums;
}
.ldc-day.is-today .ldc-day-name { color: var(--ldc-red-ink); }
.ldc-day.is-selected {
    border-color: var(--ldc-red);
    background: var(--ldc-surface-accent);
}
.ldc-day.is-selected .ldc-day-num { color: var(--ldc-red-ink); }
.ldc-day.is-future { opacity: .38; cursor: default; }

.ldc-daystrip-arrow {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    border-radius: 12px;
    text-decoration: none;
    font-size: 20px;
    line-height: 1;
    color: var(--ldc-red-ink);
}
.ldc-daystrip-arrow.is-off { color: var(--ldc-text-muted); opacity: .3; }

.ldc-back-today { margin-left: 8px; font-size: 13px; }

/* The caption under the strip on a module page. Sits tight to the strip it
   belongs to rather than floating between it and the first card. */
.ldc-daystrip-caption {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0 4px;
    margin: -12px 0 18px;
    font-size: 14px;
    color: var(--ldc-text-muted);
}
.ldc-daystrip-caption strong { color: var(--ldc-text); font-weight: 600; }

@media (max-width: 380px) {
    .ldc-daystrip { padding: 6px 2px; }
    .ldc-daystrip-arrow { width: 20px; font-size: 18px; }
    .ldc-day-num { font-size: 16px; }
    .ldc-day-name { font-size: 10px; }
}

.ldc-dash-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
}
@media (max-width: 700px) {
    .ldc-dash-grid { grid-template-columns: 1fr; }
}
.ldc-dash-card { margin-bottom: 0; }

.ldc-dash-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    padding-bottom: 10px;
    margin-bottom: 12px;
    border-bottom: 1px solid var(--ldc-border);
}
.ldc-dash-title {
    font-family: var(--ldc-font-display);
    font-weight: 600;
    font-size: 15px;
    color: var(--ldc-red-ink);
}
.ldc-dash-icon { margin-right: 6px; }

.ldc-dash-body .ldc-stat-grid { grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); }
.ldc-dash-body .ldc-btn { margin-top: 12px; }
.ldc-dash-body p { margin: 0 0 8px; font-size: 13px; }

.ldc-dash-welcome p {
    font-size: 14px;
    line-height: 1.6;
    color: var(--ldc-text);
    margin: 0 0 14px;
}

.ldc-dash-line {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    font-size: 13px;
    padding: 4px 0;
}
.ldc-dash-line strong {
    font-family: var(--ldc-font-display);
    font-variant-numeric: tabular-nums;
    font-size: 15px;
}
.ldc-dash-empty {
    font-size: 13px;
    color: var(--ldc-text-muted);
    padding: 6px 0 2px;
}

/* ==========================================================================
   EXPORT PAGE
   ========================================================================== */
.ldc-export-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--ldc-border);
}
.ldc-export-row:last-of-type { border-bottom: none; }
.ldc-export-name {
    font-family: var(--ldc-font-display);
    font-weight: 600;
    font-size: 14px;
}
.ldc-export-name .ldw-muted {
    display: block;
    font-family: var(--ldc-font-body);
    font-weight: 400;
    font-size: 11px;
    color: var(--ldc-text-muted);
}
.ldc-btn-sm {
    padding: 7px 14px;
    font-size: 13px;
    white-space: nowrap;
}
.ldc-export .ldc-card p { font-size: 14px; line-height: 1.6; margin: 0 0 12px; }

/* ==========================================================================
   LEGAL PAGES + FOOTER
   ========================================================================== */
.ldc-legal .ldc-manual-body p { margin: 0 0 12px; }
.ldc-legal .ldc-manual-body ul { margin: 0 0 12px; padding-left: 22px; }
.ldc-legal .ldc-manual-body li { margin-bottom: 7px; }
.ldc-legal .ldc-manual-body h4 { color: var(--ldc-red-ink); font-size: 14px; margin: 16px 0 8px; }
.ldc-legal-footer {
    text-align: center;
    font-size: 12px;
    color: var(--ldc-text-muted);
    margin: 4px 0 0;
}

.ldc-footer {
    max-width: 720px;
    margin: 0 auto;
    padding: 24px 16px 32px;
    text-align: center;
    border-top: 1px solid var(--ldc-border);
}
@media (max-width: 1024px) {
    /* The body reserves the nav now, so the footer only needs ordinary
       breathing room. It used to add the nav height again, which left a
       finger-and-a-half of empty cream at the end of every page. */
    .ldc-footer { padding-bottom: 28px; }
}
.ldc-footer-links {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px 18px;
    margin-bottom: 10px;
}
.ldc-footer-links a {
    font-family: var(--ldc-font-display);
    font-size: 13px;
    font-weight: 600;
    color: var(--ldc-text-muted);
    text-decoration: none;
}
.ldc-footer-links a:hover { color: var(--ldc-red-ink); }
.ldc-footer-note {
    font-size: 12px;
    color: var(--ldc-text-muted);
    margin: 0;
    line-height: 1.5;
}

/* ---- consent-withdrawn banner ---- */
.ldc-consent-banner {
    max-width: 720px;
    margin: 16px auto 0;
    background: var(--ldc-surface-alert);
    border: 1px solid var(--ldc-red);
    border-radius: var(--ldc-radius);
    padding: 14px 16px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 14px;
    font-size: 13px;
    line-height: 1.5;
}
.ldc-consent-banner strong {
    font-family: var(--ldc-font-display);
    color: var(--ldc-red-ink);
    width: 100%;
}
.ldc-consent-banner span { flex: 1; min-width: 220px; color: var(--ldc-text); }

/* ==========================================================================
   MOBILE INPUT SIZING

   Two separate causes of the same symptom on phones:
   1. iOS gives date/time inputs an intrinsic width of their own and centres
      the value, so they push past a 100%-wide container.
   2. A grid item's default min-width is auto, not 0, so any item with wide
      content stretches its whole column ("grid blowout").
   Both are fixed here once, for every form in the suite.
   ========================================================================== */
.ldc-form input[type="date"],
.ldc-form input[type="time"],
.ldc-form input[type="datetime-local"] {
    -webkit-appearance: none;
    appearance: none;
    display: block;
    width: 100%;
    min-width: 0;
    max-width: 100%;
    text-align: left;
    /* iOS ignores the shared font stack on these controls without this */
    font-family: var(--ldc-font-body);
}
/* the native picker button must not be able to widen the field either */
.ldc-form input[type="date"]::-webkit-date-and-time-value,
.ldc-form input[type="time"]::-webkit-date-and-time-value,
.ldc-form input[type="datetime-local"]::-webkit-date-and-time-value {
    text-align: left;
    min-width: 0;
}
.ldc-form input[type="date"]::-webkit-calendar-picker-indicator,
.ldc-form input[type="time"]::-webkit-calendar-picker-indicator,
.ldc-form input[type="datetime-local"]::-webkit-calendar-picker-indicator {
    margin-left: 4px;
}

/* grid children may shrink below their content width */
.ldc-row-2 > *,
.ldc-dash-grid > *,
.ldc-stat-grid > *,
.ldn-macro-inputs > *,
.ldn-calc-row > *,
.lde-zone-inputs > * {
    min-width: 0;
}

/* last-resort guard: nothing inside a Lamduan page may push the page sideways */
.ldc-page { overflow-x: clip; }

/* The greeting badge. It sits on the baseline of a heading that can wrap, so
   it is inline-block and never becomes a line-break opportunity of its own. */
.ldc-greet-icon {
    display: inline-block;
    white-space: nowrap;
    cursor: default;
}

/* ==========================================================================
   APP SHELL — what makes a page stop feeling like a web page on a phone

   Everything in this block is scoped to <= 1024px. The desktop layout is
   untouched: on a laptop the browser chrome is the frame, and pretending
   otherwise just wastes screen.
   ========================================================================== */

/* -- 1. Inputs at 16px --------------------------------------------------
   Safari on iOS zooms the whole page in when a focused input is smaller than
   16px, then leaves you scrolled sideways. Nothing else on this list breaks
   the illusion faster, and nothing else is a one-line fix. */
@media (max-width: 1024px) {
    /* !important is deliberate and load-order-proof. This is not styling, it
       is a platform behaviour fix: any module stylesheet that later sets 14px
       on one of its own selects silently brings the zoom bug back, and the
       person who wrote that rule would have no reason to suspect it. */
    input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]),
    select,
    textarea {
        font-size: 16px !important;
    }
    .ldc-form input[type="text"],
    .ldc-form input[type="email"],
    .ldc-form input[type="password"],
    .ldc-form input[type="number"],
    .ldc-form input[type="date"],
    .ldc-form input[type="time"],
    .ldc-form input[type="datetime-local"],
    .ldc-form select,
    .ldc-form textarea,
    .ldc-field input,
    .ldc-field select {
        padding: 13px 14px;
        border-radius: 12px;
        min-height: 50px;
    }
    .ldc-form textarea { min-height: 88px; }
}

/* -- 2. Touch behaviour -------------------------------------------------- */
@media (max-width: 1024px) {
    html {
        /* `contain` stops scroll chaining but leaves pull-to-refresh alone.
           Killing pull-to-refresh in a browser tab takes away a gesture the
           person expects to have, so the harder `none` is applied only when
           the site is actually running as an installed app. */
        overscroll-behavior-y: contain;
    }
    body.ldc-app,
    body.ldc-app > * {
        overscroll-behavior-y: none;
    }
    body {
        -webkit-tap-highlight-color: transparent;
        -webkit-text-size-adjust: 100%;
    }
    /* Chrome is furniture and should not be selectable; content still is, so
       a weight or a note can be copied out. */
    .ldc-topbar, .ldc-bottomnav, .ldc-sheet, .ldc-btn, .ldc-linkbtn,
    .ldc-card-title, .ldc-stat-label, .ldc-nav-label {
        -webkit-user-select: none;
        user-select: none;
    }
    /* Press feedback. A control that does nothing under the thumb until the
       next page paints reads as a broken web page, not a fast one. */
    .ldc-btn:active,
    .ldc-bottomnav-link:active,
    .ldc-sheet-link:active,
    .ldc-dash-card:active {
        transform: scale(.975);
        opacity: .9;
    }
    .ldc-btn, .ldc-bottomnav-link, .ldc-sheet-link, .ldc-dash-card {
        transition: transform .12s ease, opacity .12s ease;
    }
    .ldc-btn { min-height: 50px; }
    .ldc-btn-block { width: 100%; }
    .ldc-linkbtn { min-height: 44px; display: inline-flex; align-items: center; }
}

/* -- 3. Header that gets out of the way ---------------------------------- */
/* -- 4. The sheet -------------------------------------------------------- */
.ldc-sheet-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(60, 47, 34, .38);
    z-index: 10000;
    opacity: 0;
    transition: opacity .22s ease;
}
.ldc-sheet-backdrop.is-open { opacity: 1; }

.ldc-sheet {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 10001;
    background: var(--ldc-card-bg);
    border-radius: 20px 20px 0 0;
    padding: 8px 12px calc(16px + env(safe-area-inset-bottom, 0px));
    box-shadow: 0 -8px 30px rgba(60, 47, 34, .18);
    transform: translateY(100%);
    transition: transform .26s cubic-bezier(.32, .72, 0, 1);
    max-height: 80vh;
    overflow-y: auto;
}
.ldc-sheet.is-open { transform: translateY(0); }

.ldc-sheet-grip {
    width: 40px;
    height: 4px;
    border-radius: 4px;
    background: var(--ldc-border);
    margin: 4px auto 10px;
}
.ldc-sheet-link {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 10px;
    border-radius: 12px;
    text-decoration: none;
    color: var(--ldc-text);
    font-weight: 600;
    min-height: 52px;
}
.ldc-sheet-link.is-active { color: var(--ldc-red-ink); background: var(--ldc-bg); }
.ldc-sheet-icon { font-size: 22px; line-height: 1; width: 26px; text-align: center; }
.ldc-sheet-rule { border: 0; border-top: 1px solid var(--ldc-border); margin: 8px 10px; }

/* On desktop the sheet is a dropdown hanging off the button, not a panel
   sliding up from the bottom of a 27-inch screen. */
@media (min-width: 1025px) {
    .ldc-sheet {
        position: absolute;
        left: auto;
        right: 16px;
        bottom: auto;
        top: 64px;
        width: 280px;
        border-radius: 14px;
        transform: translateY(-8px);
        opacity: 0;
        pointer-events: none;
    }
    .ldc-sheet.is-open { transform: translateY(0); opacity: 1; pointer-events: auto; }
    .ldc-sheet-grip { display: none; }
    .ldc-sheet-backdrop { background: transparent; }
}

/* -- 5. Bottom bar ------------------------------------------------------- */
@media (max-width: 1024px) {
    .ldc-bottomnav {
        background: var(--ldc-card-bg);
    }
    /* frosted only where the blur works, so content scrolling under the bar
       reads as depth rather than as a bar that lost its background */
    @supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
        .ldc-bottomnav {
            background: var(--ldc-glass);
            -webkit-backdrop-filter: saturate(180%) blur(14px);
            backdrop-filter: saturate(180%) blur(14px);
        }
    }
    .ldc-bottomnav-link {
        font-size: 10.5px;
        gap: 3px;
        padding-top: 2px;
        position: relative;
    }
    /* The active pill is the icon's own background. Drawing it as an absolutely
       positioned ::before inside a flex column put it wherever the static
       position happened to land -- a pale blob floating above the icon. */
    .ldc-bottomnav-link .ldc-nav-icon {
        font-size: 22px;
        display: flex;
        align-items: center;
        justify-content: center;
        width: 54px;
        height: 30px;
        border-radius: 999px;
        transition: background-color .18s ease;
    }
    .ldc-bottomnav-link.is-active .ldc-nav-icon { background: var(--ldc-nav-pill); }
}

/* -- 6. Cards and page rhythm -------------------------------------------- */
@media (max-width: 1024px) {
    .ldc-page {
        padding-left: 14px;
        padding-right: 14px;
    }
    .ldc-card {
        border-radius: 18px;
        padding: 16px 16px 18px;
        box-shadow: 0 1px 2px rgba(60, 47, 34, .05), 0 6px 18px rgba(60, 47, 34, .05);
        border: 0;
    }
    .ldc-page > h1 {
        font-size: 1.7rem;
        line-height: 1.25;
        letter-spacing: -.01em;
        margin-bottom: 2px;
    }
    .ldc-subtitle { margin-bottom: 16px; }
    .ldc-stat {
        border-radius: 14px;
        padding: 12px 14px;
    }
    .ldc-stat-value { font-size: 1.5rem; }

    /* Two up, always. auto-fit will squeeze a third column onto a 390px
       screen the moment the padding shrinks, and then every label wraps to
       two lines and the tiles stop being glanceable. */
    .ldc-stat-grid,
    .ldc-dash-body .ldc-stat-grid {
        grid-template-columns: 1fr 1fr;
    }

    /* Keep the name and its level badge on the same line: an emoji stranded
       alone on line two reads as a rendering fault, not a flourish. */
    .ldc-greet-name { white-space: nowrap; }
}

/* -- 7. Hints behind an (i) ---------------------------------------------- */
.ldc-hint-btn {
    appearance: none;
    border: 0;
    background: transparent;
    color: var(--ldc-link);
    font: inherit;
    font-size: 15px;
    line-height: 1;
    cursor: pointer;
    padding: 6px;
    margin-left: 4px;
    border-radius: 50%;
    min-width: 30px;
    min-height: 30px;
    vertical-align: middle;
}
.ldc-hint-btn[aria-expanded="true"] { background: var(--ldc-surface-cool); }

/* Not scoped to <label> any more: a hint may name its own owner with
   data-ldc-hint-for, and that owner is often a heading rather than a label --
   the title of the food calculator, for one. Scoped to the tag, the ⓘ landed
   on a block element with no flex on it and sat on its own line below the
   title it belonged to. */
.ldc-label-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

/* Collapsed by default only once the script has taken over: with JS off the
   hints stay exactly where they were, which is the whole point of doing this
   as an enhancement rather than by deleting them from the markup. */
.ldc-hints-collapsible .ldc-hint[hidden] { display: none; }
.ldc-hints-collapsible .ldc-hint.is-revealed {
    display: block;
    background: var(--ldc-surface-soft);
    border-left: 3px solid var(--ldc-teal);
    border-radius: 0 8px 8px 0;
    padding: 8px 10px;
    margin-top: 6px;
}

@media (prefers-reduced-motion: reduce) {
    .ldc-topbar, .ldc-sheet, .ldc-sheet-backdrop,
    .ldc-btn, .ldc-bottomnav-link, .ldc-sheet-link, .ldc-dash-card {
        transition: none !important;
    }
}

/* language row inside the sheet (mobile only -- on desktop it stays in the bar) */
.ldc-sheet-lang {
    display: none;
    align-items: center;
    justify-content: space-between;
    padding: 10px 10px 14px;
}
.ldc-sheet-lang-label { font-weight: 600; color: var(--ldc-text-muted); }
/* The switch is absolutely positioned inside the desktop header; in the sheet
   it has to sit in the flow or it floats off over the links below. */
.ldc-sheet-lang .ldc-langswitch {
    position: static;
    transform: none;
    right: auto;
    top: auto;
}
@media (max-width: 1024px) {
    .ldc-sheet-lang { display: flex; }
}
@media (min-width: 1025px) {
    .ldc-sheet-lang + .ldc-sheet-rule { display: none; }
}

/* ==========================================================================
   LIST ROWS
   The shape every phone app uses for a list of records: a leading icon, a
   title with a quiet second line, and the number that matters pinned to the
   right edge where the eye can run down a column of them.

   Lives in Core so weight, food, training and fasting all get the same row
   instead of four near-misses.
   ========================================================================== */
.ldc-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 2px;
    border-bottom: 1px solid var(--ldc-border);
    min-height: 60px;
}
/* ---- [hidden] has to actually hide -------------------------------------
   The browser's own rule is [hidden]{display:none}, which any class rule that
   sets a display of its own outranks -- so `el.hidden = true` on something
   styled `display:inline-block` leaves it on screen, and the script that set
   it has no way to tell. That is how the supplement rows came to flash their
   "ดูรายละเอียด" link while it was supposed to be hidden. State the winner
   once, here, rather than patching it per class as it is discovered. */
[hidden] { display: none !important; }

.ldc-row:last-child { border-bottom: 0; }

.ldc-row-icon {
    flex: 0 0 42px;
    width: 42px;
    height: 42px;
    border-radius: 13px;
    background: var(--ldc-bg);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 21px;
    line-height: 1;
}
.ldc-row-main {
    flex: 1 1 auto;
    min-width: 0;
    /* Column flex rather than block flow: the title's and the sub's clip-pad
       margins have to add up, and adjacent block margins collapse instead. */
    display: flex;
    flex-direction: column;
}
/* ---- Thai marks and boxes that clip ---------------------------------------
   Thai stacks a vowel and then a tone mark above the consonant, so the ink of
   a word like น้ำหนัก rises higher than the font's own ascent: IBM Plex Sans
   Thai needs line-height 1.6 at weight 400 and 1.71 at 700 before that ink
   fits inside the line box. Any box that clips -- ellipsis truncation, a
   line-clamp -- therefore shaves the tone marks off, which is what turns
   เฉลี่ย into เฉลย on screen.

   Loosening every line in the app to 1.7 would be the wrong trade. Instead a
   clipping box grows its clip rect by --ldc-clip-pad and gives the same
   amount straight back as negative margin, so the ink survives and nothing
   moves. Add both lines together, or the layout shifts. */

/* Both are spans in the markup, so they need display:block -- left inline
   they run together on one line and the value gets shoved out of the row. */
.ldc-row-title {
    display: block;
    font-weight: 600;
    line-height: 1.35;
    /* Two lines, then ellipsis. A single clamped line cuts a date range in
       half, which is worse than the wrap it was meant to prevent. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    /* clip-rect breathing room for Thai tone marks; see --ldc-clip-pad */
    padding-top: var(--ldc-clip-pad);
    padding-bottom: var(--ldc-clip-pad);
    margin-top: calc(-1 * var(--ldc-clip-pad));
    margin-bottom: calc(-1 * var(--ldc-clip-pad));
}
.ldc-row-sub {
    display: block;
    font-size: .8rem;
    color: var(--ldc-text-muted);
    line-height: 1.4;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    /* clip-rect breathing room for Thai tone marks; see --ldc-clip-pad */
    padding-top: var(--ldc-clip-pad);
    padding-bottom: var(--ldc-clip-pad);
    margin-top: calc(-1 * var(--ldc-clip-pad));
    margin-bottom: calc(-1 * var(--ldc-clip-pad));
}
.ldc-row-value {
    flex: 0 0 auto;
    text-align: right;
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--ldc-red-ink);
    line-height: 1.15;
}
.ldc-row-unit {
    display: block;
    font-family: var(--ldc-font-body);
    font-size: .72rem;
    font-weight: 600;
    color: var(--ldc-text-muted);
}
/* The week-over-week line, under the unit.
   Right-aligned with the value it belongs to, and small enough that it reads
   as a footnote to the number rather than as a second number. */
.ldc-row-trend {
    display: block;
    margin-top: 2px;
    font-family: var(--ldc-font-body);
    font-size: .7rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    color: var(--ldc-text-muted);
}
/* --ldc-ok and --ldc-red-ink, not the brand fills: both were derived to clear
   4.5:1 as small text on every surface these themes paint. The arrow says the
   same thing as the colour, so nothing is lost where the two are hard to
   tell apart. */
.ldc-row-trend.is-up   { color: var(--ldc-ok); }
.ldc-row-trend.is-down { color: var(--ldc-red-ink); }
.ldc-row-trend.is-flat { color: var(--ldc-text-muted); }

/* a third line under the row, for macro chips and the like */
.ldc-row-extra {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    padding: 0 2px 12px 56px;
    margin-top: -8px;
    border-bottom: 1px solid var(--ldc-border);
    font-size: .8rem;
    color: var(--ldc-text-muted);
}
.ldc-row-extra:last-child { border-bottom: 0; }

/* Tables become lists on a phone: the grid lines and the cramped columns are
   what make a table look like a spreadsheet embedded in an app. */
@media (max-width: 1024px) {
    .ldc-table { border-collapse: collapse; width: 100%; }
    .ldc-table th {
        font-size: .72rem;
        text-transform: none;
        color: var(--ldc-text-muted);
        font-weight: 600;
        padding: 6px 8px;
        border: 0;
        background: transparent;
    }
    .ldc-table td {
        padding: 13px 8px;
        border: 0;
        border-bottom: 1px solid var(--ldc-border);
        font-size: .95rem;
    }
    .ldc-table tr:last-child td { border-bottom: 0; }
    /* the first column is the label, the rest are numbers */
    .ldc-table td:not(:first-child),
    .ldc-table th:not(:first-child) {
        text-align: right;
        font-variant-numeric: tabular-nums;
    }
    .ldc-table td:first-child { font-weight: 600; }
}

/* ==========================================================================
   NO TOP BAR ON A PHONE

   A masthead across the top is the single loudest "this is a web page" signal
   there is -- none of the apps this was modelled on have one. What replaces
   it is one round button wearing the member's level badge, floating over the
   content in the corner, the way those apps float their own controls.
   ========================================================================== */
@media (max-width: 1024px) {
    .ldc-topbar { display: none; }

    body,
    body.admin-bar,
    body.ldc-app {
        padding-top: env(safe-area-inset-top, 0px);
    }
    body.admin-bar { padding-top: calc(46px + env(safe-area-inset-top, 0px)); }

    /* The page's own heading is the screen title on a phone. The 56px of
       right padding was reserved for the floating menu button; the button
       lives in the bottom bar now, so the heading gets the width back --
       which matters, because Thai headings wrap badly in a narrow column. */
    .ldc-page > h1 {
        padding-top: 10px;
    }
}

/* ==========================================================================
   NO SCROLLBAR ON THE PHONE

   The point of this shell is that it does not read as a web page, and a
   permanent grey track down the right edge is the single loudest thing still
   saying "browser". Native apps have no visible track; the content itself is
   what tells you where you are.

   Hidden only up to the tablet breakpoint, and only for the page. On a
   desktop, where a mouse and not a thumb does the scrolling, taking the
   scrollbar away removes a real control -- somebody drags it, and somebody
   reads how far down the page they are from it. Scrolling still works
   everywhere either way: this hides the indicator, never the overflow.
   ========================================================================== */
@media (max-width: 1024px) {
    html {
        scrollbar-width: none;          /* Firefox */
        -ms-overflow-style: none;       /* old Edge */
    }
    html::-webkit-scrollbar,
    body::-webkit-scrollbar { width: 0; height: 0; display: none; }

    /* Panes that scroll inside the page -- the sheet, and any wide table in
       its own scroller -- lose their tracks too, for the same reason. A wide
       table keeps its horizontal overflow; only the bar stops being drawn. */
    .ldc-sheet { scrollbar-width: none; -ms-overflow-style: none; }
    .ldc-sheet::-webkit-scrollbar { width: 0; height: 0; display: none; }
}

/* ==========================================================================
   THE MENU BUTTON

   It used to float over the top-right corner of every page. That put the one
   control which reaches everything -- profile, goals, the rest of the menu --
   at the far corner from a thumb holding the phone, and it sat on top of the
   content it was floating over.

   It is the middle seat of the bottom bar now, the way every app of this
   shape places its primary control. It still wears the member's own level
   badge, so the bar says who is signed in without spending a word on it.
   ========================================================================== */
.ldc-bottomnav-menu {
    display: none;
}

@media (max-width: 1024px) {
    .ldc-bottomnav-menu {
        font-family: var(--ldc-font-display);
        flex: 1 1 0;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 2px;
        min-width: 0;
        padding: 0;
        border: 0;
        background: none;
        color: var(--ldc-nav-ink);
        font-size: 11px;
        font-weight: 600;
        cursor: pointer;
        -webkit-tap-highlight-color: transparent;
    }

    /* The badge is a filled disc so the middle seat reads as the primary
       control rather than as a fifth tab that happens to have an emoji. It
       lifts above the bar's top edge, which is what makes it a button on the
       bar rather than an item in it. */
    .ldc-bottomnav-menu-face {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 44px;
        height: 44px;
        margin-top: -18px;
        border-radius: 50%;
        background: var(--ldc-card-bg);
        border: 1px solid var(--ldc-border);
        box-shadow: 0 2px 6px rgba(60, 47, 34, .10), 0 8px 22px rgba(60, 47, 34, .10);
        font-size: 23px;
        line-height: 1;
        transition: transform .18s cubic-bezier(.34, 1.56, .64, 1);
    }

    .ldc-bottomnav-menu:active .ldc-bottomnav-menu-face { transform: scale(.9); }
    .ldc-bottomnav-menu[aria-expanded="true"] .ldc-bottomnav-menu-face { transform: rotate(90deg) scale(.92); }

    .ldc-bottomnav-menu .ldc-nav-label {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        max-width: 100%;
        /* clip-rect breathing room for Thai tone marks; see --ldc-clip-pad */
        padding-top: var(--ldc-clip-pad);
        padding-bottom: var(--ldc-clip-pad);
        margin-top: calc(-1 * var(--ldc-clip-pad));
        margin-bottom: calc(-1 * var(--ldc-clip-pad));
}

    /* The disc pokes above the bar, so the bar needs room for it and the
       shadow needs somewhere to fall. */
    .ldc-bottomnav { overflow: visible; }
}

@media (prefers-reduced-motion: reduce) {
    .ldc-bottomnav-menu-face { transition: none; }
}

/* ==========================================================================
   A SOFTER LOOK
   Rounder, warmer, less boxy -- the register the reference apps are written
   in. Colours are untouched; this is all radius, shadow and spacing.
   ========================================================================== */
@media (max-width: 1024px) {
    .ldc-card {
        border-radius: 24px;
        padding: 18px;
        border: 0;
        box-shadow: 0 1px 2px rgba(60, 47, 34, .04),
                    0 10px 26px rgba(196, 138, 61, .10);
    }
    .ldc-card + .ldc-card { margin-top: 14px; }

    /* card headings get their icon in a soft rounded tile, like the list rows */
    .ldc-card-title {
        display: flex;
        align-items: center;
        gap: 9px;
        font-size: 1.06rem;
    }

    .ldc-stat {
        border-radius: 18px;
        background: linear-gradient(160deg, var(--ldc-surface-soft) 0%, var(--ldc-surface-accent) 100%);
        border: 0;
        padding: 14px 15px;
    }
    .ldc-stat-label { font-size: .76rem; }
    .ldc-stat-value { font-size: 1.55rem; letter-spacing: -.01em; }

    .ldc-btn {
        border-radius: 999px;
        font-size: 1rem;
        letter-spacing: .01em;
        box-shadow: 0 6px 16px rgba(223, 48, 28, .18);
    }
    .ldc-btn-secondary { box-shadow: 0 6px 16px rgba(0, 183, 205, .18); }
    .ldc-btn-block { min-height: 54px; }

    .ldc-row-icon {
        border-radius: 15px;
        background: linear-gradient(160deg, var(--ldc-surface-soft) 0%, var(--ldc-surface-accent) 100%);
    }

    .ldc-page > h1 {
        font-size: 1.72rem;
        letter-spacing: -.015em;
    }

    /* the tab bar sits on a rounded shelf rather than a full-width slab */
    .ldc-bottomnav {
        border-top: 0;
        box-shadow: 0 -2px 24px rgba(60, 47, 34, .10);
    }
    .ldc-bottomnav-link .ldc-nav-icon {
        transition: background-color .18s ease, transform .18s cubic-bezier(.34, 1.56, .64, 1);
    }
    .ldc-bottomnav-link.is-active .ldc-nav-icon { transform: translateY(-2px) scale(1.06); }

    .ldc-sheet { border-radius: 26px 26px 0 0; }
    .ldc-sheet-link { border-radius: 15px; }
    .ldc-sheet-icon {
        width: 38px;
        height: 38px;
        border-radius: 13px;
        background: linear-gradient(160deg, var(--ldc-surface-soft) 0%, var(--ldc-surface-accent) 100%);
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 19px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .ldc-bottomnav-link .ldc-nav-icon { transition: none; }
}

/* ==========================================================================
   THE DESKTOP MENU BUTTON
   Only ever seen on a laptop: phones get the floating avatar instead. Kept
   here because the sheet it opens is shared between the two.
   ========================================================================== */
.ldc-menu-btn {
    appearance: none;
    border: 1px solid var(--ldc-border);
    background: var(--ldc-card-bg);
    border-radius: 12px;
    width: 44px;
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    padding: 0;
}
.ldc-menu-bars { display: block; width: 18px; }
.ldc-menu-bars span {
    display: block;
    height: 2px;
    border-radius: 2px;
    background: var(--ldc-red);
    transition: transform .2s ease, opacity .2s ease;
}
.ldc-menu-bars span + span { margin-top: 4px; }
.ldc-menu-btn[aria-expanded="true"] .ldc-menu-bars span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.ldc-menu-btn[aria-expanded="true"] .ldc-menu-bars span:nth-child(2) { opacity: 0; }
.ldc-menu-btn[aria-expanded="true"] .ldc-menu-bars span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

@media (max-width: 1024px) {
    /* the whole desktop header is gone on a phone, but be explicit */
    .ldc-menu-btn { display: none; }
}

/* Text that only screen readers need. Off-screen rather than display:none,
   because display:none takes it out of the accessibility tree too. */
.ldc-sr {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}


/* ==========================================================================
   SVG LINE WEIGHT

   Every chart in the suite drew its own grid line with the same four inline
   attributes copied into four plugins, which meant "make the lines heavier"
   was a four-file change that would drift the first time one was missed.
   The weight lives here now: charts mark their guides with .ldc-grid and
   their axis numbers with .ldc-axis-label, and this block is the only place
   either is described.

   Weights are set for a phone held at arm's length in daylight, not for a
   desktop monitor in a dark room -- thin hairlines simply vanish there.
   ========================================================================== */
.ldc-chart .ldc-grid {
    stroke: var(--ldc-border);
    stroke-width: 1.4;
    stroke-dasharray: 4 4;
}
.ldc-chart .ldc-axis-label {
    font-size: 11px;
    font-weight: 600;
    fill: var(--ldc-axis-strong);
}

/* A stroke inside a stretched SVG (preserveAspectRatio="none") is stretched
   with it, so it comes out thin on one axis and fat on the other. This keeps
   it at the width it was asked for, whatever the box does. */
.ldc-fixed-stroke { vector-effect: non-scaling-stroke; }

/* ==========================================================================
   THEME PICKER

   The swatch IS the label. Naming a colour scheme is guesswork -- "ป่าราตรี"
   tells you nothing until you have seen it -- so every option shows its four
   colours at the size they will actually appear.
   ========================================================================== */
.ldc-themeswitch {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 10px;
    margin: 4px 0 6px;
}
.ldc-theme-opt {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 12px 14px;
    border: 1.5px solid var(--ldc-border);
    border-radius: 14px;
    background: var(--ldc-card-bg);
    text-decoration: none;
    color: var(--ldc-text);
    transition: border-color .15s ease, transform .12s ease;
}
.ldc-theme-opt:active { transform: scale(.98); }
.ldc-theme-opt.is-active { border-color: var(--ldc-red); border-width: 2px; }
.ldc-theme-swatch {
    display: flex;
    height: 22px;
    border-radius: 999px;
    overflow: hidden;
    border: 1px solid var(--ldc-border);
}
.ldc-theme-swatch span { flex: 1 1 0; }
.ldc-theme-name {
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-size: .95rem;
}
.ldc-theme-opt.is-active .ldc-theme-name { color: var(--ldc-red-ink); }
.ldc-theme-note {
    font-size: .78rem;
    color: var(--ldc-text-muted);
    line-height: 1.45;
}

/* in the slide-up panel it is a row of chips, not a grid of cards */
/* Five across a 360px phone is 66px each, which is not a chip, it is a
   sliver. Two rows instead. */
.ldc-themeswitch.is-compact {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 6px;
    margin: 0;
}
.ldc-themeswitch.is-compact .ldc-theme-opt {
    min-width: 0;
    align-items: center;
    padding: 7px 8px;
    border-radius: 11px;
    gap: 3px;
}
.ldc-themeswitch.is-compact .ldc-theme-swatch { width: 100%; height: 12px; }
.ldc-themeswitch.is-compact .ldc-theme-name {
    font-size: .72rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
    /* clip-rect breathing room for Thai tone marks; see --ldc-clip-pad */
    padding-top: var(--ldc-clip-pad);
    padding-bottom: var(--ldc-clip-pad);
    margin-top: calc(-1 * var(--ldc-clip-pad));
    margin-bottom: calc(-1 * var(--ldc-clip-pad));
}
.ldc-sheet-theme {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 4px 0 10px;
}

@media (prefers-reduced-motion: reduce) {
    .ldc-theme-opt { transition: none; }
}

/* --- the slot above the cards -------------------------------------------- */
.ldc-dash-top { margin-bottom: 16px; }
.ldc-dash-top > .ldc-card { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   Drawn icons.

   They stand in a row of colour emoji, so they are sized against the font --
   1em, aligned on the text baseline like a glyph -- rather than given a fixed
   pixel box. Change the font size around one and the drawing follows, which
   is what an emoji would have done.
   -------------------------------------------------------------------------- */
.ldc-icon {
    width: 1em;
    height: 1em;
    display: inline-block;
    vertical-align: -0.14em;
    overflow: visible;
}

/* The bottom bar and the dashboard set their icon sizes on the wrapper, and
   an emoji picks that up through font-size. An SVG has to be told. */
.ldc-nav-icon .ldc-icon,
.ldc-sheet-icon .ldc-icon,
.ldc-dash-icon .ldc-icon,
.ldv-item-icon .ldc-icon,
.ldv-topic-icon .ldc-icon,
.lds-field-icon .ldc-icon,
.ldg-goal-icon .ldc-icon { width: 1em; height: 1em; }

/* ---- the missing-page list ------------------------------------------------
   Its own rules rather than .ldc-sheet-link, which lives inside the
   max-width:1024px block and would leave this list unstyled on a desktop --
   the one width where a mistyped address is most likely to be typed. */
.ldc-404-links {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 4px;
    margin: 14px 0 6px;
}
.ldc-404-link {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 52px;
    padding: 12px 10px;
    border-radius: 12px;
    text-decoration: none;
    font-weight: 600;
    color: var(--ldc-text);
}
.ldc-404-link:hover,
.ldc-404-link:focus-visible { background: var(--ldc-surface-soft); }
.ldc-404-icon { width: 26px; font-size: 22px; line-height: 1; text-align: center; flex: 0 0 auto; }
.ldc-404-home { margin: 14px 0 0; }

/* ---- pull to refresh ------------------------------------------------------
   The indicator hangs above the top edge and is pushed down by the finger.
   It sits under the safe-area inset so it clears the notch, and above every
   card but below the menu sheet, which is a dialog and outranks it. */
.ldc-ptr {
    position: fixed;
    top: calc(env(safe-area-inset-top, 0px) - 44px);
    left: 0;
    right: 0;
    display: flex;
    justify-content: center;
    z-index: 9998;
    pointer-events: none;
    transform: translateY(0);
}
.ldc-ptr.is-animating { transition: transform .22s cubic-bezier(.34, 1.2, .64, 1); }
.ldc-ptr-ring {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--ldc-card-bg);
    color: var(--ldc-red);
    box-shadow: 0 2px 6px rgba(60, 47, 34, .12), 0 8px 22px rgba(60, 47, 34, .10);
    opacity: 0;
    transition: transform .18s ease, background-color .18s ease;
}
.ldc-ptr-ring.is-armed { background: var(--ldc-surface-accent); }
.ldc-ptr.is-loading .ldc-ptr-ring {
    animation: ldc-ptr-spin .7s linear infinite;
    background: var(--ldc-card-bg);
}
@keyframes ldc-ptr-spin { to { transform: rotate(360deg); } }

/* A reader who has asked for less motion still needs to see the state; they
   just do not need it spun at them. */
@media (prefers-reduced-motion: reduce) {
    .ldc-ptr.is-animating { transition: none; }
    .ldc-ptr-ring { transition: none; }
    .ldc-ptr.is-loading .ldc-ptr-ring { animation: none; opacity: 1; }
}

/* ==========================================================================
   HELP AND CONTACT
   ========================================================================== */

/* The honeypot. Off-screen rather than display:none, because a robot worth
   defending against reads the stylesheet too and skips what is hidden --
   and because a field that is merely moved still carries its label to a
   screen reader that goes looking, which display:none would take away. */
.ldc-hp {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

.ldc-support-q {
    border-top: 1px solid var(--ldc-border);
    padding: 12px 0;
}
.ldc-support-q:first-of-type { border-top: 0; }
.ldc-support-q summary {
    cursor: pointer;
    font-family: var(--ldc-font-display);
    font-weight: 600;
    color: var(--ldc-text);
    list-style: none;
}
.ldc-support-q summary::-webkit-details-marker { display: none; }
/* A caret drawn in text, so it follows the reader's own writing direction
   and needs no image to load on a page people reach when something is
   already going wrong. */
.ldc-support-q summary::before {
    content: '+';
    display: inline-block;
    width: 1.2em;
    color: var(--ldc-red-ink);
    font-weight: 700;
}
.ldc-support-q[open] summary::before { content: '\2212'; }
.ldc-support-q p {
    margin-left: 1.2em;
}

/* Prose, not form hints.
   A 692px card sets about ninety Thai characters on a line, which is half
   again past the width the eye tracks comfortably, and the paragraph under
   the address was being set at the 12px meant for the note beside an input.
   Both are fixed by measure rather than by centring: the text keeps its left
   edge with everything else and simply stops sooner. */
.ldc-support-note,
.ldc-support-q p {
    max-width: 38em;
    margin: 6px 0 0;
    color: var(--ldc-text-muted);
    line-height: 1.6;
}
.ldc-support-note { font-size: 14px; }

/* The address is the one thing on the card a person came to act on, so it
   is shaped like something to press rather than left as bare underlined
   text -- and it breaks on the @ rather than mid-word, because an address
   split across a line has to stay readable to be typed out by hand. */
.ldc-support-mail {
    margin: 0;
}
.ldc-support-mail a {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 16px;
    border: 1px solid var(--ldc-border);
    border-radius: 999px;
    background: var(--ldc-cream);
    font-family: var(--ldc-font-display);
    font-size: 16px;
    font-weight: 600;
    color: var(--ldc-red-ink);
    text-decoration: none;
    line-height: 1.3;
    word-break: break-word;
}
.ldc-support-mail a:hover,
.ldc-support-mail a:focus-visible {
    border-color: var(--ldc-red-ink);
}
.ldc-support-mail-icon {
    display: inline-flex;
    flex: 0 0 auto;
}

/* ldv-advice */
/* ==========================================================================
   ADVICE

   Two states with very different jobs. A finding has to be readable at a
   glance and then in full. The waiting state has to look like a system
   patiently collecting, not one that failed — which is mostly a matter of
   giving it a shape and a checklist rather than a sentence of apology.

   Colour through role tokens; the brand colours are fills and borders here,
   never text.
   ========================================================================== */
.ldv-page .ldc-card + .ldc-card { margin-top: 14px; }

/* --- one finding ---------------------------------------------------------- */
.ldv-item { padding: 14px 0; }
.ldv-item + .ldv-item { border-top: 1px solid var(--ldc-border); }
.ldv-item-head {
    display: flex;
    align-items: baseline;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 6px;
}
.ldv-item-icon { font-size: 18px; flex: 0 0 auto; line-height: 1.2; }
.ldv-item-title {
    flex: 1 1 auto;
    min-width: 0;
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-size: 15px;
    line-height: 1.5;
    color: var(--ldc-text);
}
.ldv-item-sev {
    flex: 0 0 auto;
    font-size: 12px;
    font-weight: 700;
    padding: 3px 10px;
    border-radius: 999px;
    background: var(--ldc-surface-soft);
    color: var(--ldc-text);
    white-space: nowrap;
}
.ldv-item.is-watch .ldv-item-sev { background: var(--ldc-surface-warn); }
.ldv-item.is-note  .ldv-item-sev { background: var(--ldc-surface-cool); }
.ldv-item.is-good  .ldv-item-sev { background: var(--ldc-surface-ok); }
.ldv-item-body {
    margin: 0;
    font-size: 14px;
    line-height: 1.8;
    color: var(--ldc-text-soft);
}
/* On the dashboard the card holds one finding, so it needs no top padding
   and no rule above it. */
.ldc-dash-card .ldv-item:first-child { padding-top: 0; }
.ldv-more {
    margin: 4px 0 12px;
    font-size: 13px;
    color: var(--ldc-text-muted);
    text-align: center;
}

/* --- waiting for enough data ---------------------------------------------
   Deliberately not styled as a warning. Nothing has gone wrong; the answer
   is simply "not yet", and it comes with the list of what would change it. */
.ldv-waiting {
    text-align: center;
    padding: 6px 0 12px;
}
.ldv-waiting-icon { font-size: 30px; line-height: 1; margin-bottom: 6px; }
.ldv-waiting strong {
    display: block;
    font-family: var(--ldc-font-display);
    font-size: 16px;
    color: var(--ldc-text);
    margin-bottom: 4px;
}
.ldv-waiting > p {
    margin: 0 auto 14px;
    max-width: 46ch;
    font-size: 13px;
    line-height: 1.75;
    color: var(--ldc-text-muted);
}
.ldv-waiting-list {
    list-style: none;
    margin: 0;
    padding: 0;
    text-align: left;
}
.ldv-waiting-list li {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    border-radius: var(--ldc-radius-sm);
    background: var(--ldc-surface-soft);
    margin-bottom: 8px;
}
.ldv-waiting-what { font-weight: 700; font-size: 14px; color: var(--ldc-text); }
.ldv-waiting-count {
    flex: 0 0 auto;
    font-size: 13px;
    color: var(--ldc-label);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* --- what it was read from ------------------------------------------------ */
.ldv-basis .ldc-hint { margin: 0 0 10px; }
.ldv-basis .ldc-row-sub { font-variant-numeric: tabular-nums; }

.ldv-disclaimer {
    font-size: 13px;
    line-height: 1.75;
    color: var(--ldc-text-soft);
}
.ldv-disclaimer strong {
    display: block;
    color: var(--ldc-red-ink);
    margin-bottom: 4px;
    font-size: 14px;
}

@media (max-width: 400px) {
    .ldv-waiting-list li { flex-direction: column; gap: 2px; }
    .ldv-waiting-count { white-space: normal; }
}

/* --------------------------------------------------------------------------
   The wait, separated from the shortfalls.

   Both used to be rows in one list, wearing the same "N more days" shape --
   so the smallest number read as the finish line, when the 30 days of use was
   still running underneath it. The clock gets its own block, ahead of the
   list, and the list drops the "more needed" phrasing for a plain "3 of 10"
   so it cannot be mistaken for a countdown of its own.
   -------------------------------------------------------------------------- */
.ldv-waiting-clock {
    margin: 14px auto 4px;
    padding: 12px 16px;
    border-radius: var(--ldc-radius-sm);
    background: var(--ldc-surface-accent);
    text-align: center;
}

.ldv-waiting-clock-line {
    display: block;
    font-family: var(--ldc-font-display);
    font-weight: 700;
    color: var(--ldc-text);
    font-variant-numeric: tabular-nums;
}

.ldv-waiting-clock-more {
    display: block;
    margin-top: 2px;
    font-size: .88rem;
    font-weight: 600;
    color: var(--ldc-accent-ink);
    font-variant-numeric: tabular-nums;
}

.ldv-waiting-lead {
    margin: 16px 0 8px;
    font-size: .9rem;
    font-weight: 600;
    color: var(--ldc-text-muted);
    text-align: center;
}

.ldv-waiting-why {
    margin: 12px 0 0;
    font-size: .84rem;
    line-height: 1.6;
    color: var(--ldc-text-muted);
    text-align: left;
}

/* --------------------------------------------------------------------------
   Choosing what gets read.

   Two levels, and the nesting has to be visible without a word of explanation:
   an area, and the individual numbers inside it. The area is a card; its
   numbers are chips indented under it, and they dim as a group when the area
   itself is switched off -- because that is what actually happens to them.

   No script: the checkbox is moved out of sight rather than removed, so focus
   and screen readers still reach it, and `:has()` makes the card respond as
   soon as it is ticked instead of waiting for the save.
   -------------------------------------------------------------------------- */
.ldv-area {
    margin: 0 0 10px;
    padding: 4px 4px 10px;
    border: 1.5px solid var(--ldc-border);
    border-radius: 16px;
    background: var(--ldc-card-bg);
    transition: border-color .15s ease;
}

.ldv-area.is-on,
.ldv-area:has(.ldv-area-head input:checked) { border-color: var(--ldc-teal); }
.ldv-area.is-on:has(.ldv-area-head input:not(:checked)) { border-color: var(--ldc-border); }

/* Scoped to the card on purpose. These are <label> elements inside a
   .ldc-form, and `.ldc-form label { display: block }` -- one specificity point
   more than a bare `.ldv-area-head` -- flattens them: the switch collapsed to
   a 2px sliver and the chip ticks to a hairline. The component has to hold its
   shape wherever it is dropped, not only where it was born. Same lesson the
   fasting plan cards learnt. */
.ldv-topics .ldv-area-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px 8px;
    cursor: pointer;
    position: relative;
}

.ldv-topics .ldv-area-head input,
.ldv-topics .ldv-var input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    min-height: 0;
    margin: 0;
    padding: 0;
    pointer-events: none;
}

.ldv-area-icon { font-size: 1.15rem; line-height: 1; flex: 0 0 auto; }

.ldv-area-name {
    flex: 1 1 auto;
    min-width: 0;
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-size: 1rem;
    color: var(--ldc-text-muted);
}

.ldv-area.is-on .ldv-area-name,
.ldv-area:has(.ldv-area-head input:checked) .ldv-area-name { color: var(--ldc-text); }
.ldv-area.is-on:has(.ldv-area-head input:not(:checked)) .ldv-area-name { color: var(--ldc-text-muted); }

/* The switch. A track and a knob, drawn in CSS -- it has to read as ON or OFF
   from across the room, which a tick in a box does not. */
.ldv-topics .ldv-area-state {
    display: block;
    flex: 0 0 auto;
    width: 40px;
    height: 23px;
    border-radius: 999px;
    /* An explicit border as well as a fill: --ldc-track is nearly the card
       colour on the pale themes, and without an edge the switch rendered as a
       lone knob floating in space with no track behind it. */
    background: var(--ldc-track);
    border: 1px solid var(--ldc-border);
    box-sizing: border-box;
    position: relative;
    transition: background-color .18s ease, border-color .18s ease;
}

.ldv-topics .ldv-area-state::after {
    content: "";
    position: absolute;
    top: 3px;
    left: 3px;
    width: 17px;
    height: 17px;
    border-radius: 50%;
    background: var(--ldc-card-bg);
    box-shadow: 0 1px 3px rgba(60, 47, 34, .3);
    transition: transform .18s cubic-bezier(.34, 1.56, .64, 1);
}

.ldv-topics .ldv-area.is-on .ldv-area-state,
.ldv-topics .ldv-area:has(.ldv-area-head input:checked) .ldv-area-state {
    background: var(--ldc-teal);
    border-color: var(--ldc-teal);
}
.ldv-area.is-on .ldv-area-state::after,
.ldv-area:has(.ldv-area-head input:checked) .ldv-topics .ldv-area-state::after { transform: translateX(17px); }
.ldv-topics .ldv-area.is-on:has(.ldv-area-head input:not(:checked)) .ldv-area-state {
    background: var(--ldc-track);
    border-color: var(--ldc-border);
}
.ldv-area.is-on:has(.ldv-area-head input:not(:checked)) .ldv-topics .ldv-area-state::after { transform: none; }

.ldv-area-head input:focus-visible ~ .ldv-area-state {
    outline: 2px solid var(--ldc-teal);
    outline-offset: 3px;
}

/* ---- the numbers inside an area ---- */
.ldv-vars {
    display: flex;
    flex-direction: column;
    gap: 7px;
    padding: 2px 12px 0 44px;
}

/* The chip and its "i" sit on one line that never wraps, so the button can
   never end up orphaned under a long Thai label -- the chip shrinks and wraps
   its own text instead. The explanation is a sibling BELOW that line, so it
   pushes the rest down rather than floating over what you were reading; on a
   phone there is no hover, and a panel that covers the page is worse than one
   that moves it. */
.ldv-var-row { display: block; }

.ldv-var-line {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: 6px;
}

.ldv-topics .ldv-help-btn {
    flex: 0 0 auto;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 1.5px solid var(--ldc-border);
    background: var(--ldc-card-bg);
    color: var(--ldc-text-muted);
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-size: .78rem;
    line-height: 1;
    cursor: pointer;
}

.ldv-topics .ldv-help-btn input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    min-height: 0;
    margin: 0;
    padding: 0;
    pointer-events: none;
}

.ldv-var-row:has(.ldv-help-toggle:checked) .ldv-help-btn {
    border-color: var(--ldc-teal);
    background: var(--ldc-surface-accent);
    color: var(--ldc-text);
}

.ldv-help-text {
    margin: 6px 0 2px;
    padding: 9px 12px;
    border-radius: var(--ldc-radius-sm);
    background: var(--ldc-surface-soft);
    font-size: .82rem;
    font-weight: 400;
    line-height: 1.65;
    color: var(--ldc-text-muted);
}

.ldv-var-row:not(:has(.ldv-help-toggle:checked)) .ldv-help-text { display: none; }

/* Where :has() is not supported the button cannot do anything, so it is
   removed and the explanations simply stay open. Verbose beats a button that
   does nothing when pressed. */
@supports not selector(:has(*)) {
    .ldv-topics .ldv-help-btn { display: none; }
    .ldv-help-text { display: block; }
}

.ldv-topics .ldv-var {
    position: relative;
    /* Shrinkable, so a long label wraps INSIDE the chip instead of shoving
       the "i" onto a line of its own -- which read as an orphaned button
       belonging to nothing. */
    flex: 0 1 auto;
    min-width: 0;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px 6px 10px;
    border: 1.5px solid var(--ldc-border);
    border-radius: 999px;
    background: var(--ldc-card-bg);
    cursor: pointer;
    font-size: .82rem;
    font-weight: 600;
    color: var(--ldc-text-muted);
    transition: border-color .15s ease, background-color .15s ease, color .15s ease;
}

/* A small tick, so an on chip is not distinguished by colour alone. */
.ldv-topics .ldv-var::before {
    content: "";
    display: block;
    box-sizing: border-box;
    width: 13px;
    height: 13px;
    flex: 0 0 auto;
    border-radius: 4px;
    border: 1.5px solid var(--ldc-border);
    background: transparent;
}

.ldv-topics .ldv-var.is-on,
.ldv-topics .ldv-var:has(input:checked) {
    border-color: var(--ldc-teal);
    background: var(--ldc-surface-accent);
    color: var(--ldc-text);
}

.ldv-topics .ldv-var.is-on::before,
.ldv-topics .ldv-var:has(input:checked)::before {
    border-color: var(--ldc-teal);
    background: var(--ldc-teal);
    box-shadow: inset 0 0 0 2px var(--ldc-card-bg);
}

.ldv-topics .ldv-var.is-on:has(input:not(:checked)) {
    border-color: var(--ldc-border);
    background: var(--ldc-card-bg);
    color: var(--ldc-text-muted);
}

.ldv-topics .ldv-var.is-on:has(input:not(:checked))::before {
    border-color: var(--ldc-border);
    background: transparent;
    box-shadow: none;
}

.ldv-var input:focus-visible ~ .ldv-var-name {
    outline: 2px solid var(--ldc-teal);
    outline-offset: 3px;
    border-radius: 4px;
}

.ldv-topics-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 4px;
}

@media (prefers-reduced-motion: reduce) {
    .ldv-area, .ldv-area-state, .ldv-area-state::after, .ldv-var { transition: none; }
}

/* --------------------------------------------------------------------------
   The supplements, one row each.

   An honest supplement panel is mostly a list of things that do less than the
   label suggests, so the evidence grade is the loudest thing in each row --
   coloured AND worded, never colour alone.
   -------------------------------------------------------------------------- */
.ldv-supp {
    padding: 12px 0;
    border-top: 1px solid var(--ldc-border);
}

.ldv-supp:first-of-type { border-top: 0; }

.ldv-supp-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 6px;
    margin-bottom: 6px;
}

.ldv-supp-name {
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-size: 1rem;
    color: var(--ldc-text);
}

.ldv-supp-take {
    font-size: .82rem;
    font-weight: 600;
    color: var(--ldc-text-muted);
    font-variant-numeric: tabular-nums;
}

.ldv-supp-take.is-thin { color: var(--ldc-accent-ink); }

.ldv-supp-claim {
    margin: 0 0 6px;
    font-size: .86rem;
    line-height: 1.7;
    color: var(--ldc-text-muted);
}

.ldv-grade {
    display: inline-block;
    margin-right: 6px;
    padding: 1px 9px;
    border-radius: 999px;
    font-size: .72rem;
    font-weight: 700;
    white-space: nowrap;
    vertical-align: 1px;
}

.ldv-grade.is-strong   { background: var(--ldc-surface-ok);     color: var(--ldc-ok); }
.ldv-grade.is-moderate { background: var(--ldc-surface-accent); color: var(--ldc-accent-ink); }
.ldv-grade.is-weak     { background: var(--ldc-surface-warn);   color: var(--ldc-accent-ink); }
.ldv-grade.is-none     { background: var(--ldc-surface-soft);   color: var(--ldc-text-muted); }

.ldv-supp-note {
    margin: 4px 0 0;
    padding: 8px 11px;
    border-radius: var(--ldc-radius-sm);
    background: var(--ldc-surface-warn);
    font-size: .82rem;
    line-height: 1.6;
    color: var(--ldc-text);
}

/* lde-exercise */
/* Exercise Log -- only what Core's shared theme doesn't already cover.
   Zone colours live in PHP (lde_zones) so charts, chips and bars can never
   drift apart; this file only handles layout. */

.lde-zone-inputs-wrap {
    background: var(--ldc-cream);
    border: 1px dashed var(--ldc-orange);
    border-radius: var(--ldc-radius-sm);
    padding: 14px;
    margin-bottom: 14px;
}
.lde-zone-label {
    display: block;
    font-family: var(--ldc-font-display);
    font-weight: 600;
    font-size: 14px;
    color: var(--ldc-red-ink);
    margin-bottom: 4px;
}
.lde-zone-inputs-wrap .ldc-hint { margin-bottom: 12px; }

.lde-zone-inputs {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 8px;
}
@media (max-width: 520px) {
    .lde-zone-inputs { grid-template-columns: repeat(3, 1fr); }
}
.lde-zone-field {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
}
.lde-zone-field input {
    width: 100%;
    text-align: center;
    padding: 9px 6px;
    border: 1px solid var(--ldc-border);
    border-radius: var(--ldc-radius-sm);
    font-size: 15px;
    font-variant-numeric: tabular-nums;
    background: var(--ldc-card-bg);
    color: var(--ldc-text);
}

.lde-zone-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 34px;
    height: 22px;
    padding: 0 8px;
    border-radius: 999px;
    font-family: var(--ldc-font-display);
    font-size: 12px;
    font-weight: 700;
    color: var(--ldc-text);
    flex: none;
}

.lde-live-total {
    margin: 12px 0 0;
    font-size: 13px;
    color: var(--ldc-text-muted);
    text-align: center;
}
.lde-live-total strong {
    font-family: var(--ldc-font-display);
    font-size: 18px;
    color: var(--ldc-red-ink);
}

/* ---- zone reference rows ---- */
.lde-zone-row {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    padding: 9px 0;
    border-bottom: 1px solid var(--ldc-border);
}
.lde-zone-row:last-child { border-bottom: none; }
.lde-zone-name {
    font-family: var(--ldc-font-display);
    font-weight: 600;
    font-size: 13px;
}
.lde-zone-desc {
    font-size: 12px;
    color: var(--ldc-text-muted);
    line-height: 1.45;
    margin-top: 2px;
}

/* ---- stacked zone bar ---- */
.lde-zonebar {
    display: flex;
    height: 12px;
    border-radius: 999px;
    overflow: hidden;
    margin: 12px 0 8px;
    background: var(--ldc-cream);
}
.lde-zonebar .lde-seg { display: block; height: 100%; }

.lde-zonelegend {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
    font-size: 12px;
    color: var(--ldc-text-muted);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.lde-zonelegend.lde-legend-center { justify-content: center; padding: 4px 0 2px; }
.lde-zonelegend span.is-empty { opacity: .35; }
.lde-zonelegend strong { color: var(--ldc-text); margin-left: 3px; }

.lde-dot {
    display: inline-block;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    margin-right: 5px;
}

/* ---- session cards ---- */

.lde-chart-axis {
    display: flex;
    justify-content: space-between;
    font-size: 11px;
    color: var(--ldc-label);
    padding: 2px 2px 4px;
}

.lde-session {
    border: 1px solid var(--ldc-border);
    border-radius: var(--ldc-radius-sm);
    padding: 12px;
    margin-bottom: 10px;
    background: var(--ldc-card-bg);
}
.lde-session-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 10px;
}
.lde-session-name {
    font-family: var(--ldc-font-display);
    font-weight: 600;
    font-size: 14px;
}
.lde-session-name .ldw-muted { margin-left: 6px; }
.lde-session-total {
    font-family: var(--ldc-font-display);
    font-weight: 700;
    color: var(--ldc-red-ink);
    white-space: nowrap;
}
.lde-session-detail { font-size: 13px; margin-top: 2px; }
.lde-session-note { margin-top: 6px; }
.lde-session-actions { margin-top: 8px; }
.lde-delete-form { display: inline; margin: 0; }

.lde-page .ldw-muted {
    color: var(--ldc-text-muted);
    font-size: 11px;
    font-weight: 400;
}

/* ldf-fasting */
/* Fasting timer -- only what Core's shared theme doesn't already cover. */

.ldf-timer-card {
    text-align: center;
    padding: 24px 18px 20px;
}
.ldf-timer-card.is-fasting { border-color: var(--ldc-teal); }
.ldf-timer-card.is-reached { border-color: var(--ldc-teal); background: var(--ldc-surface-cool); }

.ldf-state-label {
    font-family: var(--ldc-font-display);
    font-weight: 600;
    font-size: 14px;
    color: var(--ldc-text-muted);
    letter-spacing: .02em;
}

.ldf-clock {
    font-family: var(--ldc-font-display);
    font-variant-numeric: tabular-nums;
    font-size: 46px;
    font-weight: 700;
    line-height: 1.1;
    color: var(--ldc-red-ink);
    margin: 6px 0 4px;
}
@media (max-width: 380px) {
    .ldf-clock { font-size: 38px; }
}
.ldf-timer-card.is-fasting .ldf-clock { color: var(--ldc-link); }

.ldf-sub {
    font-size: 13px;
    color: var(--ldc-text-muted);
    margin-bottom: 14px;
}

.ldf-progress {
    height: 10px;
    border-radius: 999px;
    background: var(--ldc-cream);
    overflow: hidden;
    margin: 0 0 18px;
}
.ldf-progress span {
    display: block;
    height: 100%;
    background: linear-gradient(90deg, var(--ldc-teal), var(--ldc-orange));
    transition: width .4s ease;
}

.ldf-big-btn {
    font-size: 16px;
    padding: 16px 20px;
}
.ldf-protocol-field { text-align: left; margin-bottom: 14px; }
.ldf-protocol-field select {
    width: 100%;
    padding: 10px 12px;
    border: 1px solid var(--ldc-border);
    border-radius: var(--ldc-radius-sm);
    font-size: 15px;
    background: var(--ldc-card-bg);
    color: var(--ldc-text);
}
.ldf-action-form .ldc-hint { text-align: left; }

/* ---- chart ---- */
.ldf-chart-axis {
    display: flex;
    justify-content: space-between;
    font-size: 11px;
    color: var(--ldc-label);
    padding: 2px 2px 4px;
}
.ldf-legend {
    display: flex;
    justify-content: center;
    gap: 16px;
    font-size: 12px;
    font-weight: 600;
    color: var(--ldc-text-muted);
    padding-bottom: 2px;
}
.ldf-dot {
    display: inline-block;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    margin-right: 5px;
}

/* ---- history ---- */
.ldf-row {
    border: 1px solid var(--ldc-border);
    border-radius: var(--ldc-radius-sm);
    padding: 11px 13px;
    margin-bottom: 10px;
    background: var(--ldc-card-bg);
}
.ldf-row.is-open { border-color: var(--ldc-teal); background: var(--ldc-surface-cool); }
.ldf-row-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 10px;
}
.ldf-row-when {
    font-family: var(--ldc-font-display);
    font-weight: 600;
    font-size: 13px;
}
.ldf-row-hours {
    font-family: var(--ldc-font-display);
    font-weight: 700;
    color: var(--ldc-text-muted);
    white-space: nowrap;
}
.ldf-row-hours.is-hit { color: var(--ldc-link); }
.ldf-row-actions { margin-top: 8px; }
.ldf-delete-form { display: inline; margin: 0; }
.ldf-edit-form { margin-top: 12px; }

.ldf-page .ldw-muted {
    color: var(--ldc-text-muted);
    font-size: 11px;
    font-weight: 400;
}

/* the timer reused inside a dashboard card: no card chrome of its own */
.ldf-dash-timer {
    border: none;
    box-shadow: none;
    background: none;
    padding: 0;
    margin: 0;
    text-align: center;
}
/* Every clock in the module sits inside a ring, so `.ldf-ring .ldf-clock`
   below out-orders this at equal specificity and it has never applied.
   Kept only as the size a clock outside a ring would take. */
.ldf-dash-timer .ldf-clock { font-size: 34px; }
/* the ring is smaller inside a dashboard card than on the fasting page --
   the card is one of five on the overview, not the whole screen */
.ldf-dash-timer .ldf-ring { max-width: 180px; }
.ldf-dash-timer .ldf-ring-next { font-size: 30px; }
/* The eating window: the time the next fast starts, in place of a clock that
   would sit frozen at 00:00:00 -- which is what made the ring look broken. */
.ldf-ring-next {
    font-family: var(--ldc-font-display);
    font-size: 34px;
    font-weight: 700;
    line-height: 1.1;
    color: var(--ldc-text);
    margin: 2px 0;
    font-variant-numeric: tabular-nums;
}
.ldf-dash-timer .ldf-progress { margin-bottom: 14px; }
.ldf-dash-streak {
    font-size: 13px;
    color: var(--ldc-text-muted);
    margin: 6px 0 14px;
}

/* the day's finished fasts, shown on the dashboard when the day strip is
   pointing at a day that is already over */
.ldf-dash-daylist {
    list-style: none;
    margin: 10px 0 0;
    padding: 0;
    font-size: 13px;
    color: var(--ldc-text-muted);
}
.ldf-dash-daylist li {
    padding: 5px 0;
    border-top: 1px solid var(--ldc-border);
}

/* ==========================================================================
   HORMONE TIMELINE
   The ribbon is one SVG stretched to the card width; everything below it is
   plain flow layout so it reflows cleanly at 320px.
   ========================================================================== */
.ldf-ribbon-wrap { margin: 4px 0 18px; }

/* The box is the positioning context for everything drawn on top of the bars:
   the pin and the hour labels are HTML, so they keep the page's font and are
   never stretched by the SVG's non-uniform scaling. */
.ldf-ribbon-box {
    position: relative;
    padding-top: 12px;
    padding-bottom: 20px;
}
.ldf-ribbon {
    display: block;
    width: 100%;
    height: 40px;
}
.ldf-ribbon-target {
    stroke: var(--ldc-text);
    stroke-width: 2.8;
    stroke-dasharray: 4 3;
    opacity: .72;
}

/* the marker, a small triangle sitting on the bar */
.ldf-ribbon-pin {
    position: absolute;
    top: 0;
    width: 0;
    height: 0;
    margin-left: -6px;
    border-left: 6px solid transparent;
    border-right: 6px solid transparent;
    border-top: 8px solid var(--ldc-text);
    transition: left .9s linear;
}
.ldf-ribbon-over {
    position: absolute;
    top: 0;
    right: 0;
    font-size: 11px;
    font-weight: 700;
    color: var(--ldc-text);
}

.ldf-ribbon-ticks {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 18px;
}
.ldf-ribbon-tick {
    position: absolute;
    transform: translateX(-50%);
    font-family: var(--ldc-font-display);
    font-size: 11px;
    font-variant-numeric: tabular-nums;
    color: var(--ldc-text-muted);
    white-space: nowrap;
}
/* the first and last labels tuck inside the ends instead of hanging off */
.ldf-ribbon-tick:first-child { transform: none; }
.ldf-ribbon-tick:last-child  { transform: translateX(-100%); }

.ldf-ribbon-axis {
    margin-top: 0;
    text-align: right;
    font-size: .74rem;
    color: var(--ldc-text-muted);
}

/* the phase you are in right now */
.ldf-now {
    border-left: 5px solid var(--ldf-phase, var(--ldc-orange));
    background: var(--ldc-surface-soft);
    border-radius: 10px;
    padding: 14px 16px;
    margin-bottom: 14px;
}
.ldf-now-head { display: flex; gap: 12px; align-items: flex-start; }
.ldf-now-icon { font-size: 1.7rem; line-height: 1.2; }
.ldf-now-title {
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-size: 1.08rem;
    color: var(--ldc-red-ink);
}
.ldf-now-range {
    font-size: .8rem;
    color: var(--ldc-text-soft);
    font-variant-numeric: tabular-nums;
}
.ldf-now-lead { margin: 10px 0 8px; font-weight: 600; }
.ldf-now-body { margin: 0; padding-left: 1.1em; }
.ldf-now-body li { margin-bottom: 6px; line-height: 1.55; }

/* the full list, collapsed by default while a fast is running */
.ldf-phase-all > summary {
    cursor: pointer;
    font-weight: 600;
    color: var(--ldc-link);
    padding: 8px 0;
}
.ldf-phase-list {
    list-style: none;
    margin: 10px 0 0;
    padding: 0;
}
.ldf-phase-item {
    display: flex;
    gap: 12px;
    padding: 12px 0;
    border-top: 1px solid var(--ldc-border);
}
.ldf-phase-item.is-passed { opacity: .55; }
.ldf-phase-item.is-here   { opacity: 1; }
/* The phase colour identifies the row as a BAR, not as the lettering.
   Phase colours are data -- eight fixed hues that have to stay put across
   themes -- and several of them are dark, which made the hours unreadable on
   a dark card and washed out on a pale one. As a bar the colour still says
   which phase this is, at a size that works on any background, and the
   number is legible in every theme. */
.ldf-phase-when {
    flex: 0 0 66px;
    min-width: 0;
    padding-left: 8px;
    border-left: 4px solid var(--ldf-phase, var(--ldc-orange));
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--ldc-text);
    line-height: 1.25;
}
.ldf-phase-unit { display: block; font-size: .72rem; font-weight: 600; color: var(--ldc-text-soft); }
.ldf-phase-text { min-width: 0; flex: 1; }
.ldf-phase-title { font-weight: 700; }
.ldf-phase-here {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 8px;
    border-radius: 999px;
    background: var(--ldc-red);
    color: var(--ldc-on-accent);
    font-size: .7rem;
    font-weight: 700;
    vertical-align: middle;
}
.ldf-phase-flag { margin-left: 4px; }
.ldf-phase-lead { margin: 4px 0 6px; color: var(--ldc-text-soft); }
.ldf-phase-text ul { margin: 0; padding-left: 1.1em; }
.ldf-phase-text li { margin-bottom: 5px; font-size: .93rem; line-height: 1.5; }

.ldf-phase-tip p { margin: 6px 0 0; }

/* corrections tucked behind a summary so the button stays the loud thing */
.ldf-fix { margin-top: 14px; text-align: left; }
.ldf-fix > summary {
    cursor: pointer;
    font-size: .88rem;
    color: var(--ldc-link);
    font-weight: 600;
    padding: 6px 0;
}
.ldf-fix .ldc-form { margin-top: 8px; }

.ldf-target-warning { margin-top: 10px; text-align: left; }

@media (max-width: 420px) {
    .ldf-phase-when { flex-basis: 56px; font-size: .95rem; }
}

/* ==========================================================================
   THE DIAL
   A ring with the clock inside it. The arc is one SVG circle whose
   stroke-dasharray the timer script rewrites every second.
   ========================================================================== */
.ldf-ring {
    position: relative;
    width: min(260px, 72vw);
    aspect-ratio: 1 / 1;
    margin: 6px auto 14px;
    /* The lettering inside has to fit THIS box, not the window. The same
       ring is 260px on the fasting page and 180px inside a dashboard card,
       so a viewport-based size that fits one overflows the other -- which
       is exactly what it did: 03:30:58 ran outside the dial on the
       dashboard at every width. Making the ring a query container lets the
       clock be a fraction of the ring instead. */
    container-type: inline-size;
    container-name: ldf-ring;
}
.ldf-ring-svg {
    width: 100%;
    height: 100%;
    /* start the arc at twelve o'clock instead of three */
    transform: rotate(-90deg);
    overflow: visible;
}
.ldf-ring-track,
.ldf-ring-arc {
    fill: none;
    stroke-width: 15;
    stroke-linecap: round;
}
.ldf-ring-track { stroke: var(--ldc-track); }
.ldf-ring-arc {
    stroke: var(--ldc-orange);
    transition: stroke-dasharray .9s linear, stroke .3s ease;
}
/* No arc during the eating window: there is no target to be a fraction of,
   and a zero-length arc with a round cap draws a lone dot at twelve o'clock
   that looks like a bug rather than an empty ring. */
/* The eating ring fills too now, in the cool colour rather than the warm one:
   the two states are different things and should not read as the same clock
   in two moods. It is only hidden at exactly zero, because a zero-length arc
   with a round cap paints a stray dot at twelve o'clock -- the attribute
   selector catches that whether the value came from PHP or from the script. */
.ldf-ring.is-eating .ldf-ring-arc { stroke: var(--ldc-info); }
.ldf-ring.is-empty .ldf-ring-arc { display: none; }
.ldf-ring.is-eating .ldf-ring-track { stroke: var(--ldc-track); }
.is-reached .ldf-ring-arc { stroke: var(--ldc-ok); }

.ldf-ring-inner {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    text-align: center;
    /* The clear disc inside the stroke has radius 80.5 of the 100-unit
       half-width (r=88, stroke 15), so 14% a side stays inside the ring
       with room to spare where the clock sits -- at the vertical middle,
       where the chord is widest. */
    padding: 0 14%;
}
.ldf-ring-state {
    font-size: .82rem;
    font-weight: 600;
    color: var(--ldc-text-muted);
}
.ldf-ring .ldf-clock {
    font-family: var(--ldc-font-display);
    /* 03:30:58 is eight characters, about 4.15em wide in the display face.
       14% of the ring leaves it filling roughly four fifths of the 72% the
       padding above allows -- enough headroom for a font that loads late,
       a wider fallback, or a three-digit hour on a very long fast.
       The px bounds are guard rails for a ring outside the 100-290px the
       layout actually produces, never the size in normal use. */
    font-size: clamp(15px, 14cqw, 40px);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--ldc-red-ink);
    line-height: 1.1;
    margin: 0;
}
/* Container units landed in Safari 16 and Chrome 105. Anything older never
   sees the rule above, so it gets a size per ring by hand -- the situation
   the ring query replaced, but only for browsers that cannot do better. */
@supports not (width: 1cqw) {
    .ldf-ring .ldf-clock { font-size: clamp(1.5rem, 8vw, 2.2rem); }
    .ldf-dash-timer .ldf-ring .ldf-clock { font-size: 24px; }
}

.ldf-ring-pct {
    font-size: .84rem;
    font-weight: 600;
    color: var(--ldc-text-muted);
    font-variant-numeric: tabular-nums;
}
/* The target inside the ring is a link to the picker, but it has to keep
   reading as a number, not as body-copy link. Underline only on the pencil
   so the number itself stays clean. */
.ldf-ring-plan {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-top: 4px;
    padding: 2px 10px;
    border-radius: 999px;
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-size: .9rem;
    color: var(--ldc-accent-ink);
    text-decoration: none;
    background: rgba(255, 145, 0, .09);
    transition: background .15s ease;
}
.ldf-ring-plan:hover,
.ldf-ring-plan:focus-visible { background: rgba(255, 145, 0, .18); }
.ldf-ring-plan-edit { font-size: .74rem; opacity: .75; }

/* the target picker sits inside a <details>, so it needs a little more room
   than the compact time-fix forms next to it */
.ldf-target-fix .ldf-plan-grid { margin-top: 6px; }
.ldf-target-fix > summary { color: var(--ldc-accent-ink); }

/* the phase chip under the dial */
.ldf-milestone {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 0 auto 14px;
    padding: 8px 16px;
    border-radius: 999px;
    background: var(--ldc-surface-soft);
    border: 1px solid var(--ldf-phase, var(--ldc-orange));
    font-weight: 600;
    font-size: .9rem;
    max-width: 100%;
}
.ldf-milestone-icon { font-size: 1.1rem; line-height: 1; }
.ldf-milestone-text { color: var(--ldf-phase, var(--ldc-red)); }

.ldf-timer-card .ldf-sub { margin-bottom: 12px; }

/* the clock time the fast (or the eating window) ends -- the answer to the
   question the timer is actually being asked */
.ldf-when {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    max-width: 100%;
    margin: -4px auto 14px;
    padding: 7px 14px;
    border-radius: 999px;
    background: var(--ldc-surface-soft);
    border: 1px solid var(--ldc-border);
    font-size: .84rem;
    font-weight: 600;
    color: var(--ldc-text);
    line-height: 1.4;
    text-align: center;
}
.ldf-when-icon { font-size: .92rem; line-height: 1; flex: 0 0 auto; }
.ldf-dash-timer .ldf-when {
    margin-bottom: 10px;
    font-size: .8rem;
}

/* the old linear bar is redundant now the ring shows the same thing */
.ldf-progress { display: none; }

/* ==========================================================================
   PLAN CARDS
   ========================================================================== */
.ldf-plan-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
    gap: 10px;
    margin: 4px 0 10px;
}
/* Scoped to the grid on purpose. A plan card is a <label>, and any container
   that styles its own labels -- `.ldc-form label { display:block }` is one --
   outranks a bare `.ldf-plan` and flattens the card. The component has to
   hold its shape wherever it is dropped, not only where it was born. */
.ldf-plan-grid .ldf-plan {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    min-height: 76px;
    padding: 12px 8px;
    border: 1.5px solid var(--ldc-border);
    border-radius: 16px;
    background: var(--ldc-card-bg);
    cursor: pointer;
    text-align: center;
    transition: border-color .15s ease, background-color .15s ease, transform .12s ease;
}
.ldf-plan-grid .ldf-plan:active { transform: scale(.97); }
/* The radio is the control, not decoration -- it is moved out of sight rather
   than removed, so focus and screen readers still find it. */
.ldf-plan-grid .ldf-plan input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    min-height: 0;      /* the mobile 50px input floor must not reach it */
    margin: 0;
    padding: 0;
    pointer-events: none;
}
.ldf-plan-name {
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-size: 1.02rem;
    color: var(--ldc-text);
}
.ldf-plan-sub {
    font-size: .76rem;
    color: var(--ldc-text-muted);
}
.ldf-plan-flag {
    position: absolute;
    top: 6px;
    right: 8px;
    font-size: .72rem;
}
.ldf-plan-grid .ldf-plan.is-selected {
    border-color: var(--ldc-red);
    /* the highlight surface, not the page colour: on a strongly tinted theme
       --ldc-bg would put the card's lettering straight onto the wallpaper */
    background: var(--ldc-surface-accent);
}
.ldf-plan-grid .ldf-plan.is-selected .ldf-plan-name { color: var(--ldc-red-ink); }
.ldf-plan input:focus-visible + .ldf-plan-name {
    outline: 2px solid var(--ldc-teal);
    outline-offset: 3px;
    border-radius: 4px;
}
.ldf-plan-custom .ldf-plan-name { font-size: .92rem; }

@media (prefers-reduced-motion: reduce) {
    .ldf-ring-arc, .ldf-plan { transition: none; }
}

/* ==========================================================================
   WEEK STRIP
   ========================================================================== */
.ldf-week { margin-bottom: 4px; }
.ldf-week-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: 10px;
}
.ldf-week-title {
    font-family: var(--ldc-font-display);
    font-weight: 700;
    color: var(--ldc-red-ink);
}
.ldf-week-score {
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--ldc-accent-ink);
}
.ldf-week-cols {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 6px;
    align-items: end;
}
.ldf-week-col {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    min-width: 0;
}
.ldf-week-tick {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    border: 1.5px solid var(--ldc-border);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: 700;
    color: transparent;
    line-height: 1;
}
.ldf-week-col.is-hit .ldf-week-tick {
    background: var(--ldc-teal);
    border-color: var(--ldc-teal);
    color: var(--ldc-on-accent);
}
/* The bar grows from the bottom, so the wrapper is the full-height track and
   the bar inside it is a percentage of that. */
.ldf-week-bar-wrap {
    width: 100%;
    height: 62px;
    border-radius: 8px;
    background: var(--ldc-surface-accent);
    display: flex;
    align-items: flex-end;
    overflow: hidden;
}
.ldf-week-bar {
    width: 100%;
    background: var(--ldc-orange);
    border-radius: 8px;
    transition: height .3s ease;
}
.ldf-week-col.is-hit .ldf-week-bar { background: var(--ldc-teal); }
.ldf-week-day {
    font-size: 11px;
    font-weight: 600;
    color: var(--ldc-text-muted);
}
.ldf-week-col.is-today .ldf-week-day {
    color: var(--ldc-red-ink);
    font-weight: 700;
}
.ldf-week-col.is-today .ldf-week-bar-wrap {
    outline: 2px solid rgba(223, 48, 28, .25);
    outline-offset: 1px;
}

@media (prefers-reduced-motion: reduce) {
    .ldf-week-bar { transition: none; }
}

/* History rows use Core's shared list row inside a bordered card.

   `.ldf-row` is a card with a border on all four sides, not a divider list --
   so it must NOT get the `:last-child { border-bottom: 0 }` treatment that
   suits `.ldc-row`. That rule was carried over when these rows moved onto the
   shared component and it sliced the bottom edge off the last card in the
   history, which reads as a box that failed to close. */
.ldf-row .ldc-row-value.is-hit { color: var(--ldc-ok); }
.ldf-row .ldc-row { border-bottom: 0; }
.ldf-row:last-child { margin-bottom: 0; }
.ldf-row-actions { padding: 0 2px 12px 56px; margin-top: -6px; }


/* ==========================================================================
   THE EATING WINDOW

   Three questions, answered in the order people ask them: how much longer,
   how long have I been eating, and what time do I stop. The countdown is the
   big one because it is the one being watched.
   ========================================================================== */
/* Cool ink to match the cool arc: fasting is the warm state and eating is
   the other one, and the two should not read as the same clock in two moods.
   Both are ink tokens, so neither can drift under AA in a new theme. */
/* `.ldf-ring .ldf-clock` sets the colour, so this has to out-specify it. */
.ldf-ring .ldf-clock.ldf-eat-left { color: var(--ldc-link); font-variant-numeric: tabular-nums; }
/* Past the start time it stops being a countdown and starts being a nudge. */
.ldf-ring .ldf-clock.ldf-eat-left.is-over { color: var(--ldc-accent-ink); }

.ldf-eat-facts {
    display: flex;
    justify-content: center;
    gap: 10px;
    margin: 2px 0 14px;
}
.ldf-eat-fact {
    flex: 1 1 0;
    max-width: 190px;
    padding: 9px 10px;
    border-radius: var(--ldc-radius-sm);
    background: var(--ldc-surface-soft);
    text-align: center;
}
.ldf-eat-fact-label {
    display: block;
    font-size: 12px;
    color: var(--ldc-text-muted);
    margin-bottom: 2px;
}
.ldf-eat-fact-value {
    display: block;
    font-family: var(--ldc-font-display);
    font-size: 16px;
    font-weight: 700;
    color: var(--ldc-text);
    font-variant-numeric: tabular-nums;
}
/* Past the start time, the card stops being a countdown and starts being a
   nudge -- so the panel that carries the start time says so. */
.ldf-timer-card.is-over .ldf-eat-fact + .ldf-eat-fact { background: var(--ldc-surface-warn); }
@media (max-width: 380px) {
    .ldf-eat-fact-value { font-size: 15px; }
    .ldf-eat-fact-label { font-size: 11px; }
}


/* ldg-goal */
/* ==========================================================================
   GOALS
   Every colour goes through a Core role token; text uses the ink tokens, so
   a sixth theme cannot push anything under AA.
   ========================================================================== */

.ldg-h2 {
    font-family: var(--ldc-font-display);
    font-size: 19px;
    font-weight: 700;
    color: var(--ldc-red-ink);
    margin: 24px 0 10px;
}

/* --- the invitation, before any goal exists ------------------------------- */
.ldg-invite { display: flex; gap: 12px; align-items: flex-start; margin-bottom: 0; }
.ldg-invite-icon { font-size: 24px; flex: 0 0 auto; line-height: 1.1; }
.ldg-invite strong { display: block; font-family: var(--ldc-font-display); font-size: 15px; }
.ldg-invite p { margin: 4px 0 10px; font-size: 13px; color: var(--ldc-text-muted); line-height: 1.6; }

/* --- one goal ------------------------------------------------------------- */
.ldg-card { margin-bottom: 0; }
.ldg-card > .ldg-goal + .ldg-goal { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--ldc-border); }

.ldg-goal-head {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 10px;
}
.ldg-goal-icon { font-size: 17px; flex: 0 0 auto; }
.ldg-goal-name {
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-size: 15px;
    flex: 1 1 auto;
    min-width: 0;
}
.ldg-goal-state {
    flex: 0 0 auto;
    font-size: 12px;
    font-weight: 700;
    padding: 3px 10px;
    border-radius: 999px;
    background: var(--ldc-surface-soft);
    color: var(--ldc-text);
    white-space: nowrap;
}
.ldg-goal.is-ok   .ldg-goal-state { background: var(--ldc-surface-ok); }
.ldg-goal.is-warn .ldg-goal-state { background: var(--ldc-surface-warn); }
.ldg-goal.is-info .ldg-goal-state { background: var(--ldc-surface-cool); }

.ldg-goal-figure { display: flex; align-items: center; gap: 14px; margin-bottom: 10px; }
.ldg-goal-pct {
    flex: 0 0 auto;
    font-family: var(--ldc-font-display);
    font-size: 34px;
    font-weight: 700;
    line-height: 1;
    color: var(--ldc-link);
    font-variant-numeric: tabular-nums;
}
.ldg-goal-pct span { font-size: 17px; margin-left: 1px; }
.ldg-goal.is-warn .ldg-goal-pct { color: var(--ldc-accent-ink); }
.ldg-goal-nums { flex: 1 1 auto; min-width: 0; }
.ldg-goal-line { font-size: 13px; line-height: 1.6; font-variant-numeric: tabular-nums; }
.ldg-goal-left { color: var(--ldc-text-muted); }

/* --- the bar: fill is distance done, tick is time gone -------------------- */
.ldg-bar {
    position: relative;
    height: 12px;
    border-radius: 999px;
    background: var(--ldc-track);
    overflow: hidden;
}
.ldg-bar-fill {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: var(--ldc-teal);
    transition: width .3s ease;
}
.ldg-goal.is-warn .ldg-bar-fill { background: var(--ldc-orange); }
/* The tick is the only mark that can sit on top of the fill, so it is drawn in
   the page ground rather than a text colour -- it has to read against both the
   filled and the empty half of the bar. */
.ldg-bar-tick {
    position: absolute;
    top: -2px;
    bottom: -2px;
    width: 3px;
    margin-left: -1.5px;
    border-radius: 2px;
    background: var(--ldc-ink);
    opacity: .85;
}

.ldg-goal-meta {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    margin-top: 6px;
    font-size: 12px;
    color: var(--ldc-text-muted);
    font-variant-numeric: tabular-nums;
}
.ldg-goal-note {
    margin: 10px 0 0;
    font-size: 13px;
    line-height: 1.65;
    color: var(--ldc-text-muted);
}
.ldg-goal-kind {
    padding: 10px 12px;
    border-radius: var(--ldc-radius-sm);
    background: var(--ldc-surface-soft);
    color: var(--ldc-text);
}
.ldg-goal-dates {
    margin-top: 12px;
    padding-top: 10px;
    border-top: 1px solid var(--ldc-border);
    font-size: 12px;
    color: var(--ldc-text-muted);
}
.ldg-remove-form { margin: 10px 0 0; }
.ldg-form-card .ldc-card-title { font-size: 15px; }
.ldg-now {
    margin: 0 0 10px;
    font-family: var(--ldc-font-display);
    font-size: 15px;
    font-weight: 700;
}

@media (max-width: 380px) {
    .ldg-goal-pct { font-size: 29px; }
    .ldg-goal-state { font-size: 11px; }
}

/* ldn-nutrition */
/* Nutrition Log -- only what Core's shared theme doesn't already cover.
   Macro colours are fixed across the whole plugin so a colour always means
   the same macro: carbs = orange, protein = teal, fat = red. */

/* The three macro colours are a data encoding, not chrome: carb orange,
   protein blue, fat red is a rule the whole suite reads by. They stay put
   in every theme -- a bar that changes meaning with the wallpaper is a bar
   nobody can read twice. */
.ldn-seg-carb    { background: #FF9100; }
.ldn-seg-protein { background: #00B7CD; }
.ldn-seg-fat     { background: #DF301C; }

.ldn-macrobar {
    display: flex;
    height: 12px;
    border-radius: 999px;
    overflow: hidden;
    margin: 14px 0 8px;
    background: var(--ldc-cream);
}
.ldn-macrobar .ldn-seg { display: block; height: 100%; }

.ldn-macrolegend {
    display: flex;
    gap: 14px;
    flex-wrap: wrap;
    font-size: 12px;
    color: var(--ldc-text-muted);
    font-weight: 600;
}
.ldn-macrolegend.ldn-legend-center { justify-content: center; padding: 4px 0 2px; }

.ldn-dot {
    display: inline-block;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    margin-right: 5px;
    vertical-align: baseline;
}

.ldn-macro-inputs {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
}
@media (max-width: 420px) {
    .ldn-macro-inputs { grid-template-columns: 1fr; }
}

.ldn-live-kcal {
    margin: 4px 0 16px;
    font-size: 13px;
    color: var(--ldc-text-muted);
}
.ldn-live-kcal strong {
    font-family: var(--ldc-font-display);
    font-size: 17px;
    color: var(--ldc-red-ink);
}

.ldn-chart-axis {
    display: flex;
    justify-content: space-between;
    font-size: 11px;
    color: var(--ldc-label);
    padding: 2px 2px 4px;
}

.ldn-meal {
    border: 1px solid var(--ldc-border);
    border-radius: var(--ldc-radius-sm);
    padding: 10px 12px;
    margin-bottom: 10px;
    background: var(--ldc-card-bg);
}
.ldn-meal-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 10px;
}
.ldn-meal-name {
    font-family: var(--ldc-font-display);
    font-weight: 600;
    font-size: 14px;
}
.ldn-meal-name .ldw-muted { margin-left: 6px; }
.ldn-meal-kcal {
    font-family: var(--ldc-font-display);
    font-weight: 700;
    color: var(--ldc-red-ink);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.ldn-meal-food {
    font-size: 13px;
    color: var(--ldc-text);
    margin-top: 2px;
}
.ldn-meal-macros {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    margin-top: 8px;
    font-size: 12px;
    font-weight: 600;
    color: var(--ldc-text-muted);
    font-variant-numeric: tabular-nums;
}
.ldn-meal-actions {
    margin-left: auto;
    display: flex;
    gap: 10px;
    align-items: center;
}
.ldn-delete-form { display: inline; margin: 0; }

/* shared with the weight plugin's muted caption style, redefined here so the
   nutrition plugin still looks right if used on its own */
.ldn-page .ldw-muted {
    color: var(--ldc-text-muted);
    font-size: 11px;
    font-weight: 400;
}

/* ---- food calculator ---- */
.ldn-calc {
    background: var(--ldc-cream);
    border: 1px dashed var(--ldc-orange);
    border-radius: var(--ldc-radius-sm);
    padding: 14px;
    margin-bottom: 16px;
}
.ldn-calc-title {
    font-family: var(--ldc-font-display);
    font-weight: 600;
    color: var(--ldc-red-ink);
    font-size: 14px;
    margin-bottom: 4px;
}
.ldn-calc .ldc-hint { margin-bottom: 12px; }

.ldn-calc-row {
    display: grid;
    grid-template-columns: 1fr 90px 130px;
    gap: 10px;
    align-items: end;
}
@media (max-width: 520px) {
    .ldn-calc-row { grid-template-columns: 1fr 1fr; }
    .ldn-calc-row > .ldc-field:first-child { grid-column: 1 / -1; }
}
.ldn-calc-row .ldc-field { margin-bottom: 0; }
.ldn-calc-row select,
.ldn-calc-row input {
    width: 100%;
    padding: 10px 10px;
    border: 1px solid var(--ldc-border);
    border-radius: var(--ldc-radius-sm);
    font-size: 15px;
    background: var(--ldc-card-bg);
    color: var(--ldc-text);
}
.ldn-calc-row label {
    display: block;
    font-weight: 600;
    font-size: 13px;
    color: var(--ldc-text);
    margin-bottom: 4px;
}

.ldn-calc-add { margin-top: 4px; }

.ldn-calc-list { margin-top: 12px; }
.ldn-calc-empty {
    font-size: 12px;
    color: var(--ldc-text-muted);
    padding: 6px 0;
}
.ldn-calc-item {
    display: flex;
    align-items: center;
    gap: 10px;
    background: var(--ldc-card-bg);
    border: 1px solid var(--ldc-border);
    border-radius: 999px;
    padding: 7px 14px;
    margin-bottom: 6px;
    font-size: 13px;
}
.ldn-calc-item-name { flex: 1; min-width: 0; }
.ldn-calc-item-kcal {
    font-family: var(--ldc-font-display);
    font-weight: 700;
    color: var(--ldc-red-ink);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.ldn-calc-note { margin-top: 10px; }
.ldn-macro-intro { margin-bottom: 10px; }


/* ==========================================================================
   ALCOHOL

   Chips rather than a dropdown, because this is answered in one tap while
   standing up, and because seeing all four kinds at once is what reminds
   somebody that "just a beer" is on the list. Every colour goes through a
   role token; the brand colours are fills and borders here, never text.
   ========================================================================== */
.ldn-alcohol .ldc-card-title { margin-bottom: 10px; }

.ldn-alc-choice { display: flex; gap: 10px; margin-bottom: 12px; }
.ldn-alc-opt {
    flex: 1 1 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 52px;
    padding: 10px 12px;
    border: 2px solid var(--ldc-border);
    border-radius: var(--ldc-radius);
    background: var(--ldc-card-bg);
    font-weight: 600;
    font-size: 15px;
    cursor: pointer;
    transition: border-color .15s ease, background .15s ease;
}
/* The radio stays in the DOM and stays focusable -- hidden with opacity, not
   display:none, so a keyboard and a screen reader can still reach it. */
.ldn-alc-opt input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.ldn-alc-opt-icon { font-size: 20px; line-height: 1; }
.ldn-alc-opt.is-on { border-color: var(--ldc-orange); background: var(--ldc-surface-accent); }
.ldn-alc-opt:has(input:focus-visible) { outline: 3px solid var(--ldc-teal); outline-offset: 2px; }

.ldn-alc-kinds { margin-bottom: 10px; }
.ldn-alc-kinds .ldc-hint { margin: 0 0 8px; }
.ldn-alc-kindrow { display: flex; flex-wrap: wrap; gap: 8px; }
.ldn-alc-kind {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 44px;          /* a real tap target, not a checkbox */
    padding: 8px 14px;
    border: 2px solid var(--ldc-border);
    border-radius: 999px;
    background: var(--ldc-card-bg);
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
}
.ldn-alc-kind input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.ldn-alc-kind-icon { font-size: 17px; line-height: 1; }
.ldn-alc-kind.is-on { border-color: var(--ldc-teal); background: var(--ldc-surface-cool); }
.ldn-alc-kind:has(input:focus-visible) { outline: 3px solid var(--ldc-teal); outline-offset: 2px; }

.ldn-alc-note { margin: 0 0 12px; }
.ldn-alc-actions { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.ldn-alc-actions .ldc-btn { flex: 1 1 auto; }

.ldn-alc-summary {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--ldc-border);
    font-size: 13px;
    line-height: 1.7;
    color: var(--ldc-text-muted);
}
.ldn-alc-summary-kinds { display: block; margin-top: 4px; }
.ldn-alc-summary-kinds span { display: inline-block; margin-right: 10px; }

/* the one line the dashboard card is allowed */
.ldn-dash-alc {
    margin-top: 10px;
    padding: 8px 12px;
    border-radius: var(--ldc-radius-sm);
    background: var(--ldc-surface-soft);
    font-size: 13px;
    font-weight: 600;
    color: var(--ldc-text-soft);
}

@media (max-width: 400px) {
    .ldn-alc-opt { font-size: 14px; padding: 10px 8px; }
    .ldn-alc-kind { padding: 8px 11px; font-size: 13px; }
}

/* ── ช่องค้นหาอาหาร ───────────────────────────────────────────────────────
   แทนที่ดรอปดาวน์เมื่อ JS ทำงาน · ตัว <select> ยังอยู่ในหน้า ไม่ได้ลบ
   จึงต้องซ่อนด้วยคลาส ไม่ใช่ display:none ใน critical CSS (กฎของแผงเมนู) */
.ldn-hidden-select { display: none !important; }

.ldn-food-field { position: relative; }

.ldn-search { position: relative; }

.ldn-search-input { width: 100%; }

.ldn-search-clear {
    position: absolute;
    inset-inline-end: 8px;
    top: 50%;
    transform: translateY(-50%);
    border: 0;
    background: none;
    font-size: 22px;
    line-height: 1;
    padding: 0 6px;
    cursor: pointer;
    color: var(--ldc-text-muted);
}

.ldn-search-results {
    position: absolute;
    z-index: 30;
    inset-inline: 0;
    top: calc(100% + 4px);
    margin: 0;
    padding: 4px;
    list-style: none;
    max-height: 46vh;
    overflow-y: auto;
    background: var(--ldc-card-bg);
    border: 1px solid var(--ldc-border);
    border-radius: 12px;
    box-shadow: 0 10px 28px rgba(0, 0, 0, .16);
}

/* หนึ่งบรรทัดต่อหนึ่งอาหาร ถ้ากว้างพอ -- แต่ป้ายแหล่งที่มายาวขึ้นมากตอนที่
   แถวจากฉลากแบรนด์เข้ามา ("จากแบรนด์โดยตรง · ก.ย. 2569" ยาวกว่า "กรมอนามัย"
   เกือบสามเท่า) ชื่ออาหารเลยถูกบีบจนขึ้นบรรทัดใหม่รอบๆ ป้าย และอ่านออกมาเป็น
   "เมจิ / โกลด์ [ป้าย] แม็กซ์" เห็นตอนดูหน้าจริงบนมือถือ ไม่มีเทสต์ตัวไหนจับได้
   ให้ห่อบรรทัดแทน: ชื่อได้บรรทัดของตัวเองเมื่อที่ไม่พอ ป้ายกับแคลอรีลงบรรทัด
   ถัดไปพร้อมกัน */
.ldn-search-item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
    padding: 10px 10px;
    border-radius: 8px;
    cursor: pointer;
}

.ldn-search-item.is-active,
.ldn-search-item:hover { background: var(--ldc-surface-soft); }

/* 12em คือความกว้างที่ชื่ออาหารไทยทั่วไปอ่านรู้เรื่องโดยไม่หักคำ ต่ำกว่านั้น
   ให้ขึ้นบรรทัดใหม่ทั้งแถวดีกว่าบีบชื่อ */
.ldn-search-name { flex: 1 1 12em; min-width: 0; }

.ldn-search-macro {
    flex: 0 0 auto;
    font-size: .82em;
    color: var(--ldc-text-muted);
    font-variant-numeric: tabular-nums;
}

.ldn-search-none {
    padding: 12px 10px;
    color: var(--ldc-text-muted);
}

/* ป้ายแหล่งที่มา -- สีต่างกันเพื่อให้กวาดตาแล้วเห็นว่าแถวไหนน่าเชื่อกว่า
   ไม่ใช่เพื่อความสวย ตัวที่ผู้ใช้กรอกจึงเป็นสีเตือน ไม่ใช่สีกลาง */
.ldn-src {
    flex: 0 0 auto;
    font-size: .72em;
    line-height: 1;
    padding: 4px 7px;
    border-radius: 999px;
    white-space: nowrap;
    border: 1px solid transparent;
}

.ldn-src-usda   { background: var(--ldc-surface-cool);  color: var(--ldc-info); }
.ldn-src-anamai { background: var(--ldc-surface-ok);    color: var(--ldc-ok); }
.ldn-src-est  { background: var(--ldc-surface-warn);  color: var(--ldc-warn); }
.ldn-src-user { background: var(--ldc-surface-alert); color: var(--ldc-red-ink); }
/* A brand row is neither a laboratory measurement nor a stranger's guess, so
   it gets neither the green nor the red. Soft, with the brand orange ink. */
.ldn-src-brand { background: var(--ldc-surface-soft); color: var(--ldc-accent-ink); }
/* The beverage association's rows are a citation of somebody else's
   republication of a label, so they get their own badge colour rather than
   borrowing the brand one. */
.ldn-src-tba { background: var(--ldc-surface-soft); color: var(--ldc-link); }

@media (max-width: 1024px) {
    .ldn-search-input { font-size: 16px; }   /* กัน Safari ซูมทั้งหน้า */
    .ldn-search-results { max-height: 40vh; }
}

/* Where the page's own table ends and the rest of USDA begins. Quiet on
   purpose: it is a signpost, not a result. */
.ldn-search-more {
    padding: 0.35rem 0.75rem;
    font-size: 0.75rem;
    letter-spacing: 0.02em;
    color: var(--ldc-text-muted);
    background: var(--ldc-surface-soft);
    border-top: 1px solid var(--ldc-border);
    cursor: default;
}

/* -- What the source badges mean ----------------------------------------
   The legend under the ⓘ on the food field. Each line shows the real badge,
   styled exactly as it appears in the results, beside the sentence that
   explains it -- so the reader matches them by sight rather than by name. */
.ldn-src-legend {
    list-style: none;
    margin: 8px 0 0;
    padding: 0;
}
.ldn-src-legend li {
    display: flex;
    align-items: flex-start;
    gap: 7px;
    margin-bottom: 7px;
    line-height: 1.5;
}
.ldn-src-legend li:last-child { margin-bottom: 0; }
/* In the results a badge is a short tail on one line, so nowrap and
   shrink-to-fit are right there. In the legend they are a column, and both
   rules work against it: the widest name sets a different left edge for every
   sentence, and the longest one ("สมาคมเครื่องดื่มไทย") pushes its sentence
   off the screen. Here they get a fixed column and are allowed to wrap. */
.ldn-src-legend .ldn-src {
    flex: 0 0 6.8em;
    margin-top: 1px;
    white-space: normal;
    text-align: center;
    /* Two of the badge colours are a soft surface barely distinct from the
       card behind them -- on the page that is deliberate and quiet, but in a
       legend, where the badge IS the thing being pointed at, one that reads
       as plain text teaches the wrong shape. A hairline in the badge's own
       ink makes every one of them read as the pill it is. */
    border-color: currentColor;
}

/* lds-supplement */
/* ==========================================================================
   SUPPLEMENT LOG
   Every colour goes through a Core role token. Nothing is written as a hex
   value, so a sixth theme cannot break this file quietly.
   ========================================================================== */

/* 19px bold so it qualifies as large text under WCAG (>=18.66px bold), which
   is what lets it keep the brand red on a tinted page: the pastel theme reads
   3.4:1 there, which passes the 3:1 large-text threshold and fails the 4.5:1
   body-text one. Shrink this below 18.66px and the heading stops being legible
   in that theme. */
.lds-h2 {
    font-family: var(--ldc-font-display);
    font-size: 19px;
    font-weight: 700;
    color: var(--ldc-red-ink);
    margin: 26px 0 10px;
    display: flex;
    align-items: baseline;
    gap: 8px;
}
.lds-count {
    font-family: var(--ldc-font-body);
    font-size: 13px;
    font-weight: 600;
    color: var(--ldc-text-muted);
}
.lds-not-advice { margin-bottom: 18px; }

/* --- today ---------------------------------------------------------------- */
.lds-progress { margin-bottom: 14px; }
.lds-progress-bar {
    height: 10px;
    border-radius: 999px;
    background: var(--ldc-track);
    overflow: hidden;
}
.lds-progress-bar > span {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: var(--ldc-teal);
    transition: width .25s ease;
}
.lds-progress-text {
    margin-top: 6px;
    font-family: var(--ldc-font-display);
    font-size: 14px;
    font-weight: 700;
    color: var(--ldc-text);
    font-variant-numeric: tabular-nums;
}
.lds-streak { font-weight: 600; color: var(--ldc-text-muted); }

.lds-slot { margin-top: 14px; }
.lds-slot-head {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    font-weight: 600;
    color: var(--ldc-text-muted);
    margin-bottom: 6px;
}

.lds-tick { margin: 0; }
.lds-tick-btn {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-width: 0;
    padding: 10px 12px;
    margin-bottom: 6px;
    border: 1px solid var(--ldc-border);
    border-radius: var(--ldc-radius-sm);
    background: var(--ldc-surface-soft);
    color: var(--ldc-text);
    font: inherit;
    text-align: left;
    cursor: pointer;
}
.lds-tick-box {
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    border: 2px solid var(--ldc-border-strong);
    border-radius: 7px;
    background: var(--ldc-card-bg);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    font-weight: 700;
    line-height: 1;
    color: var(--ldc-on-accent);
}
.lds-tick.is-on .lds-tick-btn {
    background: var(--ldc-surface-ok);
    border-color: var(--ldc-ok);
}
.lds-tick.is-on .lds-tick-box {
    background: var(--ldc-ok);
    border-color: var(--ldc-ok);
}
.lds-tick-name {
    flex: 1 1 auto;
    min-width: 0;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    /* Thai tone marks rise above the line box; grow the clip rect and take
       the same back as margin. See --ldc-clip-pad in core's theme.css. */
    padding-top: var(--ldc-clip-pad);
    padding-bottom: var(--ldc-clip-pad);
    margin-top: calc(-1 * var(--ldc-clip-pad));
    margin-bottom: calc(-1 * var(--ldc-clip-pad));
}
.lds-tick-dose {
    flex: 0 0 auto;
    font-size: 13px;
    color: var(--ldc-text-muted);
    font-variant-numeric: tabular-nums;
}
.lds-tick-all { margin-top: 12px; }

/* --- findings ------------------------------------------------------------- */
.lds-findings { display: grid; gap: 12px; }
.lds-finding { margin-bottom: 0; border-left: 5px solid var(--ldc-border-strong); }
.lds-finding.is-danger { border-left-color: var(--ldc-red); }
.lds-finding.is-warn   { border-left-color: var(--ldc-warn); }
.lds-finding.is-info   { border-left-color: var(--ldc-info); }

.lds-finding-head {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin-bottom: 8px;
}
.lds-finding-icon { font-size: 20px; line-height: 1.2; flex: 0 0 auto; }
.lds-finding-sev {
    display: block;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ldc-text-muted);
}
.lds-finding.is-danger .lds-finding-sev { color: var(--ldc-red-ink); }
.lds-finding-title {
    display: block;
    font-family: var(--ldc-font-display);
    font-size: 15px;
    color: var(--ldc-text);
}
.lds-finding-num {
    display: inline-block;
    padding: 4px 10px;
    margin-bottom: 8px;
    border-radius: 999px;
    background: var(--ldc-surface-alert);
    font-size: 13px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--ldc-text);
}
.lds-finding-msg { margin: 0 0 8px; font-size: 14px; line-height: 1.65; }
.lds-finding-fix {
    margin: 0;
    padding: 10px 12px;
    border-radius: var(--ldc-radius-sm);
    background: var(--ldc-surface-cool);
    font-size: 14px;
    line-height: 1.65;
}
.lds-finding-fix strong { display: block; color: var(--ldc-text); margin-bottom: 2px; }

.lds-clean { display: flex; gap: 12px; align-items: flex-start; }
.lds-clean-icon { font-size: 22px; flex: 0 0 auto; }
.lds-clean p { margin: 4px 0 0; font-size: 13px; color: var(--ldc-text-muted); line-height: 1.65; }

.lds-drugs .ldc-card-title { font-size: 15px; }
.lds-drug-list { margin: 10px 0 0; padding-left: 18px; font-size: 14px; line-height: 1.7; }
.lds-drug-list li { margin-bottom: 8px; }
.lds-drug-list strong { color: var(--ldc-red-ink); }

/* --- the regimen ---------------------------------------------------------- */
.lds-stack-card > .lds-stack-row + .lds-stack-row { border-top: 1px solid var(--ldc-border); }
.lds-stack-row > summary {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 11px 0;
    cursor: pointer;
    list-style: none;
    min-width: 0;
}
.lds-stack-row > summary::-webkit-details-marker { display: none; }
.lds-stack-slot { flex: 0 0 auto; }
.lds-stack-name {
    flex: 1 1 auto;
    min-width: 0;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    /* Thai tone marks rise above the line box; grow the clip rect and take
       the same back as margin. See --ldc-clip-pad in core's theme.css. */
    padding-top: var(--ldc-clip-pad);
    padding-bottom: var(--ldc-clip-pad);
    margin-top: calc(-1 * var(--ldc-clip-pad));
    margin-bottom: calc(-1 * var(--ldc-clip-pad));
}
.lds-stack-dose {
    flex: 0 0 auto;
    font-size: 13px;
    color: var(--ldc-text-muted);
    font-variant-numeric: tabular-nums;
}
.lds-edit { margin-bottom: 8px; }
.lds-edit-actions { margin-top: 4px; }
.lds-remove-form { margin: 0 0 10px; }

/* --- the catalogue -------------------------------------------------------- */
.lds-browse-hint { margin: -4px 0 12px; }

/* The search box is the way into a list of 74 entries, so it is sized like the
   thing it is -- a primary control -- rather than like an ordinary form field.
   The magnifier is a background image rather than an icon element so that the
   input stays a plain input: no wrapper to break, nothing to knock out of
   alignment when the browser draws its own clear button. */
.lds-search { margin-bottom: 16px; }
.lds-search input {
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
    height: 54px;
    padding: 0 44px 0 46px;
    border-radius: 999px;
    border: 2px solid var(--ldc-border-strong);
    background-color: var(--ldc-card-bg);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237a6a56' stroke-width='2.4' stroke-linecap='round'%3E%3Ccircle cx='10.5' cy='10.5' r='6.5'/%3E%3Cpath d='M15.5 15.5 21 21'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: 15px center;
    background-size: 21px 21px;
    font-size: 16px;
    /* 400 to match the placeholder it replaces -- the field used to ask for
       a 500 that is no longer shipped, and a browser asked for a weight it
       does not have synthesises one, which reads as a smudge. */
    font-weight: 400;
    color: var(--ldc-text);
}
.lds-search input::placeholder { color: var(--ldc-text-muted); font-weight: 400; }
.lds-search input:focus {
    outline: none;
    border-color: var(--ldc-teal);
    box-shadow: 0 0 0 4px var(--ldc-surface-cool);
}
@media (max-width: 380px) {
    .lds-search input { height: 50px; padding: 0 38px 0 42px; background-position: 13px center; }
}
.lds-noresult {
    margin: 0 0 14px;
    padding: 14px;
    border-radius: var(--ldc-radius-sm);
    background: var(--ldc-surface-soft);
    color: var(--ldc-text-muted);
    text-align: center;
}
.lds-group-head {
    display: flex;
    align-items: center;
    gap: 7px;
    font-family: var(--ldc-font-display);
    font-size: 14px;
    font-weight: 700;
    color: var(--ldc-text-soft);
    margin: 18px 0 8px;
}
.lds-group-card > .lds-item + .lds-item { border-top: 1px solid var(--ldc-border); }
.lds-item > summary {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 11px 0;
    cursor: pointer;
    list-style: none;
    min-width: 0;
}
.lds-item > summary::-webkit-details-marker { display: none; }
.lds-item > summary::before {
    content: "▸";
    flex: 0 0 auto;
    color: var(--ldc-accent-ink);
    font-size: 12px;
}
.lds-item[open] > summary::before { content: "▾"; }

/* Waiting for a write-up to arrive.
   Nothing in here may change the size of anything: the whole point of making
   the row wait is that it opens once, at its final height, instead of opening
   small, flashing the "read more" link, and jumping again when the text
   lands. So the feedback is colour only. */
.lds-item[aria-busy="true"] > summary {
    opacity: .55;
    cursor: progress;
}
/* These two carry a display of their own, which outranks the browser's
   [hidden]{display:none} -- so el.hidden = true would leave them on screen.
   Core states the same thing globally, but a module has to stand on its own:
   core being one release behind must not turn this row's write-up back into a
   flash of the "read more" link. */
.lds-item-more[hidden],
.lds-item-wait[hidden] { display: none; }
.lds-item-wait {
    display: block;
    padding: 2px 0 12px;
    font-size: 13px;
    color: var(--ldc-text-muted);
}
.lds-item-name { font-weight: 600; }
.lds-item-also {
    font-size: 12px;
    color: var(--ldc-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    /* Thai tone marks rise above the line box; grow the clip rect and take
       the same back as margin. See --ldc-clip-pad in core's theme.css. */
    padding-top: var(--ldc-clip-pad);
    padding-bottom: var(--ldc-clip-pad);
    margin-top: calc(-1 * var(--ldc-clip-pad));
    margin-bottom: calc(-1 * var(--ldc-clip-pad));
}
.lds-add { margin: 10px 0 14px; }

/* --- one supplement's six answers ----------------------------------------- */
.lds-detail { padding: 4px 0 10px; }

/* The catalogue write-ups arrive when an entry is opened, so this block is
   a link before it is the article. Give it the same room either way, so
   opening one does not make the row jump as the text lands. */
.lds-item-body { min-height: 30px; padding: 2px 0 10px; }
.lds-item-more { display: inline-block; padding: 4px 0; }
.lds-item-body[aria-busy="true"] { opacity: .55; }
.lds-field { margin-bottom: 12px; }
.lds-field-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 3px;
}
.lds-field-icon { font-size: 14px; }
.lds-field-label {
    font-family: var(--ldc-font-display);
    font-size: 13px;
    font-weight: 700;
    color: var(--ldc-text-soft);
}
.lds-field p { margin: 0; font-size: 14px; line-height: 1.7; }
.lds-cap { color: var(--ldc-text-muted); font-size: 13px !important; margin-top: 3px !important; }

/* The badge text is the thing that has to be readable, so it uses colours that
   clear 4.5:1 on their own tint in every theme -- the meaning is carried by the
   background. --ldc-teal on --ldc-surface-cool measured 3:1 in the dark themes,
   which is why "moderate" uses the body colour rather than the accent. */
.lds-ev {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 700;
    line-height: 1.5;
    white-space: nowrap;
}
.lds-ev-strong   { background: var(--ldc-surface-ok);    color: var(--ldc-ok); }
.lds-ev-moderate { background: var(--ldc-surface-cool);  color: var(--ldc-text); }
.lds-ev-weak     { background: var(--ldc-surface-warn);  color: var(--ldc-text); }
.lds-ev-none     { background: var(--ldc-surface-soft);  color: var(--ldc-text-muted); }

.lds-note {
    margin-top: 10px;
    padding: 11px 13px;
    border-radius: var(--ldc-radius-sm);
    font-size: 13px;
    line-height: 1.7;
    background: var(--ldc-surface-soft);
}
.lds-note strong { display: block; margin-bottom: 2px; }
.lds-note-time { background: var(--ldc-surface-cool); }
.lds-note-time strong { color: var(--ldc-text); }
.lds-note-care { background: var(--ldc-surface-warn); }
.lds-note-care strong { color: var(--ldc-text); }
.lds-note-drug { background: var(--ldc-surface-alert); }
.lds-note-drug strong { color: var(--ldc-red-ink); }

/* --- dashboard card ------------------------------------------------------- */
.lds-dash-list { margin-top: 10px; }
.lds-dash-done {
    margin-top: 10px;
    padding: 12px;
    border-radius: var(--ldc-radius-sm);
    background: var(--ldc-surface-ok);
    color: var(--ldc-ok);
    font-weight: 700;
    text-align: center;
}
.lds-dash-more {
    font-size: 13px;
    color: var(--ldc-text-muted);
    text-align: center;
    padding-top: 4px;
}

@media (max-width: 420px) {
    .lds-tick-dose { font-size: 12px; }
    .lds-finding-title { font-size: 14px; }
}

/* ldwa-water */
/* ==========================================================================
   WATER LOG — บันทึกการดื่มน้ำ

   Teal is the water colour throughout, which is Core's existing --ldc-teal.
   Nothing here introduces a new hue: the palette is fixed at four and a fifth
   one would make every other screen look like a different product.
   ========================================================================== */

.ldwa-page .ldc-card { text-align: center; }
.ldwa-page .ldc-card-title,
.ldwa-page .ldc-form,
.ldwa-page .ldwa-day,
.ldwa-page .ldwa-entry { text-align: left; }

/* ---- the vase ---------------------------------------------------------- */
.ldwa-vase {
    width: 190px;
    max-width: 66%;
    margin: 2px auto 6px;
}
.ldwa-vase-svg { display: block; width: 100%; height: auto; overflow: visible; }

.ldwa-glass {
    fill: var(--ldc-glass-fill);
    stroke: var(--ldc-border-strong);
    stroke-width: 3.6;
    stroke-linejoin: round;
}
/* Opaque enough to swallow the stems it covers. At .82 the submerged part
   showed through as a ghost, which read as a drawing mistake rather than as
   water. */
.ldwa-water { fill: var(--ldc-teal); opacity: .93; }
/* the crest is a paler band, so the surface reads as water rather than as a
   seam where two shapes of the same colour meet */
.ldwa-wave  { fill: var(--ldc-teal-soft); opacity: 1; }
.ldwa-rim {
    fill: var(--ldc-glass-fill);
    stroke: var(--ldc-border-strong);
    stroke-width: 2.8;
}

/* The stems are drawn behind the glass, so the neck crosses them and the
   flowers look like they are standing in the water rather than in front. */
.ldwa-stem {
    fill: none;
    stroke: var(--ldc-leaf);
    stroke-width: 3.4;
    stroke-linecap: round;
}
.ldwa-leaf { fill: var(--ldc-leaf); }

/* --ldwa-p runs 0 to 1 with the day. The blooms open as it climbs: this is
   the entire reward for drinking, and it costs one custom property. */
.ldwa-bloom {
    transform: scale(calc(.62 + var(--ldwa-p, 0) * .38));
    opacity: calc(.42 + var(--ldwa-p, 0) * .58);
    transition: transform .5s ease, opacity .5s ease;
}
.ldwa-petal {
    fill: var(--ldc-surface-soft);
    stroke: var(--ldc-orange);
    stroke-width: 1.9;
    stroke-linejoin: round;
}
.ldwa-pollen { fill: var(--ldc-orange); }

.ldwa-vase.is-full .ldwa-petal { fill: var(--ldc-surface-soft); stroke: var(--ldc-red); }
.ldwa-vase.is-full .ldwa-pollen { fill: var(--ldc-red); }

/* the surface drifts, slowly, the way water in a glass actually does */
@keyframes ldwa-drift {
    from { transform: translateX(0); }
    to   { transform: translateX(100px); }
}
.ldwa-wave { animation: ldwa-drift 7s linear infinite; }

@media (prefers-reduced-motion: reduce) {
    .ldwa-wave { animation: none; }
    .ldwa-bloom { transition: none; }
}

/* ---- the readout ------------------------------------------------------- */
.ldwa-readout {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 18px;
    margin: 6px 0 4px;
    flex-wrap: wrap;
}
.ldwa-readout-pct {
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-size: 2.5rem;
    line-height: 1;
    color: var(--ldc-link);
    font-variant-numeric: tabular-nums;
}
.ldwa-readout-pct span { font-size: 1.3rem; margin-left: 2px; }
/* Past the goal the reading grows a digit -- 100%, 126%, and on a very long
   day four of them. Stepping the size down keeps the row on one line instead
   of wrapping the millilitres underneath it. */
.ldwa-readout-pct.is-over { font-size: 2.1rem; }
.ldwa-readout-pct.is-over span { font-size: 1.1rem; }
.ldwa-readout-side { text-align: left; min-width: 0; }
.ldwa-readout-total {
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-size: 1.32rem;
    color: var(--ldc-text);
    font-variant-numeric: tabular-nums;
}
.ldwa-readout-left { font-size: .84rem; color: var(--ldc-text-muted); }
.ldwa-main.is-reached .ldwa-readout-left { color: var(--ldc-link); font-weight: 600; }

.ldwa-goal-line {
    font-size: .8rem;
    color: var(--ldc-text-muted);
    margin-bottom: 12px;
}
.ldwa-goal-line .ldc-linkbtn { font-size: .8rem; margin-left: 4px; }

/* ---- the cup buttons --------------------------------------------------- */
.ldwa-cups {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
    margin-bottom: 12px;
}
.ldwa-cup-form { margin: 0; display: block; min-width: 0; }
.ldwa-cup {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1px;
    width: 100%;
    min-height: 82px;
    padding: 10px 6px;
    border: 1.5px solid var(--ldc-border);
    border-radius: 16px;
    background: var(--ldc-card-bg);
    cursor: pointer;
    font: inherit;
    color: var(--ldc-text);
    transition: border-color .15s ease, background-color .15s ease, transform .12s ease;
}
.ldwa-cup:hover, .ldwa-cup:focus-visible { border-color: var(--ldc-link); background: var(--ldc-surface-cool); }
.ldwa-cup:active { transform: scale(.96); }
/* ---- the drawn vessels ------------------------------------------------- */
.ldwa-vessel {
    display: block;
    width: 100%;
    height: 100%;
    overflow: visible;
}
.ldwa-vessel-body {
    fill: var(--ldc-glass-fill);
    stroke: var(--ldc-ink);
    stroke-width: 2.7;
    stroke-linejoin: round;
}
.ldwa-vessel-water { fill: var(--ldc-teal); opacity: .8; }
.ldwa-vessel-line {
    fill: none;
    stroke: var(--ldc-ink);
    stroke-width: 2.7;
    stroke-linecap: round;
}
.ldwa-cup-icon { width: 34px; height: 39px; }
.ldwa-cup-ml {
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-size: 1rem;
    color: var(--ldc-link);
    font-variant-numeric: tabular-nums;
}
.ldwa-cup-unit { font-size: .68rem; color: var(--ldc-text-muted); }

.ldwa-cups.is-compact .ldwa-cup { min-height: 64px; padding: 7px 4px; border-radius: 13px; }
.ldwa-cups.is-compact .ldwa-cup-icon { width: 26px; height: 30px; }
.ldwa-cups.is-compact .ldwa-cup-ml { font-size: .88rem; }

.ldwa-actions {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
}
/* Undo is a correction, not a decision -- it should not shout the way the
   red outline button does everywhere else in the suite. */
.ldwa-undo-form { margin: 0; }
.ldwa-undo-form .ldc-btn {
    border-color: var(--ldc-border);
    color: var(--ldc-text-muted);
    background: var(--ldc-card-bg);
    font-weight: 600;
}
.ldwa-undo-form .ldc-btn:hover,
.ldwa-undo-form .ldc-btn:focus-visible {
    border-color: var(--ldc-red);
    color: var(--ldc-red-ink);
}
.ldwa-custom { width: 100%; text-align: left; }
.ldwa-custom > summary {
    cursor: pointer;
    font-size: .84rem;
    font-weight: 600;
    color: var(--ldc-link);
    padding: 6px 0;
}
.ldwa-custom .ldc-form { margin-top: 6px; }

/* ---- seven days -------------------------------------------------------- */
.ldwa-week {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 7px;
    align-items: end;
    margin: 4px 0 10px;
}
.ldwa-week-col { text-align: center; min-width: 0; }
.ldwa-week-tube {
    position: relative;
    height: 76px;
    border-radius: 999px;
    background: var(--ldc-track);
    overflow: hidden;
    border: 1px solid var(--ldc-border);
}
.ldwa-week-fill {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    background: var(--ldc-teal);
    opacity: .8;
    border-radius: 999px;
}
.ldwa-week-tick {
    position: absolute;
    inset: auto 0 5px;
    font-size: .72rem;
    color: var(--ldc-on-accent);
    font-weight: 700;
    text-shadow: 0 1px 2px rgba(0, 0, 0, .25);
}
.ldwa-week-day { font-size: .7rem; color: var(--ldc-text-muted); margin-top: 4px; }
.ldwa-week-col.is-today .ldwa-week-day { color: var(--ldc-red-ink); font-weight: 700; }
.ldwa-week-col.is-today .ldwa-week-tube { outline: 2px solid rgba(0, 183, 205, .3); outline-offset: 1px; }

/* ---- entries and history ----------------------------------------------- */
.ldwa-card-total {
    float: right;
    font-family: var(--ldc-font-display);
    font-weight: 700;
    color: var(--ldc-link);
    font-variant-numeric: tabular-nums;
}
.ldwa-entry .ldc-row { border-bottom: 0; min-height: 52px; }
/* the row icon slot is a rounded tile; the vessel sits inside it */
.ldwa-entry .ldc-row-icon { display: flex; align-items: center; justify-content: center; }
.ldwa-entry .ldc-row-icon .ldwa-vessel { width: 26px; height: 30px; }
/* water is teal everywhere in this module; the shared row's default red is
   the alarm colour and an ordinary glass of water is not an alarm */
.ldwa-entry .ldc-row-value { color: var(--ldc-link); }
.ldwa-entry {
    border-bottom: 1px solid var(--ldc-border);
}
.ldwa-entry:last-child { border-bottom: 0; }
.ldwa-entry.is-editing {
    border: 1.5px solid var(--ldc-teal);
    border-radius: var(--ldc-radius-sm);
    background: var(--ldc-surface-cool);
    padding: 4px 10px 12px;
    margin: 6px 0;
}
.ldwa-entry-actions {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 0 2px 10px 56px;
    margin-top: -8px;
}
.ldwa-delete-form { display: inline; margin: 0; }

.ldwa-day { margin-bottom: 14px; }
.ldwa-day:last-child { margin-bottom: 0; }
.ldwa-day-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 10px;
    padding: 8px 2px 4px;
    border-bottom: 1px solid var(--ldc-border);
}
.ldwa-day-name { font-family: var(--ldc-font-display); font-weight: 700; font-size: .96rem; }
.ldwa-day-total {
    font-family: var(--ldc-font-display);
    font-weight: 700;
    color: var(--ldc-text-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.ldwa-day-total.is-hit { color: var(--ldc-link); }

/* ---- settings ---------------------------------------------------------- */
.ldwa-goal-modes {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 10px;
    margin: 4px 0 6px;
}
.ldwa-goal-modes .ldwa-goal-mode {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 12px 14px;
    border: 1.5px solid var(--ldc-border);
    border-radius: 14px;
    background: var(--ldc-card-bg);
    cursor: pointer;
    transition: border-color .15s ease, background-color .15s ease;
}
/* the radio stays in the accessibility tree, just out of sight */
.ldwa-goal-modes .ldwa-goal-mode input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    min-height: 0;
    margin: 0;
    padding: 0;
    pointer-events: none;
}
.ldwa-goal-modes .ldwa-goal-mode.is-selected { border-color: var(--ldc-link); background: var(--ldc-surface-cool); }
.ldwa-goal-mode-name { font-weight: 700; font-size: .92rem; }
.ldwa-goal-modes .ldwa-goal-mode.is-selected .ldwa-goal-mode-name { color: var(--ldc-link); }
.ldwa-goal-mode-sub { font-size: .78rem; color: var(--ldc-text-muted); }
.ldwa-goal-modes .ldwa-goal-mode input:focus-visible + .ldwa-goal-mode-name {
    outline: 2px solid var(--ldc-teal);
    outline-offset: 3px;
    border-radius: 4px;
}

.ldwa-cup-settings {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(104px, 1fr));
    gap: 8px;
    margin: 4px 0 6px;
}
.ldwa-cup-setting {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}
.ldwa-cup-setting-icon { width: 24px; height: 28px; flex: 0 0 auto; }
/* The spinner arrows eat about 20px of a 70px field and clip the last digit
   of "600". Nobody nudges a cup size one millilitre at a time anyway. */
.ldwa-cup-setting input {
    min-width: 0;
    width: 100%;
    text-align: center;
    -moz-appearance: textfield;
    appearance: textfield;
}
.ldwa-cup-setting input::-webkit-outer-spin-button,
.ldwa-cup-setting input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.ldwa-caveat {
    font-size: .78rem;
    color: var(--ldc-text-muted);
    line-height: 1.6;
    margin: 4px 2px 0;
}

/* ---- the home-screen card ---------------------------------------------- */
.ldwa-dash-top {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 10px;
}
.ldwa-dash .ldwa-vase { width: 76px; max-width: 76px; margin: 0; flex: 0 0 auto; }
.ldwa-dash-figures { min-width: 0; text-align: left; }
.ldwa-dash-total {
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-size: 1.5rem;
    color: var(--ldc-link);
    line-height: 1.15;
    font-variant-numeric: tabular-nums;
}
.ldwa-dash-goal { font-size: .8rem; color: var(--ldc-text-muted); }
.ldwa-dash-left { font-size: .82rem; color: var(--ldc-text); margin-top: 2px; }

@media (max-width: 380px) {
    .ldwa-cups { gap: 7px; }
    .ldwa-cup { min-height: 74px; }
}

/* --------------------------------------------------------------------------
   Stepping back a day.

   The page used to be nailed to today. It follows the day strip now, so it
   needs the same header the nutrition log has -- one line, arrows at the
   edges, the day in the middle -- and a line under the cups saying which day
   a tap will land on, because the cups look identical either way and that is
   exactly the kind of thing somebody finds out afterwards.
   -------------------------------------------------------------------------- */
.ldwa-backfill-note {
    margin: 10px 0 0;
    text-align: center;
}

/* ldw-weight */
/* Weight Log -- only what Core's shared theme doesn't already cover. */

.ldw-chart-axis {
    display: flex;
    justify-content: space-between;
    font-size: 11px;
    color: var(--ldc-label);
    padding: 2px 2px 4px;
}

.ldc-stat-value.is-down { color: var(--ldc-ok); }
.ldc-stat-value.is-up   { color: var(--ldc-red-ink); }

.ldw-bf-line {
    margin: 12px 0 0;
    font-size: 13px;
    color: var(--ldc-text);
}

.ldw-entries td { vertical-align: top; }
.ldw-entries .ldc-inline-actions { gap: 10px; }

.ldw-delete-form {
    display: inline;
    margin: 0;
}

.ldw-field-hint {
    margin: 6px 0 0;
    font-size: 12px;
    line-height: 1.45;
    color: var(--ldc-text-muted);
}

.ldw-spark {
    width: 100%;
    height: 44px;
    display: block;
    margin-top: 10px;
}

/* ---- circumference measurements ---- */
.ldw-measure-wrap {
    background: var(--ldc-cream);
    border: 1px dashed var(--ldc-orange);
    border-radius: var(--ldc-radius-sm);
    padding: 14px;
    margin-bottom: 14px;
}
.ldw-measure-label {
    display: block;
    font-family: var(--ldc-font-display);
    font-weight: 600;
    font-size: 14px;
    color: var(--ldc-red-ink);
    margin-bottom: 4px;
}
.ldw-measure-wrap .ldc-hint:first-of-type { margin-bottom: 12px; }
.ldw-measure-inputs {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}
.ldw-measure-inputs.has-hip { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 420px) {
    .ldw-measure-inputs,
    .ldw-measure-inputs.has-hip { grid-template-columns: 1fr 1fr; }
}
.ldw-measure-inputs > * { min-width: 0; }
.ldw-measure-inputs .ldc-field { margin-bottom: 0; }

.ldw-band {
    display: block;
    font-size: 11px;
    font-weight: 600;
    color: var(--ldc-text-muted);
    margin-top: 2px;
}
.ldw-activity-form { margin-top: 14px; }
.ldw-activity-form select {
    width: 100%;
    padding: 10px 12px;
    border: 1px solid var(--ldc-border);
    border-radius: var(--ldc-radius-sm);
    font-size: 14px;
    background: var(--ldc-card-bg);
    color: var(--ldc-text);
}


/* The weight trend is a single series, so its colour is chrome rather than a
   data encoding -- it follows the theme, unlike the macro and zone colours
   which mean something specific and stay put. */
.ldw-trend-line { stroke: var(--ldc-red); fill: none; }
.ldw-trend-dot  { fill: var(--ldc-red); }
/* gradient stops take stop-color, and like every other paint in an SVG it
   reads a custom property fine from CSS -- just not as an attribute */
.ldw-fill-top    { stop-color: var(--ldc-red); }
.ldw-fill-bottom { stop-color: var(--ldc-red); }

/* ---- been to the toilet? ------------------------------------------------
   Three cards rather than a checkbox, because "not said" has to be a visible
   choice you can go back to, not the absence of a tick. */
.ldw-bowel {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
    margin: 4px 0 6px;
}
.ldw-bowel .ldw-bowel-opt {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    min-height: 68px;
    padding: 10px 6px;
    border: 1.5px solid var(--ldc-border);
    border-radius: 14px;
    background: var(--ldc-card-bg);
    cursor: pointer;
    text-align: center;
    transition: border-color .15s ease, background-color .15s ease, transform .12s ease;
}
.ldw-bowel .ldw-bowel-opt:active { transform: scale(.97); }
/* the radio stays reachable by keyboard and screen reader, just out of sight */
.ldw-bowel .ldw-bowel-opt input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    min-height: 0;
    margin: 0;
    padding: 0;
    pointer-events: none;
}
.ldw-bowel .ldw-bowel-opt.is-selected {
    border-color: var(--ldc-red);
    background: var(--ldc-surface-accent);
}
.ldw-bowel-icon { font-size: 1.4rem; line-height: 1.1; }
.ldw-bowel-name { font-size: .8rem; font-weight: 600; }
.ldw-bowel .ldw-bowel-opt.is-selected .ldw-bowel-name { color: var(--ldc-red-ink); }
.ldw-bowel .ldw-bowel-opt input:focus-visible + .ldw-bowel-icon {
    outline: 2px solid var(--ldc-teal);
    outline-offset: 3px;
    border-radius: 6px;
}
.ldw-bowel-mark {
    display: inline-block;
    margin-left: 5px;
    font-size: .85rem;
    opacity: .45;
    vertical-align: middle;
}
.ldw-bowel-mark.is-yes { opacity: 1; }

/* ==========================================================================
   WHERE TO PUT THE TAPE

   The Navy formula is a circumference formula: it knows nothing except the
   numbers, so the numbers have to come off the right places. A sentence
   cannot show "just below the larynx"; a drawing can.
   ========================================================================== */
.ldw-guide {
    margin: 10px 0 0;
    padding: 12px 14px 4px;
    border: 1px dashed var(--ldc-orange);
    border-radius: var(--ldc-radius-sm);
    background: var(--ldc-surface-soft);
}
/* The stage is the drawing's own coordinate space: the SVG fills it, and the
   HTML labels are positioned as a percentage of it, so the two scale together
   at every width. container-type turns it into the reference for the cqw font
   sizes below. */
.ldw-guide-stage {
    position: relative;
    width: 100%;
    max-width: 340px;
    margin: 0 auto 4px;
    container-type: inline-size;
}
.ldw-guide-svg {
    display: block;
    width: 100%;
    height: auto;
}

/* Labels are HTML, not SVG <text>: Thai stacks a tone mark above a vowel that
   is already above the letter, and SVG text on iOS drops that second level --
   "ที่" came out as "ที". HTML shapes it correctly on every browser. */
.ldw-guide-tag {
    position: absolute;
    left: 51.2%;
    width: 47.6%;
    transform: translateY(-50%);
    line-height: 1.15;
}
.ldw-guide-tag b {
    display: block;
    color: var(--ldc-text);
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-size: 13.5px;
}
.ldw-guide-tag i {
    display: block;
    color: var(--ldc-text-muted);
    font-style: normal;
    font-weight: 400;
    font-size: 11.5px;
}
/* the sizes the old <text> had, expressed against the drawing's own width so
   they shrink with it -- 13.5/340 and 11.5/340 of the stage */
@supports (font-size: 1cqw) {
    .ldw-guide-tag b { font-size: 3.97cqw; }
    .ldw-guide-tag i { font-size: 3.38cqw; }
}
.ldw-guide-body {
    fill: none;
    stroke: var(--ldc-ink);
    stroke-width: 2.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}
/* the tape reads as the brand colour so it is unmistakably the thing being
   pointed at, rather than part of the body */
.ldw-guide-tape {
    fill: none;
    stroke: var(--ldc-red);
    stroke-width: 3;
    stroke-dasharray: 7 4;
}
.ldw-guide-lead {
    fill: none;
    stroke: var(--ldc-red);
    stroke-width: 1.8;
    opacity: .65;
}
.ldw-guide-numbg { fill: var(--ldc-surface-soft); stroke: none; }
.ldw-guide-num {
    fill: var(--ldc-red);
    font-family: var(--ldc-font-display);
    font-size: 12px;
    font-weight: 700;
}

.ldw-guide-caption { margin: 0; }
.ldw-guide-steps {
    margin: 0 0 6px;
    padding-left: 1.25em;
    font-size: 12.5px;
    line-height: 1.6;
    color: var(--ldc-text);
}
.ldw-guide-steps li { margin-bottom: 4px; }
.ldw-guide-steps strong { color: var(--ldc-red-ink); }
.ldw-guide .ldc-hint { margin: 0 0 8px; }

/* the manual shows both variants together -- side by side on anything wider
   than a phone, stacked below that */
.ldw-guide-pair {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 10px;
    margin: 10px 0;
}
.ldw-guide.is-compact { margin: 0; padding: 10px 10px 6px; }
.ldw-guide.is-compact .ldw-guide-stage { margin-bottom: 0; }
.ldw-guide-who {
    margin: 2px 0 0;
    text-align: center;
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-size: .85rem;
    color: var(--ldc-red-ink);
}

/* ---- the formula's answer, beside the numbers that feed it -------------- */
.ldw-navy-live {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin: 8px 0 2px;
    padding: 10px 14px;
    border: 1.5px solid var(--ldc-teal);
    border-radius: var(--ldc-radius-sm);
    background: var(--ldc-surface-cool);
}
.ldw-navy-live-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--ldc-text);
    min-width: 0;
}
.ldw-navy-live-value {
    font-family: var(--ldc-font-display);
    font-weight: 700;
    font-size: 1.45rem;
    line-height: 1.1;
    color: var(--ldc-link);
    font-variant-numeric: tabular-nums;
}
.ldw-navy-live.is-empty { border-color: var(--ldc-border); background: var(--ldc-surface-soft); }
.ldw-navy-live.is-empty .ldw-navy-live-value { color: var(--ldc-text-muted); }

/* --------------------------------------------------------------------------
   A number with its unit beside it.

   Different BIA scales report muscle mass in different units, so the unit is
   part of the entry rather than a setting buried elsewhere: the member copies
   what their own scale shows and picks the matching unit in the same motion.
   -------------------------------------------------------------------------- */
.ldw-unitfield {
    display: flex;
    gap: 8px;
    align-items: stretch;
}

.ldw-unitfield input { flex: 1 1 auto; min-width: 0; }

.ldw-unitfield select {
    flex: 0 0 auto;
    width: auto;
    min-width: 74px;
}

