/* ═══ Font Definitions (Font Loading) ═══ */
@font-face {
  font-family: 'Estedad';
  src: url('../assets/fonts/Estedad[wght].woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Estedad Mad';
  src: url('../assets/fonts/Estedad-Mad.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

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

/* ═══ Safe-Area Insets — one shared definition ═══
   Mobile devices with a notch / dynamic island / home indicator report these as
   real lengths only when viewport-fit=cover is set (it is, in index.html).
   Every floating header/bar/sheet reads the same variables instead of re-deriving
   env() inline, so the clearance policy stays uniform across views. */
:root{
  --sat:env(safe-area-inset-top,0px);
  --sab:env(safe-area-inset-bottom,0px);
  --sal:env(safe-area-inset-left,0px);
  --sar:env(safe-area-inset-right,0px);
}

/* ═══ Design Tokens — Daftarche Design System ═══
   Systematic underneath, Organic on top.
   Warm / Organic / Quiet / Expressive / Precise */

:root{
  /* ── Semantic Colors (Light) ──
     The default theme, and the same values the palette table holds as «روشن» —
     these point at them, so the interface and anything showing that palette
     (the theme picker's dot) can never disagree about what light is. */
  --color-bg:var(--pal-paper-bg);
  --color-surface:var(--pal-paper-surface);
  --color-surface-elevated:var(--pal-paper-elev);
  --color-text-primary:var(--pal-paper-text);
  --color-text-secondary:var(--pal-paper-text2);
  --color-text-muted:var(--pal-paper-muted);
  --color-text-on-accent:var(--pal-paper-on-accent);
  --color-border:var(--pal-paper-border);
  --color-border-strong:var(--pal-paper-border-strong);
  --color-accent:var(--pal-paper-accent);
  --color-accent-soft:var(--pal-paper-accent-soft);
  --color-accent-strong:var(--pal-paper-accent-strong);
  --color-focus:var(--pal-paper-accent);

  /* Meaning is not a fashion: success, warning and danger are the same three
     colours across the three daylight themes, and re-tuned once for the dark
     half (see the html[data-mode] blocks below). Without a mode attribute — a
     script-blocked first paint — these daylight values stand. */
  --color-success:var(--state-success);
  --color-warning:var(--state-warning);
  --color-danger:var(--state-danger);
  --state-success:#2e7d46;
  --state-warning:#a85f00;
  --state-danger:#c0392b;
  --state-glass-hover:rgba(37,36,34,.05);

  /* ── Legacy aliases (existing styles keep working; new styles use semantic tokens) ── */
  --bg:var(--color-bg);
  --surface:var(--color-surface);
  --text:var(--color-text-primary);
  --muted:var(--color-text-muted);
  --accent:var(--color-accent);
  --accent-2:var(--color-warning);
  --accent-soft:var(--color-accent-soft);
  --green:var(--color-success);
  --danger:var(--color-danger);
  --border:var(--color-border);

  /* ── Organic identity layers (not global character palettes) ── */
  --tape:var(--pal-paper-tape);
  --glass:var(--pal-paper-glass);
  --glass-hover:var(--state-glass-hover);

  /* ── Spacing Scale: 4 / 8 / 12 / 16 / 24 / 32 / 48 ── */
  --space-1:4px;
  --space-2:8px;
  --space-3:12px;
  --space-4:16px;
  --space-6:24px;
  --space-8:32px;
  --space-12:48px;

  /* ── Radius Scale ── */
  --radius-xs:8px;
  --radius-sm:12px;
  --radius-md:16px;
  --radius-lg:20px;
  --radius-xl:24px;
  --radius-pill:999px;

  /* ── Shadows: 3 elevations + accent/interactive ── */
  --shadow-0:none;
  --shadow-1:0 4px 14px -6px rgba(122,80,35,.18);
  --shadow-2:0 24px 50px -24px rgba(122,80,35,.35);
  --shadow-accent:0 4px 0 0 rgba(120,55,20,.35);

  /* ── Borders ── */
  --border-width:1px;
  --border-width-strong:2px;

  /* ── Typography ── */
  --font-ui: 'Estedad', system-ui, sans-serif;
  --font-personality: 'Estedad Mad', 'Estedad', system-ui, sans-serif;

  /* ── Motion ── */
  --duration-fast:.18s;
  --duration-base:.3s;
  --duration-slow:.5s;
  --ease-out:cubic-bezier(.22,1,.36,1);
  --ease-spring:cubic-bezier(.34,1.56,.64,1);

  /* ── Layout ── */
  --radius:var(--radius-lg);
  --nav-height:64px;

  /* Legacy shadow names kept for existing rules */
  --shadow-lg:var(--shadow-2);
  --shadow-sm:var(--shadow-1);
}

/* ═══ Palettes ═══
   Colour with a name, and two consumers: an app theme (html[data-theme=...],
   further down) maps a palette onto the interface tokens, and a share card
   template ([data-palette=...], right below) maps the same palette onto the
   card's own --card-* words and onto the dot a picker paints. Neither consumer
   ever names a colour itself, so a palette is written down exactly once and a
   card can never drift from the app it came from — a reader who prints a «شب»
   card while the app is in «کاغذ» gets the night the app would have drawn, and
   the card's «برنامه» template follows whatever theme is on screen.

   «کاغذ» is in the table like every other palette; the :root token block above
   simply points at it, so it stays the default for anyone who has not chosen
   otherwise — and the picker can show it as a colour rather than a promise. */
:root{
  /* Every palette below is 14 values and no more, and every one of them comes
     from a single coolors.co palette (the five anchors it is named for) or from
     a blend of those anchors: the paper, the card, a raised card, the ink, the
     half-ink, a muted grey mixed between the two, a hairline and a stronger
     line, the accent and its darker self and its soft fill, the tape on a card,
     and the frosted tint the floating dock is cut from. Colours meaning success,
     warning or danger are deliberately not here — they are shared by mode. */

  /* paper — the notebook's own paper, the theme this app was drawn in before it
     had a table at all: #F6EFE3 with the orange it has always been written in,
     #E05F28. It is in the table as a palette like the rest so the picker can
     show the default as a colour rather than a promise — and so both halves of
     that picker contain one of the app's own two themes.

     Two of the original values moved a shade, and for the same reason: the paper
     is untouched, but the ink on it had to clear the floors the other seven
     palettes clear. The muted grey was #A79C8A (2.6:1 on the card surface) and is
     #8F8574 (3.6:1). The orange was #F4703A, which reads at 2.5:1 on this paper —
     and the accent is not decoration here, it carries the chosen tab's label and
     every focus ring — so it is #E05F28: 3.2:1 on the paper and 4.8:1 for the ink
     that sits on it, which is the same two-sided window the hexagon sits in.
     Neither change is visible as a different colour; both are visible as text
     that can be read. */
  --pal-paper-bg:#f6efe3;
  --pal-paper-surface:#fffcf5;
  --pal-paper-elev:#ffffff;
  --pal-paper-text:#2e2921;
  --pal-paper-text2:#5d5548;
  --pal-paper-muted:#8f8574;
  --pal-paper-border:rgba(80,60,30,.10);
  --pal-paper-border-strong:rgba(80,60,30,.22);
  --pal-paper-accent:#e05f28;
  --pal-paper-accent-strong:#c04a18;
  --pal-paper-accent-soft:rgba(224,95,40,.13);
  --pal-paper-tape:rgba(255,196,120,.50);
  --pal-paper-glass:rgba(255,252,245,.72);
  --pal-paper-on-accent:#1e1b18;

  /* lilac — Pastel Dreamland Adventure (trending, 88.1K): the cool half of the
     light table, standing where «شیری» used to. That theme was retired because
     the picker made the case against it: «شیری» was a brighter «کاغذ» sitting
     right beside it, so two of the four light swatches promised nearly the same
     page. This one answers something the other three cannot — paper, peach and
     green are all warm, and nothing in the light half was cooler.
     #CDB4DB #FFC8DD #FFAFCC #BDE0FE #A2D2FF — the lavender anchor taken down far
     enough to carry white ink (5.3:1), which is why this palette's on-accent is
     white where «کاغذ»'s is ink. */
  --pal-lilac-bg:#f5f0fa;
  --pal-lilac-surface:#ffffff;
  --pal-lilac-elev:#ffffff;
  --pal-lilac-text:#2a2334;
  --pal-lilac-text2:#574d63;
  --pal-lilac-muted:#7d7289;
  --pal-lilac-border:rgba(109,84,143,.12);
  --pal-lilac-border-strong:rgba(109,84,143,.26);
  --pal-lilac-accent:#7b5ea7;
  --pal-lilac-accent-strong:#64498d;
  --pal-lilac-accent-soft:rgba(123,94,167,.14);
  --pal-lilac-tape:rgba(205,180,219,.55);
  --pal-lilac-glass:rgba(245,240,250,.72);
  --pal-lilac-on-accent:#ffffff;

  /* blush — Peachy Delight (43.7K): a peach paper under a dusty mauve accent.
     #D8E2DC #FFE5D9 #FFCAD4 #F4ACB7 #9D8189 */
  --pal-blush-bg:#fff1ec;
  --pal-blush-surface:#ffffff;
  --pal-blush-elev:#ffffff;
  --pal-blush-text:#33272b;
  --pal-blush-text2:#5e4b50;
  --pal-blush-muted:#94737c;
  --pal-blush-border:rgba(157,129,137,.18);
  --pal-blush-border-strong:rgba(157,129,137,.32);
  --pal-blush-accent:#9d8189;
  --pal-blush-accent-strong:#7e6169;
  --pal-blush-accent-soft:rgba(157,129,137,.16);
  --pal-blush-tape:rgba(244,172,183,.40);
  --pal-blush-glass:rgba(255,241,236,.72);
  --pal-blush-on-accent:#201a1c;

  /* sage — Earthy Forest Hues (49K): the green the mascot already is.
     #DAD7CD #A3B18A #588157 #3A5A40 #344E41 */
  --pal-sage-bg:#dad7cd;
  --pal-sage-surface:#f7f8f2;
  --pal-sage-elev:#ffffff;
  --pal-sage-text:#2a3128;
  --pal-sage-text2:#4a5244;
  --pal-sage-muted:#66705c;
  --pal-sage-border:rgba(58,90,64,.14);
  --pal-sage-border-strong:rgba(58,90,64,.26);
  --pal-sage-accent:#4a6b44;
  --pal-sage-accent-strong:#37522f;
  --pal-sage-accent-soft:rgba(88,129,87,.16);
  --pal-sage-tape:rgba(218,215,205,.70);
  --pal-sage-glass:rgba(232,234,223,.72);
  --pal-sage-on-accent:#ffffff;

  /* night — the notebook under a lamp: the same page as «کاغذ», in the dark this
     app already wore when the lights went out. #100E0C with #FF9C60, and ink on
     that accent reads at 8.4:1 where white would read at 2.1:1. */
  --pal-night-bg:#100e0c;
  --pal-night-surface:#1e1a15;
  --pal-night-elev:#2a231c;
  --pal-night-text:#f6efe2;
  --pal-night-text2:#cec3b0;
  --pal-night-muted:#9d9280;
  --pal-night-border:rgba(255,220,180,.10);
  --pal-night-border-strong:rgba(255,220,180,.22);
  --pal-night-accent:#ff9c60;
  --pal-night-accent-strong:#ffb585;
  --pal-night-accent-soft:rgba(255,156,96,.16);
  --pal-night-tape:rgba(255,190,110,.22);
  --pal-night-glass:rgba(30,26,21,.72);
  --pal-night-on-accent:#241a12;

  /* gold — Golden Twilight (24.5K): a navy night with a gold accent. It briefly
     held the key «شب», which went back to the warm night the name belongs to.
     #000814 #001D3D #003566 #FFC300 #FFD60A */
  --pal-gold-bg:#00060f;
  --pal-gold-surface:#0a1b33;
  --pal-gold-elev:#12294a;
  --pal-gold-text:#f2f6ff;
  --pal-gold-text2:#c6d4e8;
  --pal-gold-muted:#8ca0be;
  --pal-gold-border:rgba(140,160,190,.16);
  --pal-gold-border-strong:rgba(140,160,190,.30);
  --pal-gold-accent:#ffc300;
  --pal-gold-accent-strong:#ffd60a;
  --pal-gold-accent-soft:rgba(255,195,0,.16);
  --pal-gold-tape:rgba(255,195,0,.20);
  --pal-gold-glass:rgba(10,27,51,.72);
  --pal-gold-on-accent:#1a1200;

  /* ocean — Deep Sea (27.6K): slate blue, cool and quiet.
     #0D1B2A #1B263B #415A77 #778DA9 #E0E1DD */
  --pal-ocean-bg:#0b1622;
  --pal-ocean-surface:#16243a;
  --pal-ocean-elev:#1f3250;
  --pal-ocean-text:#e6ebf2;
  --pal-ocean-text2:#b4c2d6;
  --pal-ocean-muted:#7e93ae;
  --pal-ocean-border:rgba(119,141,169,.18);
  --pal-ocean-border-strong:rgba(119,141,169,.34);
  --pal-ocean-accent:#6c9bd2;
  --pal-ocean-accent-strong:#8fb7e6;
  --pal-ocean-accent-soft:rgba(108,155,210,.16);
  --pal-ocean-tape:rgba(119,141,169,.22);
  --pal-ocean-glass:rgba(22,36,58,.72);
  --pal-ocean-on-accent:#06101c;

  /* plum — Vivid Nightfall (13.9K): a deep violet with a lilac accent.
     #10002B #240046 #3C096C #5A189A #7B2CBF #9D4EDD */
  --pal-plum-bg:#0c0021;
  --pal-plum-surface:#1b0538;
  --pal-plum-elev:#2a0a52;
  --pal-plum-text:#f3eaff;
  --pal-plum-text2:#cdb6e8;
  --pal-plum-muted:#9384b8;
  --pal-plum-border:rgba(157,78,221,.20);
  --pal-plum-border-strong:rgba(157,78,221,.36);
  --pal-plum-accent:#b77bf0;
  --pal-plum-accent-strong:#cfa3f7;
  --pal-plum-accent-soft:rgba(157,78,221,.20);
  --pal-plum-tape:rgba(157,78,221,.22);
  --pal-plum-glass:rgba(27,5,56,.72);
  --pal-plum-on-accent:#17052e;

  /* day — the birthday palette, and the only one here that no theme points at.
     It is written in the palette table for the same reason as the other eight:
     a colour is written down once. What makes it different is who chose it —
     nobody did. The reader wrote a date into a settings row and this is the day
     the app answers it, so the block that consumes it hangs off data-day rather
     than data-theme, and nothing in the picker ever names it.

     It stays inside the notebook's own language instead of reaching for a
     birthday palette of its own: the same warm paper as «کاغذ», the same orange family as its ink, a shade
     brighter and more saturated to mark the day, and a deeper rose behind it.
     A cake-and-streamers palette would look like it came from another app.

     The dark half is a lamp-lit version of the same idea, in the half of the
     table that already owns the night. Both are plain colours, never a
     color-mix(), because the share card parses whatever this table holds. */
  --pal-day-bg:#fff4e6;
  --pal-day-surface:#fffdf8;
  --pal-day-elev:#ffffff;
  --pal-day-text:#3a2a1c;
  --pal-day-text2:#6b5240;
  --pal-day-muted:#8a7360;
  --pal-day-border:rgba(140,90,50,.14);
  --pal-day-border-strong:rgba(140,90,50,.28);
  --pal-day-accent:#c2410c;
  --pal-day-accent-strong:#9a3412;
  --pal-day-accent-soft:rgba(194,65,12,.14);
  --pal-day-tape:rgba(255,170,90,.55);
  --pal-day-glass:rgba(255,244,230,.74);
  --pal-day-on-accent:#fff8f0;

  /* daydark — the same day after dark. Its own name and not a mode suffix,
     because the palette table has no notion of a half: the theme blocks choose
     by name, so this one is chosen by the rule that pairs it with the light
     day above, and a reader who is in a dark theme at 22:00 on their birthday
     gets a dark birthday rather than a bright one pasted over their night. */
  --pal-daydark-bg:#181008;
  --pal-daydark-surface:#241a10;
  --pal-daydark-elev:#312415;
  --pal-daydark-text:#f8ecdd;
  --pal-daydark-text2:#d8c3ab;
  --pal-daydark-muted:#a3907a;
  --pal-daydark-border:rgba(255,200,140,.14);
  --pal-daydark-border-strong:rgba(255,200,140,.28);
  --pal-daydark-accent:#fb923c;
  --pal-daydark-accent-strong:#fdba74;
  --pal-daydark-accent-soft:rgba(251,146,60,.16);
  --pal-daydark-tape:rgba(251,146,60,.22);
  --pal-daydark-glass:rgba(36,26,16,.74);
  --pal-daydark-on-accent:#241a10;
}

/* ── From palette to the card's vocabulary ──
   A chip that wears data-palette="…" is showing the palette it would print
   with: the dot is the palette's paper, ringed in its accent. */
[data-palette="paper"]{
  --card-bg:var(--pal-paper-bg);
  --card-surface:var(--pal-paper-surface);
  --card-text:var(--pal-paper-text);
  --card-muted:var(--pal-paper-muted);
  --card-accent:var(--pal-paper-accent);
  --card-accent-soft:var(--pal-paper-accent-soft);
  --card-border:var(--pal-paper-border-strong);
  --card-grid:var(--pal-paper-border);
  --card-tape:var(--pal-paper-tape);
  --pick-dot-bg:var(--pal-paper-bg);
  --pick-dot-ring:var(--pal-paper-accent);
}
[data-palette="lilac"]{
  --card-bg:var(--pal-lilac-bg);
  --card-surface:var(--pal-lilac-surface);
  --card-text:var(--pal-lilac-text);
  --card-muted:var(--pal-lilac-muted);
  --card-accent:var(--pal-lilac-accent);
  --card-accent-soft:var(--pal-lilac-accent-soft);
  --card-border:var(--pal-lilac-border-strong);
  --card-grid:var(--pal-lilac-border);
  --card-tape:var(--pal-lilac-tape);
  --pick-dot-bg:var(--pal-lilac-bg);
  --pick-dot-ring:var(--pal-lilac-accent);
}
[data-palette="blush"]{
  --card-bg:var(--pal-blush-bg);
  --card-surface:var(--pal-blush-surface);
  --card-text:var(--pal-blush-text);
  --card-muted:var(--pal-blush-muted);
  --card-accent:var(--pal-blush-accent);
  --card-accent-soft:var(--pal-blush-accent-soft);
  --card-border:var(--pal-blush-border-strong);
  --card-grid:var(--pal-blush-border);
  --card-tape:var(--pal-blush-tape);
  --pick-dot-bg:var(--pal-blush-bg);
  --pick-dot-ring:var(--pal-blush-accent);
}
[data-palette="sage"]{
  --card-bg:var(--pal-sage-bg);
  --card-surface:var(--pal-sage-surface);
  --card-text:var(--pal-sage-text);
  --card-muted:var(--pal-sage-muted);
  --card-accent:var(--pal-sage-accent);
  --card-accent-soft:var(--pal-sage-accent-soft);
  --card-border:var(--pal-sage-border-strong);
  --card-grid:var(--pal-sage-border);
  --card-tape:var(--pal-sage-tape);
  --pick-dot-bg:var(--pal-sage-bg);
  --pick-dot-ring:var(--pal-sage-accent);
}
[data-palette="night"]{
  --card-bg:var(--pal-night-bg);
  --card-surface:var(--pal-night-surface);
  --card-text:var(--pal-night-text);
  --card-muted:var(--pal-night-muted);
  --card-accent:var(--pal-night-accent);
  --card-accent-soft:var(--pal-night-accent-soft);
  --card-border:var(--pal-night-border-strong);
  --card-grid:var(--pal-night-border);
  --card-tape:var(--pal-night-tape);
  --pick-dot-bg:var(--pal-night-bg);
  --pick-dot-ring:var(--pal-night-accent);
}
[data-palette="gold"]{
  --card-bg:var(--pal-gold-bg);
  --card-surface:var(--pal-gold-surface);
  --card-text:var(--pal-gold-text);
  --card-muted:var(--pal-gold-muted);
  --card-accent:var(--pal-gold-accent);
  --card-accent-soft:var(--pal-gold-accent-soft);
  --card-border:var(--pal-gold-border-strong);
  --card-grid:var(--pal-gold-border);
  --card-tape:var(--pal-gold-tape);
  --pick-dot-bg:var(--pal-gold-bg);
  --pick-dot-ring:var(--pal-gold-accent);
}
[data-palette="ocean"]{
  --card-bg:var(--pal-ocean-bg);
  --card-surface:var(--pal-ocean-surface);
  --card-text:var(--pal-ocean-text);
  --card-muted:var(--pal-ocean-muted);
  --card-accent:var(--pal-ocean-accent);
  --card-accent-soft:var(--pal-ocean-accent-soft);
  --card-border:var(--pal-ocean-border-strong);
  --card-grid:var(--pal-ocean-border);
  --card-tape:var(--pal-ocean-tape);
  --pick-dot-bg:var(--pal-ocean-bg);
  --pick-dot-ring:var(--pal-ocean-accent);
}
[data-palette="plum"]{
  --card-bg:var(--pal-plum-bg);
  --card-surface:var(--pal-plum-surface);
  --card-text:var(--pal-plum-text);
  --card-muted:var(--pal-plum-muted);
  --card-accent:var(--pal-plum-accent);
  --card-accent-soft:var(--pal-plum-accent-soft);
  --card-border:var(--pal-plum-border-strong);
  --card-grid:var(--pal-plum-border);
  --card-tape:var(--pal-plum-tape);
  --pick-dot-bg:var(--pal-plum-bg);
  --pick-dot-ring:var(--pal-plum-accent);
}

/* ═══ Themes ═══
   The interface's colours, one block per theme, every value a palette above or
   the :root defaults. color-scheme is declared per theme so the browser's own
   furniture — scrollbars, form controls, the canvas behind a scroll — matches
   the theme the reader actually chose rather than the system preference. */
/* ═══ Modes ═══
   The half of the table a theme belongs to, and the one place the dark-only
   decisions live. Every rule in the sheet that used to name the single dark
   theme now says html[data-mode="dark"], so another dark theme costs no new
   rule anywhere — a theme is never asked to restate a shared decision.

   What is shared by mode: the three meaning colours (success, warning, danger
   are the same in all three daylight themes and re-tuned once for the dark
   half), the hover tint the floating dock draws on its tabs, and the three
   shadows — warm brown under daylight, plain black at night. color-scheme is
   declared here and in every theme block below, so the browser's own furniture
   (scrollbars, form controls, the canvas behind a scroll) matches the choice
   whether or not the mode attribute survived a first paint. */
html[data-mode="light"]{
  color-scheme:light;
  --state-success:#2e7d46;
  --state-warning:#a85f00;
  --state-danger:#c0392b;
  --state-glass-hover:rgba(37,36,34,.05);
  --shadow-1:0 4px 14px -6px rgba(122,80,35,.18);
  --shadow-2:0 24px 50px -24px rgba(122,80,35,.35);
  --shadow-accent:0 4px 0 0 rgba(120,55,20,.35);
}
html[data-mode="dark"]{
  color-scheme:dark;
  --state-success:#7fcb8f;
  --state-warning:#f2b34c;
  --state-danger:#ff8a80;
  --state-glass-hover:rgba(255,255,255,.07);
  --shadow-1:0 4px 14px -6px rgba(0,0,0,.5);
  --shadow-2:0 24px 50px -24px rgba(0,0,0,.7);
  --shadow-accent:0 4px 0 0 rgba(0,0,0,.45);
}

/* ═══ Themes ═══
   The interface's colours, one block per theme, every value a palette above.
   Each block is the same fifteen mappings over a different palette, which is
   the whole point: the palettes are the only place a colour is written down,
   and these blocks only say which colour goes in which slot. `--glass` is the
   tint the floating dock is frosted from — it used to be a hardcoded cream that
   silently ignored every theme but one. */
html[data-theme="paper"]{
  color-scheme:light;
  --color-bg:var(--pal-paper-bg);
  --color-surface:var(--pal-paper-surface);
  --color-surface-elevated:var(--pal-paper-elev);
  --color-text-primary:var(--pal-paper-text);
  --color-text-secondary:var(--pal-paper-text2);
  --color-text-muted:var(--pal-paper-muted);
  --color-text-on-accent:var(--pal-paper-on-accent);
  --color-border:var(--pal-paper-border);
  --color-border-strong:var(--pal-paper-border-strong);
  --color-accent:var(--pal-paper-accent);
  --color-accent-strong:var(--pal-paper-accent-strong);
  --color-accent-soft:var(--pal-paper-accent-soft);
  --color-focus:var(--pal-paper-accent);
  --tape:var(--pal-paper-tape);
  --glass:var(--pal-paper-glass);
}

html[data-theme="lilac"]{
  color-scheme:light;
  --color-bg:var(--pal-lilac-bg);
  --color-surface:var(--pal-lilac-surface);
  --color-surface-elevated:var(--pal-lilac-elev);
  --color-text-primary:var(--pal-lilac-text);
  --color-text-secondary:var(--pal-lilac-text2);
  --color-text-muted:var(--pal-lilac-muted);
  --color-text-on-accent:var(--pal-lilac-on-accent);
  --color-border:var(--pal-lilac-border);
  --color-border-strong:var(--pal-lilac-border-strong);
  --color-accent:var(--pal-lilac-accent);
  --color-accent-strong:var(--pal-lilac-accent-strong);
  --color-accent-soft:var(--pal-lilac-accent-soft);
  --color-focus:var(--pal-lilac-accent);
  --tape:var(--pal-lilac-tape);
  --glass:var(--pal-lilac-glass);
}

html[data-theme="blush"]{
  color-scheme:light;
  --color-bg:var(--pal-blush-bg);
  --color-surface:var(--pal-blush-surface);
  --color-surface-elevated:var(--pal-blush-elev);
  --color-text-primary:var(--pal-blush-text);
  --color-text-secondary:var(--pal-blush-text2);
  --color-text-muted:var(--pal-blush-muted);
  --color-text-on-accent:var(--pal-blush-on-accent);
  --color-border:var(--pal-blush-border);
  --color-border-strong:var(--pal-blush-border-strong);
  --color-accent:var(--pal-blush-accent);
  --color-accent-strong:var(--pal-blush-accent-strong);
  --color-accent-soft:var(--pal-blush-accent-soft);
  --color-focus:var(--pal-blush-accent);
  --tape:var(--pal-blush-tape);
  --glass:var(--pal-blush-glass);
}

html[data-theme="sage"]{
  color-scheme:light;
  --color-bg:var(--pal-sage-bg);
  --color-surface:var(--pal-sage-surface);
  --color-surface-elevated:var(--pal-sage-elev);
  --color-text-primary:var(--pal-sage-text);
  --color-text-secondary:var(--pal-sage-text2);
  --color-text-muted:var(--pal-sage-muted);
  --color-text-on-accent:var(--pal-sage-on-accent);
  --color-border:var(--pal-sage-border);
  --color-border-strong:var(--pal-sage-border-strong);
  --color-accent:var(--pal-sage-accent);
  --color-accent-strong:var(--pal-sage-accent-strong);
  --color-accent-soft:var(--pal-sage-accent-soft);
  --color-focus:var(--pal-sage-accent);
  --tape:var(--pal-sage-tape);
  --glass:var(--pal-sage-glass);
}

html[data-theme="night"]{
  color-scheme:dark;
  --color-bg:var(--pal-night-bg);
  --color-surface:var(--pal-night-surface);
  --color-surface-elevated:var(--pal-night-elev);
  --color-text-primary:var(--pal-night-text);
  --color-text-secondary:var(--pal-night-text2);
  --color-text-muted:var(--pal-night-muted);
  --color-text-on-accent:var(--pal-night-on-accent);
  --color-border:var(--pal-night-border);
  --color-border-strong:var(--pal-night-border-strong);
  --color-accent:var(--pal-night-accent);
  --color-accent-strong:var(--pal-night-accent-strong);
  --color-accent-soft:var(--pal-night-accent-soft);
  --color-focus:var(--pal-night-accent);
  --tape:var(--pal-night-tape);
  --glass:var(--pal-night-glass);
}

html[data-theme="gold"]{
  color-scheme:dark;
  --color-bg:var(--pal-gold-bg);
  --color-surface:var(--pal-gold-surface);
  --color-surface-elevated:var(--pal-gold-elev);
  --color-text-primary:var(--pal-gold-text);
  --color-text-secondary:var(--pal-gold-text2);
  --color-text-muted:var(--pal-gold-muted);
  --color-text-on-accent:var(--pal-gold-on-accent);
  --color-border:var(--pal-gold-border);
  --color-border-strong:var(--pal-gold-border-strong);
  --color-accent:var(--pal-gold-accent);
  --color-accent-strong:var(--pal-gold-accent-strong);
  --color-accent-soft:var(--pal-gold-accent-soft);
  --color-focus:var(--pal-gold-accent);
  --tape:var(--pal-gold-tape);
  --glass:var(--pal-gold-glass);
}

html[data-theme="ocean"]{
  color-scheme:dark;
  --color-bg:var(--pal-ocean-bg);
  --color-surface:var(--pal-ocean-surface);
  --color-surface-elevated:var(--pal-ocean-elev);
  --color-text-primary:var(--pal-ocean-text);
  --color-text-secondary:var(--pal-ocean-text2);
  --color-text-muted:var(--pal-ocean-muted);
  --color-text-on-accent:var(--pal-ocean-on-accent);
  --color-border:var(--pal-ocean-border);
  --color-border-strong:var(--pal-ocean-border-strong);
  --color-accent:var(--pal-ocean-accent);
  --color-accent-strong:var(--pal-ocean-accent-strong);
  --color-accent-soft:var(--pal-ocean-accent-soft);
  --color-focus:var(--pal-ocean-accent);
  --tape:var(--pal-ocean-tape);
  --glass:var(--pal-ocean-glass);
}

html[data-theme="plum"]{
  color-scheme:dark;
  --color-bg:var(--pal-plum-bg);
  --color-surface:var(--pal-plum-surface);
  --color-surface-elevated:var(--pal-plum-elev);
  --color-text-primary:var(--pal-plum-text);
  --color-text-secondary:var(--pal-plum-text2);
  --color-text-muted:var(--pal-plum-muted);
  --color-text-on-accent:var(--pal-plum-on-accent);
  --color-border:var(--pal-plum-border);
  --color-border-strong:var(--pal-plum-border-strong);
  --color-accent:var(--pal-plum-accent);
  --color-accent-strong:var(--pal-plum-accent-strong);
  --color-accent-soft:var(--pal-plum-accent-soft);
  --color-focus:var(--pal-plum-accent);
  --tape:var(--pal-plum-tape);
  --glass:var(--pal-plum-glass);
}

/* ═══ The day ═══
   The third face on the root, after the theme and the mode, and the only one
   the reader did not choose. It is painted from the palette table like anything
   else, and it overrides the theme above it by source order — html[data-day]
   ties html[data-theme] on specificity, so being written last is what makes it
   win. Nothing about the theme underneath is changed: when the day is over the
   attribute is deleted and the reader's own colours are exactly where they left
   them, because they were never replaced.

   It is deliberately absent from THEMES. That list is what the picker walks and
   what the header switch swaps between, and a day is not a choice — putting it
   there would let someone select it on any date and it would then have to
   survive being a theme, which is the opposite of what it is. */
html[data-day="birthday"]{
  color-scheme:light;
  --color-bg:var(--pal-day-bg);
  --color-surface:var(--pal-day-surface);
  --color-surface-elevated:var(--pal-day-elev);
  --color-text-primary:var(--pal-day-text);
  --color-text-secondary:var(--pal-day-text2);
  --color-text-muted:var(--pal-day-muted);
  --color-text-on-accent:var(--pal-day-on-accent);
  --color-border:var(--pal-day-border);
  --color-border-strong:var(--pal-day-border-strong);
  --color-accent:var(--pal-day-accent);
  --color-accent-strong:var(--pal-day-accent-strong);
  --color-accent-soft:var(--pal-day-accent-soft);
  --color-focus:var(--pal-day-accent);
  --tape:var(--pal-day-tape);
  --glass:var(--pal-day-glass);
}

/* A birthday at night is a birthday, not a flashbulb. The reader's own theme
   says which half of the table they are in, and this answers in the same half
   rather than overriding their choice of darkness with brightness. Two
   attribute selectors beat the single one above, so this needs no !important
   and no source-order trick. */
html[data-day="birthday"][data-mode="dark"]{
  color-scheme:dark;
  --color-bg:var(--pal-daydark-bg);
  --color-surface:var(--pal-daydark-surface);
  --color-surface-elevated:var(--pal-daydark-elev);
  --color-text-primary:var(--pal-daydark-text);
  --color-text-secondary:var(--pal-daydark-text2);
  --color-text-muted:var(--pal-daydark-muted);
  --color-text-on-accent:var(--pal-daydark-on-accent);
  --color-border:var(--pal-daydark-border);
  --color-border-strong:var(--pal-daydark-border-strong);
  --color-accent:var(--pal-daydark-accent);
  --color-accent-strong:var(--pal-daydark-accent-strong);
  --color-accent-soft:var(--pal-daydark-accent-soft);
  --color-focus:var(--pal-daydark-accent);
  --tape:var(--pal-daydark-tape);
  --glass:var(--pal-daydark-glass);
}

/* Scroll behavior is decided per call, not globally.
   A global `scroll-behavior:smooth` turned every programmatic jump into a
   long animated scroll — switching tabs from far down the task list meant the
   viewport glided a thousand pixels while the incoming page was also animating
   in, which reads as sluggishness rather than smoothness. Page switches and
   list jumps now ask for what they want in JS ({behavior:'smooth'} stays for
   the in-list jumps that are meant to be followed by the eye), so the two never
   animate at the same time. */
body{font-family:var(--font-ui);background:var(--bg);color:var(--text);min-height:100vh;min-height:100dvh;overflow-x:hidden;transition:background var(--duration-slow),color var(--duration-slow);-webkit-tap-highlight-color:transparent;line-height:1.6}
button{touch-action:manipulation;font-family:inherit}

/* Touch ergonomics: pointer-driven only.
   - touch-action:manipulation on all interactive elements kills the legacy
     300ms tap delay and accidental double-tap zoom, without blocking scroll.
   - Contained overscroll on the independent scrollers (reading stage, notes
     list) stops pull-to-refresh from firing mid-scroll inside the reader.
   Hover effects stay desktop-only: on touch they lock in after a tap, so the
   guarded media query is what keeps the touch experience honest. */
a,button,[role=button],input[type=range],input[type=checkbox],.cal-day,.hl-dot,.goal-choice{touch-action:manipulation}
.reader-stage,.notes-list{overscroll-behavior-y:contain}
/* Compact numeric/stepper inputs are pointer-targeted, not typed into, so they
   keep their small size. Fields users actually type in are pinned to 16px in
   their own files — iOS Safari zooms the viewport into any focusable field
   set smaller than that. */
.focus-presets input,.goal-daily input,.set-row input[type=range],.dock-pop-page input[type=range]{font-size:13px}
/* The same zoom rule catches the compact *typed* fields that live inside cards
   (the add line, the search bar, the title and duration rows) and every field
   the responsive blocks shrink below 16px. Rather than keep a list that rots,
   iOS alone gets a floor: only this query matches, so desktop keeps the small
   sizes and the phone stops jumping when a field takes focus. */
@supports (-webkit-touch-callout: none){
  input:not([type=range]):not([type=checkbox]):not([type=radio]),textarea,select{font-size:16px !important}
}

/* Interactive hover is a desktop enhancement, never a touch state. Without this
   guard, a tap leaves the pressed element stuck in :hover until the user taps
   elsewhere ("sticky hover"). @media(hover:hover) matches devices that truly
   have a hover-capable pointer; touch-first devices skip every rule inside. */
@media (hover:hover){
  .theme-btn:hover{transform:translateY(-1px)}
  .nav-tab:hover{background:var(--glass-hover)}
  .focus-page-actions .ghost:hover{color:var(--accent);border-color:var(--accent)}
  .settings-btn:hover{background:var(--accent-soft);border-color:var(--accent)}
  .settings-btn.danger:hover{background:rgba(228,88,79,.1);border-color:var(--danger)}
}
input, textarea, select{font-family:inherit}

body::after{content:'';position:fixed;inset:0;z-index:97;pointer-events:none;opacity:.05;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E")}

.doodle{position:fixed;z-index:0;pointer-events:none;color:var(--accent)}
/* Ambient decorative doodles: very slow, very low character (motion budget) */
.d-sun{top:5%;inset-inline-start:4%;opacity:.3;animation:spin 90s linear infinite}
.d-star1{top:22%;inset-inline-end:7%;opacity:.4;animation:twinkle 5s ease-in-out infinite}
.d-star2{bottom:16%;inset-inline-start:6%;opacity:.35}
.d-squig{bottom:calc(var(--nav-height) + 6%);inset-inline-end:5%;opacity:.3;animation:drift 7s ease-in-out infinite}

/* ═══ Page System ═══ */
/* Page transition: very subtle opacity + small transform (Priority 8.3) */
.page{display:none;min-height:100vh;min-height:100dvh;padding:40px 20px calc(var(--nav-height) + 24px);animation:pageIn var(--duration-base) var(--ease-out)}
.page.active{display:block}
@keyframes pageIn{from{opacity:0;transform:translateY(8px)}}

/* The way back — one step of the trail, shown only while there is one. It sits
   above the header so it never fights the title for the top corner, and hugs
   the start edge (the right, in this app's reading direction). */
.page-back{display:inline-flex;align-items:center;gap:6px;align-self:flex-start;padding:8px 14px;
  border:1px solid var(--border);background:var(--surface);color:var(--text);border-radius:var(--radius-pill);
  font-family:var(--font-ui);font-size:13px;font-weight:600;line-height:1;cursor:pointer;box-shadow:var(--shadow-sm);
  transition:transform var(--duration-fast),border-color var(--duration-fast),color var(--duration-fast)}
.page-back[hidden]{display:none}
.page-back svg{width:16px;height:16px;flex:0 0 auto}
@media (hover:hover){.page-back:hover{transform:translateY(-1px);border-color:var(--accent);color:var(--accent)}}
.page-back:active{transform:translateY(1px)}
.page-back:focus-visible{outline:2px solid var(--color-focus);outline-offset:2px}
@media (prefers-reduced-motion:reduce){.page-back{transition:none}.page-back:hover,.page-back:active{transform:none}}

.app{width:100%;max-width:480px;margin:0 auto;position:relative;z-index:1;display:flex;flex-direction:column;gap:16px}

header{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
h1{font-family:var(--font-personality);font-size:clamp(28px,8vw,34px);font-weight:700;line-height:1.3}
h1 .underline{display:block;width:110px;height:10px;color:var(--accent);margin-top:2px}
h1 .underline path{stroke-dasharray:140;stroke-dashoffset:140;animation:draw var(--duration-slow) ease var(--duration-base) forwards}
.subtitle{color:var(--muted);font-size:13px;margin-top:6px;font-weight:400}

/* The two controls in the top corner, together. They were three copies of an
   inline display:flex;gap:8px with no align-items, which is what let them drift
   apart: .theme-btn had a mobile rule shrinking it to 40px, .header-avatar (in
   profile.css, linked later) never did, so below 480px the pair rendered as a
   44px button beside a 40px one — top-aligned, because nothing said otherwise.
   align-items:center is the part that was actually missing; without it the
   smaller box hangs off the top of the row rather than sitting level with it. */
.header-actions{display:flex;gap:8px;align-items:center}
.header-actions>*{flex-shrink:0}
.theme-btn{width:44px;height:44px;border-radius:var(--radius-sm);border:1px solid var(--border);background:var(--surface);color:var(--text);cursor:pointer;display:grid;place-items:center;box-shadow:var(--shadow-1);position:relative;overflow:hidden;transition:transform var(--duration-base),background var(--duration-slow);flex-shrink:0}
/* hover state lives in the @media(hover:hover) block above */
.theme-btn svg{position:absolute;transition:transform var(--duration-slow) var(--ease-out),opacity var(--duration-base)}
.theme-btn .sun{transform:translateY(-150%) rotate(-90deg);opacity:0}
html[data-mode="dark"] .theme-btn .sun{transform:none;opacity:1}
html[data-mode="dark"] .theme-btn .moon{transform:translateY(150%) rotate(90deg);opacity:0}

/* ═══ Floating Glass Dock (Navigation) ═══ */
.bottom-nav{
  position:fixed;
  bottom:calc(10px + env(safe-area-inset-bottom,0));
  left:50%;transform:translateX(-50%) translateZ(0);
  z-index:98;
  display:flex;align-items:stretch;gap:2px;
  padding:6px;border-radius:var(--radius-xl);
  /* The tint is the theme's own --glass, so the dock is frosted from whatever
     paper is behind it rather than from one hardcoded cream that only ever
     matched the lightest theme. */
  background:linear-gradient(135deg,var(--glass),color-mix(in srgb,var(--glass) 62%,transparent));
  /* Glass, at a radius the compositor can afford every frame.
     This bar floats over the whole scrolling page for the entire session, and
     the backdrop blur is re-sampled on every scroll frame — the blur radius is
     the per-frame cost. 16px still reads as frosted glass over the paper (the
     gradient, border and inner highlights carry most of the look) and costs
     roughly a third less than the previous 24px. The element is also promoted
     to its own layer so the page scrolling underneath never repaints it. */
  backdrop-filter:blur(16px) saturate(1.5);
  -webkit-backdrop-filter:blur(16px) saturate(1.5);
  border:1px solid color-mix(in srgb,var(--color-surface) 55%,transparent);
  box-shadow:
    0 18px 44px -18px rgba(122,80,35,.32),
    0 4px 18px -8px rgba(122,80,35,.16),
    inset 0 1px 0 rgba(255,255,255,.65),
    inset 0 -1px 0 rgba(255,255,255,.28);
  max-width:calc(100vw - 20px);
  transition:background var(--duration-slow),border-color var(--duration-slow),box-shadow var(--duration-slow);
}
html[data-mode="dark"] .bottom-nav{
  box-shadow:
    0 18px 44px -18px rgba(0,0,0,.72),
    0 4px 18px -8px rgba(0,0,0,.5),
    inset 0 1px 0 rgba(255,255,255,.1),
    inset 0 -1px 0 rgba(255,255,255,.04);
}

.nav-glider{
  position:absolute;top:6px;bottom:6px;left:0;
  /* The capsule glides on transform/width inside the blurred dock. Keeping it
     on its own layer means a glide never drags the dock's backdrop through a
     re-blur, so the movement stays on the compositor end to end. */
  will-change:transform,width;
  border-radius:var(--radius-lg);
  background:linear-gradient(135deg,
    color-mix(in srgb,var(--accent) 24%,transparent),
    color-mix(in srgb,var(--accent) 12%,transparent));
  border:1px solid color-mix(in srgb,var(--accent) 32%,transparent);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.3);
  transition:transform var(--duration-base) var(--ease-out),width var(--duration-base) var(--ease-out),opacity var(--duration-fast) ease;
  pointer-events:none;
}
html[data-mode="dark"] .nav-glider{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.08);
}

.nav-tab{
  position:relative;z-index:1;flex:0 0 auto;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;
  min-width:50px;padding:7px 9px;
  border:none;background:transparent;border-radius:var(--radius-lg);
  color:var(--muted);
  font-family:var(--font-ui);font-size:11px;font-weight:500;
  cursor:pointer;transition:color var(--duration-fast),background var(--duration-fast);
  -webkit-tap-highlight-color:transparent;
}
/* hover state lives in the @media(hover:hover) block above */
.nav-tab svg{width:19px;height:19px;transition:transform var(--duration-base) var(--ease-out)}
.nav-tab:active{transform:scale(.94)}
.nav-tab.active{color:var(--accent);font-weight:600}
.nav-tab.active svg{transform:translateY(-1px) scale(1.05)}
.nav-label{display:inline-flex;align-items:center;gap:3px;white-space:nowrap;line-height:1}
.beta-tag{font-style:normal;font-family:var(--font-ui);font-size:8px;font-weight:700;line-height:1;padding:2.5px 5px;border-radius:var(--radius-pill);background:var(--accent);color:#fff;letter-spacing:.3px;flex-shrink:0}

/* ═══ Focus Page ═══ */
.app-focus{align-items:center;padding-top:12px}
.focus-page-card{width:100%;max-width:360px;background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-xl);padding:28px var(--space-6);text-align:center;box-shadow:var(--shadow-1);display:flex;flex-direction:column;align-items:center;gap:18px}
.focus-page-card .focus-task{font-size:14px;color:var(--muted);font-weight:400;line-height:1.7}
.focus-page-actions{display:flex;gap:8px;width:100%}
.focus-page-actions .go{flex:1;border:none;background:var(--accent);color:#fff;font-family:var(--font-ui);font-weight:600;font-size:15px;padding:12px;border-radius:var(--radius-sm);cursor:pointer;box-shadow:var(--shadow-accent);transition:transform var(--duration-fast),box-shadow var(--duration-fast)}
.focus-page-actions .go:active{transform:translateY(3px);box-shadow:0 1px 0 0 rgba(120,55,20,.35)}
.focus-page-actions .go:disabled{opacity:.5;box-shadow:none;cursor:not-allowed}
.focus-page-actions .go:disabled:active{transform:none}
.focus-page-actions .ghost{flex:1;border:1.5px solid var(--border);background:transparent;color:var(--muted);font-family:var(--font-ui);font-weight:500;font-size:14px;padding:12px;border-radius:var(--radius-sm);cursor:pointer;transition:all var(--duration-fast)}
/* hover state lives in the @media(hover:hover) block above */
/* The task book — the pick view's list of open tasks.
   A page of the notebook rather than a system dropdown: paper surface with a
   strip of tape, hairline rules between entries, the last-focused task pinned
   first under a small ribbon, and a hand-drawn tick on the chosen one. The list
   scrolls inside the card, so a long list never grows the card itself. */
.pickbook{position:relative;width:100%;text-align:start;background:var(--color-surface);border:1px solid var(--border);border-radius:var(--radius-md);padding:10px 12px 12px;box-shadow:var(--shadow-1)}
.pickbook::before{content:'';position:absolute;inset-inline-start:20px;top:-8px;width:46px;height:15px;border-radius:2px;background:var(--tape);opacity:.7;transform:rotate(-1.5deg);pointer-events:none}
.pickbook-head{display:flex;align-items:center;gap:8px;width:100%;min-height:44px;padding-bottom:6px;border-bottom:1.5px dashed var(--border);background:transparent;border-top:none;border-inline:none;cursor:pointer;font-family:var(--font-ui);text-align:start;color:inherit}
.pickbook-head span{font-size:11.5px;font-weight:600;color:var(--muted)}
@media (hover:hover){
  .pickbook-head:hover span{color:var(--text)}
}
.pickbook-head:focus-visible{outline:2px solid var(--color-focus);outline-offset:2px;border-radius:var(--radius-xs)}
.pickbook-count{margin-inline-start:auto;font-weight:500;font-size:10.5px;opacity:.85}
.pickbook-chev{flex-shrink:0;width:15px;height:15px;color:var(--muted);transition:transform var(--duration-base) var(--ease-out)}
.pickbook-head[aria-expanded="true"] .pickbook-chev{transform:rotate(180deg)}
/* The book body: a height-animated reveal, default shut. Grid-template-rows
   gives a smooth open/close without measuring scrollHeight in JS. */
.pickbook-body{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--duration-base) var(--ease-out)}
.pickbook-body.open{grid-template-rows:1fr}
.pickbook-body-inner{overflow:hidden;min-height:0}
@media (prefers-reduced-motion:reduce){
  .pickbook-body{transition:none}
  .pickbook-chev{transition:none}
}
.pickbook-search{padding:8px 0 2px}
.pickbook-search input{width:100%;font-family:var(--font-ui);font-size:13px;border:none;border-bottom:1.5px dashed var(--border);background:transparent;color:var(--text);padding:6px 2px;outline:none;direction:rtl}
.pickbook-search input:focus{border-bottom-color:var(--accent)}
.pickbook-search input::placeholder{color:var(--muted);opacity:.8}
.pickbook-list{display:flex;flex-direction:column;max-height:196px;max-height:min(196px,34dvh);overflow-y:auto;overscroll-behavior-y:contain;scrollbar-width:thin;scrollbar-color:var(--color-border-strong) transparent}
/* Chromium: keep the little wheel unobtrusive and theme-aware */
.pickbook-list::-webkit-scrollbar{width:6px}
.pickbook-list::-webkit-scrollbar-thumb{background:var(--color-border-strong);border-radius:999px}
.pickbook-list::-webkit-scrollbar-track{background:transparent}
.pickrow{position:relative;display:flex;align-items:flex-start;gap:10px;min-height:44px;flex-shrink:0;padding:9px 4px;border-bottom:1px solid var(--border);border-radius:var(--radius-xs);cursor:pointer;transition:background var(--duration-fast)}
.pickrow[hidden]{display:none}
.pickrow:last-child{border-bottom:none}
/* The input stays focusable and announced; the whole row is the target and the
   radio itself covers a 44px touch column while staying visually hidden.
   Rows grow with their content (title + meta never clip or bleed into the
   next row) — min-height was removed because it forced the chip to overflow. */
.pickrow input{position:absolute;inset-inline-start:0;top:50%;transform:translateY(-50%);width:44px;height:44px;margin:0;opacity:0;pointer-events:none}
.pickrow::after{content:'';position:absolute;inset:0}
@media (hover:hover){
  .pickrow:hover{background:var(--accent-soft)}
}
.pickrow:has(input:checked){background:var(--accent-soft)}
.pickrow:has(input:focus-visible){outline:2px solid var(--color-focus);outline-offset:1px}
.pickrow-tick{display:grid;place-items:center;flex-shrink:0;width:20px;height:20px;margin-top:1px;border:1.5px dashed var(--color-border-strong);border-radius:50%;color:transparent;transition:color var(--duration-fast),background var(--duration-fast),border-color var(--duration-fast)}
.pickrow-tick svg{width:12px;height:12px}
.pickrow:has(input:checked) .pickrow-tick{background:var(--accent);border-color:var(--accent);border-style:solid;color:#fff}
.pickrow-main{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0}
.pickrow-title{font-size:13.5px;font-weight:500;color:var(--text);line-height:1.6;overflow-wrap:anywhere}
.pickrow:has(input:checked) .pickrow-title{font-weight:600}
.pickrow-meta{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:1px}
/* Deadline and estimate read as labels here, not as controls */
.pickrow-meta .due-chip,.pickrow-meta .dur-chip{cursor:default;font-size:10px;padding:2px 8px;line-height:1.5}
.pickrow-meta .due-chip:hover,.pickrow-meta .dur-chip:hover{transform:none}
.pick-note{font-size:10px;font-weight:600;line-height:1.6;padding:2px 8px;border-radius:var(--radius-pill);color:var(--color-accent-strong);background:var(--accent-soft)}
.pickbook-none{padding:14px 0 6px;font-size:11.5px;text-align:center;color:var(--muted)}

/* ═══ Settings ═══ */
.settings-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:8px 18px;box-shadow:var(--shadow-sm)}
.settings-row{display:flex;align-items:center;justify-content:space-between;padding:14px 0;gap:12px;flex-wrap:wrap}
/* The theme row stacks instead of sitting on one line: its control is a switch
   over the four swatches of that half, which needs the card's full width to stay
   legible — pushed into the value column it would only wrap and clip. */
.settings-row.settings-row-theme{flex-direction:column;align-items:stretch;gap:10px}
.theme-picker{display:flex;flex-direction:column;gap:10px;min-width:0}
.theme-picker .seg{align-self:flex-start}
.settings-label{font-size:14px;font-weight:500}
.settings-value{display:flex;align-items:center;gap:10px}
.settings-value span{font-size:13px;color:var(--muted);font-weight:400}
.settings-btn{position:relative;border:1.5px solid var(--border);background:transparent;color:var(--accent);font-family:var(--font-ui);font-size:12px;font-weight:600;padding:5px 14px;border-radius:var(--radius-pill);cursor:pointer;transition:all var(--duration-fast)}
/* The pill stays compact, but the area that accepts a finger is 44px tall and
   wide enough for a thumb — a tap just above or below the border still lands
   on the button instead of falling through to the row. */
.settings-btn::after{content:"";position:absolute;left:-4px;right:-4px;top:50%;height:44px;min-width:44px;transform:translateY(-50%)}
/* hover states live in the @media(hover:hover) block above */
.settings-btn.danger{color:var(--danger);border-color:rgba(228,88,79,.3)}
/* A hairline between two settings inside one card. It spans the card's content
   box: a wider line would have had to guess the card's padding, and the guess
   was already wrong at the width where that padding shrinks. */
.settings-divider{height:1px;background:var(--border)}
.settings-row.danger .settings-label{color:var(--danger)}
.settings-about{text-align:center;color:var(--muted);font-size:12px;padding:16px 0 8px;line-height:1.7;font-weight:400}

@keyframes spin{to{transform:rotate(360deg)}}
@keyframes twinkle{0%,100%{opacity:.15;transform:scale(.9)}50%{opacity:.45;transform:scale(1.08)}}
/* (floaty removed in 8.3 — large floating movement did not fit the motion DNA;
   the slower `drift` keyframe replaces it everywhere) */
@keyframes draw{to{stroke-dashoffset:0}}
@keyframes shake{0%,100%{transform:none}25%{transform:translateX(5px)}75%{transform:translateX(-5px)}}
/* Micro feedback pop — kept small on purpose (motion budget) */
@keyframes pop{0%{transform:scale(1)}40%{transform:scale(1.12)}100%{transform:scale(1)}}
/* Very low-character idle drift for small decorative art */
@keyframes drift{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}
@keyframes popIn{from{transform:scale(0)}}

/* ═══ Calm Motion & Compositing Budget ═══
   Two rules keep the interface soft rather than merely busy: loops stop when
   nobody is looking, and glass the user asked to have flattened stays flat.
   Nothing here changes a single resting pixel — only what happens over time. */

/* While the app is hidden (background tab, covered window, screen off) every
   ambient loop is paused: the page doodles, the companion characters, the
   Focus scenes' rain and waves, and the soft pulse on important tasks. The
   device stops painting frames nobody can see — battery and thermals stay
   calm — and coming back resumes each loop where it was instead of restarting
   it, so the return never looks like a flicker. */
html.tab-hidden .doodle,
html.tab-hidden .frog-emoji,
html.tab-hidden .frog-ico svg,
html.tab-hidden .frog-hero::before,
html.tab-hidden .empty .art,
html.tab-hidden .spark,
html.tab-hidden .streak.hot svg,
html.tab-hidden .ring-wrap.complete::after,
html.tab-hidden .task[data-p="high"] .pri-dot::before,
html.tab-hidden .rain-drops i,
html.tab-hidden .waves svg,
html.tab-hidden .flies i,
html.tab-hidden .focus-pill.running::after,
html.tab-hidden .reader-timer.on{animation-play-state:paused!important}

/* Flattened glass, for readers who ask the system for less transparency.
   The dock, the modal scrim and the reader bar fall back to the same surface
   and border tokens as their opaque form, so the interface keeps its paper
   identity without any per-frame backdrop sampling. */
@media (prefers-reduced-transparency:reduce){
  .bottom-nav,.reader-top,.overlay,.book-pct-badge{backdrop-filter:none;-webkit-backdrop-filter:none}
  .bottom-nav{background:var(--color-surface);border-color:var(--color-border-strong)}
  html[data-mode="dark"] .bottom-nav{background:var(--color-surface)}
  .overlay{background:rgba(46,41,33,.55)}
  .reader-top{background:var(--surface)}
  .book-pct-badge{background:rgba(0,0,0,.72)}
}

/* ═══ Accessibility Foundation ═══ */
:focus-visible{outline:2px solid var(--color-focus);outline-offset:2px;border-radius:var(--radius-xs)}
button:disabled,.switch:disabled{opacity:.45;cursor:not-allowed}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ═══ Reduced Motion (Priority 8.3) ═══
   Ambient/decorative motion stops; essential feedback stays (opacity-only,
   instant state changes, focus ring untouched). */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}
  html{scroll-behavior:auto!important}
  /* Decorative elements and ambient loops are frozen, not just accelerated */
  .doodle,.frog-emoji,.frog-ico svg,.empty .art,.spark,.frog-hero::before,.frog-hero::after,
  .rain-drops i,.flies i,.waves svg,.ring-wrap.complete,.ring-wrap.complete::after,.streak.hot svg,
  .task[data-p="high"] .pri-dot,.task[data-p="high"] .pri-dot::before,
  .focus-pill.running::after,.reader-timer.on{animation:none!important}
  /* Decorative transforms off; state/feedback transforms still apply instantly */
  .task:hover,.frog:hover,.lastread:hover,.book-card:hover,.progress-card:hover,.header-avatar:hover,
  .moods button:hover,.t-row:hover,.note-item:hover,.cat-chip:hover{transform:none!important}
}

/* ═══ Responsive ═══ */
@media (max-width:480px){
  .page{padding:24px 12px calc(var(--nav-height) + 16px)}
  .subtitle{font-size:12px}
  .bottom-nav{gap:1px;padding:5px;border-radius:var(--radius-xl)}
  .nav-tab{min-width:44px;padding:6px 7px;font-size:10px;border-radius:var(--radius-lg)}
  .nav-tab .beta-tag{font-size:7px;padding:2px 3.5px}
  .nav-tab svg{width:18px;height:18px}
  .nav-glider{top:5px;bottom:5px;border-radius:var(--radius-lg)}
  .focus-page-card{padding:22px 16px;gap:14px}
  .focus-page-actions .go{font-size:14px;padding:11px}
  .focus-page-actions .ghost{font-size:13px;padding:11px}
  .pickbook-list{max-height:min(168px,30dvh)}
  .pickrow{padding:8px 2px}
  .settings-row{padding:12px 0}
  .settings-label{font-size:13px}
  .settings-value span{font-size:12px}
}
@media (max-width:360px){
  .page{padding:20px 10px calc(var(--nav-height) + 14px)}
  .nav-tab{min-width:40px;padding:5px 5px;font-size:9px}
  .nav-tab svg{width:17px;height:17px}
  .focus-page-card{padding:18px 12px}
  .settings-card{padding:6px 14px}
}

/* ═══ 19. The sheet of paper ═══
   The one object four components share: the two date calendars, the birthday
   greeting and the update note. They used to spell the recipe out between them —
   two gradients in two files, a third at a different pitch in a third, and three
   strips of tape in three sizes — which is four chances for the same paper to
   stop being the same paper.

   overflow stays visible on purpose: the tape hangs off the top edge by 7px, and
   a component that clips for some other reason — .toast clips so its auto-dismiss
   bar cannot escape a rounded corner — would take the tape with it. Measured
   with it clipped: the tape is not there and the sheet reads as a plain
   rectangle. Components that inherit overflow:hidden from elsewhere must opt out
   in their own rule; .toast-sticky does.

   The tape, same comment: it is here, once, and everything else inherits it. */
.sheet-paper{
  /* The recipe, declared here rather than in :root for one reason: the share card
     reads its colours out of getComputedStyle and its parser only understands
     #hex and rgb()/rgba(), and tests/themes.test.mjs holds the default token block
     to that. color-mix() is the only way to write a 5% ink over an unknown
     surface, and this gradient is not one of the tokens the card reads — so it
     lives on the class instead of in the block the card does read. */
  --sheet-rule:repeating-linear-gradient(to bottom,
    transparent 0 22px,
    color-mix(in srgb,var(--color-text-primary) 5%,transparent) 22px 23px);
  --sheet-paper:var(--sheet-rule),var(--color-surface);
  --sheet-tape-w:48px;
  --sheet-tape-h:15px;
  --sheet-tape-tilt:-2deg;
  --sheet-tape-inset:20px;
  position:relative;overflow:visible;
  background:var(--sheet-paper);
  color:var(--color-text-primary);
  border:1px solid var(--color-border);
  /* No drop shadow, and that is a decision rather than an omission.
     --shadow-2 is 0 24px 50px -24px in a warm brown, and on a sheet this size it
     does not read as the shadow a page casts on the page below — it reads as a
     warm glow spilling out past the edges, which is exactly what it was asked to
     stop doing. The tape is what lifts the sheet now, and the tape is the honest
     version of that cue: it says «this is held down here» rather than «this button is
     about to be pressed», which is what a big soft accent halo says.

     The border stays, because a sheet of paper on a sheet of paper needs an edge. */
  box-shadow:none}
/* The strip of tape: same size, same tilt, same token as every other sheet. It
   says «this page is a physical object from this notebook», which is exactly
   what a calendar being filled in, a day being marked and an announcement being
   pinned to the book have in common. */
.sheet-paper::before{content:'';position:absolute;
  inset-inline-start:var(--sheet-tape-inset);top:-7px;
  width:var(--sheet-tape-w);height:var(--sheet-tape-h);
  border-radius:2px;background:var(--tape);opacity:.75;
  transform:rotate(var(--sheet-tape-tilt));pointer-events:none}
